1use midi_types::{status::*, MidiMessage};
4
5pub trait MidiRenderSlice: Sized {
7 fn render_slice(&self, buf: &mut [u8]) -> usize;
13}
14
15fn chan3byte<T0: Into<u8> + Copy, T1: Into<u8> + Copy, C: Into<u8> + Copy>(
17 buf: &mut [u8],
18 status: u8,
19 chan: &C,
20 d0: &T0,
21 d1: &T1,
22) -> usize {
23 let chan: u8 = (*chan).into();
24 let status = status | chan;
25 for (o, i) in buf.iter_mut().zip(&[status, (*d0).into(), (*d1).into()]) {
26 *o = *i;
27 }
28 3
29}
30
31fn chan2byte<T0: Into<u8> + Copy, C: Into<u8> + Copy>(
33 buf: &mut [u8],
34 status: u8,
35 chan: &C,
36 d0: &T0,
37) -> usize {
38 let chan: u8 = (*chan).into();
39 let status = status | chan;
40 for (o, i) in buf.iter_mut().zip(&[status, (*d0).into()]) {
41 *o = *i;
42 }
43 2
44}
45
46fn chan1byte(buf: &mut [u8], status: u8) -> usize {
48 buf[0] = status;
49 1
50}
51
52impl MidiRenderSlice for MidiMessage {
53 fn render_slice(&self, buf: &mut [u8]) -> usize {
55 assert!(buf.len() >= 3);
56 match self {
57 MidiMessage::NoteOff(c, n, v) => chan3byte(buf, NOTE_OFF, c, n, v),
58 MidiMessage::NoteOn(c, n, v) => chan3byte(buf, NOTE_ON, c, n, v),
59 MidiMessage::KeyPressure(c, n, v) => chan3byte(buf, KEY_PRESSURE, c, n, v),
60 MidiMessage::ControlChange(c, n, v) => chan3byte(buf, CONTROL_CHANGE, c, n, v),
61 MidiMessage::PitchBendChange(c, v) => {
62 let (v0, v1): (u8, u8) = (*v).into();
63 chan3byte(buf, PITCH_BEND_CHANGE, c, &v0, &v1)
64 }
65 MidiMessage::SongPositionPointer(v) => {
66 let (v0, v1): (u8, u8) = (*v).into();
67 chan3byte(buf, SONG_POSITION_POINTER, &0, &v0, &v1)
68 }
69 MidiMessage::ProgramChange(c, p) => chan2byte(buf, PROGRAM_CHANGE, c, p),
70 MidiMessage::ChannelPressure(c, p) => chan2byte(buf, CHANNEL_PRESSURE, c, p),
71 MidiMessage::QuarterFrame(q) => chan2byte(buf, QUARTER_FRAME, &0, q),
72 MidiMessage::SongSelect(s) => chan2byte(buf, SONG_SELECT, &0, s),
73 MidiMessage::TuneRequest => chan1byte(buf, TUNE_REQUEST),
74 MidiMessage::TimingClock => chan1byte(buf, TIMING_CLOCK),
75 MidiMessage::Start => chan1byte(buf, START),
76 MidiMessage::Continue => chan1byte(buf, CONTINUE),
77 MidiMessage::Stop => chan1byte(buf, STOP),
78 MidiMessage::ActiveSensing => chan1byte(buf, ACTIVE_SENSING),
79 MidiMessage::Reset => chan1byte(buf, RESET),
80 }
81 }
82}
83
84#[cfg(test)]
85mod test {
86 use {
87 super::*,
88 crate::test::{TEST_1BYTE, TEST_2BYTE, TEST_3BYTE},
89 };
90
91 #[test]
92 #[should_panic]
93 fn render_1_0_panic() {
94 let mut buf: [u8; 0] = [];
95 (*TEST_1BYTE)[0].render_slice(&mut buf);
96 }
97
98 #[test]
99 #[should_panic]
100 fn render_1_1_panic() {
101 let mut buf: [u8; 1] = [0; 1];
102 (*TEST_1BYTE)[0].render_slice(&mut buf);
103 }
104
105 #[test]
106 #[should_panic]
107 fn render_1_2_panic() {
108 let mut buf: [u8; 2] = [0; 2];
109 (*TEST_1BYTE)[0].render_slice(&mut buf);
110 }
111
112 #[test]
113 #[should_panic]
114 fn render_2_2_panic() {
115 let mut buf: [u8; 2] = [0; 2];
116 (*TEST_2BYTE)[0].render_slice(&mut buf);
117 }
118
119 #[test]
120 #[should_panic]
121 fn render_3_1_panic() {
122 let mut buf: [u8; 2] = [0; 2];
123 (*TEST_3BYTE)[0].render_slice(&mut buf);
124 }
125
126 #[test]
127 fn render_ok() {
128 let mut buf3 = [0, 0, 0];
129 let mut buf100 = [0; 100];
130 for v in (*TEST_1BYTE).iter() {
131 assert_eq!(1, v.render_slice(&mut buf3), "{:?}", v);
132 assert_eq!(1, v.render_slice(&mut buf100), "{:?}", v);
133 }
134
135 for v in (*TEST_2BYTE).iter() {
136 assert_eq!(2, v.render_slice(&mut buf3), "{:?}", v);
137 assert_eq!(2, v.render_slice(&mut buf100), "{:?}", v);
138 }
139
140 for v in (*TEST_3BYTE).iter() {
141 assert_eq!(3, v.render_slice(&mut buf3), "{:?}", v);
142 assert_eq!(3, v.render_slice(&mut buf100), "{:?}", v);
143 }
144 }
145}