PyObjC CoreMIDI Framework
PyObjC CoreMIDI provides Python bindings for Apple's CoreMIDI framework on macOS, enabling Python applications to interact with MIDI devices and services. It is part of the larger PyObjC bridge, which allows full-featured Cocoa applications to be written in pure Python. The current version is 12.1, with releases typically tied to macOS SDK updates and Python version support changes.
Warnings
- breaking Python 3.9 support was dropped in PyObjC 12.0. Python 3.8 support was dropped in PyObjC 11.0. The current version requires Python >= 3.10.
- gotcha CoreMIDI bindings are a low-level API, and for certain interactions, especially those not based on CoreFoundation or Objective-C types, users may need to perform manual reference counting. Some C functions like `MIDIDeviceCreate`, `MIDISend`, and event list manipulation (`MIDIEventListAdd`, `MIDIEventListInit`) are noted as requiring manual bindings or not being available from Python.
- breaking PyObjC 11.1 aligned the core bridge's behavior with `clang`'s documentation for Automatic Reference Counting (ARC) regarding initializer methods. Methods in the 'init' family now correctly steal a reference to self and return a new reference, which differs from previous PyObjC versions' handling of partially initialized objects.
- gotcha Experimental support for free-threading (PEP 703) introduced in Python 3.13 is included in PyObjC 11, but PyObjC 10.3 explicitly did not support it. While PyObjC 12.1 supports Python 3.10+, if targeting Python 3.13 with free-threading, be aware of the experimental nature of this support.
- gotcha The behavior of `__init__` when a user implements `__new__` in Objective-C bridged classes changed in PyObjC 10.3 (dropping support for `__init__` in such cases) and was partially reintroduced in 10.3.1 due to breaking popular projects.
Install
-
pip install pyobjc-framework-coremidi
Imports
- CoreMIDI
import CoreMIDI
- MIDIObjectGetStringProperty
from CoreMIDI import MIDIObjectGetStringProperty
Quickstart
import CoreMIDI
import objc
def list_midi_devices():
"""Lists all available CoreMIDI devices."""
print("MIDI Devices:")
num_devices = CoreMIDI.MIDIGetNumberOfDevices()
if num_devices == 0:
print(" No MIDI devices found.")
return
for i in range(num_devices):
midi_device_ref = CoreMIDI.MIDIGetDevice(i)
if midi_device_ref:
# MIDIObjectGetStringProperty returns a status code and the string value.
# PyObjC automatically bridges CFStringRef to Python string.
(name_result, name_str) = CoreMIDI.MIDIObjectGetStringProperty(
midi_device_ref, CoreMIDI.kMIDIPropertyName
)
if name_result == 0: # noErr
print(f" Device {i}: {name_str}")
else:
print(f" Device {i}: (Error getting name, code {name_result})")
else:
print(f" Device {i}: (Could not get device reference)")
if __name__ == "__main__":
list_midi_devices()