subsequence.midi_utils¶
MIDI device plumbing — discovering, opening, and registering hardware ports.
Provides interactive/automatic output and input device selection, the
multi-device registry used by the sequencer, and the bank_select()
helper for addressing synth banks beyond the first 128 programs.
Module Contents¶
- class subsequence.midi_utils.MidiDeviceRegistry[source]¶
Ordered registry of named MIDI ports (output or input).
Devices are stored in insertion order. Index 0 is always the first (or only) device — the default for all APIs that do not specify a device. Devices can be looked up by integer index or by name string.
Nonealways resolves to index 0.The registry is intended to be append-only once playback has started. All registered port objects must already be open.
Create an empty registry; populate it with add().
- add(name: str, port: Any, latency_ms: float = 0.0) int[source]¶
Register a port under name. Returns the assigned integer index.
latency_ms is the device’s physical output latency (non-negative); see
set_latency().
- get(device: DeviceId = None) Any | None[source]¶
Return the port for device, or
Noneif the registry is empty.None→ index 0.int→ direct index.str→ name lookup. ReturnsNoneif the device cannot be resolved (empty registry, out-of-range index, unknown name).
- index_of(device: DeviceId = None) int[source]¶
Resolve device to an integer index. Returns 0 for
None. Returns -1 if the name is unknown or the index is out of range.
- latency_of(device: DeviceId = None) float[source]¶
Return the latency (ms) for device, or 0.0 if it cannot be resolved.
Defensive on the hot dispatch path: an unknown device yields 0.0 rather than raising, so a stray event can never crash the send loop.
- max_latency() float[source]¶
Return the largest latency across all registered devices (0.0 if empty).
- replace(index: int, port: Any) None[source]¶
Replace the port object at index without changing the name or index mapping.
Used by the backward-compat
midi_out/midi_insetters to allow test code to inject a fake port after the registry has been populated. RaisesIndexErrorif index is out of range.
- set_latency(device: DeviceId, latency_ms: float) None[source]¶
Set the physical output latency (milliseconds) for device.
latency_ms must be non-negative — a device cannot sound before it is triggered, so a negative output latency is meaningless. Raises
ValueErrorfor a negative value or an unknown device.
- subsequence.midi_utils.bank_select(bank: int) Tuple[int, int][source]¶
Convert a 14-bit MIDI bank number to (MSB, LSB) for use with
p.program_change().MIDI bank select uses two control-change messages: CC 0 (Bank MSB) and CC 32 (Bank LSB). Together they encode a 14-bit bank number in the range 0–16,383:
MSB = bank // 128 (upper 7 bits, sent on CC 0) LSB = bank % 128 (lower 7 bits, sent on CC 32)
- Parameters:
bank – Integer bank number, 0–16,383. Values outside this range are clamped.
- Returns:
(msb, lsb)tuple, each value in 0–127.
Example
msb, lsb = subsequence.bank_select(128) # → (1, 0) p.program_change(48, bank_msb=msb, bank_lsb=lsb)
- subsequence.midi_utils.select_input_device(device_name: str | None = None, callback: Callable | None = None) Tuple[str | None, Any | None][source]¶
Select and open a MIDI input device.
If
device_nameis provided, attempts to open exactly that device. Ifdevice_nameis None, returns None without prompting (input is optional/advanced). To enforce input, the caller should check the return value.A named device that is not present raises ValueError rather than falling back to another input: MIDI input drives clock-follow and live note capture, so silently listening to the wrong device would desynchronise or mis-record a performance.
- Returns:
A tuple of (device_name, midi_in_object), or (None, None) when no name was given or the device failed to open.
- Raises:
ValueError – If device_name is not among the available inputs.
- subsequence.midi_utils.select_output_device(device_name: str | None = None) Tuple[str | None, Any | None][source]¶
Select and open a MIDI output device.
If
device_nameis provided, attempts to open that specific device. Ifdevice_nameis None, auto-discovers available devices:If exactly one device exists, it is selected automatically.
If multiple devices exist, prompts the user to choose one from the console.
If no devices exist, logs an error and returns None.
- Returns:
A tuple of (device_name, midi_out_object) or (None, None) on failure.