162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Helpers for UMP <-> MIDI 1.0 byte stream conversion 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/export.h> 862306a36Sopenharmony_ci#include <sound/core.h> 962306a36Sopenharmony_ci#include <sound/asound.h> 1062306a36Sopenharmony_ci#include <sound/ump.h> 1162306a36Sopenharmony_ci#include <sound/ump_convert.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * Upgrade / downgrade value bits 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_cistatic u8 downscale_32_to_7bit(u32 src) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci return src >> 25; 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic u16 downscale_32_to_14bit(u32 src) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return src >> 18; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic u8 downscale_16_to_7bit(u16 src) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci return src >> 9; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic u16 upscale_7_to_16bit(u8 src) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci u16 val, repeat; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci val = (u16)src << 9; 3662306a36Sopenharmony_ci if (src <= 0x40) 3762306a36Sopenharmony_ci return val; 3862306a36Sopenharmony_ci repeat = src & 0x3f; 3962306a36Sopenharmony_ci return val | (repeat << 3) | (repeat >> 3); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic u32 upscale_7_to_32bit(u8 src) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci u32 val, repeat; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci val = src << 25; 4762306a36Sopenharmony_ci if (src <= 0x40) 4862306a36Sopenharmony_ci return val; 4962306a36Sopenharmony_ci repeat = src & 0x3f; 5062306a36Sopenharmony_ci return val | (repeat << 19) | (repeat << 13) | 5162306a36Sopenharmony_ci (repeat << 7) | (repeat << 1) | (repeat >> 5); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic u32 upscale_14_to_32bit(u16 src) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci u32 val, repeat; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci val = src << 18; 5962306a36Sopenharmony_ci if (src <= 0x2000) 6062306a36Sopenharmony_ci return val; 6162306a36Sopenharmony_ci repeat = src & 0x1fff; 6262306a36Sopenharmony_ci return val | (repeat << 5) | (repeat >> 8); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * UMP -> MIDI 1 byte stream conversion 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci/* convert a UMP System message to MIDI 1.0 byte stream */ 6962306a36Sopenharmony_cistatic int cvt_ump_system_to_legacy(u32 data, unsigned char *buf) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci buf[0] = ump_message_status_channel(data); 7262306a36Sopenharmony_ci switch (ump_message_status_code(data)) { 7362306a36Sopenharmony_ci case UMP_SYSTEM_STATUS_MIDI_TIME_CODE: 7462306a36Sopenharmony_ci case UMP_SYSTEM_STATUS_SONG_SELECT: 7562306a36Sopenharmony_ci buf[1] = (data >> 8) & 0x7f; 7662306a36Sopenharmony_ci return 2; 7762306a36Sopenharmony_ci case UMP_SYSTEM_STATUS_SONG_POSITION: 7862306a36Sopenharmony_ci buf[1] = (data >> 8) & 0x7f; 7962306a36Sopenharmony_ci buf[2] = data & 0x7f; 8062306a36Sopenharmony_ci return 3; 8162306a36Sopenharmony_ci default: 8262306a36Sopenharmony_ci return 1; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* convert a UMP MIDI 1.0 Channel Voice message to MIDI 1.0 byte stream */ 8762306a36Sopenharmony_cistatic int cvt_ump_midi1_to_legacy(u32 data, unsigned char *buf) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci buf[0] = ump_message_status_channel(data); 9062306a36Sopenharmony_ci buf[1] = (data >> 8) & 0xff; 9162306a36Sopenharmony_ci switch (ump_message_status_code(data)) { 9262306a36Sopenharmony_ci case UMP_MSG_STATUS_PROGRAM: 9362306a36Sopenharmony_ci case UMP_MSG_STATUS_CHANNEL_PRESSURE: 9462306a36Sopenharmony_ci return 2; 9562306a36Sopenharmony_ci default: 9662306a36Sopenharmony_ci buf[2] = data & 0xff; 9762306a36Sopenharmony_ci return 3; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* convert a UMP MIDI 2.0 Channel Voice message to MIDI 1.0 byte stream */ 10262306a36Sopenharmony_cistatic int cvt_ump_midi2_to_legacy(const union snd_ump_midi2_msg *midi2, 10362306a36Sopenharmony_ci unsigned char *buf) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci unsigned char status = midi2->note.status; 10662306a36Sopenharmony_ci unsigned char channel = midi2->note.channel; 10762306a36Sopenharmony_ci u16 v; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci buf[0] = (status << 4) | channel; 11062306a36Sopenharmony_ci switch (status) { 11162306a36Sopenharmony_ci case UMP_MSG_STATUS_NOTE_OFF: 11262306a36Sopenharmony_ci case UMP_MSG_STATUS_NOTE_ON: 11362306a36Sopenharmony_ci buf[1] = midi2->note.note; 11462306a36Sopenharmony_ci buf[2] = downscale_16_to_7bit(midi2->note.velocity); 11562306a36Sopenharmony_ci if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2]) 11662306a36Sopenharmony_ci buf[2] = 1; 11762306a36Sopenharmony_ci return 3; 11862306a36Sopenharmony_ci case UMP_MSG_STATUS_POLY_PRESSURE: 11962306a36Sopenharmony_ci buf[1] = midi2->paf.note; 12062306a36Sopenharmony_ci buf[2] = downscale_32_to_7bit(midi2->paf.data); 12162306a36Sopenharmony_ci return 3; 12262306a36Sopenharmony_ci case UMP_MSG_STATUS_CC: 12362306a36Sopenharmony_ci buf[1] = midi2->cc.index; 12462306a36Sopenharmony_ci buf[2] = downscale_32_to_7bit(midi2->cc.data); 12562306a36Sopenharmony_ci return 3; 12662306a36Sopenharmony_ci case UMP_MSG_STATUS_CHANNEL_PRESSURE: 12762306a36Sopenharmony_ci buf[1] = downscale_32_to_7bit(midi2->caf.data); 12862306a36Sopenharmony_ci return 2; 12962306a36Sopenharmony_ci case UMP_MSG_STATUS_PROGRAM: 13062306a36Sopenharmony_ci if (midi2->pg.bank_valid) { 13162306a36Sopenharmony_ci buf[0] = channel | (UMP_MSG_STATUS_CC << 4); 13262306a36Sopenharmony_ci buf[1] = UMP_CC_BANK_SELECT; 13362306a36Sopenharmony_ci buf[2] = midi2->pg.bank_msb; 13462306a36Sopenharmony_ci buf[3] = channel | (UMP_MSG_STATUS_CC << 4); 13562306a36Sopenharmony_ci buf[4] = UMP_CC_BANK_SELECT_LSB; 13662306a36Sopenharmony_ci buf[5] = midi2->pg.bank_lsb; 13762306a36Sopenharmony_ci buf[6] = channel | (UMP_MSG_STATUS_PROGRAM << 4); 13862306a36Sopenharmony_ci buf[7] = midi2->pg.program; 13962306a36Sopenharmony_ci return 8; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci buf[1] = midi2->pg.program; 14262306a36Sopenharmony_ci return 2; 14362306a36Sopenharmony_ci case UMP_MSG_STATUS_PITCH_BEND: 14462306a36Sopenharmony_ci v = downscale_32_to_14bit(midi2->pb.data); 14562306a36Sopenharmony_ci buf[1] = v & 0x7f; 14662306a36Sopenharmony_ci buf[2] = v >> 7; 14762306a36Sopenharmony_ci return 3; 14862306a36Sopenharmony_ci case UMP_MSG_STATUS_RPN: 14962306a36Sopenharmony_ci case UMP_MSG_STATUS_NRPN: 15062306a36Sopenharmony_ci buf[0] = channel | (UMP_MSG_STATUS_CC << 4); 15162306a36Sopenharmony_ci buf[1] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB; 15262306a36Sopenharmony_ci buf[2] = midi2->rpn.bank; 15362306a36Sopenharmony_ci buf[3] = buf[0]; 15462306a36Sopenharmony_ci buf[4] = status == UMP_MSG_STATUS_RPN ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB; 15562306a36Sopenharmony_ci buf[5] = midi2->rpn.index; 15662306a36Sopenharmony_ci buf[6] = buf[0]; 15762306a36Sopenharmony_ci buf[7] = UMP_CC_DATA; 15862306a36Sopenharmony_ci v = downscale_32_to_14bit(midi2->rpn.data); 15962306a36Sopenharmony_ci buf[8] = v >> 7; 16062306a36Sopenharmony_ci buf[9] = buf[0]; 16162306a36Sopenharmony_ci buf[10] = UMP_CC_DATA_LSB; 16262306a36Sopenharmony_ci buf[11] = v & 0x7f; 16362306a36Sopenharmony_ci return 12; 16462306a36Sopenharmony_ci default: 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* convert a UMP 7-bit SysEx message to MIDI 1.0 byte stream */ 17062306a36Sopenharmony_cistatic int cvt_ump_sysex7_to_legacy(const u32 *data, unsigned char *buf) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci unsigned char status; 17362306a36Sopenharmony_ci unsigned char bytes; 17462306a36Sopenharmony_ci int size, offset; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci status = ump_sysex_message_status(*data); 17762306a36Sopenharmony_ci if (status > UMP_SYSEX_STATUS_END) 17862306a36Sopenharmony_ci return 0; // unsupported, skip 17962306a36Sopenharmony_ci bytes = ump_sysex_message_length(*data); 18062306a36Sopenharmony_ci if (bytes > 6) 18162306a36Sopenharmony_ci return 0; // skip 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci size = 0; 18462306a36Sopenharmony_ci if (status == UMP_SYSEX_STATUS_SINGLE || 18562306a36Sopenharmony_ci status == UMP_SYSEX_STATUS_START) { 18662306a36Sopenharmony_ci buf[0] = UMP_MIDI1_MSG_SYSEX_START; 18762306a36Sopenharmony_ci size = 1; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci offset = 8; 19162306a36Sopenharmony_ci for (; bytes; bytes--, size++) { 19262306a36Sopenharmony_ci buf[size] = (*data >> offset) & 0x7f; 19362306a36Sopenharmony_ci if (!offset) { 19462306a36Sopenharmony_ci offset = 24; 19562306a36Sopenharmony_ci data++; 19662306a36Sopenharmony_ci } else { 19762306a36Sopenharmony_ci offset -= 8; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (status == UMP_SYSEX_STATUS_SINGLE || 20262306a36Sopenharmony_ci status == UMP_SYSEX_STATUS_END) 20362306a36Sopenharmony_ci buf[size++] = UMP_MIDI1_MSG_SYSEX_END; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return size; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/** 20962306a36Sopenharmony_ci * snd_ump_convert_from_ump - convert from UMP to legacy MIDI 21062306a36Sopenharmony_ci * @data: UMP packet 21162306a36Sopenharmony_ci * @buf: buffer to store legacy MIDI data 21262306a36Sopenharmony_ci * @group_ret: pointer to store the target group 21362306a36Sopenharmony_ci * 21462306a36Sopenharmony_ci * Convert from a UMP packet @data to MIDI 1.0 bytes at @buf. 21562306a36Sopenharmony_ci * The target group is stored at @group_ret. 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * The function returns the number of bytes of MIDI 1.0 stream. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ciint snd_ump_convert_from_ump(const u32 *data, 22062306a36Sopenharmony_ci unsigned char *buf, 22162306a36Sopenharmony_ci unsigned char *group_ret) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci *group_ret = ump_message_group(*data); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci switch (ump_message_type(*data)) { 22662306a36Sopenharmony_ci case UMP_MSG_TYPE_SYSTEM: 22762306a36Sopenharmony_ci return cvt_ump_system_to_legacy(*data, buf); 22862306a36Sopenharmony_ci case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE: 22962306a36Sopenharmony_ci return cvt_ump_midi1_to_legacy(*data, buf); 23062306a36Sopenharmony_ci case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE: 23162306a36Sopenharmony_ci return cvt_ump_midi2_to_legacy((const union snd_ump_midi2_msg *)data, 23262306a36Sopenharmony_ci buf); 23362306a36Sopenharmony_ci case UMP_MSG_TYPE_DATA: 23462306a36Sopenharmony_ci return cvt_ump_sysex7_to_legacy(data, buf); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ump_convert_from_ump); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* 24262306a36Sopenharmony_ci * MIDI 1 byte stream -> UMP conversion 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci/* convert MIDI 1.0 SysEx to a UMP packet */ 24562306a36Sopenharmony_cistatic int cvt_legacy_sysex_to_ump(struct ump_cvt_to_ump *cvt, 24662306a36Sopenharmony_ci unsigned char group, u32 *data, bool finish) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci unsigned char status; 24962306a36Sopenharmony_ci bool start = cvt->in_sysex == 1; 25062306a36Sopenharmony_ci int i, offset; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (start && finish) 25362306a36Sopenharmony_ci status = UMP_SYSEX_STATUS_SINGLE; 25462306a36Sopenharmony_ci else if (start) 25562306a36Sopenharmony_ci status = UMP_SYSEX_STATUS_START; 25662306a36Sopenharmony_ci else if (finish) 25762306a36Sopenharmony_ci status = UMP_SYSEX_STATUS_END; 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci status = UMP_SYSEX_STATUS_CONTINUE; 26062306a36Sopenharmony_ci *data = ump_compose(UMP_MSG_TYPE_DATA, group, status, cvt->len); 26162306a36Sopenharmony_ci offset = 8; 26262306a36Sopenharmony_ci for (i = 0; i < cvt->len; i++) { 26362306a36Sopenharmony_ci *data |= cvt->buf[i] << offset; 26462306a36Sopenharmony_ci if (!offset) { 26562306a36Sopenharmony_ci offset = 24; 26662306a36Sopenharmony_ci data++; 26762306a36Sopenharmony_ci } else 26862306a36Sopenharmony_ci offset -= 8; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci cvt->len = 0; 27162306a36Sopenharmony_ci if (finish) 27262306a36Sopenharmony_ci cvt->in_sysex = 0; 27362306a36Sopenharmony_ci else 27462306a36Sopenharmony_ci cvt->in_sysex++; 27562306a36Sopenharmony_ci return 8; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* convert to a UMP System message */ 27962306a36Sopenharmony_cistatic int cvt_legacy_system_to_ump(struct ump_cvt_to_ump *cvt, 28062306a36Sopenharmony_ci unsigned char group, u32 *data) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, cvt->buf[0]); 28362306a36Sopenharmony_ci if (cvt->cmd_bytes > 1) 28462306a36Sopenharmony_ci data[0] |= cvt->buf[1] << 8; 28562306a36Sopenharmony_ci if (cvt->cmd_bytes > 2) 28662306a36Sopenharmony_ci data[0] |= cvt->buf[2]; 28762306a36Sopenharmony_ci return 4; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void fill_rpn(struct ump_cvt_to_ump_bank *cc, 29162306a36Sopenharmony_ci union snd_ump_midi2_msg *midi2) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci if (cc->rpn_set) { 29462306a36Sopenharmony_ci midi2->rpn.status = UMP_MSG_STATUS_RPN; 29562306a36Sopenharmony_ci midi2->rpn.bank = cc->cc_rpn_msb; 29662306a36Sopenharmony_ci midi2->rpn.index = cc->cc_rpn_lsb; 29762306a36Sopenharmony_ci cc->rpn_set = 0; 29862306a36Sopenharmony_ci cc->cc_rpn_msb = cc->cc_rpn_lsb = 0; 29962306a36Sopenharmony_ci } else { 30062306a36Sopenharmony_ci midi2->rpn.status = UMP_MSG_STATUS_NRPN; 30162306a36Sopenharmony_ci midi2->rpn.bank = cc->cc_nrpn_msb; 30262306a36Sopenharmony_ci midi2->rpn.index = cc->cc_nrpn_lsb; 30362306a36Sopenharmony_ci cc->nrpn_set = 0; 30462306a36Sopenharmony_ci cc->cc_nrpn_msb = cc->cc_nrpn_lsb = 0; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci midi2->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) | 30762306a36Sopenharmony_ci cc->cc_data_lsb); 30862306a36Sopenharmony_ci cc->cc_data_msb = cc->cc_data_lsb = 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* convert to a MIDI 1.0 Channel Voice message */ 31262306a36Sopenharmony_cistatic int cvt_legacy_cmd_to_ump(struct ump_cvt_to_ump *cvt, 31362306a36Sopenharmony_ci unsigned char group, 31462306a36Sopenharmony_ci unsigned int protocol, 31562306a36Sopenharmony_ci u32 *data, unsigned char bytes) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci const unsigned char *buf = cvt->buf; 31862306a36Sopenharmony_ci struct ump_cvt_to_ump_bank *cc; 31962306a36Sopenharmony_ci union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)data; 32062306a36Sopenharmony_ci unsigned char status, channel; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(union snd_ump_midi1_msg) != 4); 32362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(union snd_ump_midi2_msg) != 8); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* for MIDI 1.0 UMP, it's easy, just pack it into UMP */ 32662306a36Sopenharmony_ci if (protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI1) { 32762306a36Sopenharmony_ci data[0] = ump_compose(UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE, 32862306a36Sopenharmony_ci group, 0, buf[0]); 32962306a36Sopenharmony_ci data[0] |= buf[1] << 8; 33062306a36Sopenharmony_ci if (bytes > 2) 33162306a36Sopenharmony_ci data[0] |= buf[2]; 33262306a36Sopenharmony_ci return 4; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci status = *buf >> 4; 33662306a36Sopenharmony_ci channel = *buf & 0x0f; 33762306a36Sopenharmony_ci cc = &cvt->bank[channel]; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* special handling: treat note-on with 0 velocity as note-off */ 34062306a36Sopenharmony_ci if (status == UMP_MSG_STATUS_NOTE_ON && !buf[2]) 34162306a36Sopenharmony_ci status = UMP_MSG_STATUS_NOTE_OFF; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* initialize the packet */ 34462306a36Sopenharmony_ci data[0] = ump_compose(UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE, 34562306a36Sopenharmony_ci group, status, channel); 34662306a36Sopenharmony_ci data[1] = 0; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci switch (status) { 34962306a36Sopenharmony_ci case UMP_MSG_STATUS_NOTE_ON: 35062306a36Sopenharmony_ci case UMP_MSG_STATUS_NOTE_OFF: 35162306a36Sopenharmony_ci midi2->note.note = buf[1]; 35262306a36Sopenharmony_ci midi2->note.velocity = upscale_7_to_16bit(buf[2]); 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci case UMP_MSG_STATUS_POLY_PRESSURE: 35562306a36Sopenharmony_ci midi2->paf.note = buf[1]; 35662306a36Sopenharmony_ci midi2->paf.data = upscale_7_to_32bit(buf[2]); 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci case UMP_MSG_STATUS_CC: 35962306a36Sopenharmony_ci switch (buf[1]) { 36062306a36Sopenharmony_ci case UMP_CC_RPN_MSB: 36162306a36Sopenharmony_ci cc->rpn_set = 1; 36262306a36Sopenharmony_ci cc->cc_rpn_msb = buf[2]; 36362306a36Sopenharmony_ci return 0; // skip 36462306a36Sopenharmony_ci case UMP_CC_RPN_LSB: 36562306a36Sopenharmony_ci cc->rpn_set = 1; 36662306a36Sopenharmony_ci cc->cc_rpn_lsb = buf[2]; 36762306a36Sopenharmony_ci return 0; // skip 36862306a36Sopenharmony_ci case UMP_CC_NRPN_MSB: 36962306a36Sopenharmony_ci cc->nrpn_set = 1; 37062306a36Sopenharmony_ci cc->cc_nrpn_msb = buf[2]; 37162306a36Sopenharmony_ci return 0; // skip 37262306a36Sopenharmony_ci case UMP_CC_NRPN_LSB: 37362306a36Sopenharmony_ci cc->nrpn_set = 1; 37462306a36Sopenharmony_ci cc->cc_nrpn_lsb = buf[2]; 37562306a36Sopenharmony_ci return 0; // skip 37662306a36Sopenharmony_ci case UMP_CC_DATA: 37762306a36Sopenharmony_ci cc->cc_data_msb = buf[2]; 37862306a36Sopenharmony_ci return 0; // skip 37962306a36Sopenharmony_ci case UMP_CC_BANK_SELECT: 38062306a36Sopenharmony_ci cc->bank_set = 1; 38162306a36Sopenharmony_ci cc->cc_bank_msb = buf[2]; 38262306a36Sopenharmony_ci return 0; // skip 38362306a36Sopenharmony_ci case UMP_CC_BANK_SELECT_LSB: 38462306a36Sopenharmony_ci cc->bank_set = 1; 38562306a36Sopenharmony_ci cc->cc_bank_lsb = buf[2]; 38662306a36Sopenharmony_ci return 0; // skip 38762306a36Sopenharmony_ci case UMP_CC_DATA_LSB: 38862306a36Sopenharmony_ci cc->cc_data_lsb = buf[2]; 38962306a36Sopenharmony_ci if (cc->rpn_set || cc->nrpn_set) 39062306a36Sopenharmony_ci fill_rpn(cc, midi2); 39162306a36Sopenharmony_ci else 39262306a36Sopenharmony_ci return 0; // skip 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci default: 39562306a36Sopenharmony_ci midi2->cc.index = buf[1]; 39662306a36Sopenharmony_ci midi2->cc.data = upscale_7_to_32bit(buf[2]); 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci case UMP_MSG_STATUS_PROGRAM: 40162306a36Sopenharmony_ci midi2->pg.program = buf[1]; 40262306a36Sopenharmony_ci if (cc->bank_set) { 40362306a36Sopenharmony_ci midi2->pg.bank_valid = 1; 40462306a36Sopenharmony_ci midi2->pg.bank_msb = cc->cc_bank_msb; 40562306a36Sopenharmony_ci midi2->pg.bank_lsb = cc->cc_bank_lsb; 40662306a36Sopenharmony_ci cc->bank_set = 0; 40762306a36Sopenharmony_ci cc->cc_bank_msb = cc->cc_bank_lsb = 0; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case UMP_MSG_STATUS_CHANNEL_PRESSURE: 41162306a36Sopenharmony_ci midi2->caf.data = upscale_7_to_32bit(buf[1]); 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci case UMP_MSG_STATUS_PITCH_BEND: 41462306a36Sopenharmony_ci midi2->pb.data = upscale_14_to_32bit(buf[1] | (buf[2] << 7)); 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci default: 41762306a36Sopenharmony_ci return 0; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return 8; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int do_convert_to_ump(struct ump_cvt_to_ump *cvt, unsigned char group, 42462306a36Sopenharmony_ci unsigned int protocol, unsigned char c, u32 *data) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci /* bytes for 0x80-0xf0 */ 42762306a36Sopenharmony_ci static unsigned char cmd_bytes[8] = { 42862306a36Sopenharmony_ci 3, 3, 3, 3, 2, 2, 3, 0 42962306a36Sopenharmony_ci }; 43062306a36Sopenharmony_ci /* bytes for 0xf0-0xff */ 43162306a36Sopenharmony_ci static unsigned char system_bytes[16] = { 43262306a36Sopenharmony_ci 0, 2, 3, 2, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1 43362306a36Sopenharmony_ci }; 43462306a36Sopenharmony_ci unsigned char bytes; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (c == UMP_MIDI1_MSG_SYSEX_START) { 43762306a36Sopenharmony_ci cvt->in_sysex = 1; 43862306a36Sopenharmony_ci cvt->len = 0; 43962306a36Sopenharmony_ci return 0; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci if (c == UMP_MIDI1_MSG_SYSEX_END) { 44262306a36Sopenharmony_ci if (!cvt->in_sysex) 44362306a36Sopenharmony_ci return 0; /* skip */ 44462306a36Sopenharmony_ci return cvt_legacy_sysex_to_ump(cvt, group, data, true); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if ((c & 0xf0) == UMP_MIDI1_MSG_REALTIME) { 44862306a36Sopenharmony_ci bytes = system_bytes[c & 0x0f]; 44962306a36Sopenharmony_ci if (!bytes) 45062306a36Sopenharmony_ci return 0; /* skip */ 45162306a36Sopenharmony_ci if (bytes == 1) { 45262306a36Sopenharmony_ci data[0] = ump_compose(UMP_MSG_TYPE_SYSTEM, group, 0, c); 45362306a36Sopenharmony_ci return 4; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci cvt->buf[0] = c; 45662306a36Sopenharmony_ci cvt->len = 1; 45762306a36Sopenharmony_ci cvt->cmd_bytes = bytes; 45862306a36Sopenharmony_ci cvt->in_sysex = 0; /* abort SysEx */ 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (c & 0x80) { 46362306a36Sopenharmony_ci bytes = cmd_bytes[(c >> 4) & 7]; 46462306a36Sopenharmony_ci cvt->buf[0] = c; 46562306a36Sopenharmony_ci cvt->len = 1; 46662306a36Sopenharmony_ci cvt->cmd_bytes = bytes; 46762306a36Sopenharmony_ci cvt->in_sysex = 0; /* abort SysEx */ 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (cvt->in_sysex) { 47262306a36Sopenharmony_ci cvt->buf[cvt->len++] = c; 47362306a36Sopenharmony_ci if (cvt->len == 6) 47462306a36Sopenharmony_ci return cvt_legacy_sysex_to_ump(cvt, group, data, false); 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (!cvt->len) 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci cvt->buf[cvt->len++] = c; 48262306a36Sopenharmony_ci if (cvt->len < cvt->cmd_bytes) 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci cvt->len = 1; 48562306a36Sopenharmony_ci if ((cvt->buf[0] & 0xf0) == UMP_MIDI1_MSG_REALTIME) 48662306a36Sopenharmony_ci return cvt_legacy_system_to_ump(cvt, group, data); 48762306a36Sopenharmony_ci return cvt_legacy_cmd_to_ump(cvt, group, protocol, data, cvt->cmd_bytes); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/** 49162306a36Sopenharmony_ci * snd_ump_convert_to_ump - convert legacy MIDI byte to UMP packet 49262306a36Sopenharmony_ci * @cvt: converter context 49362306a36Sopenharmony_ci * @group: target UMP group 49462306a36Sopenharmony_ci * @protocol: target UMP protocol 49562306a36Sopenharmony_ci * @c: MIDI 1.0 byte data 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * Feed a MIDI 1.0 byte @c and convert to a UMP packet if completed. 49862306a36Sopenharmony_ci * The result is stored in the buffer in @cvt. 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_civoid snd_ump_convert_to_ump(struct ump_cvt_to_ump *cvt, unsigned char group, 50162306a36Sopenharmony_ci unsigned int protocol, unsigned char c) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci cvt->ump_bytes = do_convert_to_ump(cvt, group, protocol, c, cvt->ump); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ump_convert_to_ump); 506