11/* *************************************************************************/
22/* !
33 @file BLEMidi.cpp
4- @author hathach
4+ @author hathach & toddtreece
55
66 @section LICENSE
77
@@ -93,10 +93,18 @@ typedef struct ATTR_PACKED
9393{
9494 midi_header_t header;
9595 midi_timestamp_t timestamp;
96- uint8_t data[3 ];
96+ uint8_t data[20 ];
9797} midi_event_packet_t ;
9898
99- VERIFY_STATIC ( sizeof (midi_event_packet_t ) == 5 );
99+ VERIFY_STATIC ( sizeof (midi_event_packet_t ) == 22 );
100+
101+ typedef struct ATTR_PACKED
102+ {
103+ midi_header_t header;
104+ uint8_t data[20 ];
105+ } midi_split_packet_t ;
106+
107+ VERIFY_STATIC ( sizeof (midi_split_packet_t ) == 21 );
100108
101109void blemidi_write_cb (BLECharacteristic& chr, uint8_t * data, uint16_t len, uint16_t offset);
102110
@@ -208,36 +216,97 @@ int BLEMidi::read ( void )
208216 return _rxd_fifo.read (&ch) ? (int ) ch : EOF;
209217}
210218
219+ bool BLEMidi::oneByteMessage ( uint8_t status )
220+ {
221+ // system messages
222+ if (status >= 0xF4 && status <= 0xFF ) return true ;
223+
224+ // system common
225+ if (status == 0xF1 ) return true ;
226+
227+ return false ;
228+ }
229+
230+ bool BLEMidi::twoByteMessage ( uint8_t status )
231+ {
232+ // program change, aftertouch
233+ if (status >= 0xC0 && status <= 0xDF ) return true ;
234+
235+ // song select
236+ if (status == 0xF3 ) return true ;
237+
238+ return false ;
239+ }
240+
241+ bool BLEMidi::threeByteMessage ( uint8_t status )
242+ {
243+ // note off, note on, aftertouch, control change
244+ if (status >= 0x80 && status <= 0xBF ) return true ;
245+
246+ // pitch wheel change
247+ if (status >= 0xE0 && status <= 0xEF ) return true ;
248+
249+ // song position pointer
250+ if (status == 0xF2 ) return true ;
251+
252+ return false ;
253+ }
254+
211255size_t BLEMidi::write ( uint8_t b )
212256{
213- // MIDI Library will write event byte by byte. Locally buffered
214- // Until we gather all 3 bytes
257+ // MIDI Library will write event byte by byte.
258+ // We need to buffer the data until we have a full event,
259+ // or until we reach the BLE payload limit.
215260 static uint8_t count = 0 ;
216- static uint8_t buf[3 ] = { 0 };
261+ static uint8_t buf[16 ] = { 0 };
217262
263+ buf[count++] = b;
218264
219- // Not SysEx message, keep accumulating data
220- if ( buf[0 ] != 0xf0 )
265+ // if we are at the end of a sysex message
266+ // or at the end of the buffer
267+ if ((b == 0xF7 ) || (count == 16 ))
221268 {
222- buf[count++] = b;
223-
224- if ( count == 3 )
225- {
226- count = 0 ;
227269
228- send (buf);
229- }
230- }else
231- {
232- // skip until we reach 0xF7
233- if (b == 0xF7 )
234- {
235- buf[0 ] = 0 ;
236- count = 0 ;
270+ // send full event if the first byte is a status byte
271+ if (bitRead (buf[0 ], 7 )) {
272+ send (buf, count);
273+ } else {
274+ sendSplit (buf, count);
237275 }
276+
277+ // reset buffer
278+ buf[0 ] = 0 ;
279+ count = 0 ;
280+
281+ return 1 ;
282+
238283 }
239284
285+ // don't send if this is a full or split sysex
286+ if (buf[0 ] == 0xF0 || ! bitRead (buf[0 ], 7 ))
287+ return 1 ;
288+
289+ // don't send if we don't have 1 byte
290+ if (oneByteMessage (buf[0 ]) && count != 1 )
291+ return 1 ;
292+
293+ // don't send if we don't have 2 bytes
294+ if (twoByteMessage (buf[0 ]) && count != 2 )
295+ return 1 ;
296+
297+ // don't send if we don't have 3 bytes
298+ if (threeByteMessage (buf[0 ]) && count != 3 )
299+ return 1 ;
300+
301+ // send full event
302+ send (buf, count);
303+
304+ // reset buffer
305+ buf[0 ] = 0 ;
306+ count = 0 ;
307+
240308 return 1 ;
309+
241310}
242311
243312int BLEMidi::available ( void )
@@ -259,7 +328,7 @@ void BLEMidi::flush ( void )
259328/* ------------------------------------------------------------------*/
260329/* Send Event (notify)
261330 *------------------------------------------------------------------*/
262- err_t BLEMidi::send (uint8_t data[])
331+ err_t BLEMidi::send (uint8_t data[], uint8_t len )
263332{
264333 uint32_t tstamp = millis ();
265334
@@ -276,16 +345,31 @@ void BLEMidi::flush ( void )
276345 }}
277346 };
278347
279- memcpy (event.data , data, 3 );
348+ memcpy (event.data , data, len );
280349
281- VERIFY_STATUS ( _io.notify (&event, sizeof (event)) );
350+ // send data length + 1 byte for header + 1 byte for timestamp
351+ VERIFY_STATUS ( _io.notify (&event, len + 2 ) );
282352
283353 return ERROR_NONE;
284354}
285355
286- err_t BLEMidi::send (uint8_t status , uint8_t byte1, uint8_t byte2 )
356+ err_t BLEMidi::sendSplit (uint8_t data[] , uint8_t len )
287357{
288- uint8_t data[] = { status, byte1, byte2 };
289- return send (data);
290- }
358+ uint32_t tstamp = millis ();
359+
360+ midi_split_packet_t event =
361+ {
362+ .header = {{
363+ .timestamp_hi = (uint8_t ) ((tstamp & 0x1F80UL ) >> 7 ),
364+ .start_bit = 1
365+ }}
366+ };
367+
368+ memcpy (event.data , data, len);
291369
370+ // send data length + 1 byte for header
371+ // don't include the second timestamp byte
372+ VERIFY_STATUS ( _io.notify (&event, len + 1 ) );
373+
374+ return ERROR_NONE;
375+ }
0 commit comments