]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/USBHost/USBHostMIDI/USBHostMIDI.cpp
Merge commit 'fdc38ef3f92af7adeeb4de49550d8838c8a39b5c'
[max/tmk_keyboard.git] / tmk_core / tool / mbed / mbed-sdk / libraries / USBHost / USBHostMIDI / USBHostMIDI.cpp
1 /* Copyright (c) 2014 mbed.org, MIT License
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4  * and associated documentation files (the "Software"), to deal in the Software without
5  * restriction, including without limitation the rights to use, copy, modify, merge, publish,
6  * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7  * Software is furnished to do so, subject to the following conditions:
8  *
9  * The above copyright notice and this permission notice shall be included in all copies or
10  * substantial portions of the Software.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17  */
18
19 #include "USBHostMIDI.h"
20
21 #if USBHOST_MIDI
22
23 #include "dbg.h"
24
25 #define SET_LINE_CODING 0x20
26
27 USBHostMIDI::USBHostMIDI() {
28     host = USBHost::getHostInst();
29     size_bulk_in = 0;
30     size_bulk_out = 0;
31     init();
32 }
33
34 void USBHostMIDI::init() {
35     dev = NULL;
36     bulk_in = NULL;
37     bulk_out = NULL;
38     dev_connected = false;
39     midi_intf = -1;
40     midi_device_found = false;
41     sysExBufferPos = 0;
42 }
43
44 bool USBHostMIDI::connected() {
45     return dev_connected;
46 }
47
48 bool USBHostMIDI::connect() {
49     if (dev_connected) {
50         return true;
51     }
52
53     for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
54         if ((dev = host->getDevice(i)) != NULL) {
55             
56             USB_DBG("Trying to connect MIDI device\r\n");
57
58             if (host->enumerate(dev, this)) {
59                 break;
60             }
61             
62             if (midi_device_found) {
63                 bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN);
64                 bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT);
65                 
66                 if (!bulk_in || !bulk_out) {
67                     break;
68                 }
69                 
70                 USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf);
71                 dev->setName("MIDI", midi_intf);
72                 host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init);
73                 
74                 size_bulk_in = bulk_in->getSize();
75                 size_bulk_out = bulk_out->getSize();
76                 
77                 bulk_in->attach(this, &USBHostMIDI::rxHandler);
78                 
79                 host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
80                 dev_connected = true;
81                 return true;
82             }
83         }
84     }
85
86     init();
87     return false;
88 }
89
90 void USBHostMIDI::rxHandler() {
91     uint8_t *midi;
92     if (bulk_in) {
93         int length = bulk_in->getLengthTransferred();
94         if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) {
95             // MIDI event handling
96             for (int i = 0; i < length; i += 4) {
97                 if (i + 4 > length) {
98                     // length shortage, ignored.
99                     break;
100                 }
101
102                 // read each four bytes
103                 midi = &buf[i];
104                 // process MIDI message
105                 // switch by code index number
106                 switch (midi[0] & 0xf) {
107                     case 0: // miscellaneous function codes
108                         miscellaneousFunctionCode(midi[1], midi[2], midi[3]);
109                         break;
110                     case 1: // cable events
111                         cableEvent(midi[1], midi[2], midi[3]);
112                         break;
113                     case 2: // two bytes system common messages 
114                         systemCommonTwoBytes(midi[1], midi[2]);
115                         break;
116                     case 3: // three bytes system common messages 
117                         systemCommonThreeBytes(midi[1], midi[2], midi[3]);
118                         break;
119                     case 4: // SysEx starts or continues
120                         sysExBuffer[sysExBufferPos++] = midi[1];
121                         if (sysExBufferPos >= 64) {
122                             systemExclusive(sysExBuffer, sysExBufferPos, true);
123                             sysExBufferPos = 0;
124                         }
125                         sysExBuffer[sysExBufferPos++] = midi[2];
126                         if (sysExBufferPos >= 64) {
127                             systemExclusive(sysExBuffer, sysExBufferPos, true);
128                             sysExBufferPos = 0;
129                         }
130                         sysExBuffer[sysExBufferPos++] = midi[3];
131                         // SysEx continues. don't send
132                         break;
133                     case 5: // SysEx ends with single byte
134                         sysExBuffer[sysExBufferPos++] = midi[1];
135                         systemExclusive(sysExBuffer, sysExBufferPos, false);
136                         sysExBufferPos = 0;
137                         break;
138                     case 6: // SysEx ends with two bytes
139                         sysExBuffer[sysExBufferPos++] = midi[1];
140                         if (sysExBufferPos >= 64) {
141                             systemExclusive(sysExBuffer, sysExBufferPos, true);
142                             sysExBufferPos = 0;
143                         }
144                         sysExBuffer[sysExBufferPos++] = midi[2];
145                         systemExclusive(sysExBuffer, sysExBufferPos, false);
146                         sysExBufferPos = 0;
147                         break;
148                     case 7: // SysEx ends with three bytes
149                         sysExBuffer[sysExBufferPos++] = midi[1];
150                         if (sysExBufferPos >= 64) {
151                             systemExclusive(sysExBuffer, sysExBufferPos, true);
152                             sysExBufferPos = 0;
153                         }
154                         sysExBuffer[sysExBufferPos++] = midi[2];
155                         if (sysExBufferPos >= 64) {
156                             systemExclusive(sysExBuffer, sysExBufferPos, true);
157                             sysExBufferPos = 0;
158                         }
159                         sysExBuffer[sysExBufferPos++] = midi[3];
160                         systemExclusive(sysExBuffer, sysExBufferPos, false);
161                         sysExBufferPos = 0;
162                         break;
163                     case 8:
164                         noteOff(midi[1] & 0xf, midi[2], midi[3]);
165                         break;
166                     case 9:
167                         if (midi[3]) {
168                             noteOn(midi[1] & 0xf, midi[2], midi[3]);
169                         } else {
170                             noteOff(midi[1] & 0xf, midi[2], midi[3]);
171                         }
172                         break;
173                     case 10:
174                         polyKeyPress(midi[1] & 0xf, midi[2], midi[3]);
175                         break;
176                     case 11:
177                         controlChange(midi[1] & 0xf, midi[2], midi[3]);
178                         break;
179                     case 12:
180                         programChange(midi[1] & 0xf, midi[2]);
181                         break;
182                     case 13:
183                         channelPressure(midi[1] & 0xf, midi[2]);
184                         break;
185                     case 14:
186                         pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7));
187                         break;
188                     case 15:
189                         singleByte(midi[1]);
190                         break;
191                 }
192             }
193             
194             // read another message
195             host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
196         }
197     }
198 }
199
200 bool USBHostMIDI::sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) {
201     if (bulk_out) {
202         uint8_t midi[4];
203
204         midi[0] = data0;
205         midi[1] = data1;
206         midi[2] = data2;
207         midi[3] = data3;
208         if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) {
209             return true;
210         }
211     }
212     return false;
213 }
214
215 bool USBHostMIDI::sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3) {
216     return sendMidiBuffer(0, data1, data2, data3);
217 }
218
219 bool USBHostMIDI::sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3) {
220     return sendMidiBuffer(1, data1, data2, data3);
221 }
222
223 bool USBHostMIDI::sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2) {
224     return sendMidiBuffer(2, data1, data2, 0);
225 }
226
227 bool USBHostMIDI::sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3) {
228     return sendMidiBuffer(3, data1, data2, 0);
229 }
230
231 bool USBHostMIDI::sendSystemExclusive(uint8_t *buffer, int length) {
232     uint8_t midi[64];
233     int midiLength;
234     int midiPos;
235     if (bulk_out) {
236         for (int i = 0; i < length; i += 48) {
237             if (i + 48 >= length) {
238                 // contains last data
239                 midiLength = (((length - i) + 2) / 3) * 4;
240                 for (int pos = i; pos < length; pos += 3) {
241                     midiPos = (pos + 2) / 3 * 4;
242                     if (pos + 3 >= length) {
243                         // last data
244                         switch (pos % 3) {
245                             case 0:
246                                 midi[midiPos    ] = 7;
247                                 midi[midiPos + 1] = buffer[pos    ];
248                                 midi[midiPos + 2] = buffer[pos + 1];
249                                 midi[midiPos + 3] = buffer[pos + 2];
250                                 break;
251                             case 1:
252                                 midi[midiPos    ] = 5;
253                                 midi[midiPos + 1] = buffer[pos    ];
254                                 midi[midiPos + 2] = 0;
255                                 midi[midiPos + 3] = 0;
256                                break;
257                             case 2:
258                                 midi[midiPos    ] = 6;
259                                 midi[midiPos + 1] = buffer[pos    ];
260                                 midi[midiPos + 2] = buffer[pos + 1];
261                                 midi[midiPos + 3] = 0;
262                                 break;
263                         }
264                     } else {
265                         // has more data
266                         midi[midiPos    ] = 4;
267                         midi[midiPos + 1] = buffer[pos    ];
268                         midi[midiPos + 2] = buffer[pos + 1];
269                         midi[midiPos + 3] = buffer[pos + 2];
270                     }
271                 }
272             } else {
273                 // has more data
274                 midiLength = 64;
275                 for (int pos = i; pos < length; pos += 3) {
276                     midiPos = (pos + 2) / 3 * 4;
277                     midi[midiPos    ] = 4;
278                     midi[midiPos + 1] = buffer[pos    ];
279                     midi[midiPos + 2] = buffer[pos + 1];
280                     midi[midiPos + 3] = buffer[pos + 2];
281                 }
282             }
283
284             if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, midiLength) != USB_TYPE_OK) {
285                 return false;
286             }
287         }
288         return true;
289     }
290     return false;
291 }
292
293 bool USBHostMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
294     return sendMidiBuffer(8, channel & 0xf | 0x80, note & 0x7f, velocity & 0x7f);
295 }
296
297 bool USBHostMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
298     return sendMidiBuffer(9, channel & 0xf | 0x90, note & 0x7f, velocity & 0x7f);
299 }
300
301 bool USBHostMIDI::sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure) {
302     return sendMidiBuffer(10, channel & 0xf | 0xa0, note & 0x7f, pressure & 0x7f);
303 }
304
305 bool USBHostMIDI::sendControlChange(uint8_t channel, uint8_t key, uint8_t value) {
306     return sendMidiBuffer(11, channel & 0xf | 0xb0, key & 0x7f, value & 0x7f);
307 }
308
309 bool USBHostMIDI::sendProgramChange(uint8_t channel, uint8_t program) {
310     return sendMidiBuffer(12, channel & 0xf | 0xc0, program & 0x7f, 0);
311 }
312
313 bool USBHostMIDI::sendChannelPressure(uint8_t channel, uint8_t pressure) {
314     return sendMidiBuffer(13, channel & 0xf | 0xd0, pressure & 0x7f, 0);
315 }
316
317 bool USBHostMIDI::sendPitchBend(uint8_t channel, uint16_t value) {
318     return sendMidiBuffer(14, channel & 0xf | 0xe0, value & 0x7f, (value >> 7) & 0x7f);
319 }
320
321 bool USBHostMIDI::sendSingleByte(uint8_t data) {
322     return sendMidiBuffer(15, data, 0, 0);
323 }
324
325 /*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid)
326 {
327     // we don't check VID/PID for this driver
328 }
329
330 /*virtual*/ bool USBHostMIDI::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
331 {
332     // USB MIDI class/subclass
333     if ((midi_intf == -1) &&
334         (intf_class == AUDIO_CLASS) &&
335         (intf_subclass == 0x03)) {
336         midi_intf = intf_nb;
337         return true;
338     }
339     
340     // vendor specific device
341     if ((midi_intf == -1) &&
342         (intf_class == 0xff) &&
343         (intf_subclass == 0x03)) {
344         midi_intf = intf_nb;
345         return true;
346     }
347     
348     return false;
349 }
350
351 /*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
352 {
353     if (intf_nb == midi_intf) {
354         if (type == BULK_ENDPOINT) {
355             midi_device_found = true;
356             return true;
357         }
358     }
359     return false;
360 }
361
362 #endif