midi/
to_raw_messages.rs

1// Copyright 2015 Sam Doshi (sam@metal-fish.co.uk)
2//
3// Licensed under the MIT License <LICENSE or http://opensource.org/licenses/MIT>.
4// This file may not be copied, modified, or distributed except according to those terms.
5
6use constants::*;
7use types::{U7, Channel};
8use raw_message::{RawMessage};
9use RawMessage::*;
10use message::{Message};
11use Message::*;
12use utils::{mask7, status_byte, u14_to_msb_lsb};
13
14/// Convert `self` to `Vec<RawMessage>`
15///
16/// A `Vec<RawMessage>` represents ordered Midi data that must be sent as a contigious
17/// block, this is useful for representing `Message::SysEx` and `Message::NRPN14`,
18/// note that midi clock messages are allowed to interrupt sysex messages as part of the spec.
19pub trait ToRawMessages {
20    fn to_raw_messages(&self) -> Vec<RawMessage>;
21}
22
23impl ToRawMessages for RawMessage {
24    fn to_raw_messages(&self) -> Vec<RawMessage> {
25        vec!(*self)
26    }
27}
28
29impl ToRawMessages for Message {
30    fn to_raw_messages(&self) -> Vec<RawMessage> {
31        match self {
32            // System realtime
33            &Start => vec!(Status(START)),
34            &TimingClock => vec!(Status(TIMING_CLOCK)),
35            &Continue => vec!(Status(CONTINUE)),
36            &Stop => vec!(Status(STOP)),
37            &ActiveSensing => vec!(Status(ACTIVE_SENSING)),
38            &SystemReset => vec!(Status(SYSTEM_RESET)),
39
40            // Channel mode
41            &AllSoundOff(ch) => ControlChange(ch, 120, 0).to_raw_messages(),
42            &ResetAllControllers(ch) => ControlChange(ch, 121, 0).to_raw_messages(),
43            &LocalControlOff(ch) => ControlChange(ch, 122, 0).to_raw_messages(),
44            &LocalControlOn(ch) => ControlChange(ch, 122, 127).to_raw_messages(),
45            &AllNotesOff(ch) => ControlChange(ch, 123, 0).to_raw_messages(),
46
47            // Channel voice
48            &ProgramChange(ch, no) => {
49                let sb = status_byte(PROGRAM_CHANGE, ch);
50                vec!(StatusData(sb, mask7(no)))
51            },
52            &ControlChange(ch, no, val) => {
53                vec!(cc(ch, mask7(no), mask7(val)))
54            },
55            &RPN7(ch, rpn, val) => {
56                let (rpn_msb, rpn_lsb) = u14_to_msb_lsb(rpn);
57                vec!(
58                    cc(ch, CC_RPN_MSB, rpn_msb),
59                    cc(ch, CC_RPN_LSB, rpn_lsb),
60                    cc(ch, CC_DATA_ENTRY_MSB, mask7(val))
61                )
62            },
63            &RPN14(ch, rpn, val) => {
64                let (rpn_msb, rpn_lsb) = u14_to_msb_lsb(rpn);
65                let (val_msb, val_lsb) = u14_to_msb_lsb(val);
66                vec!(
67                    cc(ch, CC_RPN_MSB, rpn_msb),
68                    cc(ch, CC_RPN_LSB, rpn_lsb),
69                    cc(ch, CC_DATA_ENTRY_MSB, val_msb),
70                    cc(ch, CC_DATA_ENTRY_LSB, val_lsb)
71                )
72            },
73            &NRPN7(ch, nrpn, val) => {
74                let (nrpn_msb, nrpn_lsb) = u14_to_msb_lsb(nrpn);
75                vec!(
76                    cc(ch, CC_NRPN_MSB, nrpn_msb),
77                    cc(ch, CC_NRPN_LSB, nrpn_lsb),
78                    cc(ch, CC_DATA_ENTRY_MSB, mask7(val))
79                )
80            },
81            &NRPN14(ch, nrpn, val) => {
82                let (nrpn_msb, nrpn_lsb) = u14_to_msb_lsb(nrpn);
83                let (val_msb, val_lsb) = u14_to_msb_lsb(val);
84                vec!(
85                    cc(ch, CC_NRPN_MSB, nrpn_msb),
86                    cc(ch, CC_NRPN_LSB, nrpn_lsb),
87                    cc(ch, CC_DATA_ENTRY_MSB, val_msb),
88                    cc(ch, CC_DATA_ENTRY_LSB, val_lsb)
89                )
90            },
91            &SysEx(manufacturer, ref data) => {
92                let mut output = Vec::new();
93                output.push(SYSEX);
94                output.extend(manufacturer.to_u7s());
95                output.extend(data.iter().map(|d| mask7(*d)));
96                output.push(SYSEX_EOX);
97                output.into_iter().map(|d| Raw(d)).collect()
98            },
99            &NoteOff(ch, no, vel) => {
100                let sb = status_byte(NOTE_OFF, ch);
101                vec!(StatusDataData(sb, mask7(no), mask7(vel)))
102            },
103            &NoteOn(ch, no, vel) => {
104                let sb = status_byte(NOTE_ON, ch);
105                vec!(StatusDataData(sb, mask7(no), mask7(vel)))
106            },
107            &PitchBend(ch, bend) => {
108                let sb = status_byte(PITCH_BEND, ch);
109                let (msb, lsb) = u14_to_msb_lsb(bend);
110                vec!(StatusDataData(sb, lsb, msb))
111            }
112            &PolyphonicPressure(ch, no, vel) => {
113                let sb = status_byte(POLYPHONIC_PRESSURE, ch);
114                vec!(StatusDataData(sb, mask7(no), mask7(vel)))
115            },
116            &ChannelPressure(ch, vel) => {
117                let sb = status_byte(CHANNEL_PRESSURE, ch);
118                vec!(StatusData(sb, mask7(vel)))
119            }
120        }
121    }
122}
123
124// we need to generate a lot of CC messages...
125fn cc(ch: Channel, cc_no: U7, val: U7) -> RawMessage {
126    let sb = status_byte(CONTROL_CHANGE, ch);
127    StatusDataData(sb, cc_no, val)
128}
129
130#[cfg(test)]
131mod test {
132    use super::ToRawMessages;
133    use message::Message::*;
134    use raw_message::RawMessage::*;
135    use manufacturer::Manufacturer::*;
136    use types::Channel::*;
137
138    #[test]
139    fn test_message_to_raw_messages() {
140        // Where possible these numbers have been pasted in from
141        // http://www.midi.org/techspecs/midimessages.php
142
143        // Start
144        assert_eq!(Start.to_raw_messages(), vec![Status(0b11111010)]);
145
146        // TimingClock
147        assert_eq!(TimingClock.to_raw_messages(), vec![Status(0b11111000)]);
148
149        // Continue
150        assert_eq!(Continue.to_raw_messages(), vec![Status(0b11111011)]);
151
152        // Stop
153        assert_eq!(Stop.to_raw_messages(), vec![Status(0b11111100)]);
154
155        // ActiveSensing
156        assert_eq!(ActiveSensing.to_raw_messages(), vec![Status(0b11111110)]);
157
158        // SystemReset
159        assert_eq!(SystemReset.to_raw_messages(), vec![Status(0b11111111)]);
160
161        // AllSoundOff
162        assert_eq!(AllSoundOff(Ch1).to_raw_messages(), vec![StatusDataData(176, 120, 0)]);
163
164        // ResetAllControllers
165        assert_eq!(ResetAllControllers(Ch1).to_raw_messages(), vec![StatusDataData(176, 121, 0)]);
166
167        // LocalControlOff
168        assert_eq!(LocalControlOff(Ch1).to_raw_messages(), vec![StatusDataData(176, 122, 0)]);
169
170        // LocalControlOn
171        assert_eq!(LocalControlOn(Ch1).to_raw_messages(), vec![StatusDataData(176, 122, 127)]);
172
173        // AllNotesOff
174        assert_eq!(AllNotesOff(Ch1).to_raw_messages(), vec![StatusDataData(176, 123, 0)]);
175
176        // ProgramChange
177        assert_eq!(ProgramChange(Ch1, 0).to_raw_messages(), vec![StatusData(192, 0)]);
178        assert_eq!(ProgramChange(Ch1, 127).to_raw_messages(), vec![StatusData(192, 127)]);
179        assert_eq!(ProgramChange(Ch1, 128).to_raw_messages(), vec![StatusData(192, 0)]);
180
181        // ControlChange
182        assert_eq!(ControlChange(Ch1, 0, 0).to_raw_messages(), vec![StatusDataData(176, 0, 0)]);
183        assert_eq!(ControlChange(Ch1, 0, 127).to_raw_messages(), vec![StatusDataData(176, 0, 127)]);
184        assert_eq!(ControlChange(Ch1, 0, 128).to_raw_messages(), vec![StatusDataData(176, 0, 0)]);
185        assert_eq!(ControlChange(Ch1, 127, 0).to_raw_messages(), vec![StatusDataData(176, 127, 0)]);
186        assert_eq!(ControlChange(Ch1, 128, 0).to_raw_messages(), vec![StatusDataData(176, 0, 0)]);
187
188        // RPN7
189        assert_eq!(RPN7(Ch1, 1000, 0).to_raw_messages(), vec![StatusDataData(176, 101, 7),
190                                                              StatusDataData(176, 100, 104),
191                                                              StatusDataData(176, 6, 0)]);
192
193        // RPN14
194        assert_eq!(RPN14(Ch1, 1000, 1001).to_raw_messages(), vec![StatusDataData(176, 101, 7),
195                                                                  StatusDataData(176, 100, 104),
196                                                                  StatusDataData(176, 6, 7),
197                                                                  StatusDataData(176, 38, 105)]);
198
199        // NRPN7
200        assert_eq!(NRPN7(Ch1, 1000, 0).to_raw_messages(), vec![StatusDataData(176, 99, 7),
201                                                               StatusDataData(176, 98, 104),
202                                                               StatusDataData(176, 6, 0)]);
203
204        // NRPN14
205        assert_eq!(NRPN14(Ch1, 1000, 1001).to_raw_messages(), vec![StatusDataData(176, 99, 7),
206                                                                   StatusDataData(176, 98, 104),
207                                                                   StatusDataData(176, 6, 7),
208                                                                   StatusDataData(176, 38, 105)]);
209
210        // SysEx
211        assert_eq!(SysEx(OneByte(100), vec![1, 2, 3, 4]).to_raw_messages(),
212                   vec![Raw(0b11110000),
213                        Raw(100),
214                        Raw(1), Raw(2), Raw(3), Raw(4),
215                        Raw(0b11110111)]);
216
217        assert_eq!(SysEx(OneByte(128), vec![1, 2, 3, 4, 128]).to_raw_messages(),
218                   vec![Raw(0b11110000),
219                        Raw(0),
220                        Raw(1), Raw(2), Raw(3), Raw(4), Raw(0),
221                        Raw(0b11110111)]);
222
223        assert_eq!(SysEx(ThreeByte(100, 101, 128), vec![1, 2, 3, 4]).to_raw_messages(),
224                   vec![Raw(0b11110000),
225                        Raw(100), Raw(101), Raw(0),
226                        Raw(1), Raw(2), Raw(3), Raw(4),
227                        Raw(0b11110111)]);
228
229        // NoteOff
230        assert_eq!(NoteOff(Ch1, 0, 0).to_raw_messages(), vec![StatusDataData(128, 0, 0)]);
231        assert_eq!(NoteOff(Ch2, 127, 127).to_raw_messages(), vec![StatusDataData(129, 127, 127)]);
232        assert_eq!(NoteOff(Ch3, 128, 128).to_raw_messages(), vec![StatusDataData(130, 0, 0)]);
233
234        // NoteOn
235        assert_eq!(NoteOn(Ch4, 0, 0).to_raw_messages(), vec![StatusDataData(147, 0, 0)]);
236        assert_eq!(NoteOn(Ch5, 127, 127).to_raw_messages(), vec![StatusDataData(148, 127, 127)]);
237        assert_eq!(NoteOn(Ch6, 128, 128).to_raw_messages(), vec![StatusDataData(149, 0, 0)]);
238
239        // PitchBend
240        assert_eq!(PitchBend(Ch7, 0).to_raw_messages(), vec![StatusDataData(230, 0, 0)]);
241        assert_eq!(PitchBend(Ch8, 1000).to_raw_messages(), vec![StatusDataData(231, 104, 7)]);
242        assert_eq!(PitchBend(Ch9, 45000).to_raw_messages(), vec![StatusDataData(232, 72, 95)]);
243        assert_eq!(PitchBend(Ch10, 12232).to_raw_messages(), vec![StatusDataData(233, 72, 95)]);
244
245        // PolyphonicPressure
246        assert_eq!(PolyphonicPressure(Ch11, 0, 0).to_raw_messages(),
247                   vec![StatusDataData(170, 0, 0)]);
248        assert_eq!(PolyphonicPressure(Ch12, 127, 127).to_raw_messages(),
249                   vec![StatusDataData(171, 127, 127)]);
250        assert_eq!(PolyphonicPressure(Ch13, 128, 128).to_raw_messages(),
251                   vec![StatusDataData(172, 0, 0)]);
252
253        // ChannelPressure
254        assert_eq!(ChannelPressure(Ch14, 0).to_raw_messages(), vec![StatusData(221, 0)]);
255        assert_eq!(ChannelPressure(Ch15, 127).to_raw_messages(), vec![StatusData(222, 127)]);
256        assert_eq!(ChannelPressure(Ch16, 128).to_raw_messages(), vec![StatusData(223, 0)]);
257    }
258}
259