@@ -29,7 +29,7 @@ struct CCMidiOutput : midi::Output { | |||||
m.setStatus(0xb); | m.setStatus(0xb); | ||||
m.setNote(cc); | m.setNote(cc); | ||||
m.setValue(value); | m.setValue(value); | ||||
m.frame = frame; | |||||
m.setFrame(frame); | |||||
sendMessage(m); | sendMessage(m); | ||||
} | } | ||||
@@ -83,7 +83,7 @@ struct CV_CC : Module { | |||||
else | else | ||||
return; | return; | ||||
midiOutput.setFrame(args.frame + APP->engine->getBlockFrames()); | |||||
midiOutput.setFrame(args.frame); | |||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
int value = (int) std::round(inputs[CC_INPUTS + i].getVoltage() / 10.f * 127); | int value = (int) std::round(inputs[CC_INPUTS + i].getVoltage() / 10.f * 127); | ||||
@@ -30,7 +30,7 @@ struct GateMidiOutput : midi::Output { | |||||
m.setStatus(0x8); | m.setStatus(0x8); | ||||
m.setNote(note); | m.setNote(note); | ||||
m.setValue(0); | m.setValue(0); | ||||
m.frame = frame; | |||||
m.setFrame(frame); | |||||
sendMessage(m); | sendMessage(m); | ||||
lastGates[note] = false; | lastGates[note] = false; | ||||
} | } | ||||
@@ -47,7 +47,7 @@ struct GateMidiOutput : midi::Output { | |||||
m.setStatus(0x9); | m.setStatus(0x9); | ||||
m.setNote(note); | m.setNote(note); | ||||
m.setValue(vels[note]); | m.setValue(vels[note]); | ||||
m.frame = frame; | |||||
m.setFrame(frame); | |||||
sendMessage(m); | sendMessage(m); | ||||
} | } | ||||
else if (!gate && lastGates[note]) { | else if (!gate && lastGates[note]) { | ||||
@@ -56,7 +56,7 @@ struct GateMidiOutput : midi::Output { | |||||
m.setStatus(0x8); | m.setStatus(0x8); | ||||
m.setNote(note); | m.setNote(note); | ||||
m.setValue(vels[note]); | m.setValue(vels[note]); | ||||
m.frame = frame; | |||||
m.setFrame(frame); | |||||
sendMessage(m); | sendMessage(m); | ||||
} | } | ||||
lastGates[note] = gate; | lastGates[note] = gate; | ||||
@@ -107,7 +107,7 @@ struct CV_Gate : Module { | |||||
} | } | ||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
midiOutput.setFrame(args.frame + APP->engine->getBlockFrames()); | |||||
midiOutput.setFrame(args.frame); | |||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
int note = learnedNotes[i]; | int note = learnedNotes[i]; | ||||
@@ -76,7 +76,7 @@ struct CV_MIDI : Module { | |||||
if (rateLimiterTriggered) | if (rateLimiterTriggered) | ||||
rateLimiterTimer.time -= rateLimiterPeriod; | rateLimiterTimer.time -= rateLimiterPeriod; | ||||
midiOutput.setFrame(args.frame + APP->engine->getBlockFrames()); | |||||
midiOutput.setFrame(args.frame); | |||||
for (int c = 0; c < inputs[PITCH_INPUT].getChannels(); c++) { | 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); | int vel = (int) std::round(inputs[VEL_INPUT].getNormalPolyVoltage(10.f * 100 / 127, c) / 10.f * 127); | ||||
@@ -173,7 +173,7 @@ struct MIDI_CV : Module { | |||||
} | } | ||||
void processMessage(const midi::Message& msg) { | 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()) { | switch (msg.getStatus()) { | ||||
// note off | // note off | ||||
@@ -55,14 +55,12 @@ void InputDevice::onMessage(const Message& message) { | |||||
contextSet(input->context); | contextSet(input->context); | ||||
// Set timestamp to now if unset | // Set timestamp to now if unset | ||||
if (message.frame < 0) { | |||||
if (message.getFrame() < 0) { | |||||
double deltaTime = system::getTime() - APP->engine->getBlockTime(); | 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 | // Filter channel if message is not a system MIDI message | ||||
@@ -282,7 +280,7 @@ static const size_t InputQueue_maxSize = 8192; | |||||
struct InputQueue_Compare { | struct InputQueue_Compare { | ||||
bool operator()(const Message& a, const Message& b) { | 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) { | bool InputQueue::tryPop(Message* messageOut, int64_t maxFrame) { | ||||
if (!internal->queue.empty()) { | if (!internal->queue.empty()) { | ||||
const Message& msg = internal->queue.top(); | const Message& msg = internal->queue.top(); | ||||
if (msg.frame <= maxFrame) { | |||||
if (msg.getFrame() <= maxFrame) { | |||||
*messageOut = msg; | *messageOut = msg; | ||||
internal->queue.pop(); | internal->queue.pop(); | ||||
return true; | 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. | // 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. | // 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(); | int futureFrames = 2 * APP->engine->getBlockFrames(); | ||||
if (msg.frame - maxFrame > futureFrames) { | |||||
if (msg.getFrame() - maxFrame > futureFrames) { | |||||
internal->queue.clear(); | internal->queue.clear(); | ||||
} | } | ||||
} | } | ||||
@@ -144,15 +144,18 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||||
void sendMessage(const midi::Message& message) override { | void sendMessage(const midi::Message& message) override { | ||||
// If frame is undefined, send message immediately | // If frame is undefined, send message immediately | ||||
if (message.frame < 0) { | |||||
if (message.getFrame() < 0) { | |||||
sendMessageNow(message); | sendMessageNow(message); | ||||
return; | return; | ||||
} | } | ||||
// Schedule message to be sent by worker thread | // Schedule message to be sent by worker thread | ||||
MessageSchedule ms; | MessageSchedule ms; | ||||
ms.message = message; | 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 | // 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; | ms.timestamp = APP->engine->getBlockTime() + deltaTime; | ||||
std::lock_guard<decltype(mutex)> lock(mutex); | std::lock_guard<decltype(mutex)> lock(mutex); | ||||