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




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

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



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

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


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

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


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

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


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

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


+ 1
- 1
src/gamepad.cpp View File

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


+ 19
- 18
src/midi.cpp View File

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




+ 4
- 10
src/rtmidi.cpp View File

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



Loading…
Cancel
Save