midi_msg/system_exclusive/key_based_instrument_control.rs
1use crate::message::Channel;
2use crate::parse_error::*;
3use crate::util::*;
4use alloc::vec::Vec;
5
6/// Intended to act like Control Change messages, but targeted at an individual key.
7/// For e.g. Drum sounds that have configurable attack/release/decay per key.
8/// Used by [`UniversalRealTimeMsg::KeyBasedInstrumentControl`](crate::UniversalRealTimeMsg::KeyBasedInstrumentControl).
9///
10/// Defined in CA-023.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct KeyBasedInstrumentControl {
13 pub channel: Channel,
14 /// The MIDI key number.
15 pub key: u8,
16 /// Any number of (control number, value) pairs.
17 ///
18 /// Any controller number may be used except Bank Select MSB/LSB (`0x00`, `0x20`),
19 /// Data Entry MSB/LSB (`0x06`, `0x26`), RPN/NRPN messages (`0x60` – `0x65`),
20 /// and Mode Change messages(`0x78`-`0x7F`).
21 ///
22 /// Disallowed values will be set to `0x01` (targeting the mod wheel, which probably has no meaning).
23 pub control_values: Vec<(u8, u8)>,
24}
25
26impl KeyBasedInstrumentControl {
27 pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
28 v.push(self.channel as u8);
29 push_u7(self.key, v);
30 for (cc, x) in self.control_values.iter().cloned() {
31 if cc == 0x06 || cc == 0x26 || cc == 0x60 || cc == 0x65 || cc >= 0x78 {
32 v.push(1);
33 } else {
34 v.push(cc);
35 }
36 push_u7(x, v);
37 }
38 }
39
40 #[allow(dead_code)]
41 pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
42 Err(ParseError::NotImplemented("KeyBasedInstrumentControl"))
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use crate::*;
49 use alloc::vec;
50
51 #[test]
52 fn serialize_controller_destination() {
53 assert_eq!(
54 MidiMsg::SystemExclusive {
55 msg: SystemExclusiveMsg::UniversalRealTime {
56 device: DeviceID::AllCall,
57 msg: UniversalRealTimeMsg::KeyBasedInstrumentControl(
58 KeyBasedInstrumentControl {
59 channel: Channel::Ch2,
60 key: 0x60,
61 control_values: vec![
62 (0x06, 0x40), // CC not allowed, should become 0x01
63 (ControlNumber::Effects4Depth as u8, 0x20),
64 ]
65 }
66 ),
67 }
68 }
69 .to_midi(),
70 vec![
71 0xF0, 0x7F, 0x7F, // Receiver device
72 0xA, 0x1, // Sysex IDs
73 0x1, 0x60, 0x01, 0x40, 94, 0x20, 0xF7
74 ]
75 );
76 }
77}