comparison src/amidi-plug/amidi-plug.c @ 1414:5f892afeb8e1 audacious-plugins-1.4.0-dr2

- amidi-plug 0.8 beta1; support for gthread and v3 plugin system; needs testing and refinements
author Giacomo Lozito <james@develia.org>
date Mon, 06 Aug 2007 14:01:24 +0200
parents 761e17b23e0c
children e11d83ce8d16
comparison
equal deleted inserted replaced
1413:4731d28ea19d 1414:5f892afeb8e1
1 /* 1 /*
2 * 2 *
3 * Author: Giacomo Lozito <james@develia.org>, (C) 2005-2006 3 * Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify it 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 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 7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. 8 * option) any later version.
86 86
87 87
88 static void amidiplug_init( void ) 88 static void amidiplug_init( void )
89 { 89 {
90 g_log_set_handler(NULL , G_LOG_LEVEL_WARNING , g_log_default_handler , NULL); 90 g_log_set_handler(NULL , G_LOG_LEVEL_WARNING , g_log_default_handler , NULL);
91
92 amidiplug_gettime_mutex = g_mutex_new();
93 amidiplug_playing_mutex = g_mutex_new();
94 amidiplug_pause_cond = g_cond_new();
95 amidiplug_seekonpause_cond = g_cond_new();
96
91 DEBUGMSG( "init, read configuration\n" ); 97 DEBUGMSG( "init, read configuration\n" );
92 /* read configuration for amidi-plug */ 98 /* read configuration for amidi-plug */
93 i_configure_cfg_ap_read(); 99 i_configure_cfg_ap_read();
94 amidiplug_playing_status = AMIDIPLUG_STOP; 100 amidiplug_playing_status = AMIDIPLUG_STOP;
95 backend.gmodule = NULL; 101 backend.gmodule = NULL;
99 105
100 106
101 static void amidiplug_cleanup( void ) 107 static void amidiplug_cleanup( void )
102 { 108 {
103 i_backend_unload(); /* unload currently loaded backend */ 109 i_backend_unload(); /* unload currently loaded backend */
110
111 g_mutex_free(amidiplug_gettime_mutex);
112 g_mutex_free(amidiplug_playing_mutex);
113 g_cond_free(amidiplug_pause_cond);
114 g_cond_free(amidiplug_seekonpause_cond);
115 amidiplug_pause_cond = NULL;
116 amidiplug_seekonpause_cond = NULL;
104 } 117 }
105 118
106 119
107 static void amidiplug_configure( void ) 120 static void amidiplug_configure( void )
108 { 121 {
124 } 137 }
125 138
126 139
127 static void amidiplug_stop( InputPlayback * playback ) 140 static void amidiplug_stop( InputPlayback * playback )
128 { 141 {
142 gboolean is_error = FALSE;
129 DEBUGMSG( "STOP request at tick: %i\n" , midifile.playing_tick ); 143 DEBUGMSG( "STOP request at tick: %i\n" , midifile.playing_tick );
130 pthread_mutex_lock( &amidiplug_playing_mutex ); 144
131 if (( amidiplug_playing_status == AMIDIPLUG_PLAY ) || 145 g_mutex_lock( amidiplug_playing_mutex );
132 ( amidiplug_playing_status == AMIDIPLUG_STOP )) 146 if ( amidiplug_playing_status == AMIDIPLUG_ERR )
133 { 147 is_error = TRUE;
134 amidiplug_playing_status = AMIDIPLUG_STOP; 148 g_mutex_unlock( amidiplug_playing_mutex );
135 pthread_mutex_unlock( &amidiplug_playing_mutex ); 149
136 pthread_join( amidiplug_play_thread , NULL ); 150 if ( !is_error )
137 if ( backend.autonomous_audio == FALSE ) 151 {
138 pthread_join( amidiplug_audio_thread , NULL ); 152 /* if stop wasn't called due to error condition,
139 DEBUGMSG( "STOP activated (play thread joined)\n" ); 153 wait until the play thread reach a 'safe state'
140 } 154 (that is, when amidiplug_play_thread exists) */
141 else if ( amidiplug_playing_status == AMIDIPLUG_PAUSE ) 155 while ( !amidiplug_play_thread )
142 { 156 g_usleep( 20000 );
143 amidiplug_playing_status = AMIDIPLUG_STOP; 157 }
144 DEBUGMSG( "STOP activated (from PAUSE to STOP)\n" ); 158
145 pthread_mutex_unlock( &amidiplug_playing_mutex ); 159 g_mutex_lock( amidiplug_playing_mutex );
146 } 160 amidiplug_playing_status = AMIDIPLUG_STOP;
147 else /* AMIDIPLUG_ERR */ 161 g_cond_signal( amidiplug_pause_cond );
148 { 162 g_mutex_unlock( amidiplug_playing_mutex );
149 DEBUGMSG( "STOP activated (in error handling, ok)\n" ); 163 if ( amidiplug_play_thread )
150 pthread_mutex_unlock( &amidiplug_playing_mutex ); 164 {
151 } 165 g_thread_join( amidiplug_play_thread );
166 amidiplug_play_thread = NULL;
167 }
168 if (( backend.autonomous_audio == FALSE ) && ( amidiplug_audio_thread ))
169 {
170 g_thread_join( amidiplug_audio_thread );
171 amidiplug_audio_thread = NULL;
172 }
173 DEBUGMSG( "STOP activated (play thread joined)\n" );
152 174
153 /* kill the sequencer (while it may have been already killed if coming 175 /* kill the sequencer (while it may have been already killed if coming
154 from pause, it's safe to do anyway since it checks for multiple calls) */ 176 from pause, it's safe to do anyway since it checks for multiple calls) */
155 if ( backend.gmodule != NULL ) 177 if ( backend.gmodule != NULL )
156 backend.seq_off(); 178 backend.seq_off();
174 196
175 static void amidiplug_pause( InputPlayback * playback, gshort paused ) 197 static void amidiplug_pause( InputPlayback * playback, gshort paused )
176 { 198 {
177 if ( paused ) 199 if ( paused )
178 { 200 {
201 g_mutex_lock( amidiplug_playing_mutex );
202 if ( amidiplug_playing_status == AMIDIPLUG_SEEK )
203 {
204 DEBUGMSG( "handle SEEK ON PAUSE situation\n" , midifile.playing_tick );
205 /* uh oh, we have a pending seek; this can happen when a seek
206 is requested while playback is paused; wait for that seek to
207 be completed before pausing the song again */
208 while ( amidiplug_playing_status != AMIDIPLUG_PLAY )
209 g_cond_wait( amidiplug_seekonpause_cond , amidiplug_playing_mutex );
210 }
211 g_mutex_unlock( amidiplug_playing_mutex );
179 DEBUGMSG( "PAUSE request at tick: %i\n" , midifile.playing_tick ); 212 DEBUGMSG( "PAUSE request at tick: %i\n" , midifile.playing_tick );
180 pthread_mutex_lock( &amidiplug_playing_mutex ); 213 g_mutex_lock( amidiplug_playing_mutex );
181 /* this cond is used to avoid race conditions */
182 while ( amidiplug_playing_status != AMIDIPLUG_PLAY )
183 pthread_cond_wait( &amidiplug_playing_cond , &amidiplug_playing_mutex );
184 amidiplug_playing_status = AMIDIPLUG_PAUSE; 214 amidiplug_playing_status = AMIDIPLUG_PAUSE;
185 pthread_mutex_unlock( &amidiplug_playing_mutex ); 215 g_mutex_unlock( amidiplug_playing_mutex );
186
187 pthread_join( amidiplug_play_thread , NULL );
188 if ( backend.autonomous_audio == FALSE )
189 pthread_join( amidiplug_audio_thread , NULL );
190 DEBUGMSG( "PAUSE activated (play thread joined)\n" , midifile.playing_tick );
191
192 if ( backend.autonomous_audio == FALSE ) 216 if ( backend.autonomous_audio == FALSE )
193 playback->output->pause(paused); 217 playback->output->pause(paused);
194
195 /* kill the sequencer */
196 backend.seq_off();
197 } 218 }
198 else 219 else
199 { 220 {
200 DEBUGMSG( "PAUSE deactivated, returning to tick %i\n" , midifile.playing_tick ); 221 DEBUGMSG( "PAUSE deactivated, resume playing from tick %i\n" , midifile.playing_tick );
201 /* revive the sequencer */
202 backend.seq_on();
203 /* re-set initial tempo */
204 i_midi_setget_tempo( &midifile );
205 backend.seq_queue_tempo( midifile.current_tempo , midifile.ppq );
206 /* get back to the previous state */
207 amidiplug_skipto( midifile.playing_tick );
208
209 if ( backend.autonomous_audio == FALSE ) 222 if ( backend.autonomous_audio == FALSE )
210 playback->output->pause(paused); 223 playback->output->pause(paused);
211 224 g_mutex_lock( amidiplug_playing_mutex );
212 pthread_mutex_lock( &amidiplug_playing_mutex ); 225 amidiplug_playing_status = AMIDIPLUG_PLAY;
213 /* play play play! */ 226 g_cond_signal( amidiplug_pause_cond );
214 DEBUGMSG( "PAUSE deactivated, starting play thread again\n" ); 227 /* wait for unpause operation to be completed */
215 pthread_create(&amidiplug_play_thread, NULL, amidiplug_play_loop, playback); 228 g_cond_wait( amidiplug_pause_cond , amidiplug_playing_mutex );
216 /* this cond is used to avoid race conditions */ 229 g_mutex_unlock( amidiplug_playing_mutex );
217 while ( amidiplug_playing_status != AMIDIPLUG_PLAY )
218 pthread_cond_wait( &amidiplug_playing_cond , &amidiplug_playing_mutex );
219 pthread_mutex_unlock( &amidiplug_playing_mutex );
220 } 230 }
221 } 231 }
222 232
223 233
224 static void amidiplug_seek( InputPlayback * playback, gint time ) 234 static void amidiplug_seek( InputPlayback * playback, gint time )
225 { 235 {
226 DEBUGMSG( "SEEK requested (time %i), pausing song...\n" , time ); 236 DEBUGMSG( "SEEK requested (time %i)...\n" , time );
227 pthread_mutex_lock( &amidiplug_playing_mutex ); 237 g_mutex_lock( amidiplug_playing_mutex );
228 /* this cond is used to avoid race conditions */ 238 midifile.seeking_tick = (gint)((time * 1000000) / midifile.avg_microsec_per_tick);
229 while ( amidiplug_playing_status != AMIDIPLUG_PLAY ) 239 amidiplug_playing_status = AMIDIPLUG_SEEK;
230 pthread_cond_wait( &amidiplug_playing_cond , &amidiplug_playing_mutex ); 240 g_mutex_unlock( amidiplug_playing_mutex );
231 amidiplug_playing_status = AMIDIPLUG_PAUSE;
232 pthread_mutex_unlock( &amidiplug_playing_mutex );
233
234 pthread_join( amidiplug_play_thread , NULL );
235 if ( backend.autonomous_audio == FALSE )
236 pthread_join( amidiplug_audio_thread , NULL );
237 DEBUGMSG( "SEEK requested (time %i), song paused\n" , time );
238 /* kill the sequencer */
239 backend.seq_off();
240 /* revive the sequencer */
241 backend.seq_on();
242 /* re-set initial tempo */
243 i_midi_setget_tempo( &midifile );
244 backend.seq_queue_tempo( midifile.current_tempo , midifile.ppq );
245 /* get back to the previous state */
246 DEBUGMSG( "SEEK requested (time %i), moving to tick %i of %i\n" ,
247 time , (gint)((time * 1000000) / midifile.avg_microsec_per_tick) , midifile.max_tick );
248 midifile.playing_tick = (gint)((time * 1000000) / midifile.avg_microsec_per_tick);
249 amidiplug_skipto( midifile.playing_tick );
250 241
251 if ( backend.autonomous_audio == FALSE ) 242 if ( backend.autonomous_audio == FALSE )
252 playback->output->flush(time * 1000); 243 playback->output->flush(time * 1000);
253
254 /* play play play! */
255 DEBUGMSG( "SEEK done, starting play thread again\n" );
256 pthread_create(&amidiplug_play_thread, NULL, amidiplug_play_loop, playback);
257 } 244 }
258 245
259 246
260 static gint amidiplug_get_time( InputPlayback *playback ) 247 static gint amidiplug_get_time( InputPlayback *playback )
261 { 248 {
262 if ( backend.autonomous_audio == FALSE ) 249 if ( backend.autonomous_audio == FALSE )
263 { 250 {
264 pthread_mutex_lock( &amidiplug_playing_mutex ); 251 g_mutex_lock( amidiplug_playing_mutex );
265 if (( amidiplug_playing_status == AMIDIPLUG_PLAY ) || 252 if (( amidiplug_playing_status == AMIDIPLUG_PLAY ) ||
266 ( amidiplug_playing_status == AMIDIPLUG_PAUSE ) || 253 ( amidiplug_playing_status == AMIDIPLUG_PAUSE ) ||
254 ( amidiplug_playing_status == AMIDIPLUG_SEEK ) ||
267 (( amidiplug_playing_status == AMIDIPLUG_STOP ) && ( playback->output->buffer_playing() ))) 255 (( amidiplug_playing_status == AMIDIPLUG_STOP ) && ( playback->output->buffer_playing() )))
268 { 256 {
269 pthread_mutex_unlock( &amidiplug_playing_mutex ); 257 g_mutex_unlock( amidiplug_playing_mutex );
270 return playback->output->output_time(); 258 return playback->output->output_time();
271 } 259 }
272 else if ( amidiplug_playing_status == AMIDIPLUG_STOP ) 260 else if ( amidiplug_playing_status == AMIDIPLUG_STOP )
273 { 261 {
274 pthread_mutex_unlock( &amidiplug_playing_mutex ); 262 g_mutex_unlock( amidiplug_playing_mutex );
275 DEBUGMSG( "GETTIME on stopped song, returning -1\n" , time ); 263 DEBUGMSG( "GETTIME on stopped song, returning -1\n" , time );
276 return -1; 264 return -1;
277 } 265 }
278 else /* AMIDIPLUG_ERR */ 266 else /* AMIDIPLUG_ERR */
279 { 267 {
280 pthread_mutex_unlock( &amidiplug_playing_mutex ); 268 g_mutex_unlock( amidiplug_playing_mutex );
281 DEBUGMSG( "GETTIME on halted song (an error occurred?), returning -1 and stopping the player\n" ); 269 DEBUGMSG( "GETTIME on halted song (an error occurred?), returning -1 and stopping the player\n" );
282 audacious_drct_stop(); 270 audacious_drct_stop();
283 return -1; 271 return -1;
284 } 272 }
285 } 273 }
286 else 274 else
287 { 275 {
288 gint pt; 276 gint pt;
289 pthread_mutex_lock( &amidiplug_playing_mutex ); 277 g_mutex_lock( amidiplug_playing_mutex );
290 if (( amidiplug_playing_status == AMIDIPLUG_PLAY ) || 278 if (( amidiplug_playing_status == AMIDIPLUG_PLAY ) ||
291 ( amidiplug_playing_status == AMIDIPLUG_PAUSE )) 279 ( amidiplug_playing_status == AMIDIPLUG_PAUSE ) ||
292 { 280 ( amidiplug_playing_status == AMIDIPLUG_SEEK ))
293 pthread_mutex_unlock( &amidiplug_playing_mutex ); 281 {
294 pthread_mutex_lock(&amidiplug_gettime_mutex); 282 g_mutex_unlock( amidiplug_playing_mutex );
283 g_mutex_lock( amidiplug_gettime_mutex );
295 pt = midifile.playing_tick; 284 pt = midifile.playing_tick;
296 pthread_mutex_unlock(&amidiplug_gettime_mutex); 285 g_mutex_unlock( amidiplug_gettime_mutex );
297 return (gint)((pt * midifile.avg_microsec_per_tick) / 1000); 286 return (gint)((pt * midifile.avg_microsec_per_tick) / 1000);
298 } 287 }
299 else if ( amidiplug_playing_status == AMIDIPLUG_STOP ) 288 else if ( amidiplug_playing_status == AMIDIPLUG_STOP )
300 { 289 {
301 pthread_mutex_unlock( &amidiplug_playing_mutex ); 290 g_mutex_unlock( amidiplug_playing_mutex );
302 DEBUGMSG( "GETTIME on stopped song, returning -1\n" , time ); 291 DEBUGMSG( "GETTIME on stopped song, returning -1\n" , time );
303 return -1; 292 return -1;
304 } 293 }
305 else /* AMIDIPLUG_ERR */ 294 else /* AMIDIPLUG_ERR */
306 { 295 {
307 pthread_mutex_unlock( &amidiplug_playing_mutex ); 296 g_mutex_unlock( amidiplug_playing_mutex );
308 DEBUGMSG( "GETTIME on halted song (an error occurred?), returning -1 and stopping the player\n" , time ); 297 DEBUGMSG( "GETTIME on halted song (an error occurred?), returning -1 and stopping the player\n" , time );
309 audacious_drct_stop(); 298 audacious_drct_stop();
310 return -1; 299 return -1;
311 } 300 }
312 } 301 }
473 (gint)(midifile.length / 1000) , 462 (gint)(midifile.length / 1000) ,
474 au_bitdepth * au_samplerate * au_channels / 8 , 463 au_bitdepth * au_samplerate * au_channels / 8 ,
475 au_samplerate , au_channels ); 464 au_samplerate , au_channels );
476 g_free( filename ); 465 g_free( filename );
477 466
467 /* done with file */
468 VFS_FCLOSE( midifile.file_pointer );
469 midifile.file_pointer = NULL;
470
478 /* play play play! */ 471 /* play play play! */
479 DEBUGMSG( "PLAY requested, starting play thread\n" ); 472 DEBUGMSG( "PLAY requested, starting play thread\n" );
473 g_mutex_lock( amidiplug_playing_mutex );
480 amidiplug_playing_status = AMIDIPLUG_PLAY; 474 amidiplug_playing_status = AMIDIPLUG_PLAY;
481 pthread_create(&amidiplug_play_thread, NULL, amidiplug_play_loop, playback); 475 g_mutex_unlock( amidiplug_playing_mutex );
476 amidiplug_play_thread = g_thread_self();
477 amidiplug_play_loop(playback);
482 break; 478 break;
483 } 479 }
484 480
485 default: 481 default:
486 { 482 {
488 g_warning( "%s is not a Standard MIDI File\n" , filename_uri ); 484 g_warning( "%s is not a Standard MIDI File\n" , filename_uri );
489 break; 485 break;
490 } 486 }
491 } 487 }
492 488
493 VFS_FCLOSE( midifile.file_pointer ); 489 if ( midifile.file_pointer )
494 } 490 {
495 491 /* done with file */
496 492 VFS_FCLOSE( midifile.file_pointer );
497 493 midifile.file_pointer = NULL;
498 void * amidiplug_play_loop( void * arg ) 494 }
495 }
496
497
498
499 gpointer amidiplug_play_loop( gpointer arg )
499 { 500 {
500 InputPlayback *playback = arg; 501 InputPlayback *playback = arg;
501 gint i = 0; 502 gint j = 0;
502 gboolean rewind = FALSE; 503 gboolean rewind = TRUE;
503
504 pthread_mutex_lock( &amidiplug_playing_mutex );
505 if ( amidiplug_playing_status != AMIDIPLUG_PAUSE )
506 {
507 DEBUGMSG( "PLAY thread, rewind tracks to their first event\n" );
508 rewind = TRUE;
509 }
510 else
511 {
512 DEBUGMSG( "PLAY thread, do not rewind tracks to their first event (coming from a PAUSE status)\n" );
513 amidiplug_playing_status = AMIDIPLUG_PLAY;
514 pthread_cond_signal( &amidiplug_playing_cond );
515 }
516 pthread_mutex_unlock( &amidiplug_playing_mutex );
517 504
518 if ( rewind ) 505 if ( rewind )
519 { 506 {
520 /* initialize current position in each track */ 507 /* initialize current position in each track */
521 for (i = 0; i < midifile.num_tracks; ++i) 508 for (j = 0; j < midifile.num_tracks; ++j)
522 midifile.tracks[i].current_event = midifile.tracks[i].first_event; 509 midifile.tracks[j].current_event = midifile.tracks[j].first_event;
523 backend.seq_queue_start();
524 } 510 }
525 511
526 if ( backend.autonomous_audio == FALSE ) 512 if ( backend.autonomous_audio == FALSE )
527 { 513 amidiplug_audio_thread = g_thread_create(amidiplug_audio_loop, playback, TRUE, NULL);
528 pthread_create(&amidiplug_audio_thread, NULL, amidiplug_audio_loop, playback); 514
529 } 515 /* queue start */
530 516 backend.seq_queue_start();
531 /* common settings for all our events */ 517 /* common settings for all our events */
532 backend.seq_event_init(); 518 backend.seq_event_init();
533 519
534 DEBUGMSG( "PLAY thread, start the play loop\n" ); 520 DEBUGMSG( "PLAY thread, start the play loop\n" );
535 for (;;) 521 for (;;)
536 { 522 {
537 midievent_t * event = NULL; 523 midievent_t * event = NULL;
538 midifile_track_t * event_track = NULL; 524 midifile_track_t * event_track = NULL;
539 gint i, min_tick = midifile.max_tick + 1; 525 gint i, min_tick = midifile.max_tick + 1;
526
527 /* check if the song has been paused/seeked/stopped */
528 g_mutex_lock( amidiplug_playing_mutex );
529 if ( amidiplug_playing_status != AMIDIPLUG_PLAY )
530 {
531 DEBUGMSG( "PLAY thread, PAUSE/SEEK/STOP requested, handle in play loop\n" );
532 if ( amidiplug_playing_status == AMIDIPLUG_PAUSE )
533 {
534 DEBUGMSG( "PLAY thread, PAUSE requested, shut notes and make the play loop wait\n" );
535 backend.seq_event_allnoteoff( midifile.playing_tick );
536 backend.seq_queue_stop();
537 while (( amidiplug_playing_status != AMIDIPLUG_PLAY ) &&
538 ( amidiplug_playing_status != AMIDIPLUG_STOP ))
539 g_cond_wait( amidiplug_pause_cond , amidiplug_playing_mutex );
540 DEBUGMSG( "PLAY thread, UNPAUSE requested, resume playing\n" );
541 g_mutex_lock( amidiplug_gettime_mutex );
542 midifile.skip_offset = midifile.playing_tick;
543 g_mutex_unlock( amidiplug_gettime_mutex );
544 if ( backend.autonomous_audio == FALSE )
545 amidiplug_audio_thread = g_thread_create(amidiplug_audio_loop, playback, TRUE, NULL);
546 backend.seq_queue_start();
547 g_cond_signal( amidiplug_pause_cond );
548 }
549 if ( amidiplug_playing_status == AMIDIPLUG_SEEK )
550 {
551 backend.seq_event_allnoteoff( midifile.playing_tick );
552 backend.seq_queue_stop();
553 amidiplug_skipto( midifile.seeking_tick );
554 midifile.seeking_tick = -1;
555 amidiplug_playing_status = AMIDIPLUG_PLAY;
556 g_cond_signal( amidiplug_seekonpause_cond );
557 }
558 if ( amidiplug_playing_status == AMIDIPLUG_STOP )
559 {
560 DEBUGMSG( "PLAY thread, STOP requested, stopping...\n" );
561 g_mutex_unlock( amidiplug_playing_mutex );
562 break; /* exit from the for (;;) loop */
563 }
564 }
565 g_mutex_unlock( amidiplug_playing_mutex );
540 566
541 /* search next event */ 567 /* search next event */
542 for (i = 0; i < midifile.num_tracks; ++i) 568 for (i = 0; i < midifile.num_tracks; ++i)
543 { 569 {
544 midifile_track_t * track = &midifile.tracks[i]; 570 midifile_track_t * track = &midifile.tracks[i];
549 event = e2; 575 event = e2;
550 event_track = track; 576 event_track = track;
551 } 577 }
552 } 578 }
553 579
554 /* check if the song has been stopped */
555 pthread_mutex_lock( &amidiplug_playing_mutex );
556 if ( amidiplug_playing_status != AMIDIPLUG_PLAY )
557 {
558 DEBUGMSG( "PLAY thread, PAUSE or STOP requested, exiting from play loop\n" );
559 event = NULL;
560 }
561 pthread_mutex_unlock( &amidiplug_playing_mutex );
562
563 if (!event) 580 if (!event)
564 break; /* end of song reached */ 581 break; /* end of song reached */
565 582
566 /* advance pointer to next event */ 583 /* advance pointer to next event */
567 event_track->current_event = event->next; 584 event_track->current_event = event->next;
597 break; 614 break;
598 case SND_SEQ_EVENT_TEMPO: 615 case SND_SEQ_EVENT_TEMPO:
599 backend.seq_event_tempo( event ); 616 backend.seq_event_tempo( event );
600 DEBUGMSG( "PLAY thread, processing tempo event with value %i on tick %i\n" , 617 DEBUGMSG( "PLAY thread, processing tempo event with value %i on tick %i\n" ,
601 event->data.tempo , event->tick ); 618 event->data.tempo , event->tick );
602 pthread_mutex_lock(&amidiplug_gettime_mutex); 619 g_mutex_lock( amidiplug_gettime_mutex );
603 midifile.current_tempo = event->data.tempo; 620 midifile.current_tempo = event->data.tempo;
604 pthread_mutex_unlock(&amidiplug_gettime_mutex); 621 g_mutex_unlock( amidiplug_gettime_mutex );
605 break; 622 break;
606 case SND_SEQ_EVENT_META_TEXT: 623 case SND_SEQ_EVENT_META_TEXT:
607 /* do nothing */ 624 /* do nothing */
608 break; 625 break;
609 case SND_SEQ_EVENT_META_LYRIC: 626 case SND_SEQ_EVENT_META_LYRIC:
612 default: 629 default:
613 DEBUGMSG( "PLAY thread, encountered invalid event type %i\n" , event->type ); 630 DEBUGMSG( "PLAY thread, encountered invalid event type %i\n" , event->type );
614 break; 631 break;
615 } 632 }
616 633
617 pthread_mutex_lock(&amidiplug_gettime_mutex); 634 g_mutex_lock( amidiplug_gettime_mutex );
618 midifile.playing_tick = event->tick; 635 midifile.playing_tick = event->tick;
619 pthread_mutex_unlock(&amidiplug_gettime_mutex); 636 g_mutex_unlock( amidiplug_gettime_mutex );
620 637
621 if ( backend.autonomous_audio == TRUE ) 638 if ( backend.autonomous_audio == TRUE )
622 { 639 {
623 /* these backends deal with audio production themselves (i.e. ALSA) */ 640 /* these backends deal with audio production themselves (i.e. ALSA) */
624 backend.seq_output( NULL , NULL ); 641 backend.seq_output( NULL , NULL );
625 } 642 }
626 } 643 }
627 644
628 backend.seq_output_shut( midifile.max_tick , midifile.skip_offset ); 645 backend.seq_output_shut( midifile.max_tick , midifile.skip_offset );
629 646
630 pthread_mutex_lock( &amidiplug_playing_mutex ); 647 g_mutex_lock( amidiplug_playing_mutex );
631 if ( amidiplug_playing_status != AMIDIPLUG_PAUSE ) 648 if ( amidiplug_playing_status != AMIDIPLUG_PAUSE )
632 { 649 {
633 amidiplug_playing_status = AMIDIPLUG_STOP; 650 amidiplug_playing_status = AMIDIPLUG_STOP;
634 DEBUGMSG( "PLAY thread, song stopped/ended\n" ); 651 DEBUGMSG( "PLAY thread, song stopped/ended\n" );
635 } 652 }
636 pthread_mutex_unlock( &amidiplug_playing_mutex ); 653 g_mutex_unlock( amidiplug_playing_mutex );
637 654 return NULL;
638 pthread_exit(NULL);
639 } 655 }
640 656
641 657
642 /* amidigplug_skipto: re-do all events that influence the playing of our 658 /* amidigplug_skipto: re-do all events that influence the playing of our
643 midi file; re-do them using a time-tick of 0, so they are processed 659 midi file; re-do them using a time-tick of 0, so they are processed
722 case SND_SEQ_EVENT_SYSEX: 738 case SND_SEQ_EVENT_SYSEX:
723 backend.seq_event_sysex( event ); 739 backend.seq_event_sysex( event );
724 break; 740 break;
725 case SND_SEQ_EVENT_TEMPO: 741 case SND_SEQ_EVENT_TEMPO:
726 backend.seq_event_tempo( event ); 742 backend.seq_event_tempo( event );
727 pthread_mutex_lock(&amidiplug_gettime_mutex); 743 g_mutex_lock( amidiplug_gettime_mutex );
728 midifile.current_tempo = event->data.tempo; 744 midifile.current_tempo = event->data.tempo;
729 pthread_mutex_unlock(&amidiplug_gettime_mutex); 745 g_mutex_unlock( amidiplug_gettime_mutex );
730 break; 746 break;
731 } 747 }
732 748
733 if ( backend.autonomous_audio == TRUE ) 749 if ( backend.autonomous_audio == TRUE )
734 { 750 {
741 757
742 return; 758 return;
743 } 759 }
744 760
745 761
746 void * amidiplug_audio_loop( void * arg ) 762 gpointer amidiplug_audio_loop( gpointer arg )
747 { 763 {
748 InputPlayback *playback = arg; 764 InputPlayback *playback = arg;
749 gboolean going = 1; 765 gboolean going = 1;
750 gpointer buffer = NULL; 766 gpointer buffer = NULL;
751 gint buffer_size = 0; 767 gint buffer_size = 0;
756 while( ( playback->output->buffer_free() < buffer_size ) && ( going == TRUE ) ) 772 while( ( playback->output->buffer_free() < buffer_size ) && ( going == TRUE ) )
757 G_USLEEP(10000); 773 G_USLEEP(10000);
758 produce_audio( playback->output->written_time() , 774 produce_audio( playback->output->written_time() ,
759 FMT_S16_NE , 2 , buffer_size , buffer , &going ); 775 FMT_S16_NE , 2 , buffer_size , buffer , &going );
760 } 776 }
761 pthread_mutex_lock( &amidiplug_playing_mutex ); 777 g_mutex_lock( amidiplug_playing_mutex );
762 if ( amidiplug_playing_status != AMIDIPLUG_PLAY ) 778 if (( amidiplug_playing_status != AMIDIPLUG_PLAY ) &&
779 ( amidiplug_playing_status != AMIDIPLUG_SEEK ))
763 going = FALSE; 780 going = FALSE;
764 pthread_mutex_unlock( &amidiplug_playing_mutex ); 781 g_mutex_unlock( amidiplug_playing_mutex );
765 } 782 }
766 if ( buffer != NULL ) 783 if ( buffer != NULL )
767 g_free( buffer ); 784 g_free( buffer );
768 pthread_exit(NULL); 785 return NULL;
769 } 786 }