Browse Source

Clean up MIDI-CV, CC, and Gate.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
898bc44794
4 changed files with 162 additions and 128 deletions
  1. +61
    -6
      include/componentlibrary.hpp
  2. +17
    -18
      src/core/MIDI_CC.cpp
  3. +33
    -49
      src/core/MIDI_CV.cpp
  4. +51
    -55
      src/core/MIDI_Gate.cpp

+ 61
- 6
include/componentlibrary.hpp View File

@@ -302,179 +302,234 @@ struct Davies1900hLargeRedKnob : Davies1900hKnob {


struct Rogan : app::SvgKnob {
widget::SvgWidget* bg;
widget::SvgWidget* fg;

Rogan() {
minAngle = -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 {
Rogan6PSWhite() {
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 {
Rogan5PSGray() {
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 {
Rogan3PSBlue() {
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 {
Rogan3PSRed() {
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 {
Rogan3PSGreen() {
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 {
Rogan3PSWhite() {
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")));
fb->addChildBelow(bg, tw);

widget::SvgWidget* fg = new widget::SvgWidget;
fg->setSvg(Svg::load(asset::system("res/ComponentLibrary/Rogan3PSWhite-fg.svg")));
fb->addChildAbove(fg, tw);
}
};

struct Rogan3PBlue : Rogan {
Rogan3PBlue() {
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 {
Rogan3PRed() {
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 {
Rogan3PGreen() {
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 {
Rogan3PWhite() {
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 {
Rogan2SGray() {
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 {
Rogan2PSBlue() {
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 {
Rogan2PSRed() {
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 {
Rogan2PSGreen() {
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 {
Rogan2PSWhite() {
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 {
Rogan2PBlue() {
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 {
Rogan2PRed() {
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 {
Rogan2PGreen() {
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 {
Rogan2PWhite() {
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 {
Rogan1PSBlue() {
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 {
Rogan1PSRed() {
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 {
Rogan1PSGreen() {
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 {
Rogan1PSWhite() {
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 {
Rogan1PBlue() {
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 {
Rogan1PRed() {
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 {
Rogan1PGreen() {
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 {
Rogan1PWhite() {
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")));
}
};



+ 17
- 18
src/core/MIDI_CC.cpp View File

@@ -21,6 +21,7 @@ struct MIDI_CC : Module {
};

midi::InputQueue midiInput;

/** [cc][channel] */
int8_t ccValues[128][16];
/** 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];
bool smooth;
bool mpeMode;
bool lsbEnabled;
bool lsbMode;

MIDI_CC() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -66,7 +67,7 @@ struct MIDI_CC : Module {
midiInput.reset();
smooth = true;
mpeMode = false;
lsbEnabled = false;
lsbMode = false;
}

void process(const ProcessArgs& args) override {
@@ -80,6 +81,7 @@ struct MIDI_CC : Module {
}

int channels = mpeMode ? 16 : 1;

for (int i = 0; i < 16; i++) {
if (!outputs[CC_OUTPUT + i].isConnected())
continue;
@@ -89,7 +91,7 @@ struct MIDI_CC : Module {

for (int c = 0; c < channels; c++) {
int16_t cellValue = int16_t(ccValues[cc][c]) * 128;
if (lsbEnabled && cc < 32)
if (lsbMode && cc < 32)
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.
float value = float(cellValue) / (128 * 127);
@@ -135,11 +137,11 @@ struct MIDI_CC : Module {
learningId = -1;
}

if (lsbEnabled && cc < 32) {
if (lsbMode && cc < 32) {
// Don't set MSB yet. Wait for LSB to be received.
msbValues[cc][c] = value;
}
else if (lsbEnabled && 32 <= cc && cc < 64) {
else if (lsbMode && 32 <= cc && cc < 64) {
// Apply MSB when LSB is received
ccValues[cc - 32][c] = msbValues[cc - 32][c];
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, "mpeMode", json_boolean(mpeMode));
json_object_set_new(rootJ, "lsbEnabled", json_boolean(lsbEnabled));
json_object_set_new(rootJ, "lsbMode", json_boolean(lsbMode));
return rootJ;
}

@@ -206,9 +208,9 @@ struct MIDI_CC : Module {
if (mpeModeJ)
mpeMode = json_boolean_value(mpeModeJ);

json_t* lsbEnabledJ = json_object_get(rootJ, "lsbEnabled");
json_t* lsbEnabledJ = json_object_get(rootJ, "lsbMode");
if (lsbEnabledJ)
lsbEnabled = json_boolean_value(lsbEnabledJ);
lsbMode = json_boolean_value(lsbEnabledJ);
}
};

@@ -259,7 +261,6 @@ struct MIDI_CCWidget : ModuleWidget {
module->smooth ^= true;
}
};

SmoothItem* smoothItem = new SmoothItem;
smoothItem->text = "Smooth CC";
smoothItem->rightText = CHECKMARK(module->smooth);
@@ -272,25 +273,23 @@ struct MIDI_CCWidget : ModuleWidget {
module->mpeMode ^= true;
}
};

MpeModeItem* mpeModeItem = new MpeModeItem;
mpeModeItem->text = "MPE mode";
mpeModeItem->rightText = CHECKMARK(module->mpeMode);
mpeModeItem->module = module;
menu->addChild(mpeModeItem);

struct LSBItem : MenuItem {
struct LsbModeItem : MenuItem {
MIDI_CC* module;
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);
}
};



+ 33
- 49
src/core/MIDI_CV.cpp View File

@@ -15,11 +15,11 @@ struct MIDI_CV : Module {
NUM_INPUTS
};
enum OutputIds {
CV_OUTPUT,
PITCH_OUTPUT,
GATE_OUTPUT,
VELOCITY_OUTPUT,
AFTERTOUCH_OUTPUT,
PITCH_OUTPUT,
PW_OUTPUT,
MOD_OUTPUT,
RETRIGGER_OUTPUT,
CLOCK_OUTPUT,
@@ -59,10 +59,14 @@ struct MIDI_CV : Module {

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];
dsp::ExponentialFilter pitchFilters[16];
dsp::ExponentialFilter pwFilters[16];
dsp::ExponentialFilter modFilters[16];

dsp::PulseGenerator clockPulse;
@@ -74,11 +78,11 @@ struct MIDI_CV : Module {

MIDI_CV() {
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(VELOCITY_OUTPUT, "Velocity");
configOutput(AFTERTOUCH_OUTPUT, "Aftertouch");
configOutput(PITCH_OUTPUT, "Pitch wheel");
configOutput(PW_OUTPUT, "Pitch wheel");
configOutput(MOD_OUTPUT, "Mod wheel");
configOutput(RETRIGGER_OUTPUT, "Retrigger");
configOutput(CLOCK_OUTPUT, "Clock");
@@ -88,7 +92,7 @@ struct MIDI_CV : Module {
configOutput(CONTINUE_OUTPUT, "Continue");
heldNotes.reserve(128);
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);
}
onReset();
@@ -110,9 +114,9 @@ struct MIDI_CV : Module {
gates[c] = false;
velocities[c] = 0;
aftertouches[c] = 0;
pitches[c] = 8192;
pws[c] = 8192;
mods[c] = 0;
pitchFilters[c].reset();
pwFilters[c].reset();
modFilters[c].reset();
}
pedal = false;
@@ -130,13 +134,13 @@ struct MIDI_CV : Module {
midiInput.queue.pop();
}

outputs[CV_OUTPUT].setChannels(channels);
outputs[PITCH_OUTPUT].setChannels(channels);
outputs[GATE_OUTPUT].setChannels(channels);
outputs[VELOCITY_OUTPUT].setChannels(channels);
outputs[AFTERTOUCH_OUTPUT].setChannels(channels);
outputs[RETRIGGER_OUTPUT].setChannels(channels);
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[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);
@@ -144,37 +148,25 @@ struct MIDI_CV : Module {
}

// 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)
pitch = pitchFilters[c].process(args.sampleTime, pitch);
pw = pwFilters[c].process(args.sampleTime, pw);
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;
mod = clamp(mod, 0.f, 1.f);
if (smooth)
modFilters[c].process(args.sampleTime, mod);
mod = modFilters[c].process(args.sampleTime, mod);
else
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);
@@ -233,7 +225,7 @@ struct MIDI_CV : Module {
// pitch wheel
case 0xe: {
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;
case 0xf: {
processSystem(msg);
@@ -440,7 +432,7 @@ struct MIDI_CV : Module {
json_object_set_new(rootJ, "clockDivision", json_integer(clockDivision));
// Saving/restoring pitch and mod doesn't make much sense for MPE.
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, "midi", midiInput.toJson());
@@ -466,7 +458,7 @@ struct MIDI_CV : Module {

json_t* lastPitchJ = json_object_get(rootJ, "lastPitch");
if (lastPitchJ)
pitches[0] = json_integer_value(lastPitchJ);
pws[0] = json_integer_value(lastPitchJ);

json_t* lastModJ = json_object_get(rootJ, "lastMod");
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(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(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(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(4.61505, 92.1439)), module, MIDI_CV::CLOCK_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;
}
};

SmoothItem* smoothItem = new SmoothItem;
smoothItem->text = "Smooth pitch/mod wheel";
smoothItem->rightText = CHECKMARK(module->smooth);
@@ -533,7 +524,6 @@ struct MIDI_CVWidget : ModuleWidget {
module->clockDivision = clockDivision;
}
};

struct ClockDivisionItem : MenuItem {
MIDI_CV* module;
Menu* createChildMenu() override {
@@ -551,7 +541,6 @@ struct MIDI_CVWidget : ModuleWidget {
return menu;
}
};

ClockDivisionItem* clockDivisionItem = new ClockDivisionItem;
clockDivisionItem->text = "CLK/N divider";
clockDivisionItem->rightText = RIGHT_ARROW;
@@ -565,7 +554,6 @@ struct MIDI_CVWidget : ModuleWidget {
module->setChannels(channels);
}
};

struct ChannelItem : MenuItem {
MIDI_CV* module;
Menu* createChildMenu() override {
@@ -584,7 +572,6 @@ struct MIDI_CVWidget : ModuleWidget {
return menu;
}
};

ChannelItem* channelItem = new ChannelItem;
channelItem->text = "Polyphony channels";
channelItem->rightText = string::f("%d", module->channels) + " " + RIGHT_ARROW;
@@ -598,7 +585,6 @@ struct MIDI_CVWidget : ModuleWidget {
module->setPolyMode(polyMode);
}
};

struct PolyModeItem : MenuItem {
MIDI_CV* module;
Menu* createChildMenu() override {
@@ -621,7 +607,6 @@ struct MIDI_CVWidget : ModuleWidget {
return menu;
}
};

PolyModeItem* polyModeItem = new PolyModeItem;
polyModeItem->text = "Polyphony mode";
polyModeItem->rightText = RIGHT_ARROW;
@@ -634,7 +619,6 @@ struct MIDI_CVWidget : ModuleWidget {
module->panic();
}
};

PanicItem* panicItem = new PanicItem;
panicItem->text = "Panic";
panicItem->module = module;


+ 51
- 55
src/core/MIDI_Gate.cpp View File

@@ -13,7 +13,7 @@ struct MIDI_Gate : Module {
NUM_INPUTS
};
enum OutputIds {
ENUMS(TRIG_OUTPUT, 16),
ENUMS(GATE_OUTPUTS, 16),
NUM_OUTPUTS
};
enum LightIds {
@@ -22,21 +22,23 @@ struct MIDI_Gate : Module {

midi::InputQueue midiInput;

/** [cell][c] */
/** [cell][channel] */
bool gates[16][16];
/** [cell][c] */
/** [cell][channel] */
float gateTimes[16][16];
/** [cell][c] */
/** [cell][channel] */
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() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
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();
}
@@ -76,16 +78,16 @@ struct MIDI_Gate : Module {
int channels = mpeMode ? 16 : 1;

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++) {
// Make sure all pulses last longer than 1ms
if (gates[i][c] || gateTimes[i][c] > 0.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;
}
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 {
MIDI_GateWidget(MIDI_Gate* 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(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;
TMidiWidget* midiWidget = createWidget<TMidiWidget>(mm2px(Vec(3.399621, 14.837339)));
@@ -243,18 +221,36 @@ struct MIDI_GateWidget : ModuleWidget {
void appendContextMenu(Menu* menu) override {
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);
MIDI_GateVelocityItem* velocityItem = createMenuItem<MIDI_GateVelocityItem>("Velocity mode", CHECKMARK(module->velocityMode));
VelocityItem* velocityItem = createMenuItem<VelocityItem>("Velocity mode", CHECKMARK(module->velocityMode));
velocityItem->module = module;
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->rightText = CHECKMARK(module->mpeMode);
mpeModeItem->module = module;
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->module = module;
menu->addChild(panicItem);


Loading…
Cancel
Save