Browse Source

Make midi::Message a wrapper for std::vector<uint8_t> since MIDI messages have unbounded size (due to SysEx).

tags/v2.0.0
Andrew Belt 5 years ago
parent
commit
c713cfb864
10 changed files with 86 additions and 65 deletions
  1. +1
    -1
      include/dsp/midi.hpp
  2. +42
    -18
      include/midi.hpp
  3. +1
    -1
      src/core/CV_MIDI.cpp
  4. +6
    -4
      src/core/MIDI_CC.cpp
  5. +5
    -5
      src/core/MIDI_CV.cpp
  6. +3
    -3
      src/core/MIDI_Gate.cpp
  7. +4
    -4
      src/core/MIDI_Map.cpp
  8. +1
    -1
      src/gamepad.cpp
  9. +19
    -18
      src/midi.cpp
  10. +4
    -10
      src/rtmidi.cpp

+ 1
- 1
include/dsp/midi.hpp View File

@@ -212,7 +212,7 @@ struct MidiGenerator {
} }
} }


virtual void onMessage(midi::Message message) {}
virtual void onMessage(const midi::Message &message) {}
}; };






+ 42
- 18
include/midi.hpp View File

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






+ 1
- 1
src/core/CV_MIDI.cpp View File

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




+ 6
- 4
src/core/MIDI_CC.cpp View File

@@ -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


+ 5
- 5
src/core/MIDI_CV.cpp View File

@@ -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: {


+ 3
- 3
src/core/MIDI_Gate.cpp View File

@@ -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: {


+ 4
- 4
src/core/MIDI_Map.cpp View File

@@ -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


+ 1
- 1
src/gamepad.cpp View File

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


+ 19
- 18
src/midi.cpp View File

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






+ 4
- 10
src/rtmidi.cpp View File

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




Loading…
Cancel
Save