Dependencies:   BLE_API mbed nRF51822_BLE_MIDI

Dependents:   BLE_MIDI_one_note_TEST

Fork of BLE_MIDI by Kaoru Shoji

Committer:
kshoji
Date:
Fri Apr 03 04:24:01 2015 +0000
Revision:
1:cba2eba64f5c
Parent:
0:83889dc90473
Child:
2:dbc6f81b9ba0
Tested MIDI sending

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kshoji 0:83889dc90473 1 /* Copyright (c) 2014 mbed.org, MIT License
kshoji 0:83889dc90473 2 *
kshoji 0:83889dc90473 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
kshoji 0:83889dc90473 4 * and associated documentation files (the "Software"), to deal in the Software without
kshoji 0:83889dc90473 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
kshoji 0:83889dc90473 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
kshoji 0:83889dc90473 7 * Software is furnished to do so, subject to the following conditions:
kshoji 0:83889dc90473 8 *
kshoji 0:83889dc90473 9 * The above copyright notice and this permission notice shall be included in all copies or
kshoji 0:83889dc90473 10 * substantial portions of the Software.
kshoji 0:83889dc90473 11 *
kshoji 0:83889dc90473 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
kshoji 0:83889dc90473 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
kshoji 0:83889dc90473 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
kshoji 0:83889dc90473 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
kshoji 0:83889dc90473 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
kshoji 0:83889dc90473 17 */
kshoji 0:83889dc90473 18
kshoji 0:83889dc90473 19 #include "mbed.h"
kshoji 0:83889dc90473 20 #include "BLEMIDI.h"
kshoji 0:83889dc90473 21
kshoji 0:83889dc90473 22 void BLEMIDI::onBleDisconnection(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
kshoji 0:83889dc90473 23 device->startAdvertising();
kshoji 0:83889dc90473 24 isConnected = false;
kshoji 0:83889dc90473 25 }
kshoji 0:83889dc90473 26
kshoji 0:83889dc90473 27 void BLEMIDI::onBleConnection(Gap::Handle_t handle, Gap::addr_type_t type, const Gap::address_t addr, const Gap::ConnectionParams_t *params) {
kshoji 0:83889dc90473 28 isConnected = true;
kshoji 0:83889dc90473 29 }
kshoji 0:83889dc90473 30
kshoji 0:83889dc90473 31 void BLEMIDI::dataWrittenCallback(const GattCharacteristicWriteCBParams *params) {
kshoji 0:83889dc90473 32 // read characteristic and write serial
kshoji 0:83889dc90473 33 uint16_t length;
kshoji 0:83889dc90473 34 uint8_t rxBuffer[20];
kshoji 0:83889dc90473 35
kshoji 0:83889dc90473 36 device->readCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), rxBuffer, &length);
kshoji 0:83889dc90473 37
kshoji 0:83889dc90473 38 if (length > 1) {
kshoji 0:83889dc90473 39 // parse BLE message
kshoji 0:83889dc90473 40 uint8_t header = rxBuffer[0];
kshoji 0:83889dc90473 41 for (int i = 1; i < length; i++) {
kshoji 0:83889dc90473 42 uint8_t midiEvent = rxBuffer[i];
kshoji 0:83889dc90473 43
kshoji 0:83889dc90473 44 if (midiState == MIDI_STATE_TIMESTAMP) {
kshoji 0:83889dc90473 45 if ((midiEvent & 0x80) == 0) {
kshoji 0:83889dc90473 46 // running status
kshoji 0:83889dc90473 47 midiState = MIDI_STATE_WAIT;
kshoji 0:83889dc90473 48 }
kshoji 0:83889dc90473 49
kshoji 0:83889dc90473 50 if (midiEvent == 0xf7) {
kshoji 0:83889dc90473 51 // maybe error
kshoji 0:83889dc90473 52 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 53 continue;
kshoji 0:83889dc90473 54 }
kshoji 0:83889dc90473 55 }
kshoji 0:83889dc90473 56 if (midiState == MIDI_STATE_TIMESTAMP) {
kshoji 0:83889dc90473 57 timestamp = ((header & 0x3f) << 7) | (midiEvent & 0x7f);
kshoji 0:83889dc90473 58 midiState = MIDI_STATE_WAIT;
kshoji 0:83889dc90473 59 } else if (midiState == MIDI_STATE_WAIT) {
kshoji 0:83889dc90473 60 switch (midiEvent & 0xf0) {
kshoji 0:83889dc90473 61 case 0xf0: {
kshoji 0:83889dc90473 62 switch (midiEvent) {
kshoji 0:83889dc90473 63 case 0xf0:
kshoji 0:83889dc90473 64 sysExBuffer[sysExBufferPos++] = midiEvent;
kshoji 0:83889dc90473 65 midiState = MIDI_STATE_SIGNAL_SYSEX;
kshoji 0:83889dc90473 66 break;
kshoji 0:83889dc90473 67
kshoji 0:83889dc90473 68 case 0xf1:
kshoji 0:83889dc90473 69 case 0xf3:
kshoji 0:83889dc90473 70 // 0xf1 MIDI Time Code Quarter Frame. : 2bytes
kshoji 0:83889dc90473 71 // 0xf3 Song Select. : 2bytes
kshoji 0:83889dc90473 72 midiEventKind = midiEvent;
kshoji 0:83889dc90473 73 midiState = MIDI_STATE_SIGNAL_2BYTES_2;
kshoji 0:83889dc90473 74 break;
kshoji 0:83889dc90473 75
kshoji 0:83889dc90473 76 case 0xf2:
kshoji 0:83889dc90473 77 // 0xf2 Song Position Pointer. : 3bytes
kshoji 0:83889dc90473 78 midiEventKind = midiEvent;
kshoji 0:83889dc90473 79 midiState = MIDI_STATE_SIGNAL_3BYTES_2;
kshoji 0:83889dc90473 80 break;
kshoji 0:83889dc90473 81
kshoji 0:83889dc90473 82 case 0xf6:
kshoji 0:83889dc90473 83 // 0xf6 Tune Request : 1byte
kshoji 0:83889dc90473 84 onTuneRequest();
kshoji 0:83889dc90473 85 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 86 break;
kshoji 0:83889dc90473 87 case 0xf8:
kshoji 0:83889dc90473 88 // 0xf8 Timing Clock : 1byte
kshoji 0:83889dc90473 89 onTimingClock();
kshoji 0:83889dc90473 90 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 91 break;
kshoji 0:83889dc90473 92 case 0xfa:
kshoji 0:83889dc90473 93 // 0xfa Start : 1byte
kshoji 0:83889dc90473 94 onStart();
kshoji 0:83889dc90473 95 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 96 break;
kshoji 0:83889dc90473 97 case 0xfb:
kshoji 0:83889dc90473 98 // 0xfb Continue : 1byte
kshoji 0:83889dc90473 99 onContinue();
kshoji 0:83889dc90473 100 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 101 break;
kshoji 0:83889dc90473 102 case 0xfc:
kshoji 0:83889dc90473 103 // 0xfc Stop : 1byte
kshoji 0:83889dc90473 104 onStop();
kshoji 0:83889dc90473 105 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 106 break;
kshoji 0:83889dc90473 107 case 0xfe:
kshoji 0:83889dc90473 108 // 0xfe Active Sensing : 1byte
kshoji 0:83889dc90473 109 onActiveSensing();
kshoji 0:83889dc90473 110 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 111 break;
kshoji 0:83889dc90473 112 case 0xff:
kshoji 0:83889dc90473 113 // 0xff Reset : 1byte
kshoji 0:83889dc90473 114 onReset();
kshoji 0:83889dc90473 115 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 116 break;
kshoji 0:83889dc90473 117
kshoji 0:83889dc90473 118 default:
kshoji 0:83889dc90473 119 break;
kshoji 0:83889dc90473 120 }
kshoji 0:83889dc90473 121 }
kshoji 0:83889dc90473 122 break;
kshoji 0:83889dc90473 123 case 0x80:
kshoji 0:83889dc90473 124 case 0x90:
kshoji 0:83889dc90473 125 case 0xa0:
kshoji 0:83889dc90473 126 case 0xb0:
kshoji 0:83889dc90473 127 case 0xe0:
kshoji 0:83889dc90473 128 // 3bytes pattern
kshoji 0:83889dc90473 129 midiEventKind = midiEvent;
kshoji 0:83889dc90473 130 midiState = MIDI_STATE_SIGNAL_3BYTES_2;
kshoji 0:83889dc90473 131 break;
kshoji 0:83889dc90473 132 case 0xc0: // program change
kshoji 0:83889dc90473 133 case 0xd0: // channel after-touch
kshoji 0:83889dc90473 134 // 2bytes pattern
kshoji 0:83889dc90473 135 midiEventKind = midiEvent;
kshoji 0:83889dc90473 136 midiState = MIDI_STATE_SIGNAL_2BYTES_2;
kshoji 0:83889dc90473 137 break;
kshoji 0:83889dc90473 138 default:
kshoji 0:83889dc90473 139 // 0x00 - 0x70: running status
kshoji 0:83889dc90473 140 if ((midiEventKind & 0xf0) != 0xf0) {
kshoji 0:83889dc90473 141 // previous event kind is multi-bytes pattern
kshoji 0:83889dc90473 142 midiEventNote = midiEvent;
kshoji 0:83889dc90473 143 midiState = MIDI_STATE_SIGNAL_3BYTES_3;
kshoji 0:83889dc90473 144 }
kshoji 0:83889dc90473 145 break;
kshoji 0:83889dc90473 146 }
kshoji 0:83889dc90473 147 } else if (midiState == MIDI_STATE_SIGNAL_2BYTES_2) {
kshoji 0:83889dc90473 148 switch (midiEventKind & 0xf0) {
kshoji 0:83889dc90473 149 // 2bytes pattern
kshoji 0:83889dc90473 150 case 0xc0: // program change
kshoji 0:83889dc90473 151 midiEventNote = midiEvent;
kshoji 0:83889dc90473 152 onProgramChange(midiEventKind & 0xf, midiEventNote);
kshoji 0:83889dc90473 153 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 154 break;
kshoji 0:83889dc90473 155 case 0xd0: // channel after-touch
kshoji 0:83889dc90473 156 midiEventNote = midiEvent;
kshoji 0:83889dc90473 157 onChannelAftertouch(midiEventKind & 0xf, midiEventNote);
kshoji 0:83889dc90473 158 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 159 break;
kshoji 0:83889dc90473 160 case 0xf0: {
kshoji 0:83889dc90473 161 switch (midiEventKind) {
kshoji 0:83889dc90473 162 case 0xf1:
kshoji 0:83889dc90473 163 // 0xf1 MIDI Time Code Quarter Frame. : 2bytes
kshoji 0:83889dc90473 164 midiEventNote = midiEvent;
kshoji 0:83889dc90473 165 onTimeCodeQuarterFrame(midiEventNote);
kshoji 0:83889dc90473 166 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 167 break;
kshoji 0:83889dc90473 168 case 0xf3:
kshoji 0:83889dc90473 169 // 0xf3 Song Select. : 2bytes
kshoji 0:83889dc90473 170 midiEventNote = midiEvent;
kshoji 0:83889dc90473 171 onSongSelect(midiEventNote);
kshoji 0:83889dc90473 172 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 173 break;
kshoji 0:83889dc90473 174 default:
kshoji 0:83889dc90473 175 // illegal state
kshoji 0:83889dc90473 176 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 177 break;
kshoji 0:83889dc90473 178 }
kshoji 0:83889dc90473 179 }
kshoji 0:83889dc90473 180 break;
kshoji 0:83889dc90473 181 default:
kshoji 0:83889dc90473 182 // illegal state
kshoji 0:83889dc90473 183 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 184 break;
kshoji 0:83889dc90473 185 }
kshoji 0:83889dc90473 186 } else if (midiState == MIDI_STATE_SIGNAL_3BYTES_2) {
kshoji 0:83889dc90473 187 switch (midiEventKind & 0xf0) {
kshoji 0:83889dc90473 188 case 0x80:
kshoji 0:83889dc90473 189 case 0x90:
kshoji 0:83889dc90473 190 case 0xa0:
kshoji 0:83889dc90473 191 case 0xb0:
kshoji 0:83889dc90473 192 case 0xe0:
kshoji 0:83889dc90473 193 case 0xf0:
kshoji 0:83889dc90473 194 // 3bytes pattern
kshoji 0:83889dc90473 195 midiEventNote = midiEvent;
kshoji 0:83889dc90473 196 midiState = MIDI_STATE_SIGNAL_3BYTES_3;
kshoji 0:83889dc90473 197 break;
kshoji 0:83889dc90473 198 default:
kshoji 0:83889dc90473 199 // illegal state
kshoji 0:83889dc90473 200 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 201 break;
kshoji 0:83889dc90473 202 }
kshoji 0:83889dc90473 203 } else if (midiState == MIDI_STATE_SIGNAL_3BYTES_3) {
kshoji 0:83889dc90473 204 switch (midiEventKind & 0xf0) {
kshoji 0:83889dc90473 205 // 3bytes pattern
kshoji 0:83889dc90473 206 case 0x80: // note off
kshoji 0:83889dc90473 207 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 208 onNoteOff(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 209 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 210 break;
kshoji 0:83889dc90473 211 case 0x90: // note on
kshoji 0:83889dc90473 212 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 213 if (midiEventVelocity == 0) {
kshoji 0:83889dc90473 214 onNoteOff(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 215 } else {
kshoji 0:83889dc90473 216 onNoteOn(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 217 }
kshoji 0:83889dc90473 218 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 219 break;
kshoji 0:83889dc90473 220 case 0xa0: // control polyphonic key pressure
kshoji 0:83889dc90473 221 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 222 onPolyphonicAftertouch(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 223 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 224 break;
kshoji 0:83889dc90473 225 case 0xb0: // control change
kshoji 0:83889dc90473 226 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 227 onControlChange(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 228 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 229 break;
kshoji 0:83889dc90473 230 case 0xe0: // pitch bend
kshoji 0:83889dc90473 231 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 232 onPitchWheel(midiEventKind & 0xf, (midiEventNote & 0x7f) | ((midiEventVelocity & 0x7f) << 7));
kshoji 0:83889dc90473 233 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 234 break;
kshoji 0:83889dc90473 235 case 0xf0: // Song Position Pointer.
kshoji 0:83889dc90473 236 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 237 onSongPositionPointer((midiEventNote & 0x7f) | ((midiEventVelocity & 0x7f) << 7));
kshoji 0:83889dc90473 238 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 239 break;
kshoji 0:83889dc90473 240 default:
kshoji 0:83889dc90473 241 // illegal state
kshoji 0:83889dc90473 242 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 243 break;
kshoji 0:83889dc90473 244 }
kshoji 0:83889dc90473 245 } else if (midiState == MIDI_STATE_SIGNAL_SYSEX) {
kshoji 0:83889dc90473 246 if (midiEvent == 0xf7) {
kshoji 0:83889dc90473 247 // the end of message
kshoji 0:83889dc90473 248 // last written uint8_t is for timestamp
kshoji 1:cba2eba64f5c 249 if (sysExBufferPos > 0) {
kshoji 1:cba2eba64f5c 250 sysExBuffer[sysExBufferPos - 1] = midiEvent;
kshoji 1:cba2eba64f5c 251 onSystemExclusive(sysExBuffer, sysExBufferPos);
kshoji 1:cba2eba64f5c 252 }
kshoji 0:83889dc90473 253
kshoji 0:83889dc90473 254 sysExBufferPos = 0;
kshoji 0:83889dc90473 255 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 256 } else {
kshoji 0:83889dc90473 257 sysExBuffer[sysExBufferPos++] = midiEvent;
kshoji 0:83889dc90473 258 }
kshoji 0:83889dc90473 259 }
kshoji 0:83889dc90473 260 }
kshoji 0:83889dc90473 261 }
kshoji 0:83889dc90473 262 }
kshoji 0:83889dc90473 263
kshoji 0:83889dc90473 264 BLEMIDI::BLEMIDI(BLEDevice *dev) {
kshoji 0:83889dc90473 265 device = dev;
kshoji 0:83889dc90473 266 isConnected = false;
kshoji 0:83889dc90473 267 sysExBufferPos = 0;
kshoji 0:83889dc90473 268
kshoji 1:cba2eba64f5c 269 timestamp = 0;
kshoji 1:cba2eba64f5c 270 midiEventKind = 0;
kshoji 1:cba2eba64f5c 271 midiEventNote = 0;
kshoji 1:cba2eba64f5c 272 midiEventVelocity = 0;
kshoji 1:cba2eba64f5c 273
kshoji 0:83889dc90473 274 // Advertise packet length is 31 bytes.
kshoji 0:83889dc90473 275 // device name is upto 4 bytes if the service UUID included
kshoji 0:83889dc90473 276 const char DEVICE_NAME[] = "MIDI";
kshoji 0:83889dc90473 277
kshoji 0:83889dc90473 278 // MIDI characteristic
kshoji 0:83889dc90473 279 LongUUIDBytes_t characteristicUuid = {
kshoji 0:83889dc90473 280 0x77, 0x72, 0xe5, 0xdb, 0x38, 0x68, 0x41, 0x12,
kshoji 0:83889dc90473 281 0xa1, 0xa9, 0xf2, 0x66, 0x9d, 0x10, 0x6b, 0xf3
kshoji 0:83889dc90473 282 };
kshoji 0:83889dc90473 283
kshoji 1:cba2eba64f5c 284 midiCharacteristic = new GattCharacteristic(UUID(characteristicUuid), midi, 0, 20, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
kshoji 0:83889dc90473 285 GattCharacteristic *midiChars[] = {midiCharacteristic};
kshoji 0:83889dc90473 286
kshoji 0:83889dc90473 287 // MIDI service
kshoji 0:83889dc90473 288 LongUUIDBytes_t serviceUuid = {
kshoji 0:83889dc90473 289 0x03, 0xb8, 0x0e, 0x5a, 0xed, 0xe8, 0x4b, 0x33,
kshoji 0:83889dc90473 290 0xa7, 0x51, 0x6c, 0xe3, 0x4e, 0xc4, 0xc7, 0x00
kshoji 0:83889dc90473 291 };
kshoji 0:83889dc90473 292
kshoji 0:83889dc90473 293 GattService midiService(UUID(serviceUuid), midiChars, sizeof(midiChars) / sizeof(GattCharacteristic *));
kshoji 0:83889dc90473 294 uint8_t uuid128_list[] = {
kshoji 0:83889dc90473 295 0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7,
kshoji 0:83889dc90473 296 0x33, 0x4b, 0xe8, 0xed, 0x5a, 0x0e, 0xb8, 0x03
kshoji 0:83889dc90473 297 };
kshoji 0:83889dc90473 298
kshoji 0:83889dc90473 299 device->init();
kshoji 0:83889dc90473 300 device->reset();
kshoji 0:83889dc90473 301
kshoji 0:83889dc90473 302 /* setup callbacks */
kshoji 0:83889dc90473 303 device->onDataWritten(this, &BLEMIDI::dataWrittenCallback);
kshoji 0:83889dc90473 304
kshoji 0:83889dc90473 305 device->addService(midiService);
kshoji 0:83889dc90473 306
kshoji 0:83889dc90473 307 /* setup advertising */
kshoji 0:83889dc90473 308 device->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t*)uuid128_list, sizeof(uuid128_list));
kshoji 0:83889dc90473 309 device->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
kshoji 0:83889dc90473 310 device->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
kshoji 0:83889dc90473 311
kshoji 0:83889dc90473 312 device->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
kshoji 0:83889dc90473 313 device->setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
kshoji 0:83889dc90473 314
kshoji 0:83889dc90473 315 device->startAdvertising();
kshoji 0:83889dc90473 316 tick.start();
kshoji 0:83889dc90473 317 }
kshoji 0:83889dc90473 318
kshoji 0:83889dc90473 319 bool BLEMIDI::connected() {
kshoji 0:83889dc90473 320 return isConnected;
kshoji 0:83889dc90473 321 }
kshoji 0:83889dc90473 322
kshoji 0:83889dc90473 323 void BLEMIDI::sendMidiMessage(uint8_t data0) {
kshoji 0:83889dc90473 324 if (isConnected) {
kshoji 0:83889dc90473 325 unsigned int ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 326 midi[0] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 327 midi[1] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 328 midi[2] = data0;
kshoji 0:83889dc90473 329
kshoji 0:83889dc90473 330 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 3);
kshoji 0:83889dc90473 331 }
kshoji 0:83889dc90473 332 }
kshoji 0:83889dc90473 333
kshoji 0:83889dc90473 334 void BLEMIDI::sendMidiMessage(uint8_t data0, uint8_t data1) {
kshoji 0:83889dc90473 335 if (isConnected) {
kshoji 0:83889dc90473 336 unsigned int ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 337 midi[0] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 338 midi[1] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 339 midi[2] = data0;
kshoji 0:83889dc90473 340 midi[3] = data1;
kshoji 0:83889dc90473 341
kshoji 0:83889dc90473 342 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 4);
kshoji 0:83889dc90473 343 }
kshoji 0:83889dc90473 344 }
kshoji 0:83889dc90473 345
kshoji 0:83889dc90473 346 void BLEMIDI::sendMidiMessage(uint8_t data0, uint8_t data1, uint8_t data2) {
kshoji 0:83889dc90473 347 if (isConnected) {
kshoji 0:83889dc90473 348 unsigned int ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 349 midi[0] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 350 midi[1] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 351 midi[2] = data0;
kshoji 0:83889dc90473 352 midi[3] = data1;
kshoji 0:83889dc90473 353 midi[4] = data2;
kshoji 0:83889dc90473 354
kshoji 0:83889dc90473 355 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 5);
kshoji 0:83889dc90473 356 }
kshoji 0:83889dc90473 357 }
kshoji 0:83889dc90473 358
kshoji 0:83889dc90473 359 void BLEMIDI::sendTuneRequest() {
kshoji 0:83889dc90473 360 sendMidiMessage(0xf6);
kshoji 0:83889dc90473 361 }
kshoji 0:83889dc90473 362 void BLEMIDI::sendTimingClock() {
kshoji 0:83889dc90473 363 sendMidiMessage(0xf8);
kshoji 0:83889dc90473 364 }
kshoji 0:83889dc90473 365 void BLEMIDI::sendStart() {
kshoji 0:83889dc90473 366 sendMidiMessage(0xfa);
kshoji 0:83889dc90473 367 }
kshoji 0:83889dc90473 368 void BLEMIDI::sendContinue() {
kshoji 0:83889dc90473 369 sendMidiMessage(0xfb);
kshoji 0:83889dc90473 370 }
kshoji 0:83889dc90473 371 void BLEMIDI::sendStop() {
kshoji 0:83889dc90473 372 sendMidiMessage(0xfc);
kshoji 0:83889dc90473 373 }
kshoji 0:83889dc90473 374 void BLEMIDI::sendActiveSensing() {
kshoji 0:83889dc90473 375 sendMidiMessage(0xfe);
kshoji 0:83889dc90473 376 }
kshoji 0:83889dc90473 377 void BLEMIDI::sendReset() {
kshoji 0:83889dc90473 378 sendMidiMessage(0xff);
kshoji 0:83889dc90473 379 }
kshoji 0:83889dc90473 380 void BLEMIDI::sendProgramChange(uint8_t channel, uint8_t program) {
kshoji 0:83889dc90473 381 sendMidiMessage(0xc0 | (channel & 0xf), program);
kshoji 0:83889dc90473 382 }
kshoji 0:83889dc90473 383 void BLEMIDI::sendChannelAftertouch(uint8_t channel, uint8_t pressure) {
kshoji 0:83889dc90473 384 sendMidiMessage(0xd0 | (channel & 0xf), pressure);
kshoji 0:83889dc90473 385 }
kshoji 0:83889dc90473 386 void BLEMIDI::sendTimeCodeQuarterFrame(uint8_t timing) {
kshoji 0:83889dc90473 387 sendMidiMessage(0xf1, timing & 0x7f);
kshoji 0:83889dc90473 388 }
kshoji 0:83889dc90473 389 void BLEMIDI::sendSongSelect(uint8_t song) {
kshoji 0:83889dc90473 390 sendMidiMessage(0xf3, song & 0x7f);
kshoji 0:83889dc90473 391 }
kshoji 0:83889dc90473 392 void BLEMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
kshoji 0:83889dc90473 393 sendMidiMessage(0x80 | (channel & 0xf), note, velocity);
kshoji 0:83889dc90473 394 }
kshoji 0:83889dc90473 395 void BLEMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
kshoji 0:83889dc90473 396 sendMidiMessage(0x90 | (channel & 0xf), note, velocity);
kshoji 0:83889dc90473 397 }
kshoji 0:83889dc90473 398 void BLEMIDI::sendPolyphonicAftertouch(uint8_t channel, uint8_t note, uint8_t pressure) {
kshoji 0:83889dc90473 399 sendMidiMessage(0xa0 | (channel & 0xf), note, pressure);
kshoji 0:83889dc90473 400 }
kshoji 0:83889dc90473 401 void BLEMIDI::sendControlChange(uint8_t channel, uint8_t function, uint8_t value) {
kshoji 0:83889dc90473 402 sendMidiMessage(0xb0 | (channel & 0xf), function, value);
kshoji 0:83889dc90473 403 }
kshoji 0:83889dc90473 404 void BLEMIDI::sendPitchWheel(uint8_t channel, uint16_t amount) {
kshoji 0:83889dc90473 405 sendMidiMessage(0xe0 | (channel & 0xf), amount & 0x7f, (amount >> 7) & 0x7f);
kshoji 0:83889dc90473 406 }
kshoji 0:83889dc90473 407 void BLEMIDI::sendSongPositionPointer(uint16_t position) {
kshoji 0:83889dc90473 408 sendMidiMessage(0xf2, position & 0x7f, (position >> 7) & 0x7f);
kshoji 0:83889dc90473 409 }
kshoji 0:83889dc90473 410 void BLEMIDI::sendSystemExclusive(uint8_t * sysex, uint16_t length) {
kshoji 0:83889dc90473 411 if (isConnected) {
kshoji 0:83889dc90473 412 uint8_t position = 0;
kshoji 0:83889dc90473 413
kshoji 0:83889dc90473 414 // header
kshoji 1:cba2eba64f5c 415 uint16_t ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 416 midi[position++] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 417 midi[position++] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 418
kshoji 0:83889dc90473 419 for (int i = 0; i < length; i++) {
kshoji 0:83889dc90473 420 if (i == length - 1) {
kshoji 1:cba2eba64f5c 421 // modify last byte
kshoji 1:cba2eba64f5c 422 midi[position++] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 423
kshoji 0:83889dc90473 424 if (position == 20) {
kshoji 0:83889dc90473 425 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 20);
kshoji 0:83889dc90473 426
kshoji 0:83889dc90473 427 position = 0;
kshoji 0:83889dc90473 428 // header
kshoji 0:83889dc90473 429 midi[position++] = 0x80 | (ticks >> 7) & 0x3f;
kshoji 0:83889dc90473 430 }
kshoji 0:83889dc90473 431 }
kshoji 0:83889dc90473 432 midi[position++] = sysex[i];
kshoji 0:83889dc90473 433 if (position == 20) {
kshoji 0:83889dc90473 434 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 20);
kshoji 0:83889dc90473 435
kshoji 0:83889dc90473 436 position = 0;
kshoji 0:83889dc90473 437 // header
kshoji 0:83889dc90473 438 midi[position++] = 0x80 | (ticks >> 7) & 0x3f;
kshoji 0:83889dc90473 439 }
kshoji 0:83889dc90473 440
kshoji 0:83889dc90473 441 ticks = tick.read_ms() & 0x1fff;
kshoji 0:83889dc90473 442 }
kshoji 0:83889dc90473 443
kshoji 0:83889dc90473 444 if (position > 0) {
kshoji 0:83889dc90473 445 // send remains
kshoji 0:83889dc90473 446 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, position);
kshoji 0:83889dc90473 447 }
kshoji 0:83889dc90473 448 }
kshoji 0:83889dc90473 449 }