xpans_spe_midi 0.1.2

Wraps xpans Spatial Property Exchange (SPE) messages in MIDI
Documentation
use core::slice::{Iter, IterMut};

pub trait ReadMidi: Sized {
    fn read_midi(buf: &mut Iter<u8>) -> Self;
}

macro_rules! impl_midi_reader {
    ($t:ty, $decoder:ident) => {
        impl ReadMidi for $t {
            #[inline]
            fn read_midi(buf: &mut Iter<u8>) -> Self {
                const BYTES: usize = midi_bytes::<$t>();
                let mut int = 0;
                for (b, i) in buf.zip(0..BYTES) {
                    int |= <$t>::from(*b) << (7 * i);
                }
                let result = <$t>::from_le(int);
                result
            }
        }
    };
}

impl_midi_reader!(u16, midi_to_u16);
impl_midi_reader!(u32, midi_to_u32);
impl_midi_reader!(u64, midi_to_u64);
impl_midi_reader!(u128, midi_to_u128);

impl ReadMidi for f32 {
    #[inline]
    fn read_midi(buf: &mut Iter<u8>) -> Self {
        let bits = u32::read_midi(buf);
        f32::from_bits(bits)
    }
}
impl ReadMidi for f64 {
    #[inline]
    fn read_midi(buf: &mut Iter<u8>) -> Self {
        let bits = u64::read_midi(buf);
        f64::from_bits(bits)
    }
}

pub trait WriteMidi {
    fn write_midi(self, buf: &mut IterMut<u8>);
}

macro_rules! impl_midi_writer {
    ($t:ty, $encoder:ident) => {
        impl WriteMidi for $t {
            #[inline]
            fn write_midi(self, buf: &mut IterMut<u8>) {
                const BYTES: usize = midi_bytes::<$t>();
                let value = self.to_le();
                for (byte, i) in buf.zip(0..BYTES) {
                    *byte = ((value >> (7 * i)) & 127) as u8;
                }
            }
        }
    };
}

impl_midi_writer!(u16, u16_to_midi);
impl_midi_writer!(u32, u32_to_midi);
impl_midi_writer!(u64, u64_to_midi);
impl_midi_writer!(u128, u128_to_midi);

impl WriteMidi for f32 {
    #[inline]
    fn write_midi(self, buf: &mut IterMut<u8>) {
        self.to_bits().write_midi(buf)
    }
}
impl WriteMidi for f64 {
    #[inline]
    fn write_midi(self, buf: &mut IterMut<u8>) {
        self.to_bits().write_midi(buf)
    }
}
const U7_MASK: u16 = 2u16.pow(7) - 1;
const U14_MASK: u16 = 2u16.pow(14) - 1;

#[inline]
pub(crate) fn u14_to_u16(v: u16) -> u16 {
    let b1 = v & U7_MASK;
    let b2 = v & (U7_MASK << 8);
    (b2 >> 1) | b1
}

#[inline]
pub(crate) fn u16_to_u14(v: u16) -> u16 {
    let v = v & U14_MASK;
    let b1 = v & U7_MASK;
    let b2 = (v & !U7_MASK) << 1;
    b1 | b2
}

#[inline]
const fn midi_bytes<T>() -> usize {
    let native_bits = size_of::<T>() * 8;
    (native_bits / 7) + 1
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn u16_round_trip() {
        for i in 0x00..0xFFFF {
            let mut buf = [0u8; midi_bytes::<u16>()];
            i.write_midi(&mut buf.iter_mut());
            let back = u16::read_midi(&mut buf.iter());
            assert_eq!(i, back);
        }
    }
    #[test]
    fn f32_round_trip() {
        for i in 0x00u16..0xFFFF {
            let i = f32::from(i);
            let mut buf = [0u8; midi_bytes::<f32>()];
            i.write_midi(&mut buf.iter_mut());
            let back = f32::read_midi(&mut buf.iter());
            assert_eq!(i, back);
        }
    }
    #[test]
    fn f64_round_trip() {
        for i in 0x00u16..0xFFFF {
            let i = f64::from(i);
            let mut buf = [0u8; midi_bytes::<f64>()];
            i.write_midi(&mut buf.iter_mut());
            let back = f64::read_midi(&mut buf.iter());
            assert_eq!(i, back);
        }
    }
    #[test]
    fn u32_round_trip() {
        for i in 0x00..0xFFFF {
            let i = i * 0xFFFF;
            let mut buf = [0u8; midi_bytes::<u32>()];
            i.write_midi(&mut buf.iter_mut());
            let back = u32::read_midi(&mut buf.iter());
            assert_eq!(i, back);
            assert_eq!(i, back);
        }
    }
    #[test]
    fn u64_round_trip() {
        for i in 0x00..0xFFFF {
            let i = i * 0xFFFFFFFF;
            let mut buf = [0u8; midi_bytes::<u64>()];
            i.write_midi(&mut buf.iter_mut());
            let back = u64::read_midi(&mut buf.iter());
            assert_eq!(i, back);
            assert_eq!(i, back);
        }
    }
    #[test]
    fn u128_round_trip() {
        for i in 0x0000..0xFFFF {
            let i = i * 0xFFFFFFFFFFFFFFFF;
            let mut buf = [0u8; midi_bytes::<u128>()];
            i.write_midi(&mut buf.iter_mut());
            let back = u128::read_midi(&mut buf.iter());
            assert_eq!(i, back);
            assert_eq!(i, back);
        }
    }
    const U14_MAX: u16 = 2u16.pow(14) - 1;
    #[test]
    fn u16_u14_round_trip() {
        for i in u16::MIN..U14_MAX {
            let conv = u16_to_u14(i);
            let back = u14_to_u16(conv);
            assert_eq!(i, back);
        }
    }

    #[test]
    fn u16_to_u14_valid() {
        const MASK_VALID_U14: u16 = 0b_01111111_01111111;
        for i in u16::MIN..U14_MAX {
            let conv = u16_to_u14(i);
            let masked = conv & MASK_VALID_U14;
            assert_eq!(conv, masked);
        }
    }
}