|
|
@@ -19,10 +19,10 @@ struct MIDICCToCVInterface : Module { |
|
|
|
|
|
|
|
midi::InputQueue midiInput; |
|
|
|
int8_t values[128]; |
|
|
|
dsp::ExponentialFilter ccFilters[16]; |
|
|
|
dsp::ExponentialFilter valueFilters[16]; |
|
|
|
|
|
|
|
int learningId = -1; |
|
|
|
int learnedCcs[16] = {}; |
|
|
|
int ccs[16] = {}; |
|
|
|
bool jump[16] = {}; |
|
|
|
|
|
|
|
MIDICCToCVInterface() { |
|
|
@@ -35,7 +35,7 @@ struct MIDICCToCVInterface : Module { |
|
|
|
values[i] = 0; |
|
|
|
} |
|
|
|
for (int i = 0; i < 16; i++) { |
|
|
|
learnedCcs[i] = i; |
|
|
|
ccs[i] = i; |
|
|
|
} |
|
|
|
learningId = -1; |
|
|
|
} |
|
|
@@ -48,18 +48,18 @@ struct MIDICCToCVInterface : Module { |
|
|
|
|
|
|
|
float lambda = app()->engine->getSampleTime() * 100.f; |
|
|
|
for (int i = 0; i < 16; i++) { |
|
|
|
int learnedCc = learnedCcs[i]; |
|
|
|
int learnedCc = ccs[i]; |
|
|
|
float value = rescale(values[learnedCc], 0, 127, 0.f, 10.f); |
|
|
|
ccFilters[i].lambda = lambda; |
|
|
|
valueFilters[i].lambda = lambda; |
|
|
|
// Smooth value unless we're jumping there |
|
|
|
if (jump[i]) { |
|
|
|
ccFilters[i].out = value; |
|
|
|
valueFilters[i].out = value; |
|
|
|
jump[i] = false; |
|
|
|
} |
|
|
|
else { |
|
|
|
ccFilters[i].process(value); |
|
|
|
valueFilters[i].process(value); |
|
|
|
} |
|
|
|
outputs[CC_OUTPUT + i].setVoltage(ccFilters[i].out); |
|
|
|
outputs[CC_OUTPUT + i].setVoltage(valueFilters[i].out); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -70,7 +70,7 @@ struct MIDICCToCVInterface : Module { |
|
|
|
uint8_t cc = msg.note(); |
|
|
|
// Learn |
|
|
|
if (learningId >= 0 && values[cc] != msg.data2) { |
|
|
|
learnedCcs[learningId] = cc; |
|
|
|
ccs[learningId] = cc; |
|
|
|
learningId = -1; |
|
|
|
} |
|
|
|
int8_t oldValue = values[cc]; |
|
|
@@ -92,11 +92,17 @@ struct MIDICCToCVInterface : Module { |
|
|
|
|
|
|
|
json_t *ccsJ = json_array(); |
|
|
|
for (int i = 0; i < 16; i++) { |
|
|
|
json_t *ccJ = json_integer(learnedCcs[i]); |
|
|
|
json_array_append_new(ccsJ, ccJ); |
|
|
|
json_array_append_new(ccsJ, json_integer(ccs[i])); |
|
|
|
} |
|
|
|
json_object_set_new(rootJ, "ccs", ccsJ); |
|
|
|
|
|
|
|
// Remember values so users don't have to touch MIDI controller knobs when restarting Rack |
|
|
|
json_t *valuesJ = json_array(); |
|
|
|
for (int i = 0; i < 128; i++) { |
|
|
|
json_array_append_new(valuesJ, json_integer(values[i])); |
|
|
|
} |
|
|
|
json_object_set_new(rootJ, "values", valuesJ); |
|
|
|
|
|
|
|
json_object_set_new(rootJ, "midi", midiInput.toJson()); |
|
|
|
return rootJ; |
|
|
|
} |
|
|
@@ -107,7 +113,21 @@ struct MIDICCToCVInterface : Module { |
|
|
|
for (int i = 0; i < 16; i++) { |
|
|
|
json_t *ccJ = json_array_get(ccsJ, i); |
|
|
|
if (ccJ) |
|
|
|
learnedCcs[i] = json_integer_value(ccJ); |
|
|
|
ccs[i] = json_integer_value(ccJ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
json_t *valuesJ = json_object_get(rootJ, "values"); |
|
|
|
if (valuesJ) { |
|
|
|
for (int i = 0; i < 128; i++) { |
|
|
|
json_t *valueJ = json_array_get(valuesJ, i); |
|
|
|
if (valueJ) { |
|
|
|
values[i] = json_integer_value(valueJ); |
|
|
|
} |
|
|
|
} |
|
|
|
// Jump all CCs |
|
|
|
for (int i = 0; i < 16; i++) { |
|
|
|
jump[i] = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -145,7 +165,7 @@ struct MidiCcChoice : GridChoice { |
|
|
|
color.a = 0.5; |
|
|
|
} |
|
|
|
else { |
|
|
|
text = string::f("%d", module->learnedCcs[id]); |
|
|
|
text = string::f("%d", module->ccs[id]); |
|
|
|
color.a = 1.0; |
|
|
|
if (app()->event->selectedWidget == this) |
|
|
|
app()->event->selectedWidget = NULL; |
|
|
@@ -164,7 +184,7 @@ struct MidiCcChoice : GridChoice { |
|
|
|
if (!module) |
|
|
|
return; |
|
|
|
if (0 <= focusCc && focusCc < 128) { |
|
|
|
module->learnedCcs[id] = focusCc; |
|
|
|
module->ccs[id] = focusCc; |
|
|
|
} |
|
|
|
module->learningId = -1; |
|
|
|
} |
|
|
|