mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
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.