From 59facf4ced0cb3033e81ae2acfe624f078ab69ee Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 19 Aug 2021 19:12:33 -0400 Subject: [PATCH] Delay output MIDI message by an Engine block in the MIDI driver, instead of in CV-MIDI etc. --- src/core/CV_CC.cpp | 4 ++-- src/core/CV_Gate.cpp | 8 ++++---- src/core/CV_MIDI.cpp | 2 +- src/core/MIDI_CV.cpp | 2 +- src/midi.cpp | 18 ++++++++---------- src/rtmidi.cpp | 7 +++++-- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/core/CV_CC.cpp b/src/core/CV_CC.cpp index 80d704e3..deb2f3aa 100644 --- a/src/core/CV_CC.cpp +++ b/src/core/CV_CC.cpp @@ -29,7 +29,7 @@ struct CCMidiOutput : midi::Output { m.setStatus(0xb); m.setNote(cc); m.setValue(value); - m.frame = frame; + m.setFrame(frame); sendMessage(m); } @@ -83,7 +83,7 @@ struct CV_CC : Module { else return; - midiOutput.setFrame(args.frame + APP->engine->getBlockFrames()); + midiOutput.setFrame(args.frame); for (int i = 0; i < 16; i++) { int value = (int) std::round(inputs[CC_INPUTS + i].getVoltage() / 10.f * 127); diff --git a/src/core/CV_Gate.cpp b/src/core/CV_Gate.cpp index 43913748..e5924e94 100644 --- a/src/core/CV_Gate.cpp +++ b/src/core/CV_Gate.cpp @@ -30,7 +30,7 @@ struct GateMidiOutput : midi::Output { m.setStatus(0x8); m.setNote(note); m.setValue(0); - m.frame = frame; + m.setFrame(frame); sendMessage(m); lastGates[note] = false; } @@ -47,7 +47,7 @@ struct GateMidiOutput : midi::Output { m.setStatus(0x9); m.setNote(note); m.setValue(vels[note]); - m.frame = frame; + m.setFrame(frame); sendMessage(m); } else if (!gate && lastGates[note]) { @@ -56,7 +56,7 @@ struct GateMidiOutput : midi::Output { m.setStatus(0x8); m.setNote(note); m.setValue(vels[note]); - m.frame = frame; + m.setFrame(frame); sendMessage(m); } lastGates[note] = gate; @@ -107,7 +107,7 @@ struct CV_Gate : Module { } void process(const ProcessArgs& args) override { - midiOutput.setFrame(args.frame + APP->engine->getBlockFrames()); + midiOutput.setFrame(args.frame); for (int i = 0; i < 16; i++) { int note = learnedNotes[i]; diff --git a/src/core/CV_MIDI.cpp b/src/core/CV_MIDI.cpp index f1e2fb55..99385e1f 100644 --- a/src/core/CV_MIDI.cpp +++ b/src/core/CV_MIDI.cpp @@ -76,7 +76,7 @@ struct CV_MIDI : Module { if (rateLimiterTriggered) rateLimiterTimer.time -= rateLimiterPeriod; - midiOutput.setFrame(args.frame + APP->engine->getBlockFrames()); + midiOutput.setFrame(args.frame); for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); c++) { int vel = (int) std::round(inputs[VEL_INPUT].getNormalPolyVoltage(10.f * 100 / 127, c) / 10.f * 127); diff --git a/src/core/MIDI_CV.cpp b/src/core/MIDI_CV.cpp index c8792942..3c1d21de 100644 --- a/src/core/MIDI_CV.cpp +++ b/src/core/MIDI_CV.cpp @@ -173,7 +173,7 @@ struct MIDI_CV : Module { } void processMessage(const midi::Message& msg) { - // DEBUG("MIDI: %ld %s", msg.frame, msg.toString().c_str()); + // DEBUG("MIDI: %ld %s", msg.getFrame(), msg.toString().c_str()); switch (msg.getStatus()) { // note off diff --git a/src/midi.cpp b/src/midi.cpp index 155bdf82..8efa3e27 100644 --- a/src/midi.cpp +++ b/src/midi.cpp @@ -55,14 +55,12 @@ void InputDevice::onMessage(const Message& message) { contextSet(input->context); // Set timestamp to now if unset - if (message.frame < 0) { + if (message.getFrame() < 0) { double deltaTime = system::getTime() - APP->engine->getBlockTime(); - int deltaFrames = std::floor(deltaTime * APP->engine->getSampleRate()); - int64_t nextBlockFrame = APP->engine->getBlockFrame() + APP->engine->getBlockFrames(); - msg.frame = nextBlockFrame + deltaFrames; - } - else { - msg.frame = message.frame; + int64_t deltaFrames = std::floor(deltaTime * APP->engine->getSampleRate()); + // Delay message by current Engine block size + deltaFrames += APP->engine->getBlockFrames(); + msg.setFrame(APP->engine->getBlockFrame() + deltaFrames); } // Filter channel if message is not a system MIDI message @@ -282,7 +280,7 @@ static const size_t InputQueue_maxSize = 8192; struct InputQueue_Compare { bool operator()(const Message& a, const Message& b) { - return a.frame > b.frame; + return a.getFrame() > b.getFrame(); } }; @@ -319,7 +317,7 @@ void InputQueue::onMessage(const Message& message) { bool InputQueue::tryPop(Message* messageOut, int64_t maxFrame) { if (!internal->queue.empty()) { const Message& msg = internal->queue.top(); - if (msg.frame <= maxFrame) { + if (msg.getFrame() <= maxFrame) { *messageOut = msg; internal->queue.pop(); return true; @@ -328,7 +326,7 @@ bool InputQueue::tryPop(Message* messageOut, int64_t maxFrame) { // If next MIDI message is too far in the future, clear the queue. // This solves the issue of unconsumed messages getting stuck in the future when a DAW rewinds the engine frame. int futureFrames = 2 * APP->engine->getBlockFrames(); - if (msg.frame - maxFrame > futureFrames) { + if (msg.getFrame() - maxFrame > futureFrames) { internal->queue.clear(); } } diff --git a/src/rtmidi.cpp b/src/rtmidi.cpp index 3060984b..9a2631d6 100644 --- a/src/rtmidi.cpp +++ b/src/rtmidi.cpp @@ -144,15 +144,18 @@ struct RtMidiOutputDevice : midi::OutputDevice { void sendMessage(const midi::Message& message) override { // If frame is undefined, send message immediately - if (message.frame < 0) { + if (message.getFrame() < 0) { sendMessageNow(message); return; } // Schedule message to be sent by worker thread MessageSchedule ms; ms.message = message; + int64_t deltaFrames = message.getFrame() - APP->engine->getBlockFrame(); + // Delay message by current Engine block size + deltaFrames += APP->engine->getBlockFrames(); // Compute time in next Engine block to send message - double deltaTime = (message.frame - APP->engine->getBlockFrame()) * APP->engine->getSampleTime(); + double deltaTime = deltaFrames * APP->engine->getSampleTime(); ms.timestamp = APP->engine->getBlockTime() + deltaTime; std::lock_guard lock(mutex);