| @@ -16,11 +16,21 @@ struct MIDI_Map : Module { | |||||
| }; | }; | ||||
| midi::InputQueue midiInput; | midi::InputQueue midiInput; | ||||
| /** Channel ID of the learning session */ | |||||
| int learningId; | int learningId; | ||||
| /** Whether the CC has been set during the learning session */ | |||||
| bool learnedCc; | |||||
| /** Whether the param has been set during the learning session */ | |||||
| bool learnedParam; | |||||
| /** The learned CC number of each channel */ | |||||
| int learnedCcs[8]; | int learnedCcs[8]; | ||||
| /** The learned module handle of each channel */ | |||||
| ModuleHandle learnedModuleHandles[8]; | ModuleHandle learnedModuleHandles[8]; | ||||
| /** The learned param ID of each channel */ | |||||
| int learnedParamIds[8]; | int learnedParamIds[8]; | ||||
| /** The value of each CC number */ | |||||
| int8_t values[128]; | int8_t values[128]; | ||||
| /** The smoothing processor (normalized between 0 and 1) of each channel */ | |||||
| dsp::ExponentialFilter valueFilters[8]; | dsp::ExponentialFilter valueFilters[8]; | ||||
| MIDI_Map() { | MIDI_Map() { | ||||
| @@ -39,6 +49,8 @@ struct MIDI_Map : Module { | |||||
| void onReset() override { | void onReset() override { | ||||
| learningId = -1; | learningId = -1; | ||||
| learnedCc = false; | |||||
| learnedParam = false; | |||||
| for (int i = 0; i < 8; i++) { | for (int i = 0; i < 8; i++) { | ||||
| learnedCcs[i] = -1; | learnedCcs[i] = -1; | ||||
| unloadModuleHandle(i); | unloadModuleHandle(i); | ||||
| @@ -71,6 +83,7 @@ struct MIDI_Map : Module { | |||||
| learnedModuleHandles[learningId].id = module->id; | learnedModuleHandles[learningId].id = module->id; | ||||
| loadModuleHandle(learningId); | loadModuleHandle(learningId); | ||||
| learnedParamIds[learningId] = paramId; | learnedParamIds[learningId] = paramId; | ||||
| learnedParam = true; | |||||
| commitLearn(); | commitLearn(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -115,6 +128,8 @@ struct MIDI_Map : Module { | |||||
| // Learn | // Learn | ||||
| if (learningId >= 0 && values[cc] != msg.getValue()) { | if (learningId >= 0 && values[cc] != msg.getValue()) { | ||||
| learnedCcs[learningId] = cc; | learnedCcs[learningId] = cc; | ||||
| valueFilters[learningId].reset(); | |||||
| learnedCc = true; | |||||
| commitLearn(); | commitLearn(); | ||||
| } | } | ||||
| values[cc] = msg.getValue(); | values[cc] = msg.getValue(); | ||||
| @@ -135,22 +150,45 @@ struct MIDI_Map : Module { | |||||
| void commitLearn() { | void commitLearn() { | ||||
| if (learningId < 0) | if (learningId < 0) | ||||
| return; | return; | ||||
| if (learnedModuleHandles[learningId].id < 0) | |||||
| if (!learnedCc) | |||||
| return; | return; | ||||
| if (learnedCcs[learningId] < 0) | |||||
| if (!learnedParam) | |||||
| return; | return; | ||||
| learningId++; | |||||
| if (learningId >= 8) | |||||
| learningId = -1; | |||||
| // Reset learned state | |||||
| learnedCc = false; | |||||
| learnedParam = false; | |||||
| // Find next unlearned channel | |||||
| while (++learningId < 8) { | |||||
| if (learnedCcs[learningId] < 0 || learnedModuleHandles[learningId].id < 0) | |||||
| return; | |||||
| } | |||||
| learningId = -1; | |||||
| } | } | ||||
| void clearLearn(int id) { | void clearLearn(int id) { | ||||
| disableLearn(id); | |||||
| learnedCcs[id] = -1; | learnedCcs[id] = -1; | ||||
| unloadModuleHandle(id); | unloadModuleHandle(id); | ||||
| learnedModuleHandles[id].id = -1; | learnedModuleHandles[id].id = -1; | ||||
| loadModuleHandle(id); | loadModuleHandle(id); | ||||
| } | } | ||||
| void enableLearn(int id) { | |||||
| if (learningId != id) { | |||||
| learningId = id; | |||||
| learnedCc = false; | |||||
| learnedParam = false; | |||||
| } | |||||
| } | |||||
| void disableLearn(int id) { | |||||
| if (learningId == id) { | |||||
| learningId = -1; | |||||
| learnedCc = false; | |||||
| learnedParam = false; | |||||
| } | |||||
| } | |||||
| json_t *dataToJson() override { | json_t *dataToJson() override { | ||||
| json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
| @@ -231,27 +269,28 @@ struct MIDI_MapChoice : LedDisplayChoice { | |||||
| if (module) { | if (module) { | ||||
| module->clearLearn(id); | module->clearLearn(id); | ||||
| } | } | ||||
| e.consume(this); | |||||
| } | } | ||||
| } | } | ||||
| void onSelect(const event::Select &e) override { | void onSelect(const event::Select &e) override { | ||||
| if (!module) | if (!module) | ||||
| return; | return; | ||||
| module->learningId = id; | |||||
| module->enableLearn(id); | |||||
| e.consume(this); | e.consume(this); | ||||
| } | } | ||||
| void onDeselect(const event::Deselect &e) override { | void onDeselect(const event::Deselect &e) override { | ||||
| if (!module) | if (!module) | ||||
| return; | return; | ||||
| if (module->learningId == id) { | |||||
| module->learningId = -1; | |||||
| } | |||||
| module->disableLearn(id); | |||||
| } | } | ||||
| void step() override { | void step() override { | ||||
| if (!module) | if (!module) | ||||
| return; | return; | ||||
| // Set bgColor and selected state | |||||
| if (module->learningId == id) { | if (module->learningId == id) { | ||||
| bgColor = color; | bgColor = color; | ||||
| bgColor.a = 0.15; | bgColor.a = 0.15; | ||||
| @@ -264,27 +303,35 @@ struct MIDI_MapChoice : LedDisplayChoice { | |||||
| bgColor = nvgRGBA(0, 0, 0, 0); | bgColor = nvgRGBA(0, 0, 0, 0); | ||||
| // HACK | // HACK | ||||
| // Don't let the event state call onDeselect() | |||||
| if (APP->event->selectedWidget == this) | if (APP->event->selectedWidget == this) | ||||
| APP->event->setSelected(NULL); | APP->event->setSelected(NULL); | ||||
| } | } | ||||
| // Set text | |||||
| text = ""; | text = ""; | ||||
| color.a = 1.0; | |||||
| if (module->learnedCcs[id] >= 0) { | if (module->learnedCcs[id] >= 0) { | ||||
| text += string::f("CC%d ", module->learnedCcs[id]); | text += string::f("CC%d ", module->learnedCcs[id]); | ||||
| } | } | ||||
| if (module->learnedModuleHandles[id].id >= 0) { | if (module->learnedModuleHandles[id].id >= 0) { | ||||
| text += getParamName(); | text += getParamName(); | ||||
| } | } | ||||
| if (!(module->learnedCcs[id] >= 0) && !(module->learnedModuleHandles[id].id >= 0)) { | |||||
| if (module->learnedCcs[id] < 0 && module->learnedModuleHandles[id].id < 0) { | |||||
| if (module->learningId == id) { | if (module->learningId == id) { | ||||
| text = "Mapping..."; | text = "Mapping..."; | ||||
| } | } | ||||
| else { | else { | ||||
| text = "Unmapped"; | text = "Unmapped"; | ||||
| color.a = 0.5; | |||||
| } | } | ||||
| } | } | ||||
| // Set text color | |||||
| if ((module->learnedCcs[id] >= 0 && module->learnedModuleHandles[id].id >= 0) || module->learningId == id) { | |||||
| color.a = 1.0; | |||||
| } | |||||
| else { | |||||
| color.a = 0.5; | |||||
| } | |||||
| } | } | ||||
| std::string getParamName() { | std::string getParamName() { | ||||