implemented parser for incoming messages

This commit is contained in:
lathoub 2018-11-11 08:49:56 -05:00
parent e91e4209b1
commit 26c4973e12
2 changed files with 502 additions and 457 deletions

View File

@ -132,9 +132,9 @@ public:
inline void read() inline void read()
{ {
// n/a, data comes in async (see onWrite callbacks)
} }
inline void sendMIDI(StatusByte, DataByte data1 = 0, DataByte data2 = 0);
inline void receive(uint8_t *buffer, uint8_t bufferSize); inline void receive(uint8_t *buffer, uint8_t bufferSize);
void onConnected(void(*fptr)()) { void onConnected(void(*fptr)()) {
@ -219,6 +219,39 @@ bool BleMidiInterface::begin(const char* deviceName)
return true; return true;
} }
void BleMidiInterface::sendMIDI(StatusByte status, DataByte data1, DataByte data2)
{
MidiType type = getTypeFromStatusByte(status);
Channel channel = getChannelFromStatusByte(status);
switch (type) {
case NoteOff:
if (_noteOffCallback) _noteOffCallback(channel, data1, data2);
break;
case NoteOn:
if (_noteOnCallback) _noteOnCallback(channel, data1, data2);
break;
case AfterTouchPoly:
if (_afterTouchPolyCallback) _afterTouchPolyCallback(channel, data1, data2);
break;
case ControlChange:
if (_controlChangeCallback) _controlChangeCallback(channel, data1, data2);
break;
case ProgramChange:
if (_programChangeCallback) _programChangeCallback(channel, data1);
break;
case AfterTouchChannel:
if (_afterTouchChannelCallback) _afterTouchChannelCallback(channel, data1);
break;
case PitchBend:
if (_pitchBendCallback) {
int value = (int) ((data1 & 0x7f) | ((data2 & 0x7f) << 7)) + MIDI_PITCHBEND_MIN;
_pitchBendCallback(channel, value);
}
break;
}
}
void BleMidiInterface::receive(uint8_t *buffer, uint8_t bufferSize) void BleMidiInterface::receive(uint8_t *buffer, uint8_t bufferSize)
{ {
/* /*
@ -251,26 +284,24 @@ void BleMidiInterface::receive(uint8_t *buffer, uint8_t bufferSize)
MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved
from other messages except for System Exclusive messages. from other messages except for System Exclusive messages.
*/ */
Channel channel;
MidiType command;
//Pointers used to search through payload. //Pointers used to search through payload.
uint8_t lPtr = 0; uint8_t lPtr = 0;
uint8_t rPtr = 0; uint8_t rPtr = 0;
//lastStatus used to capture runningStatus
uint8_t lastStatus;
//Decode first packet -- SHALL be "Full MIDI message" //Decode first packet -- SHALL be "Full MIDI message"
lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status" lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status"
//While statement contains incrementing pointers and breaks when buffer size exceeded. //While statement contains incrementing pointers and breaks when buffer size exceeded.
while(1){ while(1){
//lastStatus used to capture runningStatus lastStatus = buffer[lPtr];
auto lastStatus = buffer[lPtr];
if( (buffer[lPtr] < 0x80) ){ if( (buffer[lPtr] < 0x80) ){
//Status message not present, bail //Status message not present, bail
return; return;
} }
command = getTypeFromStatusByte(lastStatus);
channel = getChannelFromStatusByte(lastStatus);
//Point to next non-data byte //Point to next non-data byte
rPtr = lPtr; rPtr = lPtr;
while( (buffer[rPtr + 1] < 0x80)&&(rPtr < (bufferSize - 1)) ){ while( (buffer[rPtr + 1] < 0x80)&&(rPtr < (bufferSize - 1)) ){
@ -279,36 +310,28 @@ void BleMidiInterface::receive(uint8_t *buffer, uint8_t bufferSize)
//look at l and r pointers and decode by size. //look at l and r pointers and decode by size.
if( rPtr - lPtr < 1 ){ if( rPtr - lPtr < 1 ){
//Time code or system //Time code or system
// MIDI.send(command, 0, 0, channel); sendMIDI(lastStatus);
} else if( rPtr - lPtr < 2 ) { } else if( rPtr - lPtr < 2 ) {
// MIDI.send(command, buffer[lPtr + 1], 0, channel); sendMIDI(lastStatus, buffer[lPtr + 1]);
} else if( rPtr - lPtr < 3 ) { } else if( rPtr - lPtr < 3 ) {
sendMIDI(lastStatus, buffer[lPtr + 1], buffer[lPtr + 2]);
// TODO: switch for type
if (_noteOnCallback) // if an attached function exisist, call it here
_noteOnCallback(0, 1, 2);
// MIDI.send(command, buffer[lPtr + 1], buffer[lPtr + 2], channel);
} else { } else {
//Too much data //Too much data
//If not System Common or System Real-Time, send it as running status //If not System Common or System Real-Time, send it as running status
switch( buffer[lPtr] & 0xF0 ) switch( buffer[lPtr] & 0xF0 )
{ {
case 0x80: case NoteOff:
case 0x90: case NoteOn:
case 0xA0: case AfterTouchPoly:
case 0xB0: case ControlChange:
case 0xE0: case PitchBend:
for (int i = lPtr; i < rPtr; i = i + 2) { for(int i = lPtr; i < rPtr; i = i + 2)
// MIDI.send(command, buffer[i + 1], buffer[i + 2], channel); sendMIDI(lastStatus, buffer[i + 1], buffer[i + 2]);
}
break; break;
case 0xC0: case ProgramChange:
case 0xD0: case AfterTouchChannel:
for (int i = lPtr; i < rPtr; i = i + 1) { for(int i = lPtr; i < rPtr; i = i + 1)
// MIDI.send(command, buffer[i + 1], 0, channel); sendMIDI(lastStatus, buffer[i + 1]);
}
break; break;
default: default:
break; break;
@ -321,6 +344,7 @@ if (_noteOnCallback) // if an attached function exisist, call it here
return; return;
} }
} }
} }
END_BLEMIDI_NAMESPACE END_BLEMIDI_NAMESPACE

View File

@ -277,24 +277,24 @@ protected:
public: public:
// sending // sending
void sendNoteOn(DataByte note, DataByte velocity, Channel channel) { void sendNoteOn(DataByte note, DataByte velocity, Channel channel) {
send(MidiType::NoteOn, channel, note, velocity); sendChannelMessage(MidiType::NoteOn, channel, note, velocity);
} }
void sendNoteOff(DataByte note, DataByte velocity, Channel channel) { void sendNoteOff(DataByte note, DataByte velocity, Channel channel) {
send(MidiType::NoteOff, channel, note, velocity); sendChannelMessage(MidiType::NoteOff, channel, note, velocity);
} }
void sendProgramChange(DataByte number, Channel channel) { void sendProgramChange(DataByte number, Channel channel) {
send(MidiType::ProgramChange, number, 0, channel); sendChannelMessage(MidiType::ProgramChange, number, 0, channel);
} }
void sendControlChange(DataByte number, DataByte value, Channel channel) { void sendControlChange(DataByte number, DataByte value, Channel channel) {
send(MidiType::ControlChange, number, value, channel); sendChannelMessage(MidiType::ControlChange, number, value, channel);
} }
void sendPitchBend(int value, Channel channel) { void sendPitchBend(int value, Channel channel) {
const unsigned bend = unsigned(value - int(MIDI_PITCHBEND_MIN)); const unsigned bend = unsigned(value - int(MIDI_PITCHBEND_MIN));
send(MidiType::PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, channel); sendChannelMessage(MidiType::PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, channel);
} }
void sendPitchBend(double pitchValue, Channel channel) { void sendPitchBend(double pitchValue, Channel channel) {
@ -304,15 +304,15 @@ public:
} }
void sendPolyPressure(DataByte note, DataByte pressure, Channel channel) { void sendPolyPressure(DataByte note, DataByte pressure, Channel channel) {
send(MidiType::AfterTouchPoly, note, pressure, channel); sendChannelMessage(MidiType::AfterTouchPoly, note, pressure, channel);
} }
void sendAfterTouch(DataByte pressure, Channel channel) { void sendAfterTouch(DataByte pressure, Channel channel) {
send(MidiType::AfterTouchChannel, pressure, 0, channel); sendChannelMessage(MidiType::AfterTouchChannel, pressure, 0, channel);
} }
void sendAfterTouch(DataByte note, DataByte pressure, Channel channel) { void sendAfterTouch(DataByte note, DataByte pressure, Channel channel) {
send(MidiType::AfterTouchChannel, note, pressure, channel); sendChannelMessage(MidiType::AfterTouchChannel, note, pressure, channel);
} }
@ -322,62 +322,66 @@ public:
void sendTimeCodeQuarterFrame(DataByte typeNibble, DataByte valuesNibble) { void sendTimeCodeQuarterFrame(DataByte typeNibble, DataByte valuesNibble) {
// TODO f(typeNibble, valuesNibble); const byte data = byte((((typeNibble & 0x07) << 4) | (valuesNibble & 0x0f)));
send(MidiType::TimeCodeQuarterFrame); sendTimeCodeQuarterFrame(data);
} }
void sendTimeCodeQuarterFrame(DataByte data) { void sendTimeCodeQuarterFrame(DataByte data) {
send(MidiType::TimeCodeQuarterFrame, data); sendSystemCommonMessage(MidiType::TimeCodeQuarterFrame, data);
} }
void sendSongPosition(unsigned short beats) { void sendSongPosition(unsigned short beats) {
send(MidiType::SongPosition, beats); byte data1 = beats & 0x7f;
byte data2 = (beats >> 7) & 0x7f;
sendSystemCommonMessage(MidiType::SongPosition, data1, data2);
} }
void sendSongSelect(DataByte number) { void sendSongSelect(DataByte number) {
send(MidiType::SongSelect, number); sendSystemCommonMessage(MidiType::SongSelect, number & 0x7f);
} }
void sendTuneRequest() { void sendTuneRequest() {
send(MidiType::TuneRequest); sendSystemCommonMessage(MidiType::TuneRequest);
} }
void sendActiveSensing() { void sendActiveSensing() {
send(MidiType::ActiveSensing); sendSystemCommonMessage(MidiType::ActiveSensing);
} }
void sendStart() { void sendStart() {
send(MidiType::Start); sendRealTimeMessage(MidiType::Start);
} }
void sendContinue() { void sendContinue() {
send(MidiType::Continue); sendRealTimeMessage(MidiType::Continue);
} }
void sendStop() { void sendStop() {
send(MidiType::Stop); sendRealTimeMessage(MidiType::Stop);
} }
void sendClock() { void sendClock() {
send(MidiType::Clock); sendRealTimeMessage(MidiType::Clock);
} }
void sendTick() { void sendTick() {
send(MidiType::Tick); sendRealTimeMessage(MidiType::Tick);
} }
void sendReset() { void sendReset() {
send(MidiType::SystemReset); sendRealTimeMessage(MidiType::SystemReset);
} }
//receiving //receiving
void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) {
_noteOnCallback = fptr;
}
void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) {
_noteOffCallback = fptr; _noteOffCallback = fptr;
} }
void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) {
_noteOnCallback = fptr;
}
void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { void setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) {
_afterTouchPolyCallback = fptr; _afterTouchPolyCallback = fptr;
} }
@ -428,8 +432,9 @@ public:
} }
protected: protected:
// Channel messages // Channel messages
virtual void send(MidiType type, DataByte data1, DataByte data2, Channel channel) virtual void sendChannelMessage(MidiType type, DataByte data1, DataByte data2, Channel channel)
{ {
// Then test if channel is valid // Then test if channel is valid
if (channel >= MIDI_CHANNEL_OFF || if (channel >= MIDI_CHANNEL_OFF ||
@ -460,27 +465,42 @@ protected:
} }
else if (type >= MidiType::Clock && type <= MidiType::SystemReset) else if (type >= MidiType::Clock && type <= MidiType::SystemReset)
{ {
send(type); // System Real-time and 1 byte. sendRealTimeMessage(type); // System Real-time and 1 byte.
} }
} }
// SystemCommon message // SystemCommon message
virtual void send(MidiType type, DataByte data1) virtual void sendSystemCommonMessage(MidiType type, DataByte data1 = 0, DataByte data2 = 0)
{ {
} }
// realTime messages // RealTime messages
virtual void send(MidiType type) virtual void sendRealTimeMessage(MidiType type)
{ {
// Do not invalidate Running Status for real-time messages
// as they can be interleaved within any message.
switch (type)
{
case Clock:
case Start:
case Stop:
case Continue:
case ActiveSensing:
case SystemReset:
serialize(type);
break;
default:
// Invalid Real Time marker
break;
}
} }
virtual bool begin(const char*) = 0; virtual bool begin(const char*) = 0;
virtual void read() = 0;
// serialize from the hardware // serialize from the hardware
virtual void read() = 0;
// serialize towards to hardware // serialize towards to hardware
virtual void serialize(DataByte) = 0; virtual void serialize(DataByte) = 0;
@ -491,3 +511,4 @@ protected:
}; };
} }