| @@ -7,6 +7,7 @@ namespace core { | |||
| struct CCMidiOutput : midi::Output { | |||
| int lastValues[128]; | |||
| int64_t timestamp = -1; | |||
| CCMidiOutput() { | |||
| reset(); | |||
| @@ -28,8 +29,13 @@ struct CCMidiOutput : midi::Output { | |||
| m.setStatus(0xb); | |||
| m.setNote(cc); | |||
| m.setValue(value); | |||
| m.timestamp = timestamp; | |||
| sendMessage(m); | |||
| } | |||
| void setTimestamp(int64_t timestamp) { | |||
| this->timestamp = timestamp; | |||
| } | |||
| }; | |||
| @@ -49,7 +55,7 @@ struct CV_CC : Module { | |||
| }; | |||
| CCMidiOutput midiOutput; | |||
| float rateLimiterPhase = 0.f; | |||
| dsp::Timer rateLimiterTimer; | |||
| int learningId = -1; | |||
| int learnedCcs[16] = {}; | |||
| @@ -70,14 +76,14 @@ struct CV_CC : Module { | |||
| } | |||
| 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; | |||
| } | |||
| midiOutput.setTimestamp(APP->engine->getFrameTime()); | |||
| for (int i = 0; i < 16; i++) { | |||
| int value = (int) std::round(inputs[CC_INPUTS + i].getVoltage() / 10.f * 127); | |||
| @@ -8,6 +8,7 @@ namespace core { | |||
| struct GateMidiOutput : midi::Output { | |||
| int vels[128]; | |||
| bool lastGates[128]; | |||
| int64_t timestamp = -1; | |||
| GateMidiOutput() { | |||
| reset(); | |||
| @@ -29,6 +30,7 @@ struct GateMidiOutput : midi::Output { | |||
| m.setStatus(0x8); | |||
| m.setNote(note); | |||
| m.setValue(0); | |||
| m.timestamp = timestamp; | |||
| sendMessage(m); | |||
| lastGates[note] = false; | |||
| } | |||
| @@ -45,6 +47,7 @@ struct GateMidiOutput : midi::Output { | |||
| m.setStatus(0x9); | |||
| m.setNote(note); | |||
| m.setValue(vels[note]); | |||
| m.timestamp = timestamp; | |||
| sendMessage(m); | |||
| } | |||
| else if (!gate && lastGates[note]) { | |||
| @@ -53,10 +56,15 @@ struct GateMidiOutput : midi::Output { | |||
| m.setStatus(0x8); | |||
| m.setNote(note); | |||
| m.setValue(vels[note]); | |||
| m.timestamp = timestamp; | |||
| sendMessage(m); | |||
| } | |||
| 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 { | |||
| midiOutput.setTimestamp(APP->engine->getFrameTime()); | |||
| for (int i = 0; i < 16; i++) { | |||
| int note = learnedNotes[i]; | |||
| if (velocityMode) { | |||
| @@ -93,21 +93,23 @@ struct CV_MIDI : Module { | |||
| 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; | |||
| midiOutput.setClock(clk); | |||
| @@ -560,10 +560,8 @@ void Engine::step(int frames) { | |||
| random::init(); | |||
| internal->stepFrame = internal->frame; | |||
| int64_t oldStepTime = internal->stepTime; | |||
| internal->stepTime = system::getNanoseconds(); | |||
| internal->stepFrames = frames; | |||
| DEBUG("time %ld", internal->stepTime - oldStepTime); | |||
| // Set sample rate | |||
| if (internal->sampleRate != settings::sampleRate) { | |||