@@ -35,7 +35,6 @@ struct MIDIClockToCVInterface : MidiIO, Module { | |||
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); | |||
virtual void resetMidi(); | |||
void onDeviceChange(); | |||
virtual json_t *toJson() { | |||
void resetMidi(); | |||
json_t *toJson() { | |||
json_t *rootJ = json_object(); | |||
addBaseJson(rootJ); | |||
json_object_set_new(rootJ, "clock1ratio", json_integer(clock1ratio)); | |||
@@ -56,7 +57,7 @@ struct MIDIClockToCVInterface : MidiIO, Module { | |||
return rootJ; | |||
} | |||
virtual void fromJson(json_t *rootJ) { | |||
void fromJson(json_t *rootJ) { | |||
baseFromJson(rootJ); | |||
json_t *c1rJ = json_object_get(rootJ, "clock1ratio"); | |||
if (c1rJ) { | |||
@@ -69,7 +70,7 @@ struct MIDIClockToCVInterface : MidiIO, Module { | |||
} | |||
} | |||
virtual void initialize() { | |||
void initialize() { | |||
resetMidi(); | |||
} | |||
@@ -178,6 +179,10 @@ void MIDIClockToCVInterface::processMidi(std::vector<unsigned char> msg) { | |||
} | |||
void MIDIClockToCVInterface::onDeviceChange() { | |||
setIgnores(true, false); | |||
} | |||
struct ClockRatioItem : MenuItem { | |||
int ratio; | |||
int *clockRatio; | |||
@@ -7,7 +7,6 @@ | |||
using namespace rack; | |||
/** | |||
* MidiIO implements the shared functionality of all midi modules, namely: | |||
* + Channel Selection (including helper for storing json) | |||
@@ -27,7 +26,7 @@ void MidiIO::setChannel(int 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) { | |||
if (deviceName != "") { | |||
@@ -51,7 +50,7 @@ void MidiIO::baseFromJson(json_t *rootJ) { | |||
std::vector<std::string> MidiIO::getDevices() { | |||
/* 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 = {}; | |||
@@ -85,20 +84,34 @@ void MidiIO::openDevice(std::string deviceName) { | |||
} | |||
catch (RtMidiError &error) { | |||
fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); | |||
this->deviceName = ""; | |||
this->id = -1; | |||
return; | |||
} | |||
} | |||
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() { | |||
@@ -141,13 +154,15 @@ bool MidiIO::isPortOpen() { | |||
void MidiIO::close() { | |||
MidiInWrapper * mw = midiInMap[deviceName]; | |||
MidiInWrapper *mw = midiInMap[deviceName]; | |||
if (!mw || id < 0) { | |||
//fprintf(stderr, "Trying to close already closed device!\n"); | |||
return; | |||
} | |||
setIgnores(); // reset ignore types for this instance | |||
mw->erase(id); | |||
if (mw->subscribers == 0) { | |||
@@ -15,6 +15,12 @@ using namespace rack; | |||
struct MidiInWrapper : RtMidiIn { | |||
std::unordered_map<int, std::list<std::vector<unsigned char>>> idMessagesMap; | |||
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 subscribers = 0; | |||
@@ -28,6 +34,10 @@ struct MidiInWrapper : RtMidiIn { | |||
subscribers++; | |||
idMessagesMap[id] = {}; | |||
idStampsMap[id] = {}; | |||
ignoresMap[id][0] = true; | |||
ignoresMap[id][1] = true; | |||
ignoresMap[id][2] = true; | |||
return id; | |||
} | |||
@@ -35,6 +45,7 @@ struct MidiInWrapper : RtMidiIn { | |||
subscribers--; | |||
idMessagesMap.erase(id); | |||
idStampsMap.erase(id); | |||
ignoresMap.erase(id); | |||
} | |||
}; | |||
@@ -47,9 +58,6 @@ private: | |||
bool isOut = false; | |||
public: | |||
bool ignore_midiSysex=true; | |||
bool ignore_midiTime=true; | |||
bool ignore_midiSense=true; | |||
int channel; | |||
@@ -63,6 +71,8 @@ public: | |||
void openDevice(std::string deviceName); | |||
void setIgnores(bool ignoreSysex = true, bool ignoreTime = true, bool ignoreSense = true); | |||
std::string getDeviceName(); | |||
void setChannel(int channel); | |||
@@ -79,6 +89,9 @@ public: | |||
/* called when midi port is set */ | |||
virtual void resetMidi()=0; | |||
/* called if a user switches or sets the deivce (and after this device is initialised)*/ | |||
virtual void onDeviceChange(){}; | |||
}; | |||
////////////////////// | |||