diff --git a/src/Core/Core.hpp b/src/Core/Core.hpp index d96b5581..c5c6064a 100644 --- a/src/Core/Core.hpp +++ b/src/Core/Core.hpp @@ -11,3 +11,54 @@ extern Model *modelMIDICCToCVInterface; extern Model *modelMIDITriggerToCVInterface; extern Model *modelBlank; extern Model *modelNotes; + + + +struct GridChoice : LedDisplayChoice { + virtual void setId(int id) {} +}; + + +struct Grid16MidiWidget : MidiWidget { + LedDisplaySeparator *hSeparators[4]; + LedDisplaySeparator *vSeparators[4]; + GridChoice *gridChoices[4][4]; + + void createGridChoices() { + 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++) { + GridChoice *gridChoice = createGridChoice(); + assert(gridChoice); + gridChoice->box.pos = pos; + gridChoice->setId(4*y + x); + gridChoices[x][y] = gridChoice; + addChild(gridChoice); + } + pos = gridChoices[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++) { + gridChoices[x][y]->box.size.x = box.size.x / 4; + gridChoices[x][y]->box.pos.x = box.size.x / 4 * x; + } + } + } + virtual GridChoice *createGridChoice() {return NULL;} +}; \ No newline at end of file diff --git a/src/Core/MIDICCToCVInterface.cpp b/src/Core/MIDICCToCVInterface.cpp index b581d598..3425e689 100644 --- a/src/Core/MIDICCToCVInterface.cpp +++ b/src/Core/MIDICCToCVInterface.cpp @@ -3,57 +3,6 @@ #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 MIDICCToCVInterface : Module { enum ParamIds { NUM_PARAMS @@ -70,10 +19,23 @@ struct MIDICCToCVInterface : Module { }; MidiInputQueue midiInput; - uint8_t cvs[128] = {}; + uint8_t cvs[16]; ExponentialFilter ccFilters[16]; - MIDICCToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + int learningId = -1; + uint8_t learnedCcs[16] = {}; + + MIDICCToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + onReset(); + } + + void onReset() override { + for (int i = 0; i < 16; i++) { + cvs[i] = 0; + learnedCcs[i] = i; + } + learningId = -1; + } void step() override { MidiMessage msg; @@ -90,11 +52,20 @@ struct MIDICCToCVInterface : Module { } void processMessage(MidiMessage msg) { - debug("MIDI: %01x %01x %02x %02x", msg.status(), msg.channel(), msg.data1, msg.data2); switch (msg.status()) { // cc case 0xb: { - cvs[msg.note()] = msg.value(); + uint8_t cc = msg.note(); + // Learn + if (learningId >= 0) { + learnedCcs[learningId] = cc; + } + // Set CV + for (int i = 0; i < 16; i++) { + if (learnedCcs[i] == cc) { + cvs[i] = msg.value(); + } + } } break; default: break; } @@ -113,6 +84,51 @@ struct MIDICCToCVInterface : Module { }; +struct MidiCcChoice : GridChoice { + MIDICCToCVInterface *module; + int id; + + MidiCcChoice() { + box.size.y = mm2px(6.666); + textOffset.y -= 4; + } + + void setId(int id) override { + this->id = id; + } + + void step() override { + if (module->learningId == id) { + text = "LRN"; + color.a = 0.5; + } + else { + text = stringf("%d", id); + color.a = 1.0; + } + } + + void onFocus(EventFocus &e) override { + e.consumed = true; + module->learningId = id; + } + + void onDefocus(EventDefocus &e) override { + module->learningId = -1; + } +}; + + +struct MidiCcWidget : Grid16MidiWidget { + MIDICCToCVInterface *module; + GridChoice *createGridChoice() override { + MidiCcChoice *gridChoice = new MidiCcChoice(); + gridChoice->module = module; + return gridChoice; + } +}; + + struct MIDICCToCVInterfaceWidget : ModuleWidget { MIDICCToCVInterfaceWidget(MIDICCToCVInterface *module) : ModuleWidget(module) { setPanel(SVG::load(assetGlobal("res/Core/MIDICCToCVInterface.svg"))); @@ -139,11 +155,12 @@ struct MIDICCToCVInterfaceWidget : ModuleWidget { addOutput(Port::create(mm2px(Vec(27.09498, 108.14429)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 14)); addOutput(Port::create(mm2px(Vec(38.693932, 108.14429)), Port::OUTPUT, module, MIDICCToCVInterface::CC_OUTPUT + 15)); - MidiWidget *midiWidget = Widget::create(mm2px(Vec(3.399621, 14.837339))); + MidiCcWidget *midiWidget = Widget::create(mm2px(Vec(3.399621, 14.837339))); + midiWidget->module = module; midiWidget->box.size = mm2px(Vec(44, 54.667)); midiWidget->midiIO = &module->midiInput; + midiWidget->createGridChoices(); addChild(midiWidget); - } }; diff --git a/src/Core/MIDITriggerToCVInterface.cpp b/src/Core/MIDITriggerToCVInterface.cpp index be9d32de..63aa3a80 100644 --- a/src/Core/MIDITriggerToCVInterface.cpp +++ b/src/Core/MIDITriggerToCVInterface.cpp @@ -1,57 +1,5 @@ #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 { @@ -73,6 +21,8 @@ struct MIDITriggerToCVInterface : Module { bool gates[16]; float gateTimes[16]; + int learningId = -1; + uint8_t learnedNotes[16] = {}; MIDITriggerToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { onReset(); @@ -82,26 +32,32 @@ struct MIDITriggerToCVInterface : Module { for (int i = 0; i < 16; i++) { gates[i] = false; gateTimes[i] = 0.f; + learnedNotes[i] = i + 36; } + learningId = -1; } void pressNote(uint8_t note) { - // TEMP - if (note >= 16) - return; - int i = note; - - gates[i] = true; - gateTimes[i] = 1e-3f; + // Learn + if (learningId >= 0) { + learnedNotes[learningId] = note; + } + // Find id + for (int i = 0; i < 16; i++) { + if (learnedNotes[i] == note) { + gates[i] = true; + gateTimes[i] = 1e-3f; + } + } } void releaseNote(uint8_t note) { - // TEMP - if (note >= 16) - return; - int i = note; - - gates[i] = false; + // Find id + for (int i = 0; i < 16; i++) { + if (learnedNotes[i] == note) { + gates[i] = false; + } + } } void step() override { @@ -158,6 +114,58 @@ struct MIDITriggerToCVInterface : Module { }; +struct MidiTrigChoice : GridChoice { + MIDITriggerToCVInterface *module; + int id; + + MidiTrigChoice() { + box.size.y = mm2px(6.666); + textOffset.y -= 4; + textOffset.x -= 4; + } + + void setId(int id) override { + this->id = id; + } + + void step() override { + if (module->learningId == id) { + text = "LRN"; + color.a = 0.5; + } + else { + uint8_t note = module->learnedNotes[id]; + static const char *noteNames[] = { + "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" + }; + int oct = note / 12 - 1; + int semi = note % 12; + text = stringf("%s%d", noteNames[semi], oct); + color.a = 1.0; + } + } + + void onFocus(EventFocus &e) override { + e.consumed = true; + module->learningId = id; + } + + void onDefocus(EventDefocus &e) override { + module->learningId = -1; + } +}; + + +struct MidiTrigWidget : Grid16MidiWidget { + MIDITriggerToCVInterface *module; + GridChoice *createGridChoice() override { + MidiTrigChoice *gridChoice = new MidiTrigChoice(); + gridChoice->module = module; + return gridChoice; + } +}; + + struct MIDITriggerToCVInterfaceWidget : ModuleWidget { MIDITriggerToCVInterfaceWidget(MIDITriggerToCVInterface *module) : ModuleWidget(module) { setPanel(SVG::load(assetGlobal("res/Core/MIDITriggerToCVInterface.svg"))); @@ -184,9 +192,11 @@ struct MIDITriggerToCVInterfaceWidget : ModuleWidget { 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))); + MidiTrigWidget *midiWidget = Widget::create(mm2px(Vec(3.399621, 14.837339))); + midiWidget->module = module; midiWidget->box.size = mm2px(Vec(44, 54.667)); midiWidget->midiIO = &module->midiInput; + midiWidget->createGridChoices(); addChild(midiWidget); } diff --git a/src/ui/TextField.cpp b/src/ui/TextField.cpp index 2a57f448..dcbf550d 100644 --- a/src/ui/TextField.cpp +++ b/src/ui/TextField.cpp @@ -31,7 +31,6 @@ void TextField::draw(NVGcontext *vg) { } void TextField::onMouseDown(EventMouseDown &e) { - debug("%d", this == gFocusedWidget); if (e.button == 0) { cursor = selection = getTextPosition(e.pos); }