Skip to content

🎹 MIDI API

linuxpy.midi.device

Human friendly interface to linux MIDI subsystem.

The heart of linuxpy MIDI library is the Sequencer class. Usually you need only one instance of Sequencer for your application. The recommended way is to use it within a context manager like:

with Sequencer("My MIDI App") as midi:
    print(f"MIDI version: {midi.version}")

which is roughly equivalent to:

midi = Sequencer("My MIDI App")
midi.open()
try:
    print(f"MIDI version: {midi.version}")
finally:
    midi.close()

Here's a real world example:

from linuxpy.midi.device import Sequencer

with Sequencer("My MIDI App") as midi:
    print(f"I'm client {midi.client_id}")
    print(f"MIDI version: {midi.version}")
    port = midi.create_port()
    port.connect_from((0, 1))
    for event in midi:
        print(event)

MidiError

Bases: Exception

MIDI error

Sequencer(name: str = 'linuxpy client', **kwargs)

Bases: BaseDevice

Central MIDI class.

from linuxpy.midi.device import Sequencer

with Sequencer("My MIDI App") as midi:
    print(f"I'm client {midi.client_id}")
    print(f"MIDI version: {midi.version}")
    port = midi.create_port()
    port.connect_from((0, 1))
    for event in midi:
        print(event)

client_info: snd_seq_client_info property

Current Client information

client: Client property

Current Client information

running_mode: snd_seq_running_info property

Current running mode

system_info: snd_seq_system_info property

Current system information

iter_clients: Iterable[Client] property

An iterator over all open clients on the system. It returns new Client each time

clients: Sequence[Client] property

Returns a new list of all clients on the system

iter_ports: Iterable[Port] property

An iterator over all open ports on the system. It returns new Port objects each time

ports: Sequence[Port] property

Returns a new list of all open ports on the system. It returns new Port objects each time

__iter__() -> Iterable[Event]

Build an infinite iterator that streams MIDI events from the subscribed ports. You'll need an open sequencer before using it:

from linuxpy.midi.device import Sequencer

with Sequencer() as midi:
    port = midi.create_port()
    port.connect_from((0, 1))
    for event in midi:
        print(event)

__aiter__() -> AsyncIterable[Event] async

Build an infinite async iterator that streams MIDI events from the subscribed ports. You'll need an open sequencer before using it:

import asyncio
from linuxpy.midi.device import Sequencer

async def main():
    with Sequencer() as midi:
        port = midi.create_port()
        port.connect_from((0, 1))
        async for event in midi:
            print(event)

asyncio.run(main())

get_client(client_id: int) -> Client

Returns a Client for the given ID or raises an error if the client doesn't exist. It returns new Client object each time

get_port(address: FullPortAddress) -> Port

Returns a Port for the given address or raises an error if the port doesn't exist. It returns new Port object each time

create_port(name: str = 'linuxpy port', capabilities: PortCapability = INPUT_OUTPUT, port_type: PortType = PortType.MIDI_GENERIC | PortType.APPLICATION) -> Port

Create a new local port. By default it will create a MIDI generic application Input/Output port.

delete_port(port: Union[int, Port])

Delete a previously created local port. If the port has any subscriptions they will be closed before the port is deleted

subscribe(src: FullPortAddress, dest: FullPortAddress)

Subscribe a source port to a destination port

unsubscribe(src: FullPortAddress, dest: FullPortAddress)

Unsubscribe a previously subscribed source port to a destination port

iter_raw_read(max_nb_packets: int = 64) -> Iterable[Event]

Read list of pending events. If the sequencer is opened in blocking mode and there are no events it blocks until at least one event occurs otherwise as OSError is raised.

Use the read() call instead because it handles blocking vs non-blocking variants transperently.

raw_read(max_nb_packets=64) -> Sequence[Event]

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it.

Use the read() call instead because it handles blocking vs non-blocking variants transperently.

wait_read() -> Sequence[Event]

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it. This method assumes the internal file descriptior was opened in non-blocking mode.

Use the read() call instead because it handles blocking vs non-blocking variants transperently

read() -> Sequence[Event]

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it

write(event: Event)

Send an event message

send(port: PortAddress, event_type: Union[str, int, EventType], queue: int = QUEUE_DIRECT, to: Union[FullPortAddress, FullPortAddresses] = SUBSCRIBERS, **kwargs)

Send a message of the given type from a specific port to the destination address(es). Use kwargs to pass specific event arguments like velocity in a "note on" event.

event_type can be an instance of EventType or the equivalent number or a case insensitive string matching the event type (ex: "noteon", "NOTEON", "note-on" or "note on").

The following example sends "note on" with velocity 45 on port 0 of client 14:

midi.send((14, 0), "note on", velocity=45)

Client(sequencer: Sequencer, client: snd_seq_client_info)

MIDI sequencer client. Don't instantiate this object directly Use instead Sequencer.get_client()

name: str property

Client name

is_local: bool property

True if the client was created by the MIDI sequencer that it references or False otherwise"

iter_ports: Iterable[Port] property

An iterator over all open ports for this client. It returns new Port each time

ports: Sequence[Port] property

Returns a new list of all open ports for this client

__int__()

The client ID

Port(sequencer: Sequencer, port: snd_seq_port_info)

MIDI sequencer port. Don't instantiate this object directly Use instead Sequencer.get_port()

name: str property

Port name

is_local: bool property

True if the port was created by the MIDI sequencer that it references or False otherwise"

client_id: int property

The client ID

port_id: int property

The port ID

type: PortType property

The port type

capability: PortCapability property

The port capabilities

address: snd_seq_addr property

The port address

__int__()

The port ID

connect_from(src: FullPortAddress)

Connect this port to a remote port. After connecting, this port will receive events originating from the source port.

Example:

from linuxpy.midi.device import Sequencer

with Sequencer() as midi:
    port = midi.create_port()
    port.connect_from((0, 1))
    for event in midi:
        print(event)

disconnect_from(src: FullPortAddress)

Disconnect this port from a previously connected source port.

connect_to(dest: FullPortAddress)

Connect this port to a remote port. After connecting, events originating from this port will be sent to the destination port.

Example:

from linuxpy.midi.device import Sequencer

with Sequencer() as midi:
    port = midi.create_port()
    # Assume 14:0 is Midi Through
    port.connect_to((14, 0))
    port.send("note on", note=11, velocity=10)

disconnect_to(dest: FullPortAddress)

Disconnect this port from a previously connected destination port.

delete()

Delete this port. Raises MidiError if port is not local. Any subscriptions are canceled before the port is deleted.

send(event_type: Union[str, int, EventType], **kwargs)

Send a message of the given type from to the destination address(es). Use kwargs to pass specific event arguments like velocity in a "note on" event.

event_type can be an instance of EventType or the equivalent number or a case insensitive string matching the event type (ex: "noteon", "NOTEON", "note-on" or "note on").

The following example sends "note on" on note 42, with velocity 45:

port.send("note on", note=42, velocity=45)

Event(event: snd_seq_event)

Event message object result of listening on a sequencer

__bytes__()

Serialize the Event in a bytes ready to be sent

new(etype: EventT, **kwargs) classmethod

Create new Event of the given type

to_address(addr: FullPortAddress) -> snd_seq_addr

Convert to low level snd_seq_addr

event_stream(sequencer: Sequencer) -> Iterable[Event]

Infinite stream of events coming from the given sequencer

async_event_stream(sequencer: Sequencer, maxsize: int = 10) -> AsyncIterable[Event] async

Infinite async stream of events coming from the given sequencer