midir/
common.rs

1#![deny(missing_docs)]
2
3use backend::{
4    MidiInput as MidiInputImpl, MidiInputConnection as MidiInputConnectionImpl,
5    MidiInputPort as MidiInputPortImpl, MidiOutput as MidiOutputImpl,
6    MidiOutputConnection as MidiOutputConnectionImpl, MidiOutputPort as MidiOutputPortImpl,
7};
8use errors::*;
9
10use crate::{backend, errors, Ignore, InitError};
11
12/// Trait that abstracts over input and output ports.
13pub trait MidiIO {
14    /// Type of an input or output port structure.
15    type Port: Clone;
16
17    /// Get a collection of all MIDI input or output ports.
18    /// The resulting vector contains one object per port, which you can use to
19    /// query metadata about the port or connect to it.
20    fn ports(&self) -> Vec<Self::Port>;
21
22    /// Get the number of available MIDI input or output ports.
23    fn port_count(&self) -> usize;
24
25    /// Get the name of a specified MIDI input or output port.
26    ///
27    /// An error will be returned when the port is no longer valid
28    /// (e.g. the respective device has been disconnected).
29    fn port_name(&self, port: &Self::Port) -> Result<String, PortInfoError>;
30}
31
32/// An object representing a single input port.
33/// How the port is identified internally is backend-dependent.
34/// If the backend allows it, port objects remain valid when
35/// other ports in the system change (i.e. it is not just an index).
36///
37/// Use the `ports` method of a `MidiInput` instance to obtain
38/// available ports.
39#[derive(Clone, PartialEq)]
40pub struct MidiInputPort {
41    pub(crate) imp: MidiInputPortImpl,
42}
43
44impl MidiInputPort {
45    /// Get a unique stable identifier for this port.
46    /// This identifier must be treated as an opaque string.
47    pub fn id(&self) -> String {
48        self.imp.id()
49    }
50}
51
52/// A collection of input ports.
53pub type MidiInputPorts = Vec<MidiInputPort>;
54
55/// An instance of `MidiInput` is required for anything related to MIDI input.
56/// Create one with `MidiInput::new`.
57pub struct MidiInput {
58    //ignore_flags: Ignore
59    imp: MidiInputImpl,
60}
61
62impl MidiInput {
63    /// Creates a new `MidiInput` object that is required for any MIDI input functionality.
64    pub fn new(client_name: &str) -> Result<Self, InitError> {
65        MidiInputImpl::new(client_name).map(|imp| MidiInput { imp })
66    }
67
68    /// Set flags to decide what kind of messages should be ignored (i.e., filtered out)
69    /// by this `MidiInput`. By default, no messages are ignored.
70    pub fn ignore(&mut self, flags: Ignore) {
71        self.imp.ignore(flags);
72    }
73
74    /// Get a collection of all MIDI input ports that *midir* can connect to.
75    /// The resulting vector contains one object per port, which you can use to
76    /// query metadata about the port or connect to it in order to receive
77    /// MIDI messages.
78    pub fn ports(&self) -> MidiInputPorts {
79        self.imp.ports_internal()
80    }
81
82    /// Get the number of available MIDI input ports that *midir* can connect to.
83    pub fn port_count(&self) -> usize {
84        self.imp.port_count()
85    }
86
87    /// Get the name of a specified MIDI input port.
88    ///
89    /// An error will be returned when the port is no longer valid
90    /// (e.g. the respective device has been disconnected).
91    pub fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
92        self.imp.port_name(&port.imp)
93    }
94
95    /// Get a MIDI input port by its unique identifier.
96    pub fn find_port_by_id(&self, id: String) -> Option<MidiInputPort> {
97        self.ports().into_iter().find(|port| port.id() == id)
98    }
99
100    /// Connect to a specified MIDI input port in order to receive messages.
101    /// For each incoming MIDI message, the provided `callback` function will
102    /// be called. The first parameter of the callback function is a timestamp
103    /// (in microseconds) designating the time since some unspecified point in
104    /// the past (which will not change during the lifetime of a
105    /// `MidiInputConnection`). The second parameter contains the actual bytes
106    /// of the MIDI message.
107    ///
108    /// Additional data that should be passed whenever the callback is
109    /// invoked can be specified by `data`. Use the empty tuple `()` if
110    /// you do not want to pass any additional data.
111    ///
112    /// The connection will be kept open as long as the returned
113    /// `MidiInputConnection` is kept alive.
114    ///
115    /// The `port_name` is an additional name that will be assigned to the
116    /// connection. It is only used by some backends.
117    ///
118    /// An error will be returned when the port is no longer valid
119    /// (e.g. the respective device has been disconnected).
120    pub fn connect<F, T: Send>(
121        self,
122        port: &MidiInputPort,
123        port_name: &str,
124        callback: F,
125        data: T,
126    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
127    where
128        F: FnMut(u64, &[u8], &mut T) + Send + 'static,
129    {
130        match self.imp.connect(&port.imp, port_name, callback, data) {
131            Ok(imp) => Ok(MidiInputConnection { imp }),
132            Err(imp) => {
133                let kind = imp.kind();
134                Err(ConnectError::new(
135                    kind,
136                    MidiInput {
137                        imp: imp.into_inner(),
138                    },
139                ))
140            }
141        }
142    }
143}
144
145impl MidiIO for MidiInput {
146    type Port = MidiInputPort;
147
148    fn ports(&self) -> MidiInputPorts {
149        self.imp.ports_internal()
150    }
151
152    fn port_count(&self) -> usize {
153        self.imp.port_count()
154    }
155
156    fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
157        self.imp.port_name(&port.imp)
158    }
159}
160
161#[cfg(unix)]
162impl<T: Send> crate::os::unix::VirtualInput<T> for MidiInput {
163    fn create_virtual<F>(
164        self,
165        port_name: &str,
166        callback: F,
167        data: T,
168    ) -> Result<MidiInputConnection<T>, ConnectError<Self>>
169    where
170        F: FnMut(u64, &[u8], &mut T) + Send + 'static,
171    {
172        match self.imp.create_virtual(port_name, callback, data) {
173            Ok(imp) => Ok(MidiInputConnection { imp }),
174            Err(imp) => {
175                let kind = imp.kind();
176                Err(ConnectError::new(
177                    kind,
178                    MidiInput {
179                        imp: imp.into_inner(),
180                    },
181                ))
182            }
183        }
184    }
185}
186
187/// Represents an open connection to a MIDI input port.
188pub struct MidiInputConnection<T: 'static> {
189    imp: MidiInputConnectionImpl<T>,
190}
191
192impl<T> MidiInputConnection<T> {
193    /// Closes the connection. The returned values allow you to
194    /// inspect the additional data passed to the callback (the `data`
195    /// parameter of `connect`), or to reuse the `MidiInput` object,
196    /// but they can be safely ignored.
197    pub fn close(self) -> (MidiInput, T) {
198        let (imp, data) = self.imp.close();
199        (MidiInput { imp }, data)
200    }
201}
202
203/// An object representing a single output port.
204/// How the port is identified internally is backend-dependent.
205/// If the backend allows it, port objects remain valid when
206/// other ports in the system change (i.e. it is not just an index).
207///
208/// Use the `ports` method of a `MidiOutput` instance to obtain
209/// available ports.
210#[derive(Clone, PartialEq)]
211pub struct MidiOutputPort {
212    pub(crate) imp: MidiOutputPortImpl,
213}
214
215impl MidiOutputPort {
216    /// Get a unique stable identifier for this port.
217    /// This identifier must be treated as an opaque string.
218    pub fn id(&self) -> String {
219        self.imp.id()
220    }
221}
222
223/// A collection of output ports.
224pub type MidiOutputPorts = Vec<MidiOutputPort>;
225
226/// An instance of `MidiOutput` is required for anything related to MIDI output.
227/// Create one with `MidiOutput::new`.
228pub struct MidiOutput {
229    imp: MidiOutputImpl,
230}
231
232impl MidiOutput {
233    /// Creates a new `MidiOutput` object that is required for any MIDI output functionality.
234    pub fn new(client_name: &str) -> Result<Self, InitError> {
235        MidiOutputImpl::new(client_name).map(|imp| MidiOutput { imp })
236    }
237
238    /// Get a collection of all MIDI output ports that *midir* can connect to.
239    /// The resulting vector contains one object per port, which you can use to
240    /// query metadata about the port or connect to it in order to send
241    /// MIDI messages.
242    pub fn ports(&self) -> MidiOutputPorts {
243        self.imp.ports_internal()
244    }
245
246    /// Get the number of available MIDI output ports that *midir* can connect to.
247    pub fn port_count(&self) -> usize {
248        self.imp.port_count()
249    }
250
251    /// Get the name of a specified MIDI output port.
252    ///
253    /// An error will be returned when the port is no longer valid
254    /// (e.g. the respective device has been disconnected).
255    pub fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
256        self.imp.port_name(&port.imp)
257    }
258
259    /// Get a MIDI output port by its unique identifier.
260    pub fn find_port_by_id(&self, id: String) -> Option<MidiOutputPort> {
261        self.ports().into_iter().find(|port| port.id() == id)
262    }
263
264    /// Connect to a specified MIDI output port in order to send messages.
265    /// The connection will be kept open as long as the returned
266    /// `MidiOutputConnection` is kept alive.
267    ///
268    /// The `port_name` is an additional name that will be assigned to the
269    /// connection. It is only used by some backends.
270    ///
271    /// An error will be returned when the port is no longer valid
272    /// (e.g. the respective device has been disconnected).
273    pub fn connect(
274        self,
275        port: &MidiOutputPort,
276        port_name: &str,
277    ) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
278        match self.imp.connect(&port.imp, port_name) {
279            Ok(imp) => Ok(MidiOutputConnection { imp }),
280            Err(imp) => {
281                let kind = imp.kind();
282                Err(ConnectError::new(
283                    kind,
284                    MidiOutput {
285                        imp: imp.into_inner(),
286                    },
287                ))
288            }
289        }
290    }
291}
292
293impl MidiIO for MidiOutput {
294    type Port = MidiOutputPort;
295
296    fn ports(&self) -> MidiOutputPorts {
297        self.imp.ports_internal()
298    }
299
300    fn port_count(&self) -> usize {
301        self.imp.port_count()
302    }
303
304    fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
305        self.imp.port_name(&port.imp)
306    }
307}
308
309#[cfg(unix)]
310impl crate::os::unix::VirtualOutput for MidiOutput {
311    fn create_virtual(
312        self,
313        port_name: &str,
314    ) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
315        match self.imp.create_virtual(port_name) {
316            Ok(imp) => Ok(MidiOutputConnection { imp }),
317            Err(imp) => {
318                let kind = imp.kind();
319                Err(ConnectError::new(
320                    kind,
321                    MidiOutput {
322                        imp: imp.into_inner(),
323                    },
324                ))
325            }
326        }
327    }
328}
329
330/// Represents an open connection to a MIDI output port.
331pub struct MidiOutputConnection {
332    imp: MidiOutputConnectionImpl,
333}
334
335impl MidiOutputConnection {
336    /// Closes the connection. The returned value allows you to
337    /// reuse the `MidiOutput` object, but it can be safely ignored.
338    pub fn close(self) -> MidiOutput {
339        MidiOutput {
340            imp: self.imp.close(),
341        }
342    }
343
344    /// Send a message to the port that this output connection is connected to.
345    /// The message must be a valid MIDI message (see https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message).
346    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
347        self.imp.send(message)
348    }
349}
350
351#[cfg(test)]
352mod tests {
353    use super::*;
354
355    #[test]
356    fn test_trait_impls() {
357        // make sure that all the structs implement `Send`
358        fn is_send<T: Send>() {}
359        is_send::<MidiInput>();
360        is_send::<MidiOutput>();
361        #[cfg(not(target_arch = "wasm32"))]
362        {
363            // The story around threading and `Send` on WASM is not clear yet
364            // Tracking issue:      https://github.com/Boddlnagg/midir/issues/49
365            // Prev. discussion:    https://github.com/Boddlnagg/midir/pull/47
366            is_send::<MidiInputPort>();
367            is_send::<MidiInputConnection<()>>();
368            is_send::<MidiOutputPort>();
369            is_send::<MidiOutputConnection>();
370        }
371
372        // make sure that Midi port structs implement `PartialEq`
373        fn is_partial_eq<T: PartialEq>() {}
374        is_partial_eq::<MidiInputPortImpl>();
375        is_partial_eq::<MidiOutputPortImpl>();
376
377        is_partial_eq::<MidiInputPort>();
378        is_partial_eq::<MidiOutputPort>();
379    }
380}