midir/backend/winmm/
mod.rs

1use parking_lot::ReentrantMutex as Mutex;
2use std::alloc::{alloc, dealloc, Layout};
3use std::ffi::OsString;
4use std::io::{stderr, Write};
5use std::mem::MaybeUninit;
6use std::os::windows::ffi::OsStringExt;
7use std::ptr::null_mut;
8use std::thread::sleep;
9use std::time::Duration;
10use std::{mem, ptr, slice};
11
12use windows::core::PSTR;
13use windows::Win32::Media::Audio::{
14    midiInAddBuffer, midiInClose, midiInGetDevCapsW, midiInGetNumDevs, midiInMessage, midiInOpen,
15    midiInPrepareHeader, midiInReset, midiInStart, midiInStop, midiInUnprepareHeader, midiOutClose,
16    midiOutGetDevCapsW, midiOutGetNumDevs, midiOutLongMsg, midiOutMessage, midiOutOpen,
17    midiOutPrepareHeader, midiOutReset, midiOutShortMsg, midiOutUnprepareHeader, CALLBACK_FUNCTION,
18    CALLBACK_NULL, HMIDIIN, HMIDIOUT, MIDIERR_NOTREADY, MIDIERR_STILLPLAYING, MIDIHDR, MIDIINCAPSW,
19    MIDIOUTCAPSW,
20};
21use windows::Win32::Media::Multimedia::{DRV_QUERYDEVICEINTERFACE, DRV_QUERYDEVICEINTERFACESIZE};
22use windows::Win32::Media::{MMSYSERR_ALLOCATED, MMSYSERR_BADDEVICEID, MMSYSERR_NOERROR};
23
24#[allow(non_camel_case_types)]
25#[allow(clippy::upper_case_acronyms)]
26type ULONG = u32;
27#[allow(non_camel_case_types)]
28#[allow(clippy::upper_case_acronyms)]
29type UINT = u32;
30#[allow(non_camel_case_types)]
31#[allow(clippy::upper_case_acronyms)]
32type DWORD = u32;
33#[allow(non_camel_case_types)]
34#[allow(clippy::upper_case_acronyms)]
35type DWORD_PTR = usize;
36
37use crate::errors::*;
38use crate::{Ignore, MidiMessage};
39
40mod handler;
41
42const MIDIR_SYSEX_BUFFER_SIZE: usize = 1024;
43const MIDIR_SYSEX_BUFFER_COUNT: usize = 4;
44
45// helper for string conversion
46fn from_wide_ptr(ptr: *const u16, max_len: usize) -> OsString {
47    unsafe {
48        assert!(!ptr.is_null());
49        let len = (0..max_len as isize)
50            .position(|i| *ptr.offset(i) == 0)
51            .unwrap();
52        let slice = slice::from_raw_parts(ptr, len);
53        OsString::from_wide(slice)
54    }
55}
56
57#[derive(Debug)]
58pub struct MidiInput {
59    ignore_flags: Ignore,
60}
61
62#[derive(Clone)]
63pub struct MidiInputPort {
64    name: String,
65    interface_id: Box<[u16]>,
66}
67
68impl MidiInputPort {
69    pub fn id(&self) -> String {
70        String::from_utf16_lossy(&self.interface_id)
71    }
72}
73
74impl PartialEq for MidiInputPort {
75    fn eq(&self, other: &Self) -> bool {
76        self.interface_id == other.interface_id
77    }
78}
79
80pub struct MidiInputConnection<T> {
81    handler_data: Box<HandlerData<T>>,
82}
83
84impl MidiInputPort {
85    fn count() -> UINT {
86        unsafe { midiInGetNumDevs() }
87    }
88
89    fn interface_id(port_number: UINT) -> Result<Box<[u16]>, PortInfoError> {
90        let mut buffer_size: ULONG = 0;
91        let result = unsafe {
92            midiInMessage(
93                HMIDIIN(port_number as isize),
94                DRV_QUERYDEVICEINTERFACESIZE,
95                &mut buffer_size as *mut _ as DWORD_PTR,
96                0,
97            )
98        };
99        if result == MMSYSERR_BADDEVICEID {
100            return Err(PortInfoError::PortNumberOutOfRange);
101        } else if result != MMSYSERR_NOERROR {
102            return Err(PortInfoError::CannotRetrievePortName);
103        }
104        let mut buffer = Vec::<u16>::with_capacity(buffer_size as usize / 2);
105        unsafe {
106            let result = midiInMessage(
107                HMIDIIN(port_number as isize),
108                DRV_QUERYDEVICEINTERFACE,
109                buffer.as_mut_ptr() as usize,
110                buffer_size as DWORD_PTR,
111            );
112            if result == MMSYSERR_BADDEVICEID {
113                return Err(PortInfoError::PortNumberOutOfRange);
114            } else if result != MMSYSERR_NOERROR {
115                return Err(PortInfoError::CannotRetrievePortName);
116            }
117            buffer.set_len(buffer_size as usize / 2);
118        }
119        //println!("{}", from_wide_ptr(buffer.as_ptr(), buffer.len()).to_string_lossy().into_owned());
120        Ok(buffer.into_boxed_slice())
121    }
122
123    fn name(port_number: UINT) -> Result<String, PortInfoError> {
124        let mut device_caps: MaybeUninit<MIDIINCAPSW> = MaybeUninit::uninit();
125        let result = unsafe {
126            midiInGetDevCapsW(
127                port_number as usize,
128                device_caps.as_mut_ptr(),
129                mem::size_of::<MIDIINCAPSW>() as u32,
130            )
131        };
132        if result == MMSYSERR_BADDEVICEID {
133            return Err(PortInfoError::PortNumberOutOfRange);
134        } else if result != MMSYSERR_NOERROR {
135            return Err(PortInfoError::CannotRetrievePortName);
136        }
137        let device_caps = unsafe { device_caps.assume_init() };
138        let pname_ptr: *const [u16; 32] = std::ptr::addr_of!(device_caps.szPname);
139        let output = from_wide_ptr(pname_ptr as *const _, 32)
140            .to_string_lossy()
141            .into_owned();
142        Ok(output)
143    }
144
145    fn from_port_number(port_number: UINT) -> Result<Self, PortInfoError> {
146        Ok(MidiInputPort {
147            name: Self::name(port_number)?,
148            interface_id: Self::interface_id(port_number)?,
149        })
150    }
151
152    fn current_port_number(&self) -> Option<UINT> {
153        for i in 0..Self::count() {
154            if let Ok(name) = Self::name(i) {
155                if name != self.name {
156                    continue;
157                }
158                if let Ok(id) = Self::interface_id(i) {
159                    if id == self.interface_id {
160                        return Some(i);
161                    }
162                }
163            }
164        }
165        None
166    }
167}
168
169struct SysexBuffer([*mut MIDIHDR; MIDIR_SYSEX_BUFFER_COUNT]);
170unsafe impl Send for SysexBuffer {}
171
172struct MidiInHandle(Mutex<HMIDIIN>);
173unsafe impl Send for MidiInHandle {}
174
175/// This is all the data that is stored on the heap as long as a connection
176/// is opened and passed to the callback handler.
177///
178/// It is important that `user_data` is the last field to not influence
179/// offsets after monomorphization.
180struct HandlerData<T> {
181    message: MidiMessage,
182    sysex_buffer: SysexBuffer,
183    in_handle: Option<MidiInHandle>,
184    ignore_flags: Ignore,
185    callback: Box<dyn FnMut(u64, &[u8], &mut T) + Send + 'static>,
186    user_data: Option<T>,
187}
188
189impl MidiInput {
190    pub fn new(_client_name: &str) -> Result<Self, InitError> {
191        Ok(MidiInput {
192            ignore_flags: Ignore::None,
193        })
194    }
195
196    pub fn ignore(&mut self, flags: Ignore) {
197        self.ignore_flags = flags;
198    }
199
200    pub(crate) fn ports_internal(&self) -> Vec<crate::common::MidiInputPort> {
201        let count = MidiInputPort::count();
202        let mut result = Vec::with_capacity(count as usize);
203        for i in 0..count {
204            let port = match MidiInputPort::from_port_number(i) {
205                Ok(p) => p,
206                Err(_) => continue,
207            };
208            result.push(crate::common::MidiInputPort { imp: port });
209        }
210        result
211    }
212
213    pub fn port_count(&self) -> usize {
214        MidiInputPort::count() as usize
215    }
216
217    pub fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
218        Ok(port.name.clone())
219    }
220
221    pub fn connect<F, T: Send>(
222        self,
223        port: &MidiInputPort,
224        _port_name: &str,
225        callback: F,
226        data: T,
227    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
228    where
229        F: FnMut(u64, &[u8], &mut T) + Send + 'static,
230    {
231        let port_number = match port.current_port_number() {
232            Some(p) => p,
233            None => return Err(ConnectError::new(ConnectErrorKind::InvalidPort, self)),
234        };
235
236        let mut handler_data = Box::new(HandlerData {
237            message: MidiMessage::new(),
238            sysex_buffer: SysexBuffer([null_mut(); MIDIR_SYSEX_BUFFER_COUNT]),
239            in_handle: None,
240            ignore_flags: self.ignore_flags,
241            callback: Box::new(callback),
242            user_data: Some(data),
243        });
244
245        let mut in_handle: MaybeUninit<HMIDIIN> = MaybeUninit::uninit();
246        let handler_data_ptr: *mut HandlerData<T> = &mut *handler_data;
247        let result = unsafe {
248            midiInOpen(
249                in_handle.as_mut_ptr(),
250                port_number as UINT,
251                handler::handle_input::<T> as DWORD_PTR,
252                handler_data_ptr as DWORD_PTR,
253                CALLBACK_FUNCTION,
254            )
255        };
256        if result == MMSYSERR_ALLOCATED {
257            return Err(ConnectError::other(
258                "could not create Windows MM MIDI input port (MMSYSERR_ALLOCATED)",
259                self,
260            ));
261        } else if result != MMSYSERR_NOERROR {
262            return Err(ConnectError::other(
263                "could not create Windows MM MIDI input port",
264                self,
265            ));
266        }
267        let in_handle = unsafe { in_handle.assume_init() };
268
269        // Allocate and init the sysex buffers.
270        for i in 0..MIDIR_SYSEX_BUFFER_COUNT {
271            handler_data.sysex_buffer.0[i] = Box::into_raw(Box::new(MIDIHDR {
272                lpData: PSTR(unsafe {
273                    alloc(Layout::from_size_align_unchecked(
274                        MIDIR_SYSEX_BUFFER_SIZE,
275                        1,
276                    ))
277                }),
278                dwBufferLength: MIDIR_SYSEX_BUFFER_SIZE as u32,
279                dwBytesRecorded: 0,
280                dwUser: i as DWORD_PTR, // We use the dwUser parameter as buffer indicator
281                dwFlags: 0,
282                lpNext: ptr::null_mut(),
283                reserved: 0,
284                dwOffset: 0,
285                dwReserved: unsafe { mem::zeroed() },
286            }));
287
288            // TODO: are those buffers ever freed if an error occurs here (altough these calls probably only fail with out-of-memory)?
289            // TODO: close port in case of error?
290
291            let result = unsafe {
292                midiInPrepareHeader(
293                    in_handle,
294                    handler_data.sysex_buffer.0[i],
295                    mem::size_of::<MIDIHDR>() as u32,
296                )
297            };
298            if result != MMSYSERR_NOERROR {
299                return Err(ConnectError::other(
300                    "could not initialize Windows MM MIDI input port (PrepareHeader)",
301                    self,
302                ));
303            }
304
305            // Register the buffer.
306            let result = unsafe {
307                midiInAddBuffer(
308                    in_handle,
309                    handler_data.sysex_buffer.0[i],
310                    mem::size_of::<MIDIHDR>() as u32,
311                )
312            };
313            if result != MMSYSERR_NOERROR {
314                return Err(ConnectError::other(
315                    "could not initialize Windows MM MIDI input port (AddBuffer)",
316                    self,
317                ));
318            }
319        }
320
321        handler_data.in_handle = Some(MidiInHandle(Mutex::new(in_handle)));
322
323        // We can safely access (a copy of) `in_handle` here, although
324        // it has been copied into the Mutex already, because the callback
325        // has not been called yet.
326        let result = unsafe { midiInStart(in_handle) };
327        if result != MMSYSERR_NOERROR {
328            unsafe { midiInClose(in_handle) };
329            return Err(ConnectError::other(
330                "could not start Windows MM MIDI input port",
331                self,
332            ));
333        }
334
335        Ok(MidiInputConnection { handler_data })
336    }
337}
338
339impl<T> MidiInputConnection<T> {
340    pub fn close(mut self) -> (MidiInput, T) {
341        self.close_internal();
342
343        (
344            MidiInput {
345                ignore_flags: self.handler_data.ignore_flags,
346            },
347            self.handler_data.user_data.take().unwrap(),
348        )
349    }
350
351    fn close_internal(&mut self) {
352        // for information about this lock, see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
353        let in_handle_lock = self.handler_data.in_handle.as_ref().unwrap().0.lock();
354
355        // TODO: Call both reset and stop here? The difference seems to be that
356        //       reset "returns all pending input buffers to the callback function"
357        unsafe {
358            midiInReset(*in_handle_lock);
359            midiInStop(*in_handle_lock);
360        }
361
362        for i in 0..MIDIR_SYSEX_BUFFER_COUNT {
363            let result;
364            unsafe {
365                result = midiInUnprepareHeader(
366                    *in_handle_lock,
367                    self.handler_data.sysex_buffer.0[i],
368                    mem::size_of::<MIDIHDR>() as u32,
369                );
370                dealloc(
371                    (*self.handler_data.sysex_buffer.0[i]).lpData.0 as *mut _,
372                    Layout::from_size_align_unchecked(MIDIR_SYSEX_BUFFER_SIZE, 1),
373                );
374                // recreate the Box so that it will be dropped/deallocated at the end of this scope
375                let _ = Box::from_raw(self.handler_data.sysex_buffer.0[i]);
376            }
377
378            if result != MMSYSERR_NOERROR {
379                let _ = writeln!(stderr(), "Warning: Ignoring error shutting down Windows MM input port (UnprepareHeader).");
380            }
381        }
382
383        unsafe { midiInClose(*in_handle_lock) };
384    }
385}
386
387impl<T> Drop for MidiInputConnection<T> {
388    fn drop(&mut self) {
389        // If user_data has been emptied, we know that we already have closed the connection
390        if self.handler_data.user_data.is_some() {
391            self.close_internal()
392        }
393    }
394}
395
396#[derive(Debug)]
397pub struct MidiOutput;
398
399#[derive(Clone)]
400pub struct MidiOutputPort {
401    name: String,
402    interface_id: Box<[u16]>,
403}
404
405impl MidiOutputPort {
406    pub fn id(&self) -> String {
407        String::from_utf16_lossy(&self.interface_id)
408    }
409}
410
411impl PartialEq for MidiOutputPort {
412    fn eq(&self, other: &Self) -> bool {
413        self.interface_id == other.interface_id
414    }
415}
416
417pub struct MidiOutputConnection {
418    out_handle: HMIDIOUT,
419}
420
421unsafe impl Send for MidiOutputConnection {}
422
423impl MidiOutputPort {
424    fn count() -> UINT {
425        unsafe { midiOutGetNumDevs() }
426    }
427
428    fn interface_id(port_number: UINT) -> Result<Box<[u16]>, PortInfoError> {
429        let mut buffer_size: ULONG = 0;
430        let result = unsafe {
431            midiOutMessage(
432                HMIDIOUT(port_number as isize),
433                DRV_QUERYDEVICEINTERFACESIZE,
434                &mut buffer_size as *mut _ as DWORD_PTR,
435                0,
436            )
437        };
438        if result == MMSYSERR_BADDEVICEID {
439            return Err(PortInfoError::PortNumberOutOfRange);
440        } else if result != MMSYSERR_NOERROR {
441            return Err(PortInfoError::CannotRetrievePortName);
442        }
443        let mut buffer = Vec::<u16>::with_capacity(buffer_size as usize / 2);
444        unsafe {
445            let result = midiOutMessage(
446                HMIDIOUT(port_number as isize),
447                DRV_QUERYDEVICEINTERFACE,
448                buffer.as_mut_ptr() as DWORD_PTR,
449                buffer_size as DWORD_PTR,
450            );
451            if result == MMSYSERR_BADDEVICEID {
452                return Err(PortInfoError::PortNumberOutOfRange);
453            } else if result != MMSYSERR_NOERROR {
454                return Err(PortInfoError::CannotRetrievePortName);
455            }
456            buffer.set_len(buffer_size as usize / 2);
457        }
458        //println!("{}", from_wide_ptr(buffer.as_ptr(), buffer.len()).to_string_lossy().into_owned());
459        Ok(buffer.into_boxed_slice())
460    }
461
462    fn name(port_number: UINT) -> Result<String, PortInfoError> {
463        let mut device_caps: MaybeUninit<MIDIOUTCAPSW> = MaybeUninit::uninit();
464        let result = unsafe {
465            midiOutGetDevCapsW(
466                port_number as usize,
467                device_caps.as_mut_ptr(),
468                mem::size_of::<MIDIOUTCAPSW>() as u32,
469            )
470        };
471        if result == MMSYSERR_BADDEVICEID {
472            return Err(PortInfoError::PortNumberOutOfRange);
473        } else if result != MMSYSERR_NOERROR {
474            return Err(PortInfoError::CannotRetrievePortName);
475        }
476        let device_caps = unsafe { device_caps.assume_init() };
477        let pname_ptr: *const [u16; 32] = std::ptr::addr_of!(device_caps.szPname);
478        let output = from_wide_ptr(pname_ptr as *const _, 32)
479            .to_string_lossy()
480            .into_owned();
481        Ok(output)
482    }
483
484    fn from_port_number(port_number: UINT) -> Result<Self, PortInfoError> {
485        Ok(MidiOutputPort {
486            name: Self::name(port_number)?,
487            interface_id: Self::interface_id(port_number)?,
488        })
489    }
490
491    fn current_port_number(&self) -> Option<UINT> {
492        for i in 0..Self::count() {
493            if let Ok(name) = Self::name(i) {
494                if name != self.name {
495                    continue;
496                }
497                if let Ok(id) = Self::interface_id(i) {
498                    if id == self.interface_id {
499                        return Some(i);
500                    }
501                }
502            }
503        }
504        None
505    }
506}
507
508impl MidiOutput {
509    pub fn new(_client_name: &str) -> Result<Self, InitError> {
510        Ok(MidiOutput)
511    }
512
513    pub(crate) fn ports_internal(&self) -> Vec<crate::common::MidiOutputPort> {
514        let count = MidiOutputPort::count();
515        let mut result = Vec::with_capacity(count as usize);
516        for i in 0..count {
517            let port = match MidiOutputPort::from_port_number(i) {
518                Ok(p) => p,
519                Err(_) => continue,
520            };
521            result.push(crate::common::MidiOutputPort { imp: port });
522        }
523        result
524    }
525
526    pub fn port_count(&self) -> usize {
527        MidiOutputPort::count() as usize
528    }
529
530    pub fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
531        Ok(port.name.clone())
532    }
533
534    pub fn connect(
535        self,
536        port: &MidiOutputPort,
537        _port_name: &str,
538    ) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
539        let port_number = match port.current_port_number() {
540            Some(p) => p,
541            None => return Err(ConnectError::new(ConnectErrorKind::InvalidPort, self)),
542        };
543        let mut out_handle: MaybeUninit<HMIDIOUT> = MaybeUninit::uninit();
544        let result = unsafe {
545            midiOutOpen(
546                out_handle.as_mut_ptr(),
547                port_number as UINT,
548                0,
549                0,
550                CALLBACK_NULL,
551            )
552        };
553        if result == MMSYSERR_ALLOCATED {
554            return Err(ConnectError::other(
555                "could not create Windows MM MIDI output port (MMSYSERR_ALLOCATED)",
556                self,
557            ));
558        } else if result != MMSYSERR_NOERROR {
559            return Err(ConnectError::other(
560                "could not create Windows MM MIDI output port",
561                self,
562            ));
563        }
564        Ok(MidiOutputConnection {
565            out_handle: unsafe { out_handle.assume_init() },
566        })
567    }
568}
569
570impl MidiOutputConnection {
571    pub fn close(self) -> MidiOutput {
572        // The actual closing is done by the implementation of Drop
573        MidiOutput // In this API this is a noop
574    }
575
576    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
577        let nbytes = message.len();
578        if nbytes == 0 {
579            return Err(SendError::InvalidData(
580                "message to be sent must not be empty",
581            ));
582        }
583
584        if message[0] == 0xF0 {
585            // Sysex message
586            // Allocate buffer for sysex data and copy message
587            let mut buffer = message.to_vec();
588
589            // Create and prepare MIDIHDR structure.
590            let mut sysex = MIDIHDR {
591                lpData: PSTR(buffer.as_mut_ptr()),
592                dwBufferLength: nbytes as u32,
593                dwBytesRecorded: 0,
594                dwUser: 0,
595                dwFlags: 0,
596                lpNext: ptr::null_mut(),
597                reserved: 0,
598                dwOffset: 0,
599                dwReserved: unsafe { mem::zeroed() },
600            };
601
602            let result = unsafe {
603                midiOutPrepareHeader(
604                    self.out_handle,
605                    &mut sysex,
606                    mem::size_of::<MIDIHDR>() as u32,
607                )
608            };
609
610            if result != MMSYSERR_NOERROR {
611                return Err(SendError::Other(
612                    "preparation for sending sysex message failed (OutPrepareHeader)",
613                ));
614            }
615
616            // Send the message.
617            loop {
618                let result = unsafe {
619                    midiOutLongMsg(self.out_handle, &sysex, mem::size_of::<MIDIHDR>() as u32)
620                };
621                if result == MIDIERR_NOTREADY {
622                    sleep(Duration::from_millis(1));
623                    continue;
624                } else {
625                    if result != MMSYSERR_NOERROR {
626                        return Err(SendError::Other("sending sysex message failed"));
627                    }
628                    break;
629                }
630            }
631
632            loop {
633                let result = unsafe {
634                    midiOutUnprepareHeader(
635                        self.out_handle,
636                        &mut sysex,
637                        mem::size_of::<MIDIHDR>() as u32,
638                    )
639                };
640                if result == MIDIERR_STILLPLAYING {
641                    sleep(Duration::from_millis(1));
642                    continue;
643                } else {
644                    break;
645                }
646            }
647        } else {
648            // Channel or system message.
649            // Make sure the message size isn't too big.
650            if nbytes > 3 {
651                return Err(SendError::InvalidData(
652                    "non-sysex message must not be longer than 3 bytes",
653                ));
654            }
655
656            // Pack MIDI bytes into double word.
657            let mut packet: u32 = 0;
658            let ptr = std::ptr::addr_of_mut!(packet).cast::<u8>();
659            for (i, item) in message.iter().enumerate().take(nbytes) {
660                unsafe { *ptr.add(i) = *item };
661            }
662
663            // Send the message immediately.
664            loop {
665                let result = unsafe { midiOutShortMsg(self.out_handle, packet) };
666                if result == MIDIERR_NOTREADY {
667                    sleep(Duration::from_millis(1));
668                    continue;
669                } else {
670                    if result != MMSYSERR_NOERROR {
671                        return Err(SendError::Other("sending non-sysex message failed"));
672                    }
673                    break;
674                }
675            }
676        }
677
678        Ok(())
679    }
680}
681
682impl Drop for MidiOutputConnection {
683    fn drop(&mut self) {
684        unsafe {
685            midiOutReset(self.out_handle);
686            midiOutClose(self.out_handle);
687        }
688    }
689}