Skip to content

Commit cadfafb

Browse files
tatokissezero
authored andcommitted
native_midi_linux_alsa: Add support for System Exclusive messages
1 parent eb9619e commit cadfafb

File tree

1 file changed

+39
-7
lines changed

1 file changed

+39
-7
lines changed

src/codecs/native_midi/native_midi_linux_alsa.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
#include <string.h>
4343
#include <sys/stat.h>
4444

45+
#include <assert.h>
46+
4547
//#define SDL_NATIVE_MIDI_ALSA_DYNAMIC "libasound.so.2"
4648

4749
static int load_alsa_syms(void);
@@ -438,7 +440,7 @@ static NativeMidiSong *currentsong = NULL;
438440
NativeMidiSong *native_midi_loadsong_IO(SDL_IOStream *src, bool closeio)
439441
{
440442
NativeMidiSong *song;
441-
MIDIEvent *end;
443+
MIDIEvent *event;
442444
int sv[2];
443445

444446
if (!(song = SDL_calloc(1, sizeof(NativeMidiSong)))) {
@@ -455,7 +457,7 @@ NativeMidiSong *native_midi_loadsong_IO(SDL_IOStream *src, bool closeio)
455457
song->mainsock = sv[0];
456458
song->threadsock = sv[1];
457459

458-
end = song->evtlist = CreateMIDIEventList(src, &song->ppqn);
460+
event = song->evtlist = CreateMIDIEventList(src, &song->ppqn);
459461

460462
if (!song->evtlist) {
461463
close_sockpair(song);
@@ -464,6 +466,37 @@ NativeMidiSong *native_midi_loadsong_IO(SDL_IOStream *src, bool closeio)
464466
return NULL;
465467
}
466468

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+
467500
if (!(song->seq = open_seq(&song->srcport))) {
468501
FreeMIDIEventList(song->evtlist);
469502
close_sockpair(song);
@@ -478,11 +511,6 @@ NativeMidiSong *native_midi_loadsong_IO(SDL_IOStream *src, bool closeio)
478511

479512
SDL_SetAtomicInt(&song->playerstate, NATIVE_MIDI_STOPPED);
480513

481-
/* Find the last event to get its time */
482-
while (end->next)
483-
end = end->next;
484-
485-
song->endtime = end->time;
486514

487515
/* Since there's no reliable volume control solution it's better to leave the music playing instead of having hanging notes */
488516
song->allow_pause = SDL_GetHintBoolean("SDL_NATIVE_MUSIC_ALLOW_PAUSE", false);
@@ -692,6 +720,7 @@ static int native_midi_player_thread(void *d)
692720
const unsigned char channel = event->status & 0x0F;
693721

694722
snd_seq_ev_set_dest(&evt, song->dstaddr.client, song->dstaddr.port);
723+
snd_seq_ev_set_fixed(&evt);
695724
snd_seq_ev_schedule_tick(&evt, queue, 0, event->time);
696725

697726
bool unhandled = false;
@@ -733,6 +762,9 @@ static int native_midi_player_thread(void *d)
733762
snd_seq_ev_set_queue_tempo(&evt, queue, t);
734763
break;
735764
}
765+
} else if (event->status == MIDI_CMD_COMMON_SYSEX) {
766+
snd_seq_ev_set_sysex(&evt, event->extraLen, event->extraData);
767+
break;
736768
}
737769

738770
unhandled = true;

0 commit comments

Comments
 (0)