Skip to content

Instantly share code, notes, and snippets.

@jgwill
Last active January 2, 2025 20:38
Show Gist options
  • Save jgwill/bba3d443d2f44ef199286d180b6111be to your computer and use it in GitHub Desktop.
Save jgwill/bba3d443d2f44ef199286d180b6111be to your computer and use it in GitHub Desktop.
orpheus523 - MIDI_Python_Module_2412240950

MIDI_Python_Module_2412240950

Kids friendly explanation.

What is this script?
This script is like a special listener for music notes from a MIDI device (like a keyboard or a synthesizer). It listens to the notes you play and tells you information about them in a fun way.

How does it work?

  1. Importing Helpers:

    • mido helps the script understand MIDI messages, which are like secret codes for musical notes.
    • time helps us keep track of when notes start and stop.
    • yaml is like a special way to write down information so it's easy to read, like making a list in a diary.
  2. Setting Up the Monitor:

    • The MidiMonitor class is like our spy gadget. When you create one, you can tell it which MIDI device (or "port") to listen to.
  3. Listening to Different Ports:

    • list_ports() is like looking through a window to see all the musical instruments (MIDI devices) connected to your computer.
  4. Handling Notes:

    • When you press a key (_handle_note_on), it's like starting a timer for how long you hold that note. It stores when you began playing the note, how hard you pressed (velocity), and on which instrument (channel).
    • When you let go of the key (_handle_note_off), it figures out how long you played that note (duration) and writes it down in a special format (YAML) so we can read it like a story.
  5. Processing Messages:

    • _process_message is like deciding what to do with each note you play or stop. It decides if it's a start, stop, or something else and then shares that info.
  6. Start Listening:

    • start_monitoring is when our gadget starts listening. It opens up the connection to your MIDI device and listens for every note you play, telling you what it hears in a nice, readable format.
  7. Example Use:

    • When you run this script, it shows you all the MIDI devices connected and asks you to pick one. Once you choose, it will listen to that device and print out info like what note you played, how hard, and for how long.

So, this script is like having a musical detective that listens to every note you play on your MIDI instrument and reports back what it hears in a way that's easy for you to understand! Remember, if you want to use this, you'll need to have a MIDI device plugged into your computer.

import mido
import time
import yaml
class MidiMonitor:
def __init__(self, port_name=None):
self.port_name = port_name
self.note_info = {}
def list_ports(self):
return mido.get_input_names()
def set_port(self, port_name):
self.port_name = port_name
def _handle_note_on(self, msg):
if msg.velocity > 0: # Note start
self.note_info[(msg.channel, msg.note)] = {
'start_time': time.time(),
'velocity': msg.velocity
}
def _handle_note_off(self, msg):
key = (msg.channel, msg.note)
if key in self.note_info:
start_info = self.note_info.pop(key)
duration = time.time() - start_info['start_time']
msg_dict = {
'type': msg.type,
'note': msg.note,
'velocity': start_info['velocity'],
'channel': msg.channel,
'duration': duration
}
return yaml.dump(msg_dict, default_flow_style=False, sort_keys=False)
else:
return yaml.dump(msg.dict(), default_flow_style=False, sort_keys=False)
def _process_message(self, msg):
if msg.type == 'note_on':
self._handle_note_on(msg)
elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0):
return self._handle_note_off(msg)
else:
return yaml.dump(msg.dict(), default_flow_style=False, sort_keys=False)
def start_monitoring(self):
if not self.port_name:
raise ValueError("No MIDI input port specified.")
try:
with mido.open_input(self.port_name) as inport:
print(f"Listening for MIDI input on {self.port_name}...")
for msg in inport:
output = self._process_message(msg)
if output:
print(output)
except ValueError:
raise ValueError(f"Could not open MIDI input port '{self.port_name}'. Ensure the device is connected.")
except KeyboardInterrupt:
print("Monitoring stopped.")
# Example Usage
if __name__ == "__main__":
monitor = MidiMonitor()
ports = monitor.list_ports()
print("Available MIDI input ports:")
for i, port in enumerate(ports):
print(f"{i}: {port}")
selected_port = int(input("Select port number: "))
monitor.set_port(ports[selected_port])
monitor.start_monitoring()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment