The proposed change is that incoming events will be pushed into the
sequencer queue by the midi thread, then popped and processed by the
audio thread. (The call stack for the audio thread would be:
fluid_synth_one_block -> fluid_sample_timer_process ->
fluid_sequencer_process -> fluid_seq_fluidsynth_callback ->
fluid_synth_noteon and friends)
However, if you say that Swami expects fluid_synth_t to be somewhat
thread-safe (just had a five-minute look a qsynth and at first glance it
seems to expect the same), perhaps it would be bad to enforce the
single-threaded synth at this point. Besides, I like the current idea of
starving the MIDI threads preferred to underrunning the audio in a
heavy-load situation. And that would break.
So the thread synchronization is limited to the sequencer. Here's the
suggested rules for using the sequencer in a thread-safe way:
- Only one thread at a time can call fluid_sequencer_process. This would
normally be the audio thread, via the sample timer callback.
- Any thread can call fluid_sequencer_send_at. The shortcut from
fluid_sequencer_send_at to fluid_sequencer_send_now is removed. This is
a subtle change of behavior but it is more consistent with the
documentation (i e "MAKES A COPY").
- fluid_sequencer_get_tick can be called from any thread (and should be
implemented with glib atomic integers).
- fluid_sequencer_send_now and fluid_sequencer_process are the only
public API calls that can result in midi events being sent. Midi events
are sent before the call returns and in the context of the calling
thread.
- Don't mess around with registering clients, or anything else, while
another thread makes a call to the sequencer.
A question would be whether this means we should leave up to the
libfluidsynth user to insert a sequencer in the midi processing chain,
or if we should create it automatically behind the scenes somehow (and
if so, what component should create it?). What do you think?
I don't think I fully understand this last bit. I guess all events
would go through the sequencer? If that were the case, I could see how
the fluid_synth_t would create it. Maybe even the fluid_synth_noteon
and friends could go through this?
Right. But if we were to go that way, perhaps we need all calls to go
through the sequencer, not only the ones that translate directly to a
midi event. Which probably means additional work.
My patch - in its current state - does not touch the synth. It changes
the sequencer according to the text above, and fluidsynth.c manually
inserts a sequencer between the midi router and the synth. So
libfluidsynth applications such as Swami and qsynth will neither suffer
or gain from this patch, unless they do the same.
What do you say if we leave it at that for the moment, I commit the
patch and we can all test it to see if we find any difference in latency
or stability when we use fluidsynth from the command line?
And at a later point in time we could review the synth threading a bit
more deep, to see if we can improve the situation (with regards to
segfaults, parallellization, stalls etc)?
// David