1use libc::{c_int, c_uint, c_void, size_t, c_short, pollfd};
4use super::ctl_int::{ctl_ptr, Ctl};
5use super::{Direction, poll};
6use super::error::*;
7use crate::alsa;
8use ::alloc::ffi::CString;
9use ::alloc::string::{String, ToString};
10use core::ptr;
11use core::ffi::CStr;
12
13#[derive(Debug)]
15pub struct Iter<'a> {
16 ctl: &'a Ctl,
17 device: c_int,
18 in_count: i32,
19 out_count: i32,
20 current: i32,
21}
22
23#[derive(Debug)]
25pub struct Info(*mut alsa::snd_rawmidi_info_t);
26
27impl Drop for Info {
28 fn drop(&mut self) { unsafe { alsa::snd_rawmidi_info_free(self.0) }; }
29}
30
31impl Info {
32 fn new() -> Result<Info> {
33 let mut p = ptr::null_mut();
34 acheck!(snd_rawmidi_info_malloc(&mut p)).map(|_| Info(p))
35 }
36
37 fn from_iter(c: &Ctl, device: i32, sub: i32, dir: Direction) -> Result<Info> {
38 let r = Info::new()?;
39 unsafe { alsa::snd_rawmidi_info_set_device(r.0, device as c_uint) };
40 let d = match dir {
41 Direction::Playback => alsa::SND_RAWMIDI_STREAM_OUTPUT,
42 Direction::Capture => alsa::SND_RAWMIDI_STREAM_INPUT,
43 };
44 unsafe { alsa::snd_rawmidi_info_set_stream(r.0, d) };
45 unsafe { alsa::snd_rawmidi_info_set_subdevice(r.0, sub as c_uint) };
46 acheck!(snd_ctl_rawmidi_info(ctl_ptr(c), r.0)).map(|_| r)
47 }
48
49 fn subdev_count(c: &Ctl, device: c_int) -> Result<(i32, i32)> {
50 let i = Info::from_iter(c, device, 0, Direction::Capture)?;
51 let o = Info::from_iter(c, device, 0, Direction::Playback)?;
52 Ok((unsafe { alsa::snd_rawmidi_info_get_subdevices_count(o.0) as i32 },
53 unsafe { alsa::snd_rawmidi_info_get_subdevices_count(i.0) as i32 }))
54 }
55
56 pub fn get_device(&self) -> i32 { unsafe { alsa::snd_rawmidi_info_get_device(self.0) as i32 }}
57 pub fn get_subdevice(&self) -> i32 { unsafe { alsa::snd_rawmidi_info_get_subdevice(self.0) as i32 }}
58 pub fn get_stream(&self) -> super::Direction {
59 if unsafe { alsa::snd_rawmidi_info_get_stream(self.0) } == alsa::SND_RAWMIDI_STREAM_OUTPUT { super::Direction::Playback }
60 else { super::Direction::Capture }
61 }
62
63 pub fn get_subdevice_name(&self) -> Result<String> {
64 let c = unsafe { alsa::snd_rawmidi_info_get_subdevice_name(self.0) };
65 from_const("snd_rawmidi_info_get_subdevice_name", c).map(|s| s.to_string())
66 }
67 pub fn get_id(&self) -> Result<String> {
68 let c = unsafe { alsa::snd_rawmidi_info_get_id(self.0) };
69 from_const("snd_rawmidi_info_get_id", c).map(|s| s.to_string())
70 }
71}
72
73#[derive(Debug)]
75pub struct Status(*mut alsa::snd_rawmidi_status_t);
76
77impl Status {
78 fn new() -> Result<Self> {
79 let mut p = ptr::null_mut();
80 acheck!(snd_rawmidi_status_malloc(&mut p)).map(|_| Status(p))
81 }
82}
83
84impl Status {
85 pub fn get_avail(&self) -> usize { unsafe { alsa::snd_rawmidi_status_get_avail(self.0 as *const _) } }
86 pub fn get_xruns(&self) -> usize { unsafe { alsa::snd_rawmidi_status_get_xruns(self.0 as *const _) } }
87}
88
89impl Drop for Status {
90 fn drop(&mut self) { unsafe { alsa::snd_rawmidi_status_free(self.0) }; }
91}
92
93
94impl<'a> Iter<'a> {
95 pub fn new(c: &'a Ctl) -> Iter<'a> { Iter { ctl: c, device: -1, in_count: 0, out_count: 0, current: 0 }}
96}
97
98impl<'a> Iterator for Iter<'a> {
99 type Item = Result<Info>;
100 fn next(&mut self) -> Option<Result<Info>> {
101 if self.current < self.in_count {
102 self.current += 1;
103 return Some(Info::from_iter(self.ctl, self.device, self.current-1, Direction::Capture));
104 }
105 if self.current - self.in_count < self.out_count {
106 self.current += 1;
107 return Some(Info::from_iter(self.ctl, self.device, self.current-1-self.in_count, Direction::Playback));
108 }
109
110 let r = acheck!(snd_ctl_rawmidi_next_device(ctl_ptr(self.ctl), &mut self.device));
111 match r {
112 Err(e) if e.errno() == libc::ENOTTY => return None,
113 Err(e) => return Some(Err(e)),
114 Ok(_) if self.device == -1 => return None,
115 _ => {},
116 }
117 self.current = 0;
118 match Info::subdev_count(self.ctl, self.device) {
119 Err(e) => Some(Err(e)),
120 Ok((oo, ii)) => {
121 self.in_count = ii;
122 self.out_count = oo;
123 self.next()
124 }
125 }
126 }
127}
128
129#[derive(Debug)]
131pub struct Rawmidi(*mut alsa::snd_rawmidi_t);
132
133unsafe impl Send for Rawmidi {}
134
135impl Drop for Rawmidi {
136 fn drop(&mut self) { unsafe { alsa::snd_rawmidi_close(self.0) }; }
137}
138
139impl Rawmidi {
140
141 pub fn new(name: &str, dir: Direction, nonblock: bool) -> Result<Self> {
143 Self::open(&CString::new(name).unwrap(), dir, nonblock)
144 }
145
146 pub fn open(name: &CStr, dir: Direction, nonblock: bool) -> Result<Rawmidi> {
147 let mut h = ptr::null_mut();
148 let flags = if nonblock { 2 } else { 0 }; acheck!(snd_rawmidi_open(
150 if dir == Direction::Capture { &mut h } else { ptr::null_mut() },
151 if dir == Direction::Playback { &mut h } else { ptr::null_mut() },
152 name.as_ptr(), flags))
153 .map(|_| Rawmidi(h))
154 }
155
156 pub fn info(&self) -> Result<Info> {
157 Info::new().and_then(|i| acheck!(snd_rawmidi_info(self.0, i.0)).map(|_| i))
158 }
159
160 pub fn status(&self) -> Result<Status> {
161 Status::new().and_then(|i| acheck!(snd_rawmidi_status(self.0, i.0)).map(|_| i))
162 }
163
164 pub fn drop(&self) -> Result<()> { acheck!(snd_rawmidi_drop(self.0)).map(|_| ()) }
165 pub fn drain(&self) -> Result<()> { acheck!(snd_rawmidi_drain(self.0)).map(|_| ()) }
166 pub fn name(&self) -> Result<String> {
167 let c = unsafe { alsa::snd_rawmidi_name(self.0) };
168 from_const("snd_rawmidi_name", c).map(|s| s.to_string())
169 }
170
171 pub fn io(&self) -> IO<'_> { IO(self) }
172}
173
174impl poll::Descriptors for Rawmidi {
175 fn count(&self) -> usize {
176 unsafe { alsa::snd_rawmidi_poll_descriptors_count(self.0) as usize }
177 }
178 fn fill(&self, p: &mut [pollfd]) -> Result<usize> {
179 let z = unsafe { alsa::snd_rawmidi_poll_descriptors(self.0, p.as_mut_ptr(), p.len() as c_uint) };
180 from_code("snd_rawmidi_poll_descriptors", z).map(|_| z as usize)
181 }
182 fn revents(&self, p: &[pollfd]) -> Result<poll::Flags> {
183 let mut r = 0;
184 let z = unsafe { alsa::snd_rawmidi_poll_descriptors_revents(self.0, p.as_ptr() as *mut pollfd, p.len() as c_uint, &mut r) };
185 from_code("snd_rawmidi_poll_descriptors_revents", z).map(|_| poll::Flags::from_bits_truncate(r as c_short))
186 }
187}
188
189#[derive(Debug)]
191pub struct IO<'a>(&'a Rawmidi);
192
193#[cfg(feature = "std")]
194impl<'a> std::io::Read for IO<'a> {
195 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
196 let r = unsafe { alsa::snd_rawmidi_read((self.0).0, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };
197 if r < 0 { Err(std::io::Error::from_raw_os_error(r as i32)) }
198 else { Ok(r as usize) }
199 }
200}
201
202#[cfg(feature = "std")]
203impl<'a> std::io::Write for IO<'a> {
204 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
205 let r = unsafe { alsa::snd_rawmidi_write((self.0).0, buf.as_ptr() as *const c_void, buf.len() as size_t) };
206 if r < 0 { Err(std::io::Error::from_raw_os_error(r as i32)) }
207 else { Ok(r as usize) }
208 }
209 fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
210}
211
212
213#[test]
214fn print_rawmidis() {
215 extern crate std;
216
217 for a in super::card::Iter::new().map(|a| a.unwrap()) {
218 for b in Iter::new(&Ctl::from_card(&a, false).unwrap()).map(|b| b.unwrap()) {
219 std::println!("Rawmidi {:?} (hw:{},{},{}) {} - {}", b.get_stream(), a.get_index(), b.get_device(), b.get_subdevice(),
220 a.get_name().unwrap(), b.get_subdevice_name().unwrap())
221 }
222 }
223}