Keyboard firmwares for Atmel AVR and Cortex-M
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

USBHostMIDI.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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. #include "USBHostMIDI.h"
  19. #if USBHOST_MIDI
  20. #include "dbg.h"
  21. #define SET_LINE_CODING 0x20
  22. USBHostMIDI::USBHostMIDI() {
  23. host = USBHost::getHostInst();
  24. size_bulk_in = 0;
  25. size_bulk_out = 0;
  26. init();
  27. }
  28. void USBHostMIDI::init() {
  29. dev = NULL;
  30. bulk_in = NULL;
  31. bulk_out = NULL;
  32. dev_connected = false;
  33. midi_intf = -1;
  34. midi_device_found = false;
  35. sysExBufferPos = 0;
  36. }
  37. bool USBHostMIDI::connected() {
  38. return dev_connected;
  39. }
  40. bool USBHostMIDI::connect() {
  41. if (dev_connected) {
  42. return true;
  43. }
  44. for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
  45. if ((dev = host->getDevice(i)) != NULL) {
  46. USB_DBG("Trying to connect MIDI device\r\n");
  47. if (host->enumerate(dev, this)) {
  48. break;
  49. }
  50. if (midi_device_found) {
  51. bulk_in = dev->getEndpoint(midi_intf, BULK_ENDPOINT, IN);
  52. bulk_out = dev->getEndpoint(midi_intf, BULK_ENDPOINT, OUT);
  53. if (!bulk_in || !bulk_out) {
  54. break;
  55. }
  56. USB_INFO("New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, midi_intf);
  57. dev->setName("MIDI", midi_intf);
  58. host->registerDriver(dev, midi_intf, this, &USBHostMIDI::init);
  59. size_bulk_in = bulk_in->getSize();
  60. size_bulk_out = bulk_out->getSize();
  61. bulk_in->attach(this, &USBHostMIDI::rxHandler);
  62. host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
  63. dev_connected = true;
  64. return true;
  65. }
  66. }
  67. }
  68. init();
  69. return false;
  70. }
  71. void USBHostMIDI::rxHandler() {
  72. uint8_t *midi;
  73. if (bulk_in) {
  74. int length = bulk_in->getLengthTransferred();
  75. if (bulk_in->getState() == USB_TYPE_IDLE || bulk_in->getState() == USB_TYPE_FREE) {
  76. // MIDI event handling
  77. for (int i = 0; i < length; i += 4) {
  78. if (i + 4 > length) {
  79. // length shortage, ignored.
  80. break;
  81. }
  82. // read each four bytes
  83. midi = &buf[i];
  84. // process MIDI message
  85. // switch by code index number
  86. switch (midi[0] & 0xf) {
  87. case 0: // miscellaneous function codes
  88. miscellaneousFunctionCode(midi[1], midi[2], midi[3]);
  89. break;
  90. case 1: // cable events
  91. cableEvent(midi[1], midi[2], midi[3]);
  92. break;
  93. case 2: // two bytes system common messages
  94. systemCommonTwoBytes(midi[1], midi[2]);
  95. break;
  96. case 3: // three bytes system common messages
  97. systemCommonThreeBytes(midi[1], midi[2], midi[3]);
  98. break;
  99. case 4: // SysEx starts or continues
  100. sysExBuffer[sysExBufferPos++] = midi[1];
  101. if (sysExBufferPos >= 64) {
  102. systemExclusive(sysExBuffer, sysExBufferPos, true);
  103. sysExBufferPos = 0;
  104. }
  105. sysExBuffer[sysExBufferPos++] = midi[2];
  106. if (sysExBufferPos >= 64) {
  107. systemExclusive(sysExBuffer, sysExBufferPos, true);
  108. sysExBufferPos = 0;
  109. }
  110. sysExBuffer[sysExBufferPos++] = midi[3];
  111. // SysEx continues. don't send
  112. break;
  113. case 5: // SysEx ends with single byte
  114. sysExBuffer[sysExBufferPos++] = midi[1];
  115. systemExclusive(sysExBuffer, sysExBufferPos, false);
  116. sysExBufferPos = 0;
  117. break;
  118. case 6: // SysEx ends with two bytes
  119. sysExBuffer[sysExBufferPos++] = midi[1];
  120. if (sysExBufferPos >= 64) {
  121. systemExclusive(sysExBuffer, sysExBufferPos, true);
  122. sysExBufferPos = 0;
  123. }
  124. sysExBuffer[sysExBufferPos++] = midi[2];
  125. systemExclusive(sysExBuffer, sysExBufferPos, false);
  126. sysExBufferPos = 0;
  127. break;
  128. case 7: // SysEx ends with three bytes
  129. sysExBuffer[sysExBufferPos++] = midi[1];
  130. if (sysExBufferPos >= 64) {
  131. systemExclusive(sysExBuffer, sysExBufferPos, true);
  132. sysExBufferPos = 0;
  133. }
  134. sysExBuffer[sysExBufferPos++] = midi[2];
  135. if (sysExBufferPos >= 64) {
  136. systemExclusive(sysExBuffer, sysExBufferPos, true);
  137. sysExBufferPos = 0;
  138. }
  139. sysExBuffer[sysExBufferPos++] = midi[3];
  140. systemExclusive(sysExBuffer, sysExBufferPos, false);
  141. sysExBufferPos = 0;
  142. break;
  143. case 8:
  144. noteOff(midi[1] & 0xf, midi[2], midi[3]);
  145. break;
  146. case 9:
  147. if (midi[3]) {
  148. noteOn(midi[1] & 0xf, midi[2], midi[3]);
  149. } else {
  150. noteOff(midi[1] & 0xf, midi[2], midi[3]);
  151. }
  152. break;
  153. case 10:
  154. polyKeyPress(midi[1] & 0xf, midi[2], midi[3]);
  155. break;
  156. case 11:
  157. controlChange(midi[1] & 0xf, midi[2], midi[3]);
  158. break;
  159. case 12:
  160. programChange(midi[1] & 0xf, midi[2]);
  161. break;
  162. case 13:
  163. channelPressure(midi[1] & 0xf, midi[2]);
  164. break;
  165. case 14:
  166. pitchBend(midi[1] & 0xf, midi[2] | (midi[3] << 7));
  167. break;
  168. case 15:
  169. singleByte(midi[1]);
  170. break;
  171. }
  172. }
  173. // read another message
  174. host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
  175. }
  176. }
  177. }
  178. bool USBHostMIDI::sendMidiBuffer(uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) {
  179. if (bulk_out) {
  180. uint8_t midi[4];
  181. midi[0] = data0;
  182. midi[1] = data1;
  183. midi[2] = data2;
  184. midi[3] = data3;
  185. if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, 4) == USB_TYPE_OK) {
  186. return true;
  187. }
  188. }
  189. return false;
  190. }
  191. bool USBHostMIDI::sendMiscellaneousFunctionCode(uint8_t data1, uint8_t data2, uint8_t data3) {
  192. return sendMidiBuffer(0, data1, data2, data3);
  193. }
  194. bool USBHostMIDI::sendCableEvent(uint8_t data1, uint8_t data2, uint8_t data3) {
  195. return sendMidiBuffer(1, data1, data2, data3);
  196. }
  197. bool USBHostMIDI::sendSystemCommmonTwoBytes(uint8_t data1, uint8_t data2) {
  198. return sendMidiBuffer(2, data1, data2, 0);
  199. }
  200. bool USBHostMIDI::sendSystemCommmonThreeBytes(uint8_t data1, uint8_t data2, uint8_t data3) {
  201. return sendMidiBuffer(3, data1, data2, 0);
  202. }
  203. bool USBHostMIDI::sendSystemExclusive(uint8_t *buffer, int length) {
  204. uint8_t midi[64];
  205. int midiLength;
  206. int midiPos;
  207. if (bulk_out) {
  208. for (int i = 0; i < length; i += 48) {
  209. if (i + 48 >= length) {
  210. // contains last data
  211. midiLength = (((length - i) + 2) / 3) * 4;
  212. for (int pos = i; pos < length; pos += 3) {
  213. midiPos = (pos + 2) / 3 * 4;
  214. if (pos + 3 >= length) {
  215. // last data
  216. switch (pos % 3) {
  217. case 0:
  218. midi[midiPos ] = 7;
  219. midi[midiPos + 1] = buffer[pos ];
  220. midi[midiPos + 2] = buffer[pos + 1];
  221. midi[midiPos + 3] = buffer[pos + 2];
  222. break;
  223. case 1:
  224. midi[midiPos ] = 5;
  225. midi[midiPos + 1] = buffer[pos ];
  226. midi[midiPos + 2] = 0;
  227. midi[midiPos + 3] = 0;
  228. break;
  229. case 2:
  230. midi[midiPos ] = 6;
  231. midi[midiPos + 1] = buffer[pos ];
  232. midi[midiPos + 2] = buffer[pos + 1];
  233. midi[midiPos + 3] = 0;
  234. break;
  235. }
  236. } else {
  237. // has more data
  238. midi[midiPos ] = 4;
  239. midi[midiPos + 1] = buffer[pos ];
  240. midi[midiPos + 2] = buffer[pos + 1];
  241. midi[midiPos + 3] = buffer[pos + 2];
  242. }
  243. }
  244. } else {
  245. // has more data
  246. midiLength = 64;
  247. for (int pos = i; pos < length; pos += 3) {
  248. midiPos = (pos + 2) / 3 * 4;
  249. midi[midiPos ] = 4;
  250. midi[midiPos + 1] = buffer[pos ];
  251. midi[midiPos + 2] = buffer[pos + 1];
  252. midi[midiPos + 3] = buffer[pos + 2];
  253. }
  254. }
  255. if (host->bulkWrite(dev, bulk_out, (uint8_t *)midi, midiLength) != USB_TYPE_OK) {
  256. return false;
  257. }
  258. }
  259. return true;
  260. }
  261. return false;
  262. }
  263. bool USBHostMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
  264. return sendMidiBuffer(8, channel & 0xf | 0x80, note & 0x7f, velocity & 0x7f);
  265. }
  266. bool USBHostMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
  267. return sendMidiBuffer(9, channel & 0xf | 0x90, note & 0x7f, velocity & 0x7f);
  268. }
  269. bool USBHostMIDI::sendPolyKeyPress(uint8_t channel, uint8_t note, uint8_t pressure) {
  270. return sendMidiBuffer(10, channel & 0xf | 0xa0, note & 0x7f, pressure & 0x7f);
  271. }
  272. bool USBHostMIDI::sendControlChange(uint8_t channel, uint8_t key, uint8_t value) {
  273. return sendMidiBuffer(11, channel & 0xf | 0xb0, key & 0x7f, value & 0x7f);
  274. }
  275. bool USBHostMIDI::sendProgramChange(uint8_t channel, uint8_t program) {
  276. return sendMidiBuffer(12, channel & 0xf | 0xc0, program & 0x7f, 0);
  277. }
  278. bool USBHostMIDI::sendChannelPressure(uint8_t channel, uint8_t pressure) {
  279. return sendMidiBuffer(13, channel & 0xf | 0xd0, pressure & 0x7f, 0);
  280. }
  281. bool USBHostMIDI::sendPitchBend(uint8_t channel, uint16_t value) {
  282. return sendMidiBuffer(14, channel & 0xf | 0xe0, value & 0x7f, (value >> 7) & 0x7f);
  283. }
  284. bool USBHostMIDI::sendSingleByte(uint8_t data) {
  285. return sendMidiBuffer(15, data, 0, 0);
  286. }
  287. /*virtual*/ void USBHostMIDI::setVidPid(uint16_t vid, uint16_t pid)
  288. {
  289. // we don't check VID/PID for this driver
  290. }
  291. /*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
  292. {
  293. // USB MIDI class/subclass
  294. if ((midi_intf == -1) &&
  295. (intf_class == AUDIO_CLASS) &&
  296. (intf_subclass == 0x03)) {
  297. midi_intf = intf_nb;
  298. return true;
  299. }
  300. // vendor specific device
  301. if ((midi_intf == -1) &&
  302. (intf_class == 0xff) &&
  303. (intf_subclass == 0x03)) {
  304. midi_intf = intf_nb;
  305. return true;
  306. }
  307. return false;
  308. }
  309. /*virtual*/ bool USBHostMIDI::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
  310. {
  311. if (intf_nb == midi_intf) {
  312. if (type == BULK_ENDPOINT) {
  313. midi_device_found = true;
  314. return true;
  315. }
  316. }
  317. return false;
  318. }
  319. #endif