From 8622ac12f882a37f0101fad7ebf89e163f828a9c Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 10 Mar 2018 20:52:48 -0500 Subject: [PATCH] Partial QuadMidiToCvInterface --- src/Core/MIDIToCVInterface.cpp | 58 ++++---- src/Core/QuadMIDIToCVInterface.cpp | 217 ++++++++++++++++++++++++----- 2 files changed, 215 insertions(+), 60 deletions(-) diff --git a/src/Core/MIDIToCVInterface.cpp b/src/Core/MIDIToCVInterface.cpp index 7543de14..9685185f 100644 --- a/src/Core/MIDIToCVInterface.cpp +++ b/src/Core/MIDIToCVInterface.cpp @@ -6,12 +6,6 @@ #include -struct MidiNoteData { - uint8_t velocity = 0; - uint8_t aftertouch = 0; -}; - - struct MIDIToCVInterface : Module { enum ParamIds { NUM_PARAMS @@ -49,25 +43,45 @@ struct MIDIToCVInterface : Module { PulseGenerator continuePulse; PulseGenerator clockPulse; - MidiNoteData noteData[128]; - std::list heldNotes; + struct NoteData { + uint8_t velocity = 0; + uint8_t aftertouch = 0; + }; + + NoteData noteData[128]; + std::vector heldNotes; uint8_t lastNote; bool pedal; bool gate; - MIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + MIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS), heldNotes(128) { onReset(); } + 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"); + if (midiJ) + midiInput.fromJson(midiJ); + } + void onReset() override { heldNotes.clear(); - pedal = false; lastNote = 60; + pedal = false; + gate = false; } void pressNote(uint8_t note) { // Remove existing similar note - heldNotes.remove(note); + auto it = std::find(heldNotes.begin(), heldNotes.end(), note); + if (it != heldNotes.end()) + heldNotes.erase(it); // Push note heldNotes.push_back(note); lastNote = note; @@ -76,15 +90,15 @@ struct MIDIToCVInterface : Module { void releaseNote(uint8_t note) { // Remove the note - heldNotes.remove(note); + auto it = std::find(heldNotes.begin(), heldNotes.end(), note); + if (it != heldNotes.end()) + heldNotes.erase(it); // Hold note if pedal is pressed if (pedal) return; // Set last note if (!heldNotes.empty()) { - auto it2 = heldNotes.end(); - it2--; - lastNote = *it2; + lastNote = heldNotes[heldNotes.size() - 1]; gate = true; } else { @@ -124,6 +138,9 @@ struct MIDIToCVInterface : Module { outputs[CONTINUE_OUTPUT].value = continuePulse.process(deltaTime) ? 10.f : 0.f; outputs[CLOCK_OUTPUT].value = clockPulse.process(deltaTime) ? 10.f : 0.f; + // TODO + outputs[CLOCK_2_OUTPUT].value = 0.f; + outputs[CLOCK_HALF_OUTPUT].value = 0.f; } void processMessage(MidiMessage msg) { @@ -204,17 +221,6 @@ struct MIDIToCVInterface : Module { 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); - } }; diff --git a/src/Core/QuadMIDIToCVInterface.cpp b/src/Core/QuadMIDIToCVInterface.cpp index c39d05af..73a3a903 100644 --- a/src/Core/QuadMIDIToCVInterface.cpp +++ b/src/Core/QuadMIDIToCVInterface.cpp @@ -1,6 +1,8 @@ #include "Core.hpp" #include "midi.hpp" +#include + struct QuadMIDIToCVInterface : Module { enum ParamIds { @@ -10,22 +12,10 @@ struct QuadMIDIToCVInterface : Module { NUM_INPUTS }; enum OutputIds { - 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, + ENUMS(CV_OUTPUT, 4), + ENUMS(GATE_OUTPUT, 4), + ENUMS(VELOCITY_OUTPUT, 4), + ENUMS(AFTERTOUCH_OUTPUT, 4), NUM_OUTPUTS }; enum LightIds { @@ -34,9 +24,168 @@ struct QuadMIDIToCVInterface : Module { MidiInputQueue midiInput; - QuadMIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} + enum PolyMode { + ROTATE_MODE, + RESET_MODE, + REASSIGN_MODE, + UNISON_MODE, + NUM_MODES + }; + PolyMode polyMode = ROTATE_MODE; + + struct NoteData { + uint8_t velocity = 0; + uint8_t aftertouch = 0; + }; + + NoteData noteData[128]; + std::vector heldNotes; + uint8_t notes[4]; + bool gates[4]; + bool pedal; + + QuadMIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS), heldNotes(128) { + onReset(); + } + + json_t *toJson() override { + json_t *rootJ = json_object(); + json_object_set_new(rootJ, "midi", midiInput.toJson()); + json_object_set_new(rootJ, "polyMode", json_integer(polyMode)); + return rootJ; + } + + void fromJson(json_t *rootJ) override { + json_t *midiJ = json_object_get(rootJ, "midi"); + if (midiJ) + midiInput.fromJson(midiJ); + + json_t *polyModeJ = json_object_get(rootJ, "polyMode"); + if (polyModeJ) + polyMode = (PolyMode) json_integer_value(polyModeJ); + } + + void onReset() override { + for (int i = 0; i < 4; i++) { + notes[i] = 60; + gates[i] = false; + } + pedal = false; + } + + void pressNote(uint8_t note) { + // Remove existing similar note + auto it = std::find(heldNotes.begin(), heldNotes.end(), note); + if (it != heldNotes.end()) + heldNotes.erase(it); + // Push note + heldNotes.push_back(note); + + // Set notes and gates + switch (polyMode) { + case ROTATE_MODE: { + + } break; + case RESET_MODE: { - void step() override {} + } break; + case REASSIGN_MODE: { + + } break; + case UNISON_MODE: { + + } break; + default: break; + } + } + + void releaseNote(uint8_t note) { + // Remove the note + auto it = std::find(heldNotes.begin(), heldNotes.end(), note); + if (it != heldNotes.end()) + heldNotes.erase(it); + // Hold note if pedal is pressed + // if (pedal) + // return; + // // Set last note + // if (!heldNotes.empty()) { + // auto it2 = heldNotes.end(); + // it2--; + // lastNote = *it2; + // gate = true; + // } + // else { + // gate = false; + // } + } + + void pressPedal() { + pedal = true; + } + + void releasePedal() { + pedal = false; + releaseNote(255); + } + + void step() override { + MidiMessage msg; + while (midiInput.shift(&msg)) { + processMessage(msg); + } + + for (int i = 0; i < 4; i++) { + uint8_t lastNote = notes[i]; + outputs[CV_OUTPUT + i].value = (lastNote - 60) / 12.f; + outputs[GATE_OUTPUT + i].value = gates[i] ? 10.f : 0.f; + outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].velocity, 0, 127, 0.f, 10.f); + outputs[VELOCITY_OUTPUT + i].value = rescale(noteData[lastNote].aftertouch, 0, 127, 0.f, 10.f); + } + } + + void processMessage(MidiMessage msg) { + switch (msg.status()) { + // note off + case 0x8: { + // releaseNote(msg.data1); + } break; + // note on + case 0x9: { + if (msg.data2 > 0) { + uint8_t note = msg.data1 & 0x7f; + noteData[note].velocity = msg.data2; + // pressNote(msg.data1); + } + else { + // For some reason, some keyboards send a "note on" event with a velocity of 0 to signal that the key has been released. + // releaseNote(msg.data1); + } + } break; + // channel aftertouch + case 0xa: { + uint8_t note = msg.data1 & 0x7f; + noteData[note].aftertouch = msg.data2; + } break; + // cc + case 0xb: { + processCC(msg); + } break; + default: break; + } + } + + void processCC(MidiMessage msg) { + switch (msg.data1) { + // sustain + case 0x40: { + if (msg.data2 >= 64) + pressPedal(); + else + releasePedal(); + } break; + default: break; + } + } }; @@ -49,22 +198,22 @@ struct QuadMIDIToCVInterfaceWidget : ModuleWidget { 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)); + addOutput(Port::create(mm2px(Vec(3.894335, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 0)); + addOutput(Port::create(mm2px(Vec(15.494659, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 0)); + addOutput(Port::create(mm2px(Vec(27.094986, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 0)); + addOutput(Port::create(mm2px(Vec(38.693935, 60.144478)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 0)); + addOutput(Port::create(mm2px(Vec(3.894335, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 1)); + addOutput(Port::create(mm2px(Vec(15.494659, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 1)); + addOutput(Port::create(mm2px(Vec(27.094986, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 1)); + addOutput(Port::create(mm2px(Vec(38.693935, 76.144882)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 1)); + addOutput(Port::create(mm2px(Vec(3.894335, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 2)); + addOutput(Port::create(mm2px(Vec(15.494659, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 2)); + addOutput(Port::create(mm2px(Vec(27.094986, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 2)); + addOutput(Port::create(mm2px(Vec(38.693935, 92.143906)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 2)); + addOutput(Port::create(mm2px(Vec(3.894335, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::CV_OUTPUT + 3)); + addOutput(Port::create(mm2px(Vec(15.494659, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::GATE_OUTPUT + 3)); + addOutput(Port::create(mm2px(Vec(27.094986, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::VELOCITY_OUTPUT + 3)); + addOutput(Port::create(mm2px(Vec(38.693935, 108.1443)), Port::OUTPUT, module, QuadMIDIToCVInterface::AFTERTOUCH_OUTPUT + 3)); MidiWidget *midiWidget = Widget::create(mm2px(Vec(3.4009969, 14.837336))); midiWidget->box.size = mm2px(Vec(44, 28));