From 44f85a8e466e3facfe1c38ea5e4f3ad394ae5bb3 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sun, 24 Aug 2025 00:19:47 -0400 Subject: [PATCH] MIDI to Gate: Add Aftertouch "Gate amplitude" mode. --- src/core/MIDI_Gate.cpp | 64 +++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/src/core/MIDI_Gate.cpp b/src/core/MIDI_Gate.cpp index d1e71ace..d4bf1a0e 100644 --- a/src/core/MIDI_Gate.cpp +++ b/src/core/MIDI_Gate.cpp @@ -35,7 +35,12 @@ struct MIDI_Gate : Module { // Settings - bool velocityMode; + enum VelocityMode { + FIXED_MODE, + VELOCITY_MODE, + AFTERTOUCH_MODE, + }; + VelocityMode velocityMode; bool mpeMode; bool trigMode; @@ -55,7 +60,7 @@ struct MIDI_Gate : Module { } learningId = -1; midiInput.reset(); - velocityMode = false; + velocityMode = FIXED_MODE; mpeMode = false; trigMode = false; panic(); @@ -65,7 +70,7 @@ struct MIDI_Gate : Module { for (int i = 0; i < 16; i++) { for (int c = 0; c < 16; c++) { gates[i][c] = false; - velocities[i][c] = 0; + velocities[i][c] = 127; trigPulses[i][c].reset(); } } @@ -83,7 +88,9 @@ struct MIDI_Gate : Module { for (int c = 0; c < channels; c++) { bool pulse = trigPulses[i][c].process(args.sampleTime); bool gate = pulse || (!trigMode && gates[i][c]); - float velocity = gate ? velocityMode ? (velocities[i][c] / 127.f) : 1.f : 0.f; + float velocity = gate ? 1.f : 0.f; + if (velocityMode != FIXED_MODE) + velocity *= velocities[i][c] / 127.f; outputs[GATE_OUTPUTS + i].setVoltage(velocity * 10.f, c); } outputs[GATE_OUTPUTS + i].setChannels(channels); @@ -98,14 +105,38 @@ struct MIDI_Gate : Module { } break; // note on case 0x9: { - if (msg.getValue() > 0) { - pressNote(msg.getChannel(), msg.getNote(), msg.getValue()); + uint8_t velocity = msg.getValue(); + if (velocity > 0) { + pressNote(msg.getChannel(), msg.getNote(), velocity); } else { // Note-on event with velocity 0 is an alternative for note-off event. releaseNote(msg.getChannel(), msg.getNote()); } } break; + // polyphonic pressure/aftertouch + case 0xa: { + if (velocityMode == AFTERTOUCH_MODE) { + uint8_t c = mpeMode ? msg.getChannel() : 0; + uint8_t note = msg.getNote(); + uint8_t velocity = msg.getValue(); + for (int i = 0; i < 16; i++) { + if (learnedNotes[i] == note) { + velocities[i][c] = velocity; + } + } + } + } break; + // channel pressure/aftertouch + case 0xd: { + if (velocityMode == AFTERTOUCH_MODE) { + uint8_t c = mpeMode ? msg.getChannel() : 0; + uint8_t velocity = msg.getNote(); + for (int i = 0; i < 16; i++) { + velocities[i][c] = velocity; + } + } + } break; default: break; } } @@ -121,7 +152,8 @@ struct MIDI_Gate : Module { for (int i = 0; i < 16; i++) { if (learnedNotes[i] == note) { gates[i][c] = true; - velocities[i][c] = vel; + if (velocityMode == VELOCITY_MODE) + velocities[i][c] = vel; trigPulses[i][c].trigger(1e-3f); } } @@ -153,12 +185,11 @@ struct MIDI_Gate : Module { json_t* notesJ = json_array(); for (int i = 0; i < 16; i++) { - json_t* noteJ = json_integer(learnedNotes[i]); - json_array_append_new(notesJ, noteJ); + json_array_append_new(notesJ, json_integer(learnedNotes[i])); } json_object_set_new(rootJ, "notes", notesJ); - json_object_set_new(rootJ, "velocity", json_boolean(velocityMode)); + json_object_set_new(rootJ, "velocity", json_integer(velocityMode)); json_object_set_new(rootJ, "mpeMode", json_boolean(mpeMode)); @@ -180,8 +211,11 @@ struct MIDI_Gate : Module { } json_t* velocityJ = json_object_get(rootJ, "velocity"); - if (velocityJ) - velocityMode = json_boolean_value(velocityJ); + // Boolean in Rack <=v2.6.4 + if (json_is_true(velocityJ)) + velocityMode = VELOCITY_MODE; + else if (json_is_integer(velocityJ)) + velocityMode = VelocityMode(json_integer_value(velocityJ)); json_t* mpeModeJ = json_object_get(rootJ, "mpeMode"); if (mpeModeJ) @@ -238,7 +272,11 @@ struct MIDI_GateWidget : ModuleWidget { menu->addChild(new MenuSeparator); - menu->addChild(createBoolPtrMenuItem("Velocity mode", "", &module->velocityMode)); + menu->addChild(createIndexPtrSubmenuItem("Gate amplitude", { + "10V", + "Velocity", + "Aftertouch", + }, &module->velocityMode)); menu->addChild(createBoolPtrMenuItem("MPE mode", "", &module->mpeMode));