Update/sync to Rack 2.1

Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
falkTX 2022-02-27 00:18:43 +00:00
parent 6cb739b52c
commit 5188b50a4f
No known key found for this signature in database
GPG key ID: CDBAA37ABC74FBA0
16 changed files with 223 additions and 143 deletions

View file

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

View file

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

View file

@ -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",