Add fluid_voice_set_callback() for voice lifecycle notifications#1778
Conversation
Implement a new public API function fluid_voice_set_callback() that allows applications to register a callback to be notified when: - A true noteoff is processed (FLUID_VOICE_CALLBACK_NOTEOFF) - The voice finishes playing and is removed from DSP (FLUID_VOICE_CALLBACK_FINISHED) Changes: - Add fluid_voice_callback_reason enum and fluid_voice_callback_t typedef to include/fluidsynth/voice.h - Add fluid_voice_set_callback() declaration to public header - Add callback/callback_data fields to struct _fluid_voice_t - Implement callback invocation in fluid_voice_release() and fluid_voice_stop() - Clear callback fields on voice re-initialization in fluid_voice_init() - Add unit test test_voice_callback.c Agent-Logs-Url: https://github.com/derselbst/fluidsynth/sessions/3c1d7aa5-1096-44d4-ae88-631b25ff90c3 Co-authored-by: derselbst <8152480+derselbst@users.noreply.github.com>
…ext API call Move finished voice processing into fluid_synth_render_blocks() right after fluid_rvoice_mixer_render() completes. This ensures the FINISHED callback fires as soon as the voice finishes rendering, regardless of whether any subsequent synth API call is made. Agent-Logs-Url: https://github.com/derselbst/fluidsynth/sessions/735fc152-b315-4555-a553-672d551927b3 Co-authored-by: derselbst <8152480+derselbst@users.noreply.github.com>
… thread The previous approach called fluid_synth_check_finished_voices() from fluid_synth_render_blocks(), which created two consumers on the SPSC finished_voices ringbuffer — a data race between the render thread and the API thread (in fluid_synth_api_enter). New approach: - Add finished callback fields to fluid_rvoice_t (function ptr, voice ptr, data) - Add fluid_rvoice_set_finished_callback() event function dispatched via the event queue from fluid_voice_set_callback() - Fire the FINISHED callback directly from the mixer's fluid_mixer_buffer_process_finished_voices() in the render thread, before pushing to the ringbuffer - Remove FINISHED callback from fluid_voice_stop() (now redundant) This maintains the SPSC invariant: the render thread is both the producer of finished voice notifications AND the invoker of the callback, while the API thread remains the sole consumer of the ringbuffer. Agent-Logs-Url: https://github.com/derselbst/fluidsynth/sessions/735fc152-b315-4555-a553-672d551927b3 Co-authored-by: derselbst <8152480+derselbst@users.noreply.github.com>
…safety Eliminate the intermediate trampoline that read voice->callback from the API-thread-owned fluid_voice_t. Instead, store the user's callback function pointer directly on the rvoice (ABI-compatible: void* vs fluid_voice_t*, int vs enum). This ensures the render thread only reads data from the rvoice (set via the event queue), never from the API-thread's fluid_voice_t. Agent-Logs-Url: https://github.com/derselbst/fluidsynth/sessions/735fc152-b315-4555-a553-672d551927b3 Co-authored-by: derselbst <8152480+derselbst@users.noreply.github.com>
|
@copilot SonarQube complains about too much code duplication in the newly added test/test_voice_callback.c. Pls. fix that for me, thanks. |
Agent-Logs-Url: https://github.com/FluidSynth/fluidsynth/sessions/8f0c89cb-66e9-4e4e-97bc-870c80534532 Co-authored-by: derselbst <8152480+derselbst@users.noreply.github.com>
Fixed in 68271c8. The three near-identical voicelist-scan-and-configure blocks are now consolidated into a |
|
|



Currently, apps using
fluid_synth_start()/fluid_synth_start_voice()have no way to know when afluid_voice_tor its ID becomes invalid — i.e. the voice may finish playing before even receiving a noteoff (e.g. short unlooped percussion samples). This adds a per-voice callback for two lifecycle events: true noteoff (release phase entered, not held by sustain/sostenuto) and voice finished (removed from DSP loop).Example Usage