| @@ -35,7 +35,6 @@ struct MIDIClockToCVInterface : MidiIO, Module { | |||||
| MIDIClockToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | MIDIClockToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | ||||
| ignore_midiTime = false; | |||||
| } | } | ||||
| @@ -46,9 +45,11 @@ struct MIDIClockToCVInterface : MidiIO, Module { | |||||
| void processMidi(std::vector<unsigned char> msg); | void processMidi(std::vector<unsigned char> msg); | ||||
| virtual void resetMidi(); | |||||
| void onDeviceChange(); | |||||
| virtual json_t *toJson() { | |||||
| void resetMidi(); | |||||
| json_t *toJson() { | |||||
| json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
| addBaseJson(rootJ); | addBaseJson(rootJ); | ||||
| json_object_set_new(rootJ, "clock1ratio", json_integer(clock1ratio)); | json_object_set_new(rootJ, "clock1ratio", json_integer(clock1ratio)); | ||||
| @@ -56,7 +57,7 @@ struct MIDIClockToCVInterface : MidiIO, Module { | |||||
| return rootJ; | return rootJ; | ||||
| } | } | ||||
| virtual void fromJson(json_t *rootJ) { | |||||
| void fromJson(json_t *rootJ) { | |||||
| baseFromJson(rootJ); | baseFromJson(rootJ); | ||||
| json_t *c1rJ = json_object_get(rootJ, "clock1ratio"); | json_t *c1rJ = json_object_get(rootJ, "clock1ratio"); | ||||
| if (c1rJ) { | if (c1rJ) { | ||||
| @@ -69,7 +70,7 @@ struct MIDIClockToCVInterface : MidiIO, Module { | |||||
| } | } | ||||
| } | } | ||||
| virtual void initialize() { | |||||
| void initialize() { | |||||
| resetMidi(); | resetMidi(); | ||||
| } | } | ||||
| @@ -178,6 +179,10 @@ void MIDIClockToCVInterface::processMidi(std::vector<unsigned char> msg) { | |||||
| } | } | ||||
| void MIDIClockToCVInterface::onDeviceChange() { | |||||
| setIgnores(true, false); | |||||
| } | |||||
| struct ClockRatioItem : MenuItem { | struct ClockRatioItem : MenuItem { | ||||
| int ratio; | int ratio; | ||||
| int *clockRatio; | int *clockRatio; | ||||
| @@ -7,7 +7,6 @@ | |||||
| using namespace rack; | using namespace rack; | ||||
| /** | /** | ||||
| * MidiIO implements the shared functionality of all midi modules, namely: | * MidiIO implements the shared functionality of all midi modules, namely: | ||||
| * + Channel Selection (including helper for storing json) | * + Channel Selection (including helper for storing json) | ||||
| @@ -27,7 +26,7 @@ void MidiIO::setChannel(int channel) { | |||||
| this->channel = channel; | this->channel = channel; | ||||
| } | } | ||||
| std::unordered_map<std::string, MidiInWrapper*> MidiIO::midiInMap = {}; | |||||
| std::unordered_map<std::string, MidiInWrapper *> MidiIO::midiInMap = {}; | |||||
| json_t *MidiIO::addBaseJson(json_t *rootJ) { | json_t *MidiIO::addBaseJson(json_t *rootJ) { | ||||
| if (deviceName != "") { | if (deviceName != "") { | ||||
| @@ -51,7 +50,7 @@ void MidiIO::baseFromJson(json_t *rootJ) { | |||||
| std::vector<std::string> MidiIO::getDevices() { | std::vector<std::string> MidiIO::getDevices() { | ||||
| /* Note: we could also use an existing interface if one exists */ | /* Note: we could also use an existing interface if one exists */ | ||||
| static RtMidiIn * m = new RtMidiIn(); | |||||
| static RtMidiIn *m = new RtMidiIn(); | |||||
| std::vector<std::string> names = {}; | std::vector<std::string> names = {}; | ||||
| @@ -85,20 +84,34 @@ void MidiIO::openDevice(std::string deviceName) { | |||||
| } | } | ||||
| catch (RtMidiError &error) { | catch (RtMidiError &error) { | ||||
| fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); | fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); | ||||
| this->deviceName = ""; | |||||
| this->id = -1; | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| this->deviceName = deviceName; | this->deviceName = deviceName; | ||||
| /* TODO: this works for now, but is not ideal. If a clock is added and connected to a module | |||||
| * the time messages will still be received after the clock is removed. This adds an overhead | |||||
| * which can be avoided but I want to find a good solution.*/ | |||||
| if (!ignore_midiTime || !ignore_midiTime || !ignore_midiSense){ | |||||
| midiInMap[deviceName]->ignoreTypes(ignore_midiSysex, ignore_midiTime, ignore_midiSense); | |||||
| id = midiInMap[deviceName]->add(); | |||||
| onDeviceChange(); | |||||
| } | |||||
| void MidiIO::setIgnores(bool ignoreSysex, bool ignoreTime, bool ignoreSense) { | |||||
| bool sy = true, ti = true, se = true; | |||||
| midiInMap[deviceName]->ignoresMap[id][0] = ignoreSysex; | |||||
| midiInMap[deviceName]->ignoresMap[id][1] = ignoreTime; | |||||
| midiInMap[deviceName]->ignoresMap[id][2] = ignoreSense; | |||||
| for (auto kv : midiInMap[deviceName]->ignoresMap) { | |||||
| sy = sy && kv.second[0]; | |||||
| ti = ti && kv.second[1]; | |||||
| se = se && kv.second[2]; | |||||
| } | } | ||||
| id = midiInMap[deviceName]->add(); | |||||
| midiInMap[deviceName]->ignoreTypes(se,ti,se); | |||||
| } | } | ||||
| std::string MidiIO::getDeviceName() { | std::string MidiIO::getDeviceName() { | ||||
| @@ -141,13 +154,15 @@ bool MidiIO::isPortOpen() { | |||||
| void MidiIO::close() { | void MidiIO::close() { | ||||
| MidiInWrapper * mw = midiInMap[deviceName]; | |||||
| MidiInWrapper *mw = midiInMap[deviceName]; | |||||
| if (!mw || id < 0) { | if (!mw || id < 0) { | ||||
| //fprintf(stderr, "Trying to close already closed device!\n"); | //fprintf(stderr, "Trying to close already closed device!\n"); | ||||
| return; | return; | ||||
| } | } | ||||
| setIgnores(); // reset ignore types for this instance | |||||
| mw->erase(id); | mw->erase(id); | ||||
| if (mw->subscribers == 0) { | if (mw->subscribers == 0) { | ||||
| @@ -15,6 +15,12 @@ using namespace rack; | |||||
| struct MidiInWrapper : RtMidiIn { | struct MidiInWrapper : RtMidiIn { | ||||
| std::unordered_map<int, std::list<std::vector<unsigned char>>> idMessagesMap; | std::unordered_map<int, std::list<std::vector<unsigned char>>> idMessagesMap; | ||||
| std::unordered_map<int, std::list<double>> idStampsMap; | std::unordered_map<int, std::list<double>> idStampsMap; | ||||
| /* Stores Ignore settings for each instance in the following order: | |||||
| * {ignore_midiSysex, ignore_midiTime, ignore_midiSense} | |||||
| */ | |||||
| std::unordered_map<int, bool[3]> ignoresMap; | |||||
| int uid_c = 0; | int uid_c = 0; | ||||
| int subscribers = 0; | int subscribers = 0; | ||||
| @@ -28,6 +34,10 @@ struct MidiInWrapper : RtMidiIn { | |||||
| subscribers++; | subscribers++; | ||||
| idMessagesMap[id] = {}; | idMessagesMap[id] = {}; | ||||
| idStampsMap[id] = {}; | idStampsMap[id] = {}; | ||||
| ignoresMap[id][0] = true; | |||||
| ignoresMap[id][1] = true; | |||||
| ignoresMap[id][2] = true; | |||||
| return id; | return id; | ||||
| } | } | ||||
| @@ -35,6 +45,7 @@ struct MidiInWrapper : RtMidiIn { | |||||
| subscribers--; | subscribers--; | ||||
| idMessagesMap.erase(id); | idMessagesMap.erase(id); | ||||
| idStampsMap.erase(id); | idStampsMap.erase(id); | ||||
| ignoresMap.erase(id); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -47,9 +58,6 @@ private: | |||||
| bool isOut = false; | bool isOut = false; | ||||
| public: | public: | ||||
| bool ignore_midiSysex=true; | |||||
| bool ignore_midiTime=true; | |||||
| bool ignore_midiSense=true; | |||||
| int channel; | int channel; | ||||
| @@ -63,6 +71,8 @@ public: | |||||
| void openDevice(std::string deviceName); | void openDevice(std::string deviceName); | ||||
| void setIgnores(bool ignoreSysex = true, bool ignoreTime = true, bool ignoreSense = true); | |||||
| std::string getDeviceName(); | std::string getDeviceName(); | ||||
| void setChannel(int channel); | void setChannel(int channel); | ||||
| @@ -79,6 +89,9 @@ public: | |||||
| /* called when midi port is set */ | /* called when midi port is set */ | ||||
| virtual void resetMidi()=0; | virtual void resetMidi()=0; | ||||
| /* called if a user switches or sets the deivce (and after this device is initialised)*/ | |||||
| virtual void onDeviceChange(){}; | |||||
| }; | }; | ||||
| ////////////////////// | ////////////////////// | ||||