@@ -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 { | 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; | return bytes[0] & 0xf; | ||||
} | } | ||||
void setChannel(uint8_t channel) { | void setChannel(uint8_t channel) { | ||||
if (bytes.size() < 1) | |||||
return; | |||||
bytes[0] = (bytes[0] & 0xf0) | (channel & 0xf); | bytes[0] = (bytes[0] & 0xf0) | (channel & 0xf); | ||||
} | } | ||||
uint8_t getStatus() { | |||||
uint8_t getStatus() const { | |||||
if (bytes.size() < 1) | |||||
return 0; | |||||
return bytes[0] >> 4; | return bytes[0] >> 4; | ||||
} | } | ||||
void setStatus(uint8_t status) { | void setStatus(uint8_t status) { | ||||
if (bytes.size() < 1) | |||||
return; | |||||
bytes[0] = (bytes[0] & 0xf) | (status << 4); | bytes[0] = (bytes[0] & 0xf) | (status << 4); | ||||
} | } | ||||
uint8_t getNote() { | |||||
uint8_t getNote() const { | |||||
if (bytes.size() < 2) | |||||
return 0; | |||||
return bytes[1]; | return bytes[1]; | ||||
} | } | ||||
void setNote(uint8_t note) { | void setNote(uint8_t note) { | ||||
if (bytes.size() < 2) | |||||
return; | |||||
bytes[1] = note & 0x7f; | bytes[1] = note & 0x7f; | ||||
} | } | ||||
uint8_t getValue() { | |||||
uint8_t getValue() const { | |||||
if (bytes.size() < 3) | |||||
return 0; | |||||
return bytes[2]; | return bytes[2]; | ||||
} | } | ||||
void setValue(uint8_t value) { | void setValue(uint8_t value) { | ||||
if (bytes.size() < 3) | |||||
return; | |||||
bytes[2] = value & 0x7f; | bytes[2] = value & 0x7f; | ||||
} | } | ||||
}; | }; | ||||
@@ -103,14 +124,14 @@ struct InputDevice : Device { | |||||
std::set<Input*> subscribed; | std::set<Input*> subscribed; | ||||
void subscribe(Input* input); | void subscribe(Input* input); | ||||
void unsubscribe(Input* input); | void unsubscribe(Input* input); | ||||
void onMessage(Message message); | |||||
void onMessage(const Message &message); | |||||
}; | }; | ||||
struct OutputDevice : Device { | struct OutputDevice : Device { | ||||
std::set<Output*> subscribed; | std::set<Output*> subscribed; | ||||
void subscribe(Output* input); | void subscribe(Output* input); | ||||
void unsubscribe(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; | std::vector<int> getChannels() override; | ||||
virtual void onMessage(Message message) {} | |||||
virtual void onMessage(const Message &message) {} | |||||
}; | }; | ||||
struct InputQueue : Input { | struct InputQueue : Input { | ||||
int queueMaxSize = 8192; | int queueMaxSize = 8192; | ||||
std::queue<Message> queue; | 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; | 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 { | 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); | Output::sendMessage(message); | ||||
} | } | ||||
@@ -48,8 +48,8 @@ struct MIDI_CC : Module { | |||||
} | } | ||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
midi::Message msg; | |||||
while (midiInput.shift(&msg)) { | |||||
while (!midiInput.empty()) { | |||||
midi::Message msg = midiInput.shift(); | |||||
processMessage(msg); | processMessage(msg); | ||||
} | } | ||||
@@ -73,7 +73,7 @@ struct MIDI_CC : Module { | |||||
} | } | ||||
} | } | ||||
void processMessage(midi::Message msg) { | |||||
void processMessage(const midi::Message &msg) { | |||||
switch (msg.getStatus()) { | switch (msg.getStatus()) { | ||||
// cc | // cc | ||||
case 0xb: { | 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(); | uint8_t cc = msg.getNote(); | ||||
if (msg.bytes.size() < 2) | |||||
return; | |||||
// Allow CC to be negative if the 8th bit is set. | // Allow CC to be negative if the 8th bit is set. | ||||
// The gamepad driver abuses this, for example. | // The gamepad driver abuses this, for example. | ||||
// Cast uint8_t to int8_t | // Cast uint8_t to int8_t | ||||
@@ -119,8 +119,8 @@ struct MIDI_CV : Module { | |||||
} | } | ||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
midi::Message msg; | |||||
while (midiInput.shift(&msg)) { | |||||
while (!midiInput.empty()) { | |||||
midi::Message msg = midiInput.shift(); | |||||
processMessage(msg); | processMessage(msg); | ||||
} | } | ||||
@@ -159,7 +159,7 @@ struct MIDI_CV : Module { | |||||
outputs[CONTINUE_OUTPUT].setVoltage(continuePulse.process(args.sampleTime) ? 10.f : 0.f); | 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()); | // DEBUG("MIDI: %01x %01x %02x %02x", msg.getStatus(), msg.getChannel(), msg.getNote(), msg.getValue()); | ||||
switch (msg.getStatus()) { | 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()) { | switch (msg.getNote()) { | ||||
// mod | // mod | ||||
case 0x01: { | case 0x01: { | ||||
@@ -235,7 +235,7 @@ struct MIDI_CV : Module { | |||||
} | } | ||||
} | } | ||||
void processSystem(midi::Message msg) { | |||||
void processSystem(const midi::Message &msg) { | |||||
switch (msg.getChannel()) { | switch (msg.getChannel()) { | ||||
// Timing | // Timing | ||||
case 0x8: { | case 0x8: { | ||||
@@ -55,8 +55,8 @@ struct MIDI_Gate : Module { | |||||
} | } | ||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
midi::Message msg; | |||||
while (midiInput.shift(&msg)) { | |||||
while (!midiInput.empty()) { | |||||
midi::Message msg = midiInput.shift(); | |||||
processMessage(msg); | processMessage(msg); | ||||
} | } | ||||
@@ -75,7 +75,7 @@ struct MIDI_Gate : Module { | |||||
} | } | ||||
} | } | ||||
void processMessage(midi::Message msg) { | |||||
void processMessage(const midi::Message &msg) { | |||||
switch (msg.getStatus()) { | switch (msg.getStatus()) { | ||||
// note off | // note off | ||||
case 0x8: { | case 0x8: { | ||||
@@ -78,8 +78,8 @@ struct MIDI_Map : Module { | |||||
void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
if (divider.process()) { | if (divider.process()) { | ||||
midi::Message msg; | |||||
while (midiInput.shift(&msg)) { | |||||
while (!midiInput.empty()) { | |||||
midi::Message msg = midiInput.shift(); | |||||
processMessage(msg); | 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()); | // DEBUG("MIDI: %01x %01x %02x %02x", msg.getStatus(), msg.getChannel(), msg.getNote(), msg.getValue()); | ||||
switch (msg.getStatus()) { | 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(); | uint8_t cc = msg.getNote(); | ||||
int8_t value = msg.getValue(); | int8_t value = msg.getValue(); | ||||
// Learn | // Learn | ||||
@@ -51,7 +51,7 @@ struct InputDevice : midi::InputDevice { | |||||
midi::Message msg; | midi::Message msg; | ||||
msg.setStatus(0xb); | msg.setStatus(0xb); | ||||
msg.setNote(i); | msg.setNote(i); | ||||
// Allow 8th bit to be set | |||||
// Allow 8th bit to be set to allow bipolar value hack. | |||||
msg.bytes[2] = cc; | msg.bytes[2] = cc; | ||||
onMessage(msg); | onMessage(msg); | ||||
} | } | ||||
@@ -25,7 +25,7 @@ void InputDevice::unsubscribe(Input* input) { | |||||
subscribed.erase(it); | subscribed.erase(it); | ||||
} | } | ||||
void InputDevice::onMessage(Message message) { | |||||
void InputDevice::onMessage(const Message &message) { | |||||
for (Input* input : subscribed) { | for (Input* input : subscribed) { | ||||
// Filter channel | // Filter channel | ||||
if (input->channel < 0 || message.getStatus() == 0xf || message.getChannel() == input->channel) { | if (input->channel < 0 || message.getStatus() == 0xf || message.getChannel() == input->channel) { | ||||
@@ -163,21 +163,21 @@ std::vector<int> Input::getChannels() { | |||||
return channels; | return channels; | ||||
} | } | ||||
void InputQueue::onMessage(Message message) { | |||||
void InputQueue::onMessage(const Message &message) { | |||||
if ((int) queue.size() >= queueMaxSize) | |||||
return; | |||||
// Push to queue | // 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; | return channels; | ||||
} | } | ||||
void Output::sendMessage(Message message) { | |||||
void Output::sendMessage(const Message &message) { | |||||
if (!outputDevice) | if (!outputDevice) | ||||
return; | return; | ||||
// Set channel | // 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) | if (!midiInputDevice) | ||||
return; | 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; | 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); | midiInputDevice->onMessage(msg); | ||||
} | } | ||||
}; | }; | ||||
@@ -79,8 +72,9 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||||
return name; | 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); | |||||
} | } | ||||
}; | }; | ||||