| @@ -101,12 +101,12 @@ struct HostMIDICC : TerminalModule { | |||
| lastBlockFrame = -1; | |||
| channel = 0; | |||
| for (int cc = 0; cc < 128; cc++) { | |||
| for (uint8_t cc = 0; cc < 128; cc++) { | |||
| for (int c = 0; c < 16; c++) { | |||
| ccValues[cc][c] = 0; | |||
| } | |||
| } | |||
| for (int cc = 0; cc < 32; cc++) { | |||
| for (uint8_t cc = 0; cc < 32; cc++) { | |||
| for (int c = 0; c < 16; c++) { | |||
| msbValues[cc][c] = 0; | |||
| } | |||
| @@ -121,7 +121,7 @@ struct HostMIDICC : TerminalModule { | |||
| lsbMode = false; | |||
| } | |||
| bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, int learnedCcs[16], | |||
| bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, int8_t learnedCcs[16], | |||
| const bool isBypassed) | |||
| { | |||
| // Cardinal specific | |||
| @@ -181,12 +181,21 @@ struct HostMIDICC : TerminalModule { | |||
| // adapted from Rack | |||
| const uint8_t c = mpeMode ? chan : 0; | |||
| const uint8_t cc = data[1]; | |||
| const int8_t cc = data[1]; | |||
| const uint8_t value = data[2]; | |||
| // Learn | |||
| if (learningId >= 0 && ccValues[cc][c] != value) | |||
| { | |||
| // NOTE: does the same as `setLearnedCc` | |||
| if (cc >= 0) | |||
| { | |||
| for (int id = 0; id < 16; ++id) | |||
| { | |||
| if (learnedCcs[id] == cc) | |||
| learnedCcs[id] = -1; | |||
| } | |||
| } | |||
| learnedCcs[learningId] = cc; | |||
| learningId = -1; | |||
| } | |||
| @@ -219,7 +228,10 @@ struct HostMIDICC : TerminalModule { | |||
| continue; | |||
| outputs[CC_OUTPUT + i].setChannels(channels); | |||
| int cc = learnedCcs[i]; | |||
| const int8_t cc = learnedCcs[i]; | |||
| if (cc < 0) | |||
| continue; | |||
| for (int c = 0; c < channels; c++) | |||
| { | |||
| @@ -365,7 +377,7 @@ struct HostMIDICC : TerminalModule { | |||
| } midiOutput; | |||
| int learnedCcs[16]; | |||
| int8_t learnedCcs[16]; | |||
| HostMIDICC() | |||
| : pcontext(static_cast<CardinalPluginContext*>(APP)), | |||
| @@ -377,14 +389,14 @@ struct HostMIDICC : TerminalModule { | |||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
| for (int i = 0; i < 16; i++) | |||
| configInput(CC_INPUTS + i, string::f("Cell %d", i + 1)); | |||
| for (int id = 0; id < 16; ++id) | |||
| configInput(CC_INPUTS + id, string::f("Cell %d", id + 1)); | |||
| configInput(CC_INPUT_CH_PRESSURE, "Channel pressure"); | |||
| configInput(CC_INPUT_PITCHBEND, "Pitchbend"); | |||
| for (int i = 0; i < 16; i++) | |||
| configOutput(CC_OUTPUT + i, string::f("Cell %d", i + 1)); | |||
| for (int id = 0; id < 16; ++id) | |||
| configOutput(CC_OUTPUT + id, string::f("Cell %d", id + 1)); | |||
| configOutput(CC_OUTPUT_CH_PRESSURE, "Channel pressure"); | |||
| configOutput(CC_OUTPUT_PITCHBEND, "Pitchbend"); | |||
| @@ -394,9 +406,8 @@ struct HostMIDICC : TerminalModule { | |||
| void onReset() override | |||
| { | |||
| for (int i = 0; i < 16; i++) { | |||
| learnedCcs[i] = i + 1; | |||
| } | |||
| for (int id = 0; id < 16; ++id) | |||
| learnedCcs[id] = id + 1; | |||
| midiInput.reset(); | |||
| midiOutput.reset(); | |||
| } | |||
| @@ -416,8 +427,10 @@ struct HostMIDICC : TerminalModule { | |||
| for (int i = 0; i < 16; i++) | |||
| { | |||
| int value = (int) std::round(inputs[CC_INPUTS + i].getVoltage() / 10.f * 127); | |||
| value = clamp(value, 0, 127); | |||
| if (learnedCcs[id] < 0) | |||
| continue; | |||
| uint8_t value = (uint8_t) clamp(std::round(inputs[CC_INPUTS + id].getVoltage() / 10.f * 127), 0.f, 127.f); | |||
| midiOutput.sendCC(learnedCcs[i], value); | |||
| } | |||
| @@ -434,6 +447,20 @@ struct HostMIDICC : TerminalModule { | |||
| } | |||
| } | |||
| void setLearnedCc(const int id, const int8_t cc) | |||
| { | |||
| // Unset IDs of similar CCs | |||
| if (cc >= 0) | |||
| { | |||
| for (int idx = 0; idx < 16; ++idx) | |||
| { | |||
| if (learnedCcs[idx] == cc) | |||
| learnedCcs[idx] = -1; | |||
| } | |||
| } | |||
| learnedCcs[id] = cc; | |||
| } | |||
| json_t* dataToJson() override | |||
| { | |||
| json_t* const rootJ = json_object(); | |||
| @@ -442,8 +469,8 @@ struct HostMIDICC : TerminalModule { | |||
| // input and output | |||
| if (json_t* const ccsJ = json_array()) | |||
| { | |||
| for (int i = 0; i < 16; i++) | |||
| json_array_append_new(ccsJ, json_integer(learnedCcs[i])); | |||
| for (int id = 0; id < 16; ++id) | |||
| json_array_append_new(ccsJ, json_integer(learnedCcs[id])); | |||
| json_object_set_new(rootJ, "ccs", ccsJ); | |||
| } | |||
| @@ -473,12 +500,12 @@ struct HostMIDICC : TerminalModule { | |||
| // input and output | |||
| if (json_t* const ccsJ = json_object_get(rootJ, "ccs")) | |||
| { | |||
| for (int i = 0; i < 16; i++) | |||
| for (int id = 0; id < 16; ++id) | |||
| { | |||
| if (json_t* const ccJ = json_array_get(ccsJ, i)) | |||
| learnedCcs[i] = json_integer_value(ccJ); | |||
| if (json_t* const ccJ = json_array_get(ccsJ, id)) | |||
| setLearnedCc(id, json_integer_value(ccJ)); | |||
| else | |||
| learnedCcs[i] = i + 1; | |||
| learnedCcs[id] = -1; | |||
| } | |||
| } | |||
| @@ -524,7 +551,7 @@ struct HostMIDICC : TerminalModule { | |||
| struct CardinalCcChoice : CardinalLedDisplayChoice { | |||
| HostMIDICC* const module; | |||
| const int id; | |||
| int focusCc = -1; | |||
| int8_t focusCc = -1; | |||
| CardinalCcChoice(HostMIDICC* const m, const int i) | |||
| : CardinalLedDisplayChoice(), | |||
| @@ -540,7 +567,7 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { | |||
| void step() override | |||
| { | |||
| int cc; | |||
| int8_t cc; | |||
| if (module == nullptr) | |||
| { | |||
| @@ -583,8 +610,8 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { | |||
| if (module->midiInput.learningId == id) | |||
| { | |||
| if (0 <= focusCc && focusCc < 128) | |||
| module->learnedCcs[id] = focusCc; | |||
| if (focusCc >= 0) | |||
| module->setLearnedCc(id, focusCc); | |||
| module->midiInput.learningId = -1; | |||
| } | |||
| } | |||
| @@ -600,7 +627,7 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { | |||
| focusCc = focusCc * 10 + (c - '0'); | |||
| } | |||
| if (focusCc >= 128) | |||
| if (focusCc < 0) | |||
| focusCc = -1; | |||
| e.consume(this); | |||
| @@ -104,7 +104,7 @@ struct HostMIDIGate : TerminalModule { | |||
| } | |||
| bool process(const ProcessArgs& args, std::vector<rack::engine::Output>& outputs, | |||
| const bool velocityMode, uint8_t learnedNotes[18], const bool isBypassed) | |||
| const bool velocityMode, int8_t learnedNotes[18], const bool isBypassed) | |||
| { | |||
| // Cardinal specific | |||
| const int64_t blockFrame = pcontext->engine->getBlockFrame(); | |||
| @@ -153,17 +153,30 @@ struct HostMIDIGate : TerminalModule { | |||
| if (data[2] > 0) | |||
| { | |||
| const int c = mpeMode ? (data[0] & 0x0F) : 0; | |||
| const int8_t note = data[1]; | |||
| // Learn | |||
| if (learningId >= 0) { | |||
| learnedNotes[learningId] = data[1]; | |||
| if (learningId >= 0) | |||
| { | |||
| // NOTE: does the same as `setLearnedNote` | |||
| if (note >= 0) | |||
| { | |||
| for (int id = 0; id < 18; ++id) | |||
| { | |||
| if (learnedNotes[id] == note) | |||
| learnedNotes[id] = -1; | |||
| } | |||
| } | |||
| learnedNotes[learningId] = note; | |||
| learningId = -1; | |||
| } | |||
| // Find id | |||
| for (int i = 0; i < 18; i++) { | |||
| if (learnedNotes[i] == data[1]) { | |||
| gates[i][c] = true; | |||
| gateTimes[i][c] = 1e-3f; | |||
| velocities[i][c] = data[2]; | |||
| for (int id = 0; id < 18; ++id) | |||
| { | |||
| if (learnedNotes[id] == note) | |||
| { | |||
| gates[id][c] = true; | |||
| gateTimes[id][c] = 1e-3f; | |||
| velocities[id][c] = data[2]; | |||
| } | |||
| } | |||
| break; | |||
| @@ -172,11 +185,12 @@ struct HostMIDIGate : TerminalModule { | |||
| // note off | |||
| case 0x80: | |||
| const int c = mpeMode ? (data[0] & 0x0F) : 0; | |||
| const int8_t note = data[1]; | |||
| // Find id | |||
| for (int i = 0; i < 18; i++) { | |||
| if (learnedNotes[i] == data[1]) { | |||
| gates[i][c] = false; | |||
| } | |||
| for (int id = 0; id < 18; ++id) | |||
| { | |||
| if (learnedNotes[id] == note) | |||
| gates[id][c] = false; | |||
| } | |||
| break; | |||
| } | |||
| @@ -217,7 +231,7 @@ struct HostMIDIGate : TerminalModule { | |||
| uint8_t channel = 0; | |||
| // base class vars | |||
| int vels[128]; | |||
| uint8_t vels[128]; | |||
| bool lastGates[128]; | |||
| int64_t frame = 0; | |||
| @@ -230,7 +244,7 @@ struct HostMIDIGate : TerminalModule { | |||
| void reset() | |||
| { | |||
| // base class vars | |||
| for (int note = 0; note < 128; ++note) | |||
| for (uint8_t note = 0; note < 128; ++note) | |||
| { | |||
| vels[note] = 100; | |||
| lastGates[note] = false; | |||
| @@ -245,7 +259,7 @@ struct HostMIDIGate : TerminalModule { | |||
| // TODO send all notes off CC | |||
| // Send all note off commands | |||
| for (int note = 0; note < 128; note++) | |||
| for (uint8_t note = 0; note < 128; note++) | |||
| { | |||
| // Note off | |||
| midi::Message m; | |||
| @@ -258,12 +272,12 @@ struct HostMIDIGate : TerminalModule { | |||
| } | |||
| } | |||
| void setVelocity(int vel, int note) | |||
| void setVelocity(uint8_t note, uint8_t vel) | |||
| { | |||
| vels[note] = vel; | |||
| } | |||
| void setGate(bool gate, int note) | |||
| void setGate(uint8_t note, bool gate) | |||
| { | |||
| if (gate && !lastGates[note]) | |||
| { | |||
| @@ -296,7 +310,8 @@ struct HostMIDIGate : TerminalModule { | |||
| } midiOutput; | |||
| bool velocityMode = false; | |||
| uint8_t learnedNotes[18] = {}; | |||
| int8_t learnedNotes[18] = {}; | |||
| dsp::SchmittTrigger cellTriggers[18]; | |||
| HostMIDIGate() | |||
| : pcontext(static_cast<CardinalPluginContext*>(APP)), | |||
| @@ -308,19 +323,19 @@ struct HostMIDIGate : TerminalModule { | |||
| config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
| for (int i = 0; i < 18; i++) | |||
| configInput(GATE_INPUTS + i, string::f("Gate %d", i + 1)); | |||
| for (int id = 0; id < 18; ++id) | |||
| configInput(GATE_INPUTS + id, string::f("Gate %d", id + 1)); | |||
| for (int i = 0; i < 18; i++) | |||
| configOutput(GATE_OUTPUTS + i, string::f("Gate %d", i + 1)); | |||
| for (int id = 0; id < 18; ++id) | |||
| configOutput(GATE_OUTPUTS + id, string::f("Gate %d", id + 1)); | |||
| onReset(); | |||
| } | |||
| void onReset() override | |||
| { | |||
| for (int i = 0; i < 18; ++i) | |||
| learnedNotes[i] = 36 + i; | |||
| for (int id = 0; id < 18; ++id) | |||
| learnedNotes[id] = 36 + id; | |||
| velocityMode = false; | |||
| @@ -341,26 +356,41 @@ struct HostMIDIGate : TerminalModule { | |||
| if (isBypassed()) | |||
| return; | |||
| for (int i = 0; i < 18; ++i) | |||
| for (int id = 0; id < 18; ++id) | |||
| { | |||
| const int note = learnedNotes[i]; | |||
| const int8_t note = learnedNotes[id]; | |||
| if (note < 0) | |||
| continue; | |||
| if (velocityMode) | |||
| { | |||
| int vel = (int) std::round(inputs[GATE_INPUTS + i].getVoltage() / 10.f * 127); | |||
| vel = clamp(vel, 0, 127); | |||
| midiOutput.setVelocity(vel, note); | |||
| midiOutput.setGate(vel > 0, note); | |||
| uint8_t vel = (uint8_t) clamp(std::round(inputs[GATE_INPUTS + id].getVoltage() / 10.f * 127), 0.f, 127.f); | |||
| midiOutput.setVelocity(note, vel); | |||
| midiOutput.setGate(note, vel > 0); | |||
| } | |||
| else | |||
| { | |||
| const bool gate = inputs[GATE_INPUTS + i].getVoltage() >= 1.f; | |||
| midiOutput.setVelocity(100, note); | |||
| midiOutput.setGate(gate, note); | |||
| const bool gate = inputs[GATE_INPUTS + id].getVoltage() >= 1.f; | |||
| midiOutput.setVelocity(note, 100); | |||
| midiOutput.setGate(note, gate); | |||
| } | |||
| } | |||
| } | |||
| void setLearnedNote(const int id, const int8_t note) { | |||
| // Unset IDs of similar note | |||
| if (note >= 0) | |||
| { | |||
| for (int idx = 0; idx < 18; ++idx) | |||
| { | |||
| if (learnedNotes[idx] == note) | |||
| learnedNotes[idx] = -1; | |||
| } | |||
| } | |||
| learnedNotes[id] = note; | |||
| } | |||
| json_t* dataToJson() override | |||
| { | |||
| json_t* const rootJ = json_object(); | |||
| @@ -369,8 +399,8 @@ struct HostMIDIGate : TerminalModule { | |||
| // input and output | |||
| if (json_t* const notesJ = json_array()) | |||
| { | |||
| for (int i = 0; i < 18; i++) | |||
| json_array_append_new(notesJ, json_integer(learnedNotes[i])); | |||
| for (int id = 0; id < 18; ++id) | |||
| json_array_append_new(notesJ, json_integer(learnedNotes[id])); | |||
| json_object_set_new(rootJ, "notes", notesJ); | |||
| } | |||
| json_object_set_new(rootJ, "velocity", json_boolean(velocityMode)); | |||
| @@ -390,12 +420,12 @@ struct HostMIDIGate : TerminalModule { | |||
| // input and output | |||
| if (json_t* const notesJ = json_object_get(rootJ, "notes")) | |||
| { | |||
| for (int i = 0; i < 18; i++) | |||
| for (int id = 0; id < 18; ++id) | |||
| { | |||
| if (json_t* const noteJ = json_array_get(notesJ, i)) | |||
| learnedNotes[i] = json_integer_value(noteJ); | |||
| if (json_t* const noteJ = json_array_get(notesJ, id)) | |||
| setLearnedNote(id, json_integer_value(noteJ)); | |||
| else | |||
| learnedNotes[i] = -1; | |||
| learnedNotes[id] = -1; | |||
| } | |||
| } | |||
| @@ -430,7 +460,7 @@ struct HostMIDIGate : TerminalModule { | |||
| struct CardinalNoteChoice : CardinalLedDisplayChoice { | |||
| HostMIDIGate* const module; | |||
| const int id; | |||
| int focusNote = -1; | |||
| int8_t focusNote = -1; | |||
| CardinalNoteChoice(HostMIDIGate* const m, const int i) | |||
| : CardinalLedDisplayChoice(), | |||
| @@ -439,7 +469,7 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { | |||
| void step() override | |||
| { | |||
| int note; | |||
| int8_t note; | |||
| if (module == nullptr) | |||
| { | |||
| @@ -489,8 +519,8 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { | |||
| if (module->midiInput.learningId == id) | |||
| { | |||
| if (0 <= focusNote && focusNote < 128) | |||
| module->learnedNotes[id] = focusNote; | |||
| if (focusNote >= 0) | |||
| module->setLearnedNote(id, focusNote); | |||
| module->midiInput.learningId = -1; | |||
| } | |||
| } | |||
| @@ -518,7 +548,7 @@ struct CardinalNoteChoice : CardinalLedDisplayChoice { | |||
| } | |||
| } | |||
| if (focusNote >= 128) | |||
| if (focusNote < 0) | |||
| focusNote = -1; | |||
| e.consume(this); | |||
| @@ -86,6 +86,8 @@ struct HostMIDI : TerminalModule { | |||
| uint8_t channel; | |||
| // stuff from Rack | |||
| /** Number of semitones to bend up/down by pitch wheel */ | |||
| float pwRange; | |||
| bool smooth; | |||
| int channels; | |||
| enum PolyMode { | |||
| @@ -144,6 +146,7 @@ struct HostMIDI : TerminalModule { | |||
| smooth = true; | |||
| channels = 1; | |||
| polyMode = ROTATE_MODE; | |||
| pwRange = 2; | |||
| panic(); | |||
| } | |||
| @@ -246,30 +249,20 @@ struct HostMIDI : TerminalModule { | |||
| ++midiEventFrame; | |||
| // Rack stuff | |||
| outputs[PITCH_OUTPUT].setChannels(channels); | |||
| outputs[GATE_OUTPUT].setChannels(channels); | |||
| outputs[VELOCITY_OUTPUT].setChannels(channels); | |||
| outputs[AFTERTOUCH_OUTPUT].setChannels(channels); | |||
| for (int c = 0; c < channels; 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); | |||
| } | |||
| // Set pitch and mod wheel | |||
| const int wheelChannels = (polyMode == MPE_MODE) ? 16 : 1; | |||
| float pwValues[16] = {}; | |||
| outputs[PITCHBEND_OUTPUT].setChannels(wheelChannels); | |||
| outputs[MODWHEEL_OUTPUT].setChannels(wheelChannels); | |||
| for (int c = 0; c < wheelChannels; c++) { | |||
| float pw = ((int) pws[c] - 8192) / 8191.f; | |||
| float pw = (int16_t(pws[c]) - 8192) / 8191.f; | |||
| pw = clamp(pw, -1.f, 1.f); | |||
| if (smooth) | |||
| pw = pwFilters[c].process(args.sampleTime, pw); | |||
| else | |||
| pwFilters[c].out = pw; | |||
| outputs[PITCHBEND_OUTPUT].setVoltage(pw * 5.f); | |||
| pwValues[c] = pw; | |||
| outputs[PITCHBEND_OUTPUT].setVoltage(pw * 5.f, c); | |||
| float mod = mods[c] / 127.f; | |||
| mod = clamp(mod, 0.f, 1.f); | |||
| @@ -277,7 +270,22 @@ struct HostMIDI : TerminalModule { | |||
| mod = modFilters[c].process(args.sampleTime, mod); | |||
| else | |||
| modFilters[c].out = mod; | |||
| outputs[MODWHEEL_OUTPUT].setVoltage(mod * 10.f); | |||
| outputs[MODWHEEL_OUTPUT].setVoltage(mod * 10.f, c); | |||
| } | |||
| // Set note outputs | |||
| outputs[PITCH_OUTPUT].setChannels(channels); | |||
| outputs[GATE_OUTPUT].setChannels(channels); | |||
| outputs[VELOCITY_OUTPUT].setChannels(channels); | |||
| outputs[AFTERTOUCH_OUTPUT].setChannels(channels); | |||
| for (int c = 0; c < channels; c++) { | |||
| float pw = pwValues[(polyMode == MPE_MODE) ? c : 0]; | |||
| float pitch = (notes[c] - 60.f + pw * pwRange) / 12.f; | |||
| outputs[PITCH_OUTPUT].setVoltage(pitch, 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); | |||
| } | |||
| outputs[START_OUTPUT].setVoltage(startPulse.process(args.sampleTime) ? 10.f : 0.f); | |||
| @@ -636,6 +644,7 @@ struct HostMIDI : TerminalModule { | |||
| json_t* const rootJ = json_object(); | |||
| DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr); | |||
| json_object_set_new(rootJ, "pwRange", json_real(midiInput.pwRange)); | |||
| json_object_set_new(rootJ, "smooth", json_boolean(midiInput.smooth)); | |||
| json_object_set_new(rootJ, "channels", json_integer(midiInput.channels)); | |||
| json_object_set_new(rootJ, "polyMode", json_integer(midiInput.polyMode)); | |||
| @@ -655,6 +664,12 @@ struct HostMIDI : TerminalModule { | |||
| void dataFromJson(json_t* const rootJ) override | |||
| { | |||
| if (json_t* const pwRangeJ = json_object_get(rootJ, "pwRange")) | |||
| midiInput.pwRange = json_number_value(pwRangeJ); | |||
| // For backwards compatibility, set to 0 if undefined in JSON. | |||
| else | |||
| midiInput.pwRange = 0; | |||
| if (json_t* const smoothJ = json_object_get(rootJ, "smooth")) | |||
| midiInput.smooth = json_boolean_value(smoothJ); | |||
| @@ -738,6 +753,16 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { | |||
| menu->addChild(createBoolPtrMenuItem("Smooth pitch/mod wheel", "", &module->midiInput.smooth)); | |||
| static const std::vector<float> pwRanges = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 24, 36, 48}; | |||
| menu->addChild(createSubmenuItem("Pitch bend range", string::f("%g", module->midiInput.pwRange), [=](Menu* menu) { | |||
| for (size_t i = 0; i < pwRanges.size(); i++) { | |||
| menu->addChild(createCheckMenuItem(string::f("%g", pwRanges[i]), "", | |||
| [=]() {return module->midiInput.pwRange == pwRanges[i];}, | |||
| [=]() {module->midiInput.pwRange = pwRanges[i];} | |||
| )); | |||
| } | |||
| })); | |||
| struct InputChannelItem : MenuItem { | |||
| HostMIDI* module; | |||
| Menu* createChildMenu() override { | |||
| @@ -758,24 +783,14 @@ struct HostMIDIWidget : ModuleWidgetWith9HP { | |||
| inputChannelItem->module = module; | |||
| menu->addChild(inputChannelItem); | |||
| struct PolyphonyChannelItem : MenuItem { | |||
| HostMIDI* module; | |||
| Menu* createChildMenu() override { | |||
| Menu* menu = new Menu; | |||
| for (int c = 1; c <= 16; c++) { | |||
| menu->addChild(createCheckMenuItem((c == 1) ? "Monophonic" : string::f("%d", c), "", | |||
| [=]() {return module->midiInput.channels == c;}, | |||
| [=]() {module->midiInput.setChannels(c);} | |||
| )); | |||
| } | |||
| return menu; | |||
| menu->addChild(createSubmenuItem("Polyphony channels", string::f("%d", module->midiInput.channels), [=](Menu* menu) { | |||
| for (int c = 1; c <= 16; c++) { | |||
| menu->addChild(createCheckMenuItem((c == 1) ? "Monophonic" : string::f("%d", c), "", | |||
| [=]() {return module->midiInput.channels == c;}, | |||
| [=]() {module->midiInput.setChannels(c);} | |||
| )); | |||
| } | |||
| }; | |||
| PolyphonyChannelItem* const polyphonyChannelItem = new PolyphonyChannelItem; | |||
| polyphonyChannelItem->text = "Polyphony channels"; | |||
| polyphonyChannelItem->rightText = string::f("%d", module->midiInput.channels) + " " + RIGHT_ARROW; | |||
| polyphonyChannelItem->module = module; | |||
| menu->addChild(polyphonyChannelItem); | |||
| })); | |||
| menu->addChild(createIndexPtrSubmenuItem("Polyphony mode", { | |||
| "Rotate", | |||
| @@ -206,7 +206,7 @@ ifeq ($(MACOS),true) | |||
| LINK_FLAGS += -framework IOKit | |||
| else ifeq ($(WINDOWS),true) | |||
| # needed by VCVRack | |||
| EXTRA_LIBS += -ldbghelp -lshlwapi | |||
| EXTRA_LIBS += -ldbghelp -lshlwapi -Wl,--stack,0x100000 | |||
| # needed by JW-Modules | |||
| EXTRA_LIBS += -lws2_32 -lwinmm | |||
| endif | |||
| @@ -1 +1 @@ | |||
| Subproject commit 0d003b96476af45102117c2bb958aeb59eb523cf | |||
| Subproject commit 30665d62801c2ced7260a37a2d0214edfe6528a9 | |||
| @@ -534,7 +534,7 @@ struct HelpButton : MenuButton { | |||
| menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | |||
| menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { | |||
| system::openBrowser("https://vcvrack.com/manual/"); | |||
| system::openBrowser("https://vcvrack.com/manual"); | |||
| })); | |||
| menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { | |||
| @@ -50,7 +50,7 @@ const std::string APP_NAME = "Cardinal"; | |||
| const std::string APP_EDITION = getPluginFormatName(); | |||
| const std::string APP_EDITION_NAME = "Audio Plugin"; | |||
| const std::string APP_VERSION_MAJOR = "2"; | |||
| const std::string APP_VERSION = "2.0"; | |||
| const std::string APP_VERSION = "2.1"; | |||
| #if defined ARCH_WIN | |||
| const std::string APP_OS = "win"; | |||
| #elif ARCH_MAC | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/engine/Engine.cpp 2022-01-15 11:59:46.188414546 +0000 | |||
| +++ Engine.cpp 2022-02-09 02:13:37.829435608 +0000 | |||
| --- ../Rack/src/engine/Engine.cpp 2022-02-05 22:30:09.253393116 +0000 | |||
| +++ Engine.cpp 2022-02-10 18:51:20.077011285 +0000 | |||
| @@ -1,3 +1,30 @@ | |||
| +/* | |||
| + * DISTRHO Cardinal Plugin | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/app/MenuBar.cpp 2022-01-15 11:59:46.188414546 +0000 | |||
| +++ MenuBar.cpp 2022-02-14 03:38:00.935519007 +0000 | |||
| --- ../Rack/src/app/MenuBar.cpp 2022-02-26 23:08:06.697192725 +0000 | |||
| +++ MenuBar.cpp 2022-02-26 23:19:38.779828613 +0000 | |||
| @@ -1,8 +1,33 @@ | |||
| +/* | |||
| + * DISTRHO Cardinal Plugin | |||
| @@ -562,7 +562,7 @@ | |||
| } | |||
| }; | |||
| @@ -802,63 +528,23 @@ | |||
| @@ -802,65 +528,23 @@ | |||
| struct HelpButton : MenuButton { | |||
| @@ -584,29 +584,35 @@ | |||
| - | |||
| - menu->addChild(createMenuItem("User manual", "F1", [=]() { | |||
| + menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { | |||
| system::openBrowser("https://vcvrack.com/manual/"); | |||
| system::openBrowser("https://vcvrack.com/manual"); | |||
| })); | |||
| - menu->addChild(createMenuItem("Support", "", [=]() { | |||
| - system::openBrowser("https://vcvrack.com/support"); | |||
| - })); | |||
| - | |||
| - menu->addChild(createMenuItem("VCVRack.com", "", [=]() { | |||
| - system::openBrowser("https://vcvrack.com/"); | |||
| + menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { | |||
| + system::openBrowser("https://github.com/DISTRHO/Cardinal/"); | |||
| })); | |||
| menu->addChild(new ui::MenuSeparator); | |||
| - menu->addChild(createMenuLabel(APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION)); | |||
| - | |||
| - menu->addChild(createMenuItem("Open user folder", "", [=]() { | |||
| - system::openDirectory(asset::user("")); | |||
| - })); | |||
| - | |||
| - if (library::isAppUpdateAvailable()) { | |||
| - menu->addChild(new ui::MenuSeparator); | |||
| - menu->addChild(createMenuItem("Changelog", "", [=]() { | |||
| - system::openBrowser("https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md"); | |||
| - })); | |||
| - | |||
| - if (library::isAppUpdateAvailable()) { | |||
| - menu->addChild(createMenuItem("Update " + APP_NAME, APP_VERSION + " → " + library::appVersion, [=]() { | |||
| - system::openBrowser(library::appDownloadUrl); | |||
| - })); | |||
| - | |||
| - menu->addChild(createMenuItem("Review changelog", "", [=]() { | |||
| - system::openBrowser(library::appChangelogUrl); | |||
| - })); | |||
| - } | |||
| - else if (!settings::autoCheckUpdates && !settings::devMode) { | |||
| - menu->addChild(createMenuItem("Check for " + APP_NAME + " update", "", [=]() { | |||
| @@ -616,10 +622,6 @@ | |||
| - t.detach(); | |||
| - }, false, true)); | |||
| - } | |||
| - | |||
| menu->addChild(new ui::MenuSeparator); | |||
| - menu->addChild(createMenuLabel(APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION)); | |||
| - } | |||
| - | |||
| - void step() override { | |||
| @@ -631,7 +633,7 @@ | |||
| } | |||
| }; | |||
| @@ -908,7 +594,9 @@ | |||
| @@ -910,7 +594,9 @@ | |||
| struct MenuBar : widget::OpaqueWidget { | |||
| MeterLabel* meterLabel; | |||
| @@ -642,7 +644,7 @@ | |||
| const float margin = 5; | |||
| box.size.y = BND_WIDGET_HEIGHT + 2 * margin; | |||
| @@ -917,7 +605,7 @@ | |||
| @@ -919,7 +605,7 @@ | |||
| layout->spacing = math::Vec(0, 0); | |||
| addChild(layout); | |||
| @@ -651,7 +653,7 @@ | |||
| fileButton->text = "File"; | |||
| layout->addChild(fileButton); | |||
| @@ -933,10 +621,6 @@ | |||
| @@ -935,10 +621,6 @@ | |||
| engineButton->text = "Engine"; | |||
| layout->addChild(engineButton); | |||
| @@ -662,7 +664,7 @@ | |||
| HelpButton* helpButton = new HelpButton; | |||
| helpButton->text = "Help"; | |||
| layout->addChild(helpButton); | |||
| @@ -971,7 +655,11 @@ | |||
| @@ -973,7 +655,11 @@ | |||
| widget::Widget* createMenuBar() { | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/plugin/Model.cpp 2021-10-20 03:28:14.516922788 +0100 | |||
| +++ Model.cpp 2022-01-24 00:11:36.628498885 +0000 | |||
| --- ../Rack/src/plugin/Model.cpp 2021-10-17 13:57:23.257633662 +0100 | |||
| +++ Model.cpp 2022-01-23 17:13:22.080013846 +0000 | |||
| @@ -1,3 +1,30 @@ | |||
| +/* | |||
| + * DISTRHO Cardinal Plugin | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/app/Scene.cpp 2021-12-04 09:46:43.912932319 +0000 | |||
| +++ Scene.cpp 2022-02-11 05:30:49.567801073 +0000 | |||
| --- ../Rack/src/app/Scene.cpp 2022-02-26 23:08:06.701192797 +0000 | |||
| +++ Scene.cpp 2022-02-17 23:13:46.013018500 +0000 | |||
| @@ -1,3 +1,30 @@ | |||
| +/* | |||
| + * DISTRHO Cardinal Plugin | |||
| @@ -58,7 +58,7 @@ | |||
| namespace rack { | |||
| namespace app { | |||
| @@ -23,16 +63,55 @@ | |||
| @@ -23,21 +63,60 @@ | |||
| math::Vec size; | |||
| void draw(const DrawArgs& args) override { | |||
| @@ -120,6 +120,12 @@ | |||
| size = APP->window->getSize(); | |||
| } | |||
| void onDragMove(const DragMoveEvent& e) override { | |||
| - size = size.plus(e.mouseDelta); | |||
| + size = size.plus(e.mouseDelta.mult(APP->window->pixelRatio)); | |||
| APP->window->setSize(size.round()); | |||
| } | |||
| }; | |||
| @@ -46,9 +125,32 @@ | |||
| struct Scene::Internal { | |||
| ResizeHandle* resizeHandle; | |||
| @@ -283,7 +289,7 @@ | |||
| // Key commands that can be overridden by children | |||
| if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | |||
| - // Alternate key command for exiting fullscreen, since F11 doesn't work reliably on Mac due to "Show desktop" OS binding. | |||
| - // Alternative key command for exiting fullscreen, since F11 doesn't work reliably on Mac due to "Show desktop" OS binding. | |||
| - if (e.key == GLFW_KEY_ESCAPE && (e.mods & RACK_MOD_MASK) == 0) { | |||
| - if (APP->window->isFullScreen()) { | |||
| - APP->window->setFullScreen(false); | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/window/Window.cpp 2022-01-01 15:50:17.777305924 +0000 | |||
| +++ Window.cpp 2022-02-13 02:07:46.554983286 +0000 | |||
| --- ../Rack/src/window/Window.cpp 2022-02-09 15:35:19.238863170 +0000 | |||
| +++ Window.cpp 2022-02-13 21:19:37.799091196 +0000 | |||
| @@ -1,33 +1,83 @@ | |||
| +/* | |||
| + * DISTRHO Cardinal Plugin | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/dep/oui-blendish/blendish.c 2021-12-12 16:59:23.714275191 +0000 | |||
| +++ blendish.c 2021-12-12 16:51:37.956349106 +0000 | |||
| --- ../Rack/dep/oui-blendish/blendish.c 2021-10-17 13:57:24.613620711 +0100 | |||
| +++ blendish.c 2021-12-13 09:36:22.182673256 +0000 | |||
| @@ -61,7 +61,7 @@ | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/common.cpp 2021-12-04 09:46:43.912932319 +0000 | |||
| +++ common.cpp 2022-01-24 00:11:36.628498885 +0000 | |||
| --- ../Rack/src/common.cpp 2021-11-23 19:57:23.719015894 +0000 | |||
| +++ common.cpp 2022-02-27 00:17:50.908149000 +0000 | |||
| @@ -1,6 +1,38 @@ | |||
| +/* | |||
| + * DISTRHO Cardinal Plugin | |||
| @@ -52,7 +52,7 @@ | |||
| +const std::string APP_EDITION_NAME = "Audio Plugin"; | |||
| const std::string APP_VERSION_MAJOR = "2"; | |||
| -const std::string APP_VERSION = TOSTRING(_APP_VERSION); | |||
| +const std::string APP_VERSION = "2.0"; | |||
| +const std::string APP_VERSION = "2.1"; | |||
| #if defined ARCH_WIN | |||
| const std::string APP_OS = "win"; | |||
| #elif ARCH_MAC | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/context.cpp 2022-01-15 11:59:46.188414546 +0000 | |||
| +++ context.cpp 2022-01-24 00:11:36.628498885 +0000 | |||
| --- ../Rack/src/context.cpp 2022-02-05 22:30:09.253393116 +0000 | |||
| +++ context.cpp 2022-01-23 17:13:11.652514338 +0000 | |||
| @@ -1,3 +1,30 @@ | |||
| +/* | |||
| + * DISTRHO Cardinal Plugin | |||
| @@ -1,5 +1,5 @@ | |||
| --- ../Rack/src/plugin.cpp 2022-01-15 11:59:46.188414546 +0000 | |||
| +++ plugin.cpp 2022-01-30 02:49:08.228488442 +0000 | |||
| --- ../Rack/src/plugin.cpp 2022-02-05 22:30:09.265393248 +0000 | |||
| +++ plugin.cpp 2022-01-30 00:24:49.375329910 +0000 | |||
| @@ -1,308 +1,40 @@ | |||
| -#include <thread> | |||
| -#include <map> | |||