| @@ -302,179 +302,234 @@ struct Davies1900hLargeRedKnob : Davies1900hKnob { | |||||
| struct Rogan : app::SvgKnob { | struct Rogan : app::SvgKnob { | ||||
| widget::SvgWidget* bg; | |||||
| widget::SvgWidget* fg; | |||||
| Rogan() { | Rogan() { | ||||
| minAngle = -0.83 * M_PI; | minAngle = -0.83 * M_PI; | ||||
| maxAngle = 0.83 * M_PI; | maxAngle = 0.83 * M_PI; | ||||
| bg = new widget::SvgWidget; | |||||
| fb->addChildBelow(bg, tw); | |||||
| fg = new widget::SvgWidget; | |||||
| fb->addChildAbove(fg, tw); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan6PSWhite : Rogan { | struct Rogan6PSWhite : Rogan { | ||||
| Rogan6PSWhite() { | Rogan6PSWhite() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan6PSWhite.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan6PSWhite.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan5PSGray : Rogan { | struct Rogan5PSGray : Rogan { | ||||
| Rogan5PSGray() { | Rogan5PSGray() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan5PSGray.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan5PSGray.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PSBlue : Rogan { | struct Rogan3PSBlue : Rogan { | ||||
| Rogan3PSBlue() { | Rogan3PSBlue() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSBlue.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSBlue.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PSRed : Rogan { | struct Rogan3PSRed : Rogan { | ||||
| Rogan3PSRed() { | Rogan3PSRed() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSRed.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSRed.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PSGreen : Rogan { | struct Rogan3PSGreen : Rogan { | ||||
| Rogan3PSGreen() { | Rogan3PSGreen() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSGreen.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSGreen.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PSWhite : Rogan { | struct Rogan3PSWhite : Rogan { | ||||
| Rogan3PSWhite() { | Rogan3PSWhite() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite.svg"))); | ||||
| widget::SvgWidget* bg = new widget::SvgWidget; | |||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | ||||
| fb->addChildBelow(bg, tw); | |||||
| widget::SvgWidget* fg = new widget::SvgWidget; | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | ||||
| fb->addChildAbove(fg, tw); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PBlue : Rogan { | struct Rogan3PBlue : Rogan { | ||||
| Rogan3PBlue() { | Rogan3PBlue() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PBlue.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PBlue.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PRed : Rogan { | struct Rogan3PRed : Rogan { | ||||
| Rogan3PRed() { | Rogan3PRed() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PRed.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PRed.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PGreen : Rogan { | struct Rogan3PGreen : Rogan { | ||||
| Rogan3PGreen() { | Rogan3PGreen() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PGreen.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PGreen.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan3PWhite : Rogan { | struct Rogan3PWhite : Rogan { | ||||
| Rogan3PWhite() { | Rogan3PWhite() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PWhite.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PWhite.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2SGray : Rogan { | struct Rogan2SGray : Rogan { | ||||
| Rogan2SGray() { | Rogan2SGray() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2SGray.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2SGray.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PSBlue : Rogan { | struct Rogan2PSBlue : Rogan { | ||||
| Rogan2PSBlue() { | Rogan2PSBlue() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSBlue.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSBlue.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PSRed : Rogan { | struct Rogan2PSRed : Rogan { | ||||
| Rogan2PSRed() { | Rogan2PSRed() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSRed.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSRed.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PSGreen : Rogan { | struct Rogan2PSGreen : Rogan { | ||||
| Rogan2PSGreen() { | Rogan2PSGreen() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSGreen.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSGreen.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PSWhite : Rogan { | struct Rogan2PSWhite : Rogan { | ||||
| Rogan2PSWhite() { | Rogan2PSWhite() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSWhite.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PSWhite.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PBlue : Rogan { | struct Rogan2PBlue : Rogan { | ||||
| Rogan2PBlue() { | Rogan2PBlue() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PBlue.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PBlue.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PRed : Rogan { | struct Rogan2PRed : Rogan { | ||||
| Rogan2PRed() { | Rogan2PRed() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PRed.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PRed.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PGreen : Rogan { | struct Rogan2PGreen : Rogan { | ||||
| Rogan2PGreen() { | Rogan2PGreen() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PGreen.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PGreen.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan2PWhite : Rogan { | struct Rogan2PWhite : Rogan { | ||||
| Rogan2PWhite() { | Rogan2PWhite() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PWhite.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan2PWhite.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PSBlue : Rogan { | struct Rogan1PSBlue : Rogan { | ||||
| Rogan1PSBlue() { | Rogan1PSBlue() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSBlue.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSBlue.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PSRed : Rogan { | struct Rogan1PSRed : Rogan { | ||||
| Rogan1PSRed() { | Rogan1PSRed() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSRed.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSRed.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PSGreen : Rogan { | struct Rogan1PSGreen : Rogan { | ||||
| Rogan1PSGreen() { | Rogan1PSGreen() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSGreen.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSGreen.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PSWhite : Rogan { | struct Rogan1PSWhite : Rogan { | ||||
| Rogan1PSWhite() { | Rogan1PSWhite() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSWhite.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PSWhite.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PBlue : Rogan { | struct Rogan1PBlue : Rogan { | ||||
| Rogan1PBlue() { | Rogan1PBlue() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PBlue.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PBlue.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PRed : Rogan { | struct Rogan1PRed : Rogan { | ||||
| Rogan1PRed() { | Rogan1PRed() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PRed.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PRed.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PGreen : Rogan { | struct Rogan1PGreen : Rogan { | ||||
| Rogan1PGreen() { | Rogan1PGreen() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PGreen.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PGreen.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| struct Rogan1PWhite : Rogan { | struct Rogan1PWhite : Rogan { | ||||
| Rogan1PWhite() { | Rogan1PWhite() { | ||||
| setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PWhite.svg"))); | setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan1PWhite.svg"))); | ||||
| bg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-bg.svg"))); | |||||
| fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg"))); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -21,6 +21,7 @@ struct MIDI_CC : Module { | |||||
| }; | }; | ||||
| midi::InputQueue midiInput; | midi::InputQueue midiInput; | ||||
| /** [cc][channel] */ | /** [cc][channel] */ | ||||
| int8_t ccValues[128][16]; | int8_t ccValues[128][16]; | ||||
| /** When LSB is enabled for CC 0-31, the MSB is stored here until the LSB is received. | /** When LSB is enabled for CC 0-31, the MSB is stored here until the LSB is received. | ||||
| @@ -33,7 +34,7 @@ struct MIDI_CC : Module { | |||||
| dsp::ExponentialFilter valueFilters[16][16]; | dsp::ExponentialFilter valueFilters[16][16]; | ||||
| bool smooth; | bool smooth; | ||||
| bool mpeMode; | bool mpeMode; | ||||
| bool lsbEnabled; | |||||
| bool lsbMode; | |||||
| MIDI_CC() { | MIDI_CC() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
| @@ -66,7 +67,7 @@ struct MIDI_CC : Module { | |||||
| midiInput.reset(); | midiInput.reset(); | ||||
| smooth = true; | smooth = true; | ||||
| mpeMode = false; | mpeMode = false; | ||||
| lsbEnabled = false; | |||||
| lsbMode = false; | |||||
| } | } | ||||
| void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
| @@ -80,6 +81,7 @@ struct MIDI_CC : Module { | |||||
| } | } | ||||
| int channels = mpeMode ? 16 : 1; | int channels = mpeMode ? 16 : 1; | ||||
| for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
| if (!outputs[CC_OUTPUT + i].isConnected()) | if (!outputs[CC_OUTPUT + i].isConnected()) | ||||
| continue; | continue; | ||||
| @@ -89,7 +91,7 @@ struct MIDI_CC : Module { | |||||
| for (int c = 0; c < channels; c++) { | for (int c = 0; c < channels; c++) { | ||||
| int16_t cellValue = int16_t(ccValues[cc][c]) * 128; | int16_t cellValue = int16_t(ccValues[cc][c]) * 128; | ||||
| if (lsbEnabled && cc < 32) | |||||
| if (lsbMode && cc < 32) | |||||
| cellValue += ccValues[cc + 32][c]; | cellValue += ccValues[cc + 32][c]; | ||||
| // Maximum value for 14-bit CC should be MSB=127 LSB=0, not MSB=127 LSB=127, because this is the maximum value that 7-bit controllers can send. | // Maximum value for 14-bit CC should be MSB=127 LSB=0, not MSB=127 LSB=127, because this is the maximum value that 7-bit controllers can send. | ||||
| float value = float(cellValue) / (128 * 127); | float value = float(cellValue) / (128 * 127); | ||||
| @@ -135,11 +137,11 @@ struct MIDI_CC : Module { | |||||
| learningId = -1; | learningId = -1; | ||||
| } | } | ||||
| if (lsbEnabled && cc < 32) { | |||||
| if (lsbMode && cc < 32) { | |||||
| // Don't set MSB yet. Wait for LSB to be received. | // Don't set MSB yet. Wait for LSB to be received. | ||||
| msbValues[cc][c] = value; | msbValues[cc][c] = value; | ||||
| } | } | ||||
| else if (lsbEnabled && 32 <= cc && cc < 64) { | |||||
| else if (lsbMode && 32 <= cc && cc < 64) { | |||||
| // Apply MSB when LSB is received | // Apply MSB when LSB is received | ||||
| ccValues[cc - 32][c] = msbValues[cc - 32][c]; | ccValues[cc - 32][c] = msbValues[cc - 32][c]; | ||||
| ccValues[cc][c] = value; | ccValues[cc][c] = value; | ||||
| @@ -170,7 +172,7 @@ struct MIDI_CC : Module { | |||||
| json_object_set_new(rootJ, "smooth", json_boolean(smooth)); | json_object_set_new(rootJ, "smooth", json_boolean(smooth)); | ||||
| json_object_set_new(rootJ, "mpeMode", json_boolean(mpeMode)); | json_object_set_new(rootJ, "mpeMode", json_boolean(mpeMode)); | ||||
| json_object_set_new(rootJ, "lsbEnabled", json_boolean(lsbEnabled)); | |||||
| json_object_set_new(rootJ, "lsbMode", json_boolean(lsbMode)); | |||||
| return rootJ; | return rootJ; | ||||
| } | } | ||||
| @@ -206,9 +208,9 @@ struct MIDI_CC : Module { | |||||
| if (mpeModeJ) | if (mpeModeJ) | ||||
| mpeMode = json_boolean_value(mpeModeJ); | mpeMode = json_boolean_value(mpeModeJ); | ||||
| json_t* lsbEnabledJ = json_object_get(rootJ, "lsbEnabled"); | |||||
| json_t* lsbEnabledJ = json_object_get(rootJ, "lsbMode"); | |||||
| if (lsbEnabledJ) | if (lsbEnabledJ) | ||||
| lsbEnabled = json_boolean_value(lsbEnabledJ); | |||||
| lsbMode = json_boolean_value(lsbEnabledJ); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -259,7 +261,6 @@ struct MIDI_CCWidget : ModuleWidget { | |||||
| module->smooth ^= true; | module->smooth ^= true; | ||||
| } | } | ||||
| }; | }; | ||||
| SmoothItem* smoothItem = new SmoothItem; | SmoothItem* smoothItem = new SmoothItem; | ||||
| smoothItem->text = "Smooth CC"; | smoothItem->text = "Smooth CC"; | ||||
| smoothItem->rightText = CHECKMARK(module->smooth); | smoothItem->rightText = CHECKMARK(module->smooth); | ||||
| @@ -272,25 +273,23 @@ struct MIDI_CCWidget : ModuleWidget { | |||||
| module->mpeMode ^= true; | module->mpeMode ^= true; | ||||
| } | } | ||||
| }; | }; | ||||
| MpeModeItem* mpeModeItem = new MpeModeItem; | MpeModeItem* mpeModeItem = new MpeModeItem; | ||||
| mpeModeItem->text = "MPE mode"; | mpeModeItem->text = "MPE mode"; | ||||
| mpeModeItem->rightText = CHECKMARK(module->mpeMode); | mpeModeItem->rightText = CHECKMARK(module->mpeMode); | ||||
| mpeModeItem->module = module; | mpeModeItem->module = module; | ||||
| menu->addChild(mpeModeItem); | menu->addChild(mpeModeItem); | ||||
| struct LSBItem : MenuItem { | |||||
| struct LsbModeItem : MenuItem { | |||||
| MIDI_CC* module; | MIDI_CC* module; | ||||
| void onAction(const ActionEvent& e) override { | void onAction(const ActionEvent& e) override { | ||||
| module->lsbEnabled ^= true; | |||||
| module->lsbMode ^= true; | |||||
| } | } | ||||
| }; | }; | ||||
| LSBItem* highResolutionItem = new LSBItem; | |||||
| highResolutionItem->text = "CC 0-31 controls are 14-bit"; | |||||
| highResolutionItem->rightText = CHECKMARK(module->lsbEnabled); | |||||
| highResolutionItem->module = module; | |||||
| menu->addChild(highResolutionItem); | |||||
| LsbModeItem* lsbItem = new LsbModeItem; | |||||
| lsbItem->text = "CC 0-31 controls are 14-bit"; | |||||
| lsbItem->rightText = CHECKMARK(module->lsbMode); | |||||
| lsbItem->module = module; | |||||
| menu->addChild(lsbItem); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -15,11 +15,11 @@ struct MIDI_CV : Module { | |||||
| NUM_INPUTS | NUM_INPUTS | ||||
| }; | }; | ||||
| enum OutputIds { | enum OutputIds { | ||||
| CV_OUTPUT, | |||||
| PITCH_OUTPUT, | |||||
| GATE_OUTPUT, | GATE_OUTPUT, | ||||
| VELOCITY_OUTPUT, | VELOCITY_OUTPUT, | ||||
| AFTERTOUCH_OUTPUT, | AFTERTOUCH_OUTPUT, | ||||
| PITCH_OUTPUT, | |||||
| PW_OUTPUT, | |||||
| MOD_OUTPUT, | MOD_OUTPUT, | ||||
| RETRIGGER_OUTPUT, | RETRIGGER_OUTPUT, | ||||
| CLOCK_OUTPUT, | CLOCK_OUTPUT, | ||||
| @@ -59,10 +59,14 @@ struct MIDI_CV : Module { | |||||
| int rotateIndex; | int rotateIndex; | ||||
| // 16 channels for MPE. When MPE is disabled, only the first channel is used. | |||||
| uint16_t pitches[16]; | |||||
| /** Pitch wheel. | |||||
| When MPE is disabled, only the first channel is used. | |||||
| [channel] | |||||
| */ | |||||
| uint16_t pws[16]; | |||||
| /** [channel] */ | |||||
| uint8_t mods[16]; | uint8_t mods[16]; | ||||
| dsp::ExponentialFilter pitchFilters[16]; | |||||
| dsp::ExponentialFilter pwFilters[16]; | |||||
| dsp::ExponentialFilter modFilters[16]; | dsp::ExponentialFilter modFilters[16]; | ||||
| dsp::PulseGenerator clockPulse; | dsp::PulseGenerator clockPulse; | ||||
| @@ -74,11 +78,11 @@ struct MIDI_CV : Module { | |||||
| MIDI_CV() { | MIDI_CV() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
| configOutput(CV_OUTPUT, "V/oct"); | |||||
| configOutput(PITCH_OUTPUT, "Pitch (1V/oct)"); | |||||
| configOutput(GATE_OUTPUT, "Gate"); | configOutput(GATE_OUTPUT, "Gate"); | ||||
| configOutput(VELOCITY_OUTPUT, "Velocity"); | configOutput(VELOCITY_OUTPUT, "Velocity"); | ||||
| configOutput(AFTERTOUCH_OUTPUT, "Aftertouch"); | configOutput(AFTERTOUCH_OUTPUT, "Aftertouch"); | ||||
| configOutput(PITCH_OUTPUT, "Pitch wheel"); | |||||
| configOutput(PW_OUTPUT, "Pitch wheel"); | |||||
| configOutput(MOD_OUTPUT, "Mod wheel"); | configOutput(MOD_OUTPUT, "Mod wheel"); | ||||
| configOutput(RETRIGGER_OUTPUT, "Retrigger"); | configOutput(RETRIGGER_OUTPUT, "Retrigger"); | ||||
| configOutput(CLOCK_OUTPUT, "Clock"); | configOutput(CLOCK_OUTPUT, "Clock"); | ||||
| @@ -88,7 +92,7 @@ struct MIDI_CV : Module { | |||||
| configOutput(CONTINUE_OUTPUT, "Continue"); | configOutput(CONTINUE_OUTPUT, "Continue"); | ||||
| heldNotes.reserve(128); | heldNotes.reserve(128); | ||||
| for (int c = 0; c < 16; c++) { | for (int c = 0; c < 16; c++) { | ||||
| pitchFilters[c].setTau(1 / 30.f); | |||||
| pwFilters[c].setTau(1 / 30.f); | |||||
| modFilters[c].setTau(1 / 30.f); | modFilters[c].setTau(1 / 30.f); | ||||
| } | } | ||||
| onReset(); | onReset(); | ||||
| @@ -110,9 +114,9 @@ struct MIDI_CV : Module { | |||||
| gates[c] = false; | gates[c] = false; | ||||
| velocities[c] = 0; | velocities[c] = 0; | ||||
| aftertouches[c] = 0; | aftertouches[c] = 0; | ||||
| pitches[c] = 8192; | |||||
| pws[c] = 8192; | |||||
| mods[c] = 0; | mods[c] = 0; | ||||
| pitchFilters[c].reset(); | |||||
| pwFilters[c].reset(); | |||||
| modFilters[c].reset(); | modFilters[c].reset(); | ||||
| } | } | ||||
| pedal = false; | pedal = false; | ||||
| @@ -130,13 +134,13 @@ struct MIDI_CV : Module { | |||||
| midiInput.queue.pop(); | midiInput.queue.pop(); | ||||
| } | } | ||||
| outputs[CV_OUTPUT].setChannels(channels); | |||||
| outputs[PITCH_OUTPUT].setChannels(channels); | |||||
| outputs[GATE_OUTPUT].setChannels(channels); | outputs[GATE_OUTPUT].setChannels(channels); | ||||
| outputs[VELOCITY_OUTPUT].setChannels(channels); | outputs[VELOCITY_OUTPUT].setChannels(channels); | ||||
| outputs[AFTERTOUCH_OUTPUT].setChannels(channels); | outputs[AFTERTOUCH_OUTPUT].setChannels(channels); | ||||
| outputs[RETRIGGER_OUTPUT].setChannels(channels); | outputs[RETRIGGER_OUTPUT].setChannels(channels); | ||||
| for (int c = 0; c < channels; c++) { | for (int c = 0; c < channels; c++) { | ||||
| outputs[CV_OUTPUT].setVoltage((notes[c] - 60.f) / 12.f, c); | |||||
| outputs[PITCH_OUTPUT].setVoltage((notes[c] - 60.f) / 12.f, c); | |||||
| outputs[GATE_OUTPUT].setVoltage(gates[c] ? 10.f : 0.f, c); | outputs[GATE_OUTPUT].setVoltage(gates[c] ? 10.f : 0.f, c); | ||||
| outputs[VELOCITY_OUTPUT].setVoltage(rescale(velocities[c], 0, 127, 0.f, 10.f), c); | outputs[VELOCITY_OUTPUT].setVoltage(rescale(velocities[c], 0, 127, 0.f, 10.f), c); | ||||
| outputs[AFTERTOUCH_OUTPUT].setVoltage(rescale(aftertouches[c], 0, 127, 0.f, 10.f), c); | outputs[AFTERTOUCH_OUTPUT].setVoltage(rescale(aftertouches[c], 0, 127, 0.f, 10.f), c); | ||||
| @@ -144,37 +148,25 @@ struct MIDI_CV : Module { | |||||
| } | } | ||||
| // Set pitch and mod wheel | // Set pitch and mod wheel | ||||
| auto updatePitch = [&](int c) { | |||||
| float pitch = ((int) pitches[c] - 8192) / 8191.f; | |||||
| pitch = clamp(pitch, -1.f, 1.f); | |||||
| int wheelChannels = (polyMode == MPE_MODE) ? 16 : 1; | |||||
| outputs[PW_OUTPUT].setChannels(wheelChannels); | |||||
| outputs[MOD_OUTPUT].setChannels(wheelChannels); | |||||
| for (int c = 0; c < wheelChannels; c++) { | |||||
| float pw = ((int) pws[c] - 8192) / 8191.f; | |||||
| pw = clamp(pw, -1.f, 1.f); | |||||
| if (smooth) | if (smooth) | ||||
| pitch = pitchFilters[c].process(args.sampleTime, pitch); | |||||
| pw = pwFilters[c].process(args.sampleTime, pw); | |||||
| else | else | ||||
| pitchFilters[c].out = pitch; | |||||
| outputs[PITCH_OUTPUT].setVoltage(pitchFilters[c].out * 5.f); | |||||
| }; | |||||
| auto updateMod = [&](int c) { | |||||
| pwFilters[c].out = pw; | |||||
| outputs[PW_OUTPUT].setVoltage(pw * 5.f); | |||||
| float mod = mods[c] / 127.f; | float mod = mods[c] / 127.f; | ||||
| mod = clamp(mod, 0.f, 1.f); | mod = clamp(mod, 0.f, 1.f); | ||||
| if (smooth) | if (smooth) | ||||
| modFilters[c].process(args.sampleTime, mod); | |||||
| mod = modFilters[c].process(args.sampleTime, mod); | |||||
| else | else | ||||
| modFilters[c].out = mod; | modFilters[c].out = mod; | ||||
| outputs[MOD_OUTPUT].setVoltage(modFilters[c].out * 10.f); | |||||
| }; | |||||
| if (polyMode == MPE_MODE) { | |||||
| for (int c = 0; c < channels; c++) { | |||||
| updatePitch(c); | |||||
| outputs[PITCH_OUTPUT].setChannels(1); | |||||
| updateMod(c); | |||||
| outputs[MOD_OUTPUT].setChannels(1); | |||||
| } | |||||
| } | |||||
| else { | |||||
| updatePitch(0); | |||||
| outputs[PITCH_OUTPUT].setChannels(1); | |||||
| updateMod(0); | |||||
| outputs[MOD_OUTPUT].setChannels(1); | |||||
| outputs[MOD_OUTPUT].setVoltage(mod * 10.f); | |||||
| } | } | ||||
| outputs[CLOCK_OUTPUT].setVoltage(clockPulse.process(args.sampleTime) ? 10.f : 0.f); | outputs[CLOCK_OUTPUT].setVoltage(clockPulse.process(args.sampleTime) ? 10.f : 0.f); | ||||
| @@ -233,7 +225,7 @@ struct MIDI_CV : Module { | |||||
| // pitch wheel | // pitch wheel | ||||
| case 0xe: { | case 0xe: { | ||||
| int c = (polyMode == MPE_MODE) ? msg.getChannel() : 0; | int c = (polyMode == MPE_MODE) ? msg.getChannel() : 0; | ||||
| pitches[c] = ((uint16_t) msg.getValue() << 7) | msg.getNote(); | |||||
| pws[c] = ((uint16_t) msg.getValue() << 7) | msg.getNote(); | |||||
| } break; | } break; | ||||
| case 0xf: { | case 0xf: { | ||||
| processSystem(msg); | processSystem(msg); | ||||
| @@ -440,7 +432,7 @@ struct MIDI_CV : Module { | |||||
| json_object_set_new(rootJ, "clockDivision", json_integer(clockDivision)); | json_object_set_new(rootJ, "clockDivision", json_integer(clockDivision)); | ||||
| // Saving/restoring pitch and mod doesn't make much sense for MPE. | // Saving/restoring pitch and mod doesn't make much sense for MPE. | ||||
| if (polyMode != MPE_MODE) { | if (polyMode != MPE_MODE) { | ||||
| json_object_set_new(rootJ, "lastPitch", json_integer(pitches[0])); | |||||
| json_object_set_new(rootJ, "lastPitch", json_integer(pws[0])); | |||||
| json_object_set_new(rootJ, "lastMod", json_integer(mods[0])); | json_object_set_new(rootJ, "lastMod", json_integer(mods[0])); | ||||
| } | } | ||||
| json_object_set_new(rootJ, "midi", midiInput.toJson()); | json_object_set_new(rootJ, "midi", midiInput.toJson()); | ||||
| @@ -466,7 +458,7 @@ struct MIDI_CV : Module { | |||||
| json_t* lastPitchJ = json_object_get(rootJ, "lastPitch"); | json_t* lastPitchJ = json_object_get(rootJ, "lastPitch"); | ||||
| if (lastPitchJ) | if (lastPitchJ) | ||||
| pitches[0] = json_integer_value(lastPitchJ); | |||||
| pws[0] = json_integer_value(lastPitchJ); | |||||
| json_t* lastModJ = json_object_get(rootJ, "lastMod"); | json_t* lastModJ = json_object_get(rootJ, "lastMod"); | ||||
| if (lastModJ) | if (lastModJ) | ||||
| @@ -489,11 +481,11 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
| addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 60.1445)), module, MIDI_CV::CV_OUTPUT)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 60.1445)), module, MIDI_CV::PITCH_OUTPUT)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 60.1445)), module, MIDI_CV::GATE_OUTPUT)); | addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 60.1445)), module, MIDI_CV::GATE_OUTPUT)); | ||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 60.1445)), module, MIDI_CV::VELOCITY_OUTPUT)); | addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 60.1445)), module, MIDI_CV::VELOCITY_OUTPUT)); | ||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 76.1449)), module, MIDI_CV::AFTERTOUCH_OUTPUT)); | addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 76.1449)), module, MIDI_CV::AFTERTOUCH_OUTPUT)); | ||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 76.1449)), module, MIDI_CV::PITCH_OUTPUT)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 76.1449)), module, MIDI_CV::PW_OUTPUT)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 76.1449)), module, MIDI_CV::MOD_OUTPUT)); | addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.8143, 76.1449)), module, MIDI_CV::MOD_OUTPUT)); | ||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 92.1439)), module, MIDI_CV::CLOCK_OUTPUT)); | addOutput(createOutput<PJ301MPort>(mm2px(Vec(4.61505, 92.1439)), module, MIDI_CV::CLOCK_OUTPUT)); | ||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 92.1439)), module, MIDI_CV::CLOCK_DIV_OUTPUT)); | addOutput(createOutput<PJ301MPort>(mm2px(Vec(16.214, 92.1439)), module, MIDI_CV::CLOCK_DIV_OUTPUT)); | ||||
| @@ -519,7 +511,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| module->smooth ^= true; | module->smooth ^= true; | ||||
| } | } | ||||
| }; | }; | ||||
| SmoothItem* smoothItem = new SmoothItem; | SmoothItem* smoothItem = new SmoothItem; | ||||
| smoothItem->text = "Smooth pitch/mod wheel"; | smoothItem->text = "Smooth pitch/mod wheel"; | ||||
| smoothItem->rightText = CHECKMARK(module->smooth); | smoothItem->rightText = CHECKMARK(module->smooth); | ||||
| @@ -533,7 +524,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| module->clockDivision = clockDivision; | module->clockDivision = clockDivision; | ||||
| } | } | ||||
| }; | }; | ||||
| struct ClockDivisionItem : MenuItem { | struct ClockDivisionItem : MenuItem { | ||||
| MIDI_CV* module; | MIDI_CV* module; | ||||
| Menu* createChildMenu() override { | Menu* createChildMenu() override { | ||||
| @@ -551,7 +541,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| return menu; | return menu; | ||||
| } | } | ||||
| }; | }; | ||||
| ClockDivisionItem* clockDivisionItem = new ClockDivisionItem; | ClockDivisionItem* clockDivisionItem = new ClockDivisionItem; | ||||
| clockDivisionItem->text = "CLK/N divider"; | clockDivisionItem->text = "CLK/N divider"; | ||||
| clockDivisionItem->rightText = RIGHT_ARROW; | clockDivisionItem->rightText = RIGHT_ARROW; | ||||
| @@ -565,7 +554,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| module->setChannels(channels); | module->setChannels(channels); | ||||
| } | } | ||||
| }; | }; | ||||
| struct ChannelItem : MenuItem { | struct ChannelItem : MenuItem { | ||||
| MIDI_CV* module; | MIDI_CV* module; | ||||
| Menu* createChildMenu() override { | Menu* createChildMenu() override { | ||||
| @@ -584,7 +572,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| return menu; | return menu; | ||||
| } | } | ||||
| }; | }; | ||||
| ChannelItem* channelItem = new ChannelItem; | ChannelItem* channelItem = new ChannelItem; | ||||
| channelItem->text = "Polyphony channels"; | channelItem->text = "Polyphony channels"; | ||||
| channelItem->rightText = string::f("%d", module->channels) + " " + RIGHT_ARROW; | channelItem->rightText = string::f("%d", module->channels) + " " + RIGHT_ARROW; | ||||
| @@ -598,7 +585,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| module->setPolyMode(polyMode); | module->setPolyMode(polyMode); | ||||
| } | } | ||||
| }; | }; | ||||
| struct PolyModeItem : MenuItem { | struct PolyModeItem : MenuItem { | ||||
| MIDI_CV* module; | MIDI_CV* module; | ||||
| Menu* createChildMenu() override { | Menu* createChildMenu() override { | ||||
| @@ -621,7 +607,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| return menu; | return menu; | ||||
| } | } | ||||
| }; | }; | ||||
| PolyModeItem* polyModeItem = new PolyModeItem; | PolyModeItem* polyModeItem = new PolyModeItem; | ||||
| polyModeItem->text = "Polyphony mode"; | polyModeItem->text = "Polyphony mode"; | ||||
| polyModeItem->rightText = RIGHT_ARROW; | polyModeItem->rightText = RIGHT_ARROW; | ||||
| @@ -634,7 +619,6 @@ struct MIDI_CVWidget : ModuleWidget { | |||||
| module->panic(); | module->panic(); | ||||
| } | } | ||||
| }; | }; | ||||
| PanicItem* panicItem = new PanicItem; | PanicItem* panicItem = new PanicItem; | ||||
| panicItem->text = "Panic"; | panicItem->text = "Panic"; | ||||
| panicItem->module = module; | panicItem->module = module; | ||||
| @@ -13,7 +13,7 @@ struct MIDI_Gate : Module { | |||||
| NUM_INPUTS | NUM_INPUTS | ||||
| }; | }; | ||||
| enum OutputIds { | enum OutputIds { | ||||
| ENUMS(TRIG_OUTPUT, 16), | |||||
| ENUMS(GATE_OUTPUTS, 16), | |||||
| NUM_OUTPUTS | NUM_OUTPUTS | ||||
| }; | }; | ||||
| enum LightIds { | enum LightIds { | ||||
| @@ -22,21 +22,23 @@ struct MIDI_Gate : Module { | |||||
| midi::InputQueue midiInput; | midi::InputQueue midiInput; | ||||
| /** [cell][c] */ | |||||
| /** [cell][channel] */ | |||||
| bool gates[16][16]; | bool gates[16][16]; | ||||
| /** [cell][c] */ | |||||
| /** [cell][channel] */ | |||||
| float gateTimes[16][16]; | float gateTimes[16][16]; | ||||
| /** [cell][c] */ | |||||
| /** [cell][channel] */ | |||||
| uint8_t velocities[16][16]; | uint8_t velocities[16][16]; | ||||
| int learningId = -1; | |||||
| uint8_t learnedNotes[16] = {}; | |||||
| bool velocityMode = false; | |||||
| bool mpeMode = false; | |||||
| /** Cell ID in learn mode, or -1 if none. */ | |||||
| int learningId; | |||||
| /** [cell] */ | |||||
| uint8_t learnedNotes[16]; | |||||
| bool velocityMode; | |||||
| bool mpeMode; | |||||
| MIDI_Gate() { | MIDI_Gate() { | ||||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | ||||
| for (int i = 0; i < 16; i++) | for (int i = 0; i < 16; i++) | ||||
| configOutput(TRIG_OUTPUT + i, string::f("Cell %d", i + 1)); | |||||
| configOutput(GATE_OUTPUTS + i, string::f("Gate %d", i + 1)); | |||||
| onReset(); | onReset(); | ||||
| } | } | ||||
| @@ -76,16 +78,16 @@ struct MIDI_Gate : Module { | |||||
| int channels = mpeMode ? 16 : 1; | int channels = mpeMode ? 16 : 1; | ||||
| for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
| outputs[TRIG_OUTPUT + i].setChannels(channels); | |||||
| outputs[GATE_OUTPUTS + i].setChannels(channels); | |||||
| for (int c = 0; c < channels; c++) { | for (int c = 0; c < channels; c++) { | ||||
| // Make sure all pulses last longer than 1ms | // Make sure all pulses last longer than 1ms | ||||
| if (gates[i][c] || gateTimes[i][c] > 0.f) { | if (gates[i][c] || gateTimes[i][c] > 0.f) { | ||||
| float velocity = velocityMode ? (velocities[i][c] / 127.f) : 1.f; | float velocity = velocityMode ? (velocities[i][c] / 127.f) : 1.f; | ||||
| outputs[TRIG_OUTPUT + i].setVoltage(velocity * 10.f, c); | |||||
| outputs[GATE_OUTPUTS + i].setVoltage(velocity * 10.f, c); | |||||
| gateTimes[i][c] -= args.sampleTime; | gateTimes[i][c] -= args.sampleTime; | ||||
| } | } | ||||
| else { | else { | ||||
| outputs[TRIG_OUTPUT + i].setVoltage(0.f, c); | |||||
| outputs[GATE_OUTPUTS + i].setVoltage(0.f, c); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -181,30 +183,6 @@ struct MIDI_Gate : Module { | |||||
| }; | }; | ||||
| struct MIDI_GateVelocityItem : MenuItem { | |||||
| MIDI_Gate* module; | |||||
| void onAction(const ActionEvent& e) override { | |||||
| module->velocityMode ^= true; | |||||
| } | |||||
| }; | |||||
| struct MIDI_GateMpeModeItem : MenuItem { | |||||
| MIDI_Gate* module; | |||||
| void onAction(const ActionEvent& e) override { | |||||
| module->mpeMode ^= true; | |||||
| } | |||||
| }; | |||||
| struct MIDI_GatePanicItem : MenuItem { | |||||
| MIDI_Gate* module; | |||||
| void onAction(const ActionEvent& e) override { | |||||
| module->panic(); | |||||
| } | |||||
| }; | |||||
| struct MIDI_GateWidget : ModuleWidget { | struct MIDI_GateWidget : ModuleWidget { | ||||
| MIDI_GateWidget(MIDI_Gate* module) { | MIDI_GateWidget(MIDI_Gate* module) { | ||||
| setModule(module); | setModule(module); | ||||
| @@ -215,22 +193,22 @@ struct MIDI_GateWidget : ModuleWidget { | |||||
| addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
| addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | ||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.894335, 73.344704)), module, MIDI_Gate::TRIG_OUTPUT + 0)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.494659, 73.344704)), module, MIDI_Gate::TRIG_OUTPUT + 1)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.094982, 73.344704)), module, MIDI_Gate::TRIG_OUTPUT + 2)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 73.344704)), module, MIDI_Gate::TRIG_OUTPUT + 3)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.8943355, 84.945023)), module, MIDI_Gate::TRIG_OUTPUT + 4)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.49466, 84.945023)), module, MIDI_Gate::TRIG_OUTPUT + 5)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.094982, 84.945023)), module, MIDI_Gate::TRIG_OUTPUT + 6)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 84.945023)), module, MIDI_Gate::TRIG_OUTPUT + 7)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.8943343, 96.543976)), module, MIDI_Gate::TRIG_OUTPUT + 8)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.494659, 96.543976)), module, MIDI_Gate::TRIG_OUTPUT + 9)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 96.543976)), module, MIDI_Gate::TRIG_OUTPUT + 10)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 96.543976)), module, MIDI_Gate::TRIG_OUTPUT + 11)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.894335, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 12)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.49466, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 13)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 14)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), module, MIDI_Gate::TRIG_OUTPUT + 15)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.894335, 73.344704)), module, MIDI_Gate::GATE_OUTPUTS + 0)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.494659, 73.344704)), module, MIDI_Gate::GATE_OUTPUTS + 1)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.094982, 73.344704)), module, MIDI_Gate::GATE_OUTPUTS + 2)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 73.344704)), module, MIDI_Gate::GATE_OUTPUTS + 3)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.8943355, 84.945023)), module, MIDI_Gate::GATE_OUTPUTS + 4)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.49466, 84.945023)), module, MIDI_Gate::GATE_OUTPUTS + 5)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.094982, 84.945023)), module, MIDI_Gate::GATE_OUTPUTS + 6)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 84.945023)), module, MIDI_Gate::GATE_OUTPUTS + 7)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.8943343, 96.543976)), module, MIDI_Gate::GATE_OUTPUTS + 8)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.494659, 96.543976)), module, MIDI_Gate::GATE_OUTPUTS + 9)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 96.543976)), module, MIDI_Gate::GATE_OUTPUTS + 10)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 96.543976)), module, MIDI_Gate::GATE_OUTPUTS + 11)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.894335, 108.14429)), module, MIDI_Gate::GATE_OUTPUTS + 12)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.49466, 108.14429)), module, MIDI_Gate::GATE_OUTPUTS + 13)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.09498, 108.14429)), module, MIDI_Gate::GATE_OUTPUTS + 14)); | |||||
| addOutput(createOutput<PJ301MPort>(mm2px(Vec(38.693932, 108.14429)), module, MIDI_Gate::GATE_OUTPUTS + 15)); | |||||
| typedef Grid16MidiWidget<NoteChoice<MIDI_Gate>> TMidiWidget; | typedef Grid16MidiWidget<NoteChoice<MIDI_Gate>> TMidiWidget; | ||||
| TMidiWidget* midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339))); | TMidiWidget* midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339))); | ||||
| @@ -243,18 +221,36 @@ struct MIDI_GateWidget : ModuleWidget { | |||||
| void appendContextMenu(Menu* menu) override { | void appendContextMenu(Menu* menu) override { | ||||
| MIDI_Gate* module = dynamic_cast<MIDI_Gate*>(this->module); | MIDI_Gate* module = dynamic_cast<MIDI_Gate*>(this->module); | ||||
| struct VelocityItem : MenuItem { | |||||
| MIDI_Gate* module; | |||||
| void onAction(const ActionEvent& e) override { | |||||
| module->velocityMode ^= true; | |||||
| } | |||||
| }; | |||||
| menu->addChild(new MenuSeparator); | menu->addChild(new MenuSeparator); | ||||
| MIDI_GateVelocityItem* velocityItem = createMenuItem<MIDI_GateVelocityItem>("Velocity mode", CHECKMARK(module->velocityMode)); | |||||
| VelocityItem* velocityItem = createMenuItem<VelocityItem>("Velocity mode", CHECKMARK(module->velocityMode)); | |||||
| velocityItem->module = module; | velocityItem->module = module; | ||||
| menu->addChild(velocityItem); | menu->addChild(velocityItem); | ||||
| MIDI_GateMpeModeItem* mpeModeItem = new MIDI_GateMpeModeItem; | |||||
| struct MpeModeItem : MenuItem { | |||||
| MIDI_Gate* module; | |||||
| void onAction(const ActionEvent& e) override { | |||||
| module->mpeMode ^= true; | |||||
| } | |||||
| }; | |||||
| MpeModeItem* mpeModeItem = new MpeModeItem; | |||||
| mpeModeItem->text = "MPE mode"; | mpeModeItem->text = "MPE mode"; | ||||
| mpeModeItem->rightText = CHECKMARK(module->mpeMode); | mpeModeItem->rightText = CHECKMARK(module->mpeMode); | ||||
| mpeModeItem->module = module; | mpeModeItem->module = module; | ||||
| menu->addChild(mpeModeItem); | menu->addChild(mpeModeItem); | ||||
| MIDI_GatePanicItem* panicItem = new MIDI_GatePanicItem; | |||||
| struct PanicItem : MenuItem { | |||||
| MIDI_Gate* module; | |||||
| void onAction(const ActionEvent& e) override { | |||||
| module->panic(); | |||||
| } | |||||
| }; | |||||
| PanicItem* panicItem = new PanicItem; | |||||
| panicItem->text = "Panic"; | panicItem->text = "Panic"; | ||||
| panicItem->module = module; | panicItem->module = module; | ||||
| menu->addChild(panicItem); | menu->addChild(panicItem); | ||||