#include #include "rack.hpp" #include "rtmidi/RtMidi.h" using namespace rack; struct IgnoreFlags { bool midiSysex = true; bool midiTime = true; bool midiSense = true; }; struct MidiMessage { std::vector bytes; double timeStamp; MidiMessage() : bytes(0), timeStamp(0.0) {}; }; /** * This class allows to use one instance of rtMidiIn with * multiple modules. A MidiIn port will be opened only once while multiple * instances can use it simultaniously, each receiving all its incoming messages. */ struct MidiInWrapper : RtMidiIn { std::unordered_map> idMessagesMap; std::unordered_map ignoresMap; int uid_c = 0; MidiInWrapper() : RtMidiIn() { idMessagesMap = {}; }; int add() { int id = ++uid_c; idMessagesMap[id] = {}; ignoresMap[id] = IgnoreFlags(); return id; } void erase(int id) { idMessagesMap.erase(id); ignoresMap.erase(id); } }; /** * Note: MidiIO is not thread safe which might become * important in the future */ struct MidiIO { private: static std::unordered_map midiInMap; /* TODO: add for midi out*/ int id = -1; std::string deviceName = ""; bool isOut = false; public: int channel; MidiIO(bool isOut = false); ~MidiIO() { close(); } std::vector getDevices(); void openDevice(std::string deviceName); void setIgnores(bool ignoreSysex = true, bool ignoreTime = true, bool ignoreSense = true); std::string getDeviceName(); void setChannel(int channel); double getMessage(std::vector *msg); json_t *addBaseJson(json_t *rootJ); void baseFromJson(json_t *rootJ); bool isPortOpen(); void close(); /* called when midi port is set */ virtual void resetMidi()=0; /* called if a user switches or sets the device (and after this device is initialised)*/ virtual void onDeviceChange() {}; }; struct TransitionSmoother { enum TransitionFunction { SMOOTHSTEP, EXP, LIN, }; enum TransitionMode { DELTA, CONST, }; float start; float end; float x; float delta; float step; TransitionFunction t; void set(float start, float end, int l = 1500, TransitionFunction t = LIN, TransitionMode m = DELTA, bool reset = true) { this->start = start; this->end = end; this->delta = end - start; this->t = t; if (reset || x >= 1) { this->x = 0; } switch (m) { case DELTA: /* If the change is smaller, the transition phase is longer */ this->step = delta > 0 ? delta/l : -delta/l; break; case CONST: this->step = 1.0/l; break; } } float next() { float next = start; x += step; if (x >= 1) return end; switch (t) { case SMOOTHSTEP: next += delta*x*x*(3-2*x); break; case EXP: next += delta*x*x; break; case LIN: next += delta*x; break; } if ((delta > 0 && next > end) || (delta <= 0 && next < end)) return end; return next;; } }; ////////////////////// // MIDI module widgets ////////////////////// struct MidiItem : MenuItem { MidiIO *midiModule; void onAction(EventAction &e); }; struct MidiChoice : ChoiceButton { MidiIO *midiModule; void onAction(EventAction &e); void step(); }; struct ChannelItem : MenuItem { MidiIO *midiModule; int channel; void onAction(EventAction &e); }; struct ChannelChoice : ChoiceButton { MidiIO *midiModule; void onAction(EventAction &e); void step(); }; struct MidiToCVWidget : ModuleWidget { MidiToCVWidget(); void step(); }; struct MIDICCToCVWidget : ModuleWidget { MIDICCToCVWidget(); void step(); }; struct MIDIClockToCVWidget : ModuleWidget { MIDIClockToCVWidget(); void step(); }; struct MIDITriggerToCVWidget : ModuleWidget { MIDITriggerToCVWidget(); void step(); }; struct QuadMidiToCVWidget : ModuleWidget { QuadMidiToCVWidget(); void step(); };