diff --git a/src/core/MidiCCToCV.cpp b/src/core/MIDICCToCVInterface.cpp similarity index 100% rename from src/core/MidiCCToCV.cpp rename to src/core/MIDICCToCVInterface.cpp diff --git a/src/core/MIDITriggerToCVInterface.cpp b/src/core/MIDITriggerToCVInterface.cpp new file mode 100644 index 00000000..de4bb272 --- /dev/null +++ b/src/core/MIDITriggerToCVInterface.cpp @@ -0,0 +1,143 @@ +#include "core.hpp" +#include "midi.hpp" +#include "dsp/filter.hpp" + + + +struct CcChoice : LedDisplayChoice { + CcChoice() { + box.size.y = mm2px(6.666); + textOffset.y -= 4; + } +}; + + +struct CcMidiWidget : MidiWidget { + LedDisplaySeparator *hSeparators[4]; + LedDisplaySeparator *vSeparators[4]; + LedDisplayChoice *ccChoices[4][4]; + + CcMidiWidget() { + Vec pos = channelChoice->box.getBottomLeft(); + for (int x = 1; x < 4; x++) { + vSeparators[x] = Widget::create(pos); + addChild(vSeparators[x]); + } + for (int y = 0; y < 4; y++) { + hSeparators[y] = Widget::create(pos); + addChild(hSeparators[y]); + for (int x = 0; x < 4; x++) { + CcChoice *ccChoice = Widget::create(pos); + ccChoice->text = stringf("%d", x*4+y); + ccChoices[x][y] = ccChoice; + addChild(ccChoice); + } + pos = ccChoices[0][y]->box.getBottomLeft(); + } + for (int x = 1; x < 4; x++) { + vSeparators[x]->box.size.y = pos.y - vSeparators[x]->box.pos.y; + } + } + void step() override { + MidiWidget::step(); + for (int x = 1; x < 4; x++) { + vSeparators[x]->box.pos.x = box.size.x / 4 * x; + } + for (int y = 0; y < 4; y++) { + hSeparators[y]->box.size.x = box.size.x; + for (int x = 0; x < 4; x++) { + ccChoices[x][y]->box.size.x = box.size.x / 4; + ccChoices[x][y]->box.pos.x = box.size.x / 4 * x; + } + } + } +}; + + +struct MIDITriggerToCVInterface : Module { + enum ParamIds { + NUM_PARAMS + }; + enum InputIds { + NUM_INPUTS + }; + enum OutputIds { + ENUMS(TRIG_OUTPUT, 16), + NUM_OUTPUTS + }; + enum LightIds { + NUM_LIGHTS + }; + + MidiInputQueue midiInput; + + MIDITriggerToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + + void step() override { + MidiMessage msg; + while (midiInput.shift(&msg)) { + processMessage(msg); + } + + for (int i = 0; i < 16; i++) { + outputs[TRIG_OUTPUT + i].value = 0.f; + } + } + + void processMessage(MidiMessage msg) { + // debug("MIDI: %01x %01x %02x %02x", msg.status(), msg.channel(), msg.data1, msg.data2); + + switch (msg.status()) { + default: break; + } + } + + json_t *toJson() override { + json_t *rootJ = json_object(); + json_object_set_new(rootJ, "midi", midiInput.toJson()); + return rootJ; + } + + void fromJson(json_t *rootJ) override { + json_t *midiJ = json_object_get(rootJ, "midi"); + midiInput.fromJson(midiJ); + } +}; + + +struct MIDITriggerToCVInterfaceWidget : ModuleWidget { + MIDITriggerToCVInterfaceWidget(MIDITriggerToCVInterface *module) : ModuleWidget(module) { + setPanel(SVG::load(assetGlobal("res/Core/MIDICCToCVInterface.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, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 0)); + addOutput(Port::create(mm2px(Vec(15.494659, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 1)); + addOutput(Port::create(mm2px(Vec(27.094982, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 2)); + addOutput(Port::create(mm2px(Vec(38.693932, 73.344704)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 3)); + addOutput(Port::create(mm2px(Vec(3.8943355, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 4)); + addOutput(Port::create(mm2px(Vec(15.49466, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 5)); + addOutput(Port::create(mm2px(Vec(27.094982, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 6)); + addOutput(Port::create(mm2px(Vec(38.693932, 84.945023)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 7)); + addOutput(Port::create(mm2px(Vec(3.8943343, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 8)); + addOutput(Port::create(mm2px(Vec(15.494659, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 9)); + addOutput(Port::create(mm2px(Vec(27.09498, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 10)); + addOutput(Port::create(mm2px(Vec(38.693932, 96.543976)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 11)); + addOutput(Port::create(mm2px(Vec(3.894335, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 12)); + addOutput(Port::create(mm2px(Vec(15.49466, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 13)); + addOutput(Port::create(mm2px(Vec(27.09498, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 14)); + addOutput(Port::create(mm2px(Vec(38.693932, 108.14429)), Port::OUTPUT, module, MIDITriggerToCVInterface::TRIG_OUTPUT + 15)); + + MidiWidget *midiWidget = Widget::create(mm2px(Vec(3.399621, 14.837339))); + midiWidget->box.size = mm2px(Vec(44, 54.667)); + midiWidget->midiIO = &module->midiInput; + addChild(midiWidget); + + } +}; + + +Model *modelMIDITriggerToCVInterface = Model::create("Core", "MIDITriggerToCVInterface", "MIDI-TRIG", MIDI_TAG, EXTERNAL_TAG); diff --git a/src/core/MidiTriggerToCV.cpp b/src/core/MidiTriggerToCV.cpp deleted file mode 100644 index 0936468f..00000000 --- a/src/core/MidiTriggerToCV.cpp +++ /dev/null @@ -1,286 +0,0 @@ -#if 0 -#include -#include -#include "core.hpp" -#include "MidiIO.hpp" -#include "dsp/digital.hpp" - - -using namespace rack; - -struct TriggerValue { - int val = 0; - int num; - bool numInited = false; - bool onFocus = false; -}; - -struct MIDITriggerToCVInterface : MidiIO, Module { - enum ParamIds { - NUM_PARAMS - }; - enum InputIds { - NUM_INPUTS - }; - enum OutputIds { - NUM_OUTPUTS = 16 - }; - - TriggerValue trigger[NUM_OUTPUTS]; - - MIDITriggerToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { - for (int i = 0; i < NUM_OUTPUTS; i++) { - trigger[i].num = i; - } - } - - ~MIDITriggerToCVInterface() { - } - - void step() override; - - void processMidi(std::vector msg); - - void resetMidi() override; - - virtual json_t *toJson() override { - json_t *rootJ = json_object(); - addBaseJson(rootJ); - for (int i = 0; i < NUM_OUTPUTS; i++) { - json_object_set_new(rootJ, std::to_string(i).c_str(), json_integer(trigger[i].num)); - } - return rootJ; - } - - void fromJson(json_t *rootJ) override { - baseFromJson(rootJ); - for (int i = 0; i < NUM_OUTPUTS; i++) { - json_t *ccNumJ = json_object_get(rootJ, std::to_string(i).c_str()); - if (ccNumJ) { - trigger[i].num = json_integer_value(ccNumJ); - trigger[i].numInited = true; - } - - } - } - - void onReset() override { - resetMidi(); - } -}; - - -void MIDITriggerToCVInterface::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 < NUM_OUTPUTS; i++) { - // Note: Could have an option to select between gate and velocity - // but trigger seams more useful - // outputs[i].value = trigger[i] / 127.0 * 10; - outputs[i].value = trigger[i].val > 0 ? 10.0 : 0.0; - } -} - -void MIDITriggerToCVInterface::resetMidi() { - for (int i = 0; i < NUM_OUTPUTS; i++) { - trigger[i].val = 0; - } -}; - -void MIDITriggerToCVInterface::processMidi(std::vector msg) { - int channel = msg[0] & 0xf; - int status = (msg[0] >> 4) & 0xf; - int data1 = msg[1]; - int data2 = msg[2]; - - //fprintf(stderr, "channel %d status %d data1 %d data2 %d\n", channel, status, data1,data2); - - // Filter channels - if (this->channel >= 0 && this->channel != channel) - return; - - if (status == 0x8) { // note off - for (int i = 0; i < NUM_OUTPUTS; i++) { - if (data1 == trigger[i].num) { - trigger[i].val = 0; - } - } - return; - } - - if (status == 0x9) { // note on - for (int i = 0; i < NUM_OUTPUTS; i++) { - if (trigger[i].onFocus && data2 > 0) { - trigger[i].num = data1; - } - - if (data1 == trigger[i].num) { - trigger[i].val = data2; - } - } - } - -} - -struct TriggerTextField : TextField { - void onTextChange() override; - - void draw(NVGcontext *vg) override; - - void onMouseDown(EventMouseDown &e) override; - - void onMouseUp(EventMouseUp &e) override; - - void onMouseLeave(EventMouseLeave &e) override; - - int outNum; - MIDITriggerToCVInterface *module; -}; - -void TriggerTextField::draw(NVGcontext *vg) { - /* This is necessary, since the save - * file is loaded after constructing the widget*/ - if (module->trigger[outNum].numInited) { - module->trigger[outNum].numInited = false; - text = std::to_string(module->trigger[outNum].num); - } - - if (module->trigger[outNum].onFocus) { - text = std::to_string(module->trigger[outNum].num); - } - - TextField::draw(vg); -} - -void TriggerTextField::onTextChange() { - if (text.size() > 0) { - try { - int num = std::stoi(text); - // Only allow valid cc numbers - if (num < 0 || num > 127 || text.size() > 3) { - text = ""; - begin = end = 0; - module->trigger[outNum].num = -1; - } - else { - module->trigger[outNum].num = num; - } - } - catch (...) { - text = ""; - begin = end = 0; - module->trigger[outNum].num = -1; - } - }; -} - -void TriggerTextField::onMouseUp(EventMouseUp &e) { - if (e.button == 1) { - module->trigger[outNum].onFocus = false; - e.consumed = true; - } - TextField::onMouseUp(e); -} - -void TriggerTextField::onMouseDown(EventMouseDown &e) { - if (e.button == 1) { - module->trigger[outNum].onFocus = true; - e.consumed = true; - } - TextField::onMouseDown(e); -} - -void TriggerTextField::onMouseLeave(EventMouseLeave &e) { - module->trigger[outNum].onFocus = false; - e.consumed = true; -} - -MIDITriggerToCVWidget::MIDITriggerToCVWidget() { - MIDITriggerToCVInterface *module = new MIDITriggerToCVInterface(); - setModule(module); - box.size = Vec(16 * 15, 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 - 11 * 15, margin); - label->text = "MIDI Trigger to CV"; - addChild(label); - yPos = labelHeight * 2; - } - - { - Label *label = new Label(); - label->box.pos = Vec(margin, yPos); - label->text = "MIDI Interface"; - addChild(label); - - MidiChoice *midiChoice = new MidiChoice(); - midiChoice->midiModule = dynamic_cast(module); - midiChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos); - midiChoice->box.size.x = (box.size.x / 2.0) - margin; - addChild(midiChoice); - yPos += midiChoice->box.size.y + margin; - } - - { - Label *label = new Label(); - label->box.pos = Vec(margin, yPos); - label->text = "Channel"; - addChild(label); - - ChannelChoice *channelChoice = new ChannelChoice(); - channelChoice->midiModule = dynamic_cast(module); - channelChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos); - channelChoice->box.size.x = (box.size.x / 2.0) - margin; - addChild(channelChoice); - yPos += channelChoice->box.size.y + margin * 3; - } - - for (int i = 0; i < MIDITriggerToCVInterface::NUM_OUTPUTS; i++) { - TriggerTextField *triggerNumChoice = new TriggerTextField(); - triggerNumChoice->module = module; - triggerNumChoice->outNum = i; - triggerNumChoice->text = std::to_string(module->trigger[i].num); - triggerNumChoice->box.pos = Vec(11 + (i % 4) * (63), yPos); - triggerNumChoice->box.size.x = 29; - - addChild(triggerNumChoice); - - yPos += labelHeight + margin; - addOutput(createOutput(Vec((i % 4) * (63) + 10, yPos + 5), module, i)); - - if ((i + 1) % 4 == 0) { - yPos += 47 + margin; - } - else { - yPos -= labelHeight + margin; - } - } -} - -void MIDITriggerToCVWidget::step() { - ModuleWidget::step(); -} -#endif \ No newline at end of file diff --git a/src/core/QuadMidiToCV.cpp b/src/core/QuadMIDIToCVInterface.cpp similarity index 100% rename from src/core/QuadMidiToCV.cpp rename to src/core/QuadMIDIToCVInterface.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index ada56a62..178ddef1 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -9,6 +9,7 @@ void init(rack::Plugin *p) { p->addModel(modelMIDIToCVInterface); p->addModel(modelQuadMIDIToCVInterface); p->addModel(modelMIDICCToCVInterface); + p->addModel(modelMIDITriggerToCVInterface); p->addModel(modelBlank); p->addModel(modelNotes); } diff --git a/src/core/core.hpp b/src/core/core.hpp index 9d2878a7..d96b5581 100644 --- a/src/core/core.hpp +++ b/src/core/core.hpp @@ -8,5 +8,6 @@ extern Model *modelAudioInterface; extern Model *modelMIDIToCVInterface; extern Model *modelQuadMIDIToCVInterface; extern Model *modelMIDICCToCVInterface; +extern Model *modelMIDITriggerToCVInterface; extern Model *modelBlank; extern Model *modelNotes;