Antoine, I was hoping you are listening :)
It is not quite clear to me why you need the system timer for scheduling those patterns, could you pls. elaborate? I would assume that you add a FLUID_SEQ_TIMER event to the synth and once you get the callback via fluid_event_callback_t you are provided with a timestamp by the sequencer. The timestamp currently comes from fluid_sequencer_get_tick(). Why does it matter that you need fluid_curtime() rather than currentMs which is provided by the synth?
seq->useSystemTimer ? (int) fluid_curtime() : fluid_atomic_int_get(&seq->currentMs);
> then we open ourselves up to bug reports where people ask: why does this (broken) MIDI file sound different in Fluidsynth than in almost all other MIDI players?
Not quite, because for now this change would be limited to the sequencer only, the fluid_player will be unchanged. The sequencer is a fluidsynth specific component, so I do believe that we have the freedom to tweak things here and there. So far I can't see any drawbacks of the event ordering I've proposed. And if we ever decide to make the fluid_player use the sequencer, we can just assign an alternative ordering function internally, that restores the FIFO ordering.
> Why would we need a deprecation period? Are you intending to change the behaviour or API of the sequencer?
I don't think an API change will be necessary. The deprecation just came to my mind because of the possible transition from C to C++.
> it surely can also be improved using an optimization of the current C implementation
The problem seems to be the heavy usage of linked lists. Lists have a poor cache performance. One would need to rewrite it using a contiguous container...
> Couldn't we simply implement that kind of heap/queue in C?
... we could. But I'm not a friend of adding yet another custom heap/queue implementation to the code base, when we can simply use one from a library.
[For the record, I'm appending Marcus' last mail below, which he mistakenly only sent to me]
10. Dezember 2019, 18:26:35 CET:
> Hi again,
> > > Why is "Note-On last" the better order? How do you know that that
> > > special (and seemingly Fluidsynth specific) ordering is what the author of
> > > the MIDI file wanted?
> > When something happens at the same tick, I don't claim to know anything.
> > My proposed solution is simply the best guess I can come up with in such a
> > situation. Two examples:
> > a) NoteOn and ProgChange happen in that order at the same tick. Would it
> > make sense to turn on the note using the old instrument, although we are
> > just about to receive a new program at the same tick? I don't think so. The
> > NoteOn, although first in the stream, should use the new program.
> > b) NoteOn at tick 0, after e.g. 100 ticks: NoteOn and NoteOff. All three
> > note events happen in the given order on the same channel and trigger the
> > same key. How would fluidsynth interpret them currently? The first note is
> > triggered, it sounds for a while until the second NoteOn arrives. That
> > second NoteOn kills overlapping notes, i.e. it kills the first note. But
> > oops, just after that second note was turned on, it will be turned off
> > right again, because we have a NoteOff at the same tick, which apparently
> > was meant to turn off the first note though.
> > For case b) I have MIDI files that do such things. Ofc you are right
> > Marcus, technically the MIDI converter program is to blame. I cannot really
> > change the converter though. I would alternatively need to handle those
> > cases in my program. I was just thinking of a possibly acceptable way for
> > fluidsynth to handle such "corner-cases".
> I understand where you are coming from and I share your pain. But the ugly
> truth is: MIDI events on the same tick don't have a defined order in the
> spec. The only real extra information that we have that might carry some
> extra information about the intention of the author of the file is the
> order of events in the stream. All other orderings are completely
> artificial and by definition non-standard. And as you mention that almost
> all MIDI players use the stream order in these cases, that comes close to a
> agreed solution by the community in my opinion. And we would have to have a
> real good reason not to go along with the established standard.
> If we implement our own ordering, then we open ourselves up to bug reports
> where people ask: why does this (broken) MIDI file sound different in
> Fluidsynth than in almost all other MIDI players? And responding with
> "because it's broken" doesn't really work, because it works in almost all
> other players.
> > > > 3. Simpler implementation?
> > > What trips me up though: if your program was really stuck in that loop
> > > for seconds, I'm wondering how many events you were actually adding to the
> > > sequencer... Millions?
> > I'm takling about ten-thousands of events. Here are some measurements:
> Wow, that's quite a difference, thanks for the info!
> > > > 5. The system timer
> > > isn't there a global timing event that MIDI devices can send to each
> > > other to synchronise playback position and playback speed?
> > You seem to refer to "System Real Time Messages". But I don't know how
> > this could be integrated into fluidsynth.
> On second thought, this is probably out of scope for Fluidsynth. And to be
> honest, I don't really understand why we have two timing sources.
> > > adding another implementation in C++ is not cleanup IMO... it adds more
> > > technological debt because we now have to keep two different
> > > implementations in sync.
> > Having two implementations would be temporarily. First add an
> > "experimental" C++ impl., then deprecate the current C implementation while
> > using the C++ impl. by default and finally remove the deprecated.
> Why would we need a deprecation period? Are you intending to change the
> behaviour or API of the sequencer?
> > > But I do wonder: what can C++ do that C can't? And especially: why can
> > > C++ do it faster?
> > Simply that I'm more familiar how to do those things in C++ rather than
> > with glib. And I'm not sure what Carlo, you, and the other embedded system
> > guys said, if we fortify the glib dependency. I'm not sure how they think
> > about a dependency to the C++ std lib either...
> I'm not worried about glib, but Carlo probably has quite a different
> opinion :-)
> If what I found online is correct, then std::priority_queue uses a max-heap
> structure to store the data, hence its speed. Couldn't we simply implement
> that kind of heap/queue in C? I'm sure there is tried and tested code
> around that we could simply adopt.