use std::fmt::Formatter;
use std::marker::PhantomData;
use std::mem::size_of;
use std::ops::Deref;
use std::slice;
use coremidi_sys::{
MIDIEventList, MIDIEventListAdd, MIDIEventListInit, MIDIEventPacket, MIDIEventPacketNext,
};
use crate::protocol::Protocol;
pub type Timestamp = u64;
pub struct EventList(MIDIEventList);
impl EventList {
pub fn protocol(&self) -> Protocol {
Protocol::from(self.0.protocol)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
self.0.numPackets as usize
}
pub fn iter(&self) -> EventListIter {
EventListIter {
count: self.len(),
packet_ptr: std::ptr::addr_of!(self.0.packet) as *const MIDIEventPacket,
_phantom: PhantomData,
}
}
pub(crate) unsafe fn as_ptr(&self) -> *const MIDIEventList {
self as *const EventList as *const MIDIEventList
}
}
impl std::fmt::Debug for EventList {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
writeln!(
f,
"EventList(protocol={:?}, packets={})",
self.protocol(),
self.len()
)?;
for packet in self.iter() {
writeln!(f, "{:?}", packet)?;
}
Ok(())
}
}
pub struct EventListIter<'a> {
count: usize,
packet_ptr: *const MIDIEventPacket,
_phantom: PhantomData<&'a MIDIEventPacket>,
}
impl<'a> Iterator for EventListIter<'a> {
type Item = &'a EventPacket;
fn next(&mut self) -> Option<&'a EventPacket> {
if self.count > 0 {
let packet = unsafe { &*(self.packet_ptr as *const EventPacket) };
self.count -= 1;
self.packet_ptr = unsafe { MIDIEventPacketNext(self.packet_ptr) };
Some(packet)
} else {
None
}
}
}
pub struct EventPacket(MIDIEventPacket);
impl EventPacket {
pub fn timestamp(&self) -> Timestamp {
self.0.timeStamp as Timestamp
}
pub fn data(&self) -> &[u32] {
let data_ptr = self.0.words.as_ptr();
let data_len = self.0.wordCount as usize;
unsafe { slice::from_raw_parts(data_ptr, data_len) }
}
}
impl std::fmt::Debug for EventPacket {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, " {:024}:", self.timestamp())?;
for word in self.data().iter() {
write!(f, " {:08x}", word)?;
}
Ok(())
}
}
#[derive(Clone)]
pub struct EventBuffer {
storage: Storage,
current_packet_offset: usize,
}
impl EventBuffer {
const PACKET_HEADER_SIZE: usize = 8 + 4;
pub fn new(protocol: Protocol) -> Self {
Self::with_capacity(Storage::INLINE_SIZE, protocol)
}
pub fn with_capacity(capacity: usize, protocol: Protocol) -> Self {
let mut storage = Storage::with_capacity(capacity);
let event_list_ptr = unsafe { storage.as_mut_ptr::<MIDIEventList>() };
let current_packet_ptr = unsafe { MIDIEventListInit(event_list_ptr, protocol.into()) };
let current_packet_offset = unsafe {
(current_packet_ptr as *const u8).offset_from(event_list_ptr as *const u8) as usize
};
Self {
storage,
current_packet_offset,
}
}
pub fn capacity(&self) -> usize {
self.storage.capacity()
}
pub fn with_packet(mut self, timestamp: Timestamp, data: &[u32]) -> Self {
self.push(timestamp, data);
self
}
pub fn push(&mut self, timestamp: Timestamp, data: &[u32]) -> &mut Self {
self.ensure_capacity(data.len());
let packet_list_ptr = unsafe { self.storage.as_mut_ptr::<MIDIEventList>() };
let current_packet_ptr = unsafe {
self.storage.as_ptr::<u8>().add(self.current_packet_offset) as *mut MIDIEventPacket
};
let current_packet_ptr = unsafe {
MIDIEventListAdd(
packet_list_ptr,
self.storage.capacity() as u64,
current_packet_ptr,
timestamp,
data.len() as u64,
data.as_ptr(),
)
};
self.current_packet_offset = unsafe {
(current_packet_ptr as *const u8).offset_from(packet_list_ptr as *const u8) as usize
};
self
}
pub fn clear(&mut self) {
let event_list_ptr = unsafe { self.storage.as_mut_ptr::<MIDIEventList>() };
let protocol = unsafe { (*event_list_ptr).protocol };
let current_packet_ptr = unsafe { MIDIEventListInit(event_list_ptr, protocol) };
self.current_packet_offset = unsafe {
(current_packet_ptr as *const u8).offset_from(event_list_ptr as *const u8) as usize
};
}
fn ensure_capacity(&mut self, data_len: usize) {
let next_capacity =
self.aligned_bytes_len() + Self::PACKET_HEADER_SIZE + data_len * size_of::<u32>();
unsafe {
self.storage.ensure_capacity(next_capacity);
}
}
#[inline]
fn aligned_bytes_len(&self) -> usize {
let storage_start_ptr = unsafe { self.storage.as_ptr::<u8>() };
if self.as_ref().is_empty() {
self.current_packet_offset
} else {
let current_packet = unsafe {
&*(self.storage.as_ptr::<u8>().add(self.current_packet_offset)
as *const MIDIEventPacket)
};
let current_packet_data_ptr = current_packet.words.as_ptr() as *const u8;
let data_offset = current_packet_data_ptr as *const u8 as usize
- storage_start_ptr as *const u8 as usize;
let data_len = current_packet.wordCount as usize * size_of::<u32>();
(data_offset + data_len + 3) & !3
}
}
}
impl AsRef<EventList> for EventBuffer {
#[inline]
fn as_ref(&self) -> &EventList {
unsafe { &*self.storage.as_ptr::<EventList>() }
}
}
impl Deref for EventBuffer {
type Target = EventList;
#[inline]
fn deref(&self) -> &EventList {
self.as_ref()
}
}
#[derive(Clone)]
pub(crate) enum Storage {
Inline([u32; Storage::INLINE_SIZE / 4]),
External(Vec<u32>),
}
impl Storage {
pub(crate) const INLINE_SIZE: usize = 8 + 12 + 4 * 4;
#[inline]
#[allow(clippy::uninit_vec)]
pub(crate) fn with_capacity(capacity: usize) -> Self {
if capacity <= Self::INLINE_SIZE {
Self::Inline([0; Self::INLINE_SIZE / 4])
} else {
let u32_len = ((capacity - 1) / 4) + 1;
let mut buffer = Vec::with_capacity(u32_len);
unsafe {
buffer.set_len(u32_len);
}
Storage::External(buffer)
}
}
#[inline]
pub(crate) fn capacity(&self) -> usize {
match *self {
Storage::Inline(ref inline) => inline.len() * 4,
Storage::External(ref vec) => vec.len() * 4,
}
}
#[inline]
pub(crate) fn get_slice<T>(&self) -> &[T] {
unsafe {
match *self {
Storage::Inline(ref inline) => slice::from_raw_parts(
inline.as_ptr() as *const T,
inline.len() * size_of::<u32>() / size_of::<T>(),
),
Storage::External(ref vec) => {
slice::from_raw_parts(vec.as_ptr() as *const T, vec.len() * 4 / size_of::<T>())
}
}
}
}
#[allow(clippy::uninit_vec)]
pub(crate) unsafe fn ensure_capacity(&mut self, capacity: usize) {
if capacity < Self::INLINE_SIZE || capacity < self.get_slice::<u8>().len() {
return;
}
let vec_capacity = ((capacity - 1) / 4) + 1;
let vec: Option<Vec<u32>> = match *self {
Storage::Inline(ref inline) => {
let mut v = Vec::with_capacity(vec_capacity);
v.extend_from_slice(inline);
v.set_len(vec_capacity);
Some(v)
}
Storage::External(ref mut vec) => {
let current_len = vec.len();
vec.reserve(vec_capacity - current_len);
vec.set_len(vec_capacity);
None
}
};
if let Some(v) = vec {
*self = Storage::External(v);
}
}
#[inline]
pub(crate) unsafe fn as_ptr<T>(&self) -> *const T {
match *self {
Storage::Inline(ref inline) => inline.as_ptr() as *const T,
Storage::External(ref vec) => vec.as_ptr() as *const T,
}
}
#[inline]
pub(crate) unsafe fn as_mut_ptr<T>(&mut self) -> *mut T {
self.as_ptr::<T>() as *mut T
}
}
impl std::fmt::Debug for Storage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for b in self.get_slice::<u8>() {
write!(f, " {:02x}", *b)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::events::{Storage, Timestamp};
use crate::protocol::Protocol;
use crate::{EventBuffer, EventList};
use coremidi_sys::{
kMIDIProtocol_2_0, ByteCount, MIDIEventList, MIDIEventListAdd, MIDIEventListInit,
MIDIProtocolID,
};
#[test]
fn event_list_accessors() {
const BUFFER_SIZE: usize = 256;
let buffer = [0u8; BUFFER_SIZE];
let event_list_ptr = buffer.as_ptr() as *const MIDIEventList as *mut MIDIEventList;
let event_packet_ptr =
unsafe { MIDIEventListInit(event_list_ptr, kMIDIProtocol_2_0 as MIDIProtocolID) };
let event_packet_ptr = unsafe {
MIDIEventListAdd(
event_list_ptr,
BUFFER_SIZE as ByteCount,
event_packet_ptr,
10,
2,
[1, 2].as_ptr(),
)
};
let _ = unsafe {
MIDIEventListAdd(
event_list_ptr,
BUFFER_SIZE as ByteCount,
event_packet_ptr,
20,
3,
[3, 4, 5].as_ptr(),
)
};
let event_list = unsafe { &*(event_list_ptr as *const EventList) };
assert_eq!(event_list.protocol(), Protocol::Midi20);
assert!(!event_list.is_empty());
assert_eq!(event_list.len(), 2);
assert_eq!(
event_list
.iter()
.map(|packet| (packet.timestamp(), packet.data().to_vec()))
.collect::<Vec<(Timestamp, Vec<u32>)>>(),
vec![(10, vec![1, 2]), (20, vec![3, 4, 5]),]
);
}
#[test]
fn event_buffer_new() {
let event_buffer = EventBuffer::new(Protocol::Midi20);
assert_eq!(event_buffer.capacity(), Storage::INLINE_SIZE);
assert_eq!(event_buffer.protocol(), Protocol::Midi20);
assert_eq!(event_buffer.len(), 0);
}
#[test]
fn event_buffer_with_capacity_inline() {
let event_buffer = EventBuffer::with_capacity(2, Protocol::Midi20);
assert_eq!(event_buffer.capacity(), Storage::INLINE_SIZE);
assert_eq!(event_buffer.protocol(), Protocol::Midi20);
assert_eq!(event_buffer.len(), 0);
}
#[test]
fn event_buffer_with_capacity_external() {
let event_buffer = EventBuffer::with_capacity(Storage::INLINE_SIZE * 2, Protocol::Midi20);
assert_eq!(event_buffer.capacity(), Storage::INLINE_SIZE * 2);
}
#[test]
fn event_buffer_with_packet() {
let event_buffer = EventBuffer::new(Protocol::Midi20)
.with_packet(10, &[1, 2])
.with_packet(20, &[3, 4, 5]);
assert_eq!(event_buffer.len(), 2);
assert_eq!(
event_buffer
.iter()
.map(|packet| (packet.timestamp(), packet.data().to_vec()))
.collect::<Vec<(Timestamp, Vec<u32>)>>(),
vec![(10, vec![1, 2]), (20, vec![3, 4, 5]),]
);
}
#[test]
fn event_buffer_push_within_capacity() {
let mut event_buffer = EventBuffer::new(Protocol::Midi20);
event_buffer.push(10, &[1, 2]).push(20, &[3, 4, 5]);
assert_eq!(event_buffer.len(), 2);
assert_eq!(
event_buffer
.iter()
.map(|packet| (packet.timestamp(), packet.data().to_vec()))
.collect::<Vec<(Timestamp, Vec<u32>)>>(),
vec![(10, vec![1, 2]), (20, vec![3, 4, 5]),]
);
}
#[test]
fn event_buffer_push_over_capacity() {
let mut event_buffer = EventBuffer::new(Protocol::Midi20);
event_buffer
.push(10, &[1, 2])
.push(20, &[3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(event_buffer.len(), 2);
assert_eq!(
event_buffer
.iter()
.map(|packet| (packet.timestamp(), packet.data().to_vec()))
.collect::<Vec<(Timestamp, Vec<u32>)>>(),
vec![(10, vec![1, 2]), (20, vec![3, 4, 5, 6, 7, 8, 9, 10])]
);
}
#[test]
fn event_buffer_clear() {
let mut event_buffer = EventBuffer::new(Protocol::Midi20).with_packet(10, &[1, 2]);
assert_eq!(event_buffer.len(), 1);
assert_eq!(
event_buffer
.iter()
.map(|packet| (packet.timestamp(), packet.data().to_vec()))
.collect::<Vec<(Timestamp, Vec<u32>)>>(),
vec![(10, vec![1, 2])]
);
event_buffer.clear();
assert_eq!(event_buffer.len(), 0);
assert_eq!(event_buffer.capacity(), Storage::INLINE_SIZE);
assert_eq!(
event_buffer
.iter()
.map(|packet| (packet.timestamp(), packet.data().to_vec()))
.collect::<Vec<(Timestamp, Vec<u32>)>>(),
vec![]
);
}
}