0
# Core MIDI I/O
1
2
Primary interfaces for MIDI input and output operations, providing cross-platform realtime MIDI functionality with support for both hardware and virtual ports.
3
4
## Capabilities
5
6
### MidiIn Class
7
8
MIDI input client interface for receiving MIDI messages with support for polling and callback-based message handling.
9
10
```python { .api }
11
class MidiIn:
12
def __init__(self, rtapi=API_UNSPECIFIED, name="RtMidi Client", queue_size_limit=1024):
13
"""
14
Create MIDI input instance.
15
16
Parameters:
17
- rtapi: API backend (API_UNSPECIFIED, API_LINUX_ALSA, API_MACOSX_CORE, etc.)
18
- name: Client name for MIDI system
19
- queue_size_limit: Internal ring buffer size for incoming MIDI events
20
21
Raises:
22
- SystemError: If RtMidi backend initialization fails
23
- TypeError: If incompatible parameter type is passed
24
"""
25
26
def get_current_api(self):
27
"""
28
Get the low-level MIDI backend API used by this instance.
29
30
Returns:
31
- int: One of the API_* constants
32
"""
33
34
def get_port_count(self):
35
"""
36
Get number of available MIDI input ports.
37
38
Returns:
39
- int: Number of available ports
40
"""
41
42
def get_port_name(self, port, encoding='auto'):
43
"""
44
Get name of MIDI input port by number.
45
46
Parameters:
47
- port: Port number (0-based)
48
- encoding: Text encoding ('auto', 'utf-8', 'latin1', 'macroman', or None)
49
50
Returns:
51
- str: Port name (if encoding specified)
52
- bytes: Port name (if encoding=None)
53
- None: If port name is empty
54
"""
55
56
def get_ports(self, encoding='auto'):
57
"""
58
Get list of available MIDI input port names.
59
60
Parameters:
61
- encoding: Text encoding for port names
62
63
Returns:
64
- list[str]: List of port names with index corresponding to port number
65
"""
66
67
def is_port_open(self):
68
"""
69
Check if a port is currently open.
70
71
Returns:
72
- bool: True if port is open (including virtual ports)
73
"""
74
75
def open_port(self, port=0, name=None):
76
"""
77
Open MIDI input port by number.
78
79
Parameters:
80
- port: Port number to open (default: 0)
81
- name: Port name (default: "RtMidi input")
82
83
Returns:
84
- MidiIn: Self for method chaining
85
86
Raises:
87
- InvalidPortError: Invalid port number
88
- InvalidUseError: Port already open
89
- TypeError: Incompatible parameter type
90
"""
91
92
def open_virtual_port(self, name=None):
93
"""
94
Open virtual MIDI input port.
95
96
Parameters:
97
- name: Virtual port name (default: "RtMidi virtual input")
98
99
Returns:
100
- MidiIn: Self for method chaining
101
102
Raises:
103
- InvalidUseError: Port already open
104
- UnsupportedOperationError: Virtual ports not supported (Windows MM)
105
- TypeError: Incompatible parameter type
106
"""
107
108
def close_port(self):
109
"""
110
Close opened MIDI input port and cancel any callbacks.
111
Safe to call repeatedly or when no port is open.
112
"""
113
114
def set_client_name(self, name):
115
"""
116
Set MIDI client name (ALSA only).
117
118
Parameters:
119
- name: Client name string
120
121
Raises:
122
- UnsupportedOperationError: API doesn't support client name changes
123
- TypeError: Incompatible parameter type
124
"""
125
126
def set_port_name(self, name):
127
"""
128
Set name of currently opened port (ALSA/JACK only).
129
130
Parameters:
131
- name: Port name string
132
133
Raises:
134
- InvalidUseError: No port currently open
135
- UnsupportedOperationError: API doesn't support port name changes
136
- TypeError: Incompatible parameter type
137
"""
138
139
def get_message(self):
140
"""
141
Poll for MIDI input message.
142
143
Returns:
144
- tuple[list[int], float]: (message_bytes, delta_time) if message available
145
- None: If no message available
146
147
Note: Non-blocking. Returns immediately if no message available.
148
"""
149
150
def ignore_types(self, sysex=True, timing=True, active_sense=True):
151
"""
152
Enable/disable filtering of MIDI event types.
153
154
Parameters:
155
- sysex: Filter System Exclusive messages (default: True)
156
- timing: Filter MIDI Clock messages (default: True)
157
- active_sense: Filter Active Sensing messages (default: True)
158
159
Note: Set to False to receive these message types.
160
"""
161
162
def set_callback(self, func, data=None):
163
"""
164
Register callback function for MIDI input.
165
166
Parameters:
167
- func: Callback function taking (message_tuple, data) arguments
168
- data: User data passed to callback (can be any Python object)
169
170
Note: Callback receives ((message_bytes, delta_time), data) arguments.
171
Replaces any previously registered callback.
172
"""
173
174
def cancel_callback(self):
175
"""
176
Remove registered callback function.
177
Safe to call when no callback is registered.
178
"""
179
180
def set_error_callback(self, func, data=None):
181
"""
182
Register error callback function.
183
184
Parameters:
185
- func: Error callback taking (error_type, error_message, data) arguments
186
- data: User data passed to callback
187
188
Note: Replaces default error handler that raises exceptions.
189
"""
190
191
def cancel_error_callback(self):
192
"""
193
Remove error callback and reinstate default error handler.
194
"""
195
196
def delete(self):
197
"""
198
Manually destroy C++ instance for immediate cleanup.
199
200
Warning: Instance must not be used after calling this method.
201
"""
202
203
@property
204
def is_deleted(self):
205
"""Check if C++ instance has been destroyed."""
206
207
def __enter__(self):
208
"""Context manager entry - returns self."""
209
210
def __exit__(self, *exc_info):
211
"""Context manager exit - closes port automatically."""
212
```
213
214
### MidiOut Class
215
216
MIDI output client interface for sending MIDI messages to hardware and virtual ports.
217
218
```python { .api }
219
class MidiOut:
220
def __init__(self, rtapi=API_UNSPECIFIED, name="RtMidi Client"):
221
"""
222
Create MIDI output instance.
223
224
Parameters:
225
- rtapi: API backend (API_UNSPECIFIED, API_LINUX_ALSA, API_MACOSX_CORE, etc.)
226
- name: Client name for MIDI system
227
228
Raises:
229
- SystemError: If RtMidi backend initialization fails
230
- TypeError: If incompatible parameter type is passed
231
"""
232
233
def get_current_api(self):
234
"""
235
Get the low-level MIDI backend API used by this instance.
236
237
Returns:
238
- int: One of the API_* constants
239
"""
240
241
def get_port_count(self):
242
"""
243
Get number of available MIDI output ports.
244
245
Returns:
246
- int: Number of available ports
247
"""
248
249
def get_port_name(self, port, encoding='auto'):
250
"""
251
Get name of MIDI output port by number.
252
253
Parameters:
254
- port: Port number (0-based)
255
- encoding: Text encoding ('auto', 'utf-8', 'latin1', 'macroman', or None)
256
257
Returns:
258
- str: Port name (if encoding specified)
259
- bytes: Port name (if encoding=None)
260
- None: If port name is empty
261
"""
262
263
def get_ports(self, encoding='auto'):
264
"""
265
Get list of available MIDI output port names.
266
267
Parameters:
268
- encoding: Text encoding for port names
269
270
Returns:
271
- list[str]: List of port names with index corresponding to port number
272
"""
273
274
def is_port_open(self):
275
"""
276
Check if a port is currently open.
277
278
Returns:
279
- bool: True if port is open (including virtual ports)
280
"""
281
282
def open_port(self, port=0, name=None):
283
"""
284
Open MIDI output port by number.
285
286
Parameters:
287
- port: Port number to open (default: 0)
288
- name: Port name (default: "RtMidi output")
289
290
Returns:
291
- MidiOut: Self for method chaining
292
293
Raises:
294
- InvalidPortError: Invalid port number
295
- InvalidUseError: Port already open
296
- TypeError: Incompatible parameter type
297
"""
298
299
def open_virtual_port(self, name=None):
300
"""
301
Open virtual MIDI output port.
302
303
Parameters:
304
- name: Virtual port name (default: "RtMidi virtual output")
305
306
Returns:
307
- MidiOut: Self for method chaining
308
309
Raises:
310
- InvalidUseError: Port already open
311
- UnsupportedOperationError: Virtual ports not supported (Windows MM)
312
- TypeError: Incompatible parameter type
313
"""
314
315
def close_port(self):
316
"""
317
Close opened MIDI output port.
318
Safe to call repeatedly or when no port is open.
319
"""
320
321
def set_client_name(self, name):
322
"""
323
Set MIDI client name (ALSA only).
324
325
Parameters:
326
- name: Client name string
327
328
Raises:
329
- UnsupportedOperationError: API doesn't support client name changes
330
- TypeError: Incompatible parameter type
331
"""
332
333
def set_port_name(self, name):
334
"""
335
Set name of currently opened port (ALSA/JACK only).
336
337
Parameters:
338
- name: Port name string
339
340
Raises:
341
- InvalidUseError: No port currently open
342
- UnsupportedOperationError: API doesn't support port name changes
343
- TypeError: Incompatible parameter type
344
"""
345
346
def send_message(self, message):
347
"""
348
Send MIDI message to output port.
349
350
Parameters:
351
- message: Iterable of integers (0-255) representing MIDI message bytes
352
353
Raises:
354
- ValueError: Empty message or invalid SysEx message format
355
356
Notes:
357
- Normal MIDI messages: 1-3 bytes
358
- SysEx messages: Must start with 0xF0 if longer than 3 bytes
359
- With some APIs (Windows MM) this function blocks until message is sent
360
"""
361
362
def set_error_callback(self, func, data=None):
363
"""
364
Register error callback function.
365
366
Parameters:
367
- func: Error callback taking (error_type, error_message, data) arguments
368
- data: User data passed to callback
369
370
Note: Replaces default error handler that raises exceptions.
371
"""
372
373
def cancel_error_callback(self):
374
"""
375
Remove error callback and reinstate default error handler.
376
"""
377
378
def delete(self):
379
"""
380
Manually destroy C++ instance for immediate cleanup.
381
382
Warning: Instance must not be used after calling this method.
383
"""
384
385
@property
386
def is_deleted(self):
387
"""Check if C++ instance has been destroyed."""
388
389
def __enter__(self):
390
"""Context manager entry - returns self."""
391
392
def __exit__(self, *exc_info):
393
"""Context manager exit - closes port automatically."""
394
```
395
396
## Usage Examples
397
398
### Basic MIDI Output
399
400
```python
401
import rtmidi
402
403
# Create and open MIDI output
404
midiout = rtmidi.MidiOut()
405
ports = midiout.get_ports()
406
407
if ports:
408
print("Available output ports:")
409
for i, port in enumerate(ports):
410
print(f" {i}: {port}")
411
412
midiout.open_port(0)
413
print(f"Opened: {ports[0]}")
414
else:
415
midiout.open_virtual_port("Python Virtual Out")
416
print("Created virtual output port")
417
418
# Send MIDI messages
419
note_on = [0x90, 60, 100] # Note On, Middle C, velocity 100
420
note_off = [0x80, 60, 0] # Note Off, Middle C
421
422
midiout.send_message(note_on)
423
time.sleep(1.0)
424
midiout.send_message(note_off)
425
426
# Clean up
427
midiout.close_port()
428
del midiout
429
```
430
431
### Callback-based MIDI Input
432
433
```python
434
import rtmidi
435
import time
436
437
def midi_callback(message_data, user_data):
438
message, delta_time = message_data
439
print(f"MIDI: {message} (dt: {delta_time:.3f}s)")
440
441
# Create and configure MIDI input
442
midiin = rtmidi.MidiIn()
443
midiin.ignore_types(sysex=False) # Enable SysEx reception
444
445
ports = midiin.get_ports()
446
if ports:
447
midiin.open_port(0)
448
else:
449
midiin.open_virtual_port("Python Virtual In")
450
451
# Set callback and wait for messages
452
midiin.set_callback(midi_callback)
453
print("Listening for MIDI messages. Press Enter to exit.")
454
input()
455
456
# Clean up
457
midiin.cancel_callback()
458
midiin.close_port()
459
del midiin
460
```
461
462
### Context Manager Usage
463
464
```python
465
import rtmidi
466
467
# Automatic resource cleanup with context manager
468
with rtmidi.MidiOut() as midiout:
469
if midiout.get_port_count() > 0:
470
midiout.open_port(0)
471
midiout.send_message([0x90, 64, 100]) # Send note
472
time.sleep(0.5)
473
midiout.send_message([0x80, 64, 0]) # Stop note
474
# Port automatically closed when exiting context
475
```