ump_convert.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Helpers for UMP <-> MIDI 1.0 byte stream conversion
  4. */
  5. #include <linux/module.h>
  6. #include <linux/export.h>
  7. #include <sound/core.h>
  8. #include <sound/asound.h>
  9. #include <sound/ump.h>
  10. #include <sound/ump_convert.h>
  11. /*
  12. * Upgrade / downgrade value bits
  13. */
  14. static u8 downscale_32_to_7bit(u32 src)
  15. {
  16. return src >> 25;
  17. }
  18. static u16 downscale_32_to_14bit(u32 src)
  19. {
  20. return src >> 18;
  21. }
  22. static u8 downscale_16_to_7bit(u16 src)
  23. {
  24. return src >> 9;
  25. }
  26. static u16 upscale_7_to_16bit(u8 src)
  27. {
  28. u16 val, repeat;
  29. val = (u16)src << 9;
  30. if (src <= 0x40)
  31. return val;
  32. repeat = src & 0x3f;
  33. return val | (repeat << 3) | (repeat >> 3);
  34. }
  35. static u32 upscale_7_to_32bit(u8 src)
  36. {
  37. u32 val, repeat;
  38. val = src << 25;
  39. if (src <= 0x40)
  40. return val;
  41. repeat = src & 0x3f;
  42. return val | (repeat << 19) | (repeat << 13) |
  43. (repeat << 7) | (repeat << 1) | (repeat >> 5);
  44. }
  45. static u32 upscale_14_to_32bit(u16 src)
  46. {
  47. u32 val, repeat;
  48. val = src << 18;
  49. if (src <= 0x2000)
  50. return val;
  51. repeat = src & 0x1fff;
  52. return val | (repeat << 5) | (repeat >> 8);
  53. }
  54. /*
  55. * UMP -> MIDI 1 byte stream conversion
  56. */
  57. /* convert a UMP System message to MIDI 1.0 byte stream */
  58. static int cvt_ump_system_to_legacy(u32 data, unsigned char *buf)
  59. {
  60. buf[0] = ump_message_status_channel(data);
  61. switch (ump_message_status_code(data)) {
  62. case UMP_SYSTEM_STATUS_MIDI_TIME_CODE:
  63. case UMP_SYSTEM_STATUS_SONG_SELECT:
  64. buf[1] = (data >> 8) & 0x7f;
  65. return 2;
  66. case UMP_SYSTEM_STATUS_SONG_POSITION:
  67. buf[1] = (data >> 8) & 0x7f;
  68. buf[2] = data & 0x7f;
  69. return 3;
  70. default:
  71. return 1;
  72. }
  73. }
  74. /* convert a UMP MIDI 1.0 Channel Voice message to MIDI 1.0 byte stream */
  75. static int cvt_ump_midi1_to_legacy(u32 data, unsigned char *buf)
  76. {
  77. buf[0] = ump_message_status_channel(data);
  78. buf[1] = (data >> 8) & 0xff;
  79. switch (ump_message_status_code(data)) {
  80. case UMP_MSG_STATUS_PROGRAM:
  81. case UMP_MSG_STATUS_CHANNEL_PRESSURE:
  82. return 2;
  83. default:
  84. buf[2] = data & 0xff;
  85. return 3;
  86. }
  87. }
  88. /* convert a UMP MIDI 2.0 Channel Voice message to MIDI 1.0 byte stream */
  89. static int cvt_ump_midi2_to_legacy(const union snd_ump_midi2_msg *midi2,
  90. unsigned char *buf)
  91. {
  92. unsigned char status = midi2->note.status;
  93. unsigned char channel = midi2->note.channel;
  94. u16 v;
  95. buf[0] = (status << 4) | channel;
  96. switch (status) {
  97. case UMP_MSG_STATUS_NOTE_OFF:
  98. case UMP_MSG_STATUS_NOTE_ON:
  99. buf[1] = midi2->note.note;
  100. buf[2] = downscale_16_to_7bit(midi2->note.velocity);
  101. if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2])
  102. buf[2] = 1;
  103. return 3;
  104. case UMP_MSG_STATUS_POLY_PRESSURE:
  105. buf[1] = midi2->paf.note;
  106. buf[2] = downscale_32_to_7bit(midi2->paf.data);
  107. return 3;
  108. case UMP_MSG_STATUS_CC:
  109. buf[1] = midi2->cc.index;
  110. buf[2] = downscale_32_to_7bit(midi2->cc.data);
  111. return 3;
  112. case UMP_MSG_STATUS_CHANNEL_PRESSURE:
  113. buf[1] = downscale_32_to_7bit(midi2->caf.data);
  114. return 2;
  115. case UMP_MSG_STATUS_PROGRAM:
  116. if (midi2->pg.bank_valid) {
  117. buf[0] = channel | (UMP_MSG_STATUS_CC << 4);
  118. buf[1] = UMP_CC_BANK_SELECT;
  119. buf[2] = midi2->pg.bank_msb;
  120. buf[3] = channel | (UMP_MSG_STATUS_CC << 4);
  121. buf[4] = UMP_CC_BANK_SELECT_LSB;
  122. buf[5] = midi2->pg.bank_lsb;
  123. buf[6] = channel | (UMP_MSG_STATUS_PROGRAM << 4);
  124. buf[7] = midi2->pg.program;
  125. return 8;
  126. }
  127. buf[1] = midi2->pg.program;
  128. return 2;
  129. case UMP_MSG_STATUS_PITCH_BEND:
  130. v = downscale_32_to_14bit(midi2->pb.data);
  131. buf[1] = v & 0x7f;
  132. buf[2] = v >> 7;
  133. return 3;
  134. case UMP_MSG_STATUS_RPN:
  135. case UMP_MSG_STATUS_NRPN:
  136. buf[0] = channel | (UMP_MSG_STATUS_CC << 4);
  137. buf[1] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB;
  138. buf[2] = midi2->rpn.bank;
  139. buf[3] = buf[0];
  140. buf[4] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB;
  141. buf[5] = midi2->rpn.index;
  142. buf[6] = buf[0];
  143. buf[7] = UMP_CC_DATA;
  144. v = downscale_32_to_14bit(midi2->rpn.data);
  145. buf[8] = v >> 7;
  146. buf[9] = buf[0];
  147. buf[10] = UMP_CC_DATA_LSB;
  148. buf[11] = v & 0x7f;
  149. return 12;
  150. default:
  151. return 0;
  152. }
  153. }
  154. /* convert a UMP 7-bit SysEx message to MIDI 1.0 byte stream */
  155. static int cvt_ump_sysex7_to_legacy(const u32 *data, unsigned char *buf)
  156. {
  157. unsigned char status;
  158. unsigned char bytes;
  159. int size, offset;
  160. status = ump_sysex_message_status(*data);
  161. if (status > UMP_SYSEX_STATUS_END)
  162. return 0; // unsupported, skip
  163. bytes = ump_sysex_message_length(*data);
  164. if (bytes > 6)
  165. return 0; // skip
  166. size = 0;
  167. if (status == UMP_SYSEX_STATUS_SINGLE ||
  168. status == UMP_SYSEX_STATUS_START) {
  169. buf[0] = UMP_MIDI1_MSG_SYSEX_START;
  170. size = 1;
  171. }
  172. offset = 8;
  173. for (; bytes; bytes--, size++) {
  174. buf[size] = (*data >> offset) & 0x7f;
  175. if (!offset) {
  176. offset = 24;
  177. data++;
  178. } else {
  179. offset -= 8;
  180. }
  181. }
  182. if (status == UMP_SYSEX_STATUS_SINGLE ||
  183. status == UMP_SYSEX_STATUS_END)
  184. buf[size++] = UMP_MIDI1_MSG_SYSEX_END;
  185. return size;
  186. }
  187. /**
  188. * snd_ump_convert_from_ump - convert from UMP to legacy MIDI
  189. * @data: UMP packet
  190. * @buf: buffer to store legacy MIDI data
  191. * @group_ret: pointer to store the target group
  192. *
  193. * Convert from a UMP packet @data to MIDI 1.0 bytes at @buf.
  194. * The target group is stored at @group_ret.
  195. *
  196. * The function returns the number of bytes of MIDI 1.0 stream.
  197. */
  198. int snd_ump_convert_from_ump(const u32 *data,
  199. unsigned char *buf,
  200. unsigned char *group_ret)
  201. {
  202. *group_ret = ump_message_group(*data);
  203. switch (ump_message_type(*data)) {
  204. case UMP_MSG_TYPE_SYSTEM:
  205. return cvt_ump_system_to_legacy(*data, buf);
  206. case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
  207. return cvt_ump_midi1_to_legacy(*data, buf);
  208. case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
  209. return cvt_ump_midi2_to_legacy((const union snd_ump_midi2_msg *)data,
  210. buf);
  211. case UMP_MSG_TYPE_DATA:
  212. return cvt_ump_sysex7_to_legacy(data, buf);
  213. }
  214. return 0;
  215. }
  216. EXPORT_SYMBOL_GPL(snd_ump_convert_from_ump);
  217. /*
  218. * MIDI 1 byte stream -> UMP conversion
  219. */
  220. /* convert MIDI 1.0 SysEx to a UMP packet */
  221. static int cvt_legacy_sysex_to_ump(struct ump_cvt_to_ump *cvt,
  222. unsigned char group, u32 *data, bool finish)
  223. {
  224. unsigned char status;
  225. bool start = cvt->in_sysex == 1;
  226. int i, offset;
  227. if (start && finish)
  228. status = UMP_SYSEX_STATUS_SINGLE;
  229. else if (start)
  230. status = UMP_SYSEX_STATUS_START;
  231. else if (finish)
  232. status = UMP_SYSEX_STATUS_END;
  233. else
  234. status = UMP_SYSEX_STATUS_CONTINUE;
  235. *data = ump_compose(UMP_MSG_TYPE_DATA, group, status, cvt->len);
  236. offset = 8;
  237. for (i = 0; i < cvt->len; i++) {
  238. *data |= cvt->buf[i] << offset;
  239. if (!offset) {
  240. offset = 24;
  241. data++;
  242. } else
  243. offset -= 8;
  244. }
  245. cvt->len = 0;
  246. if (finish)
  247. cvt->in_sysex = 0;
  248. else
  249. cvt->in_sysex++;
  250. return 8;
  251. }
  252. /* convert to a UMP System message */
  253. static int cvt_legacy_system_to_ump(struct ump_cvt_to_ump *cvt,
  254. unsigned char group, u32 *data)
  255. {
  256. data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, cvt->buf[0]);
  257. if (cvt->cmd_bytes > 1)
  258. data[0] |= cvt->buf[1] << 8;
  259. if (cvt->cmd_bytes > 2)
  260. data[0] |= cvt->buf[2];
  261. return 4;
  262. }
  263. static void reset_rpn(struct ump_cvt_to_ump_bank *cc)
  264. {
  265. cc->rpn_set = 0;
  266. cc->nrpn_set = 0;
  267. cc->cc_rpn_msb = cc->cc_rpn_lsb = 0;
  268. cc->cc_data_msb = cc->cc_data_lsb = 0;
  269. cc->cc_data_msb_set = cc->cc_data_lsb_set = 0;
  270. }
  271. static int fill_rpn(struct ump_cvt_to_ump_bank *cc,
  272. union snd_ump_midi2_msg *midi2,
  273. bool flush)
  274. {
  275. if (!(cc->cc_data_lsb_set || cc->cc_data_msb_set))
  276. return 0; // skip
  277. /* when not flushing, wait for complete data set */
  278. if (!flush && (!cc->cc_data_lsb_set || !cc->cc_data_msb_set))
  279. return 0; // skip
  280. if (cc->rpn_set) {
  281. midi2->rpn.status = UMP_MSG_STATUS_RPN;
  282. midi2->rpn.bank = cc->cc_rpn_msb;
  283. midi2->rpn.index = cc->cc_rpn_lsb;
  284. } else if (cc->nrpn_set) {
  285. midi2->rpn.status = UMP_MSG_STATUS_NRPN;
  286. midi2->rpn.bank = cc->cc_nrpn_msb;
  287. midi2->rpn.index = cc->cc_nrpn_lsb;
  288. } else {
  289. return 0; // skip
  290. }
  291. midi2->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) |
  292. cc->cc_data_lsb);
  293. reset_rpn(cc);
  294. return 1;
  295. }
  296. /* convert to a MIDI 1.0 Channel Voice message */
  297. static int cvt_legacy_cmd_to_ump(struct ump_cvt_to_ump *cvt,
  298. unsigned char group,
  299. unsigned int protocol,
  300. u32 *data, unsigned char bytes)
  301. {
  302. const unsigned char *buf = cvt->buf;
  303. struct ump_cvt_to_ump_bank *cc;
  304. union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)data;
  305. unsigned char status, channel;
  306. int ret;
  307. BUILD_BUG_ON(sizeof(union snd_ump_midi1_msg) != 4);
  308. BUILD_BUG_ON(sizeof(union snd_ump_midi2_msg) != 8);
  309. /* for MIDI 1.0 UMP, it's easy, just pack it into UMP */
  310. if (protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI1) {
  311. data[0] = ump_compose(UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE,
  312. group, 0, buf[0]);
  313. data[0] |= buf[1] << 8;
  314. if (bytes > 2)
  315. data[0] |= buf[2];
  316. return 4;
  317. }
  318. status = *buf >> 4;
  319. channel = *buf & 0x0f;
  320. cc = &cvt->bank[channel];
  321. /* special handling: treat note-on with 0 velocity as note-off */
  322. if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2])
  323. status = UMP_MSG_STATUS_NOTE_OFF;
  324. /* initialize the packet */
  325. data[0] = ump_compose(UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE,
  326. group, status, channel);
  327. data[1] = 0;
  328. switch (status) {
  329. case UMP_MSG_STATUS_NOTE_ON:
  330. case UMP_MSG_STATUS_NOTE_OFF:
  331. midi2->note.note = buf[1];
  332. midi2->note.velocity = upscale_7_to_16bit(buf[2]);
  333. break;
  334. case UMP_MSG_STATUS_POLY_PRESSURE:
  335. midi2->paf.note = buf[1];
  336. midi2->paf.data = upscale_7_to_32bit(buf[2]);
  337. break;
  338. case UMP_MSG_STATUS_CC:
  339. switch (buf[1]) {
  340. case UMP_CC_RPN_MSB:
  341. ret = fill_rpn(cc, midi2, true);
  342. cc->rpn_set = 1;
  343. cc->cc_rpn_msb = buf[2];
  344. if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
  345. reset_rpn(cc);
  346. return ret;
  347. case UMP_CC_RPN_LSB:
  348. ret = fill_rpn(cc, midi2, true);
  349. cc->rpn_set = 1;
  350. cc->cc_rpn_lsb = buf[2];
  351. if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
  352. reset_rpn(cc);
  353. return ret;
  354. case UMP_CC_NRPN_MSB:
  355. ret = fill_rpn(cc, midi2, true);
  356. cc->nrpn_set = 1;
  357. cc->cc_nrpn_msb = buf[2];
  358. return ret;
  359. case UMP_CC_NRPN_LSB:
  360. ret = fill_rpn(cc, midi2, true);
  361. cc->nrpn_set = 1;
  362. cc->cc_nrpn_lsb = buf[2];
  363. return ret;
  364. case UMP_CC_DATA:
  365. cc->cc_data_msb_set = 1;
  366. cc->cc_data_msb = buf[2];
  367. return fill_rpn(cc, midi2, false);
  368. case UMP_CC_BANK_SELECT:
  369. cc->bank_set = 1;
  370. cc->cc_bank_msb = buf[2];
  371. return 0; // skip
  372. case UMP_CC_BANK_SELECT_LSB:
  373. cc->bank_set = 1;
  374. cc->cc_bank_lsb = buf[2];
  375. return 0; // skip
  376. case UMP_CC_DATA_LSB:
  377. cc->cc_data_lsb_set = 1;
  378. cc->cc_data_lsb = buf[2];
  379. return fill_rpn(cc, midi2, false);
  380. default:
  381. midi2->cc.index = buf[1];
  382. midi2->cc.data = upscale_7_to_32bit(buf[2]);
  383. break;
  384. }
  385. break;
  386. case UMP_MSG_STATUS_PROGRAM:
  387. midi2->pg.program = buf[1];
  388. if (cc->bank_set) {
  389. midi2->pg.bank_valid = 1;
  390. midi2->pg.bank_msb = cc->cc_bank_msb;
  391. midi2->pg.bank_lsb = cc->cc_bank_lsb;
  392. cc->bank_set = 0;
  393. }
  394. break;
  395. case UMP_MSG_STATUS_CHANNEL_PRESSURE:
  396. midi2->caf.data = upscale_7_to_32bit(buf[1]);
  397. break;
  398. case UMP_MSG_STATUS_PITCH_BEND:
  399. midi2->pb.data = upscale_14_to_32bit(buf[1] | (buf[2] << 7));
  400. break;
  401. default:
  402. return 0;
  403. }
  404. return 8;
  405. }
  406. static int do_convert_to_ump(struct ump_cvt_to_ump *cvt, unsigned char group,
  407. unsigned int protocol, unsigned char c, u32 *data)
  408. {
  409. /* bytes for 0x80-0xf0 */
  410. static unsigned char cmd_bytes[8] = {
  411. 3, 3, 3, 3, 2, 2, 3, 0
  412. };
  413. /* bytes for 0xf0-0xff */
  414. static unsigned char system_bytes[16] = {
  415. 0, 2, 3, 2, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1
  416. };
  417. unsigned char bytes;
  418. if (c == UMP_MIDI1_MSG_SYSEX_START) {
  419. cvt->in_sysex = 1;
  420. cvt->len = 0;
  421. return 0;
  422. }
  423. if (c == UMP_MIDI1_MSG_SYSEX_END) {
  424. if (!cvt->in_sysex)
  425. return 0; /* skip */
  426. return cvt_legacy_sysex_to_ump(cvt, group, data, true);
  427. }
  428. if ((c & 0xf0) == UMP_MIDI1_MSG_REALTIME) {
  429. bytes = system_bytes[c & 0x0f];
  430. if (!bytes)
  431. return 0; /* skip */
  432. if (bytes == 1) {
  433. data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, c);
  434. return 4;
  435. }
  436. cvt->buf[0] = c;
  437. cvt->len = 1;
  438. cvt->cmd_bytes = bytes;
  439. cvt->in_sysex = 0; /* abort SysEx */
  440. return 0;
  441. }
  442. if (c & 0x80) {
  443. bytes = cmd_bytes[(c >> 4) & 7];
  444. cvt->buf[0] = c;
  445. cvt->len = 1;
  446. cvt->cmd_bytes = bytes;
  447. cvt->in_sysex = 0; /* abort SysEx */
  448. return 0;
  449. }
  450. if (cvt->in_sysex) {
  451. cvt->buf[cvt->len++] = c;
  452. if (cvt->len == 6)
  453. return cvt_legacy_sysex_to_ump(cvt, group, data, false);
  454. return 0;
  455. }
  456. if (!cvt->len)
  457. return 0;
  458. cvt->buf[cvt->len++] = c;
  459. if (cvt->len < cvt->cmd_bytes)
  460. return 0;
  461. cvt->len = 1;
  462. if ((cvt->buf[0] & 0xf0) == UMP_MIDI1_MSG_REALTIME)
  463. return cvt_legacy_system_to_ump(cvt, group, data);
  464. return cvt_legacy_cmd_to_ump(cvt, group, protocol, data, cvt->cmd_bytes);
  465. }
  466. /**
  467. * snd_ump_convert_to_ump - convert legacy MIDI byte to UMP packet
  468. * @cvt: converter context
  469. * @group: target UMP group
  470. * @protocol: target UMP protocol
  471. * @c: MIDI 1.0 byte data
  472. *
  473. * Feed a MIDI 1.0 byte @c and convert to a UMP packet if completed.
  474. * The result is stored in the buffer in @cvt.
  475. */
  476. void snd_ump_convert_to_ump(struct ump_cvt_to_ump *cvt, unsigned char group,
  477. unsigned int protocol, unsigned char c)
  478. {
  479. cvt->ump_bytes = do_convert_to_ump(cvt, group, protocol, c, cvt->ump);
  480. }
  481. EXPORT_SYMBOL_GPL(snd_ump_convert_to_ump);