| @@ -212,7 +212,7 @@ struct MidiGenerator { | |||
| } | |||
| } | |||
| virtual void onMessage(midi::Message message) {} | |||
| virtual void onMessage(const midi::Message &message) {} | |||
| }; | |||
| @@ -15,38 +15,59 @@ namespace midi { | |||
| struct Message { | |||
| uint8_t size = 3; | |||
| uint8_t bytes[3] = {}; | |||
| /** Initialized to 3 empty bytes. */ | |||
| std::vector<uint8_t> bytes; | |||
| uint8_t getSize() { | |||
| return size; | |||
| Message() : bytes(3) {} | |||
| int getSize() const { | |||
| return bytes.size(); | |||
| } | |||
| void setSize(uint8_t size) { | |||
| assert(size <= 3); | |||
| this->size = size; | |||
| void setSize(int size) { | |||
| bytes.resize(size); | |||
| } | |||
| uint8_t getChannel() { | |||
| uint8_t getChannel() const { | |||
| if (bytes.size() < 1) | |||
| return 0; | |||
| return bytes[0] & 0xf; | |||
| } | |||
| void setChannel(uint8_t channel) { | |||
| if (bytes.size() < 1) | |||
| return; | |||
| bytes[0] = (bytes[0] & 0xf0) | (channel & 0xf); | |||
| } | |||
| uint8_t getStatus() { | |||
| uint8_t getStatus() const { | |||
| if (bytes.size() < 1) | |||
| return 0; | |||
| return bytes[0] >> 4; | |||
| } | |||
| void setStatus(uint8_t status) { | |||
| if (bytes.size() < 1) | |||
| return; | |||
| bytes[0] = (bytes[0] & 0xf) | (status << 4); | |||
| } | |||
| uint8_t getNote() { | |||
| uint8_t getNote() const { | |||
| if (bytes.size() < 2) | |||
| return 0; | |||
| return bytes[1]; | |||
| } | |||
| void setNote(uint8_t note) { | |||
| if (bytes.size() < 2) | |||
| return; | |||
| bytes[1] = note & 0x7f; | |||
| } | |||
| uint8_t getValue() { | |||
| uint8_t getValue() const { | |||
| if (bytes.size() < 3) | |||
| return 0; | |||
| return bytes[2]; | |||
| } | |||
| void setValue(uint8_t value) { | |||
| if (bytes.size() < 3) | |||
| return; | |||
| bytes[2] = value & 0x7f; | |||
| } | |||
| }; | |||
| @@ -103,14 +124,14 @@ struct InputDevice : Device { | |||
| std::set<Input*> subscribed; | |||
| void subscribe(Input* input); | |||
| void unsubscribe(Input* input); | |||
| void onMessage(Message message); | |||
| void onMessage(const Message &message); | |||
| }; | |||
| struct OutputDevice : Device { | |||
| std::set<Output*> subscribed; | |||
| void subscribe(Output* input); | |||
| void unsubscribe(Output* input); | |||
| virtual void sendMessage(Message message) {} | |||
| virtual void sendMessage(const Message &message) {} | |||
| }; | |||
| //////////////////// | |||
| @@ -187,16 +208,19 @@ struct Input : Port { | |||
| std::vector<int> getChannels() override; | |||
| virtual void onMessage(Message message) {} | |||
| virtual void onMessage(const Message &message) {} | |||
| }; | |||
| struct InputQueue : Input { | |||
| int queueMaxSize = 8192; | |||
| std::queue<Message> queue; | |||
| void onMessage(Message message) override; | |||
| /** If a Message is available, writes `message` and return true */ | |||
| bool shift(Message* message); | |||
| void onMessage(const Message &message) override; | |||
| bool empty(); | |||
| /** Returns Message from first in queue. | |||
| You must check empty(). If the queue is empty, the behavior of this method is undefined. | |||
| */ | |||
| Message shift(); | |||
| }; | |||
| @@ -222,7 +246,7 @@ struct Output : Port { | |||
| std::vector<int> getChannels() override; | |||
| void sendMessage(Message message); | |||
| void sendMessage(const Message &message); | |||
| }; | |||
| @@ -6,7 +6,7 @@ namespace core { | |||
| struct MidiOutput : dsp::MidiGenerator<PORT_MAX_CHANNELS>, midi::Output { | |||
| void onMessage(midi::Message message) override { | |||
| void onMessage(const midi::Message &message) override { | |||
| Output::sendMessage(message); | |||
| } | |||
| @@ -48,8 +48,8 @@ struct MIDI_CC : Module { | |||
| } | |||
| void process(const ProcessArgs& args) override { | |||
| midi::Message msg; | |||
| while (midiInput.shift(&msg)) { | |||
| while (!midiInput.empty()) { | |||
| midi::Message msg = midiInput.shift(); | |||
| processMessage(msg); | |||
| } | |||
| @@ -73,7 +73,7 @@ struct MIDI_CC : Module { | |||
| } | |||
| } | |||
| void processMessage(midi::Message msg) { | |||
| void processMessage(const midi::Message &msg) { | |||
| switch (msg.getStatus()) { | |||
| // cc | |||
| case 0xb: { | |||
| @@ -83,8 +83,10 @@ struct MIDI_CC : Module { | |||
| } | |||
| } | |||
| void processCC(midi::Message msg) { | |||
| void processCC(const midi::Message &msg) { | |||
| uint8_t cc = msg.getNote(); | |||
| if (msg.bytes.size() < 2) | |||
| return; | |||
| // Allow CC to be negative if the 8th bit is set. | |||
| // The gamepad driver abuses this, for example. | |||
| // Cast uint8_t to int8_t | |||
| @@ -119,8 +119,8 @@ struct MIDI_CV : Module { | |||
| } | |||
| void process(const ProcessArgs& args) override { | |||
| midi::Message msg; | |||
| while (midiInput.shift(&msg)) { | |||
| while (!midiInput.empty()) { | |||
| midi::Message msg = midiInput.shift(); | |||
| processMessage(msg); | |||
| } | |||
| @@ -159,7 +159,7 @@ struct MIDI_CV : Module { | |||
| outputs[CONTINUE_OUTPUT].setVoltage(continuePulse.process(args.sampleTime) ? 10.f : 0.f); | |||
| } | |||
| void processMessage(midi::Message msg) { | |||
| void processMessage(const midi::Message &msg) { | |||
| // DEBUG("MIDI: %01x %01x %02x %02x", msg.getStatus(), msg.getChannel(), msg.getNote(), msg.getValue()); | |||
| switch (msg.getStatus()) { | |||
| @@ -217,7 +217,7 @@ struct MIDI_CV : Module { | |||
| } | |||
| } | |||
| void processCC(midi::Message msg) { | |||
| void processCC(const midi::Message &msg) { | |||
| switch (msg.getNote()) { | |||
| // mod | |||
| case 0x01: { | |||
| @@ -235,7 +235,7 @@ struct MIDI_CV : Module { | |||
| } | |||
| } | |||
| void processSystem(midi::Message msg) { | |||
| void processSystem(const midi::Message &msg) { | |||
| switch (msg.getChannel()) { | |||
| // Timing | |||
| case 0x8: { | |||
| @@ -55,8 +55,8 @@ struct MIDI_Gate : Module { | |||
| } | |||
| void process(const ProcessArgs& args) override { | |||
| midi::Message msg; | |||
| while (midiInput.shift(&msg)) { | |||
| while (!midiInput.empty()) { | |||
| midi::Message msg = midiInput.shift(); | |||
| processMessage(msg); | |||
| } | |||
| @@ -75,7 +75,7 @@ struct MIDI_Gate : Module { | |||
| } | |||
| } | |||
| void processMessage(midi::Message msg) { | |||
| void processMessage(const midi::Message &msg) { | |||
| switch (msg.getStatus()) { | |||
| // note off | |||
| case 0x8: { | |||
| @@ -78,8 +78,8 @@ struct MIDI_Map : Module { | |||
| void process(const ProcessArgs& args) override { | |||
| if (divider.process()) { | |||
| midi::Message msg; | |||
| while (midiInput.shift(&msg)) { | |||
| while (!midiInput.empty()) { | |||
| midi::Message msg = midiInput.shift(); | |||
| processMessage(msg); | |||
| } | |||
| @@ -123,7 +123,7 @@ struct MIDI_Map : Module { | |||
| } | |||
| } | |||
| void processMessage(midi::Message msg) { | |||
| void processMessage(const midi::Message &msg) { | |||
| // DEBUG("MIDI: %01x %01x %02x %02x", msg.getStatus(), msg.getChannel(), msg.getNote(), msg.getValue()); | |||
| switch (msg.getStatus()) { | |||
| @@ -135,7 +135,7 @@ struct MIDI_Map : Module { | |||
| } | |||
| } | |||
| void processCC(midi::Message msg) { | |||
| void processCC(const midi::Message &msg) { | |||
| uint8_t cc = msg.getNote(); | |||
| int8_t value = msg.getValue(); | |||
| // Learn | |||
| @@ -51,7 +51,7 @@ struct InputDevice : midi::InputDevice { | |||
| midi::Message msg; | |||
| msg.setStatus(0xb); | |||
| msg.setNote(i); | |||
| // Allow 8th bit to be set | |||
| // Allow 8th bit to be set to allow bipolar value hack. | |||
| msg.bytes[2] = cc; | |||
| onMessage(msg); | |||
| } | |||
| @@ -25,7 +25,7 @@ void InputDevice::unsubscribe(Input* input) { | |||
| subscribed.erase(it); | |||
| } | |||
| void InputDevice::onMessage(Message message) { | |||
| void InputDevice::onMessage(const Message &message) { | |||
| for (Input* input : subscribed) { | |||
| // Filter channel | |||
| if (input->channel < 0 || message.getStatus() == 0xf || message.getChannel() == input->channel) { | |||
| @@ -163,21 +163,21 @@ std::vector<int> Input::getChannels() { | |||
| return channels; | |||
| } | |||
| void InputQueue::onMessage(Message message) { | |||
| void InputQueue::onMessage(const Message &message) { | |||
| if ((int) queue.size() >= queueMaxSize) | |||
| return; | |||
| // Push to queue | |||
| if ((int) queue.size() < queueMaxSize) | |||
| queue.push(message); | |||
| queue.push(message); | |||
| } | |||
| bool InputQueue::shift(Message* message) { | |||
| if (!message) | |||
| return false; | |||
| if (!queue.empty()) { | |||
| *message = queue.front(); | |||
| queue.pop(); | |||
| return true; | |||
| } | |||
| return false; | |||
| bool InputQueue::empty() { | |||
| return queue.empty(); | |||
| } | |||
| Message InputQueue::shift() { | |||
| Message msg = queue.front(); | |||
| queue.pop(); | |||
| return msg; | |||
| } | |||
| //////////////////// | |||
| @@ -220,16 +220,17 @@ std::vector<int> Output::getChannels() { | |||
| return channels; | |||
| } | |||
| void Output::sendMessage(Message message) { | |||
| void Output::sendMessage(const Message &message) { | |||
| if (!outputDevice) | |||
| return; | |||
| // Set channel | |||
| if (message.getStatus() != 0xf) { | |||
| message.setChannel(channel); | |||
| Message msg = message; | |||
| if (msg.getStatus() != 0xf) { | |||
| msg.setChannel(channel); | |||
| } | |||
| // DEBUG("sendMessage %02x %02x %02x", message.cmd, message.data1, message.data2); | |||
| outputDevice->sendMessage(message); | |||
| // DEBUG("sendMessage %02x %02x %02x", msg.cmd, msg.data1, msg.data2); | |||
| outputDevice->sendMessage(msg); | |||
| } | |||
| @@ -45,15 +45,8 @@ struct RtMidiInputDevice : midi::InputDevice { | |||
| if (!midiInputDevice) | |||
| return; | |||
| // Users have reported that some MIDI devices can send messages >3 bytes. I don't know how this is possible, so just reject the message. | |||
| if (message->size() > 3) | |||
| return; | |||
| midi::Message msg; | |||
| msg.size = message->size(); | |||
| for (int i = 0; i < msg.size; i++) { | |||
| msg.bytes[i] = (*message)[i]; | |||
| } | |||
| msg.bytes = std::vector<uint8_t>(message->begin(), message->end()); | |||
| midiInputDevice->onMessage(msg); | |||
| } | |||
| }; | |||
| @@ -79,8 +72,9 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||
| return name; | |||
| } | |||
| void sendMessage(midi::Message message) override { | |||
| rtMidiOut->sendMessage(message.bytes, message.size); | |||
| void sendMessage(const midi::Message &message) override { | |||
| std::vector<unsigned char> bytes(message.bytes.begin(), message.bytes.end()); | |||
| rtMidiOut->sendMessage(&bytes); | |||
| } | |||
| }; | |||