Skip to content

MIDI Interface API Reference

Auto-generated API documentation for the MIDI interface.

MIDIInterface

MIDIInterface(port_name='FLStudio_MIDI')

Interface for MIDI communication using mido library.

Initialize MIDI interface.

Parameters:

Name Type Description Default
port_name str

Name of the MIDI port to connect to

'FLStudio_MIDI'
Source code in src/fruityloops_mcp/midi_interface.py
def __init__(self, port_name: str = "FLStudio_MIDI"):
    """Initialize MIDI interface.

    Args:
        port_name: Name of the MIDI port to connect to
    """
    self.port_name = port_name
    self._output_port: mido.ports.BaseOutput | None = None
    self._input_port: mido.ports.BaseInput | None = None
    self._is_connected = False

is_connected property

Check if MIDI ports are connected.

connect()

Connect to MIDI ports.

Returns:

Type Description
bool

True if connection successful, False otherwise

Source code in src/fruityloops_mcp/midi_interface.py
def connect(self) -> bool:
    """Connect to MIDI ports.

    Returns:
        True if connection successful, False otherwise
    """
    if self._is_connected:
        return True

    try:
        # Check if port exists in available ports
        output_ports = mido.get_output_names()
        input_ports = mido.get_input_names()

        if self.port_name not in output_ports:
            logger.warning(
                f"Output port '{self.port_name}' not found. Available: {output_ports}"
            )
            return False

        if self.port_name not in input_ports:
            logger.warning(f"Input port '{self.port_name}' not found. Available: {input_ports}")
            return False

        # Open ports
        self._output_port = mido.open_output(self.port_name)
        self._input_port = mido.open_input(self.port_name)
        self._is_connected = True
        logger.info(f"Connected to MIDI port: {self.port_name}")
        return True

    except Exception as e:
        logger.error(f"Failed to connect to MIDI port: {e}")
        return False

disconnect()

Disconnect from MIDI ports.

Source code in src/fruityloops_mcp/midi_interface.py
def disconnect(self) -> None:
    """Disconnect from MIDI ports."""
    if not self._is_connected:
        return

    try:
        if self._output_port:
            self._output_port.close()
            self._output_port = None

        if self._input_port:
            self._input_port.close()
            self._input_port = None

        self._is_connected = False
        logger.info(f"Disconnected from MIDI port: {self.port_name}")

    except Exception as e:
        logger.error(f"Error disconnecting from MIDI port: {e}")

send_note_on(note, velocity=64, channel=0)

Send MIDI note on message.

Parameters:

Name Type Description Default
note int

MIDI note number (0-127)

required
velocity int

Note velocity (0-127)

64
channel int

MIDI channel (0-15)

0

Returns:

Type Description
bool

True if message sent successfully, False otherwise

Source code in src/fruityloops_mcp/midi_interface.py
def send_note_on(self, note: int, velocity: int = 64, channel: int = 0) -> bool:
    """Send MIDI note on message.

    Args:
        note: MIDI note number (0-127)
        velocity: Note velocity (0-127)
        channel: MIDI channel (0-15)

    Returns:
        True if message sent successfully, False otherwise
    """
    if not self._is_connected or not self._output_port:
        logger.warning("Cannot send note_on: MIDI not connected")
        return False

    try:
        msg = mido.Message("note_on", note=note, velocity=velocity, channel=channel)
        self._output_port.send(msg)
        return True
    except mido.ports.PortNotOpenError:
        self._is_connected = False
        logger.error("MIDI port is not open")
        return False
    except Exception as e:
        logger.error(f"Error sending note_on: {e}")
        return False

send_note_off(note, velocity=64, channel=0)

Send MIDI note off message.

Parameters:

Name Type Description Default
note int

MIDI note number (0-127)

required
velocity int

Note velocity (0-127)

64
channel int

MIDI channel (0-15)

0

Returns:

Type Description
bool

True if message sent successfully, False otherwise

Source code in src/fruityloops_mcp/midi_interface.py
def send_note_off(self, note: int, velocity: int = 64, channel: int = 0) -> bool:
    """Send MIDI note off message.

    Args:
        note: MIDI note number (0-127)
        velocity: Note velocity (0-127)
        channel: MIDI channel (0-15)

    Returns:
        True if message sent successfully, False otherwise
    """
    if not self._is_connected or not self._output_port:
        logger.warning("Cannot send note_off: MIDI not connected")
        return False

    try:
        msg = mido.Message("note_off", note=note, velocity=velocity, channel=channel)
        self._output_port.send(msg)
        return True
    except mido.ports.PortNotOpenError:
        self._is_connected = False
        logger.error("MIDI port is not open")
        return False
    except Exception as e:
        logger.error(f"Error sending note_off: {e}")
        return False

send_control_change(control, value, channel=0)

Send MIDI control change message.

Parameters:

Name Type Description Default
control int

Control number (0-127)

required
value int

Control value (0-127)

required
channel int

MIDI channel (0-15)

0

Returns:

Type Description
bool

True if message sent successfully, False otherwise

Source code in src/fruityloops_mcp/midi_interface.py
def send_control_change(self, control: int, value: int, channel: int = 0) -> bool:
    """Send MIDI control change message.

    Args:
        control: Control number (0-127)
        value: Control value (0-127)
        channel: MIDI channel (0-15)

    Returns:
        True if message sent successfully, False otherwise
    """
    if not self._is_connected or not self._output_port:
        logger.warning("Cannot send control_change: MIDI not connected")
        return False

    try:
        msg = mido.Message("control_change", control=control, value=value, channel=channel)
        self._output_port.send(msg)
        return True
    except Exception as e:
        logger.error(f"Error sending control_change: {e}")
        return False

