| 1 | //! MIDI sequencer I/O and enumeration |
| 2 | |
| 3 | use libc::{c_uint, c_int, c_short, c_uchar, c_void, c_long, size_t, pollfd}; |
| 4 | use super::error::*; |
| 5 | use crate::alsa; |
| 6 | use super::{Direction, poll}; |
| 7 | use std::{ptr, fmt, mem, slice, time, cell}; |
| 8 | use std::str::{FromStr, Split}; |
| 9 | use std::ffi::CStr; |
| 10 | use std::borrow::Cow; |
| 11 | |
| 12 | // Workaround for improper alignment of snd_seq_ev_ext_t in alsa-sys |
| 13 | #[repr (packed)] |
| 14 | struct EvExtPacked { |
| 15 | len: c_uint, |
| 16 | ptr: *mut c_void, |
| 17 | } |
| 18 | |
| 19 | /// [snd_seq_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___sequencer.html) wrapper |
| 20 | /// |
| 21 | /// To access the functions `event_input`, `event_input_pending` and `set_input_buffer_size`, |
| 22 | /// you first have to obtain an instance of `Input` by calling `input()`. Only one instance of |
| 23 | /// `Input` may exist at any time for a given `Seq`. |
| 24 | pub struct Seq(*mut alsa::snd_seq_t, cell::Cell<bool>); |
| 25 | |
| 26 | unsafe impl Send for Seq {} |
| 27 | |
| 28 | impl Drop for Seq { |
| 29 | fn drop(&mut self) { unsafe { alsa::snd_seq_close(self.0) }; } |
| 30 | } |
| 31 | |
| 32 | impl Seq { |
| 33 | fn check_has_input(&self) { |
| 34 | if self.1.get() { panic!("No additional Input object allowed" )} |
| 35 | } |
| 36 | |
| 37 | /// Opens the sequencer. |
| 38 | /// |
| 39 | /// If name is None, "default" will be used. That's almost always what you usually want to use anyway. |
| 40 | pub fn open(name: Option<&CStr>, dir: Option<Direction>, nonblock: bool) -> Result<Seq> { |
| 41 | let n2 = name.unwrap_or(unsafe { CStr::from_bytes_with_nul_unchecked(b"default \0" ) }); |
| 42 | let mut h = ptr::null_mut(); |
| 43 | let mode = if nonblock { alsa::SND_SEQ_NONBLOCK } else { 0 }; |
| 44 | let streams = match dir { |
| 45 | None => alsa::SND_SEQ_OPEN_DUPLEX, |
| 46 | Some(Direction::Playback) => alsa::SND_SEQ_OPEN_OUTPUT, |
| 47 | Some(Direction::Capture) => alsa::SND_SEQ_OPEN_INPUT, |
| 48 | }; |
| 49 | acheck!(snd_seq_open(&mut h, n2.as_ptr(), streams, mode)) |
| 50 | .map(|_| Seq(h, cell::Cell::new(false))) |
| 51 | } |
| 52 | |
| 53 | pub fn set_client_name(&self, name: &CStr) -> Result<()> { |
| 54 | acheck!(snd_seq_set_client_name(self.0, name.as_ptr())).map(|_| ()) |
| 55 | } |
| 56 | |
| 57 | pub fn set_client_event_filter(&self, event_type: i32) -> Result<()> { |
| 58 | acheck!(snd_seq_set_client_event_filter(self.0, event_type as c_int)).map(|_| ()) |
| 59 | } |
| 60 | |
| 61 | pub fn set_client_pool_output(&self, size: u32) -> Result<()> { |
| 62 | acheck!(snd_seq_set_client_pool_output(self.0, size as size_t)).map(|_| ()) |
| 63 | } |
| 64 | |
| 65 | pub fn set_client_pool_input(&self, size: u32) -> Result<()> { |
| 66 | acheck!(snd_seq_set_client_pool_input(self.0, size as size_t)).map(|_| ()) |
| 67 | } |
| 68 | |
| 69 | pub fn set_client_pool_output_room(&self, size: u32) -> Result<()> { |
| 70 | acheck!(snd_seq_set_client_pool_output_room(self.0, size as size_t)).map(|_| ()) |
| 71 | } |
| 72 | |
| 73 | pub fn client_id(&self) -> Result<i32> { |
| 74 | acheck!(snd_seq_client_id(self.0)).map(|q| q as i32) |
| 75 | } |
| 76 | |
| 77 | pub fn drain_output(&self) -> Result<i32> { |
| 78 | acheck!(snd_seq_drain_output(self.0)).map(|q| q as i32) |
| 79 | } |
| 80 | |
| 81 | pub fn get_any_client_info(&self, client: i32) -> Result<ClientInfo> { |
| 82 | let c = ClientInfo::new()?; |
| 83 | acheck!(snd_seq_get_any_client_info(self.0, client, c.0)).map(|_| c) |
| 84 | } |
| 85 | |
| 86 | pub fn get_any_port_info(&self, a: Addr) -> Result<PortInfo> { |
| 87 | let c = PortInfo::new()?; |
| 88 | acheck!(snd_seq_get_any_port_info(self.0, a.client as c_int, a.port as c_int, c.0)).map(|_| c) |
| 89 | } |
| 90 | |
| 91 | pub fn create_port(&self, port: &PortInfo) -> Result<()> { |
| 92 | acheck!(snd_seq_create_port(self.0, port.0)).map(|_| ()) |
| 93 | } |
| 94 | |
| 95 | pub fn create_simple_port(&self, name: &CStr, caps: PortCap, t: PortType) -> Result<i32> { |
| 96 | acheck!(snd_seq_create_simple_port(self.0, name.as_ptr(), caps.bits() as c_uint, t.bits() as c_uint)).map(|q| q as i32) |
| 97 | } |
| 98 | |
| 99 | pub fn set_port_info(&self, port: i32, info: &mut PortInfo) -> Result<()> { |
| 100 | acheck!(snd_seq_set_port_info(self.0, port, info.0)).map(|_| ()) |
| 101 | } |
| 102 | |
| 103 | pub fn delete_port(&self, port: i32) -> Result<()> { |
| 104 | acheck!(snd_seq_delete_port(self.0, port as c_int)).map(|_| ()) |
| 105 | } |
| 106 | |
| 107 | pub fn subscribe_port(&self, info: &PortSubscribe) -> Result<()> { |
| 108 | acheck!(snd_seq_subscribe_port(self.0, info.0)).map(|_| ()) |
| 109 | } |
| 110 | |
| 111 | pub fn unsubscribe_port(&self, sender: Addr, dest: Addr) -> Result<()> { |
| 112 | let z = PortSubscribe::new()?; |
| 113 | z.set_sender(sender); |
| 114 | z.set_dest(dest); |
| 115 | acheck!(snd_seq_unsubscribe_port(self.0, z.0)).map(|_| ()) |
| 116 | } |
| 117 | |
| 118 | pub fn control_queue(&self, q: i32, t: EventType, value: i32, e: Option<&mut Event>) -> Result<()> { |
| 119 | assert!(EvQueueControl::<()>::has_data(t) || EvQueueControl::<i32>::has_data(t) || EvQueueControl::<u32>::has_data(t)); |
| 120 | let p = e.map(|e| &mut e.0 as *mut _).unwrap_or(ptr::null_mut()); |
| 121 | acheck!(snd_seq_control_queue(self.0, q as c_int, t as c_int, value as c_int, p)).map(|_| ()) |
| 122 | } |
| 123 | |
| 124 | pub fn event_output(&self, e: &mut Event) -> Result<u32> { |
| 125 | e.ensure_buf(); |
| 126 | acheck!(snd_seq_event_output(self.0, &mut e.0)).map(|q| q as u32) |
| 127 | } |
| 128 | |
| 129 | pub fn event_output_buffer(&self, e: &mut Event) -> Result<u32> { |
| 130 | e.ensure_buf(); |
| 131 | acheck!(snd_seq_event_output_buffer(self.0, &mut e.0)).map(|q| q as u32) |
| 132 | } |
| 133 | |
| 134 | pub fn event_output_direct(&self, e: &mut Event) -> Result<u32> { |
| 135 | e.ensure_buf(); |
| 136 | acheck!(snd_seq_event_output_direct(self.0, &mut e.0)).map(|q| q as u32) |
| 137 | } |
| 138 | |
| 139 | pub fn get_queue_tempo(&self, q: i32) -> Result<QueueTempo> { |
| 140 | let value = QueueTempo::new()?; |
| 141 | acheck!(snd_seq_get_queue_tempo(self.0, q as c_int, value.0)).map(|_| value) |
| 142 | } |
| 143 | |
| 144 | pub fn set_queue_tempo(&self, q: i32, value: &QueueTempo) -> Result<()> { |
| 145 | acheck!(snd_seq_set_queue_tempo(self.0, q as c_int, value.0)).map(|_| ()) |
| 146 | } |
| 147 | |
| 148 | pub fn get_queue_status(&self, q: i32) -> Result<QueueStatus> { |
| 149 | let value = QueueStatus::new()?; |
| 150 | acheck!(snd_seq_get_queue_status(self.0, q as c_int, value.0)).map(|_| value) |
| 151 | } |
| 152 | |
| 153 | pub fn free_queue(&self, q: i32) -> Result<()> { acheck!(snd_seq_free_queue(self.0, q)).map(|_| ()) } |
| 154 | pub fn alloc_queue(&self) -> Result<i32> { acheck!(snd_seq_alloc_queue(self.0)).map(|q| q as i32) } |
| 155 | pub fn alloc_named_queue(&self, n: &CStr) -> Result<i32> { |
| 156 | acheck!(snd_seq_alloc_named_queue(self.0, n.as_ptr())).map(|q| q as i32) |
| 157 | } |
| 158 | |
| 159 | pub fn sync_output_queue(&self) -> Result<()> { |
| 160 | acheck!(snd_seq_sync_output_queue(self.0)).map(|_| ()) |
| 161 | } |
| 162 | |
| 163 | pub fn drop_output(&self) -> Result<()> { |
| 164 | acheck!(snd_seq_drop_output(self.0)).map(|_| ()) |
| 165 | } |
| 166 | |
| 167 | /// Call this function to obtain an instance of `Input` to access the functions `event_input`, |
| 168 | /// `event_input_pending` and `set_input_buffer_size`. See the documentation of `Input` for details. |
| 169 | pub fn input(&self) -> Input { |
| 170 | Input::new(self) |
| 171 | } |
| 172 | |
| 173 | pub fn remove_events(&self, condition: RemoveEvents) -> Result<()> { |
| 174 | acheck!(snd_seq_remove_events(self.0, condition.0)).map(|_| ()) |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | /// Struct for receiving input events from a sequencer. The methods offered by this |
| 179 | /// object may modify the internal input buffer of the sequencer, which must not happen |
| 180 | /// while an `Event` is alive that has been obtained from a call to `event_input` (which |
| 181 | /// takes `Input` by mutable reference for this reason). This is because the event might |
| 182 | /// directly reference the sequencer's input buffer for variable-length messages (e.g. Sysex). |
| 183 | /// |
| 184 | /// Note: Only one `Input` object is allowed in scope at a time. |
| 185 | pub struct Input<'a>(&'a Seq); |
| 186 | |
| 187 | impl<'a> Drop for Input<'a> { |
| 188 | fn drop(&mut self) { (self.0).1.set(val:false) } |
| 189 | } |
| 190 | |
| 191 | impl<'a> Input<'a> { |
| 192 | fn new(s: &'a Seq) -> Input<'a> { |
| 193 | s.check_has_input(); |
| 194 | s.1.set(true); |
| 195 | Input(s) |
| 196 | } |
| 197 | |
| 198 | pub fn event_input(&mut self) -> Result<Event> { |
| 199 | // The returned event might reference the input buffer of the `Seq`. |
| 200 | // Therefore we mutably borrow the `Input` structure, preventing any |
| 201 | // other function call that might change the input buffer while the |
| 202 | // event is alive. |
| 203 | let mut z = ptr::null_mut(); |
| 204 | acheck!(snd_seq_event_input((self.0).0, &mut z))?; |
| 205 | unsafe { Event::extract (&mut *z, "snd_seq_event_input" ) } |
| 206 | } |
| 207 | |
| 208 | pub fn event_input_pending(&self, fetch_sequencer: bool) -> Result<u32> { |
| 209 | acheck!(snd_seq_event_input_pending((self.0).0, if fetch_sequencer {1} else {0})).map(|q| q as u32) |
| 210 | } |
| 211 | |
| 212 | pub fn set_input_buffer_size(&self, size: u32) -> Result<()> { |
| 213 | acheck!(snd_seq_set_input_buffer_size((self.0).0, size as size_t)).map(|_| ()) |
| 214 | } |
| 215 | |
| 216 | pub fn drop_input(&self) -> Result<()> { |
| 217 | acheck!(snd_seq_drop_input((self.0).0)).map(|_| ()) |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | fn polldir(o: Option<Direction>) -> c_short { |
| 222 | match o { |
| 223 | None => poll::Flags::IN | poll::Flags::OUT, |
| 224 | Some(Direction::Playback) => poll::Flags::OUT, |
| 225 | Some(Direction::Capture) => poll::Flags::IN, |
| 226 | }.bits() |
| 227 | } |
| 228 | |
| 229 | impl<'a> poll::Descriptors for (&'a Seq, Option<Direction>) { |
| 230 | |
| 231 | fn count(&self) -> usize { |
| 232 | unsafe { alsa::snd_seq_poll_descriptors_count((self.0).0, events:polldir(self.1)) as usize } |
| 233 | } |
| 234 | |
| 235 | fn fill(&self, p: &mut [pollfd]) -> Result<usize> { |
| 236 | let z: i32 = unsafe { alsa::snd_seq_poll_descriptors((self.0).0, pfds:p.as_mut_ptr(), space:p.len() as c_uint, events:polldir(self.1)) }; |
| 237 | from_code("snd_seq_poll_descriptors" , z).map(|_| z as usize) |
| 238 | } |
| 239 | |
| 240 | fn revents(&self, p: &[pollfd]) -> Result<poll::Flags> { |
| 241 | let mut r: u16 = 0; |
| 242 | let z: i32 = unsafe { alsa::snd_seq_poll_descriptors_revents((self.0).0, pfds:p.as_ptr() as *mut pollfd, nfds:p.len() as c_uint, &mut r) }; |
| 243 | from_code("snd_seq_poll_descriptors_revents" , z).map(|_| poll::Flags::from_bits_truncate(bits:r as c_short)) |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | /// [snd_seq_client_info_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_client.html) wrapper |
| 248 | pub struct ClientInfo(*mut alsa::snd_seq_client_info_t); |
| 249 | |
| 250 | unsafe impl Send for ClientInfo {} |
| 251 | |
| 252 | impl Drop for ClientInfo { |
| 253 | fn drop(&mut self) { |
| 254 | unsafe { alsa::snd_seq_client_info_free(self.0) }; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | impl ClientInfo { |
| 259 | fn new() -> Result<Self> { |
| 260 | let mut p: *mut _snd_seq_client_info = ptr::null_mut(); |
| 261 | acheck!(snd_seq_client_info_malloc(&mut p)).map(|_| ClientInfo(p)) |
| 262 | } |
| 263 | |
| 264 | // Not sure if it's useful for this one to be public. |
| 265 | fn set_client(&self, client: i32) { |
| 266 | unsafe { alsa::snd_seq_client_info_set_client(self.0, client as c_int) }; |
| 267 | } |
| 268 | |
| 269 | pub fn get_client(&self) -> i32 { |
| 270 | unsafe { alsa::snd_seq_client_info_get_client(self.0) as i32 } |
| 271 | } |
| 272 | |
| 273 | pub fn get_name(&self) -> Result<&str> { |
| 274 | let c: *const {unknown} = unsafe { alsa::snd_seq_client_info_get_name(self.0) }; |
| 275 | from_const(func:"snd_seq_client_info_get_name" , s:c) |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | impl fmt::Debug for ClientInfo { |
| 280 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 281 | write!(f, "ClientInfo( {}, {:?})" , self.get_client(), self.get_name()) |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | #[derive (Copy, Clone)] |
| 286 | /// Iterates over clients connected to the seq API (both kernel and userspace clients). |
| 287 | pub struct ClientIter<'a>(&'a Seq, i32); |
| 288 | |
| 289 | impl<'a> ClientIter<'a> { |
| 290 | pub fn new(seq: &'a Seq) -> Self { ClientIter(seq, -1) } |
| 291 | } |
| 292 | |
| 293 | impl<'a> Iterator for ClientIter<'a> { |
| 294 | type Item = ClientInfo; |
| 295 | fn next(&mut self) -> Option<Self::Item> { |
| 296 | let z: ClientInfo = ClientInfo::new().unwrap(); |
| 297 | z.set_client(self.1); |
| 298 | let r = unsafe { alsa::snd_seq_query_next_client((self.0).0, info:z.0) }; |
| 299 | if r < 0 { self.1 = -1; return None }; |
| 300 | self.1 = z.get_client(); |
| 301 | Some(z) |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | /// [snd_seq_port_info_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_port.html) wrapper |
| 306 | pub struct PortInfo(*mut alsa::snd_seq_port_info_t); |
| 307 | |
| 308 | unsafe impl Send for PortInfo {} |
| 309 | |
| 310 | impl Drop for PortInfo { |
| 311 | fn drop(&mut self) { |
| 312 | unsafe { alsa::snd_seq_port_info_free(self.0) }; |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | impl PortInfo { |
| 317 | fn new() -> Result<Self> { |
| 318 | let mut p = ptr::null_mut(); |
| 319 | acheck!(snd_seq_port_info_malloc(&mut p)).map(|_| PortInfo(p)) |
| 320 | } |
| 321 | |
| 322 | /// Creates a new PortInfo with all fields set to zero. |
| 323 | pub fn empty() -> Result<Self> { |
| 324 | let z = Self::new()?; |
| 325 | unsafe { ptr::write_bytes(z.0 as *mut u8, 0, alsa::snd_seq_port_info_sizeof()) }; |
| 326 | Ok(z) |
| 327 | } |
| 328 | |
| 329 | pub fn get_client(&self) -> i32 { |
| 330 | unsafe { alsa::snd_seq_port_info_get_client(self.0) as i32 } |
| 331 | } |
| 332 | |
| 333 | pub fn get_port(&self) -> i32 { |
| 334 | unsafe { alsa::snd_seq_port_info_get_port(self.0) as i32 } |
| 335 | } |
| 336 | |
| 337 | // Not sure if it's useful for this one to be public. |
| 338 | fn set_client(&self, client: i32) { |
| 339 | unsafe { alsa::snd_seq_port_info_set_client(self.0, client as c_int) }; |
| 340 | } |
| 341 | |
| 342 | // Not sure if it's useful for this one to be public. |
| 343 | fn set_port(&self, port: i32) { |
| 344 | unsafe { alsa::snd_seq_port_info_set_port(self.0, port as c_int) }; |
| 345 | } |
| 346 | |
| 347 | pub fn get_name(&self) -> Result<&str> { |
| 348 | let c = unsafe { alsa::snd_seq_port_info_get_name(self.0) }; |
| 349 | from_const("snd_seq_port_info_get_name" , c) |
| 350 | } |
| 351 | |
| 352 | pub fn set_name(&mut self, name: &CStr) { |
| 353 | // Note: get_name returns an interior reference, so this one must take &mut self |
| 354 | unsafe { alsa::snd_seq_port_info_set_name(self.0, name.as_ptr()) }; |
| 355 | } |
| 356 | |
| 357 | pub fn get_capability(&self) -> PortCap { |
| 358 | PortCap::from_bits_truncate(unsafe { alsa::snd_seq_port_info_get_capability(self.0) as u32 }) |
| 359 | } |
| 360 | |
| 361 | pub fn get_type(&self) -> PortType { |
| 362 | PortType::from_bits_truncate(unsafe { alsa::snd_seq_port_info_get_type(self.0) as u32 }) |
| 363 | } |
| 364 | |
| 365 | pub fn set_capability(&self, c: PortCap) { |
| 366 | unsafe { alsa::snd_seq_port_info_set_capability(self.0, c.bits() as c_uint) } |
| 367 | } |
| 368 | |
| 369 | pub fn set_type(&self, c: PortType) { |
| 370 | unsafe { alsa::snd_seq_port_info_set_type(self.0, c.bits() as c_uint) } |
| 371 | } |
| 372 | |
| 373 | /// Returns an Addr containing this PortInfo's client and port id. |
| 374 | pub fn addr(&self) -> Addr { |
| 375 | Addr { |
| 376 | client: self.get_client(), |
| 377 | port: self.get_port(), |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | pub fn get_midi_channels(&self) -> i32 { unsafe { alsa::snd_seq_port_info_get_midi_channels(self.0) as i32 } } |
| 382 | pub fn get_midi_voices(&self) -> i32 { unsafe { alsa::snd_seq_port_info_get_midi_voices(self.0) as i32 } } |
| 383 | pub fn get_synth_voices(&self) -> i32 { unsafe { alsa::snd_seq_port_info_get_synth_voices(self.0) as i32 } } |
| 384 | pub fn get_read_use(&self) -> i32 { unsafe { alsa::snd_seq_port_info_get_read_use(self.0) as i32 } } |
| 385 | pub fn get_write_use(&self) -> i32 { unsafe { alsa::snd_seq_port_info_get_write_use(self.0) as i32 } } |
| 386 | pub fn get_port_specified(&self) -> bool { unsafe { alsa::snd_seq_port_info_get_port_specified(self.0) == 1 } } |
| 387 | pub fn get_timestamping(&self) -> bool { unsafe { alsa::snd_seq_port_info_get_timestamping(self.0) == 1 } } |
| 388 | pub fn get_timestamp_real(&self) -> bool { unsafe { alsa::snd_seq_port_info_get_timestamp_real(self.0) == 1 } } |
| 389 | pub fn get_timestamp_queue(&self) -> i32 { unsafe { alsa::snd_seq_port_info_get_timestamp_queue(self.0) as i32 } } |
| 390 | |
| 391 | pub fn set_midi_channels(&self, value: i32) { unsafe { alsa::snd_seq_port_info_set_midi_channels(self.0, value as c_int) } } |
| 392 | pub fn set_midi_voices(&self, value: i32) { unsafe { alsa::snd_seq_port_info_set_midi_voices(self.0, value as c_int) } } |
| 393 | pub fn set_synth_voices(&self, value: i32) { unsafe { alsa::snd_seq_port_info_set_synth_voices(self.0, value as c_int) } } |
| 394 | pub fn set_port_specified(&self, value: bool) { unsafe { alsa::snd_seq_port_info_set_port_specified(self.0, if value { 1 } else { 0 } ) } } |
| 395 | pub fn set_timestamping(&self, value: bool) { unsafe { alsa::snd_seq_port_info_set_timestamping(self.0, if value { 1 } else { 0 } ) } } |
| 396 | pub fn set_timestamp_real(&self, value: bool) { unsafe { alsa::snd_seq_port_info_set_timestamp_real(self.0, if value { 1 } else { 0 } ) } } |
| 397 | pub fn set_timestamp_queue(&self, value: i32) { unsafe { alsa::snd_seq_port_info_set_timestamp_queue(self.0, value as c_int) } } |
| 398 | } |
| 399 | |
| 400 | impl fmt::Debug for PortInfo { |
| 401 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 402 | write!(f, "PortInfo( {}: {}, {:?})" , self.get_client(), self.get_port(), self.get_name()) |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | #[derive (Copy, Clone)] |
| 407 | /// Iterates over clients connected to the seq API (both kernel and userspace clients). |
| 408 | pub struct PortIter<'a>(&'a Seq, i32, i32); |
| 409 | |
| 410 | impl<'a> PortIter<'a> { |
| 411 | pub fn new(seq: &'a Seq, client: i32) -> Self { PortIter(seq, client, -1) } |
| 412 | } |
| 413 | |
| 414 | impl<'a> Iterator for PortIter<'a> { |
| 415 | type Item = PortInfo; |
| 416 | fn next(&mut self) -> Option<Self::Item> { |
| 417 | let z: PortInfo = PortInfo::new().unwrap(); |
| 418 | z.set_client(self.1); |
| 419 | z.set_port(self.2); |
| 420 | let r = unsafe { alsa::snd_seq_query_next_port((self.0).0, info:z.0) }; |
| 421 | if r < 0 { self.2 = -1; return None }; |
| 422 | self.2 = z.get_port(); |
| 423 | Some(z) |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | bitflags! { |
| 428 | #[repr (transparent)] |
| 429 | #[derive (Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 430 | /// [SND_SEQ_PORT_CAP_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_port.html) constants |
| 431 | pub struct PortCap: u32 { |
| 432 | const READ = 1<<0; |
| 433 | const WRITE = 1<<1; |
| 434 | const SYNC_READ = 1<<2; |
| 435 | const SYNC_WRITE = 1<<3; |
| 436 | const DUPLEX = 1<<4; |
| 437 | const SUBS_READ = 1<<5; |
| 438 | const SUBS_WRITE = 1<<6; |
| 439 | const NO_EXPORT = 1<<7; |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | bitflags! { |
| 444 | #[repr (transparent)] |
| 445 | #[derive (Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 446 | /// [SND_SEQ_PORT_TYPE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_port.html) constants |
| 447 | pub struct PortType: u32 { |
| 448 | const SPECIFIC = (1<<0); |
| 449 | const MIDI_GENERIC = (1<<1); |
| 450 | const MIDI_GM = (1<<2); |
| 451 | const MIDI_GS = (1<<3); |
| 452 | const MIDI_XG = (1<<4); |
| 453 | const MIDI_MT32 = (1<<5); |
| 454 | const MIDI_GM2 = (1<<6); |
| 455 | const SYNTH = (1<<10); |
| 456 | const DIRECT_SAMPLE = (1<<11); |
| 457 | const SAMPLE = (1<<12); |
| 458 | const HARDWARE = (1<<16); |
| 459 | const SOFTWARE = (1<<17); |
| 460 | const SYNTHESIZER = (1<<18); |
| 461 | const PORT = (1<<19); |
| 462 | const APPLICATION = (1<<20); |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | bitflags! { |
| 467 | #[repr (transparent)] |
| 468 | #[derive (Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 469 | /// [SND_SEQ_REMOVE_xxx](https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_event.html) constants |
| 470 | pub struct Remove: u32 { |
| 471 | const INPUT = (1<<0); |
| 472 | const OUTPUT = (1<<1); |
| 473 | const DEST = (1<<2); |
| 474 | const DEST_CHANNEL = (1<<3); |
| 475 | const TIME_BEFORE = (1<<4); |
| 476 | const TIME_AFTER = (1<<5); |
| 477 | const TIME_TICK = (1<<6); |
| 478 | const EVENT_TYPE = (1<<7); |
| 479 | const IGNORE_OFF = (1<<8); |
| 480 | const TAG_MATCH = (1<<9); |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | |
| 485 | /// [snd_seq_addr_t](http://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__addr__t.html) wrapper |
| 486 | #[derive (Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)] |
| 487 | pub struct Addr { |
| 488 | pub client: i32, |
| 489 | pub port: i32, |
| 490 | } |
| 491 | |
| 492 | impl FromStr for Addr { |
| 493 | type Err = Box<dyn std::error::Error>; |
| 494 | |
| 495 | fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { |
| 496 | let mut split: Split<'_, char> = s.trim().split(':' ); |
| 497 | let client: i32 = split&str.next() |
| 498 | .ok_or(err:"no client provided" )? |
| 499 | .parse::<i32>()?; |
| 500 | let port: i32 = split&str.next() |
| 501 | .ok_or(err:"no port provided" )? |
| 502 | .parse::<i32>()?; |
| 503 | match split.next() { |
| 504 | Some(_) => { |
| 505 | Err("too many arguments" .into()) |
| 506 | }, |
| 507 | None => { |
| 508 | Ok(Addr { client, port }) |
| 509 | } |
| 510 | } |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | impl Addr { |
| 515 | pub fn system_timer() -> Addr { Addr { client: alsa::SND_SEQ_CLIENT_SYSTEM as i32, port: alsa::SND_SEQ_PORT_SYSTEM_TIMER as i32 } } |
| 516 | pub fn system_announce() -> Addr { Addr { client: alsa::SND_SEQ_CLIENT_SYSTEM as i32, port: alsa::SND_SEQ_PORT_SYSTEM_ANNOUNCE as i32 } } |
| 517 | pub fn broadcast() -> Addr { Addr { client: alsa::SND_SEQ_ADDRESS_BROADCAST as i32, port: alsa::SND_SEQ_ADDRESS_BROADCAST as i32 } } |
| 518 | } |
| 519 | |
| 520 | /// [snd_seq_port_subscribe_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_subscribe.html) wrapper |
| 521 | pub struct PortSubscribe(*mut alsa::snd_seq_port_subscribe_t); |
| 522 | |
| 523 | unsafe impl Send for PortSubscribe {} |
| 524 | |
| 525 | impl Drop for PortSubscribe { |
| 526 | fn drop(&mut self) { unsafe { alsa::snd_seq_port_subscribe_free(self.0) }; } |
| 527 | } |
| 528 | |
| 529 | impl PortSubscribe { |
| 530 | fn new() -> Result<Self> { |
| 531 | let mut p = ptr::null_mut(); |
| 532 | acheck!(snd_seq_port_subscribe_malloc(&mut p)).map(|_| PortSubscribe(p)) |
| 533 | } |
| 534 | |
| 535 | /// Creates a new PortSubscribe with all fields set to zero. |
| 536 | pub fn empty() -> Result<Self> { |
| 537 | let z = Self::new()?; |
| 538 | unsafe { ptr::write_bytes(z.0 as *mut u8, 0, alsa::snd_seq_port_subscribe_sizeof()) }; |
| 539 | Ok(z) |
| 540 | } |
| 541 | |
| 542 | pub fn get_sender(&self) -> Addr { unsafe { |
| 543 | let z = alsa::snd_seq_port_subscribe_get_sender(self.0); |
| 544 | Addr { client: (*z).client as i32, port: (*z).port as i32 } |
| 545 | } } |
| 546 | |
| 547 | pub fn get_dest(&self) -> Addr { unsafe { |
| 548 | let z = alsa::snd_seq_port_subscribe_get_dest(self.0); |
| 549 | Addr { client: (*z).client as i32, port: (*z).port as i32 } |
| 550 | } } |
| 551 | |
| 552 | pub fn get_queue(&self) -> i32 { unsafe { alsa::snd_seq_port_subscribe_get_queue(self.0) as i32 } } |
| 553 | pub fn get_exclusive(&self) -> bool { unsafe { alsa::snd_seq_port_subscribe_get_exclusive(self.0) == 1 } } |
| 554 | pub fn get_time_update(&self) -> bool { unsafe { alsa::snd_seq_port_subscribe_get_time_update(self.0) == 1 } } |
| 555 | pub fn get_time_real(&self) -> bool { unsafe { alsa::snd_seq_port_subscribe_get_time_real(self.0) == 1 } } |
| 556 | |
| 557 | pub fn set_sender(&self, value: Addr) { |
| 558 | let z = alsa::snd_seq_addr_t { client: value.client as c_uchar, port: value.port as c_uchar }; |
| 559 | unsafe { alsa::snd_seq_port_subscribe_set_sender(self.0, &z) }; |
| 560 | } |
| 561 | |
| 562 | pub fn set_dest(&self, value: Addr) { |
| 563 | let z = alsa::snd_seq_addr_t { client: value.client as c_uchar, port: value.port as c_uchar }; |
| 564 | unsafe { alsa::snd_seq_port_subscribe_set_dest(self.0, &z) }; |
| 565 | } |
| 566 | |
| 567 | pub fn set_queue(&self, value: i32) { unsafe { alsa::snd_seq_port_subscribe_set_queue(self.0, value as c_int) } } |
| 568 | pub fn set_exclusive(&self, value: bool) { unsafe { alsa::snd_seq_port_subscribe_set_exclusive(self.0, if value { 1 } else { 0 } ) } } |
| 569 | pub fn set_time_update(&self, value: bool) { unsafe { alsa::snd_seq_port_subscribe_set_time_update(self.0, if value { 1 } else { 0 } ) } } |
| 570 | pub fn set_time_real(&self, value: bool) { unsafe { alsa::snd_seq_port_subscribe_set_time_real(self.0, if value { 1 } else { 0 } ) } } |
| 571 | |
| 572 | } |
| 573 | |
| 574 | /// [snd_seq_query_subs_type_t](https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_subscribe.html) wrapper |
| 575 | #[derive (Copy, Clone)] |
| 576 | pub enum QuerySubsType { |
| 577 | READ = alsa::SND_SEQ_QUERY_SUBS_READ as isize, |
| 578 | WRITE = alsa::SND_SEQ_QUERY_SUBS_WRITE as isize, |
| 579 | } |
| 580 | |
| 581 | /// [snd_seq_query_subscribe_t](https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_subscribe.html) wrapper |
| 582 | //(kept private, functionality exposed by PortSubscribeIter) |
| 583 | struct QuerySubscribe(*mut alsa::snd_seq_query_subscribe_t); |
| 584 | |
| 585 | unsafe impl Send for QuerySubscribe {} |
| 586 | |
| 587 | impl Drop for QuerySubscribe { |
| 588 | fn drop(&mut self) { unsafe { alsa::snd_seq_query_subscribe_free(self.0) } } |
| 589 | } |
| 590 | |
| 591 | impl QuerySubscribe { |
| 592 | pub fn new() -> Result<Self> { |
| 593 | let mut q = ptr::null_mut(); |
| 594 | acheck!(snd_seq_query_subscribe_malloc(&mut q)).map(|_| QuerySubscribe(q)) |
| 595 | } |
| 596 | |
| 597 | pub fn get_index(&self) -> i32 { unsafe { alsa::snd_seq_query_subscribe_get_index(self.0) as i32 } } |
| 598 | pub fn get_addr(&self) -> Addr { unsafe { |
| 599 | let a = &(*alsa::snd_seq_query_subscribe_get_addr(self.0)); |
| 600 | Addr { client: a.client as i32, port: a.port as i32 } |
| 601 | } } |
| 602 | pub fn get_queue(&self) -> i32 { unsafe { alsa::snd_seq_query_subscribe_get_queue(self.0) as i32 } } |
| 603 | pub fn get_exclusive(&self) -> bool { unsafe { alsa::snd_seq_query_subscribe_get_exclusive(self.0) == 1 } } |
| 604 | pub fn get_time_update(&self) -> bool { unsafe { alsa::snd_seq_query_subscribe_get_time_update(self.0) == 1 } } |
| 605 | pub fn get_time_real(&self) -> bool { unsafe { alsa::snd_seq_query_subscribe_get_time_real(self.0) == 1 } } |
| 606 | |
| 607 | pub fn set_root(&self, value: Addr) { unsafe { |
| 608 | let a = alsa::snd_seq_addr_t { client: value.client as c_uchar, port: value.port as c_uchar}; |
| 609 | alsa::snd_seq_query_subscribe_set_root(self.0, &a); |
| 610 | } } |
| 611 | pub fn set_type(&self, value: QuerySubsType) { unsafe { |
| 612 | alsa::snd_seq_query_subscribe_set_type(self.0, value as alsa::snd_seq_query_subs_type_t) |
| 613 | } } |
| 614 | pub fn set_index(&self, value: i32) { unsafe { alsa::snd_seq_query_subscribe_set_index(self.0, value as c_int) } } |
| 615 | } |
| 616 | |
| 617 | #[derive (Copy, Clone)] |
| 618 | /// Iterates over port subscriptions for a given client:port/type. |
| 619 | pub struct PortSubscribeIter<'a> { |
| 620 | seq: &'a Seq, |
| 621 | addr: Addr, |
| 622 | query_subs_type: QuerySubsType, |
| 623 | index: i32 |
| 624 | } |
| 625 | |
| 626 | impl<'a> PortSubscribeIter<'a> { |
| 627 | pub fn new(seq: &'a Seq, addr: Addr, query_subs_type: QuerySubsType) -> Self { |
| 628 | PortSubscribeIter {seq, addr, query_subs_type, index: 0 } |
| 629 | } |
| 630 | } |
| 631 | |
| 632 | impl<'a> Iterator for PortSubscribeIter<'a> { |
| 633 | type Item = PortSubscribe; |
| 634 | |
| 635 | fn next(&mut self) -> Option<Self::Item> { |
| 636 | let query = QuerySubscribe::new().unwrap(); |
| 637 | |
| 638 | query.set_root(self.addr); |
| 639 | query.set_type(self.query_subs_type); |
| 640 | query.set_index(self.index); |
| 641 | |
| 642 | let r = unsafe { alsa::snd_seq_query_port_subscribers((self.seq).0, query.0) }; |
| 643 | if r < 0 { |
| 644 | self.index = 0; |
| 645 | return None; |
| 646 | } |
| 647 | |
| 648 | self.index = query.get_index() + 1; |
| 649 | let vtr = PortSubscribe::new().unwrap(); |
| 650 | match self.query_subs_type { |
| 651 | QuerySubsType::READ => { |
| 652 | vtr.set_sender(self.addr); |
| 653 | vtr.set_dest(query.get_addr()); |
| 654 | }, |
| 655 | QuerySubsType:: WRITE => { |
| 656 | vtr.set_sender(query.get_addr()); |
| 657 | vtr.set_dest(self.addr); |
| 658 | } |
| 659 | }; |
| 660 | vtr.set_queue(query.get_queue()); |
| 661 | vtr.set_exclusive(query.get_exclusive()); |
| 662 | vtr.set_time_update(query.get_time_update()); |
| 663 | vtr.set_time_real(query.get_time_real()); |
| 664 | |
| 665 | Some(vtr) |
| 666 | } |
| 667 | } |
| 668 | |
| 669 | /// [snd_seq_event_t](http://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__event__t.html) wrapper |
| 670 | /// |
| 671 | /// Fields of the event is not directly exposed. Instead call `Event::new` to set data (which can be, e g, an EvNote). |
| 672 | /// Use `get_type` and `get_data` to retrieve data. |
| 673 | /// |
| 674 | /// The lifetime parameter refers to the lifetime of an associated external buffer that might be used for |
| 675 | /// variable-length messages (e.g. SysEx). |
| 676 | pub struct Event<'a>(alsa::snd_seq_event_t, EventType, Option<Cow<'a, [u8]>>); |
| 677 | |
| 678 | unsafe impl<'a> Send for Event<'a> {} |
| 679 | |
| 680 | impl<'a> Event<'a> { |
| 681 | /// Creates a new event. For events that carry variable-length data (e.g. Sysex), `new_ext` has to be used instead. |
| 682 | pub fn new<D: EventData>(t: EventType, data: &D) -> Event<'static> { |
| 683 | assert!(!Event::has_ext_data(t), "event type must not carry variable-length data" ); |
| 684 | let mut z = Event(unsafe { mem::zeroed() }, t, None); |
| 685 | (z.0).type_ = t as c_uchar; |
| 686 | (z.0).flags |= Event::get_length_flag(t); |
| 687 | debug_assert!(D::has_data(t)); |
| 688 | data.set_data(&mut z); |
| 689 | z |
| 690 | } |
| 691 | |
| 692 | /// Creates a new event carrying variable-length data. This is required for event types `Sysex`, `Bounce`, and the `UsrVar` types. |
| 693 | pub fn new_ext<D: Into<Cow<'a, [u8]>>>(t: EventType, data: D) -> Event<'a> { |
| 694 | assert!(Event::has_ext_data(t), "event type must carry variable-length data" ); |
| 695 | let mut z = Event(unsafe { mem::zeroed() }, t, Some(data.into())); |
| 696 | (z.0).type_ = t as c_uchar; |
| 697 | (z.0).flags |= Event::get_length_flag(t); |
| 698 | z |
| 699 | } |
| 700 | |
| 701 | /// Consumes this event and returns an (otherwise unchanged) event where the externally referenced |
| 702 | /// buffer for variable length messages (e.g. SysEx) has been copied into the event. |
| 703 | /// The returned event has a static lifetime, i e, it's decoupled from the original buffer. |
| 704 | pub fn into_owned(self) -> Event<'static> { |
| 705 | Event(self.0, self.1, self.2.map(|cow| Cow::Owned(cow.into_owned()))) |
| 706 | } |
| 707 | |
| 708 | fn get_length_flag(t: EventType) -> u8 { |
| 709 | match t { |
| 710 | EventType::Sysex => alsa::SND_SEQ_EVENT_LENGTH_VARIABLE, |
| 711 | EventType::Bounce => alsa::SND_SEQ_EVENT_LENGTH_VARIABLE, // not clear whether this should be VARIABLE or VARUSR |
| 712 | EventType::UsrVar0 => alsa::SND_SEQ_EVENT_LENGTH_VARUSR, |
| 713 | EventType::UsrVar1 => alsa::SND_SEQ_EVENT_LENGTH_VARUSR, |
| 714 | EventType::UsrVar2 => alsa::SND_SEQ_EVENT_LENGTH_VARUSR, |
| 715 | EventType::UsrVar3 => alsa::SND_SEQ_EVENT_LENGTH_VARUSR, |
| 716 | EventType::UsrVar4 => alsa::SND_SEQ_EVENT_LENGTH_VARUSR, |
| 717 | _ => alsa::SND_SEQ_EVENT_LENGTH_FIXED |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | fn has_ext_data(t: EventType) -> bool { |
| 722 | Event::get_length_flag(t) != alsa::SND_SEQ_EVENT_LENGTH_FIXED |
| 723 | } |
| 724 | |
| 725 | /// Extracts event type and data. Produces a result with an arbitrary lifetime, hence the unsafety. |
| 726 | unsafe fn extract<'any>(z: &mut alsa::snd_seq_event_t, func: &'static str) -> Result<Event<'any>> { |
| 727 | let t = EventType::from_c_int((*z).type_ as c_int, func)?; |
| 728 | let ext_data = if Event::has_ext_data(t) { |
| 729 | assert_ne!((*z).flags & alsa::SND_SEQ_EVENT_LENGTH_MASK, alsa::SND_SEQ_EVENT_LENGTH_FIXED); |
| 730 | Some(Cow::Borrowed({ |
| 731 | let zz: &EvExtPacked = &*(&(*z).data as *const alsa::snd_seq_event__bindgen_ty_1 as *const _); |
| 732 | slice::from_raw_parts((*zz).ptr as *mut u8, (*zz).len as usize) |
| 733 | })) |
| 734 | } else { |
| 735 | None |
| 736 | }; |
| 737 | Ok(Event(ptr::read(z), t, ext_data)) |
| 738 | } |
| 739 | |
| 740 | /// Ensures that the ev.ext union element points to the correct resize_buffer for events |
| 741 | /// with variable length content |
| 742 | fn ensure_buf(&mut self) { |
| 743 | if !Event::has_ext_data(self.1) { return; } |
| 744 | let slice: &[u8] = match self.2 { |
| 745 | Some(Cow::Owned(ref mut vec)) => &vec[..], |
| 746 | Some(Cow::Borrowed(buf)) => buf, |
| 747 | // The following case is always a logic error in the program, thus panicking is okay. |
| 748 | None => panic!("event type requires variable-length data, but none was provided" ) |
| 749 | }; |
| 750 | let z: &mut EvExtPacked = unsafe { &mut *(&mut self.0.data as *mut alsa::snd_seq_event__bindgen_ty_1 as *mut _) }; |
| 751 | z.len = slice.len() as c_uint; |
| 752 | z.ptr = slice.as_ptr() as *mut c_void; |
| 753 | } |
| 754 | |
| 755 | #[inline ] |
| 756 | pub fn get_type(&self) -> EventType { self.1 } |
| 757 | |
| 758 | /// Extract the event data from an event. |
| 759 | /// Use `get_ext` instead for events carrying variable-length data. |
| 760 | pub fn get_data<D: EventData>(&self) -> Option<D> { if D::has_data(self.1) { Some(D::get_data(self)) } else { None } } |
| 761 | |
| 762 | /// Extract the variable-length data carried by events of type `Sysex`, `Bounce`, or the `UsrVar` types. |
| 763 | pub fn get_ext(&self) -> Option<&[u8]> { |
| 764 | if Event::has_ext_data(self.1) { |
| 765 | match self.2 { |
| 766 | Some(Cow::Owned(ref vec)) => Some(&vec[..]), |
| 767 | Some(Cow::Borrowed(buf)) => Some(buf), |
| 768 | // The following case is always a logic error in the program, thus panicking is okay. |
| 769 | None => panic!("event type requires variable-length data, but none was found" ) |
| 770 | } |
| 771 | } else { |
| 772 | None |
| 773 | } |
| 774 | } |
| 775 | |
| 776 | pub fn set_subs(&mut self) { |
| 777 | self.0.dest.client = alsa::SND_SEQ_ADDRESS_SUBSCRIBERS; |
| 778 | self.0.dest.port = alsa::SND_SEQ_ADDRESS_UNKNOWN; |
| 779 | } |
| 780 | |
| 781 | pub fn set_source(&mut self, p: i32) { self.0.source.port = p as u8 } |
| 782 | pub fn set_dest(&mut self, d: Addr) { self.0.dest.client = d.client as c_uchar; self.0.dest.port = d.port as c_uchar; } |
| 783 | pub fn set_tag(&mut self, t: u8) { self.0.tag = t as c_uchar; } |
| 784 | pub fn set_queue(&mut self, q: i32) { self.0.queue = q as c_uchar; } |
| 785 | |
| 786 | pub fn get_source(&self) -> Addr { Addr { client: self.0.source.client as i32, port: self.0.source.port as i32 } } |
| 787 | pub fn get_dest(&self) -> Addr { Addr { client: self.0.dest.client as i32, port: self.0.dest.port as i32 } } |
| 788 | pub fn get_tag(&self) -> u8 { self.0.tag as u8 } |
| 789 | pub fn get_queue(&self) -> i32 { self.0.queue as i32 } |
| 790 | |
| 791 | pub fn schedule_real(&mut self, queue: i32, relative: bool, rtime: time::Duration) { |
| 792 | self.0.flags &= !(alsa::SND_SEQ_TIME_STAMP_MASK | alsa::SND_SEQ_TIME_MODE_MASK); |
| 793 | self.0.flags |= alsa::SND_SEQ_TIME_STAMP_REAL | (if relative { alsa::SND_SEQ_TIME_MODE_REL } else { alsa::SND_SEQ_TIME_MODE_ABS }); |
| 794 | self.0.queue = queue as u8; |
| 795 | let t = unsafe { &mut self.0.time.time }; |
| 796 | t.tv_sec = rtime.as_secs() as c_uint; |
| 797 | t.tv_nsec = rtime.subsec_nanos() as c_uint; |
| 798 | } |
| 799 | |
| 800 | pub fn schedule_tick(&mut self, queue: i32, relative: bool, ttime: u32) { |
| 801 | self.0.flags &= !(alsa::SND_SEQ_TIME_STAMP_MASK | alsa::SND_SEQ_TIME_MODE_MASK); |
| 802 | self.0.flags |= alsa::SND_SEQ_TIME_STAMP_TICK | (if relative { alsa::SND_SEQ_TIME_MODE_REL } else { alsa::SND_SEQ_TIME_MODE_ABS }); |
| 803 | self.0.queue = queue as u8; |
| 804 | let t = unsafe { &mut self.0.time.tick }; |
| 805 | *t = ttime as c_uint; |
| 806 | } |
| 807 | |
| 808 | pub fn set_direct(&mut self) { self.0.queue = alsa::SND_SEQ_QUEUE_DIRECT } |
| 809 | |
| 810 | pub fn get_relative(&self) -> bool { (self.0.flags & alsa::SND_SEQ_TIME_MODE_REL) != 0 } |
| 811 | |
| 812 | pub fn get_time(&self) -> Option<time::Duration> { |
| 813 | if (self.0.flags & alsa::SND_SEQ_TIME_STAMP_REAL) != 0 { |
| 814 | let d = self.0.time; |
| 815 | let t = unsafe { &d.time }; |
| 816 | Some(time::Duration::new(t.tv_sec as u64, t.tv_nsec as u32)) |
| 817 | } else { None } |
| 818 | } |
| 819 | |
| 820 | pub fn get_tick(&self) -> Option<u32> { |
| 821 | if (self.0.flags & alsa::SND_SEQ_TIME_STAMP_REAL) == 0 { |
| 822 | let d = self.0.time; |
| 823 | let t = unsafe { &d.tick }; |
| 824 | Some(*t) |
| 825 | } else { None } |
| 826 | } |
| 827 | |
| 828 | /// Returns true if the message is high priority. |
| 829 | pub fn get_priority(&self) -> bool { (self.0.flags & alsa::SND_SEQ_PRIORITY_HIGH) != 0 } |
| 830 | |
| 831 | pub fn set_priority(&mut self, is_high_prio: bool) { |
| 832 | if is_high_prio { self.0.flags |= alsa::SND_SEQ_PRIORITY_HIGH; } |
| 833 | else { self.0.flags &= !alsa::SND_SEQ_PRIORITY_HIGH; } |
| 834 | } |
| 835 | } |
| 836 | |
| 837 | impl<'a> Clone for Event<'a> { |
| 838 | fn clone(&self) -> Self { Event(unsafe { ptr::read(&self.0) }, self.1, self.2.clone()) } |
| 839 | } |
| 840 | |
| 841 | impl<'a> fmt::Debug for Event<'a> { |
| 842 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 843 | let mut x: DebugTuple<'_, '_> = f.debug_tuple(name:"Event" ); |
| 844 | x.field(&self.1); |
| 845 | if let Some(z: EvNote) = self.get_data::<EvNote>() { x.field(&z); } |
| 846 | if let Some(z: EvCtrl) = self.get_data::<EvCtrl>() { x.field(&z); } |
| 847 | if let Some(z: Addr) = self.get_data::<Addr>() { x.field(&z); } |
| 848 | if let Some(z: Connect) = self.get_data::<Connect>() { x.field(&z); } |
| 849 | if let Some(z: EvQueueControl<()>) = self.get_data::<EvQueueControl<()>>() { x.field(&z); } |
| 850 | if let Some(z: EvQueueControl) = self.get_data::<EvQueueControl<i32>>() { x.field(&z); } |
| 851 | if let Some(z: EvQueueControl) = self.get_data::<EvQueueControl<u32>>() { x.field(&z); } |
| 852 | if let Some(z: EvQueueControl) = self.get_data::<EvQueueControl<time::Duration>>() { x.field(&z); } |
| 853 | if let Some(z: EvResult) = self.get_data::<EvResult>() { x.field(&z); } |
| 854 | if let Some(z: [u8; 12]) = self.get_data::<[u8; 12]>() { x.field(&z); } |
| 855 | if let Some(z: &[u8]) = self.get_ext() { x.field(&z); } |
| 856 | x.finish() |
| 857 | } |
| 858 | } |
| 859 | |
| 860 | /// Internal trait implemented for different event type structs (`EvNote`, `EvCtrl`, etc). |
| 861 | /// |
| 862 | /// Use it through `Event::get_data` and `Event::new`. |
| 863 | pub trait EventData { |
| 864 | #[doc (hidden)] |
| 865 | fn get_data(ev: &Event) -> Self; |
| 866 | #[doc (hidden)] |
| 867 | fn has_data(e: EventType) -> bool; |
| 868 | #[doc (hidden)] |
| 869 | fn set_data(&self, ev: &mut Event); |
| 870 | } |
| 871 | |
| 872 | impl EventData for () { |
| 873 | fn get_data(_: &Event) -> Self {} |
| 874 | fn has_data(e: EventType) -> bool { |
| 875 | matches!(e, |
| 876 | EventType::TuneRequest | |
| 877 | EventType::Reset | |
| 878 | EventType::Sensing | |
| 879 | EventType::None) |
| 880 | } |
| 881 | fn set_data(&self, _: &mut Event) {} |
| 882 | } |
| 883 | |
| 884 | impl EventData for [u8; 12] { |
| 885 | fn get_data(ev: &Event) -> Self { |
| 886 | let d = unsafe { ptr::read(&ev.0.data) }; |
| 887 | let z = unsafe { &d.raw8 }; |
| 888 | z.d |
| 889 | } |
| 890 | fn has_data(e: EventType) -> bool { |
| 891 | matches!(e, |
| 892 | EventType::Echo | |
| 893 | EventType::Oss | |
| 894 | EventType::Usr0 | |
| 895 | EventType::Usr1 | |
| 896 | EventType::Usr2 | |
| 897 | EventType::Usr3 | |
| 898 | EventType::Usr4 | |
| 899 | EventType::Usr5 | |
| 900 | EventType::Usr6 | |
| 901 | EventType::Usr7 | |
| 902 | EventType::Usr8 | |
| 903 | EventType::Usr9) |
| 904 | } |
| 905 | fn set_data(&self, ev: &mut Event) { |
| 906 | let z = unsafe { &mut ev.0.data.raw8 }; |
| 907 | z.d = *self; |
| 908 | } |
| 909 | } |
| 910 | |
| 911 | |
| 912 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Default)] |
| 913 | pub struct EvNote { |
| 914 | pub channel: u8, |
| 915 | pub note: u8, |
| 916 | pub velocity: u8, |
| 917 | pub off_velocity: u8, |
| 918 | pub duration: u32, |
| 919 | } |
| 920 | |
| 921 | impl EventData for EvNote { |
| 922 | fn get_data(ev: &Event) -> Self { |
| 923 | let z: &alsa::snd_seq_ev_note_t = unsafe { &*(&ev.0.data as *const alsa::snd_seq_event__bindgen_ty_1 as *const _) }; |
| 924 | EvNote { channel: z.channel as u8, note: z.note as u8, velocity: z.velocity as u8, off_velocity: z.off_velocity as u8, duration: z.duration as u32 } |
| 925 | } |
| 926 | fn has_data(e: EventType) -> bool { |
| 927 | matches!(e, |
| 928 | EventType::Note | |
| 929 | EventType::Noteon | |
| 930 | EventType::Noteoff | |
| 931 | EventType::Keypress) |
| 932 | } |
| 933 | fn set_data(&self, ev: &mut Event) { |
| 934 | let z: &mut alsa::snd_seq_ev_note_t = unsafe { &mut *(&mut ev.0.data as *mut alsa::snd_seq_event__bindgen_ty_1 as *mut _) }; |
| 935 | z.channel = self.channel as c_uchar; |
| 936 | z.note = self.note as c_uchar; |
| 937 | z.velocity = self.velocity as c_uchar; |
| 938 | z.off_velocity = self.off_velocity as c_uchar; |
| 939 | z.duration = self.duration as c_uint; |
| 940 | } |
| 941 | } |
| 942 | |
| 943 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Default)] |
| 944 | pub struct EvCtrl { |
| 945 | pub channel: u8, |
| 946 | pub param: u32, |
| 947 | pub value: i32, |
| 948 | } |
| 949 | |
| 950 | impl EventData for EvCtrl { |
| 951 | fn get_data(ev: &Event) -> Self { |
| 952 | let z: &alsa::snd_seq_ev_ctrl_t = unsafe { &*(&ev.0.data as *const alsa::snd_seq_event__bindgen_ty_1 as *const _) }; |
| 953 | EvCtrl { channel: z.channel as u8, param: z.param as u32, value: z.value as i32 } |
| 954 | } |
| 955 | fn has_data(e: EventType) -> bool { |
| 956 | matches!(e, |
| 957 | EventType::Controller | |
| 958 | EventType::Pgmchange | |
| 959 | EventType::Chanpress | |
| 960 | EventType::Pitchbend | |
| 961 | EventType::Control14 | |
| 962 | EventType::Nonregparam | |
| 963 | EventType::Regparam | |
| 964 | EventType::Songpos | |
| 965 | EventType::Songsel | |
| 966 | EventType::Qframe | |
| 967 | EventType::Timesign | |
| 968 | EventType::Keysign) |
| 969 | } |
| 970 | fn set_data(&self, ev: &mut Event) { |
| 971 | let z: &mut alsa::snd_seq_ev_ctrl_t = unsafe { &mut *(&mut ev.0.data as *mut alsa::snd_seq_event__bindgen_ty_1 as *mut _) }; |
| 972 | z.channel = self.channel as c_uchar; |
| 973 | z.param = self.param as c_uint; |
| 974 | z.value = self.value as c_int; |
| 975 | } |
| 976 | } |
| 977 | |
| 978 | impl EventData for Addr { |
| 979 | fn get_data(ev: &Event) -> Self { |
| 980 | let z: &alsa::snd_seq_addr_t = unsafe { &*(&ev.0.data as *const alsa::snd_seq_event__bindgen_ty_1 as *const _) }; |
| 981 | Addr { client: z.client as i32, port: z.port as i32 } |
| 982 | } |
| 983 | fn has_data(e: EventType) -> bool { |
| 984 | matches!(e, |
| 985 | EventType::ClientStart | |
| 986 | EventType::ClientExit | |
| 987 | EventType::ClientChange | |
| 988 | EventType::PortStart | |
| 989 | EventType::PortExit | |
| 990 | EventType::PortChange) |
| 991 | } |
| 992 | fn set_data(&self, ev: &mut Event) { |
| 993 | let z: &mut alsa::snd_seq_addr_t = unsafe { &mut *(&mut ev.0.data as *mut alsa::snd_seq_event__bindgen_ty_1 as *mut _) }; |
| 994 | z.client = self.client as c_uchar; |
| 995 | z.port = self.port as c_uchar; |
| 996 | } |
| 997 | } |
| 998 | |
| 999 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Default)] |
| 1000 | /// [snd_seq_connect_t](http://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__connect__t.html) wrapper |
| 1001 | pub struct Connect { |
| 1002 | pub sender: Addr, |
| 1003 | pub dest: Addr, |
| 1004 | } |
| 1005 | |
| 1006 | impl EventData for Connect { |
| 1007 | fn get_data(ev: &Event) -> Self { |
| 1008 | let d: snd_seq_event__bindgen_ty_1 = unsafe { ptr::read(&ev.0.data) }; |
| 1009 | let z: &snd_seq_connect = unsafe { &d.connect }; |
| 1010 | Connect { |
| 1011 | sender: Addr { client: z.sender.client as i32, port: z.sender.port as i32 }, |
| 1012 | dest: Addr { client: z.dest.client as i32, port: z.dest.port as i32 } |
| 1013 | } |
| 1014 | } |
| 1015 | fn has_data(e: EventType) -> bool { |
| 1016 | matches!(e, |
| 1017 | EventType::PortSubscribed | |
| 1018 | EventType::PortUnsubscribed) |
| 1019 | } |
| 1020 | fn set_data(&self, ev: &mut Event) { |
| 1021 | let z: &mut snd_seq_connect = unsafe { &mut ev.0.data.connect }; |
| 1022 | z.sender.client = self.sender.client as c_uchar; |
| 1023 | z.sender.port = self.sender.port as c_uchar; |
| 1024 | z.dest.client = self.dest.client as c_uchar; |
| 1025 | z.dest.port = self.dest.port as c_uchar; |
| 1026 | } |
| 1027 | } |
| 1028 | |
| 1029 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Default)] |
| 1030 | /// [snd_seq_ev_queue_control_t](http://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__ev__queue__control__t.html) wrapper |
| 1031 | /// |
| 1032 | /// Note: This struct is generic, but what types of T are required for the different EvQueueControl messages is |
| 1033 | /// not very well documented in alsa-lib. Right now, Tempo is i32, Tick, SetposTick and SyncPos are u32, SetposTime is time::Duration, |
| 1034 | /// and the rest is (). If I guessed wrong, let me know. |
| 1035 | pub struct EvQueueControl<T> { |
| 1036 | pub queue: i32, |
| 1037 | pub value: T, |
| 1038 | } |
| 1039 | |
| 1040 | impl EventData for EvQueueControl<()> { |
| 1041 | fn get_data(ev: &Event) -> Self { |
| 1042 | let d: snd_seq_event__bindgen_ty_1 = unsafe { ptr::read(&ev.0.data) }; |
| 1043 | let z: &snd_seq_ev_queue_control = unsafe { &d.queue }; |
| 1044 | EvQueueControl { queue: z.queue as i32, value: () } |
| 1045 | } |
| 1046 | fn has_data(e: EventType) -> bool { |
| 1047 | matches!(e, |
| 1048 | EventType::Start | |
| 1049 | EventType::Continue | |
| 1050 | EventType::Stop | |
| 1051 | EventType::Clock | |
| 1052 | EventType::QueueSkew) |
| 1053 | } |
| 1054 | fn set_data(&self, ev: &mut Event) { |
| 1055 | let z: &mut snd_seq_ev_queue_control = unsafe { &mut ev.0.data.queue }; |
| 1056 | z.queue = self.queue as c_uchar; |
| 1057 | } |
| 1058 | } |
| 1059 | |
| 1060 | impl EventData for EvQueueControl<i32> { |
| 1061 | fn get_data(ev: &Event) -> Self { unsafe { |
| 1062 | let mut d: snd_seq_event__bindgen_ty_1 = ptr::read(&ev.0.data); |
| 1063 | let z: &mut snd_seq_ev_queue_control = &mut d.queue; |
| 1064 | EvQueueControl { queue: z.queue as i32, value: z.param.value as i32 } |
| 1065 | } } |
| 1066 | fn has_data(e: EventType) -> bool { |
| 1067 | matches!(e, |
| 1068 | EventType::Tempo) |
| 1069 | } |
| 1070 | fn set_data(&self, ev: &mut Event) { unsafe { |
| 1071 | let z: &mut snd_seq_ev_queue_control = &mut ev.0.data.queue; |
| 1072 | z.queue = self.queue as c_uchar; |
| 1073 | z.param.value = self.value as c_int; |
| 1074 | } } |
| 1075 | } |
| 1076 | |
| 1077 | impl EventData for EvQueueControl<u32> { |
| 1078 | fn get_data(ev: &Event) -> Self { unsafe { |
| 1079 | let mut d: snd_seq_event__bindgen_ty_1 = ptr::read(&ev.0.data); |
| 1080 | let z: &mut snd_seq_ev_queue_control = &mut d.queue; |
| 1081 | EvQueueControl { queue: z.queue as i32, value: z.param.position as u32 } |
| 1082 | } } |
| 1083 | fn has_data(e: EventType) -> bool { |
| 1084 | matches!(e, |
| 1085 | EventType::SyncPos | |
| 1086 | EventType::Tick | |
| 1087 | EventType::SetposTick) |
| 1088 | } |
| 1089 | fn set_data(&self, ev: &mut Event) { unsafe { |
| 1090 | let z: &mut snd_seq_ev_queue_control = &mut ev.0.data.queue; |
| 1091 | z.queue = self.queue as c_uchar; |
| 1092 | z.param.position = self.value as c_uint; |
| 1093 | } } |
| 1094 | } |
| 1095 | |
| 1096 | impl EventData for EvQueueControl<time::Duration> { |
| 1097 | fn get_data(ev: &Event) -> Self { unsafe { |
| 1098 | let mut d: snd_seq_event__bindgen_ty_1 = ptr::read(&ev.0.data); |
| 1099 | let z: &mut snd_seq_ev_queue_control = &mut d.queue; |
| 1100 | let t: &mut snd_seq_real_time = &mut z.param.time.time; |
| 1101 | EvQueueControl { queue: z.queue as i32, value: time::Duration::new(secs:t.tv_sec as u64, nanos:t.tv_nsec as u32) } |
| 1102 | } } |
| 1103 | fn has_data(e: EventType) -> bool { |
| 1104 | matches!(e, |
| 1105 | EventType::SetposTime) |
| 1106 | } |
| 1107 | fn set_data(&self, ev: &mut Event) { unsafe { |
| 1108 | let z: &mut snd_seq_ev_queue_control = &mut ev.0.data.queue; |
| 1109 | z.queue = self.queue as c_uchar; |
| 1110 | let t: &mut snd_seq_real_time = &mut z.param.time.time; |
| 1111 | t.tv_sec = self.value.as_secs() as c_uint; |
| 1112 | t.tv_nsec = self.value.subsec_nanos() as c_uint; |
| 1113 | } } |
| 1114 | } |
| 1115 | |
| 1116 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Default)] |
| 1117 | /// [snd_seq_result_t](http://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__result__t.html) wrapper |
| 1118 | /// |
| 1119 | /// It's called EvResult instead of Result, in order to not be confused with Rust's Result type. |
| 1120 | pub struct EvResult { |
| 1121 | pub event: i32, |
| 1122 | pub result: i32, |
| 1123 | } |
| 1124 | |
| 1125 | impl EventData for EvResult { |
| 1126 | fn get_data(ev: &Event) -> Self { |
| 1127 | let d: snd_seq_event__bindgen_ty_1 = unsafe { ptr::read(&ev.0.data) }; |
| 1128 | let z: &snd_seq_result = unsafe { &d.result }; |
| 1129 | EvResult { event: z.event as i32, result: z.result as i32 } |
| 1130 | } |
| 1131 | fn has_data(e: EventType) -> bool { |
| 1132 | matches!(e, |
| 1133 | EventType::System | |
| 1134 | EventType::Result) |
| 1135 | } |
| 1136 | fn set_data(&self, ev: &mut Event) { |
| 1137 | let z: &mut snd_seq_result = unsafe { &mut ev.0.data.result }; |
| 1138 | z.event = self.event as c_int; |
| 1139 | z.result = self.result as c_int; |
| 1140 | } |
| 1141 | } |
| 1142 | |
| 1143 | |
| 1144 | |
| 1145 | alsa_enum!( |
| 1146 | /// [SND_SEQ_EVENT_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_events.html) constants |
| 1147 | |
| 1148 | EventType, ALL_EVENT_TYPES[59], |
| 1149 | |
| 1150 | Bounce = SND_SEQ_EVENT_BOUNCE, |
| 1151 | Chanpress = SND_SEQ_EVENT_CHANPRESS, |
| 1152 | ClientChange = SND_SEQ_EVENT_CLIENT_CHANGE, |
| 1153 | ClientExit = SND_SEQ_EVENT_CLIENT_EXIT, |
| 1154 | ClientStart = SND_SEQ_EVENT_CLIENT_START, |
| 1155 | Clock = SND_SEQ_EVENT_CLOCK, |
| 1156 | Continue = SND_SEQ_EVENT_CONTINUE, |
| 1157 | Control14 = SND_SEQ_EVENT_CONTROL14, |
| 1158 | Controller = SND_SEQ_EVENT_CONTROLLER, |
| 1159 | Echo = SND_SEQ_EVENT_ECHO, |
| 1160 | Keypress = SND_SEQ_EVENT_KEYPRESS, |
| 1161 | Keysign = SND_SEQ_EVENT_KEYSIGN, |
| 1162 | None = SND_SEQ_EVENT_NONE, |
| 1163 | Nonregparam = SND_SEQ_EVENT_NONREGPARAM, |
| 1164 | Note = SND_SEQ_EVENT_NOTE, |
| 1165 | Noteoff = SND_SEQ_EVENT_NOTEOFF, |
| 1166 | Noteon = SND_SEQ_EVENT_NOTEON, |
| 1167 | Oss = SND_SEQ_EVENT_OSS, |
| 1168 | Pgmchange = SND_SEQ_EVENT_PGMCHANGE, |
| 1169 | Pitchbend = SND_SEQ_EVENT_PITCHBEND, |
| 1170 | PortChange = SND_SEQ_EVENT_PORT_CHANGE, |
| 1171 | PortExit = SND_SEQ_EVENT_PORT_EXIT, |
| 1172 | PortStart = SND_SEQ_EVENT_PORT_START, |
| 1173 | PortSubscribed = SND_SEQ_EVENT_PORT_SUBSCRIBED, |
| 1174 | PortUnsubscribed = SND_SEQ_EVENT_PORT_UNSUBSCRIBED, |
| 1175 | Qframe = SND_SEQ_EVENT_QFRAME, |
| 1176 | QueueSkew = SND_SEQ_EVENT_QUEUE_SKEW, |
| 1177 | Regparam = SND_SEQ_EVENT_REGPARAM, |
| 1178 | Reset = SND_SEQ_EVENT_RESET, |
| 1179 | Result = SND_SEQ_EVENT_RESULT, |
| 1180 | Sensing = SND_SEQ_EVENT_SENSING, |
| 1181 | SetposTick = SND_SEQ_EVENT_SETPOS_TICK, |
| 1182 | SetposTime = SND_SEQ_EVENT_SETPOS_TIME, |
| 1183 | Songpos = SND_SEQ_EVENT_SONGPOS, |
| 1184 | Songsel = SND_SEQ_EVENT_SONGSEL, |
| 1185 | Start = SND_SEQ_EVENT_START, |
| 1186 | Stop = SND_SEQ_EVENT_STOP, |
| 1187 | SyncPos = SND_SEQ_EVENT_SYNC_POS, |
| 1188 | Sysex = SND_SEQ_EVENT_SYSEX, |
| 1189 | System = SND_SEQ_EVENT_SYSTEM, |
| 1190 | Tempo = SND_SEQ_EVENT_TEMPO, |
| 1191 | Tick = SND_SEQ_EVENT_TICK, |
| 1192 | Timesign = SND_SEQ_EVENT_TIMESIGN, |
| 1193 | TuneRequest = SND_SEQ_EVENT_TUNE_REQUEST, |
| 1194 | Usr0 = SND_SEQ_EVENT_USR0, |
| 1195 | Usr1 = SND_SEQ_EVENT_USR1, |
| 1196 | Usr2 = SND_SEQ_EVENT_USR2, |
| 1197 | Usr3 = SND_SEQ_EVENT_USR3, |
| 1198 | Usr4 = SND_SEQ_EVENT_USR4, |
| 1199 | Usr5 = SND_SEQ_EVENT_USR5, |
| 1200 | Usr6 = SND_SEQ_EVENT_USR6, |
| 1201 | Usr7 = SND_SEQ_EVENT_USR7, |
| 1202 | Usr8 = SND_SEQ_EVENT_USR8, |
| 1203 | Usr9 = SND_SEQ_EVENT_USR9, |
| 1204 | UsrVar0 = SND_SEQ_EVENT_USR_VAR0, |
| 1205 | UsrVar1 = SND_SEQ_EVENT_USR_VAR1, |
| 1206 | UsrVar2 = SND_SEQ_EVENT_USR_VAR2, |
| 1207 | UsrVar3 = SND_SEQ_EVENT_USR_VAR3, |
| 1208 | UsrVar4 = SND_SEQ_EVENT_USR_VAR4, |
| 1209 | ); |
| 1210 | |
| 1211 | /// [snd_seq_queue_tempo_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_queue.html) wrapper |
| 1212 | pub struct QueueTempo(*mut alsa::snd_seq_queue_tempo_t); |
| 1213 | |
| 1214 | unsafe impl Send for QueueTempo {} |
| 1215 | |
| 1216 | impl Drop for QueueTempo { |
| 1217 | fn drop(&mut self) { unsafe { alsa::snd_seq_queue_tempo_free(self.0) } } |
| 1218 | } |
| 1219 | |
| 1220 | impl QueueTempo { |
| 1221 | fn new() -> Result<Self> { |
| 1222 | let mut q = ptr::null_mut(); |
| 1223 | acheck!(snd_seq_queue_tempo_malloc(&mut q)).map(|_| QueueTempo(q)) |
| 1224 | } |
| 1225 | |
| 1226 | /// Creates a new QueueTempo with all fields set to zero. |
| 1227 | pub fn empty() -> Result<Self> { |
| 1228 | let q = QueueTempo::new()?; |
| 1229 | unsafe { ptr::write_bytes(q.0 as *mut u8, 0, alsa::snd_seq_queue_tempo_sizeof()) }; |
| 1230 | Ok(q) |
| 1231 | } |
| 1232 | |
| 1233 | pub fn get_queue(&self) -> i32 { unsafe { alsa::snd_seq_queue_tempo_get_queue(self.0) as i32 } } |
| 1234 | pub fn get_tempo(&self) -> u32 { unsafe { alsa::snd_seq_queue_tempo_get_tempo(self.0) as u32 } } |
| 1235 | pub fn get_ppq(&self) -> i32 { unsafe { alsa::snd_seq_queue_tempo_get_ppq(self.0) as i32 } } |
| 1236 | pub fn get_skew(&self) -> u32 { unsafe { alsa::snd_seq_queue_tempo_get_skew(self.0) as u32 } } |
| 1237 | pub fn get_skew_base(&self) -> u32 { unsafe { alsa::snd_seq_queue_tempo_get_skew_base(self.0) as u32 } } |
| 1238 | |
| 1239 | // pub fn set_queue(&self, value: i32) { unsafe { alsa::snd_seq_queue_tempo_set_queue(self.0, value as c_int) } } |
| 1240 | pub fn set_tempo(&self, value: u32) { unsafe { alsa::snd_seq_queue_tempo_set_tempo(self.0, value as c_uint) } } |
| 1241 | pub fn set_ppq(&self, value: i32) { unsafe { alsa::snd_seq_queue_tempo_set_ppq(self.0, value as c_int) } } |
| 1242 | pub fn set_skew(&self, value: u32) { unsafe { alsa::snd_seq_queue_tempo_set_skew(self.0, value as c_uint) } } |
| 1243 | pub fn set_skew_base(&self, value: u32) { unsafe { alsa::snd_seq_queue_tempo_set_skew_base(self.0, value as c_uint) } } |
| 1244 | } |
| 1245 | |
| 1246 | /// [snd_seq_queue_status_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_queue.html) wrapper |
| 1247 | pub struct QueueStatus(*mut alsa::snd_seq_queue_status_t); |
| 1248 | |
| 1249 | unsafe impl Send for QueueStatus {} |
| 1250 | |
| 1251 | impl Drop for QueueStatus { |
| 1252 | fn drop(&mut self) { unsafe { alsa::snd_seq_queue_status_free(self.0) } } |
| 1253 | } |
| 1254 | |
| 1255 | impl QueueStatus { |
| 1256 | fn new() -> Result<Self> { |
| 1257 | let mut q: *mut _snd_seq_queue_status = ptr::null_mut(); |
| 1258 | acheck!(snd_seq_queue_status_malloc(&mut q)).map(|_| QueueStatus(q)) |
| 1259 | } |
| 1260 | |
| 1261 | /// Creates a new QueueStatus with all fields set to zero. |
| 1262 | pub fn empty() -> Result<Self> { |
| 1263 | let q: QueueStatus = QueueStatus::new()?; |
| 1264 | unsafe { ptr::write_bytes(dst:q.0 as *mut u8, val:0, count:alsa::snd_seq_queue_status_sizeof()) }; |
| 1265 | Ok(q) |
| 1266 | } |
| 1267 | |
| 1268 | pub fn get_queue(&self) -> i32 { unsafe { alsa::snd_seq_queue_status_get_queue(self.0) as i32 } } |
| 1269 | pub fn get_events(&self) -> i32 { unsafe { alsa::snd_seq_queue_status_get_events(self.0) as i32 } } |
| 1270 | pub fn get_tick_time(&self) -> u32 { unsafe {alsa::snd_seq_queue_status_get_tick_time(self.0) as u32 } } |
| 1271 | pub fn get_real_time(&self) -> time::Duration { unsafe { |
| 1272 | let t: &snd_seq_real_time = &(*alsa::snd_seq_queue_status_get_real_time(self.0)); |
| 1273 | time::Duration::new(secs:t.tv_sec as u64, nanos:t.tv_nsec as u32) |
| 1274 | } } |
| 1275 | pub fn get_status(&self) -> u32 { unsafe { alsa::snd_seq_queue_status_get_status(self.0) as u32 } } |
| 1276 | } |
| 1277 | |
| 1278 | /// [snd_seq_remove_events_t](https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_event.html) wrapper |
| 1279 | pub struct RemoveEvents(*mut alsa::snd_seq_remove_events_t); |
| 1280 | |
| 1281 | unsafe impl Send for RemoveEvents {} |
| 1282 | |
| 1283 | impl Drop for RemoveEvents { |
| 1284 | fn drop(&mut self) { unsafe { alsa::snd_seq_remove_events_free(self.0) } } |
| 1285 | } |
| 1286 | |
| 1287 | impl RemoveEvents { |
| 1288 | pub fn new() -> Result<Self> { |
| 1289 | let mut q = ptr::null_mut(); |
| 1290 | acheck!(snd_seq_remove_events_malloc(&mut q)).map(|_| RemoveEvents(q)) |
| 1291 | } |
| 1292 | |
| 1293 | pub fn get_condition(&self) -> Remove { unsafe { |
| 1294 | Remove::from_bits_truncate(alsa::snd_seq_remove_events_get_condition(self.0) as u32) |
| 1295 | } } |
| 1296 | pub fn get_queue(&self) -> i32 { unsafe { alsa::snd_seq_remove_events_get_queue(self.0) as i32 } } |
| 1297 | pub fn get_time(&self) -> time::Duration { unsafe { |
| 1298 | let d = ptr::read(alsa::snd_seq_remove_events_get_time(self.0)); |
| 1299 | let t = &d.time; |
| 1300 | |
| 1301 | time::Duration::new(t.tv_sec as u64, t.tv_nsec as u32) |
| 1302 | } } |
| 1303 | pub fn get_dest(&self) -> Addr { unsafe { |
| 1304 | let a = &(*alsa::snd_seq_remove_events_get_dest(self.0)); |
| 1305 | |
| 1306 | Addr { client: a.client as i32, port: a.port as i32 } |
| 1307 | } } |
| 1308 | pub fn get_channel(&self) -> i32 { unsafe { alsa::snd_seq_remove_events_get_channel(self.0) as i32 } } |
| 1309 | pub fn get_event_type(&self) -> Result<EventType> { unsafe { |
| 1310 | EventType::from_c_int(alsa::snd_seq_remove_events_get_event_type(self.0), "snd_seq_remove_events_get_event_type" ) |
| 1311 | } } |
| 1312 | pub fn get_tag(&self) -> u8 { unsafe { alsa::snd_seq_remove_events_get_tag(self.0) as u8 } } |
| 1313 | |
| 1314 | |
| 1315 | pub fn set_condition(&self, value: Remove) { unsafe { |
| 1316 | alsa::snd_seq_remove_events_set_condition(self.0, value.bits() as c_uint); |
| 1317 | } } |
| 1318 | pub fn set_queue(&self, value: i32) { unsafe { alsa::snd_seq_remove_events_set_queue(self.0, value as c_int) } } |
| 1319 | pub fn set_time(&self, value: time::Duration) { unsafe { |
| 1320 | let mut d: alsa::snd_seq_timestamp_t = mem::zeroed(); |
| 1321 | let t = &mut d.time; |
| 1322 | |
| 1323 | t.tv_sec = value.as_secs() as c_uint; |
| 1324 | t.tv_nsec = value.subsec_nanos() as c_uint; |
| 1325 | |
| 1326 | alsa::snd_seq_remove_events_set_time(self.0, &d); |
| 1327 | } } |
| 1328 | pub fn set_dest(&self, value: Addr) { unsafe { |
| 1329 | let a = alsa::snd_seq_addr_t { client: value.client as c_uchar, port: value.port as c_uchar}; |
| 1330 | |
| 1331 | alsa::snd_seq_remove_events_set_dest(self.0, &a); |
| 1332 | } } |
| 1333 | pub fn set_channel(&self, value: i32) { unsafe { alsa::snd_seq_remove_events_set_channel(self.0, value as c_int) } } |
| 1334 | pub fn set_event_type(&self, value: EventType) { unsafe { alsa::snd_seq_remove_events_set_event_type(self.0, value as i32); } } |
| 1335 | pub fn set_tag(&self, value: u8) { unsafe { alsa::snd_seq_remove_events_set_tag(self.0, value as c_int) } } |
| 1336 | } |
| 1337 | |
| 1338 | /// [snd_midi_event_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___m_i_d_i___event.html) Wrapper |
| 1339 | /// |
| 1340 | /// Sequencer event <-> MIDI byte stream coder |
| 1341 | pub struct MidiEvent(*mut alsa::snd_midi_event_t); |
| 1342 | |
| 1343 | impl Drop for MidiEvent { |
| 1344 | fn drop(&mut self) { unsafe { alsa::snd_midi_event_free(self.0) } } |
| 1345 | } |
| 1346 | |
| 1347 | impl MidiEvent { |
| 1348 | pub fn new(bufsize: u32) -> Result<MidiEvent> { |
| 1349 | let mut q = ptr::null_mut(); |
| 1350 | acheck!(snd_midi_event_new(bufsize as size_t, &mut q)).map(|_| MidiEvent(q)) |
| 1351 | } |
| 1352 | |
| 1353 | pub fn resize_buffer(&self, bufsize: u32) -> Result<()> { acheck!(snd_midi_event_resize_buffer(self.0, bufsize as size_t)).map(|_| ()) } |
| 1354 | |
| 1355 | /// Note: this corresponds to snd_midi_event_no_status, but on and off are switched. |
| 1356 | /// |
| 1357 | /// Alsa-lib is a bit confusing here. Anyhow, set "enable" to true to enable running status. |
| 1358 | pub fn enable_running_status(&self, enable: bool) { unsafe { alsa::snd_midi_event_no_status(self.0, if enable {0} else {1}) } } |
| 1359 | |
| 1360 | /// Resets both encoder and decoder |
| 1361 | pub fn init(&self) { unsafe { alsa::snd_midi_event_init(self.0) } } |
| 1362 | |
| 1363 | pub fn reset_encode(&self) { unsafe { alsa::snd_midi_event_reset_encode(self.0) } } |
| 1364 | |
| 1365 | pub fn reset_decode(&self) { unsafe { alsa::snd_midi_event_reset_decode(self.0) } } |
| 1366 | |
| 1367 | pub fn decode(&self, buf: &mut [u8], ev: &mut Event) -> Result<usize> { |
| 1368 | ev.ensure_buf(); |
| 1369 | acheck!(snd_midi_event_decode(self.0, buf.as_mut_ptr() as *mut c_uchar, buf.len() as c_long, &ev.0)).map(|r| r as usize) |
| 1370 | } |
| 1371 | |
| 1372 | /// In case of success, returns a tuple of (bytes consumed from buf, found Event). |
| 1373 | pub fn encode<'a>(&'a mut self, buf: &[u8]) -> Result<(usize, Option<Event<'a>>)> { |
| 1374 | // The ALSA documentation clearly states that the event will be valid as long as the Encoder |
| 1375 | // is not messed with (because the data pointer for sysex events may point into the Encoder's |
| 1376 | // buffer). We make this safe by taking self by unique reference and coupling it to |
| 1377 | // the event's lifetime. |
| 1378 | let mut ev = unsafe { mem::zeroed() }; |
| 1379 | let r = acheck!(snd_midi_event_encode(self.0, buf.as_ptr() as *const c_uchar, buf.len() as c_long, &mut ev))?; |
| 1380 | let e = if ev.type_ == alsa::SND_SEQ_EVENT_NONE as u8 { |
| 1381 | None |
| 1382 | } else { |
| 1383 | Some(unsafe { Event::extract(&mut ev, "snd_midi_event_encode" ) }?) |
| 1384 | }; |
| 1385 | Ok((r as usize, e)) |
| 1386 | } |
| 1387 | } |
| 1388 | |
| 1389 | #[test ] |
| 1390 | fn print_seqs() { |
| 1391 | use std::ffi::CString; |
| 1392 | let s = super::Seq::open(None, None, false).unwrap(); |
| 1393 | s.set_client_name(&CString::new("rust_test_print_seqs" ).unwrap()).unwrap(); |
| 1394 | let clients: Vec<_> = ClientIter::new(&s).collect(); |
| 1395 | for a in &clients { |
| 1396 | let ports: Vec<_> = PortIter::new(&s, a.get_client()).collect(); |
| 1397 | println!("{:?}: {:?}" , a, ports); |
| 1398 | } |
| 1399 | } |
| 1400 | |
| 1401 | #[test ] |
| 1402 | fn seq_subscribe() { |
| 1403 | use std::ffi::CString; |
| 1404 | let s = super::Seq::open(None, None, false).unwrap(); |
| 1405 | s.set_client_name(&CString::new("rust_test_seq_subscribe" ).unwrap()).unwrap(); |
| 1406 | let timer_info = s.get_any_port_info(Addr { client: 0, port: 0 }).unwrap(); |
| 1407 | assert_eq!(timer_info.get_name().unwrap(), "Timer" ); |
| 1408 | let info = PortInfo::empty().unwrap(); |
| 1409 | let _port = s.create_port(&info); |
| 1410 | let subs = PortSubscribe::empty().unwrap(); |
| 1411 | subs.set_sender(Addr { client: 0, port: 0 }); |
| 1412 | subs.set_dest(Addr { client: s.client_id().unwrap(), port: info.get_port() }); |
| 1413 | s.subscribe_port(&subs).unwrap(); |
| 1414 | } |
| 1415 | |
| 1416 | #[test ] |
| 1417 | fn seq_loopback() { |
| 1418 | use std::ffi::CString; |
| 1419 | let s = super::Seq::open(Some(&CString::new("default" ).unwrap()), None, false).unwrap(); |
| 1420 | s.set_client_name(&CString::new("rust_test_seq_loopback" ).unwrap()).unwrap(); |
| 1421 | |
| 1422 | // Create ports |
| 1423 | let sinfo = PortInfo::empty().unwrap(); |
| 1424 | sinfo.set_capability(PortCap::READ | PortCap::SUBS_READ); |
| 1425 | sinfo.set_type(PortType::MIDI_GENERIC | PortType::APPLICATION); |
| 1426 | s.create_port(&sinfo).unwrap(); |
| 1427 | let sport = sinfo.get_port(); |
| 1428 | let dinfo = PortInfo::empty().unwrap(); |
| 1429 | dinfo.set_capability(PortCap::WRITE | PortCap::SUBS_WRITE); |
| 1430 | dinfo.set_type(PortType::MIDI_GENERIC | PortType::APPLICATION); |
| 1431 | s.create_port(&dinfo).unwrap(); |
| 1432 | let dport = dinfo.get_port(); |
| 1433 | |
| 1434 | // Connect them |
| 1435 | let subs = PortSubscribe::empty().unwrap(); |
| 1436 | subs.set_sender(Addr { client: s.client_id().unwrap(), port: sport }); |
| 1437 | subs.set_dest(Addr { client: s.client_id().unwrap(), port: dport }); |
| 1438 | s.subscribe_port(&subs).unwrap(); |
| 1439 | println!("Connected {:?} to {:?}" , subs.get_sender(), subs.get_dest()); |
| 1440 | |
| 1441 | // Send a note! |
| 1442 | let note = EvNote { channel: 0, note: 64, duration: 100, velocity: 100, off_velocity: 64 }; |
| 1443 | let mut e = Event::new(EventType::Noteon, ¬e); |
| 1444 | e.set_subs(); |
| 1445 | e.set_direct(); |
| 1446 | e.set_source(sport); |
| 1447 | println!("Sending {:?}" , e); |
| 1448 | s.event_output(&mut e).unwrap(); |
| 1449 | s.drain_output().unwrap(); |
| 1450 | |
| 1451 | // Receive the note! |
| 1452 | let mut input = s.input(); |
| 1453 | let e2 = input.event_input().unwrap(); |
| 1454 | println!("Receiving {:?}" , e2); |
| 1455 | assert_eq!(e2.get_type(), EventType::Noteon); |
| 1456 | assert_eq!(e2.get_data(), Some(note)); |
| 1457 | } |
| 1458 | |
| 1459 | #[test ] |
| 1460 | fn seq_encode_sysex() { |
| 1461 | let mut me = MidiEvent::new(16).unwrap(); |
| 1462 | let sysex = &[0xf0, 1, 2, 3, 4, 5, 6, 7, 0xf7]; |
| 1463 | let (s, ev) = me.encode(sysex).unwrap(); |
| 1464 | assert_eq!(s, 9); |
| 1465 | let ev = ev.unwrap(); |
| 1466 | let v = ev.get_ext().unwrap(); |
| 1467 | assert_eq!(&*v, sysex); |
| 1468 | } |
| 1469 | |
| 1470 | #[test ] |
| 1471 | fn seq_decode_sysex() { |
| 1472 | let sysex = [0xf0, 1, 2, 3, 4, 5, 6, 7, 0xf7]; |
| 1473 | let mut ev = Event::new_ext(EventType::Sysex, &sysex[..]); |
| 1474 | let me = MidiEvent::new(0).unwrap(); |
| 1475 | let mut buffer = vec![0; sysex.len()]; |
| 1476 | assert_eq!(me.decode(&mut buffer[..], &mut ev).unwrap(), sysex.len()); |
| 1477 | assert_eq!(buffer, sysex); |
| 1478 | } |
| 1479 | |
| 1480 | #[test ] |
| 1481 | #[should_panic ] |
| 1482 | fn seq_get_input_twice() { |
| 1483 | use std::ffi::CString; |
| 1484 | let s = super::Seq::open(None, None, false).unwrap(); |
| 1485 | s.set_client_name(&CString::new("rust_test_seq_get_input_twice" ).unwrap()).unwrap(); |
| 1486 | let input1 = s.input(); |
| 1487 | let input2 = s.input(); // this should panic |
| 1488 | let _ = (input1, input2); |
| 1489 | } |
| 1490 | |
| 1491 | #[test ] |
| 1492 | fn seq_has_data() { |
| 1493 | for v in EventType::all() { |
| 1494 | let v = *v; |
| 1495 | let mut i = 0; |
| 1496 | if <() as EventData>::has_data(v) { i += 1; } |
| 1497 | if <[u8; 12] as EventData>::has_data(v) { i += 1; } |
| 1498 | if Event::has_ext_data(v) { i += 1; } |
| 1499 | if EvNote::has_data(v) { i += 1; } |
| 1500 | if EvCtrl::has_data(v) { i += 1; } |
| 1501 | if Addr::has_data(v) { i += 1; } |
| 1502 | if Connect::has_data(v) { i += 1; } |
| 1503 | if EvResult::has_data(v) { i += 1; } |
| 1504 | if EvQueueControl::<()>::has_data(v) { i += 1; } |
| 1505 | if EvQueueControl::<u32>::has_data(v) { i += 1; } |
| 1506 | if EvQueueControl::<i32>::has_data(v) { i += 1; } |
| 1507 | if EvQueueControl::<time::Duration>::has_data(v) { i += 1; } |
| 1508 | if i != 1 { panic!("{:?}: {} has_data" , v, i) } |
| 1509 | } |
| 1510 | } |
| 1511 | |
| 1512 | #[test ] |
| 1513 | fn seq_remove_events() -> std::result::Result<(), Box<dyn std::error::Error>> { |
| 1514 | let info = RemoveEvents::new()?; |
| 1515 | |
| 1516 | |
| 1517 | info.set_condition(Remove::INPUT | Remove::DEST | Remove::TIME_BEFORE | Remove::TAG_MATCH); |
| 1518 | info.set_queue(123); |
| 1519 | info.set_time(time::Duration::new(456, 789)); |
| 1520 | info.set_dest(Addr { client: 212, port: 121 }); |
| 1521 | info.set_channel(15); |
| 1522 | info.set_event_type(EventType::Noteon); |
| 1523 | info.set_tag(213); |
| 1524 | |
| 1525 | assert_eq!(info.get_condition(), Remove::INPUT | Remove::DEST | Remove::TIME_BEFORE | Remove::TAG_MATCH); |
| 1526 | assert_eq!(info.get_queue(), 123); |
| 1527 | assert_eq!(info.get_time(), time::Duration::new(456, 789)); |
| 1528 | assert_eq!(info.get_dest(), Addr { client: 212, port: 121 }); |
| 1529 | assert_eq!(info.get_channel(), 15); |
| 1530 | assert_eq!(info.get_event_type()?, EventType::Noteon); |
| 1531 | assert_eq!(info.get_tag(), 213); |
| 1532 | |
| 1533 | Ok(()) |
| 1534 | } |
| 1535 | |
| 1536 | #[test ] |
| 1537 | fn seq_portsubscribeiter() { |
| 1538 | let s = super::Seq::open(None, None, false).unwrap(); |
| 1539 | |
| 1540 | // Create ports |
| 1541 | let sinfo = PortInfo::empty().unwrap(); |
| 1542 | sinfo.set_capability(PortCap::READ | PortCap::SUBS_READ); |
| 1543 | sinfo.set_type(PortType::MIDI_GENERIC | PortType::APPLICATION); |
| 1544 | s.create_port(&sinfo).unwrap(); |
| 1545 | let sport = sinfo.get_port(); |
| 1546 | let dinfo = PortInfo::empty().unwrap(); |
| 1547 | dinfo.set_capability(PortCap::WRITE | PortCap::SUBS_WRITE); |
| 1548 | dinfo.set_type(PortType::MIDI_GENERIC | PortType::APPLICATION); |
| 1549 | s.create_port(&dinfo).unwrap(); |
| 1550 | let dport = dinfo.get_port(); |
| 1551 | |
| 1552 | // Connect them |
| 1553 | let subs = PortSubscribe::empty().unwrap(); |
| 1554 | subs.set_sender(Addr { client: s.client_id().unwrap(), port: sport }); |
| 1555 | subs.set_dest(Addr { client: s.client_id().unwrap(), port: dport }); |
| 1556 | s.subscribe_port(&subs).unwrap(); |
| 1557 | |
| 1558 | // Query READ subs from sport's point of view |
| 1559 | let read_subs: Vec<PortSubscribe> = PortSubscribeIter::new(&s, |
| 1560 | Addr {client: s.client_id().unwrap(), port: sport }, |
| 1561 | QuerySubsType::READ).collect(); |
| 1562 | assert_eq!(read_subs.len(), 1); |
| 1563 | assert_eq!(read_subs[0].get_sender(), subs.get_sender()); |
| 1564 | assert_eq!(read_subs[0].get_dest(), subs.get_dest()); |
| 1565 | |
| 1566 | let write_subs: Vec<PortSubscribe> = PortSubscribeIter::new(&s, |
| 1567 | Addr {client: s.client_id().unwrap(), port: sport }, |
| 1568 | QuerySubsType::WRITE).collect(); |
| 1569 | assert_eq!(write_subs.len(), 0); |
| 1570 | |
| 1571 | // Now query WRITE subs from dport's point of view |
| 1572 | let write_subs: Vec<PortSubscribe> = PortSubscribeIter::new(&s, |
| 1573 | Addr {client: s.client_id().unwrap(), port: dport }, |
| 1574 | QuerySubsType::WRITE).collect(); |
| 1575 | assert_eq!(write_subs.len(), 1); |
| 1576 | assert_eq!(write_subs[0].get_sender(), subs.get_sender()); |
| 1577 | assert_eq!(write_subs[0].get_dest(), subs.get_dest()); |
| 1578 | } |
| 1579 | |