use midi_types::{status::*, MidiMessage};
pub trait MidiRenderSlice: Sized {
fn render_slice(&self, buf: &mut [u8]) -> usize;
}
fn chan3byte<T0: Into<u8> + Copy, T1: Into<u8> + Copy, C: Into<u8> + Copy>(
buf: &mut [u8],
status: u8,
chan: &C,
d0: &T0,
d1: &T1,
) -> usize {
let chan: u8 = (*chan).into();
let status = status | chan;
for (o, i) in buf.iter_mut().zip(&[status, (*d0).into(), (*d1).into()]) {
*o = *i;
}
3
}
fn chan2byte<T0: Into<u8> + Copy, C: Into<u8> + Copy>(
buf: &mut [u8],
status: u8,
chan: &C,
d0: &T0,
) -> usize {
let chan: u8 = (*chan).into();
let status = status | chan;
for (o, i) in buf.iter_mut().zip(&[status, (*d0).into()]) {
*o = *i;
}
2
}
fn chan1byte(buf: &mut [u8], status: u8) -> usize {
buf[0] = status;
1
}
impl MidiRenderSlice for MidiMessage {
fn render_slice(&self, buf: &mut [u8]) -> usize {
assert!(buf.len() >= 3);
match self {
MidiMessage::NoteOff(c, n, v) => chan3byte(buf, NOTE_OFF, c, n, v),
MidiMessage::NoteOn(c, n, v) => chan3byte(buf, NOTE_ON, c, n, v),
MidiMessage::KeyPressure(c, n, v) => chan3byte(buf, KEY_PRESSURE, c, n, v),
MidiMessage::ControlChange(c, n, v) => chan3byte(buf, CONTROL_CHANGE, c, n, v),
MidiMessage::PitchBendChange(c, v) => {
let (v0, v1): (u8, u8) = (*v).into();
chan3byte(buf, PITCH_BEND_CHANGE, c, &v0, &v1)
}
MidiMessage::SongPositionPointer(v) => {
let (v0, v1): (u8, u8) = (*v).into();
chan3byte(buf, SONG_POSITION_POINTER, &0, &v0, &v1)
}
MidiMessage::ProgramChange(c, p) => chan2byte(buf, PROGRAM_CHANGE, c, p),
MidiMessage::ChannelPressure(c, p) => chan2byte(buf, CHANNEL_PRESSURE, c, p),
MidiMessage::QuarterFrame(q) => chan2byte(buf, QUARTER_FRAME, &0, q),
MidiMessage::SongSelect(s) => chan2byte(buf, SONG_SELECT, &0, s),
MidiMessage::TuneRequest => chan1byte(buf, TUNE_REQUEST),
MidiMessage::TimingClock => chan1byte(buf, TIMING_CLOCK),
MidiMessage::Start => chan1byte(buf, START),
MidiMessage::Continue => chan1byte(buf, CONTINUE),
MidiMessage::Stop => chan1byte(buf, STOP),
MidiMessage::ActiveSensing => chan1byte(buf, ACTIVE_SENSING),
MidiMessage::Reset => chan1byte(buf, RESET),
}
}
}
#[cfg(test)]
mod test {
use {
super::*,
crate::test::{TEST_1BYTE, TEST_2BYTE, TEST_3BYTE},
};
#[test]
#[should_panic]
fn render_1_0_panic() {
let mut buf: [u8; 0] = [];
(*TEST_1BYTE)[0].render_slice(&mut buf);
}
#[test]
#[should_panic]
fn render_1_1_panic() {
let mut buf: [u8; 1] = [0; 1];
(*TEST_1BYTE)[0].render_slice(&mut buf);
}
#[test]
#[should_panic]
fn render_1_2_panic() {
let mut buf: [u8; 2] = [0; 2];
(*TEST_1BYTE)[0].render_slice(&mut buf);
}
#[test]
#[should_panic]
fn render_2_2_panic() {
let mut buf: [u8; 2] = [0; 2];
(*TEST_2BYTE)[0].render_slice(&mut buf);
}
#[test]
#[should_panic]
fn render_3_1_panic() {
let mut buf: [u8; 2] = [0; 2];
(*TEST_3BYTE)[0].render_slice(&mut buf);
}
#[test]
fn render_ok() {
let mut buf3 = [0, 0, 0];
let mut buf100 = [0; 100];
for v in (*TEST_1BYTE).iter() {
assert_eq!(1, v.render_slice(&mut buf3), "{:?}", v);
assert_eq!(1, v.render_slice(&mut buf100), "{:?}", v);
}
for v in (*TEST_2BYTE).iter() {
assert_eq!(2, v.render_slice(&mut buf3), "{:?}", v);
assert_eq!(2, v.render_slice(&mut buf100), "{:?}", v);
}
for v in (*TEST_3BYTE).iter() {
assert_eq!(3, v.render_slice(&mut buf3), "{:?}", v);
assert_eq!(3, v.render_slice(&mut buf100), "{:?}", v);
}
}
}