From 65681cab7b7859254c56bcf71fb7be84ffd62bf7 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 12 Oct 2017 11:40:06 +0200 Subject: [PATCH] Add midi clock module --- src/core/MidiInterface.cpp | 318 ++++++++++++++++++++++++++++++++++++- src/core/core.cpp | 1 + src/core/core.hpp | 5 + 3 files changed, 316 insertions(+), 8 deletions(-) diff --git a/src/core/MidiInterface.cpp b/src/core/MidiInterface.cpp index eef0c43f..4d13c2af 100644 --- a/src/core/MidiInterface.cpp +++ b/src/core/MidiInterface.cpp @@ -467,10 +467,6 @@ MidiToCVWidget::MidiToCVWidget() { } void MidiToCVWidget::step() { - // Assume QWERTY -#define MIDI_KEY(key, midi) if (glfwGetKey(gWindow, key)) printf("%d\n", midi); - - // MIDI_KEY(GLFW_KEY_Z, 48); ModuleWidget::step(); } @@ -702,10 +698,316 @@ MIDICCToCVWidget::MIDICCToCVWidget() { } void MIDICCToCVWidget::step() { - // Assume QWERTY -#define MIDI_KEY(key, midi) if (glfwGetKey(gWindow, key)) printf("%d\n", midi); - - // MIDI_KEY(GLFW_KEY_Z, 48); ModuleWidget::step(); } + +struct MIDIClockToCVInterface : MidiIO, Module { + enum ParamIds { + NUM_PARAMS + }; + enum InputIds { + NUM_INPUTS + }; + enum OutputIds { + CLOCK1_PULSE, + CLOCK2_PULSE, + CLOCK_START_PULSE, + CLOCK_STOP_PULSE, + NUM_OUTPUTS + }; + + int clock1ratio = 0; + int clock2ratio = 0; + + PulseGenerator clock1Pulse; + PulseGenerator clock2Pulse; + PulseGenerator clockStartPulse; + PulseGenerator clockStopPulse; + bool tick = false; + bool running = false; + bool start = false; + bool stop = false; + + MIDIClockToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { + (dynamic_cast(rtMidi))->ignoreTypes(true, false); + } + + ~MIDIClockToCVInterface() { + setPortId(-1); + } + + void step(); + + void processMidi(std::vector msg); + + virtual void resetMidi(); + + virtual json_t *toJson() { + json_t *rootJ = json_object(); + addBaseJson(rootJ); + return rootJ; + } + + virtual void fromJson(json_t *rootJ) { + baseFromJson(rootJ); + } + + virtual void initialize() { + setPortId(-1); + } + +}; + +void MIDIClockToCVInterface::step() { + static int c1_16th = 0; + static int c2_16th = 0; + + /* Note this is in relation to the Midi clock's Tick (6x per 16th note). + * Therefore, e.g. the 2:3 is calculated: + * + * 24 (Ticks per quarter note) * 2 / 3 = 16 + * + * Implying that every 16 midi clock ticks we need to send a pulse + * */ + static int ratios[] = {6, 8, 12, 16, 24, 32, 48, 96, 192}; + + if (rtMidi->isPortOpen()) { + std::vector message; + + // midiIn->getMessage returns empty vector if there are no messages in the queue + + dynamic_cast(rtMidi)->getMessage(&message); + while (message.size() > 0) { + processMidi(message); + dynamic_cast(rtMidi)->getMessage(&message); + } + + } + + if(start) { + clockStartPulse.trigger(0.1); + start=false; + c1_16th = 0; + c2_16th = 0; + } + + if(stop) { + clockStopPulse.trigger(0.1); + start=false; + } + + if (running && tick) { + tick = false; + c1_16th++; + c2_16th++; + + if (c1_16th % ratios[clock1ratio] == 0) { + c1_16th = 0; + clock1Pulse.trigger(0.1); + } + + if (c2_16th % ratios[clock2ratio] == 0) { + c2_16th = 0; + clock2Pulse.trigger(0.1); + } + } + + + bool pulse = clock1Pulse.process(1.0 / gSampleRate); + outputs[CLOCK1_PULSE].value = pulse ? 10.0 : 0.0; + + pulse = clock2Pulse.process(1.0 / gSampleRate); + outputs[CLOCK2_PULSE].value = pulse ? 10.0 : 0.0; + + pulse = clockStartPulse.process(1.0 / gSampleRate); + outputs[CLOCK_START_PULSE].value = pulse ? 10.0 : 0.0; + + pulse = clockStopPulse.process(1.0 / gSampleRate); + outputs[CLOCK_STOP_PULSE].value = pulse ? 10.0 : 0.0; + +} + +void MIDIClockToCVInterface::resetMidi() { + outputs[CLOCK1_PULSE].value = 0.0; +} + +void MIDIClockToCVInterface::processMidi(std::vector msg) { + + switch (msg[0]) { + case 0xfa: + start = true; + running = true; + break; + case 0xfc: + stop = true; + running = false; + break; + case 0xf8: + tick = true; + break; + } + + +} + +struct ClockRatioItem : MenuItem { + int ratio; + int *clockRatio; + + void onAction() { + *clockRatio = ratio; + } +}; + +struct ClockRatioChoice : ChoiceButton { + int *clockRatio; + const std::vector ratioNames = {"Sixteenth note (1:4 ratio)", "Eighth note triplet (1:3 ratio)", + "Eighth note (1:2 ratio)", "Quarter note triplet (2:3 ratio)", + "Quarter note (tap speed)", "Half note triplet (4:3 ratio)", + "Half note (2:1 ratio)", "Whole note (4:1 ratio)", + "Two whole notes (8:1 ratio)"}; + + const std::vector ratioNames_short = {"1:4 ratio", "1:3 ratio", "1:2 ratio", "2:3 ratio", "1:1 ratio", + "4:3", "2:1 ratio", "4:1 ratio", "8:1 ratio"}; + + void onAction() { + Menu *menu = gScene->createMenu(); + menu->box.pos = getAbsolutePos().plus(Vec(0, box.size.y)); + menu->box.size.x = box.size.x; + + for (int ratio = 0; ratio < ratioNames.size(); ratio++) { + ClockRatioItem *clockRatioItem = new ClockRatioItem(); + clockRatioItem->ratio = ratio; + clockRatioItem->clockRatio = clockRatio; + clockRatioItem->text = ratioNames[ratio]; + menu->pushChild(clockRatioItem); + } + } + + void step() { + text = ratioNames_short[*clockRatio]; + } +}; + +MIDIClockToCVWidget::MIDIClockToCVWidget() { + MIDIClockToCVInterface *module = new MIDIClockToCVInterface(); + setModule(module); + box.size = Vec(15 * 9, 380); + + { + Panel *panel = new LightPanel(); + panel->box.size = box.size; + addChild(panel); + } + + float margin = 5; + float labelHeight = 15; + float yPos = margin; + + addChild(createScrew(Vec(15, 0))); + addChild(createScrew(Vec(box.size.x - 30, 0))); + addChild(createScrew(Vec(15, 365))); + addChild(createScrew(Vec(box.size.x - 30, 365))); + + { + Label *label = new Label(); + label->box.pos = Vec(box.size.x - margin - 7 * 15, margin); + label->text = "MIDI Clock to CV"; + addChild(label); + yPos = labelHeight * 2; + } + + { + Label *label = new Label(); + label->box.pos = Vec(margin, yPos); + label->text = "MIDI Interface"; + addChild(label); + yPos += labelHeight + margin; + + MidiChoice *midiChoice = new MidiChoice(); + midiChoice->midiModule = dynamic_cast(module); + midiChoice->box.pos = Vec(margin, yPos); + midiChoice->box.size.x = box.size.x - 10; + addChild(midiChoice); + yPos += midiChoice->box.size.y + margin * 6; + } + + + + { + Label *label = new Label(); + label->box.pos = Vec(margin, yPos); + label->text = "Clock 1 Ratio"; + addChild(label); + yPos += labelHeight + margin; + + ClockRatioChoice *ratioChoice = new ClockRatioChoice(); + ratioChoice->clockRatio = &module->clock1ratio; + ratioChoice->box.pos = Vec(margin, yPos); + ratioChoice->box.size.x = box.size.x - 10; + addChild(ratioChoice); + yPos += ratioChoice->box.size.y + margin+5; + + } + + { + Label *label = new Label(); + label->box.pos = Vec(margin, yPos); + label->text = "Clock 1 Pulse"; + addChild(label); + + addOutput(createOutput(Vec(15 * 6, yPos - 5), module, MIDIClockToCVInterface::CLOCK1_PULSE)); + yPos += labelHeight + margin*4; + } + + + { + Label *label = new Label(); + label->box.pos = Vec(margin, yPos); + label->text = "Clock 2 Ratio"; + addChild(label); + yPos += labelHeight + margin; + + ClockRatioChoice *ratioChoice = new ClockRatioChoice(); + ratioChoice->clockRatio = &module->clock2ratio; + ratioChoice->box.pos = Vec(margin, yPos); + ratioChoice->box.size.x = box.size.x - 10; + addChild(ratioChoice); + yPos += ratioChoice->box.size.y + margin+5; + + } + + { + Label *label = new Label(); + label->box.pos = Vec(margin, yPos); + label->text = "Clock 2 Pulse"; + addChild(label); + + addOutput(createOutput(Vec(15 * 6, yPos - 5), module, MIDIClockToCVInterface::CLOCK2_PULSE)); + yPos += labelHeight + margin*7; + } + + { + Label *label = new Label(); + label->box.pos = Vec(margin, yPos); + label->text = "Clock Start"; + addChild(label); + addOutput(createOutput(Vec(15*6, yPos - 5), module, MIDIClockToCVInterface::CLOCK_START_PULSE)); + yPos += 40; + } + + { + Label *label = new Label(); + label->box.pos = Vec(margin, yPos); + label->text = "Clock Stop"; + addChild(label); + + addOutput(createOutput(Vec(15*6, yPos - 5), module, MIDIClockToCVInterface::CLOCK_STOP_PULSE)); + } +} + +void MIDIClockToCVWidget::step() { + + ModuleWidget::step(); +} \ No newline at end of file diff --git a/src/core/core.cpp b/src/core/core.cpp index 3af312dd..9d8040e2 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -8,6 +8,7 @@ void init(rack::Plugin *plugin) { createModel(plugin, "AudioInterface", "Audio Interface"); createModel(plugin, "MIDIToCVInterface", "MIDI-to-CV Interface"); createModel(plugin, "MIDICCToCVInterface", "MIDI CC-to-CV Interface"); + createModel(plugin, "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface"); // createModel(plugin, "Bridge", "Bridge"); createModel(plugin, "Blank", "Blank"); } diff --git a/src/core/core.hpp b/src/core/core.hpp index f16502c8..1aaa64ac 100644 --- a/src/core/core.hpp +++ b/src/core/core.hpp @@ -22,6 +22,11 @@ struct MIDICCToCVWidget : ModuleWidget { void step(); }; +struct MIDIClockToCVWidget : ModuleWidget { + MIDIClockToCVWidget(); + void step(); +}; + struct BridgeWidget : ModuleWidget { BridgeWidget(); };