From 8653610af1666983425da8aecf724b43915ebfaf Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 24 Feb 2018 10:00:47 -0500 Subject: [PATCH] Add MIDI-4 skeleton --- res/Core/QuadMIDIToCVInterface.svg | 628 +++++++++++++++++++++++++++++ src/core/QuadMidiToCV.cpp | 448 +++----------------- src/core/core.cpp | 7 +- src/core/core.hpp | 27 +- 4 files changed, 683 insertions(+), 427 deletions(-) create mode 100644 res/Core/QuadMIDIToCVInterface.svg diff --git a/res/Core/QuadMIDIToCVInterface.svg b/res/Core/QuadMIDIToCVInterface.svg new file mode 100644 index 00000000..4dbeae9f --- /dev/null +++ b/res/Core/QuadMIDIToCVInterface.svg @@ -0,0 +1,628 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/core/QuadMidiToCV.cpp b/src/core/QuadMidiToCV.cpp index 70b8f7ae..1466d2d3 100644 --- a/src/core/QuadMidiToCV.cpp +++ b/src/core/QuadMidiToCV.cpp @@ -1,420 +1,78 @@ -#if 0 -#include -#include #include "core.hpp" -#include "MidiIO.hpp" -#include "dsp/digital.hpp" +#include "midi.hpp" -struct MidiKey { - int pitch = 60; - int at = 0; // aftertouch - int vel = 0; // velocity - bool gate = false; - bool pedal_gate_released = false; -}; - -struct QuadMIDIToCVInterface : MidiIO, Module { +struct QuadMIDIToCVInterface : Module { enum ParamIds { - RESET_PARAM, NUM_PARAMS }; enum InputIds { NUM_INPUTS }; enum OutputIds { - PITCH_OUTPUT = 0, - GATE_OUTPUT = 4, - VELOCITY_OUTPUT = 8, - AT_OUTPUT = 12, - NUM_OUTPUTS = 16 + RECT17025_OUTPUT, + RECT17027_OUTPUT, + RECT17029_OUTPUT, + RECT17031_OUTPUT, + RECT17033_OUTPUT, + RECT17035_OUTPUT, + RECT17037_OUTPUT, + RECT17039_OUTPUT, + RECT17041_OUTPUT, + RECT17043_OUTPUT, + RECT17045_OUTPUT, + RECT17047_OUTPUT, + RECT17049_OUTPUT, + RECT17051_OUTPUT, + RECT17053_OUTPUT, + RECT17055_OUTPUT, + NUM_OUTPUTS }; enum LightIds { - RESET_LIGHT, NUM_LIGHTS }; - enum Modes { - ROTATE, - RESET, - REASSIGN - }; - - bool pedal = false; - - int mode = REASSIGN; - - int getMode() const; - - void setMode(int mode); - - MidiKey activeKeys[4]; - std::list open; - - SchmittTrigger resetTrigger; - - QuadMIDIToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { - - } - - ~QuadMIDIToCVInterface() { - }; - - void step() override; - - void processMidi(std::vector msg); - - json_t *toJson() override { - json_t *rootJ = json_object(); - addBaseJson(rootJ); - return rootJ; - } - - void fromJson(json_t *rootJ) override { - baseFromJson(rootJ); - } - - void onReset() override { - resetMidi(); - } + MidiInputQueue midiInput; - void resetMidi() override; + QuadMIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + void step() override {} }; -void QuadMIDIToCVInterface::resetMidi() { - - for (int i = 0; i < 4; i++) { - outputs[GATE_OUTPUT + i].value = 0.0; - activeKeys[i].gate = false; - activeKeys[i].vel = 0; - activeKeys[i].at = 0; - } - - open.clear(); - - pedal = false; - lights[RESET_LIGHT].value = 1.0; -} - -void QuadMIDIToCVInterface::step() { - if (isPortOpen()) { - std::vector message; - - // midiIn->getMessage returns empty vector if there are no messages in the queue - getMessage(&message); - if (message.size() > 0) { - processMidi(message); - } - } - - - for (int i = 0; i < 4; i++) { - outputs[GATE_OUTPUT + i].value = activeKeys[i].gate ? 10.0 : 0; - outputs[PITCH_OUTPUT + i].value = (activeKeys[i].pitch - 60) / 12.0; - outputs[VELOCITY_OUTPUT + i].value = activeKeys[i].vel / 127.0 * 10.0; - outputs[AT_OUTPUT + i].value = activeKeys[i].at / 127.0 * 10.0; - } - - if (resetTrigger.process(params[RESET_PARAM].value)) { - resetMidi(); - return; - } - - lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / 0.55 / engineGetSampleRate(); // fade out light -} - - -void QuadMIDIToCVInterface::processMidi(std::vector msg) { - int channel = msg[0] & 0xf; - int status = (msg[0] >> 4) & 0xf; - int data1 = msg[1]; - int data2 = msg[2]; - bool gate; - - // Filter channels - if (this->channel >= 0 && this->channel != channel) - return; - - switch (status) { - // note off - case 0x8: { - gate = false; - } - break; - case 0x9: // note on - if (data2 > 0) { - gate = true; - } - else { - // For some reason, some keyboards send a "note on" event with a velocity of 0 to signal that the key has been released. - gate = false; - } - break; - case 0xa: // channel aftertouch - for (int i = 0; i < 4; i++) { - if (activeKeys[i].pitch == data1) { - activeKeys[i].at = data2; - } - } - return; - case 0xb: // cc - if (data1 == 0x40) { // pedal - pedal = (data2 >= 64); - if (!pedal) { - for (int i = 0; i < 4; i++) { - if (activeKeys[i].pedal_gate_released) { - activeKeys[i].gate = false; - activeKeys[i].pedal_gate_released = false; - if (std::find(open.begin(), open.end(), i) != open.end()) { - open.remove(i); - } - open.push_front(i); - } - } - } - } - return; - default: - return; - } - - if (pedal && !gate) { - for (int i = 0; i < 4; i++) { - if (activeKeys[i].pitch == data1 && activeKeys[i].gate) { - activeKeys[i].pedal_gate_released = true; - } - } - return; - } - - if (!gate) { - for (int i = 0; i < 4; i++) { - if (activeKeys[i].pitch == data1 && activeKeys[i].gate) { - activeKeys[i].gate = false; - activeKeys[i].vel = data2; - if (std::find(open.begin(), open.end(), i) != open.end()) { - open.remove(i); - } - open.push_front(i); - } - } - return; - } - - if (open.empty()) { - for (int i = 0; i < 4; i++) { - open.push_back(i); - } - } - if (!activeKeys[0].gate && !activeKeys[1].gate && - !activeKeys[2].gate && !activeKeys[3].gate) { - open.sort(); - } - - - switch (mode) { - case RESET: - if (open.size() >= 4) { - open.clear(); - for (int i = 0; i < 4; i++) { - activeKeys[i].gate = false; - open.push_back(i); - } - } - break; - case REASSIGN: - open.push_back(open.front()); - break; - case ROTATE: - break; - } - - int next = open.front(); - open.pop_front(); - - for (int i = 0; i < 4; i++) { - if (activeKeys[i].pitch == data1 && activeKeys[i].gate) { - activeKeys[i].vel = data2; - if (std::find(open.begin(), open.end(), i) != open.end()) - open.remove(i); - - open.push_front(i); - activeKeys[i].gate = false; - activeKeys[i].pedal_gate_released = false; - } - } - - activeKeys[next].gate = true; - activeKeys[next].pedal_gate_released = false; - activeKeys[next].pitch = data1; - activeKeys[next].vel = data2; -} - -int QuadMIDIToCVInterface::getMode() const { - return mode; -} - -void QuadMIDIToCVInterface::setMode(int mode) { - resetMidi(); - QuadMIDIToCVInterface::mode = mode; -} - -struct ModeItem : MenuItem { - int mode; - QuadMIDIToCVInterface *module; - - void onAction(EventAction &e) override { - module->setMode(mode); +struct QuadMIDIToCVInterfaceWidget : ModuleWidget { + QuadMIDIToCVInterfaceWidget(QuadMIDIToCVInterface *module) : ModuleWidget(module) { + setPanel(SVG::load(assetGlobal("res/Core/QuadMIDIToCVInterface.svg"))); + + addChild(Widget::create(Vec(RACK_GRID_WIDTH, 0))); + addChild(Widget::create(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(Widget::create(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(Widget::create(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + addOutput(Port::create(mm2px(Vec(3.894335, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17025_OUTPUT)); + addOutput(Port::create(mm2px(Vec(15.494659, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17027_OUTPUT)); + addOutput(Port::create(mm2px(Vec(27.094986, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17029_OUTPUT)); + addOutput(Port::create(mm2px(Vec(38.693935, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17031_OUTPUT)); + addOutput(Port::create(mm2px(Vec(3.894335, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17033_OUTPUT)); + addOutput(Port::create(mm2px(Vec(15.494659, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17035_OUTPUT)); + addOutput(Port::create(mm2px(Vec(27.094986, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17037_OUTPUT)); + addOutput(Port::create(mm2px(Vec(38.693935, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17039_OUTPUT)); + addOutput(Port::create(mm2px(Vec(3.894335, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17041_OUTPUT)); + addOutput(Port::create(mm2px(Vec(15.494659, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17043_OUTPUT)); + addOutput(Port::create(mm2px(Vec(27.094986, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17045_OUTPUT)); + addOutput(Port::create(mm2px(Vec(38.693935, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17047_OUTPUT)); + addOutput(Port::create(mm2px(Vec(3.894335, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17049_OUTPUT)); + addOutput(Port::create(mm2px(Vec(15.494659, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17051_OUTPUT)); + addOutput(Port::create(mm2px(Vec(27.094986, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17053_OUTPUT)); + addOutput(Port::create(mm2px(Vec(38.693935, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::RECT17055_OUTPUT)); + + MidiWidget *midiWidget = Widget::create(mm2px(Vec(3.4009969, 14.837336))); + midiWidget->box.size = mm2px(Vec(44, 28)); + midiWidget->midiIO = &module->midiInput; + addChild(midiWidget); } }; -struct ModeChoice : ChoiceButton { - QuadMIDIToCVInterface *module; - const std::vector modeNames = {"ROTATE", "RESET", "REASSIGN"}; - - - void onAction(EventAction &e) override { - Menu *menu = gScene->createMenu(); - menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); - menu->box.size.x = box.size.x; - - for (unsigned long i = 0; i < modeNames.size(); i++) { - ModeItem *modeItem = new ModeItem(); - modeItem->mode = i; - modeItem->module = module; - modeItem->text = modeNames[i]; - menu->addChild(modeItem); - } - } - - void step() override { - text = modeNames[module->getMode()]; - } -}; - - -QuadMidiToCVWidget::QuadMidiToCVWidget() { - QuadMIDIToCVInterface *module = new QuadMIDIToCVInterface(); - setModule(module); - box.size = Vec(15 * 16, 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 - 12 * 15, margin); - label->text = "Quad MIDI to CV"; - addChild(label); - yPos = labelHeight * 2; - } - - addParam(createParam(Vec(12 * 15, labelHeight), module, QuadMIDIToCVInterface::RESET_PARAM, 0.0, 1.0, - 0.0)); - addChild(createLight>(Vec(12 * 15 + 5, labelHeight + 5), module, QuadMIDIToCVInterface::RESET_LIGHT)); - { - 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; - } - - { - Label *label = new Label(); - label->box.pos = Vec(margin, yPos); - label->text = "Channel"; - addChild(label); - yPos += labelHeight + margin; - - ChannelChoice *channelChoice = new ChannelChoice(); - channelChoice->midiModule = dynamic_cast(module); - channelChoice->box.pos = Vec(margin, yPos); - channelChoice->box.size.x = box.size.x - 10; - addChild(channelChoice); - yPos += channelChoice->box.size.y + margin; - } - - { - Label *label = new Label(); - label->box.pos = Vec(margin, yPos); - label->text = "Mode"; - addChild(label); - yPos += labelHeight + margin; - - ModeChoice *modeChoice = new ModeChoice(); - modeChoice->module = module; - modeChoice->box.pos = Vec(margin, yPos); - modeChoice->box.size.x = box.size.x - 10; - addChild(modeChoice); - yPos += modeChoice->box.size.y + margin + 15; - } - - { - Label *label = new Label(); - label->box.pos = Vec(84, yPos); - label->text = "1"; - addChild(label); - } - { - Label *label = new Label(); - label->box.pos = Vec(125, yPos); - label->text = "2"; - addChild(label); - } - { - Label *label = new Label(); - label->box.pos = Vec(164, yPos); - label->text = "3"; - addChild(label); - } - { - Label *label = new Label(); - label->box.pos = Vec(203, yPos); - label->text = "4"; - addChild(label); - } - std::string labels[4] = {"1V/oct", "Gate", "Velocity", "Aftertouch"}; - - yPos += labelHeight + margin * 2; - for (int i = 0; i < 4; i++) { - Label *label = new Label(); - label->box.pos = Vec(margin, yPos); - label->text = labels[i]; - addChild(label); - addOutput(createOutput(Vec(2 * (40), yPos - 5), module, i * 4)); - addOutput(createOutput(Vec(3 * (40), yPos - 5), module, i * 4 + 1)); - addOutput(createOutput(Vec(4 * (40), yPos - 5), module, i * 4 + 2)); - addOutput(createOutput(Vec(5 * (40), yPos - 5), module, i * 4 + 3)); - yPos += 40; - } - - -} -void QuadMidiToCVWidget::step() { +Model *modelQuadMIDIToCVInterface = Model::create("Core", "QuadMIDIToCVInterface", "MIDI-4", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG); - ModuleWidget::step(); -} -#endif \ No newline at end of file diff --git a/src/core/core.cpp b/src/core/core.cpp index 566b4488..ada56a62 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -7,13 +7,8 @@ void init(rack::Plugin *p) { p->addModel(modelAudioInterface); p->addModel(modelMIDIToCVInterface); + p->addModel(modelQuadMIDIToCVInterface); p->addModel(modelMIDICCToCVInterface); p->addModel(modelBlank); p->addModel(modelNotes); - - // TODO - // p->addModel(createModel("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); - // p->addModel(createModel("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); - // p->addModel(createModel("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); - // p->addModel(createModel("Core", "QuadMIDIToCVInterface", "Quad MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, QUAD_TAG)); } diff --git a/src/core/core.hpp b/src/core/core.hpp index 2cced2d3..9d2878a7 100644 --- a/src/core/core.hpp +++ b/src/core/core.hpp @@ -6,32 +6,7 @@ using namespace rack; extern Model *modelAudioInterface; extern Model *modelMIDIToCVInterface; +extern Model *modelQuadMIDIToCVInterface; extern Model *modelMIDICCToCVInterface; extern Model *modelBlank; extern Model *modelNotes; - - -//////////////////// -// module widgets -//////////////////// - - -// struct MIDICCToCVWidget : ModuleWidget { -// MIDICCToCVWidget(); -// void step() override; -// }; - -// struct MIDIClockToCVWidget : ModuleWidget { -// MIDIClockToCVWidget(); -// void step() override; -// }; - -// struct MIDITriggerToCVWidget : ModuleWidget { -// MIDITriggerToCVWidget(); -// void step() override; -// }; - -// struct QuadMidiToCVWidget : ModuleWidget { -// QuadMidiToCVWidget(); -// void step() override; -// };