Skip to content

fluidsyX: resume macros waiting on keyOff/sampleEnd via FluidSynth voice callbacks#10

Draft
Copilot wants to merge 5 commits into
masterfrom
copilot/adopt-new-api-for-soundmacros
Draft

fluidsyX: resume macros waiting on keyOff/sampleEnd via FluidSynth voice callbacks#10
Copilot wants to merge 5 commits into
masterfrom
copilot/adopt-new-api-for-soundmacros

Conversation

Copy link
Copy Markdown

Copilot AI commented May 24, 2026

fluidsyX had no mechanism to detect voice noteoff or sample completion, so CmdWaitTicks with keyOff or sampleEnd flags would block macro execution indefinitely. FluidSynth PR #1778 (≥ 2.5.4) adds fluid_voice_set_callback with FLUID_VOICE_CALLBACK_NOTEOFF / FLUID_VOICE_CALLBACK_FINISHED reasons, enabling these signals.

Additionally, two pre-existing bugs in CmdWaitTicks::DoFluid prevented the wait from ever terminating even when conditions were met.

New: voice callback infrastructure (FLUID_VERSION_AT_LEAST(2, 5, 4))

  • VoiceCallbackData — carries app, macroId, voiceId (for self-removal from map on FINISHED), stored in a new std::map<unsigned int, VoiceCallbackData> voiceCallbacks on FluidsyXApp. std::map stable-reference guarantee makes passing &entry to FluidSynth safe across subsequent inserts.
  • voiceStateCallback — sets keyoffReceived on NOTEOFF, sampleEndReceived on FINISHED. For indefinite waits only (inIndefiniteWait), calls scheduleImmediateResume to unblock the macro via fluid_sequencer_send_now. Finite timed waits only get the flag set; their existing timers fire and check it. The FINISHED handler also erases the voiceCallbacks entry.
  • MacroExecContext::selfId — macroId is now pre-assigned in enqueueSoundMacro before the command loop and stored on the context, making it available inside dummy_preset_noteon (called synchronously from fluid_synth_start) when registering the callback.

Bug fixes in CmdWaitTicks::DoFluid

  • Missing ctx.pc++: both pre-checks (keyOff already received, sampleEnd already received) returned 0 without advancing the program counter, causing the outer loop to re-execute the same wait instruction forever.
  • if(v) guard on keyoff pre-check: after releaseVoice() sets ctx.voiceId = 0, findVoiceById returns nullptr and the pre-check was silently skipped. Fixed to treat v == nullptr as "not sustained":
// Before
if (v) {
    if (ctx.waitingKeyoff && ctx.keyoffReceived &&
        !fluid_voice_is_sustained(v) && !fluid_voice_is_sostenuto(v)) {
        ctx.waitingKeyoff = false;
        return 0;  // missing ctx.pc++
    }
}

// After
if (ctx.waitingKeyoff && ctx.keyoffReceived &&
    (!v || (!fluid_voice_is_sustained(v) && !fluid_voice_is_sostenuto(v)))) {
    ctx.waitingKeyoff = false;
    ctx.pc++;
    return 0;
}

Copilot AI changed the title fluidsyX: implement voice callbacks for keyOff/sampleEnd SoundMacro wait support fluidsyX: resume macros waiting on keyOff/sampleEnd via FluidSynth voice callbacks May 24, 2026
Copilot AI requested a review from derselbst May 24, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants