extern crate jack_sys; extern crate libc; use self::jack_sys::jack_nframes_t; use self::libc::c_void; use std::{mem, slice}; use std::ffi::CString; mod wrappers; use self::wrappers::*; use ::{Ignore, MidiMessage}; use ::errors::*; const OUTPUT_RINGBUFFER_SIZE: usize = 16384; struct InputHandlerData { port: Option, ignore_flags: Ignore, callback: Box, user_data: Option } pub struct MidiInput { ignore_flags: Ignore, client: Option, } #[derive(Clone, PartialEq)] pub struct MidiInputPort { name: CString } pub struct MidiInputConnection { handler_data: Box>, client: Option } impl MidiInput { pub fn new(client_name: &str) -> Result { let client = match Client::open(client_name, JackOpenOptions::NoStartServer) { Ok(c) => c, Err(_) => { return Err(InitError); } // TODO: maybe add message that Jack server might not be running }; Ok(MidiInput { ignore_flags: Ignore::None, client: Some(client), }) } pub fn ignore(&mut self, flags: Ignore) { self.ignore_flags = flags; } pub(crate) fn ports_internal(&self) -> Vec<::common::MidiInputPort> { let ports = self.client.as_ref().unwrap().get_midi_ports(PortFlags::PortIsOutput); let mut result = Vec::with_capacity(ports.count()); for i in 0..ports.count() { result.push(::common::MidiInputPort { imp: MidiInputPort { name: ports.get_c_name(i).into() } }) } result } pub fn port_count(&self) -> usize { self.client.as_ref().unwrap().get_midi_ports(PortFlags::PortIsOutput).count() } pub fn port_name(&self, port: &MidiInputPort) -> Result { Ok(port.name.to_string_lossy().into()) } fn activate_callback(&mut self, callback: F, data: T) -> Box> where F: FnMut(u64, &[u8], &mut T) + Send + 'static { let handler_data = Box::new(InputHandlerData { port: None, ignore_flags: self.ignore_flags, callback: Box::new(callback), user_data: Some(data) }); let data_ptr = unsafe { mem::transmute_copy::<_, *mut InputHandlerData>(&handler_data) }; self.client.as_mut().unwrap().set_process_callback(handle_input::, data_ptr as *mut c_void); self.client.as_mut().unwrap().activate(); handler_data } pub fn connect( mut self, port: &MidiInputPort, port_name: &str, callback: F, data: T ) -> Result, ConnectError> where F: FnMut(u64, &[u8], &mut T) + Send + 'static { let mut handler_data = self.activate_callback(callback, data); // Create port ... let dest_port = match self.client.as_mut().unwrap().register_midi_port(port_name, PortFlags::PortIsInput) { Ok(p) => p, Err(()) => { return Err(ConnectError::other("could not register JACK port", self)); } }; // ... and connect it to the output if let Err(_) = self.client.as_mut().unwrap().connect(&port.name, dest_port.get_name()) { return Err(ConnectError::new(ConnectErrorKind::InvalidPort, self)); } handler_data.port = Some(dest_port); Ok(MidiInputConnection { handler_data: handler_data, client: self.client.take() }) } pub fn create_virtual( mut self, port_name: &str, callback: F, data: T ) -> Result, ConnectError> where F: FnMut(u64, &[u8], &mut T) + Send + 'static { let mut handler_data = self.activate_callback(callback, data); // Create port let port = match self.client.as_mut().unwrap().register_midi_port(port_name, PortFlags::PortIsInput) { Ok(p) => p, Err(()) => { return Err(ConnectError::other("could not register JACK port", self)); } }; handler_data.port = Some(port); Ok(MidiInputConnection { handler_data: handler_data, client: self.client.take() }) } } impl MidiInputConnection { pub fn close(mut self) -> (MidiInput, T) { self.close_internal(); (MidiInput { client: self.client.take(), ignore_flags: self.handler_data.ignore_flags, }, self.handler_data.user_data.take().unwrap()) } fn close_internal(&mut self) { let port = self.handler_data.port.take().unwrap(); self.client.as_mut().unwrap().unregister_midi_port(port); self.client.as_mut().unwrap().deactivate(); } } impl Drop for MidiInputConnection { fn drop(&mut self) { if self.client.is_some() { self.close_internal(); } } } extern "C" fn handle_input(nframes: jack_nframes_t, arg: *mut c_void) -> i32 { let data: &mut InputHandlerData = unsafe { &mut *(arg as *mut InputHandlerData) }; // Is port created? if let Some(ref port) = data.port { let buff = port.get_midi_buffer(nframes); let mut message = MidiMessage::new(); // TODO: create MidiMessage once and reuse its buffer for every handle_input call // We have midi events in buffer let evcount = buff.get_event_count(); let mut event = mem::MaybeUninit::uninit(); for j in 0..evcount { message.bytes.clear(); unsafe { buff.get_event(event.as_mut_ptr(), j) }; let event = unsafe { event.assume_init() }; for i in 0..event.size { message.bytes.push(unsafe { *event.buffer.offset(i as isize) }); } message.timestamp = Client::get_time(); // this is in microseconds (data.callback)(message.timestamp, &message.bytes, data.user_data.as_mut().unwrap()); } } return 0; } struct OutputHandlerData { port: Option, buff_size: Ringbuffer, buff_message: Ringbuffer, } pub struct MidiOutput { client: Option, } #[derive(Clone, PartialEq)] pub struct MidiOutputPort { name: CString } pub struct MidiOutputConnection { handler_data: Box, client: Option } impl MidiOutput { pub fn new(client_name: &str) -> Result { let client = match Client::open(client_name, JackOpenOptions::NoStartServer) { Ok(c) => c, Err(_) => { return Err(InitError); } // TODO: maybe add message that Jack server might not be running }; Ok(MidiOutput { client: Some(client), }) } pub(crate) fn ports_internal(&self) -> Vec<::common::MidiOutputPort> { let ports = self.client.as_ref().unwrap().get_midi_ports(PortFlags::PortIsInput); let mut result = Vec::with_capacity(ports.count()); for i in 0..ports.count() { result.push(::common::MidiOutputPort { imp: MidiOutputPort { name: ports.get_c_name(i).into() } }) } result } pub fn port_count(&self) -> usize { self.client.as_ref().unwrap().get_midi_ports(PortFlags::PortIsInput).count() } pub fn port_name(&self, port: &MidiOutputPort) -> Result { Ok(port.name.to_string_lossy().into()) } fn activate_callback(&mut self) -> Box { let handler_data = Box::new(OutputHandlerData { port: None, buff_size: Ringbuffer::new(OUTPUT_RINGBUFFER_SIZE), buff_message: Ringbuffer::new(OUTPUT_RINGBUFFER_SIZE) }); let data_ptr = unsafe { mem::transmute_copy::<_, *mut OutputHandlerData>(&handler_data) }; self.client.as_mut().unwrap().set_process_callback(handle_output, data_ptr as *mut c_void); self.client.as_mut().unwrap().activate(); handler_data } pub fn connect(mut self, port: &MidiOutputPort, port_name: &str) -> Result> { let mut handler_data = self.activate_callback(); // Create port ... let source_port = match self.client.as_mut().unwrap().register_midi_port(port_name, PortFlags::PortIsOutput) { Ok(p) => p, Err(()) => { return Err(ConnectError::other("could not register JACK port", self)); } }; // ... and connect it to the input if let Err(_) = self.client.as_mut().unwrap().connect(source_port.get_name(), &port.name) { return Err(ConnectError::new(ConnectErrorKind::InvalidPort, self)); } handler_data.port = Some(source_port); Ok(MidiOutputConnection { handler_data: handler_data, client: self.client.take() }) } pub fn create_virtual( mut self, port_name: &str ) -> Result> { let mut handler_data = self.activate_callback(); // Create port let port = match self.client.as_mut().unwrap().register_midi_port(port_name, PortFlags::PortIsOutput) { Ok(p) => p, Err(()) => { return Err(ConnectError::other("could not register JACK port", self)); } }; handler_data.port = Some(port); Ok(MidiOutputConnection { handler_data: handler_data, client: self.client.take() }) } } impl MidiOutputConnection { pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> { let nbytes = message.len(); // Write full message to buffer let written = self.handler_data.buff_message.write(message); debug_assert!(written == nbytes, "not enough bytes written to ALSA ringbuffer `message`"); let nbytes_slice = unsafe { slice::from_raw_parts(&nbytes as *const usize as *const u8, mem::size_of_val(&nbytes)) }; let written = self.handler_data.buff_size.write(nbytes_slice); debug_assert!(written == mem::size_of_val(&nbytes), "not enough bytes written to ALSA ringbuffer `size`"); Ok(()) } pub fn close(mut self) -> MidiOutput { self.close_internal(); MidiOutput { client: self.client.take(), } } fn close_internal(&mut self) { let port = self.handler_data.port.take().unwrap(); self.client.as_mut().unwrap().unregister_midi_port(port); self.client.as_mut().unwrap().deactivate(); } } impl Drop for MidiOutputConnection { fn drop(&mut self) { if self.client.is_some() { self.close_internal(); } } } extern "C" fn handle_output(nframes: jack_nframes_t, arg: *mut c_void) -> i32 { let data: &mut OutputHandlerData = unsafe { mem::transmute(arg) }; // Is port created? if let Some(ref port) = data.port { let mut space: usize = 0; let mut buff = port.get_midi_buffer(nframes); buff.clear(); while data.buff_size.get_read_space() > 0 { let read = data.buff_size.read(&mut space as *mut usize as *mut u8, mem::size_of::()); debug_assert!(read == mem::size_of::(), "not enough bytes read from `size` ringbuffer"); let midi_data = buff.event_reserve(0, space); let read = data.buff_message.read(midi_data, space); debug_assert!(read == space, "not enough bytes read from `message` ringbuffer"); } } return 0; }