42
42
#include <string.h>
43
43
#include <sys/stat.h>
44
44
45
+ #include <assert.h>
46
+
45
47
//#define SDL_NATIVE_MIDI_ALSA_DYNAMIC "libasound.so.2"
46
48
47
49
static int load_alsa_syms (void );
@@ -438,7 +440,7 @@ static NativeMidiSong *currentsong = NULL;
438
440
NativeMidiSong * native_midi_loadsong_IO (SDL_IOStream * src , bool closeio )
439
441
{
440
442
NativeMidiSong * song ;
441
- MIDIEvent * end ;
443
+ MIDIEvent * event ;
442
444
int sv [2 ];
443
445
444
446
if (!(song = SDL_calloc (1 , sizeof (NativeMidiSong )))) {
@@ -455,7 +457,7 @@ NativeMidiSong *native_midi_loadsong_IO(SDL_IOStream *src, bool closeio)
455
457
song -> mainsock = sv [0 ];
456
458
song -> threadsock = sv [1 ];
457
459
458
- end = song -> evtlist = CreateMIDIEventList (src , & song -> ppqn );
460
+ event = song -> evtlist = CreateMIDIEventList (src , & song -> ppqn );
459
461
460
462
if (!song -> evtlist ) {
461
463
close_sockpair (song );
@@ -464,6 +466,37 @@ NativeMidiSong *native_midi_loadsong_IO(SDL_IOStream *src, bool closeio)
464
466
return NULL ;
465
467
}
466
468
469
+ /* Since ALSA requires the starting F0 for SysEx, but MIDIEvent.extraData doesn't contain it, we must preprocess the list */
470
+ /* In addition, since we're going through the list, store the last event's time for looping purposes */
471
+ do {
472
+ /* Is this a SysEx? */
473
+ if (event -> status == MIDI_CMD_COMMON_SYSEX && event -> extraLen ) {
474
+ /* Sanity check in case something changes in the future */
475
+ /* This is safe to do since we can't have an F0 manufacturer ID */
476
+ assert (event -> extraData [0 ] != MIDI_CMD_COMMON_SYSEX );
477
+
478
+ /* Resize by + 1 */
479
+ Uint8 * newData = SDL_realloc (event -> extraData , event -> extraLen + 1 );
480
+ if (newData == NULL ) {
481
+ close_sockpair (song );
482
+ /* Original allocation is still valid on failure */
483
+ FreeMIDIEventList (song -> evtlist );
484
+ SDL_free (song );
485
+ MIDI_SET_ERROR ("Failed to preprocess MIDIEventList SysEx" );
486
+ return NULL ;
487
+ }
488
+
489
+ /* Prepend the F0 */
490
+ event -> extraData = newData ;
491
+ SDL_memmove (event -> extraData + 1 , event -> extraData , event -> extraLen );
492
+ event -> extraData [0 ] = MIDI_CMD_COMMON_SYSEX ;
493
+ event -> extraLen ++ ;
494
+ }
495
+
496
+ /* Store the end time */
497
+ song -> endtime = event -> time ;
498
+ } while ((event = event -> next ));
499
+
467
500
if (!(song -> seq = open_seq (& song -> srcport ))) {
468
501
FreeMIDIEventList (song -> evtlist );
469
502
close_sockpair (song );
@@ -478,11 +511,6 @@ NativeMidiSong *native_midi_loadsong_IO(SDL_IOStream *src, bool closeio)
478
511
479
512
SDL_SetAtomicInt (& song -> playerstate , NATIVE_MIDI_STOPPED );
480
513
481
- /* Find the last event to get its time */
482
- while (end -> next )
483
- end = end -> next ;
484
-
485
- song -> endtime = end -> time ;
486
514
487
515
/* Since there's no reliable volume control solution it's better to leave the music playing instead of having hanging notes */
488
516
song -> allow_pause = SDL_GetHintBoolean ("SDL_NATIVE_MUSIC_ALLOW_PAUSE" , false);
@@ -692,6 +720,7 @@ static int native_midi_player_thread(void *d)
692
720
const unsigned char channel = event -> status & 0x0F ;
693
721
694
722
snd_seq_ev_set_dest (& evt , song -> dstaddr .client , song -> dstaddr .port );
723
+ snd_seq_ev_set_fixed (& evt );
695
724
snd_seq_ev_schedule_tick (& evt , queue , 0 , event -> time );
696
725
697
726
bool unhandled = false;
@@ -733,6 +762,9 @@ static int native_midi_player_thread(void *d)
733
762
snd_seq_ev_set_queue_tempo (& evt , queue , t );
734
763
break ;
735
764
}
765
+ } else if (event -> status == MIDI_CMD_COMMON_SYSEX ) {
766
+ snd_seq_ev_set_sysex (& evt , event -> extraLen , event -> extraData );
767
+ break ;
736
768
}
737
769
738
770
unhandled = true;
0 commit comments