Files
RetroArch/midi/drivers
LibretroAdmin 36b9553fbf fmsynth: MIDI events queue for the renderer instead of racing it
Asked whether MIDI is on the threaded pipeline. It is, by inheritance:
the synth renders inside audio_driver_flush(), which the pipeline
consumer runs on the audio thread. But only the rendering moved.
fmsynth_midi_write() still applies a message straight into the voice
table from whichever thread the core calls it on - the frame - while
fmsynth_render() walks that same table on the audio thread, and there
is no synchronisation anywhere in the file.

Measured rather than argued: a core emitting a note on and a note off
every frame, under ThreadSanitizer, reports twenty-four distinct races
with the threaded pipeline on and none with it off. Every voice field,
the channel state, the allocator. Turning the pipeline on by default
turned that on for every core that uses MIDI.

Writes queue now and the renderer applies them at the top of the block
it is about to synthesise. The lock is held for the copy in and the
copy out and never across the synthesis, so a core writing a note is
never held for a render. Applying at a block boundary changes nothing
audible: the renderer already produced a whole block per call, so a
message arriving mid-block took effect at the next one either way.

A full queue drops the oldest rather than the newest, and says so once
per block: a dropped note-off leaves a voice sounding until its
envelope ends, a dropped note-on is silence nobody notices. 256
messages is a whole GM reset across sixteen channels and then some;
the test core never filled it.

Without HAVE_THREADS there is no lock and write() applies directly, as
before - correct on a build where the renderer runs on the caller's
thread.

Zero reports over four runs after, twenty-four before, and the notes
still arrive: 400 note-ons over 400 frames with the pipeline on and
off alike, no drops. ASan and LSan clean both ways, win32 syntax clean.
2026-09-05 01:56:10 +02:00
..
2025-07-10 05:59:06 +03:00