@@ -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); | |||
} | |||
}; | |||