@@ -7,6 +7,7 @@ namespace core { | |||||
struct CCMidiOutput : midi::Output { | struct CCMidiOutput : midi::Output { | ||||
int lastValues[128]; | int lastValues[128]; | ||||
int64_t timestamp = -1; | |||||
CCMidiOutput() { | CCMidiOutput() { | ||||
reset(); | reset(); | ||||
@@ -28,8 +29,13 @@ struct CCMidiOutput : midi::Output { | |||||
m.setStatus(0xb); | m.setStatus(0xb); | ||||
m.setNote(cc); | m.setNote(cc); | ||||
m.setValue(value); | m.setValue(value); | ||||
m.timestamp = timestamp; | |||||
sendMessage(m); | sendMessage(m); | ||||
} | } | ||||
void setTimestamp(int64_t timestamp) { | |||||
this->timestamp = timestamp; | |||||
} | |||||
}; | }; | ||||
@@ -49,7 +55,7 @@ struct CV_CC : Module { | |||||
}; | }; | ||||
CCMidiOutput midiOutput; | CCMidiOutput midiOutput; | ||||
float rateLimiterPhase = 0.f; | |||||
dsp::Timer rateLimiterTimer; | |||||
int learningId = -1; | int learningId = -1; | ||||
int learnedCcs[16] = {}; | int learnedCcs[16] = {}; | ||||
@@ -70,14 +76,14 @@ struct CV_CC : Module { | |||||
} | } | ||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
const float rateLimiterPeriod = 0.010f; | |||||
rateLimiterPhase += args.sampleTime / rateLimiterPeriod; | |||||
if (rateLimiterPhase >= 1.f) { | |||||
rateLimiterPhase -= 1.f; | |||||
} | |||||
else { | |||||
const float rateLimiterPeriod = 1 / 200.f; | |||||
bool rateLimiterTriggered = (rateLimiterTimer.process(args.sampleTime) >= rateLimiterPeriod); | |||||
if (rateLimiterTriggered) | |||||
rateLimiterTimer.time -= rateLimiterPeriod; | |||||
else | |||||
return; | return; | ||||
} | |||||
midiOutput.setTimestamp(APP->engine->getFrameTime()); | |||||
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); | ||||
@@ -8,6 +8,7 @@ namespace core { | |||||
struct GateMidiOutput : midi::Output { | struct GateMidiOutput : midi::Output { | ||||
int vels[128]; | int vels[128]; | ||||
bool lastGates[128]; | bool lastGates[128]; | ||||
int64_t timestamp = -1; | |||||
GateMidiOutput() { | GateMidiOutput() { | ||||
reset(); | reset(); | ||||
@@ -29,6 +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.timestamp = timestamp; | |||||
sendMessage(m); | sendMessage(m); | ||||
lastGates[note] = false; | lastGates[note] = false; | ||||
} | } | ||||
@@ -45,6 +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.timestamp = timestamp; | |||||
sendMessage(m); | sendMessage(m); | ||||
} | } | ||||
else if (!gate && lastGates[note]) { | else if (!gate && lastGates[note]) { | ||||
@@ -53,10 +56,15 @@ 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.timestamp = timestamp; | |||||
sendMessage(m); | sendMessage(m); | ||||
} | } | ||||
lastGates[note] = gate; | lastGates[note] = gate; | ||||
} | } | ||||
void setTimestamp(int64_t timestamp) { | |||||
this->timestamp = timestamp; | |||||
} | |||||
}; | }; | ||||
@@ -99,6 +107,8 @@ struct CV_Gate : Module { | |||||
} | } | ||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
midiOutput.setTimestamp(APP->engine->getFrameTime()); | |||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
int note = learnedNotes[i]; | int note = learnedNotes[i]; | ||||
if (velocityMode) { | if (velocityMode) { | ||||
@@ -93,21 +93,23 @@ struct CV_MIDI : Module { | |||||
midiOutput.setKeyPressure(aft, c); | midiOutput.setKeyPressure(aft, c); | ||||
} | } | ||||
int pw = (int) std::round((inputs[PW_INPUT].getVoltage() + 5.f) / 10.f * 0x4000); | |||||
pw = clamp(pw, 0, 0x3fff); | |||||
midiOutput.setPitchWheel(pw); | |||||
int mw = (int) std::round(inputs[MW_INPUT].getVoltage() / 10.f * 127); | |||||
mw = clamp(mw, 0, 127); | |||||
midiOutput.setModWheel(mw); | |||||
int vol = (int) std::round(inputs[VOL_INPUT].getNormalVoltage(10.f) / 10.f * 127); | |||||
vol = clamp(vol, 0, 127); | |||||
midiOutput.setVolume(vol); | |||||
int pan = (int) std::round((inputs[PAN_INPUT].getVoltage() + 5.f) / 10.f * 127); | |||||
pan = clamp(pan, 0, 127); | |||||
midiOutput.setPan(pan); | |||||
if (rateLimiterTriggered) { | |||||
int pw = (int) std::round((inputs[PW_INPUT].getVoltage() + 5.f) / 10.f * 0x4000); | |||||
pw = clamp(pw, 0, 0x3fff); | |||||
midiOutput.setPitchWheel(pw); | |||||
int mw = (int) std::round(inputs[MW_INPUT].getVoltage() / 10.f * 127); | |||||
mw = clamp(mw, 0, 127); | |||||
midiOutput.setModWheel(mw); | |||||
int vol = (int) std::round(inputs[VOL_INPUT].getNormalVoltage(10.f) / 10.f * 127); | |||||
vol = clamp(vol, 0, 127); | |||||
midiOutput.setVolume(vol); | |||||
int pan = (int) std::round((inputs[PAN_INPUT].getVoltage() + 5.f) / 10.f * 127); | |||||
pan = clamp(pan, 0, 127); | |||||
midiOutput.setPan(pan); | |||||
} | |||||
bool clk = inputs[CLK_INPUT].getVoltage() >= 1.f; | bool clk = inputs[CLK_INPUT].getVoltage() >= 1.f; | ||||
midiOutput.setClock(clk); | midiOutput.setClock(clk); | ||||
@@ -560,10 +560,8 @@ void Engine::step(int frames) { | |||||
random::init(); | random::init(); | ||||
internal->stepFrame = internal->frame; | internal->stepFrame = internal->frame; | ||||
int64_t oldStepTime = internal->stepTime; | |||||
internal->stepTime = system::getNanoseconds(); | internal->stepTime = system::getNanoseconds(); | ||||
internal->stepFrames = frames; | internal->stepFrames = frames; | ||||
DEBUG("time %ld", internal->stepTime - oldStepTime); | |||||
// Set sample rate | // Set sample rate | ||||
if (internal->sampleRate != settings::sampleRate) { | if (internal->sampleRate != settings::sampleRate) { | ||||