From 20aaf47f33257f3fac96a25e676d526390abf6ec Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 29 Jan 2022 16:51:50 +0000 Subject: [PATCH] Implement MIDI-CC panel, remove and replace old Rack CC modules Signed-off-by: falkTX --- plugins/Cardinal/orig/HostMIDICC.svg | 157 ++++++++++++++++++ plugins/Cardinal/res/HostMIDICC.svg | 202 +++++++++++++++++++++++ plugins/Cardinal/src/HostAudio.cpp | 6 +- plugins/Cardinal/src/HostMIDI-CC.cpp | 238 ++++++++++++++++++++++++++- plugins/Core.json | 20 --- plugins/plugins.cpp | 4 - src/Makefile | 2 + src/override/plugin.cpp | 3 +- 8 files changed, 598 insertions(+), 34 deletions(-) create mode 100644 plugins/Cardinal/orig/HostMIDICC.svg create mode 100644 plugins/Cardinal/res/HostMIDICC.svg diff --git a/plugins/Cardinal/orig/HostMIDICC.svg b/plugins/Cardinal/orig/HostMIDICC.svg new file mode 100644 index 0000000..c75f59e --- /dev/null +++ b/plugins/Cardinal/orig/HostMIDICC.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + Host MIDI CC + + diff --git a/plugins/Cardinal/res/HostMIDICC.svg b/plugins/Cardinal/res/HostMIDICC.svg new file mode 100644 index 0000000..b37f05e --- /dev/null +++ b/plugins/Cardinal/res/HostMIDICC.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/Cardinal/src/HostAudio.cpp b/plugins/Cardinal/src/HostAudio.cpp index 0f46885..da9bd9d 100644 --- a/plugins/Cardinal/src/HostAudio.cpp +++ b/plugins/Cardinal/src/HostAudio.cpp @@ -24,9 +24,9 @@ USE_NAMESPACE_DISTRHO; struct NanoKnob : Knob { static const int ringSize = 4; - std::string displayLabel; - std::string displayString; - float normalizedValue = 0.0f; + std::string displayLabel = "Level"; + std::string displayString = "0 dB"; + float normalizedValue = 0.5f; NanoKnob() { diff --git a/plugins/Cardinal/src/HostMIDI-CC.cpp b/plugins/Cardinal/src/HostMIDI-CC.cpp index 62b8e8e..2ac631a 100644 --- a/plugins/Cardinal/src/HostMIDI-CC.cpp +++ b/plugins/Cardinal/src/HostMIDI-CC.cpp @@ -39,10 +39,14 @@ struct HostMIDICC : Module { }; enum InputIds { ENUMS(CC_INPUTS, 16), + CC_INPUT_CHANNEL_PRESSURE, + CC_INPUT_PITCHBEND, NUM_INPUTS }; enum OutputIds { ENUMS(CC_OUTPUT, 16), + CC_OUTPUT_CHANNEL_PRESSURE, + CC_OUTPUT_PITCHBEND, NUM_OUTPUTS }; enum LightIds { @@ -272,16 +276,22 @@ struct HostMIDICC : Module { for (int i = 0; i < 16; i++) configInput(CC_INPUTS + i, string::f("Cell %d", i + 1)); + configInput(CC_INPUT_CHANNEL_PRESSURE, "Channel pressure"); + configInput(CC_INPUT_PITCHBEND, "Pitchbend"); + for (int i = 0; i < 16; i++) configOutput(CC_OUTPUT + i, string::f("Cell %d", i + 1)); + configOutput(CC_OUTPUT_CHANNEL_PRESSURE, "Channel pressure"); + configOutput(CC_OUTPUT_PITCHBEND, "Pitchbend"); + onReset(); } void onReset() override { for (int i = 0; i < 16; i++) { - learnedCcs[i] = i; + learnedCcs[i] = i + 1; } midiInput.reset(); midiOutput.reset(); @@ -353,7 +363,7 @@ struct HostMIDICC : Module { if (json_t* const ccJ = json_array_get(ccsJ, i)) learnedCcs[i] = json_integer_value(ccJ); else - learnedCcs[i] = i; + learnedCcs[i] = i + 1; } } @@ -386,12 +396,204 @@ struct HostMIDICC : Module { // -------------------------------------------------------------------------------------------------------------------- +struct CardinalMIDILearnPJ301MPort : PJ301MPort { + void onDragStart(const DragStartEvent& e) override { + PJ301MPort::onDragStart(e); + } + void onDragEnd(const DragEndEvent& e) override { + PJ301MPort::onDragEnd(e); + } +}; + +struct CardinalLedDisplayChoice : LedDisplayChoice { + CardinalLedDisplayChoice(const char* const label = nullptr) + { + color = nvgRGBf(0.76f, 0.11f, 0.22f); + textOffset.y -= 4; + + if (label != nullptr) + text = label; + } + + void drawLayer(const DrawArgs& args, int layer) override + { + // nvgScissor(args.vg, RECT_ARGS(args.clipBox)); + + if (layer == 1) + { + nvgFillColor(args.vg, color); + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgTextLetterSpacing(args.vg, 0.0f); + nvgText(args.vg, box.size.x * 0.5f, textOffset.y, text.c_str(), NULL); + } + + Widget::drawLayer(args, layer); + // nvgResetScissor(args.vg); + } +}; + +/** + * Based on VCVRack's CcChoice as defined in src/core/plugin.hpp + * Copyright (C) 2016-2021 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + */ +struct CardinalCcChoice : CardinalLedDisplayChoice { + HostMIDICC* const module; + const int id; + int focusCc; + + CardinalCcChoice(HostMIDICC* const m, const int i) + : CardinalLedDisplayChoice(), + module(m), + id(i) {} + + void step() override + { + int cc; + + if (module == nullptr) + { + cc = id; + } + else if (module->midiInput.learningId == id) + { + cc = focusCc; + color.a = 0.5f; + } + else + { + cc = module->learnedCcs[id]; + color.a = 1.0f; + + // Cancel focus if no longer learning + if (APP->event->getSelectedWidget() == this) + APP->event->setSelectedWidget(NULL); + } + + // Set text + if (cc < 0) + text = "--"; + else + text = string::f("%d", cc); + } + + void onSelect(const SelectEvent& e) override + { + DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,); + + module->midiInput.learningId = id; + focusCc = -1; + e.consume(this); + } + + void onDeselect(const DeselectEvent&) override + { + DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,); + + if (module->midiInput.learningId == id) + { + if (0 <= focusCc && focusCc < 128) + module->learnedCcs[id] = focusCc; + module->midiInput.learningId = -1; + } + } + + void onSelectText(const SelectTextEvent& e) override + { + int c = e.codepoint; + + if ('0' <= c && c <= '9') + { + if (focusCc < 0) + focusCc = 0; + focusCc = focusCc * 10 + (c - '0'); + } + + if (focusCc >= 128) + focusCc = -1; + + e.consume(this); + } + + void onSelectKey(const SelectKeyEvent& e) override + { + if ((e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) && e.action == GLFW_PRESS && (e.mods & RACK_MOD_MASK) == 0) { + DeselectEvent eDeselect; + onDeselect(eDeselect); + APP->event->selectedWidget = NULL; + e.consume(this); + } + } +}; + +struct CCGridDisplay : Widget { + void draw(const DrawArgs& args) override + { + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, 0, 0, box.size.x, box.size.y, 4); + nvgFillColor(args.vg, nvgRGB(0, 0, 0)); + nvgFill(args.vg); + + Widget::draw(args); + } + + void setModule(HostMIDICC* const module) + { + LedDisplaySeparator* hSeparators[6]; + LedDisplaySeparator* vSeparators[3]; + LedDisplayChoice* choices[3][6]; + + // Add vSeparators + for (int x = 0; x < 3; ++x) + { + vSeparators[x] = new LedDisplaySeparator; + vSeparators[x]->box.pos = Vec(box.size.x / 3 * (x+1), 0.0f); + vSeparators[x]->box.size = Vec(1.0f, box.size.y); + addChild(vSeparators[x]); + } + + // Add hSeparators and choice widgets + for (int y = 0; y < 6; ++y) + { + hSeparators[y] = new LedDisplaySeparator; + hSeparators[y]->box.pos = Vec(0.0f, box.size.y / 6 * (y+1)); + hSeparators[y]->box.size = Vec(box.size.x, 1.0f); + addChild(hSeparators[y]); + + for (int x = 0; x < 3; ++x) + { + const int id = 6 * x + y; + + switch (id) + { + case 16: + choices[x][y] = new CardinalLedDisplayChoice("Ch.press"); + break; + case 17: + choices[x][y] = new CardinalLedDisplayChoice("Pbend"); + break; + default: + choices[x][y] = new CardinalCcChoice(module, id); + break; + } + + choices[x][y]->box.pos = Vec(box.size.x / 3 * x, box.size.y / 6 * y); + choices[x][y]->box.size = Vec(box.size.x / 3, box.size.y / 6); + addChild(choices[x][y]); + } + } + } +}; + struct HostMIDICCWidget : ModuleWidget { static constexpr const float startX_In = 14.0f; - static constexpr const float startX_Out = 96.0f; - static constexpr const float startY = 74.0f; + static constexpr const float startX_Out = 115.0f; + static constexpr const float startY = 190.0f; static constexpr const float padding = 29.0f; - static constexpr const float middleX = startX_In + (startX_Out - startX_In) * 0.5f + padding * 0.35f; HostMIDICC* const module; @@ -399,12 +601,31 @@ struct HostMIDICCWidget : ModuleWidget { : module(m) { setModule(m); - setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostMIDI.svg"))); + setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostMIDICC.svg"))); addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + for (int i=0; i<18; ++i) + { + const float x = startX_In + int(i / 6) * padding; + const float y = startY + int(i % 6) * padding; + addInput(createInput(Vec(x, y), module, i)); + } + + for (int i=0; i<18; ++i) + { + const float x = startX_Out + int(i / 6) * padding; + const float y = startY + int(i % 6) * padding; + addOutput(createOutput(Vec(x, y), module, i)); + } + + CCGridDisplay* const display = createWidget(Vec(startX_In - 3.0f, 70.0f)); + display->box.size = Vec(box.size.x - startX_In * 2.0f + 6.0f, startY - 74.0f - 9.0f); + display->setModule(m); + addChild(display); } void draw(const DrawArgs& args) override @@ -415,6 +636,11 @@ struct HostMIDICCWidget : ModuleWidget { nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22))); nvgFill(args.vg); + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding * 3, padding * 6, 4); + nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0)); + nvgFill(args.vg); + ModuleWidget::draw(args); } diff --git a/plugins/Core.json b/plugins/Core.json index bfb2651..cdec1fc 100644 --- a/plugins/Core.json +++ b/plugins/Core.json @@ -12,16 +12,6 @@ "changelogUrl": "https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md", "description": "Necessary modules built into Cardinal", "modules": [ - { - "slug": "MIDICCToCVInterface", - "name": "MIDI CC to CV", - "description": "Converts MIDI CC from an external device to CV", - "manualUrl": "https://vcvrack.com/manual/Core#MIDI-CC", - "tags": [ - "External", - "MIDI" - ] - }, { "slug": "MIDITriggerToCVInterface", "name": "MIDI to Gate", @@ -42,16 +32,6 @@ "MIDI" ] }, - { - "slug": "CV-CC", - "name": "CV to MIDI CC", - "description": "Converts CV to MIDI CC and sends to an external device", - "manualUrl": "https://vcvrack.com/manual/Core#CV-CC", - "tags": [ - "External", - "MIDI" - ] - }, { "slug": "CV-Gate", "name": "Gate to MIDI", diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp index 29c79a0..3cec9ee 100644 --- a/plugins/plugins.cpp +++ b/plugins/plugins.cpp @@ -597,10 +597,8 @@ std::string pluginPath(const std::string& dirname); // core plugins namespace core { -extern Model* modelMIDICC_CV; extern Model* modelMIDI_Gate; extern Model* modelMIDIMap; -extern Model* modelCV_MIDICC; extern Model* modelGate_MIDI; extern Model* modelBlank; } @@ -694,10 +692,8 @@ static void initStatic__Core() const StaticPluginLoader spl(p, "Core"); if (spl.ok()) { - p->addModel(rack::core::modelMIDICC_CV); p->addModel(rack::core::modelMIDI_Gate); p->addModel(rack::core::modelMIDIMap); - p->addModel(rack::core::modelCV_MIDICC); p->addModel(rack::core::modelGate_MIDI); p->addModel(rack::core::modelBlank); } diff --git a/src/Makefile b/src/Makefile index 9506336..04227d4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -129,7 +129,9 @@ IGNORED_FILES += Rack/src/app/Scene.cpp IGNORED_FILES += Rack/src/app/TipWindow.cpp IGNORED_FILES += Rack/src/core/Audio.cpp IGNORED_FILES += Rack/src/core/CV_MIDI.cpp +IGNORED_FILES += Rack/src/core/CV_MIDICC.cpp IGNORED_FILES += Rack/src/core/MIDI_CV.cpp +IGNORED_FILES += Rack/src/core/MIDICC_CV.cpp IGNORED_FILES += Rack/src/core/Notes.cpp IGNORED_FILES += Rack/src/engine/Engine.cpp IGNORED_FILES += Rack/src/plugin/Model.cpp diff --git a/src/override/plugin.cpp b/src/override/plugin.cpp index 012a1d4..cd6cbc6 100644 --- a/src/override/plugin.cpp +++ b/src/override/plugin.cpp @@ -88,10 +88,11 @@ static const std::map moduleSlugFallbacks = {{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}}, {{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}}, {{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}}, + {{"Core", "MIDICCToCVInterface"}, {"Cardinal", "HostMIDICC"}}, {{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}}, + {{"Core", "CV-CC"}, {"Cardinal", "HostMIDICC"}}, {{"Core", "Notes"}, {"Cardinal", "TextEditor"}}, {{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}}, - {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}}, // {{"", ""}, {"", ""}}, };