(I think this has discussed earlier but since I just upgraded to Tracktion Engine 2.0 I thought it might be justified to bring it up again.)
When starting playback (using transport.playSectionAndReset), often the first MIDI note is not played. It is probably some kind of race/timing issue since sometimes (in a seemingly random fashion) the note is played as expected.
Playing from an earlier position, such as a few milliseconds earlier, does not help in general, although backing up far enough (say 100 ms) works around the problem.
I noticed this thread:
but I don’t think this is the same problem. I tried logging incoming messages in the synth and the NoteOn of the first note never arrives (however the NoteOff arrives).
Ok, thanks, I built the DemoRunner using CMake and added a new example, attached below.
The code may look a bit weird since I tried to use the same chain as I use in my application (in particular loading the MIDI clip via a base64-encoded MIDI file).
Setup by loading the demo, press the “Create MIDI Clip” button and add a 4OSC synth to the track. Now, pressing the “Move to first note” button followed by “Play” reproduces the problem: the first note is sometimes played, sometimes not.
Ok, I think I’ve figured out what’s happening here and it’s multi-faceted.
Firstly, it’s to do with the 'createMessagesForTime` function which gets called when there is a break in playback continuity (e.g. when you press play). Here is the output of that function:
CREATE MSSAGE FOR TIME: 2.74656
Controller Volume (coarse): 100 Channel 1 - 0
Controller Pan position (coarse): 64 Channel 1 - 0
Controller Volume (fine): 42 Channel 1 - 0
Controller Pan position (fine): 0 Channel 1 - 0
Controller Bank Select: 0 Channel 1 - 2.74656
Controller Bank Select (fine): 0 Channel 1 - 2.74656
Program change 53 Channel 1 - 2.74656
Note on A#1 Velocity 100 Channel 1 - 0.0001
As you can see, all the CC messages are created and then the note-on message which if the first in the sequence. I imagine what is happening is that somewhere the buffer is getting iterated and once the timestamp is beyond the sample range for the buffer, the iteration stops, dropping the note-on at the end.
I could partially fix this by sorting the events so the note-on appears near the start, within the allowed time range… but I think the real fix is to create all the messages at the same time. I’ve added this now on the develop branch, can you check it out and see if it fixes your issues please?
This should also fix an issue where bank select and program change messages could be missed.
A side effect seems to be that if playback is started in the middle of a long note, that note is played as if it had its onset at the starting position. I don’t know if this is intentional but it feels a bit weird, at least for piano and other instruments with much attack.
I don’t see how it could work any other way though?
There’s no way in MIDI to say “start this note but not with a note-on message”.
It’s the only way to start long notes if you start them in the middle of the note. Otherwise they wouldn’t sound until the start of the note is played which would be a bit weird?
Hmm… you may be right… so would that mean that the reason that I thought otherwise is due to this bug always hitting me in the past??
A strange thing is that if I open the DemoRunner I built just before your fix, the MidiRecordingDemo has the behaviour you describe: starting in the middle of a note plays that note back. But my MidiPlaybackDemo does NOT do that! (I tried this by positioning the playhead with the mouse and then starting playback).
I thought it could have something to do with play vs playSectionAndReset but both examples start playback in the same way (using EngineHelpers::togglePlay which calls play).
Perhaps this is not so important and worth the time to dig into but I do find it strange that they behave differently!
I think it’s just that the MIDI sequences you were using had lots of CC messages in them which messed up the order to give you the bug described. Simpler sequences would have started in the middle of the note I believe.
Thanks for making a test case I could reproduce with!
It was indeed a tricky thing to track down, it took me all morning to understand what was going on.
Would you mind if I used that MIDI in a unit test in the repo?