@@ -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); | ||||