{"id":5997,"library":"mido","title":"Mido - MIDI Objects for Python","description":"Mido is a Python library for working with MIDI 1.0 ports, messages, and files. It provides a straightforward and Pythonic interface for interacting with MIDI hardware and software. The library is currently at version 1.3.3 and has an active development cycle, with new features and bug fixes being regularly released.","status":"active","version":"1.3.3","language":"en","source_language":"en","source_url":"https://github.com/mido/mido","tags":["midi","audio","music","io","instrument"],"install":[{"cmd":"pip install mido","lang":"bash","label":"Basic installation"},{"cmd":"pip install mido[ports-rtmidi]","lang":"bash","label":"With default RtMidi backend"}],"dependencies":[{"reason":"For version introspection.","package":"packaging","optional":false},{"reason":"For version introspection on Python < 3.8.","package":"importlib_metadata","optional":true}],"imports":[{"symbol":"Message","correct":"from mido import Message"},{"symbol":"open_input","correct":"import mido; inport = mido.open_input()"},{"symbol":"open_output","correct":"import mido; outport = mido.open_output()"},{"symbol":"MidiFile","correct":"from mido import MidiFile"}],"quickstart":{"code":"import mido\n\n# Create a MIDI message\nmsg = mido.Message('note_on', note=60, velocity=64, time=0)\nprint(f\"Created message: {msg}\")\n\n# List available MIDI ports (example, actual names vary)\nprint(\"Available input ports:\", mido.get_input_names())\nprint(\"Available output ports:\", mido.get_output_names())\n\n# Open an output port and send a message (replaces 'Port Name' with an actual port if available)\ntry:\n    outport_name = next(iter(mido.get_output_names()), None)\n    if outport_name:\n        print(f\"Attempting to open output port: {outport_name}\")\n        with mido.open_output(outport_name) as outport:\n            print(f\"Sending {msg} to {outport_name}\")\n            outport.send(msg)\n            print(\"Message sent.\")\n    else:\n        print(\"No output MIDI ports found to send message.\")\nexcept Exception as e:\n    print(f\"Could not send MIDI message: {e}\")\n\n# Read a MIDI file (requires a 'test.mid' file, creating a dummy one)\ntry:\n    mid = mido.MidiFile()\n    track = mido.MidiTrack()\n    mid.tracks.append(track)\n    track.append(mido.Message('note_on', note=60, velocity=100, time=0))\n    track.append(mido.Message('note_off', note=60, velocity=100, time=120))\n    mid.save('test.mid')\n    print(\"Created dummy 'test.mid'\")\n\n    print(\"Reading messages from 'test.mid':\")\n    for msg in mido.MidiFile('test.mid').play():\n        print(msg)\nexcept Exception as e:\n    print(f\"Could not read/create MIDI file: {e}\")","lang":"python","description":"This quickstart demonstrates how to create MIDI messages, list available ports, send a message to an output port, and read/play messages from a MIDI file. It includes a fallback for when no physical MIDI ports are available and creates a dummy MIDI file for demonstration."},"warnings":[{"fix":"Adjust code referencing `key_signature.mode` to parse the `key_signature.key` string directly.","message":"The `mode` attribute was removed from `key_signature` messages in Mido 1.1.20. Minor keys are now appended with 'm', e.g., 'Cm'.","severity":"breaking","affected_versions":">=1.1.20"},{"fix":"If `time` should be ignored for comparison, compare `msg1.bytes() == msg2.bytes()` instead of `msg1 == msg2`.","message":"Message comparison (`==`) in Mido 1.1.18 started including the `time` attribute. This might break existing comparisons if time was not previously considered relevant.","severity":"breaking","affected_versions":">=1.1.18"},{"fix":"Refactor code using `port.pending()` to use `port.iter_pending()` for non-blocking iteration, or adapt to the new `_receive()` behavior if implementing custom ports.","message":"The `pending()` method was removed from the port API in Mido 1.1.10. Instead, `_receive()` is now allowed to return messages.","severity":"breaking","affected_versions":">=1.1.10"},{"fix":"Add or subtract 1 when converting between Mido's internal channel representation and a user-facing 1-16 range.","message":"Mido represents MIDI channels as 0-15, while many MIDI specifications and user interfaces use 1-16. Be mindful of this offset when displaying or receiving channel numbers from users.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Use `new_msg = msg.copy(note=70)` instead of `msg.note = 70` to modify messages.","message":"Directly setting attributes on `mido.Message` objects (e.g., `msg.note = 70`) is possible but discouraged. It's generally better to use `msg.copy()` to create a new message with updated attributes for immutability and validation.","severity":"gotcha","affected_versions":"All versions"},{"fix":"To explicitly use `PortMidi`, set the environment variable `MIDO_BACKEND=mido.backends.portmidi` or call `mido.set_backend('mido.backends.portmidi')` in your program.","message":"As of Mido 1.1.10, `RtMidi` became the default backend, replacing `PortMidi`. While generally an improvement, this might lead to different port availability or behavior for users who relied on `PortMidi`'s default selection.","severity":"gotcha","affected_versions":">=1.1.10"}],"env_vars":null,"last_verified":"2026-04-14T00:00:00.000Z","next_check":"2026-07-13T00:00:00.000Z"}