let threadbuilder = Builder::new(); let name = format!("midir ALSA input handler (port '{}')", port_name); let threadbuilder = threadbuilder.name(name); let thread = match threadbuilder.spawn(move || { letmut d = data; let h = handle_input(handler_data, &mut d);
(h, d) // return both the handler data and the user data
}) {
Ok(handle) => handle,
Err(_) => { //unsafe { snd_seq_unsubscribe_port(self.seq.as_mut_ptr(), sub.as_ptr()) }; return Err(ConnectError::other( "could not start ALSA input handler thread", self,
));
}
};
let threadbuilder = Builder::new(); let thread = match threadbuilder.spawn(move || { letmut d = data; let h = handle_input(handler_data, &mut d);
(h, d) // return both the handler data and the user data
}) {
Ok(handle) => handle,
Err(_) => { //unsafe { snd_seq_unsubscribe_port(self.seq.as_mut_ptr(), sub.as_ptr()) }; return Err(ConnectError::other( "could not start ALSA input handler thread", self,
));
}
};
/// This must only be called if the handler thread has not yet been shut down fn close_internal(&mutself) -> (HandlerData<T>, T) { // Request the thread to stop. let _res = unsafe {
libc::write( self.trigger_send_fd.as_ref().expect("send_fd already taken").get(),
&falseas *const bool as *const _,
mem::size_of::<bool>() as libc::size_t,
)
};
let thread = self.thread.take().unwrap(); // Join the thread to get the handler_data back let (mut handler_data, user_data) = match thread.join() {
Ok(data) => data, // TODO: handle this more gracefully?
Err(e) => { iflet Some(e) = e.downcast_ref::<&'static str>() {
panic!("Error when joining ALSA thread: {}", e);
} else {
panic!("Unknown error when joining ALSA thread: {:?}", e);
}
}
};
// TODO: find out why snd_seq_unsubscribe_port takes a long time if there was not yet any input message iflet Some(ref subscription) = self.subscription { let _ = handler_data
.seq
.unsubscribe_port(subscription.get_sender(), subscription.get_dest());
}
// Close the trigger fds
handler_data.trigger_rcv_fd = None; self.trigger_send_fd = None;
// Stop and free the input queue if !cfg!(feature = "avoid_timestamping") { let _ = handler_data
.seq
.control_queue(handler_data.queue_id, EventType::Stop, 0, None); let _ = handler_data.seq.drain_output(); let _ = handler_data.seq.free_queue(handler_data.queue_id);
}
// Delete the port let _ = handler_data.seq.delete_port(self.vport);
(handler_data, user_data)
}
}
impl<T> Drop for MidiInputConnection<T> { fn drop(&mutself) { // Use `self.thread` as a flag whether the connection has already been dropped ifself.thread.is_some() { self.close_internal();
}
}
}
pubstruct MidiOutput {
seq: Option<Seq>, // TODO: if `Seq` is marked as non-zero, this should just be pointer-sized
}
pubfn send(&mutself, message: &[u8]) -> Result<(), SendError> { let nbytes = message.len();
assert!(nbytes <= u32::max_value() as usize);
if nbytes > self.coder.get_buffer_size() as usize { ifself.coder.resize_buffer(nbytes as u32).is_err() { return Err(SendError::Other("could not resize ALSA encoding buffer"));
}
}
// ALSA documentation says: // The required buffer size for a sequencer event it as most 12 bytes, except for System Exclusive events (which we handle separately) letmut buffer = [0; 12];
{ // open scope where we can borrow data.seq letmut seq_input = data.seq.input();
letmut do_input = true; while do_input { iflet Ok(0) = seq_input.event_input_pending(true) { // No data pending if helpers::poll(&mut poll_fds, -1) >= 0 { // Read from our "channel" whether we should stop the thread if poll_fds[0].revents & libc::POLLIN != 0 { let _res = unsafe {
libc::read(
poll_fds[0].fd,
mem::transmute(&mut do_input),
mem::size_of::<bool>() as libc::size_t,
)
};
}
} continue;
}
// This is a bit weird, but we now have to decode an ALSA MIDI // event (back) into MIDI bytes. We'll ignore non-MIDI types.
// The ALSA sequencer has a maximum buffer size for MIDI sysex // events of 256 bytes. If a device sends sysex messages larger // than this, they are segmented into 256 byte chunks. So, // we'll watch for this and concatenate sysex chunks into a // single sysex message if necessary. // // TODO: Figure out if this is still true (seems to not be the case) // If not (i.e., each event represents a complete message), we can // call the user callback with the byte buffer directly, without the // copying to `message.bytes` first. if !continue_sysex {
message.bytes.clear()
}
let ignore_flags = data.ignore_flags;
// If here, there should be data. letmut ev = match seq_input.event_input() {
Ok(ev) => ev,
Err(ref e) if e.errno() == libc::ENOSPC => { let _ = writeln!(
stderr(), "\nError in handle_input: ALSA MIDI input buffer overrun!\n"
); continue;
}
Err(ref e) if e.errno() == libc::EAGAIN => { let _ = writeln!(
stderr(), "\nError in handle_input: no input event from ALSA MIDI input buffer!\n"
); continue;
}
Err(ref e) => { let _ = writeln!(
stderr(), "\nError in handle_input: unknown ALSA MIDI input error ({})!\n",
e
); //perror("System reports"); continue;
}
};
let do_decode = match ev.get_type() {
EventType::PortSubscribed => { if cfg!(debug) {
println!("Notice from handle_input: ALSA port connection made!")
}; false
}
EventType::PortUnsubscribed => { if cfg!(debug) { let _ = writeln!(
stderr(), "Notice from handle_input: ALSA port connection has closed!"
); let connect = ev.get_data::<Connect>().unwrap(); let _ = writeln!(
stderr(), "sender = {}:{}, dest = {}:{}",
connect.sender.client,
connect.sender.port,
connect.dest.client,
connect.dest.port
);
} false
}
EventType::Qframe => { // MIDI time code
!ignore_flags.contains(Ignore::Time)
}
EventType::Tick => { // 0xF9 ... MIDI timing tick
!ignore_flags.contains(Ignore::Time)
}
EventType::Clock => { // 0xF8 ... MIDI timing (clock) tick
!ignore_flags.contains(Ignore::Time)
}
EventType::Sensing => { // Active sensing
!ignore_flags.contains(Ignore::ActiveSense)
}
EventType::Sysex => { if !ignore_flags.contains(Ignore::Sysex) { // Directly copy the data from the external buffer to our message
message.bytes.extend_from_slice(ev.get_ext().unwrap());
continue_sysex = *message.bytes.last().unwrap() != 0xF7;
} false// don't ever decode sysex messages (it would unnecessarily copy the message content to another buffer)
}
_ => true,
};
// NOTE: SysEx messages have already been "decoded" at this point! if do_decode { iflet Ok(nbytes) = coder.get_wrapped().decode(&mut buffer, & style='color:red'>mut ev) { if nbytes > 0 {
message.bytes.extend_from_slice(&buffer[0..nbytes]);
}
}
}
if message.bytes.len() == 0 || continue_sysex { continue;
}
// Calculate the time stamp: // Use the ALSA sequencer event time data. // (thanks to Pedro Lopez-Cabanillas!). let alsa_time = ev.get_time().unwrap(); let secs = alsa_time.as_secs(); let nsecs = alsa_time.subsec_nanos();
message.timestamp = (secs as u64 * 1_000_000) + (nsecs as u64 / 1_000);
(data.callback)(message.timestamp, &message.bytes, user_data);
}
} // close scope where data.seq is borrowed
data // return data back to thread owner
}
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.