Control Surface main
MIDI Control Surface library for Arduino
Loading...
Searching...
No Matches
BLEMIDIParser.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <Settings/NamespaceSettings.hpp>
4#include <stddef.h>
5#include <stdint.h>
6
8
17 public:
18 BLEMIDIParser(const uint8_t *data, size_t length)
19 : data(data), end(data + length) {
20 // Need at least two bytes to be useful.
21 // Usually, we have header, timestamp and at least one MIDI byte,
22 // but a SysEx continuation could perhaps have only a header and a
23 // single data byte (this is not explicitly allowed by the spec, but
24 // handling this case requires no extra effort)
25 if (length < 2) {
26 this->data = end;
27 }
28 // First byte should be a header. If it's a data byte, discard packet.
29 else if (isData(data[0])) {
30 this->data = end;
31 }
32 // If the second byte is a data byte, this is a SysEx continuation
33 // packet
34 else if (isData(data[1])) {
35 this->timestamp = data[0] & 0x7F;
36 this->timestamp <<= 7;
37 this->data += 1;
38 }
39 // Otherwise, the second byte is a timestamp, so skip it
40 else {
41 this->timestamp = data[0] & 0x7F;
42 this->timestamp <<= 7;
43 this->timestamp |= data[1] & 0x7F;
44 this->data += 2;
45 }
46 }
47
53 void extend(const uint8_t *data, size_t length) {
54 this->data = data;
55 this->end = data + length;
56 }
57
60 bool pull(uint8_t &output) {
61 while (data != end) {
62 // Simply pass on all normal data bytes to the MIDI parser.
63 if (isData(*data)) {
64 output = *data++;
65 prevWasTimestamp = false;
66 return true;
67 }
68 // If it's not a data byte, it's either a timestamp byte or a
69 // MIDI status byte.
70 else {
71 // Timestamp bytes and MIDI status bytes should alternate.
73 // If the previous non-data byte was a timestamp, this one is
74 // a MIDI status byte, so send it to the MIDI parser.
75 if (!prevWasTimestamp) {
76 output = *data++;
77 return true;
78 }
79 // Otherwise it's a time stamp
80 else {
81 uint16_t timestampLow = *data++ & 0x7F;
82 // The BLE MIDI spec has the following to say about overflow:
83 // > Should the timestamp value of a subsequent MIDI message
84 // > in the same packet overflow/wrap (i.e., the
85 // > timestampLow is smaller than a preceding timestampLow),
86 // > the receiver is responsible for tracking this by
87 // > incrementing the timestampHigh by one (the incremented
88 // > value is not transmitted, only understood as a result
89 // > of the overflow condition).
90 if (timestampLow < (timestamp & 0x7F)) // overflow
91 timestamp += 0x80;
92 timestamp = (timestamp & 0x3F80) | timestampLow;
93 }
94 }
95 }
96 return false;
97 }
98
99 uint16_t getTimestamp() const { return timestamp; }
100
101 private:
102 const uint8_t *data;
103 const uint8_t *end;
104 bool prevWasTimestamp = true;
105 uint16_t timestamp = 0;
106
107 private:
110 static bool isData(uint8_t data) { return (data & (1 << 7)) == 0; }
111};
112
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Class for parsing BLE-MIDI packets.
const uint8_t * end
void extend(const uint8_t *data, size_t length)
Extend the BLE packet with the given buffer.
static bool isData(uint8_t data)
Check if the given byte is a data byte (and not a header, timestamp or status byte).
bool pull(uint8_t &output)
Get the next MIDI byte from the BLE packet (if available).
const uint8_t * data
BLEMIDIParser(const uint8_t *data, size_t length)
uint16_t getTimestamp() const