A Python binding for the RtMidi C++ library providing cross-platform realtime MIDI input/output functionality.
—
Primary interfaces for MIDI input and output operations, providing cross-platform realtime MIDI functionality with support for both hardware and virtual ports.
MIDI input client interface for receiving MIDI messages with support for polling and callback-based message handling.
class MidiIn:
def __init__(self, rtapi=API_UNSPECIFIED, name="RtMidi Client", queue_size_limit=1024):
"""
Create MIDI input instance.
Parameters:
- rtapi: API backend (API_UNSPECIFIED, API_LINUX_ALSA, API_MACOSX_CORE, etc.)
- name: Client name for MIDI system
- queue_size_limit: Internal ring buffer size for incoming MIDI events
Raises:
- SystemError: If RtMidi backend initialization fails
- TypeError: If incompatible parameter type is passed
"""
def get_current_api(self):
"""
Get the low-level MIDI backend API used by this instance.
Returns:
- int: One of the API_* constants
"""
def get_port_count(self):
"""
Get number of available MIDI input ports.
Returns:
- int: Number of available ports
"""
def get_port_name(self, port, encoding='auto'):
"""
Get name of MIDI input port by number.
Parameters:
- port: Port number (0-based)
- encoding: Text encoding ('auto', 'utf-8', 'latin1', 'macroman', or None)
Returns:
- str: Port name (if encoding specified)
- bytes: Port name (if encoding=None)
- None: If port name is empty
"""
def get_ports(self, encoding='auto'):
"""
Get list of available MIDI input port names.
Parameters:
- encoding: Text encoding for port names
Returns:
- list[str]: List of port names with index corresponding to port number
"""
def is_port_open(self):
"""
Check if a port is currently open.
Returns:
- bool: True if port is open (including virtual ports)
"""
def open_port(self, port=0, name=None):
"""
Open MIDI input port by number.
Parameters:
- port: Port number to open (default: 0)
- name: Port name (default: "RtMidi input")
Returns:
- MidiIn: Self for method chaining
Raises:
- InvalidPortError: Invalid port number
- InvalidUseError: Port already open
- TypeError: Incompatible parameter type
"""
def open_virtual_port(self, name=None):
"""
Open virtual MIDI input port.
Parameters:
- name: Virtual port name (default: "RtMidi virtual input")
Returns:
- MidiIn: Self for method chaining
Raises:
- InvalidUseError: Port already open
- UnsupportedOperationError: Virtual ports not supported (Windows MM)
- TypeError: Incompatible parameter type
"""
def close_port(self):
"""
Close opened MIDI input port and cancel any callbacks.
Safe to call repeatedly or when no port is open.
"""
def set_client_name(self, name):
"""
Set MIDI client name (ALSA only).
Parameters:
- name: Client name string
Raises:
- UnsupportedOperationError: API doesn't support client name changes
- TypeError: Incompatible parameter type
"""
def set_port_name(self, name):
"""
Set name of currently opened port (ALSA/JACK only).
Parameters:
- name: Port name string
Raises:
- InvalidUseError: No port currently open
- UnsupportedOperationError: API doesn't support port name changes
- TypeError: Incompatible parameter type
"""
def get_message(self):
"""
Poll for MIDI input message.
Returns:
- tuple[list[int], float]: (message_bytes, delta_time) if message available
- None: If no message available
Note: Non-blocking. Returns immediately if no message available.
"""
def ignore_types(self, sysex=True, timing=True, active_sense=True):
"""
Enable/disable filtering of MIDI event types.
Parameters:
- sysex: Filter System Exclusive messages (default: True)
- timing: Filter MIDI Clock messages (default: True)
- active_sense: Filter Active Sensing messages (default: True)
Note: Set to False to receive these message types.
"""
def set_callback(self, func, data=None):
"""
Register callback function for MIDI input.
Parameters:
- func: Callback function taking (message_tuple, data) arguments
- data: User data passed to callback (can be any Python object)
Note: Callback receives ((message_bytes, delta_time), data) arguments.
Replaces any previously registered callback.
"""
def cancel_callback(self):
"""
Remove registered callback function.
Safe to call when no callback is registered.
"""
def set_error_callback(self, func, data=None):
"""
Register error callback function.
Parameters:
- func: Error callback taking (error_type, error_message, data) arguments
- data: User data passed to callback
Note: Replaces default error handler that raises exceptions.
"""
def cancel_error_callback(self):
"""
Remove error callback and reinstate default error handler.
"""
def delete(self):
"""
Manually destroy C++ instance for immediate cleanup.
Warning: Instance must not be used after calling this method.
"""
@property
def is_deleted(self):
"""Check if C++ instance has been destroyed."""
def __enter__(self):
"""Context manager entry - returns self."""
def __exit__(self, *exc_info):
"""Context manager exit - closes port automatically."""MIDI output client interface for sending MIDI messages to hardware and virtual ports.
class MidiOut:
def __init__(self, rtapi=API_UNSPECIFIED, name="RtMidi Client"):
"""
Create MIDI output instance.
Parameters:
- rtapi: API backend (API_UNSPECIFIED, API_LINUX_ALSA, API_MACOSX_CORE, etc.)
- name: Client name for MIDI system
Raises:
- SystemError: If RtMidi backend initialization fails
- TypeError: If incompatible parameter type is passed
"""
def get_current_api(self):
"""
Get the low-level MIDI backend API used by this instance.
Returns:
- int: One of the API_* constants
"""
def get_port_count(self):
"""
Get number of available MIDI output ports.
Returns:
- int: Number of available ports
"""
def get_port_name(self, port, encoding='auto'):
"""
Get name of MIDI output port by number.
Parameters:
- port: Port number (0-based)
- encoding: Text encoding ('auto', 'utf-8', 'latin1', 'macroman', or None)
Returns:
- str: Port name (if encoding specified)
- bytes: Port name (if encoding=None)
- None: If port name is empty
"""
def get_ports(self, encoding='auto'):
"""
Get list of available MIDI output port names.
Parameters:
- encoding: Text encoding for port names
Returns:
- list[str]: List of port names with index corresponding to port number
"""
def is_port_open(self):
"""
Check if a port is currently open.
Returns:
- bool: True if port is open (including virtual ports)
"""
def open_port(self, port=0, name=None):
"""
Open MIDI output port by number.
Parameters:
- port: Port number to open (default: 0)
- name: Port name (default: "RtMidi output")
Returns:
- MidiOut: Self for method chaining
Raises:
- InvalidPortError: Invalid port number
- InvalidUseError: Port already open
- TypeError: Incompatible parameter type
"""
def open_virtual_port(self, name=None):
"""
Open virtual MIDI output port.
Parameters:
- name: Virtual port name (default: "RtMidi virtual output")
Returns:
- MidiOut: Self for method chaining
Raises:
- InvalidUseError: Port already open
- UnsupportedOperationError: Virtual ports not supported (Windows MM)
- TypeError: Incompatible parameter type
"""
def close_port(self):
"""
Close opened MIDI output port.
Safe to call repeatedly or when no port is open.
"""
def set_client_name(self, name):
"""
Set MIDI client name (ALSA only).
Parameters:
- name: Client name string
Raises:
- UnsupportedOperationError: API doesn't support client name changes
- TypeError: Incompatible parameter type
"""
def set_port_name(self, name):
"""
Set name of currently opened port (ALSA/JACK only).
Parameters:
- name: Port name string
Raises:
- InvalidUseError: No port currently open
- UnsupportedOperationError: API doesn't support port name changes
- TypeError: Incompatible parameter type
"""
def send_message(self, message):
"""
Send MIDI message to output port.
Parameters:
- message: Iterable of integers (0-255) representing MIDI message bytes
Raises:
- ValueError: Empty message or invalid SysEx message format
Notes:
- Normal MIDI messages: 1-3 bytes
- SysEx messages: Must start with 0xF0 if longer than 3 bytes
- With some APIs (Windows MM) this function blocks until message is sent
"""
def set_error_callback(self, func, data=None):
"""
Register error callback function.
Parameters:
- func: Error callback taking (error_type, error_message, data) arguments
- data: User data passed to callback
Note: Replaces default error handler that raises exceptions.
"""
def cancel_error_callback(self):
"""
Remove error callback and reinstate default error handler.
"""
def delete(self):
"""
Manually destroy C++ instance for immediate cleanup.
Warning: Instance must not be used after calling this method.
"""
@property
def is_deleted(self):
"""Check if C++ instance has been destroyed."""
def __enter__(self):
"""Context manager entry - returns self."""
def __exit__(self, *exc_info):
"""Context manager exit - closes port automatically."""import rtmidi
# Create and open MIDI output
midiout = rtmidi.MidiOut()
ports = midiout.get_ports()
if ports:
print("Available output ports:")
for i, port in enumerate(ports):
print(f" {i}: {port}")
midiout.open_port(0)
print(f"Opened: {ports[0]}")
else:
midiout.open_virtual_port("Python Virtual Out")
print("Created virtual output port")
# Send MIDI messages
note_on = [0x90, 60, 100] # Note On, Middle C, velocity 100
note_off = [0x80, 60, 0] # Note Off, Middle C
midiout.send_message(note_on)
time.sleep(1.0)
midiout.send_message(note_off)
# Clean up
midiout.close_port()
del midioutimport rtmidi
import time
def midi_callback(message_data, user_data):
message, delta_time = message_data
print(f"MIDI: {message} (dt: {delta_time:.3f}s)")
# Create and configure MIDI input
midiin = rtmidi.MidiIn()
midiin.ignore_types(sysex=False) # Enable SysEx reception
ports = midiin.get_ports()
if ports:
midiin.open_port(0)
else:
midiin.open_virtual_port("Python Virtual In")
# Set callback and wait for messages
midiin.set_callback(midi_callback)
print("Listening for MIDI messages. Press Enter to exit.")
input()
# Clean up
midiin.cancel_callback()
midiin.close_port()
del midiinimport rtmidi
# Automatic resource cleanup with context manager
with rtmidi.MidiOut() as midiout:
if midiout.get_port_count() > 0:
midiout.open_port(0)
midiout.send_message([0x90, 64, 100]) # Send note
time.sleep(0.5)
midiout.send_message([0x80, 64, 0]) # Stop note
# Port automatically closed when exiting contextInstall with Tessl CLI
npx tessl i tessl/pypi-python-rtmidi