use atom::prelude::*;
use core::prelude::*;
use std::convert::TryFrom;
pub struct WMidiEvent;
unsafe impl UriBound for WMidiEvent {
const URI: &'static [u8] = sys::LV2_MIDI__MidiEvent;
}
impl<'a, 'b> Atom<'a, 'b> for WMidiEvent
where
'a: 'b,
{
type ReadParameter = ();
type ReadHandle = wmidi::MidiMessage<'a>;
type WriteParameter = wmidi::MidiMessage<'static>;
type WriteHandle = ();
fn read(space: Space<'a>, _: ()) -> Option<wmidi::MidiMessage<'a>> {
space
.data()
.and_then(|bytes| wmidi::MidiMessage::try_from(bytes).ok())
}
fn init(mut frame: FramedMutSpace<'a, 'b>, message: wmidi::MidiMessage<'b>) -> Option<()> {
frame
.allocate(message.bytes_size(), false)
.and_then(|(_, space)| message.copy_to_slice(space).ok())
.map(|_| ())
}
}
pub struct SystemExclusiveWMidiEvent;
unsafe impl UriBound for SystemExclusiveWMidiEvent {
const URI: &'static [u8] = sys::LV2_MIDI__MidiEvent;
}
impl<'a, 'b> Atom<'a, 'b> for SystemExclusiveWMidiEvent
where
'a: 'b,
{
type ReadParameter = ();
type ReadHandle = wmidi::MidiMessage<'a>;
type WriteParameter = ();
type WriteHandle = Writer<'a, 'b>;
fn read(space: Space<'a>, _: ()) -> Option<wmidi::MidiMessage<'a>> {
WMidiEvent::read(space, ())
}
fn init(frame: FramedMutSpace<'a, 'b>, _: ()) -> Option<Writer<'a, 'b>> {
let mut writer = Writer { frame };
writer.write::<u8>(&0xf0);
Some(writer)
}
}
pub struct Writer<'a, 'b> {
frame: FramedMutSpace<'a, 'b>,
}
impl<'a, 'b> Writer<'a, 'b> {
pub fn allocate(&mut self, size: usize) -> Option<&'a mut [u8]> {
self.frame.allocate(size, false).map(|(_, slice)| slice)
}
pub fn write_raw(&mut self, data: &[u8]) -> Option<&'a mut [u8]> {
self.frame.write_raw(data, false)
}
pub fn write<T>(&mut self, instance: &T) -> Option<&'a mut T>
where
T: Unpin + Copy + Send + Sync + Sized + 'static,
{
(&mut self.frame as &mut dyn MutSpace).write(instance, false)
}
}
impl<'a, 'b> Drop for Writer<'a, 'b> {
fn drop(&mut self) {
self.write::<u8>(&0xf7);
}
}
#[cfg(test)]
mod tests {
use crate::wmidi_binding::*;
use atom::space::RootMutSpace;
use std::convert::TryFrom;
use std::mem::size_of;
use urid::mapper::*;
use urid::prelude::*;
use wmidi::*;
#[test]
fn test_midi_event() {
let mut mapper = Box::pin(HashURIDMapper::new());
let map_interface = mapper.as_mut().make_map_interface();
let map = Map::new(&map_interface);
let urid = map.map_type::<WMidiEvent>().unwrap();
let mut raw_space: Box<[u8]> = Box::new([0; 256]);
let reference_message =
MidiMessage::NoteOn(Channel::Ch1, Note::A0, Velocity::try_from(125).unwrap());
{
let mut space = RootMutSpace::new(raw_space.as_mut());
(&mut space as &mut dyn MutSpace)
.init(urid, reference_message.clone())
.unwrap();
}
{
let (header, raw_space) = raw_space.split_at(size_of::<sys::LV2_Atom>());
let header = unsafe { &*(header.as_ptr() as *const sys::LV2_Atom) };
assert_eq!(header.type_, urid);
assert_eq!(header.size as usize, 3);
let (message, _) = raw_space.split_at(3);
let message = MidiMessage::try_from(message).unwrap();
assert_eq!(message, reference_message);
}
{
let space = Space::from_reference(raw_space.as_ref());
let message = WMidiEvent::read(space.split_atom_body(urid).unwrap().0, ()).unwrap();
assert_eq!(message, reference_message);
}
}
#[test]
fn test_sysex_event() {
let mut mapper = Box::pin(HashURIDMapper::new());
let map_interface = mapper.as_mut().make_map_interface();
let map = Map::new(&map_interface);
let urid = map.map_type::<SystemExclusiveWMidiEvent>().unwrap();
let mut raw_space: Box<[u8]> = Box::new([0; 256]);
{
let mut space = RootMutSpace::new(raw_space.as_mut());
let mut writer = (&mut space as &mut dyn MutSpace).init(urid, ()).unwrap();
writer.write_raw(&[1, 2, 3, 4]);
}
{
let (header, raw_space) = raw_space.split_at(size_of::<sys::LV2_Atom>());
let header = unsafe { &*(header.as_ptr() as *const sys::LV2_Atom) };
assert_eq!(header.type_, urid);
assert_eq!(header.size as usize, 6);
let (message, _) = raw_space.split_at(6);
assert_eq!(message, &[0xf0, 1, 2, 3, 4, 0xf7]);
}
{
let space = Space::from_reference(raw_space.as_ref());
let message = WMidiEvent::read(space.split_atom_body(urid).unwrap().0, ()).unwrap();
assert_eq!(
message,
MidiMessage::SysEx(unsafe { U7::from_bytes_unchecked(&[1, 2, 3, 4]) })
);
}
}
}