@@ -57,18 +57,18 @@ struct CV_MIDICC : Module { | |||
CCMidiOutput midiOutput; | |||
dsp::Timer rateLimiterTimer; | |||
int learningId = -1; | |||
int learnedCcs[16] = {}; | |||
int8_t learnedCcs[16] = {}; | |||
CV_MIDICC() { | |||
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)); | |||
onReset(); | |||
} | |||
void onReset() override { | |||
for (int i = 0; i < 16; i++) { | |||
learnedCcs[i] = i; | |||
for (int id = 0; id < 16; id++) { | |||
learnedCcs[id] = id; | |||
} | |||
learningId = -1; | |||
midiOutput.reset(); | |||
@@ -85,19 +85,29 @@ struct CV_MIDICC : Module { | |||
midiOutput.setFrame(args.frame); | |||
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); | |||
midiOutput.setValue(value, learnedCcs[i]); | |||
for (int id = 0; id < 16; id++) { | |||
uint8_t value = (uint8_t) clamp(std::round(inputs[CC_INPUTS + id].getVoltage() / 10.f * 127), 0.f, 127.f); | |||
midiOutput.setValue(value, learnedCcs[id]); | |||
} | |||
} | |||
void setLearnedCc(int id, int8_t cc) { | |||
// Unset IDs of similar CCs | |||
if (cc >= 0) { | |||
for (int id = 0; id < 16; id++) { | |||
if (learnedCcs[id] == cc) | |||
learnedCcs[id] = -1; | |||
} | |||
} | |||
learnedCcs[id] = cc; | |||
} | |||
json_t* dataToJson() override { | |||
json_t* rootJ = json_object(); | |||
json_t* 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); | |||
@@ -108,10 +118,10 @@ struct CV_MIDICC : Module { | |||
void dataFromJson(json_t* rootJ) override { | |||
json_t* ccsJ = json_object_get(rootJ, "ccs"); | |||
if (ccsJ) { | |||
for (int i = 0; i < 16; i++) { | |||
json_t* ccJ = json_array_get(ccsJ, i); | |||
for (int id = 0; id < 16; id++) { | |||
json_t* ccJ = json_array_get(ccsJ, id); | |||
if (ccJ) | |||
learnedCcs[i] = json_integer_value(ccJ); | |||
setLearnedCc(id, json_integer_value(ccJ)); | |||
} | |||
} | |||
@@ -116,8 +116,7 @@ struct Gate_MIDI : Module { | |||
continue; | |||
if (velocityMode) { | |||
int8_t vel = (int8_t) clamp(std::round(inputs[GATE_INPUTS + id].getVoltage() / 10.f * 127), 0.f, 127.f); | |||
vel = clamp(vel, 0, 127); | |||
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); | |||
} | |||
@@ -29,7 +29,7 @@ struct MIDICC_CV : Module { | |||
*/ | |||
int8_t msbValues[32][16]; | |||
int learningId; | |||
int learnedCcs[16]; | |||
int8_t learnedCcs[16]; | |||
/** [cell][channel] */ | |||
dsp::ExponentialFilter valueFilters[16][16]; | |||
bool smooth; | |||
@@ -38,31 +38,31 @@ struct MIDICC_CV : Module { | |||
MIDICC_CV() { | |||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||
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)); | |||
for (int i = 0; i < 16; i++) { | |||
for (int id = 0; id < 16; id++) { | |||
for (int c = 0; c < 16; c++) { | |||
valueFilters[i][c].setTau(1 / 30.f); | |||
valueFilters[id][c].setTau(1 / 30.f); | |||
} | |||
} | |||
onReset(); | |||
} | |||
void onReset() override { | |||
for (int cc = 0; cc < 128; cc++) { | |||
for (int8_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 (int8_t cc = 0; cc < 32; cc++) { | |||
for (int c = 0; c < 16; c++) { | |||
msbValues[cc][c] = 0; | |||
} | |||
} | |||
learningId = -1; | |||
for (int i = 0; i < 16; i++) { | |||
learnedCcs[i] = i; | |||
for (int id = 0; id < 16; id++) { | |||
learnedCcs[id] = id; | |||
} | |||
midiInput.reset(); | |||
smooth = true; | |||
@@ -78,12 +78,12 @@ struct MIDICC_CV : Module { | |||
int channels = mpeMode ? 16 : 1; | |||
for (int i = 0; i < 16; i++) { | |||
if (!outputs[CC_OUTPUT + i].isConnected()) | |||
for (int id = 0; id < 16; id++) { | |||
if (!outputs[CC_OUTPUT + id].isConnected()) | |||
continue; | |||
outputs[CC_OUTPUT + i].setChannels(channels); | |||
outputs[CC_OUTPUT + id].setChannels(channels); | |||
int cc = learnedCcs[i]; | |||
int cc = learnedCcs[id]; | |||
for (int c = 0; c < channels; c++) { | |||
int16_t cellValue = int16_t(ccValues[cc][c]) * 128; | |||
@@ -95,15 +95,15 @@ struct MIDICC_CV : Module { | |||
value = clamp(value, -1.f, 1.f); | |||
// Detect behavior from MIDI buttons. | |||
if (smooth && std::fabs(valueFilters[i][c].out - value) < 1.f) { | |||
if (smooth && std::fabs(valueFilters[id][c].out - value) < 1.f) { | |||
// Smooth value with filter | |||
valueFilters[i][c].process(args.sampleTime, value); | |||
valueFilters[id][c].process(args.sampleTime, value); | |||
} | |||
else { | |||
// Jump value | |||
valueFilters[i][c].out = value; | |||
valueFilters[id][c].out = value; | |||
} | |||
outputs[CC_OUTPUT + i].setVoltage(valueFilters[i][c].out * 10.f, c); | |||
outputs[CC_OUTPUT + id].setVoltage(valueFilters[id][c].out * 10.f, c); | |||
} | |||
} | |||
} | |||
@@ -129,7 +129,7 @@ struct MIDICC_CV : Module { | |||
int8_t value = msg.bytes[2]; | |||
// Learn | |||
if (learningId >= 0 && ccValues[cc][c] != value) { | |||
learnedCcs[learningId] = cc; | |||
setLearnedCc(learningId, cc); | |||
learningId = -1; | |||
} | |||
@@ -147,6 +147,17 @@ struct MIDICC_CV : Module { | |||
} | |||
} | |||
void setLearnedCc(int id, int8_t cc) { | |||
// Unset IDs of similar CCs | |||
if (cc >= 0) { | |||
for (int id = 0; id < 16; id++) { | |||
if (learnedCcs[id] == cc) | |||
learnedCcs[id] = -1; | |||
} | |||
} | |||
learnedCcs[id] = cc; | |||
} | |||
json_t* dataToJson() override { | |||
json_t* rootJ = json_object(); | |||
@@ -178,7 +189,7 @@ struct MIDICC_CV : Module { | |||
for (int i = 0; i < 16; i++) { | |||
json_t* ccJ = json_array_get(ccsJ, i); | |||
if (ccJ) | |||
learnedCcs[i] = json_integer_value(ccJ); | |||
setLearnedCc(i, json_integer_value(ccJ)); | |||
} | |||
} | |||
@@ -137,6 +137,13 @@ struct MIDI_Gate : Module { | |||
} | |||
void setLearnedNote(int id, int8_t note) { | |||
// Unset IDs of similar note | |||
if (note >= 0) { | |||
for (int id = 0; id < 16; id++) { | |||
if (learnedNotes[id] == note) | |||
learnedNotes[id] = -1; | |||
} | |||
} | |||
learnedNotes[id] = note; | |||
} | |||
@@ -114,7 +114,7 @@ struct CcChoice : LedDisplayChoice { | |||
return; | |||
if (module->learningId == id) { | |||
if (0 <= focusCc && focusCc < 128) { | |||
module->learnedCcs[id] = focusCc; | |||
module->setLearnedCc(id, focusCc); | |||
} | |||
module->learningId = -1; | |||
} | |||