Skip to content

Commit

Permalink
native_midi: Send reset messages on track stop
Browse files Browse the repository at this point in the history
The ALSA device we're sending messages to will continue playing them
even if the program quits, and we don't want to leave notes hanging. So
when stopping the current track, send the "notes all off" and "reset all
controllers" messages to every channel, and also send an ALSA reset
event as well for good measure (the Timidity++ daemon seems to respond
to it)
  • Loading branch information
fragglet committed Sep 24, 2024
1 parent 5c10308 commit fe25166
Showing 1 changed file with 31 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/codecs/native_midi/native_midi_alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,34 @@ static void set_queue_tempo(Uint16 division)
}
}

static void send_reset(void)
{
static snd_seq_event_t alsa_ev;
int i;

snd_seq_ev_clear(&alsa_ev);
snd_seq_ev_set_source(&alsa_ev, local_port);
snd_seq_ev_set_subs(&alsa_ev);
snd_seq_ev_schedule_tick(&alsa_ev, output_queue, 0, 0);

// We send an ALSA reset event, but first send the standard MIDI control
// events to stop all notes on all channels, just in case.
for (i = 0; i < 16; i++) {
alsa_ev.type = SND_SEQ_EVENT_CONTROLLER;
snd_seq_ev_set_fixed(&alsa_ev);
alsa_ev.data.control.channel = i;
alsa_ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF;
alsa_ev.data.control.value = 0;
snd_seq_event_output(output, &alsa_ev);

alsa_ev.data.control.param = MIDI_CTL_RESET_CONTROLLERS;
snd_seq_event_output(output, &alsa_ev);
}

alsa_ev.type = SND_SEQ_EVENT_RESET;
snd_seq_event_output(output, &alsa_ev);
}

static int playback_thread(void *data)
{
NativeMidiSong *song = data;
Expand All @@ -219,6 +247,7 @@ static int playback_thread(void *data)
snd_seq_drop_output(output);
set_queue_tempo(song->division);
snd_seq_start_queue(output, output_queue, NULL);
send_reset();

while (state == PLAYING) {
if (ev == NULL) {
Expand Down Expand Up @@ -284,6 +313,8 @@ void native_midi_stop(void)
SDL_WaitThread(native_midi_thread, NULL);

snd_seq_drop_output(output);
send_reset();
snd_seq_drain_output(output);
snd_seq_stop_queue(output, output_queue, NULL);
}

Expand Down

0 comments on commit fe25166

Please sign in to comment.