comparison Plugins/Input/amidi-plug/backend-alsa/b-alsa.c @ 1387:b0590e16329f trunk

[svn] import amidi-plug 0.5
author giacomo
date Mon, 10 Jul 2006 04:52:51 -0700
parents
children db56f6752bd1
comparison
equal deleted inserted replaced
1386:f0d2b02f0382 1387:b0590e16329f
1 /*
2 *
3 * Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21 #include "b-alsa.h"
22 #include "b-alsa-config.h"
23
24 /* sequencer instance */
25 static sequencer_client_t sc;
26 /* options */
27 static amidiplug_cfg_alsa_t amidiplug_cfg_alsa;
28
29
30 gint backend_info_get( gchar ** name , gchar ** longname , gchar ** desc , gint * ppos )
31 {
32 if ( name != NULL )
33 *name = g_strdup( "alsa" );
34 if ( longname != NULL )
35 *longname = g_strdup( "ALSA Backend " AMIDIPLUG_VERSION );
36 if ( desc != NULL )
37 *desc = g_strdup( _("This backend sends MIDI events to a group of user-chosen "
38 "ALSA sequencer ports. The ALSA sequencer interface is very "
39 "versatile, it can provide ports for audio cards hardware "
40 "synthesizers (i.e. emu10k1) but also for software synths, "
41 "external devices, etc.\n"
42 "This backend does not produce audio, MIDI events are handled "
43 "directly from devices/programs behind the ALSA ports; in example, "
44 "MIDI events sent to the hardware synth will be directly played.\n"
45 "Backend written by Giacomo Lozito.") );
46 if ( ppos != NULL )
47 *ppos = 1; /* preferred position in backend list */
48 return 1;
49 }
50
51
52 gint backend_init( void )
53 {
54 /* read configuration options */
55 i_cfg_read();
56
57 sc.seq = NULL;
58 sc.client_port = 0;
59 sc.queue = 0;
60 sc.dest_port = NULL;
61 sc.dest_port_num = 0;
62 sc.queue_tempo = NULL;
63 sc.is_start = FALSE;
64
65 return 1;
66 }
67
68 gint backend_cleanup( void )
69 {
70 /* free configuration options */
71 i_cfg_free();
72
73 return 1;
74 }
75
76
77 gint sequencer_get_port_count( void )
78 {
79 return i_util_str_count( amidiplug_cfg_alsa.alsa_seq_wports , ':' );
80 }
81
82
83 gint sequencer_start( gchar * midi_fname )
84 {
85 sc.is_start = TRUE;
86 return 1; /* success */
87 }
88
89
90 gint sequencer_stop( void )
91 {
92 return 1; /* success */
93 }
94
95
96 /* activate sequencer client */
97 gint sequencer_on( void )
98 {
99 gchar * wports_str = amidiplug_cfg_alsa.alsa_seq_wports;
100
101 if ( !i_seq_open() )
102 {
103 sc.seq = NULL;
104 return 0;
105 }
106
107 if ( !i_seq_port_create() )
108 {
109 i_seq_close();
110 sc.seq = NULL;
111 return 0;
112 }
113
114 if ( !i_seq_queue_create() )
115 {
116 i_seq_close();
117 sc.seq = NULL;
118 return 0;
119 }
120
121 if (( sc.is_start == TRUE ) && ( wports_str ))
122 {
123 sc.is_start = FALSE;
124 i_seq_port_wparse( wports_str );
125 }
126
127 if ( !i_seq_port_connect() )
128 {
129 i_seq_queue_free();
130 i_seq_close();
131 sc.seq = NULL;
132 return 0;
133 }
134
135 /* success */
136 return 1;
137 }
138
139
140 /* shutdown sequencer client */
141 gint sequencer_off( void )
142 {
143 if ( sc.seq )
144 {
145 i_seq_port_disconnect();
146 i_seq_queue_free();
147 i_seq_close();
148 sc.seq = NULL;
149 /* return 1 here */
150 return 1;
151 }
152 /* return 2 if it was already freed */
153 return 2;
154 }
155
156
157 /* queue set tempo */
158 gint sequencer_queue_tempo( gint tempo , gint ppq )
159 {
160 /* interpret and set tempo */
161 snd_seq_queue_tempo_alloca( &sc.queue_tempo );
162 snd_seq_queue_tempo_set_tempo( sc.queue_tempo , tempo );
163 snd_seq_queue_tempo_set_ppq( sc.queue_tempo , ppq );
164
165 if ( snd_seq_set_queue_tempo( sc.seq , sc.queue , sc.queue_tempo ) < 0 )
166 {
167 g_warning( "Cannot set queue tempo (%u/%i)\n",
168 snd_seq_queue_tempo_get_tempo(sc.queue_tempo),
169 snd_seq_queue_tempo_get_ppq(sc.queue_tempo) );
170 return 0;
171 }
172 return 1;
173 }
174
175
176 gint sequencer_queue_start( void )
177 {
178 return snd_seq_start_queue( sc.seq , sc.queue , NULL );
179 }
180
181
182 gint sequencer_event_init( void )
183 {
184 /* common settings for all our events */
185 snd_seq_ev_clear(&sc.ev);
186 sc.ev.queue = sc.queue;
187 sc.ev.source.port = 0;
188 sc.ev.flags = SND_SEQ_TIME_STAMP_TICK;
189 return 1;
190 }
191
192
193 gint sequencer_event_noteon( midievent_t * event )
194 {
195 i_seq_event_common_init( event );
196 snd_seq_ev_set_fixed(&sc.ev);
197 sc.ev.data.note.channel = event->data.d[0];
198 sc.ev.data.note.note = event->data.d[1];
199 sc.ev.data.note.velocity = event->data.d[2];
200 return 1;
201 }
202
203
204 gint sequencer_event_noteoff( midievent_t * event )
205 {
206 i_seq_event_common_init( event );
207 snd_seq_ev_set_fixed(&sc.ev);
208 sc.ev.data.note.channel = event->data.d[0];
209 sc.ev.data.note.note = event->data.d[1];
210 sc.ev.data.note.velocity = event->data.d[2];
211 return 1;
212 }
213
214
215 gint sequencer_event_keypress( midievent_t * event )
216 {
217 i_seq_event_common_init( event );
218 snd_seq_ev_set_fixed(&sc.ev);
219 sc.ev.data.note.channel = event->data.d[0];
220 sc.ev.data.note.note = event->data.d[1];
221 sc.ev.data.note.velocity = event->data.d[2];
222 return 1;
223 }
224
225
226 gint sequencer_event_controller( midievent_t * event )
227 {
228 i_seq_event_common_init( event );
229 snd_seq_ev_set_fixed(&sc.ev);
230 sc.ev.data.control.channel = event->data.d[0];
231 sc.ev.data.control.param = event->data.d[1];
232 sc.ev.data.control.value = event->data.d[2];
233 return 1;
234 }
235
236
237 gint sequencer_event_pgmchange( midievent_t * event )
238 {
239 i_seq_event_common_init( event );
240 snd_seq_ev_set_fixed(&sc.ev);
241 sc.ev.data.control.channel = event->data.d[0];
242 sc.ev.data.control.value = event->data.d[1];
243 return 1;
244 }
245
246
247 gint sequencer_event_chanpress( midievent_t * event )
248 {
249 i_seq_event_common_init( event );
250 snd_seq_ev_set_fixed(&sc.ev);
251 sc.ev.data.control.channel = event->data.d[0];
252 sc.ev.data.control.value = event->data.d[1];
253 return 1;
254 }
255
256
257 gint sequencer_event_pitchbend( midievent_t * event )
258 {
259 i_seq_event_common_init( event );
260 snd_seq_ev_set_fixed(&sc.ev);
261 sc.ev.data.control.channel = event->data.d[0];
262 sc.ev.data.control.value = ((event->data.d[1]) | ((event->data.d[2]) << 7)) - 0x2000;
263 return 1;
264 }
265
266
267 gint sequencer_event_sysex( midievent_t * event )
268 {
269 i_seq_event_common_init( event );
270 snd_seq_ev_set_variable(&sc.ev, event->data.length, event->sysex);
271 return 1;
272 }
273
274
275 gint sequencer_event_tempo( midievent_t * event )
276 {
277 i_seq_event_common_init( event );
278 snd_seq_ev_set_fixed(&sc.ev);
279 sc.ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
280 sc.ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
281 sc.ev.data.queue.queue = sc.queue;
282 sc.ev.data.queue.param.value = event->data.tempo;
283 return 1;
284 }
285
286
287 gint sequencer_event_other( midievent_t * event )
288 {
289 /* unhandled */
290 return 1;
291 }
292
293
294 gint sequencer_output( gpointer * buffer , gint * len )
295 {
296 snd_seq_event_output( sc.seq , &sc.ev );
297 snd_seq_drain_output( sc.seq );
298 snd_seq_sync_output_queue( sc.seq );
299 return 0;
300 }
301
302
303 gint sequencer_output_shut( guint max_tick , gint skip_offset )
304 {
305 gint i = 0 , c = 0;
306 /* time to shutdown playback! */
307 /* send "ALL SOUNDS OFF" to all channels on all ports */
308 sc.ev.type = SND_SEQ_EVENT_CONTROLLER;
309 sc.ev.time.tick = 0;
310 snd_seq_ev_set_fixed(&sc.ev);
311 sc.ev.data.control.param = MIDI_CTL_ALL_SOUNDS_OFF;
312 sc.ev.data.control.value = 0;
313 for ( i = 0 ; i < sc.dest_port_num ; i++ )
314 {
315 sc.ev.queue = sc.queue;
316 sc.ev.dest = sc.dest_port[i];
317
318 for ( c = 0 ; c < 16 ; c++ )
319 {
320 sc.ev.data.control.channel = c;
321 snd_seq_event_output(sc.seq, &sc.ev);
322 snd_seq_drain_output(sc.seq);
323 }
324 }
325
326 /* schedule queue stop at end of song */
327 snd_seq_ev_clear(&sc.ev);
328 sc.ev.queue = sc.queue;
329 sc.ev.source.port = 0;
330 sc.ev.flags = SND_SEQ_TIME_STAMP_TICK;
331
332 snd_seq_ev_set_fixed(&sc.ev);
333 sc.ev.type = SND_SEQ_EVENT_STOP;
334 sc.ev.time.tick = max_tick - skip_offset;
335 sc.ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
336 sc.ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
337 sc.ev.data.queue.queue = sc.queue;
338 snd_seq_event_output(sc.seq, &sc.ev);
339 snd_seq_drain_output(sc.seq);
340 /* snd_seq_sync_output_queue(sc.seq); */
341
342 return 1;
343 }
344
345
346 gint audio_volume_get( gint * left_volume , gint * right_volume )
347 {
348 snd_mixer_t * mixer_h = NULL;
349 snd_mixer_elem_t * mixer_elem = NULL;
350 gchar mixer_card[10];
351 snprintf( mixer_card , 8 , "hw:%i" , amidiplug_cfg_alsa.alsa_mixer_card_id );
352 mixer_card[9] = '\0';
353
354 if ( snd_mixer_open( &mixer_h , 0 ) > -1 )
355 i_seq_mixer_find_selem( mixer_h , mixer_card ,
356 amidiplug_cfg_alsa.alsa_mixer_ctl_name ,
357 amidiplug_cfg_alsa.alsa_mixer_ctl_id ,
358 &mixer_elem );
359 else
360 mixer_h = NULL;
361
362 if ( ( mixer_elem ) && ( snd_mixer_selem_has_playback_volume( mixer_elem ) ) )
363 {
364 glong pv_min , pv_max , pv_range;
365 glong lc, rc;
366
367 snd_mixer_selem_get_playback_volume_range( mixer_elem , &pv_min , &pv_max );
368 pv_range = pv_max - pv_min;
369 if ( pv_range > 0 )
370 {
371 if ( snd_mixer_selem_has_playback_channel( mixer_elem , SND_MIXER_SCHN_FRONT_LEFT ) )
372 {
373 snd_mixer_selem_get_playback_volume( mixer_elem , SND_MIXER_SCHN_FRONT_LEFT , &lc );
374 /* convert the range to 0-100 (for the case that pv_range is not 0-100 already) */
375 *left_volume = (gint)(((lc - pv_min) * 100) / pv_range);
376 DEBUGMSG( "GET VOLUME requested, get left channel (%i)\n" , *left_volume );
377 }
378 if ( snd_mixer_selem_has_playback_channel( mixer_elem , SND_MIXER_SCHN_FRONT_RIGHT ) )
379 {
380 snd_mixer_selem_get_playback_volume( mixer_elem , SND_MIXER_SCHN_FRONT_RIGHT , &rc );
381 /* convert the range to 0-100 (for the case that pv_range is not 0-100 already) */
382 *right_volume = (gint)(((rc - pv_min) * 100) / pv_range);
383 DEBUGMSG( "GET VOLUME requested, get right channel (%i)\n" , *right_volume );
384 }
385 }
386 }
387
388 if ( mixer_h )
389 snd_mixer_close( mixer_h );
390 /* always return 1 here */
391 return 1;
392 }
393
394
395 gint audio_volume_set( gint left_volume , gint right_volume )
396 {
397 snd_mixer_t * mixer_h = NULL;
398 snd_mixer_elem_t * mixer_elem = NULL;
399 gchar mixer_card[10];
400 snprintf( mixer_card , 8 , "hw:%i" , amidiplug_cfg_alsa.alsa_mixer_card_id );
401 mixer_card[9] = '\0';
402
403 if ( snd_mixer_open( &mixer_h , 0 ) > -1 )
404 i_seq_mixer_find_selem( mixer_h , mixer_card ,
405 amidiplug_cfg_alsa.alsa_mixer_ctl_name ,
406 amidiplug_cfg_alsa.alsa_mixer_ctl_id ,
407 &mixer_elem );
408 else
409 mixer_h = NULL;
410
411 if ( ( mixer_elem ) && ( snd_mixer_selem_has_playback_volume( mixer_elem ) ) )
412 {
413 glong pv_min , pv_max , pv_range;
414
415 snd_mixer_selem_get_playback_volume_range( mixer_elem , &pv_min , &pv_max );
416 pv_range = pv_max - pv_min;
417 if ( pv_range > 0 )
418 {
419 if ( snd_mixer_selem_has_playback_channel( mixer_elem , SND_MIXER_SCHN_FRONT_LEFT ) )
420 {
421 DEBUGMSG( "SET VOLUME requested, setting left channel to %i%%\n" , left_volume );
422 snd_mixer_selem_set_playback_volume( mixer_elem , SND_MIXER_SCHN_FRONT_LEFT ,
423 (gint)((gdouble)(0.01 * (gdouble)(left_volume * pv_range)) + pv_min) );
424 }
425 if ( snd_mixer_selem_has_playback_channel( mixer_elem , SND_MIXER_SCHN_FRONT_RIGHT ) )
426 {
427 DEBUGMSG( "SET VOLUME requested, setting right channel to %i%%\n" , right_volume );
428 snd_mixer_selem_set_playback_volume( mixer_elem , SND_MIXER_SCHN_FRONT_RIGHT ,
429 (gint)((gdouble)(0.01 * (gdouble)(right_volume * pv_range)) + pv_min) );
430 }
431 }
432 }
433
434 if ( mixer_h )
435 snd_mixer_close( mixer_h );
436 /* always return 1 here */
437 return 1;
438 }
439
440
441 gint audio_info_get( gint * channels , gint * bitdepth , gint * samplerate )
442 {
443 /* not applicable for ALSA backend */
444 *channels = -1;
445 *bitdepth = -1;
446 *samplerate = -1;
447 return 0; /* not valid information */
448 }
449
450
451 gboolean audio_check_autonomous( void )
452 {
453 return TRUE; /* ALSA deals directly with audio production */
454 }
455
456
457
458 /* ******************************************************************
459 *** EXTRA FUNCTIONS **********************************************
460 ****************************************************************** */
461
462
463 /* get a list of writable ALSA MIDI ports
464 use the data_bucket_t here...
465 bint[0] = client id , bint[1] = port id
466 bcharp[0] = client name , bcharp[1] = port name
467 bpointer[0] = (not used) , bpointer[1] = (not used) */
468 GSList * sequencer_port_get_list( void )
469 {
470 snd_seq_t * pseq;
471 snd_seq_open( &pseq , "default" , SND_SEQ_OPEN_DUPLEX , 0 );
472
473 GSList * wports = NULL;
474 snd_seq_client_info_t *cinfo;
475 snd_seq_port_info_t *pinfo;
476
477 snd_seq_client_info_alloca( &cinfo );
478 snd_seq_port_info_alloca( &pinfo );
479
480 snd_seq_client_info_set_client( cinfo , -1 );
481 while ( snd_seq_query_next_client( pseq , cinfo ) >= 0 )
482 {
483 gint client = snd_seq_client_info_get_client( cinfo );
484 snd_seq_port_info_set_client( pinfo , client );
485 snd_seq_port_info_set_port( pinfo , -1 );
486 while (snd_seq_query_next_port( pseq , pinfo ) >= 0 )
487 {
488 if ((snd_seq_port_info_get_capability(pinfo)
489 & (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE))
490 == (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE))
491 {
492 data_bucket_t * portinfo = (data_bucket_t*)g_malloc(sizeof(data_bucket_t));
493 portinfo->bint[0] = snd_seq_port_info_get_client( pinfo );
494 portinfo->bint[1] = snd_seq_port_info_get_port( pinfo );
495 portinfo->bcharp[0] = g_strdup(snd_seq_client_info_get_name(cinfo));
496 portinfo->bcharp[1] = g_strdup(snd_seq_port_info_get_name(pinfo));
497 wports = g_slist_append( wports , portinfo );
498 }
499 }
500 }
501 /* snd_seq_port_info_free( pinfo );
502 snd_seq_client_info_free( cinfo ); */
503 snd_seq_close( pseq );
504 return wports;
505 }
506
507
508 void sequencer_port_free_list( GSList * wports )
509 {
510 GSList * start = wports;
511 while ( wports != NULL )
512 {
513 data_bucket_t * portinfo = wports->data;
514 g_free( (gpointer)portinfo->bcharp[0] );
515 g_free( (gpointer)portinfo->bcharp[1] );
516 g_free( portinfo );
517 wports = wports->next;
518 }
519 g_slist_free( start );
520 return;
521 }
522
523
524 /* get a list of available sound cards and relative mixer controls;
525 use the data_bucket_t here...
526 bint[0] = card id , bint[1] = (not used)
527 bcharp[0] = card name , bcharp[1] = (not used)
528 bpointer[0] = list (GSList) of mixer controls on the card , bpointer[1] = (not used) */
529 GSList * alsa_card_get_list( void )
530 {
531 gint soundcard_id = -1;
532 GSList * scards = NULL;
533
534 snd_card_next( &soundcard_id );
535 while ( soundcard_id > -1 )
536 {
537 /* card container */
538 data_bucket_t * cardinfo = (data_bucket_t*)g_malloc(sizeof(data_bucket_t));
539 cardinfo->bint[0] = soundcard_id;
540 /* snd_card_get_name calls strdup on its own */
541 snd_card_get_name( soundcard_id , &cardinfo->bcharp[0] );
542 /* for each sound card, get a list of available mixer controls */
543 cardinfo->bpointer[0] = i_seq_mixctl_get_list( soundcard_id );
544
545 scards = g_slist_append( scards , cardinfo );
546 snd_card_next( &soundcard_id );
547 }
548 return scards;
549 }
550
551
552 void alsa_card_free_list( GSList * scards )
553 {
554 GSList * start = scards;
555 while ( scards != NULL )
556 {
557 data_bucket_t * cardinfo = scards->data;
558 /* free the list of mixer controls for the sound card */
559 i_seq_mixctl_free_list( (GSList*)cardinfo->bpointer[0] );
560 g_free( (gpointer)cardinfo->bcharp[0] );
561 g_free( cardinfo );
562 scards = scards->next;
563 }
564 g_slist_free( start );
565 return;
566 }
567
568
569
570 /* ******************************************************************
571 *** INTERNALS ****************************************************
572 ****************************************************************** */
573
574
575 /* create sequencer client */
576 gint i_seq_open( void )
577 {
578 gint err;
579 err = snd_seq_open( &sc.seq , "default" , SND_SEQ_OPEN_DUPLEX , 0 );
580 if (err < 0)
581 return 0;
582 snd_seq_set_client_name( sc.seq , "amidi-plug" );
583 return 1;
584 }
585
586
587 /* free sequencer client */
588 gint i_seq_close( void )
589 {
590 if ( snd_seq_close( sc.seq ) < 0 )
591 return 0; /* fail */
592 else
593 return 1; /* success */
594 }
595
596
597 /* create queue */
598 gint i_seq_queue_create( void )
599 {
600 sc.queue = snd_seq_alloc_named_queue( sc.seq , "AMIDI-Plug" );
601 if ( sc.queue < 0 )
602 return 0; /* fail */
603 else
604 return 1; /* success */
605 }
606
607
608 /* free queue */
609 gint i_seq_queue_free( void )
610 {
611 if ( snd_seq_free_queue( sc.seq , sc.queue ) < 0 )
612 return 0; /* fail */
613 else
614 return 1; /* success */
615 }
616
617
618 /* create sequencer port */
619 gint i_seq_port_create( void )
620 {
621 sc.client_port = snd_seq_create_simple_port( sc.seq , "AMIDI-Plug" , 0 ,
622 SND_SEQ_PORT_TYPE_MIDI_GENERIC |
623 SND_SEQ_PORT_TYPE_APPLICATION );
624 if ( sc.client_port < 0 )
625 return 0; /* fail */
626 else
627 return 1; /* success */
628 }
629
630
631 /* port connection */
632 gint i_seq_port_connect( void )
633 {
634 gint i = 0 , err = 0;
635 for ( i = 0 ; i < sc.dest_port_num ; i++ )
636 {
637 if ( snd_seq_connect_to( sc.seq , sc.client_port ,
638 sc.dest_port[i].client ,
639 sc.dest_port[i].port ) < 0 )
640 ++err;
641 }
642 /* if these values are equal, it means
643 that all port connections failed */
644 if ( err == i )
645 return 0; /* fail */
646 else
647 return 1; /* success */
648 }
649
650
651 /* port disconnection */
652 gint i_seq_port_disconnect( void )
653 {
654 gint i = 0 , err = 0;
655 for ( i = 0 ; i < sc.dest_port_num ; i++ )
656 {
657 if ( snd_seq_disconnect_to( sc.seq , sc.client_port ,
658 sc.dest_port[i].client ,
659 sc.dest_port[i].port ) < 0 )
660 ++err;
661 }
662 /* if these values are equal, it means
663 that all port disconnections failed */
664 if ( err == i )
665 return 0; /* fail */
666 else
667 return 1; /* success */
668 }
669
670
671 /* parse writable ports */
672 gint i_seq_port_wparse( gchar * wportlist )
673 {
674 gint i = 0 , err = 0;
675 gchar **portstr = g_strsplit( wportlist , "," , 0 );
676
677 sc.dest_port_num = 0;
678
679 /* fill sc.dest_port_num with the writable port number */
680 while ( portstr[sc.dest_port_num] != NULL )
681 ++sc.dest_port_num;
682
683 /* check if there is already an allocated array and free it */
684 if ( sc.dest_port )
685 free( sc.dest_port );
686
687 if ( sc.dest_port_num > 0 )
688 /* allocate the array of writable ports */
689 sc.dest_port = calloc( sc.dest_port_num , sizeof(snd_seq_addr_t) );
690
691 for ( i = 0 ; i < sc.dest_port_num ; i++ )
692 {
693 if ( snd_seq_parse_address( sc.seq , &sc.dest_port[i] , portstr[i] ) < 0 )
694 ++err;
695 }
696
697 g_strfreev( portstr );
698
699 /* if these values are equal, it means
700 that all port translations failed */
701 if ( err == i )
702 return 0; /* fail */
703 else
704 return 1; /* success */
705 }
706
707
708 gint i_seq_event_common_init( midievent_t * event )
709 {
710 sc.ev.type = event->type;
711 sc.ev.time.tick = event->tick_real;
712 sc.ev.dest = sc.dest_port[event->port];
713 return 1;
714 }
715
716
717 /* get a list of available mixer controls for a given sound card;
718 use the data_bucket_t here...
719 bint[0] = control id , bint[1] = (not used)
720 bcharp[0] = control name , bcharp[1] = (not used)
721 bpointer[0] = (not used) , bpointer[1] = (not used) */
722 GSList * i_seq_mixctl_get_list( gint soundcard_id )
723 {
724 GSList * mixctls = NULL;
725 snd_mixer_t * mixer_h;
726 snd_mixer_selem_id_t * mixer_selem_id;
727 snd_mixer_elem_t * mixer_elem;
728 gchar card[10];
729
730 snprintf( card , 8 , "hw:%i" , soundcard_id );
731 card[9] = '\0';
732
733 snd_mixer_selem_id_alloca( &mixer_selem_id );
734 snd_mixer_open( &mixer_h , 0 );
735 snd_mixer_attach( mixer_h , card );
736 snd_mixer_selem_register( mixer_h , NULL , NULL );
737 snd_mixer_load( mixer_h );
738 for ( mixer_elem = snd_mixer_first_elem( mixer_h ) ; mixer_elem ;
739 mixer_elem = snd_mixer_elem_next( mixer_elem ) )
740 {
741 data_bucket_t * mixctlinfo = (data_bucket_t*)g_malloc(sizeof(data_bucket_t));
742 snd_mixer_selem_get_id( mixer_elem , mixer_selem_id );
743 mixctlinfo->bint[0] = snd_mixer_selem_id_get_index(mixer_selem_id);
744 mixctlinfo->bcharp[0] = g_strdup(snd_mixer_selem_id_get_name(mixer_selem_id));
745 mixctls = g_slist_append( mixctls , mixctlinfo );
746 }
747 snd_mixer_close( mixer_h );
748 return mixctls;
749 }
750
751
752 void i_seq_mixctl_free_list( GSList * mixctls )
753 {
754 GSList * start = mixctls;
755 while ( mixctls != NULL )
756 {
757 data_bucket_t * mixctlinfo = mixctls->data;
758 g_free( (gpointer)mixctlinfo->bcharp[0] );
759 g_free( mixctlinfo );
760 mixctls = mixctls->next;
761 }
762 g_slist_free( start );
763 return;
764 }
765
766
767 gint i_seq_mixer_find_selem( snd_mixer_t * mixer_h , gchar * mixer_card ,
768 gchar * mixer_control_name , gint mixer_control_id ,
769 snd_mixer_elem_t ** mixer_elem )
770 {
771 snd_mixer_selem_id_t * mixer_selem_id = NULL;
772 snd_mixer_selem_id_alloca( &mixer_selem_id );
773 snd_mixer_selem_id_set_index( mixer_selem_id , mixer_control_id );
774 snd_mixer_selem_id_set_name( mixer_selem_id , mixer_control_name );
775 snd_mixer_attach( mixer_h , mixer_card );
776 snd_mixer_selem_register( mixer_h , NULL , NULL);
777 snd_mixer_load( mixer_h );
778 /* assign the mixer element (can be NULL if there is no such element) */
779 *mixer_elem = snd_mixer_find_selem( mixer_h , mixer_selem_id );
780 /* always return 1 here */
781 return 1;
782 }
783
784
785 gchar * i_configure_read_seq_ports_default( void )
786 {
787 FILE * fp = NULL;
788 /* first try, get seq ports from proc on card0 */
789 fp = fopen( "/proc/asound/card0/wavetableD1" , "rb" );
790 if ( fp )
791 {
792 gchar buffer[100];
793 while ( !feof( fp ) )
794 {
795 fgets( buffer , 100 , fp );
796 if (( strlen( buffer ) > 11 ) && ( !strncasecmp( buffer , "addresses: " , 11 ) ))
797 {
798 /* change spaces between ports (65:0 65:1 65:2 ...)
799 into commas (65:0,65:1,65:2,...) */
800 g_strdelimit( &buffer[11] , " " , ',' );
801 /* remove lf and cr from the end of the string */
802 g_strdelimit( &buffer[11] , "\r\n" , '\0' );
803 /* ready to go */
804 DEBUGMSG( "init, default values for seq ports detected: %s\n" , &buffer[11] );
805 fclose( fp );
806 return g_strdup( &buffer[11] );
807 }
808 }
809 fclose( fp );
810 }
811
812 /* second option: do not set ports at all, let the user
813 select the right ones in the nice config window :) */
814 return g_strdup( "" );
815 }
816
817
818 /* count the number of occurrencies of a specific character 'c'
819 in the string 'string' (it must be a null-terminated string) */
820 gint i_util_str_count( gchar * string , gchar c )
821 {
822 gint i = 0 , count = 0;
823 while ( string[i] != '\0' )
824 {
825 if ( string[i] == c )
826 ++count;
827 ++i;
828 }
829 return count;
830 }
831
832
833 void i_cfg_read( void )
834 {
835 pcfg_t *cfgfile;
836 gchar * config_pathfilename = g_strjoin( "" , g_get_home_dir() , "/" ,
837 PLAYER_LOCALRCDIR , "/amidi-plug.conf" , NULL );
838 cfgfile = i_pcfg_new_from_file( config_pathfilename );
839
840 if ( !cfgfile )
841 {
842 /* alsa backend defaults */
843 amidiplug_cfg_alsa.alsa_seq_wports = i_configure_read_seq_ports_default();
844 amidiplug_cfg_alsa.alsa_mixer_card_id = 0;
845 amidiplug_cfg_alsa.alsa_mixer_ctl_name = g_strdup( "Synth" );
846 amidiplug_cfg_alsa.alsa_mixer_ctl_id = 0;
847 }
848 else
849 {
850 i_pcfg_read_string( cfgfile , "alsa" , "alsa_seq_wports" ,
851 &amidiplug_cfg_alsa.alsa_seq_wports , NULL );
852 if ( amidiplug_cfg_alsa.alsa_seq_wports == NULL )
853 amidiplug_cfg_alsa.alsa_seq_wports = i_configure_read_seq_ports_default(); /* pick default values */
854
855 i_pcfg_read_integer( cfgfile , "alsa" , "alsa_mixer_card_id" ,
856 &amidiplug_cfg_alsa.alsa_mixer_card_id , 0 );
857
858 i_pcfg_read_string( cfgfile , "alsa" , "alsa_mixer_ctl_name" ,
859 &amidiplug_cfg_alsa.alsa_mixer_ctl_name , "Synth" );
860
861 i_pcfg_read_integer( cfgfile , "alsa" , "alsa_mixer_ctl_id" ,
862 &amidiplug_cfg_alsa.alsa_mixer_ctl_id , 0 );
863
864 i_pcfg_free( cfgfile );
865 }
866
867 g_free( config_pathfilename );
868 }
869
870
871 void i_cfg_free( void )
872 {
873 g_free( amidiplug_cfg_alsa.alsa_seq_wports );
874 g_free( amidiplug_cfg_alsa.alsa_mixer_ctl_name );
875 }