use context::PortMidi;
use device::DeviceInfo;
use ffi;
use ffi::MaybeError;
use std::marker::Send;
use std::os::raw::c_int;
use std::ptr;
use types::*;
pub struct InputPort<'a> {
stream: *const ffi::PortMidiStream,
buffer_size: usize,
_context: &'a PortMidi, device: DeviceInfo,
}
impl<'a> InputPort<'a> {
pub fn new(context: &'a PortMidi, device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
if device.is_output() {
return Err(Error::NotAnInputDevice);
}
let raw_stream: *const ffi::PortMidiStream = ptr::null();
Result::from(unsafe {
ffi::Pm_OpenInput(
&raw_stream as *const *const _,
device.id(),
ptr::null(), buffer_size as c_int,
ptr::null(), ptr::null(),
) })?;
Ok(InputPort {
stream: raw_stream,
buffer_size,
_context: context,
device,
})
}
pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
let read_cnt = if cnt > self.buffer_size {
self.buffer_size as c_int
} else {
cnt as c_int
};
let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
match ffi::PmError::try_from(res) {
Ok(event_cnt) => {
let events = (0..event_cnt as usize)
.map(|i| MidiEvent::from(event_buffer[i]))
.collect::<Vec<MidiEvent>>();
Ok(Some(events))
}
Err(ffi::PmError::PmNoError) => Ok(None),
Err(err) => Err(Error::PortMidi(err)),
}
}
pub fn read(&mut self) -> Result<Option<MidiEvent>> {
let mut event = ffi::PmEvent::default();
let read_cnt = 1;
let res = unsafe { ffi::Pm_Read(self.stream, &mut event, read_cnt) };
match ffi::PmError::try_from(res) {
Ok(0) => Ok(None),
Ok(_) => Ok(Some(MidiEvent::from(event))),
Err(ffi::PmError::PmNoError) => Ok(None),
Err(err) => Err(Error::PortMidi(err)),
}
}
pub fn poll(&self) -> Result<bool> {
let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
match pm_error {
ffi::PmError::PmNoError => Ok(false),
ffi::PmError::PmGotData => Ok(true),
err => Err(Error::PortMidi(err)),
}
}
pub fn device(&self) -> DeviceInfo {
self.device.clone()
}
}
impl<'a> Drop for InputPort<'a> {
fn drop(&mut self) {
if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
println!("{}", err);
}
}
}
unsafe impl<'a> Send for InputPort<'a> {}
pub struct OutputPort<'a> {
stream: *const ffi::PortMidiStream,
_context: &'a PortMidi, device: DeviceInfo,
}
impl<'a> OutputPort<'a> {
pub fn new(
context: &'a PortMidi,
device: DeviceInfo,
buffer_size: usize,
) -> Result<OutputPort> {
if device.is_input() {
return Err(Error::NotAnOutputDevice);
}
let raw_stream: *const ffi::PortMidiStream = ptr::null();
Result::from(unsafe {
ffi::Pm_OpenOutput(
&raw_stream as *const *const _,
device.id(),
ptr::null(), buffer_size as c_int,
ptr::null(), ptr::null(), 0,
) })?;
Ok(OutputPort {
stream: raw_stream,
_context: context,
device,
})
}
pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
self.write_events(vec![midi_event])
}
pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
let events: Vec<ffi::PmEvent> = midi_events
.into_iter()
.map(|event| event.into().into())
.collect();
Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
}
pub fn write_message<T: Into<MidiMessage>>(&mut self, midi_message: T) -> Result<()> {
Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, midi_message.into().into()) })
}
pub fn device(&self) -> DeviceInfo {
self.device.clone()
}
pub fn write_sysex(&self, timestamp: ffi::PmTimestamp, msg: &[u8]) -> Result<()> {
if Some(&ffi::MIDI_EOX) != msg.last() {
Err(Error::Invalid)
} else {
Result::from(unsafe { ffi::Pm_WriteSysEx(self.stream, timestamp, msg.as_ptr()) })
}
}
}
impl<'a> Drop for OutputPort<'a> {
fn drop(&mut self) {
if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
println!("{}", err);
}
}
}
unsafe impl<'a> Send for OutputPort<'a> {}