1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
# SPDX-FileCopyrightText: 2013 Ole Martin Bjorndalen <ombdalen@gmail.com>
#
# SPDX-License-Identifier: MIT
"""
Experimental backend for rtmidi-python:
http://github.com/superquadratic/rtmidi-python
- Doesn't work with Python 3.3:
File "rtmidi_python.pyx", line 61, in rtmidi_python.MidiIn.__cinit__
(rtmidi_ python.cpp:1214)
TypeError: expected bytes, str found
- Virtual ports don't show up, so other programs can't connect to them.
- There is no way to select API.
Other than that, it works exactly like the included python-rtmidi
backend.
"""
import rtmidi_python as rtmidi
from mido.ports import BaseInput, BaseOutput
def get_devices():
devices = []
input_names = set(rtmidi.MidiIn().ports)
output_names = set(rtmidi.MidiOut().ports)
for name in sorted(input_names | output_names):
devices.append({
'name': name,
'is_input': name in input_names,
'is_output': name in output_names,
})
return devices
class PortCommon:
def _open(self, virtual=False, callback=None):
opening_input = hasattr(self, 'receive')
if opening_input:
self._rt = rtmidi.MidiIn()
self._rt.ignore_types(False, False, False)
if callback:
def callback_wrapper(message, delta_time):
self._parser.feed(message)
for message in self._parser:
callback(message)
self._rt.callback = self._callback = callback_wrapper
self._has_callback = True
else:
self._has_callback = False
else:
self._rt = rtmidi.MidiOut()
# Turn of ignore of sysex, time and active_sensing.
ports = self._rt.ports
if virtual:
if self.name is None:
raise OSError('virtual port must have a name')
self._rt.open_virtual_port(self.name)
else:
if self.name is None:
# Todo: this could fail if list is empty.
# In RtMidi, the default port is the first port.
try:
self.name = ports[0]
except IndexError as ie:
raise OSError('no ports available') from ie
try:
port_id = ports.index(self.name)
except ValueError as ve:
raise OSError(f'unknown port {self.name!r}') from ve
self._rt.open_port(port_id)
self._device_type = 'rtmidi_python'
def _close(self):
self._rt.close_port()
class Input(PortCommon, BaseInput):
# Todo: sysex messages do not arrive here.
def _receive(self, block=True):
if self._has_callback:
raise OSError('a callback is currently set for this port')
while True:
(message, delta_time) = self._rt.get_message()
if message is None:
break
else:
self._parser.feed(message)
class Output(PortCommon, BaseOutput):
def _send(self, message):
self._rt.send_message(message.bytes())
|