send_program_change(program, channel=0)

Send MIDI program change message.

Parameters:

Name Type Description Default
program int

Program number (0-127)

required
channel int

MIDI channel (0-15)

0

Returns:

Type Description
bool

True if message sent successfully, False otherwise

Source code in src/fruityloops_mcp/midi_interface.py
def send_program_change(self, program: int, channel: int = 0) -> bool:
    """Send MIDI program change message.

    Args:
        program: Program number (0-127)
        channel: MIDI channel (0-15)

    Returns:
        True if message sent successfully, False otherwise
    """
    if not self._is_connected or not self._output_port:
        logger.warning("Cannot send program_change: MIDI not connected")
        return False

    try:
        msg = mido.Message("program_change", program=program, channel=channel)
        self._output_port.send(msg)
        return True
    except Exception as e:
        logger.error(f"Error sending program_change: {e}")
        return False

send_pitch_bend(pitch, channel=0)

Send MIDI pitch bend message.

Parameters:

Name Type Description Default
pitch int

Pitch bend value (-8192 to 8191)

required
channel int

MIDI channel (0-15)

0

Returns:

Type Description
bool

True if message sent successfully, False otherwise

Source code in src/fruityloops_mcp/midi_interface.py
def send_pitch_bend(self, pitch: int, channel: int = 0) -> bool:
    """Send MIDI pitch bend message.

    Args:
        pitch: Pitch bend value (-8192 to 8191)
        channel: MIDI channel (0-15)

    Returns:
        True if message sent successfully, False otherwise
    """
    if not self._is_connected or not self._output_port:
        logger.warning("Cannot send pitch_bend: MIDI not connected")
        return False

    try:
        msg = mido.Message("pitchwheel", pitch=pitch, channel=channel)
        self._output_port.send(msg)
        return True
    except Exception as e:
        logger.error(f"Error sending pitch_bend: {e}")
        return False

list_ports()

List available MIDI ports.

Returns:

Type Description
dict[str, list[str]]

Dictionary with 'input' and 'output' keys containing lists of port names

Source code in src/fruityloops_mcp/midi_interface.py
def list_ports(self) -> dict[str, list[str]]:
    """List available MIDI ports.

    Returns:
        Dictionary with 'input' and 'output' keys containing lists of port names
    """
    return {"input": mido.get_input_names(), "output": mido.get_output_names()}

__enter__()

Context manager entry.

Source code in src/fruityloops_mcp/midi_interface.py
def __enter__(self) -> "MIDIInterface":
    """Context manager entry."""
    self.connect()
    return self

__exit__(exc_type, exc_val, exc_tb)

Context manager exit.

Source code in src/fruityloops_mcp/midi_interface.py
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
    """Context manager exit."""
    self.disconnect()

Usage Examples

Basic Usage

from fruityloops_mcp.midi_interface import MIDIInterface

# Create interface
midi = MIDIInterface(port_name="FLStudio_MIDI")

# Connect
if midi.connect():
    # Send a note
    midi.send_note_on(60, 100)
    # ... wait ...
    midi.send_note_off(60)

    # Disconnect
    midi.disconnect()

Context Manager

with MIDIInterface(port_name="FLStudio_MIDI") as midi:
    # Automatically connects
    midi.send_note_on(60, 100)
    # ... 
    # Automatically disconnects

Checking Connection Status

midi = MIDIInterface()
midi.connect()

if midi.is_connected:
    midi.send_note_on(60)

Listing Ports

midi = MIDIInterface()
ports = midi.list_ports()

print("Input ports:", ports["input"])
print("Output ports:", ports["output"])

Method Details

send_note_on

Send a MIDI note on message.

Parameters: - note (int): MIDI note number (0-127) - velocity (int): Note velocity (0-127), default=64 - channel (int): MIDI channel (0-15), default=0

Returns: - bool: True if successful, False otherwise

Example:

midi.send_note_on(60, 100, 0)  # Middle C, forte, channel 1

send_note_off

Send a MIDI note off message.

Parameters: - note (int): MIDI note number (0-127) - velocity (int): Release velocity (0-127), default=64 - channel (int): MIDI channel (0-15), default=0

Returns: - bool: True if successful, False otherwise

send_control_change

Send a MIDI control change message.

Parameters: - control (int): Controller number (0-127) - value (int): Controller value (0-127) - channel (int): MIDI channel (0-15), default=0

Returns: - bool: True if successful, False otherwise

Example:

midi.send_control_change(7, 100)  # Volume to 100
midi.send_control_change(10, 64)  # Pan to center

send_program_change

Send a MIDI program change message.

Parameters: - program (int): Program number (0-127) - channel (int): MIDI channel (0-15), default=0

Returns: - bool: True if successful, False otherwise

send_pitch_bend

Send a MIDI pitch bend message.

Parameters: - pitch (int): Pitch bend value (-8192 to 8191) - channel (int): MIDI channel (0-15), default=0

Returns: - bool: True if successful, False otherwise

Error Handling

Methods return False on error and log warnings/errors. Check return values:

if not midi.send_note_on(60):
    print("Failed to send note")

See Also