Skip to main content

midi_msg/
channel_mode.rs

1use super::parse_error::*;
2use crate::util::*;
3use alloc::vec::Vec;
4
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7/// Channel-level messages that should alter the mode of the receiver. Used in [`MidiMsg`](crate::MidiMsg).
8pub enum ChannelModeMsg {
9    /// Sound playing on the channel should be stopped as soon as possible, per GM2.
10    AllSoundOff,
11    /// Stop sounding all notes on the channel.
12    AllNotesOff,
13    /// All controllers should be reset to their default values. GM specifies some of these defaults.
14    ResetAllControllers,
15    /// An instrument set to `OmniMode(true)` should respond to MIDI messages sent over all channels.
16    OmniMode(bool),
17    /// Request that the receiver set itself to be monophonic/polyphonic.
18    PolyMode(PolyMode),
19    /// Used to turn on or off "local control" of a MIDI synthesizer instrument. When the instrument
20    /// does not have local control, its controller should only send out MIDI signals while the synthesizer should only respond to remote MIDI messages.
21    LocalControl(bool),
22}
23
24impl ChannelModeMsg {
25    pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
26        v.push(0xB0);
27        self.extend_midi_running(v);
28    }
29
30    pub(crate) fn extend_midi_running(&self, v: &mut Vec<u8>) {
31        match self {
32            ChannelModeMsg::AllSoundOff => {
33                v.push(120);
34                v.push(0);
35            }
36            ChannelModeMsg::ResetAllControllers => {
37                v.push(121);
38                v.push(0);
39            }
40            ChannelModeMsg::LocalControl(on) => {
41                v.push(122);
42                v.push(if *on { 127 } else { 0 });
43            }
44            ChannelModeMsg::AllNotesOff => {
45                v.push(123);
46                v.push(0);
47            }
48            ChannelModeMsg::OmniMode(on) => {
49                v.push(if *on { 125 } else { 124 });
50                v.push(0);
51            }
52            ChannelModeMsg::PolyMode(m) => {
53                v.push(if *m == PolyMode::Poly { 127 } else { 126 });
54                v.push(match *m {
55                    PolyMode::Poly => 0,
56                    PolyMode::Mono(n) => n.min(16),
57                })
58            }
59        }
60    }
61
62    pub(crate) fn from_midi(m: &[u8]) -> Result<(Self, usize), ParseError> {
63        // Skip the status byte since it's already been parsed
64        let (msg, len) = ChannelModeMsg::from_midi_running(&m[1..])?;
65        Ok((msg, len + 1))
66    }
67
68    pub(crate) fn from_midi_running(m: &[u8]) -> Result<(Self, usize), ParseError> {
69        if let (Some(b1), Some(b2)) = (m.first(), m.get(1)) {
70            if *b2 > 127 {
71                return Err(ParseError::ByteOverflow);
72            }
73            match (b1, b2) {
74                (120, _) => Ok((Self::AllSoundOff, 2)),
75                (121, _) => Ok((Self::ResetAllControllers, 2)),
76                (122, b2) => Ok((Self::LocalControl(bool_from_u7(*b2)?), 2)),
77                (123, _) => Ok((Self::AllNotesOff, 2)),
78                (124, _) => Ok((Self::OmniMode(false), 2)),
79                (125, _) => Ok((Self::OmniMode(true), 2)),
80                (126, b2) => Ok((Self::PolyMode(PolyMode::Mono(u8_from_u7(*b2)?)), 2)),
81                (127, _) => Ok((Self::PolyMode(PolyMode::Poly), 2)),
82                _ => Err(ParseError::Invalid(
83                    "This shouldn't be possible: values below 120 should be control change messages",
84                )),
85            }
86        } else {
87            Err(ParseError::UnexpectedEnd)
88        }
89    }
90}
91
92/// Used by [`ChannelModeMsg::PolyMode`].
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum PolyMode {
96    /// Request that the receiver be monophonic, with the given number M representing the
97    /// number of channels that should be dedicated. Since this is sent with a `ChannelModeMsg`
98    /// there is already a "base" channel associated with it, and the number of requested channels
99    /// should be from this base channel N to N+M. `0` is a special case that directing the receiver
100    /// to assign the voices to as many channels as it can receive.
101    Mono(u8),
102    /// Request the receiver to be polyphonic
103    Poly,
104}
105
106#[cfg(test)]
107mod tests {
108    use crate::*;
109    use alloc::vec;
110
111    #[test]
112    fn serialize_channel_mode_msg() {
113        assert_eq!(
114            MidiMsg::ChannelMode {
115                channel: Channel::Ch3,
116                msg: ChannelModeMsg::AllSoundOff
117            }
118            .to_midi(),
119            vec![0xB2, 120, 0]
120        );
121
122        assert_eq!(
123            MidiMsg::RunningChannelMode {
124                channel: Channel::Ch3,
125                msg: ChannelModeMsg::AllSoundOff
126            }
127            .to_midi(),
128            vec![120, 0]
129        );
130
131        assert_eq!(
132            MidiMsg::ChannelMode {
133                channel: Channel::Ch3,
134                msg: ChannelModeMsg::LocalControl(true)
135            }
136            .to_midi(),
137            vec![0xB2, 122, 127]
138        );
139
140        assert_eq!(
141            MidiMsg::ChannelMode {
142                channel: Channel::Ch3,
143                msg: ChannelModeMsg::OmniMode(true)
144            }
145            .to_midi(),
146            vec![0xB2, 125, 0]
147        );
148
149        assert_eq!(
150            MidiMsg::ChannelMode {
151                channel: Channel::Ch3,
152                msg: ChannelModeMsg::OmniMode(false)
153            }
154            .to_midi(),
155            vec![0xB2, 124, 0]
156        );
157
158        assert_eq!(
159            MidiMsg::ChannelMode {
160                channel: Channel::Ch3,
161                msg: ChannelModeMsg::PolyMode(PolyMode::Poly)
162            }
163            .to_midi(),
164            vec![0xB2, 127, 0]
165        );
166
167        assert_eq!(
168            MidiMsg::ChannelMode {
169                channel: Channel::Ch3,
170                msg: ChannelModeMsg::PolyMode(PolyMode::Mono(4))
171            }
172            .to_midi(),
173            vec![0xB2, 126, 4]
174        );
175    }
176
177    #[test]
178    fn deserialize_channel_mode_msg() {
179        let mut ctx = ReceiverContext::new();
180
181        test_serialization(
182            MidiMsg::ChannelMode {
183                channel: Channel::Ch3,
184                msg: ChannelModeMsg::AllSoundOff,
185            },
186            &mut ctx,
187        );
188
189        test_serialization(
190            MidiMsg::ChannelMode {
191                channel: Channel::Ch3,
192                msg: ChannelModeMsg::LocalControl(true),
193            },
194            &mut ctx,
195        );
196
197        test_serialization(
198            MidiMsg::ChannelMode {
199                channel: Channel::Ch3,
200                msg: ChannelModeMsg::OmniMode(true),
201            },
202            &mut ctx,
203        );
204
205        test_serialization(
206            MidiMsg::ChannelMode {
207                channel: Channel::Ch3,
208                msg: ChannelModeMsg::OmniMode(false),
209            },
210            &mut ctx,
211        );
212
213        test_serialization(
214            MidiMsg::ChannelMode {
215                channel: Channel::Ch3,
216                msg: ChannelModeMsg::PolyMode(PolyMode::Poly),
217            },
218            &mut ctx,
219        );
220
221        test_serialization(
222            MidiMsg::ChannelMode {
223                channel: Channel::Ch3,
224                msg: ChannelModeMsg::PolyMode(PolyMode::Mono(4)),
225            },
226            &mut ctx,
227        );
228    }
229}