midi_convert/
render_slice.rs

1//! Render message to a byte buffer
2
3use midi_types::{status::*, MidiMessage};
4
5/// Trait for rendering a MidiMessage into a byte slice.
6pub trait MidiRenderSlice: Sized {
7    /// Render to a slice.
8    ///
9    /// # Panics
10    ///
11    /// Panics if the slice length is less than 3.
12    fn render_slice(&self, buf: &mut [u8]) -> usize;
13}
14
15//helper to render 3 byte messages
16fn 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
31//helper to render 2 byte messages
32fn 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
46//helper to render 1 byte messages
47fn chan1byte(buf: &mut [u8], status: u8) -> usize {
48    buf[0] = status;
49    1
50}
51
52impl MidiRenderSlice for MidiMessage {
53    /// Render into a raw byte buffer, return the number of bytes rendered
54    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}