This program enables a RedBearlab nRF51822 to be used as a "bridge device" with full bi-directional communication between MIDI through standard MIDI cables and BLE-MIDI. MIDI cables are connected to the UART. This allows for example to send MIDI data to synthesizers directly from a computer or a tablet via BLE-MIDI and vice-versa, "wires-free" . The Midi Manufacturers Association BLE-MIDI Specification is used. This project is inspired by Matthias Frick's "blidino" project which implements a USB-MIDI to BLE-MIDI bridge with the nRF51822 and is available at https://github.com/sieren/blidino. I owe to him all the BLE-MIDI to MIDI parsing part.

Dependencies:   BLE_API BufferedSerial mbed nRF51822

/media/uploads/popcornell/wp_20160713_22_30_15_rich.jpg

Video

Committer:
popcornell
Date:
Tue Aug 09 12:57:23 2016 +0000
Revision:
0:244f1d0a3810
first

Who changed what in which revision?

UserRevisionLine numberNew contents of line
popcornell 0:244f1d0a3810 1 /*
popcornell 0:244f1d0a3810 2 * Original work Copyright (c) 2015 Francois Best
popcornell 0:244f1d0a3810 3 *
popcornell 0:244f1d0a3810 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
popcornell 0:244f1d0a3810 5 * of this software and associated documentation files (the "Software"), to deal
popcornell 0:244f1d0a3810 6 * in the Software without restriction, including without limitation the rights
popcornell 0:244f1d0a3810 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
popcornell 0:244f1d0a3810 8 * copies of the Software, and to permit persons to whom the Software is
popcornell 0:244f1d0a3810 9 * furnished to do so, subject to the following conditions:
popcornell 0:244f1d0a3810 10 *
popcornell 0:244f1d0a3810 11 * The above copyright notice and this permission notice shall be included in all
popcornell 0:244f1d0a3810 12 * copies or substantial portions of the Software.
popcornell 0:244f1d0a3810 13 *
popcornell 0:244f1d0a3810 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
popcornell 0:244f1d0a3810 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
popcornell 0:244f1d0a3810 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
popcornell 0:244f1d0a3810 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
popcornell 0:244f1d0a3810 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
popcornell 0:244f1d0a3810 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
popcornell 0:244f1d0a3810 20 * SOFTWARE.
popcornell 0:244f1d0a3810 21 *
popcornell 0:244f1d0a3810 22 */
popcornell 0:244f1d0a3810 23
popcornell 0:244f1d0a3810 24
popcornell 0:244f1d0a3810 25 /*
popcornell 0:244f1d0a3810 26 * Modified work by Samuele Cornell.
popcornell 0:244f1d0a3810 27 * The following code is adapted from Francois Best's Arduino MIDI Library v4.2
popcornell 0:244f1d0a3810 28 * (see https://github.com/FortySevenEffects/arduino_midi_library)
popcornell 0:244f1d0a3810 29 */
popcornell 0:244f1d0a3810 30
popcornell 0:244f1d0a3810 31
popcornell 0:244f1d0a3810 32
popcornell 0:244f1d0a3810 33 namespace MIDI {
popcornell 0:244f1d0a3810 34
popcornell 0:244f1d0a3810 35 #define SysExMaxSize 128
popcornell 0:244f1d0a3810 36 #define Use1ByteParsing 0
popcornell 0:244f1d0a3810 37
popcornell 0:244f1d0a3810 38 typedef uint8_t byte ; // byte isn't defined in mbed OS
popcornell 0:244f1d0a3810 39
popcornell 0:244f1d0a3810 40 typedef uint8_t StatusByte;
popcornell 0:244f1d0a3810 41 typedef uint8_t DataByte;
popcornell 0:244f1d0a3810 42 typedef uint8_t Channel;
popcornell 0:244f1d0a3810 43
popcornell 0:244f1d0a3810 44
popcornell 0:244f1d0a3810 45
popcornell 0:244f1d0a3810 46 /*! Enumeration of MIDI types */
popcornell 0:244f1d0a3810 47 enum MidiType
popcornell 0:244f1d0a3810 48 {
popcornell 0:244f1d0a3810 49 InvalidType = 0x00, ///< For notifying errors
popcornell 0:244f1d0a3810 50 NoteOff = 0x80, ///< Note Off
popcornell 0:244f1d0a3810 51 NoteOn = 0x90, ///< Note On
popcornell 0:244f1d0a3810 52 AfterTouchPoly = 0xA0, ///< Polyphonic AfterTouch
popcornell 0:244f1d0a3810 53 ControlChange = 0xB0, ///< Control Change / Channel Mode
popcornell 0:244f1d0a3810 54 ProgramChange = 0xC0, ///< Program Change
popcornell 0:244f1d0a3810 55 AfterTouchChannel = 0xD0, ///< Channel (monophonic) AfterTouch
popcornell 0:244f1d0a3810 56 PitchBend = 0xE0, ///< Pitch Bend
popcornell 0:244f1d0a3810 57 SystemExclusive = 0xF0, ///< System Exclusive
popcornell 0:244f1d0a3810 58 TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
popcornell 0:244f1d0a3810 59 SongPosition = 0xF2, ///< System Common - Song Position Pointer
popcornell 0:244f1d0a3810 60 SongSelect = 0xF3, ///< System Common - Song Select
popcornell 0:244f1d0a3810 61 TuneRequest = 0xF6, ///< System Common - Tune Request
popcornell 0:244f1d0a3810 62 Clock = 0xF8, ///< System Real Time - Timing Clock
popcornell 0:244f1d0a3810 63 Start = 0xFA, ///< System Real Time - Start
popcornell 0:244f1d0a3810 64 Continue = 0xFB, ///< System Real Time - Continue
popcornell 0:244f1d0a3810 65 Stop = 0xFC, ///< System Real Time - Stop
popcornell 0:244f1d0a3810 66 ActiveSensing = 0xFE, ///< System Real Time - Active Sensing
popcornell 0:244f1d0a3810 67 SystemReset = 0xFF, ///< System Real Time - System Reset
popcornell 0:244f1d0a3810 68 };
popcornell 0:244f1d0a3810 69
popcornell 0:244f1d0a3810 70
popcornell 0:244f1d0a3810 71 struct MidiMessage
popcornell 0:244f1d0a3810 72 {
popcornell 0:244f1d0a3810 73 /*! The maximum size for the System Exclusive array.
popcornell 0:244f1d0a3810 74 */
popcornell 0:244f1d0a3810 75 static const unsigned sSysExMaxSize = SysExMaxSize; // this
popcornell 0:244f1d0a3810 76
popcornell 0:244f1d0a3810 77 /*! The MIDI channel on which the message was recieved.
popcornell 0:244f1d0a3810 78 \n Value goes from 1 to 16.
popcornell 0:244f1d0a3810 79 */
popcornell 0:244f1d0a3810 80 Channel channel;
popcornell 0:244f1d0a3810 81
popcornell 0:244f1d0a3810 82 /*! The type of the message
popcornell 0:244f1d0a3810 83 (see the MidiType enum for types reference)
popcornell 0:244f1d0a3810 84 */
popcornell 0:244f1d0a3810 85 MidiType type;
popcornell 0:244f1d0a3810 86
popcornell 0:244f1d0a3810 87 /*! The first data byte.
popcornell 0:244f1d0a3810 88 \n Value goes from 0 to 127.
popcornell 0:244f1d0a3810 89 */
popcornell 0:244f1d0a3810 90 DataByte data1;
popcornell 0:244f1d0a3810 91
popcornell 0:244f1d0a3810 92 /*! The second data byte.
popcornell 0:244f1d0a3810 93 If the message is only 2 bytes long, this one is null.
popcornell 0:244f1d0a3810 94 \n Value goes from 0 to 127.
popcornell 0:244f1d0a3810 95 */
popcornell 0:244f1d0a3810 96 DataByte data2;
popcornell 0:244f1d0a3810 97
popcornell 0:244f1d0a3810 98 /*! System Exclusive dedicated byte array.
popcornell 0:244f1d0a3810 99 \n Array length is stocked on 16 bits,
popcornell 0:244f1d0a3810 100 in data1 (LSB) and data2 (MSB)
popcornell 0:244f1d0a3810 101 */
popcornell 0:244f1d0a3810 102 DataByte sysexArray[sSysExMaxSize];
popcornell 0:244f1d0a3810 103
popcornell 0:244f1d0a3810 104 /*! This boolean indicates if the message is valid or not.
popcornell 0:244f1d0a3810 105 There is no channel consideration here,
popcornell 0:244f1d0a3810 106 validity means the message respects the MIDI norm.
popcornell 0:244f1d0a3810 107 */
popcornell 0:244f1d0a3810 108 bool valid;
popcornell 0:244f1d0a3810 109
popcornell 0:244f1d0a3810 110 inline unsigned getSysExSize() const
popcornell 0:244f1d0a3810 111 {
popcornell 0:244f1d0a3810 112 const unsigned size = unsigned(data2) << 8 | data1;
popcornell 0:244f1d0a3810 113 return size > sSysExMaxSize ? sSysExMaxSize : size;
popcornell 0:244f1d0a3810 114 }
popcornell 0:244f1d0a3810 115
popcornell 0:244f1d0a3810 116 MidiMessage() { // initialize
popcornell 0:244f1d0a3810 117
popcornell 0:244f1d0a3810 118 channel=0;
popcornell 0:244f1d0a3810 119 type= InvalidType ;
popcornell 0:244f1d0a3810 120 data1= 0 ;
popcornell 0:244f1d0a3810 121 data2= 0 ;
popcornell 0:244f1d0a3810 122 valid =false ;
popcornell 0:244f1d0a3810 123 }
popcornell 0:244f1d0a3810 124
popcornell 0:244f1d0a3810 125
popcornell 0:244f1d0a3810 126 };
popcornell 0:244f1d0a3810 127
popcornell 0:244f1d0a3810 128
popcornell 0:244f1d0a3810 129 StatusByte mRunningStatus_RX;
popcornell 0:244f1d0a3810 130 StatusByte mRunningStatus_TX;
popcornell 0:244f1d0a3810 131 Channel mInputChannel= 1 ; // default 1
popcornell 0:244f1d0a3810 132 uint8_t mPendingMessage[3];
popcornell 0:244f1d0a3810 133 uint8_t mPendingMessageExpectedLenght = 0;
popcornell 0:244f1d0a3810 134 uint8_t mPendingMessageIndex= 0;
popcornell 0:244f1d0a3810 135
popcornell 0:244f1d0a3810 136
popcornell 0:244f1d0a3810 137
popcornell 0:244f1d0a3810 138 MidiMessage mMessage;
popcornell 0:244f1d0a3810 139
popcornell 0:244f1d0a3810 140
popcornell 0:244f1d0a3810 141
popcornell 0:244f1d0a3810 142 inline void resetInput()
popcornell 0:244f1d0a3810 143 {
popcornell 0:244f1d0a3810 144 mPendingMessageIndex = 0;
popcornell 0:244f1d0a3810 145 mPendingMessageExpectedLenght = 0;
popcornell 0:244f1d0a3810 146 mRunningStatus_RX = InvalidType;
popcornell 0:244f1d0a3810 147 }
popcornell 0:244f1d0a3810 148
popcornell 0:244f1d0a3810 149 MidiType getTypeFromStatusByte(uint8_t inStatus)
popcornell 0:244f1d0a3810 150 {
popcornell 0:244f1d0a3810 151 if ((inStatus < 0x80) ||
popcornell 0:244f1d0a3810 152 (inStatus == 0xf4) ||
popcornell 0:244f1d0a3810 153 (inStatus == 0xf5) ||
popcornell 0:244f1d0a3810 154 (inStatus == 0xf9) ||
popcornell 0:244f1d0a3810 155 (inStatus == 0xfD))
popcornell 0:244f1d0a3810 156 {
popcornell 0:244f1d0a3810 157 // Data bytes and undefined.
popcornell 0:244f1d0a3810 158 return InvalidType;
popcornell 0:244f1d0a3810 159 }
popcornell 0:244f1d0a3810 160 if (inStatus < 0xf0)
popcornell 0:244f1d0a3810 161 {
popcornell 0:244f1d0a3810 162 // Channel message, remove channel nibble.
popcornell 0:244f1d0a3810 163 return MidiType(inStatus & 0xf0);
popcornell 0:244f1d0a3810 164 }
popcornell 0:244f1d0a3810 165
popcornell 0:244f1d0a3810 166 return MidiType(inStatus);
popcornell 0:244f1d0a3810 167 }
popcornell 0:244f1d0a3810 168
popcornell 0:244f1d0a3810 169 /*! \brief Returns channel in the range 1-16
popcornell 0:244f1d0a3810 170 */
popcornell 0:244f1d0a3810 171
popcornell 0:244f1d0a3810 172 inline Channel getChannelFromStatusByte(uint8_t inStatus)
popcornell 0:244f1d0a3810 173 {
popcornell 0:244f1d0a3810 174 return (inStatus & 0x0f) + 1;
popcornell 0:244f1d0a3810 175 }
popcornell 0:244f1d0a3810 176
popcornell 0:244f1d0a3810 177
popcornell 0:244f1d0a3810 178 bool isChannelMessage(MidiType inType)
popcornell 0:244f1d0a3810 179 {
popcornell 0:244f1d0a3810 180 return (inType == NoteOff ||
popcornell 0:244f1d0a3810 181 inType == NoteOn ||
popcornell 0:244f1d0a3810 182 inType == ControlChange ||
popcornell 0:244f1d0a3810 183 inType == AfterTouchPoly ||
popcornell 0:244f1d0a3810 184 inType == AfterTouchChannel ||
popcornell 0:244f1d0a3810 185 inType == PitchBend ||
popcornell 0:244f1d0a3810 186 inType == ProgramChange);
popcornell 0:244f1d0a3810 187 }
popcornell 0:244f1d0a3810 188
popcornell 0:244f1d0a3810 189
popcornell 0:244f1d0a3810 190
popcornell 0:244f1d0a3810 191 bool MIDI_to_BLEMIDI_Parser (void ) {
popcornell 0:244f1d0a3810 192
popcornell 0:244f1d0a3810 193
popcornell 0:244f1d0a3810 194 if (UART.readable() == 0)
popcornell 0:244f1d0a3810 195 // No data available.
popcornell 0:244f1d0a3810 196 return false;
popcornell 0:244f1d0a3810 197
popcornell 0:244f1d0a3810 198 // Parsing algorithm:
popcornell 0:244f1d0a3810 199 // Get a byte from the serial buffer.
popcornell 0:244f1d0a3810 200 // If there is no pending message to be recomposed, start a new one.
popcornell 0:244f1d0a3810 201 // - Find type and channel (if pertinent)
popcornell 0:244f1d0a3810 202 // - Look for other bytes in buffer, call parser recursively,
popcornell 0:244f1d0a3810 203 // until the message is assembled or the buffer is empty.
popcornell 0:244f1d0a3810 204 // Else, add the extracted byte to the pending message, and check validity.
popcornell 0:244f1d0a3810 205 // When the message is done, store it.
popcornell 0:244f1d0a3810 206
popcornell 0:244f1d0a3810 207 const uint8_t extracted = UART.getc();
popcornell 0:244f1d0a3810 208
popcornell 0:244f1d0a3810 209 if (mPendingMessageIndex == 0)
popcornell 0:244f1d0a3810 210 {
popcornell 0:244f1d0a3810 211 // Start a new pending message
popcornell 0:244f1d0a3810 212 mPendingMessage[0] = extracted;
popcornell 0:244f1d0a3810 213
popcornell 0:244f1d0a3810 214 // Check for running status first
popcornell 0:244f1d0a3810 215 if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX)))
popcornell 0:244f1d0a3810 216 {
popcornell 0:244f1d0a3810 217 // Only these types allow Running Status
popcornell 0:244f1d0a3810 218
popcornell 0:244f1d0a3810 219 // If the status byte is not received, prepend it
popcornell 0:244f1d0a3810 220 // to the pending message
popcornell 0:244f1d0a3810 221 if (extracted < 0x80)
popcornell 0:244f1d0a3810 222 {
popcornell 0:244f1d0a3810 223 mPendingMessage[0] = mRunningStatus_RX;
popcornell 0:244f1d0a3810 224 mPendingMessage[1] = extracted;
popcornell 0:244f1d0a3810 225 mPendingMessageIndex = 1;
popcornell 0:244f1d0a3810 226 }
popcornell 0:244f1d0a3810 227 // Else: well, we received another status byte,
popcornell 0:244f1d0a3810 228 // so the running status does not apply here.
popcornell 0:244f1d0a3810 229 // It will be updated upon completion of this message.
popcornell 0:244f1d0a3810 230 }
popcornell 0:244f1d0a3810 231
popcornell 0:244f1d0a3810 232 switch (getTypeFromStatusByte(mPendingMessage[0]))
popcornell 0:244f1d0a3810 233 {
popcornell 0:244f1d0a3810 234 // 1 byte messages
popcornell 0:244f1d0a3810 235 case Start:
popcornell 0:244f1d0a3810 236 case Continue:
popcornell 0:244f1d0a3810 237 case Stop:
popcornell 0:244f1d0a3810 238 case Clock:
popcornell 0:244f1d0a3810 239 case ActiveSensing:
popcornell 0:244f1d0a3810 240 case SystemReset:
popcornell 0:244f1d0a3810 241 case TuneRequest:
popcornell 0:244f1d0a3810 242
popcornell 0:244f1d0a3810 243 // Handle the message type directly here.
popcornell 0:244f1d0a3810 244 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
popcornell 0:244f1d0a3810 245 mMessage.channel = 0;
popcornell 0:244f1d0a3810 246 mMessage.data1 = 0;
popcornell 0:244f1d0a3810 247 mMessage.data2 = 0;
popcornell 0:244f1d0a3810 248 mMessage.valid = true;
popcornell 0:244f1d0a3810 249
popcornell 0:244f1d0a3810 250 // \fix Running Status broken when receiving Clock messages.
popcornell 0:244f1d0a3810 251 // Do not reset all input attributes, Running Status must remain unchanged.
popcornell 0:244f1d0a3810 252 //resetInput();
popcornell 0:244f1d0a3810 253
popcornell 0:244f1d0a3810 254 // We still need to reset these
popcornell 0:244f1d0a3810 255 mPendingMessageIndex = 0;
popcornell 0:244f1d0a3810 256 mPendingMessageExpectedLenght = 0;
popcornell 0:244f1d0a3810 257
popcornell 0:244f1d0a3810 258 return true;
popcornell 0:244f1d0a3810 259 break;
popcornell 0:244f1d0a3810 260
popcornell 0:244f1d0a3810 261 // 2 bytes messages
popcornell 0:244f1d0a3810 262 case ProgramChange:
popcornell 0:244f1d0a3810 263 case AfterTouchChannel:
popcornell 0:244f1d0a3810 264 case TimeCodeQuarterFrame:
popcornell 0:244f1d0a3810 265 case SongSelect:
popcornell 0:244f1d0a3810 266 mPendingMessageExpectedLenght = 2;
popcornell 0:244f1d0a3810 267 break;
popcornell 0:244f1d0a3810 268
popcornell 0:244f1d0a3810 269 // 3 bytes messages
popcornell 0:244f1d0a3810 270 case NoteOn:
popcornell 0:244f1d0a3810 271 case NoteOff:
popcornell 0:244f1d0a3810 272 case ControlChange:
popcornell 0:244f1d0a3810 273 case PitchBend:
popcornell 0:244f1d0a3810 274 case AfterTouchPoly:
popcornell 0:244f1d0a3810 275 case SongPosition:
popcornell 0:244f1d0a3810 276 mPendingMessageExpectedLenght = 3;
popcornell 0:244f1d0a3810 277 break;
popcornell 0:244f1d0a3810 278
popcornell 0:244f1d0a3810 279 case SystemExclusive:
popcornell 0:244f1d0a3810 280 // The message can be any lenght
popcornell 0:244f1d0a3810 281 // between 3 and MidiMessage::sSysExMaxSize bytes
popcornell 0:244f1d0a3810 282 mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize;
popcornell 0:244f1d0a3810 283 mRunningStatus_RX = InvalidType;
popcornell 0:244f1d0a3810 284 mMessage.sysexArray[0] = SystemExclusive;
popcornell 0:244f1d0a3810 285 break;
popcornell 0:244f1d0a3810 286
popcornell 0:244f1d0a3810 287 case InvalidType:
popcornell 0:244f1d0a3810 288 default:
popcornell 0:244f1d0a3810 289 // This is obviously wrong. Let's get the hell out'a here.
popcornell 0:244f1d0a3810 290 resetInput();
popcornell 0:244f1d0a3810 291 return false;
popcornell 0:244f1d0a3810 292 break;
popcornell 0:244f1d0a3810 293 }
popcornell 0:244f1d0a3810 294
popcornell 0:244f1d0a3810 295 if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
popcornell 0:244f1d0a3810 296 {
popcornell 0:244f1d0a3810 297 // Reception complete
popcornell 0:244f1d0a3810 298 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
popcornell 0:244f1d0a3810 299 mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]);
popcornell 0:244f1d0a3810 300 mMessage.data1 = mPendingMessage[1];
popcornell 0:244f1d0a3810 301
popcornell 0:244f1d0a3810 302 // Save data2 only if applicable
popcornell 0:244f1d0a3810 303 if (mPendingMessageExpectedLenght == 3)
popcornell 0:244f1d0a3810 304 mMessage.data2 = mPendingMessage[2];
popcornell 0:244f1d0a3810 305 else
popcornell 0:244f1d0a3810 306 mMessage.data2 = 0;
popcornell 0:244f1d0a3810 307
popcornell 0:244f1d0a3810 308 mPendingMessageIndex = 0;
popcornell 0:244f1d0a3810 309 mPendingMessageExpectedLenght = 0;
popcornell 0:244f1d0a3810 310 mMessage.valid = true;
popcornell 0:244f1d0a3810 311 return true;
popcornell 0:244f1d0a3810 312 }
popcornell 0:244f1d0a3810 313 else
popcornell 0:244f1d0a3810 314 {
popcornell 0:244f1d0a3810 315 // Waiting for more data
popcornell 0:244f1d0a3810 316 mPendingMessageIndex++;
popcornell 0:244f1d0a3810 317 }
popcornell 0:244f1d0a3810 318
popcornell 0:244f1d0a3810 319 if (Use1ByteParsing==1)
popcornell 0:244f1d0a3810 320 {
popcornell 0:244f1d0a3810 321 // Message is not complete.
popcornell 0:244f1d0a3810 322 return false;
popcornell 0:244f1d0a3810 323 }
popcornell 0:244f1d0a3810 324 else
popcornell 0:244f1d0a3810 325 {
popcornell 0:244f1d0a3810 326 // Call the parser recursively
popcornell 0:244f1d0a3810 327 // to parse the rest of the message.
popcornell 0:244f1d0a3810 328 return MIDI_to_BLEMIDI_Parser();
popcornell 0:244f1d0a3810 329 }
popcornell 0:244f1d0a3810 330 }
popcornell 0:244f1d0a3810 331 else
popcornell 0:244f1d0a3810 332 {
popcornell 0:244f1d0a3810 333 // First, test if this is a status byte
popcornell 0:244f1d0a3810 334 if (extracted >= 0x80)
popcornell 0:244f1d0a3810 335 {
popcornell 0:244f1d0a3810 336 // Reception of status bytes in the middle of an uncompleted message
popcornell 0:244f1d0a3810 337 // are allowed only for interleaved Real Time message or EOX
popcornell 0:244f1d0a3810 338 switch (extracted)
popcornell 0:244f1d0a3810 339 {
popcornell 0:244f1d0a3810 340 case Clock:
popcornell 0:244f1d0a3810 341 case Start:
popcornell 0:244f1d0a3810 342 case Continue:
popcornell 0:244f1d0a3810 343 case Stop:
popcornell 0:244f1d0a3810 344 case ActiveSensing:
popcornell 0:244f1d0a3810 345 case SystemReset:
popcornell 0:244f1d0a3810 346
popcornell 0:244f1d0a3810 347 // Here we will have to extract the one-byte message,
popcornell 0:244f1d0a3810 348 // pass it to the structure for being read outside
popcornell 0:244f1d0a3810 349 // the MIDI class, and recompose the message it was
popcornell 0:244f1d0a3810 350 // interleaved into. Oh, and without killing the running status..
popcornell 0:244f1d0a3810 351 // This is done by leaving the pending message as is,
popcornell 0:244f1d0a3810 352 // it will be completed on next calls.
popcornell 0:244f1d0a3810 353
popcornell 0:244f1d0a3810 354 mMessage.type = (MidiType)extracted;
popcornell 0:244f1d0a3810 355 mMessage.data1 = 0;
popcornell 0:244f1d0a3810 356 mMessage.data2 = 0;
popcornell 0:244f1d0a3810 357 mMessage.channel = 0;
popcornell 0:244f1d0a3810 358 mMessage.valid = true;
popcornell 0:244f1d0a3810 359 return true;
popcornell 0:244f1d0a3810 360
popcornell 0:244f1d0a3810 361 break;
popcornell 0:244f1d0a3810 362
popcornell 0:244f1d0a3810 363 // End of Exclusive
popcornell 0:244f1d0a3810 364 case 0xf7:
popcornell 0:244f1d0a3810 365 if (mMessage.sysexArray[0] == SystemExclusive)
popcornell 0:244f1d0a3810 366 {
popcornell 0:244f1d0a3810 367 // Store the last byte (EOX)
popcornell 0:244f1d0a3810 368 mMessage.sysexArray[mPendingMessageIndex++] = 0xf7;
popcornell 0:244f1d0a3810 369 mMessage.type = SystemExclusive;
popcornell 0:244f1d0a3810 370
popcornell 0:244f1d0a3810 371 // Get length
popcornell 0:244f1d0a3810 372 mMessage.data1 = mPendingMessageIndex & 0xff; // LSB
popcornell 0:244f1d0a3810 373 mMessage.data2 = mPendingMessageIndex >> 8; // MSB
popcornell 0:244f1d0a3810 374 mMessage.channel = 0;
popcornell 0:244f1d0a3810 375 mMessage.valid = true;
popcornell 0:244f1d0a3810 376
popcornell 0:244f1d0a3810 377 resetInput();
popcornell 0:244f1d0a3810 378 return true;
popcornell 0:244f1d0a3810 379 }
popcornell 0:244f1d0a3810 380 else
popcornell 0:244f1d0a3810 381 {
popcornell 0:244f1d0a3810 382 // Well well well.. error.
popcornell 0:244f1d0a3810 383 resetInput();
popcornell 0:244f1d0a3810 384 return false;
popcornell 0:244f1d0a3810 385 }
popcornell 0:244f1d0a3810 386
popcornell 0:244f1d0a3810 387 break;
popcornell 0:244f1d0a3810 388 default:
popcornell 0:244f1d0a3810 389 break;
popcornell 0:244f1d0a3810 390 }
popcornell 0:244f1d0a3810 391 }
popcornell 0:244f1d0a3810 392
popcornell 0:244f1d0a3810 393 // Add extracted data byte to pending message
popcornell 0:244f1d0a3810 394 if (mPendingMessage[0] == SystemExclusive)
popcornell 0:244f1d0a3810 395 mMessage.sysexArray[mPendingMessageIndex] = extracted;
popcornell 0:244f1d0a3810 396 else
popcornell 0:244f1d0a3810 397 mPendingMessage[mPendingMessageIndex] = extracted;
popcornell 0:244f1d0a3810 398
popcornell 0:244f1d0a3810 399 // Now we are going to check if we have reached the end of the message
popcornell 0:244f1d0a3810 400 if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
popcornell 0:244f1d0a3810 401 {
popcornell 0:244f1d0a3810 402 // "FML" case: fall down here with an overflown SysEx..
popcornell 0:244f1d0a3810 403 // This means we received the last possible data byte that can fit
popcornell 0:244f1d0a3810 404 // the buffer. If this happens, try increasing MidiMessage::sSysExMaxSize.
popcornell 0:244f1d0a3810 405 if (mPendingMessage[0] == SystemExclusive)
popcornell 0:244f1d0a3810 406 {
popcornell 0:244f1d0a3810 407 resetInput();
popcornell 0:244f1d0a3810 408 return false;
popcornell 0:244f1d0a3810 409 }
popcornell 0:244f1d0a3810 410
popcornell 0:244f1d0a3810 411 mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
popcornell 0:244f1d0a3810 412
popcornell 0:244f1d0a3810 413 if (isChannelMessage(mMessage.type))
popcornell 0:244f1d0a3810 414 mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]);
popcornell 0:244f1d0a3810 415 else
popcornell 0:244f1d0a3810 416 mMessage.channel = 0;
popcornell 0:244f1d0a3810 417
popcornell 0:244f1d0a3810 418 mMessage.data1 = mPendingMessage[1];
popcornell 0:244f1d0a3810 419
popcornell 0:244f1d0a3810 420 // Save data2 only if applicable
popcornell 0:244f1d0a3810 421 if (mPendingMessageExpectedLenght == 3)
popcornell 0:244f1d0a3810 422 mMessage.data2 = mPendingMessage[2];
popcornell 0:244f1d0a3810 423 else
popcornell 0:244f1d0a3810 424 mMessage.data2 = 0;
popcornell 0:244f1d0a3810 425
popcornell 0:244f1d0a3810 426 // Reset local variables
popcornell 0:244f1d0a3810 427 mPendingMessageIndex = 0;
popcornell 0:244f1d0a3810 428 mPendingMessageExpectedLenght = 0;
popcornell 0:244f1d0a3810 429
popcornell 0:244f1d0a3810 430 mMessage.valid = true;
popcornell 0:244f1d0a3810 431
popcornell 0:244f1d0a3810 432 // Activate running status (if enabled for the received type)
popcornell 0:244f1d0a3810 433 switch (mMessage.type)
popcornell 0:244f1d0a3810 434 {
popcornell 0:244f1d0a3810 435 case NoteOff:
popcornell 0:244f1d0a3810 436 case NoteOn:
popcornell 0:244f1d0a3810 437 case AfterTouchPoly:
popcornell 0:244f1d0a3810 438 case ControlChange:
popcornell 0:244f1d0a3810 439 case ProgramChange:
popcornell 0:244f1d0a3810 440 case AfterTouchChannel:
popcornell 0:244f1d0a3810 441 case PitchBend:
popcornell 0:244f1d0a3810 442 // Running status enabled: store it from received message
popcornell 0:244f1d0a3810 443 mRunningStatus_RX = mPendingMessage[0];
popcornell 0:244f1d0a3810 444 break;
popcornell 0:244f1d0a3810 445
popcornell 0:244f1d0a3810 446 default:
popcornell 0:244f1d0a3810 447 // No running status
popcornell 0:244f1d0a3810 448 mRunningStatus_RX = InvalidType;
popcornell 0:244f1d0a3810 449 break;
popcornell 0:244f1d0a3810 450 }
popcornell 0:244f1d0a3810 451 return true;
popcornell 0:244f1d0a3810 452 }
popcornell 0:244f1d0a3810 453 else
popcornell 0:244f1d0a3810 454 {
popcornell 0:244f1d0a3810 455 // Then update the index of the pending message.
popcornell 0:244f1d0a3810 456 mPendingMessageIndex++;
popcornell 0:244f1d0a3810 457
popcornell 0:244f1d0a3810 458 if (Use1ByteParsing==1)
popcornell 0:244f1d0a3810 459 {
popcornell 0:244f1d0a3810 460 // Message is not complete.
popcornell 0:244f1d0a3810 461 return false;
popcornell 0:244f1d0a3810 462 }
popcornell 0:244f1d0a3810 463 else
popcornell 0:244f1d0a3810 464 {
popcornell 0:244f1d0a3810 465 // Call the parser recursively to parse the rest of the message.
popcornell 0:244f1d0a3810 466 return MIDI_to_BLEMIDI_Parser();
popcornell 0:244f1d0a3810 467 }
popcornell 0:244f1d0a3810 468 }
popcornell 0:244f1d0a3810 469 }
popcornell 0:244f1d0a3810 470 }
popcornell 0:244f1d0a3810 471
popcornell 0:244f1d0a3810 472
popcornell 0:244f1d0a3810 473 } // end namespace