From 617236be0666a1051d50bcc096e2ca5f4fcb5554 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Mon, 19 Mar 2018 13:51:54 -0400 Subject: [PATCH] Add clock divisions to MIDI-1 --- include/app.hpp | 3 - include/ui.hpp | 4 ++ src/Core/MIDICCToCVInterface.cpp | 3 +- src/Core/MIDIToCVInterface.cpp | 79 +++++++++++++++++++++++++-- src/Core/MIDITriggerToCVInterface.cpp | 3 +- 5 files changed, 82 insertions(+), 10 deletions(-) diff --git a/include/app.hpp b/include/app.hpp index 08f225c4..ad61c0ca 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -8,9 +8,6 @@ static const float SVG_DPI = 75.0; static const float MM_PER_IN = 25.4; -#define CHECKMARK_STRING "✔" -#define CHECKMARK(_cond) ((_cond) ? CHECKMARK_STRING : "") - namespace rack { diff --git a/include/ui.hpp b/include/ui.hpp index b8f9195f..39708aab 100644 --- a/include/ui.hpp +++ b/include/ui.hpp @@ -3,6 +3,10 @@ #include "blendish.h" +#define CHECKMARK_STRING "✔" +#define CHECKMARK(_cond) ((_cond) ? CHECKMARK_STRING : "") + + namespace rack { //////////////////// diff --git a/src/Core/MIDICCToCVInterface.cpp b/src/Core/MIDICCToCVInterface.cpp index 5029e609..20dba917 100644 --- a/src/Core/MIDICCToCVInterface.cpp +++ b/src/Core/MIDICCToCVInterface.cpp @@ -97,7 +97,8 @@ struct MIDICCToCVInterface : Module { } json_t *midiJ = json_object_get(rootJ, "midi"); - midiInput.fromJson(midiJ); + if (midiJ) + midiInput.fromJson(midiJ); } }; diff --git a/src/Core/MIDIToCVInterface.cpp b/src/Core/MIDIToCVInterface.cpp index 28c75d67..662099b1 100644 --- a/src/Core/MIDIToCVInterface.cpp +++ b/src/Core/MIDIToCVInterface.cpp @@ -39,11 +39,12 @@ struct MIDIToCVInterface : Module { uint16_t pitch = 0; ExponentialFilter pitchFilter; PulseGenerator retriggerPulse; - PulseGenerator clock1Pulse; - PulseGenerator clock2Pulse; + PulseGenerator clockPulses[2]; PulseGenerator startPulse; PulseGenerator stopPulse; PulseGenerator continuePulse; + int clock = 0; + int divisions[2]; struct NoteData { uint8_t velocity = 0; @@ -62,11 +63,28 @@ struct MIDIToCVInterface : Module { json_t *toJson() override { json_t *rootJ = json_object(); + + json_t *divisionsJ = json_array(); + for (int i = 0; i < 2; i++) { + json_t *divisionJ = json_integer(divisions[i]); + json_array_append_new(divisionsJ, divisionJ); + } + json_object_set_new(rootJ, "divisions", divisionsJ); + json_object_set_new(rootJ, "midi", midiInput.toJson()); return rootJ; } void fromJson(json_t *rootJ) override { + json_t *divisionsJ = json_object_get(rootJ, "divisions"); + if (divisionsJ) { + for (int i = 0; i < 2; i++) { + json_t *divisionJ = json_array_get(divisionsJ, i); + if (divisionJ) + divisions[i] = json_integer_value(divisionJ); + } + } + json_t *midiJ = json_object_get(rootJ, "midi"); if (midiJ) midiInput.fromJson(midiJ); @@ -77,6 +95,9 @@ struct MIDIToCVInterface : Module { lastNote = 60; pedal = false; gate = false; + clock = 0; + divisions[0] = 24; + divisions[1] = 6; } void pressNote(uint8_t note) { @@ -137,8 +158,8 @@ struct MIDIToCVInterface : Module { outputs[MOD_OUTPUT].value = modFilter.process(rescale(mod, 0, 127, 0.f, 10.f)); outputs[RETRIGGER_OUTPUT].value = retriggerPulse.process(deltaTime) ? 10.f : 0.f; - outputs[CLOCK_1_OUTPUT].value = clock1Pulse.process(deltaTime) ? 10.f : 0.f; - outputs[CLOCK_2_OUTPUT].value = clock2Pulse.process(deltaTime) ? 10.f : 0.f; + outputs[CLOCK_1_OUTPUT].value = clockPulses[0].process(deltaTime) ? 10.f : 0.f; + outputs[CLOCK_2_OUTPUT].value = clockPulses[1].process(deltaTime) ? 10.f : 0.f; outputs[START_OUTPUT].value = startPulse.process(deltaTime) ? 10.f : 0.f; outputs[STOP_OUTPUT].value = stopPulse.process(deltaTime) ? 10.f : 0.f; @@ -205,11 +226,20 @@ struct MIDIToCVInterface : Module { switch (msg.channel()) { // Timing case 0x8: { - // TODO + if (clock % divisions[0] == 0) { + clockPulses[0].trigger(1e-3); + } + if (clock % divisions[1] == 0) { + clockPulses[1].trigger(1e-3); + } + if (++clock >= (24*16*16)) { + clock = 0; + } } break; // Start case 0xa: { startPulse.trigger(1e-3); + clock = 0; } break; // Continue case 0xb: { @@ -252,6 +282,45 @@ struct MIDIToCVInterfaceWidget : ModuleWidget { midiWidget->midiIO = &module->midiInput; addChild(midiWidget); } + + void appendContextMenu(Menu *menu) override { + MIDIToCVInterface *module = dynamic_cast(this->module); + + struct ClockDivisionItem : MenuItem { + MIDIToCVInterface *module; + int index; + int division; + void onAction(EventAction &e) override { + module->divisions[index] = division; + } + }; + + struct ClockItem : MenuItem { + MIDIToCVInterface *module; + int index; + Menu *createChildMenu() override { + Menu *menu = new Menu(); + std::vector divisions = {24*4, 24*2, 24, 24/2, 24/4, 24/8, 2, 1}; + std::vector divisionNames = {"Whole", "Half", "Quarter", "8th", "16th", "32nd", "48th", "96th"}; + for (size_t i = 0; i < divisions.size(); i++) { + ClockDivisionItem *item = MenuItem::create(divisionNames[i], CHECKMARK(module->divisions[index] == divisions[i])); + item->module = module; + item->index = index; + item->division = divisions[i]; + menu->addChild(item); + } + return menu; + } + }; + + menu->addChild(construct()); + for (int i = 0; i < 2; i++) { + ClockItem *item = MenuItem::create(stringf("CLK %d rate", i + 1)); + item->module = module; + item->index = i; + menu->addChild(item); + } + } }; diff --git a/src/Core/MIDITriggerToCVInterface.cpp b/src/Core/MIDITriggerToCVInterface.cpp index 52b0cff0..c73c066a 100644 --- a/src/Core/MIDITriggerToCVInterface.cpp +++ b/src/Core/MIDITriggerToCVInterface.cpp @@ -127,7 +127,8 @@ struct MIDITriggerToCVInterface : Module { } json_t *midiJ = json_object_get(rootJ, "midi"); - midiInput.fromJson(midiJ); + if (midiJ) + midiInput.fromJson(midiJ); } };