impl PacketList { /// For internal usage only. /// Requires this instance to actually point to a valid MIDIPacketList pub(crate) unsafefn as_ptr(&self) -> *mut MIDIPacketList { selfas *const PacketList as *mut PacketList as *mut MIDIPacketList
}
}
impl PacketList { /// Check if the packet list is empty. /// pubfn is_empty(&self) -> bool { self.0.numPackets == 0
}
/// Get the number of packets in the list. /// pubfn len(&self) -> usize { self.0.numPackets as usize
}
/// Get an iterator for the packets in the list. /// pubfn iter(&self) -> PacketListIterator {
PacketListIterator {
count: self.len(),
packet_ptr: std::ptr::addr_of!(self.0.packet) as *const MIDIPacket,
_phantom: PhantomData,
}
}
}
impl fmt::Debug for PacketList { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let result = write!(f, "PacketList(ptr={:x}, packets=[", unsafe { self.as_ptr() as usize
}); self.iter()
.enumerate()
.fold(result, |prev_result, (i, packet)| match prev_result {
Err(err) => Err(err),
Ok(()) => { let sep = if i != 0 { ", " } else { "" };
write!(f, "{}{:?}", sep, packet)
}
})
.and_then(|_| write!(f, "])"))
}
}
impl fmt::Display for PacketList { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let num_packets = self.len(); let result = write!(f, "PacketList(len={})", num_packets); self.iter()
.fold(result, |prev_result, packet| match prev_result {
Err(err) => Err(err),
Ok(()) => write!(f, "\n {}", packet),
})
}
}
impl Packet { /// Get the packet timestamp. /// pubfn timestamp(&self) -> Timestamp { self.0.timeStamp as Timestamp
}
/// Get the packet data. This method just gives raw MIDI bytes. You would need another /// library to decode them and work with higher level events. /// /// ``` /// let packet_list = &coremidi::PacketBuffer::new(0, &[0x90, 0x40, 0x7f]); /// let data: Vec<u8> = packet_list.iter().map(|packet| packet.data().to_vec()).flatten().collect(); /// assert_eq!(data, vec![0x90, 0x40, 0x7f]) /// ``` pubfn data(&self) -> &[u8] { let data_ptr = self.0.data.as_ptr(); let data_len = self.0.length as usize; unsafe { slice::from_raw_parts(data_ptr, data_len) }
}
}
impl fmt::Debug for Packet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let result = write!(
f, "Packet(ptr={:x}, ts={:016x}, data=[", selfas *const _ as usize, self.timestamp() as u64
); let result = self
.data()
.iter()
.enumerate()
.fold(result, |prev_result, (i, b)| match prev_result {
Err(err) => Err(err),
Ok(()) => { let sep = if i > 0 { ", " } else { "" };
write!(f, "{}{:02x}", sep, b)
}
});
result.and_then(|_| write!(f, "])"))
}
}
impl fmt::Display for Packet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let result = write!(f, "{:016x}:", self.timestamp()); self.data()
.iter()
.fold(result, |prev_result, b| match prev_result {
Err(err) => Err(err),
Ok(()) => write!(f, " {:02x}", b),
})
}
}
/// A mutable `PacketList` builder. /// /// A `PacketList` is an immutable reference to a [MIDIPacketList](https://developer.apple.com/documentation/coremidi/midipacketlist) structure, /// while a `PacketBuffer` is a mutable structure that allows to build a `PacketList` by adding packets. /// It dereferences to a `PacketList`, so it can be used whenever a `PacketList` is needed. /// pubstruct PacketBuffer {
storage: Storage,
current_packet_offset: usize,
}
/// Create a `PacketBuffer` with a single packet containing the provided timestamp and data. /// /// According to the official documentation for CoreMIDI, the timestamp represents /// the time at which the events are to be played, where zero means "now". /// The timestamp applies to the first MIDI byte in the packet. /// /// Example on how to create a `PacketBuffer` with a single packet for a MIDI note on for C-5: /// /// ``` /// use coremidi::PacketBuffer; /// let buffer = PacketBuffer::new(0, &[0x90, 0x3c, 0x7f]); /// assert_eq!(buffer.len(), 1); /// assert_eq!(buffer.iter().next().map(|packet| packet.data().to_vec()), Some(vec![0x90, 0x3c, 0x7f])) /// ``` pubfn new(timestamp: Timestamp, data: &[u8]) -> Self { let capacity = data.len() + Self::PACKET_LIST_HEADER_SIZE + Self::PACKET_HEADER_SIZE; letmut storage = Storage::with_capacity(capacity); let packet_list_ptr = unsafe { storage.as_mut_ptr::<MIDIPacketList>() }; let current_packet_ptr = unsafe { MIDIPacketListInit(packet_list_ptr) }; let current_packet_ptr = unsafe {
MIDIPacketListAdd(
packet_list_ptr,
storage.capacity() as u64,
current_packet_ptr,
timestamp,
data.len() as u64,
data.as_ptr(),
)
}; let current_packet_offset = unsafe {
(current_packet_ptr as *const u8).offset_from(packet_list_ptr as *const u8) as usize
};
Self {
storage,
current_packet_offset,
}
}
/// Create an empty `PacketBuffer` with no packets. /// /// Example on how to create an empty `PacketBuffer` /// with a capacity for 128 bytes in total (including headers): /// /// ``` /// let buffer = coremidi::PacketBuffer::with_capacity(128); /// assert_eq!(buffer.len(), 0); /// assert_eq!(buffer.capacity(), 128); /// ``` pubfn with_capacity(capacity: usize) -> Self { let capacity = std::cmp::max(capacity, Storage::INLINE_SIZE); letmut storage = Storage::with_capacity(capacity); let packet_list_ptr = unsafe { storage.as_mut_ptr::<MIDIPacketList>() }; let current_packet_ptr = unsafe { MIDIPacketListInit(packet_list_ptr) }; let current_packet_offset =
(current_packet_ptr as *const u8 as usize) - (packet_list_ptr as *const u8 as usize);
Self {
storage,
current_packet_offset,
}
}
/// Get underlying buffer capacity in bytes pubfn capacity(&self) -> usize { self.storage.capacity()
}
/// Add a new event containing the provided timestamp and data. /// /// According to the official documentation for CoreMIDI, the timestamp represents /// the time at which the events are to be played, where zero means "now". /// The timestamp applies to the first MIDI byte in the packet. /// /// An event must not have a timestamp that is smaller than that of a previous event /// in the same `PacketList` /// /// Example: /// /// ``` /// let mut chord = coremidi::PacketBuffer::new(0, &[0x90, 0x3c, 0x7f]); /// chord.push_data(0, &[0x90, 0x40, 0x7f]); /// assert_eq!(chord.len(), 1); /// let repr = format!("{}", &chord as &coremidi::PacketList); /// assert_eq!(repr, "PacketList(len=1)\n 0000000000000000: 90 3c 7f 90 40 7f"); /// ``` pubfn push_data(&mutself, timestamp: Timestamp, data: &[u8]) -> &n style='color:red'>mut Self { self.ensure_capacity(data.len());
let packet_list_ptr = unsafe { self.storage.as_mut_ptr::<MIDIPacketList>() }; let current_packet_ptr = unsafe { self.storage.as_ptr::<u8>().add(self.current_packet_offset) as *mut MIDIPacket
};
let current_packet_ptr = unsafe {
MIDIPacketListAdd(
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
}
/// Clears the buffer, removing all packets. /// Note that this method has no effect on the allocated capacity of the buffer. pubfn clear(&mutself) { let packet_list_ptr = unsafe { self.storage.as_mut_ptr::<MIDIPacketList>() }; let current_packet_ptr = unsafe { MIDIPacketListInit(packet_list_ptr) }; self.current_packet_offset = unsafe {
(current_packet_ptr as *const u8).offset_from(packet_list_ptr as *const u8) as usize
};
}
/// Compares the results of building a PacketList using our PacketBuffer API /// and the native API (MIDIPacketListAdd, etc). unsafefn compare_packet_list(packets: Vec<(MIDITimeStamp, Vec<u8>)>) { // allocate a buffer on the stack for building the list using native methods const BUFFER_SIZE: usize = 65536; // maximum allowed size let buffer: &mut [u8] = &mut [0; BUFFER_SIZE]; let pkt_list_ptr = buffer.as_mut_ptr() as *mut MIDIPacketList;
// build the list letmut pkt_ptr = MIDIPacketListInit(pkt_list_ptr); for pkt in &packets {
pkt_ptr = MIDIPacketListAdd(
pkt_list_ptr,
BUFFER_SIZE as u64,
pkt_ptr,
pkt.0,
pkt.1.len() as u64,
pkt.1.as_ptr(),
);
assert!(!pkt_ptr.is_null());
} let list_native = &*(pkt_list_ptr as *const _ as *const PacketList);
// build the PacketBuffer, containing the same packets letmut packet_buf = PacketBuffer::new(packets[0].0, &packets[0].1); for pkt in &packets[1..] {
packet_buf.push_data(pkt.0, &pkt.1);
}
// check if the contents match
assert_eq!(
list_native.len(),
list.len(), "PacketList lengths must match"
); for (n, p) in list_native.iter().zip(list.iter()) {
assert_eq!(n.data(), p.data());
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-08-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.