Incorrect timestamps in midi events for external instrument plugins
DamRsn opened this issue · comments
Expected behaviour
Instrument plugins expect midi messages' timestamp to be relative to the start of the current processBlock
buffer.
Actual behaviour
In external plugins (at least), the midi messages are timestamped relatively to the start of the full audio sequence. This results in note_on
or note_off
messages that are never taken into account by the plugin because they happen at indices way larger than the bufferSize
.
With this code:
sample_rate = 44100
num_channels = 2
audio_out = my_plugin(
[mido.Message("note_on", note=60, time=0.5)],
sample_rate=sample_rate,
duration=5,
num_channels=num_channels
)
the plugin processBlock
will receive the note_on
message at index 22050
(44100 * 0.5
) and will thus never be played by the plugin (that has in my case a bufferSize
of 2048).
Steps to reproduce the behaviour
Load an instrument plugin and send midi messages at time different than 0. You should observe that nothing happens because most of the time, the timestamp of the event sent to the plugin is larger than the bufferSize
(notes not played (note_on
) or not stopped (note_off
)).
Fix
A simple fix I use is to replace
midiChunk.addEvents(midiInputBuffer, i, chunkSampleCount, 0);
by
midiChunk.addEvents(midiInputBuffer, i, chunkSampleCount, -i);
in ExternalPlugin::renderMIDIMessages()
: the sampleDeltaToAdd
is changed from 0
to -i
so that each midi event is timestamped according to the start of the current buffer and not that of the whole sequence.
Hi @DamRsn!
Great find! I've added a quick test to confirm this issue, but unfortunately I can't replicate exactly what you're seeing. In my tests, notes are received by the plugins; they're just effectively quantized to the nearest bufferSize
, which is still wrong and something that needs to be fixed. (I'm curious if there might be an implementation difference between the open-source plugin I'm using for test - specifically Magical8BitPlug2 - and the plugin you're testing with.)
Regardless, your fix looks good and I'll get that merged, add a test, and get a new deploy out. Thanks!
This has been fixed by #259 and released in v0.8.3, now live on PyPI.