| @@ -19,10 +19,10 @@ struct MIDICCToCVInterface : Module { | |||||
| midi::InputQueue midiInput; | midi::InputQueue midiInput; | ||||
| int8_t values[128]; | int8_t values[128]; | ||||
| dsp::ExponentialFilter ccFilters[16]; | |||||
| dsp::ExponentialFilter valueFilters[16]; | |||||
| int learningId = -1; | int learningId = -1; | ||||
| int learnedCcs[16] = {}; | |||||
| int ccs[16] = {}; | |||||
| bool jump[16] = {}; | bool jump[16] = {}; | ||||
| MIDICCToCVInterface() { | MIDICCToCVInterface() { | ||||
| @@ -35,7 +35,7 @@ struct MIDICCToCVInterface : Module { | |||||
| values[i] = 0; | values[i] = 0; | ||||
| } | } | ||||
| for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
| learnedCcs[i] = i; | |||||
| ccs[i] = i; | |||||
| } | } | ||||
| learningId = -1; | learningId = -1; | ||||
| } | } | ||||
| @@ -48,18 +48,18 @@ struct MIDICCToCVInterface : Module { | |||||
| float lambda = app()->engine->getSampleTime() * 100.f; | float lambda = app()->engine->getSampleTime() * 100.f; | ||||
| for (int i = 0; i < 16; i++) { | 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); | 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 | // Smooth value unless we're jumping there | ||||
| if (jump[i]) { | if (jump[i]) { | ||||
| ccFilters[i].out = value; | |||||
| valueFilters[i].out = value; | |||||
| jump[i] = false; | jump[i] = false; | ||||
| } | } | ||||
| else { | 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(); | uint8_t cc = msg.note(); | ||||
| // Learn | // Learn | ||||
| if (learningId >= 0 && values[cc] != msg.data2) { | if (learningId >= 0 && values[cc] != msg.data2) { | ||||
| learnedCcs[learningId] = cc; | |||||
| ccs[learningId] = cc; | |||||
| learningId = -1; | learningId = -1; | ||||
| } | } | ||||
| int8_t oldValue = values[cc]; | int8_t oldValue = values[cc]; | ||||
| @@ -92,11 +92,17 @@ struct MIDICCToCVInterface : Module { | |||||
| json_t *ccsJ = json_array(); | json_t *ccsJ = json_array(); | ||||
| for (int i = 0; i < 16; i++) { | 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); | 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()); | json_object_set_new(rootJ, "midi", midiInput.toJson()); | ||||
| return rootJ; | return rootJ; | ||||
| } | } | ||||
| @@ -107,7 +113,21 @@ struct MIDICCToCVInterface : Module { | |||||
| for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
| json_t *ccJ = json_array_get(ccsJ, i); | json_t *ccJ = json_array_get(ccsJ, i); | ||||
| if (ccJ) | 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; | color.a = 0.5; | ||||
| } | } | ||||
| else { | else { | ||||
| text = string::f("%d", module->learnedCcs[id]); | |||||
| text = string::f("%d", module->ccs[id]); | |||||
| color.a = 1.0; | color.a = 1.0; | ||||
| if (app()->event->selectedWidget == this) | if (app()->event->selectedWidget == this) | ||||
| app()->event->selectedWidget = NULL; | app()->event->selectedWidget = NULL; | ||||
| @@ -164,7 +184,7 @@ struct MidiCcChoice : GridChoice { | |||||
| if (!module) | if (!module) | ||||
| return; | return; | ||||
| if (0 <= focusCc && focusCc < 128) { | if (0 <= focusCc && focusCc < 128) { | ||||
| module->learnedCcs[id] = focusCc; | |||||
| module->ccs[id] = focusCc; | |||||
| } | } | ||||
| module->learningId = -1; | module->learningId = -1; | ||||
| } | } | ||||