use core_foundation_sys::base::OSStatus;
use std::ops::Deref;
use coremidi_sys::{
kMIDIObjectType_Source, ItemCount, MIDIEndpointDispose, MIDIEndpointRef,
MIDIGetNumberOfSources, MIDIGetSource, MIDIObjectFindByUniqueID, MIDIObjectRef, MIDIObjectType,
MIDIReceived, MIDIReceivedEventList, MIDIUniqueID,
};
use crate::endpoints::endpoint::Endpoint;
use crate::ports::Packets;
use crate::{unit_result_from_status, Object};
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct Source {
pub(crate) endpoint: Endpoint,
}
impl Source {
pub(crate) fn new(endpoint_ref: MIDIEndpointRef) -> Self {
Self {
endpoint: Endpoint::new(endpoint_ref),
}
}
pub fn from_index(index: usize) -> Option<Source> {
let endpoint_ref = unsafe { MIDIGetSource(index as ItemCount) };
match endpoint_ref {
0 => None,
_ => Some(Self::new(endpoint_ref)),
}
}
pub fn from_name(name: &str) -> Option<Source> {
Sources
.into_iter()
.find(|source| source.name().as_deref() == Some(name))
}
pub fn from_unique_id(unique_id: u32) -> Option<Source> {
Sources::find_by_unique_id(unique_id)
}
}
impl Clone for Source {
fn clone(&self) -> Self {
Self::new(self.endpoint.object.0)
}
}
impl AsRef<Object> for Source {
fn as_ref(&self) -> &Object {
&self.endpoint.object
}
}
impl AsRef<Endpoint> for Source {
fn as_ref(&self) -> &Endpoint {
&self.endpoint
}
}
impl Deref for Source {
type Target = Endpoint;
fn deref(&self) -> &Endpoint {
&self.endpoint
}
}
pub struct Sources;
impl Sources {
pub fn count() -> usize {
unsafe { MIDIGetNumberOfSources() as usize }
}
fn find_by_unique_id(unique_id: u32) -> Option<Source> {
let mut obj_ref: MIDIObjectRef = 0;
let mut obj_type: MIDIObjectType = 0;
let status = unsafe {
MIDIObjectFindByUniqueID(unique_id as MIDIUniqueID, &mut obj_ref, &mut obj_type)
};
if status != 0 || obj_type != kMIDIObjectType_Source {
None
} else {
Some(Source::new(obj_ref as MIDIEndpointRef))
}
}
}
impl IntoIterator for Sources {
type Item = Source;
type IntoIter = SourcesIterator;
fn into_iter(self) -> Self::IntoIter {
SourcesIterator {
index: 0,
count: Self::count(),
}
}
}
pub struct SourcesIterator {
index: usize,
count: usize,
}
impl Iterator for SourcesIterator {
type Item = Source;
fn next(&mut self) -> Option<Source> {
if self.index < self.count {
let source = Source::from_index(self.index);
self.index += 1;
source
} else {
None
}
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct VirtualSource {
pub(crate) endpoint: Endpoint,
}
impl VirtualSource {
pub(crate) fn new(endpoint_ref: MIDIEndpointRef) -> Self {
Self {
endpoint: Endpoint::new(endpoint_ref),
}
}
pub fn received<'a, P>(&self, packets: P) -> Result<(), OSStatus>
where
P: Into<Packets<'a>>,
{
let status = match packets.into() {
Packets::BorrowedPacketList(packet_list) => unsafe {
MIDIReceived(self.endpoint.object.0, packet_list.as_ptr())
},
Packets::BorrowedEventList(event_list) => unsafe {
MIDIReceivedEventList(self.endpoint.object.0, event_list.as_ptr())
},
Packets::OwnedEventBuffer(event_buffer) => unsafe {
MIDIReceivedEventList(self.endpoint.object.0, event_buffer.as_ptr())
},
};
unit_result_from_status(status)
}
}
impl Deref for VirtualSource {
type Target = Endpoint;
fn deref(&self) -> &Endpoint {
&self.endpoint
}
}
impl From<Object> for VirtualSource {
fn from(object: Object) -> Self {
Self::new(object.0)
}
}
impl Drop for VirtualSource {
fn drop(&mut self) {
unsafe { MIDIEndpointDispose(self.endpoint.object.0) };
}
}