Python Game Development library providing comprehensive multimedia functionality for creating games and interactive applications.
—
Musical Instrument Digital Interface support for music applications and real-time musical input/output. Provides comprehensive MIDI device management, event processing, and musical utility functions.
Core functions for initializing and managing the MIDI subsystem.
def init() -> None:
"""Initialize MIDI module."""
def quit() -> None:
"""Quit MIDI module."""
def get_init() -> bool:
"""
Check if MIDI module is initialized.
Returns:
bool: True if MIDI module is initialized
"""
def get_count() -> int:
"""
Get number of MIDI devices.
Returns:
int: Total number of MIDI devices (input + output)
"""
def get_default_input_id() -> int:
"""
Get default input device ID.
Returns:
int: Default input device ID, or -1 if none available
"""
def get_default_output_id() -> int:
"""
Get default output device ID.
Returns:
int: Default output device ID, or -1 if none available
"""
def get_device_info(device_id: int) -> tuple[str, str, int, int, int] | None:
"""
Get device information.
Parameters:
device_id: Device ID to query
Returns:
tuple[str, str, int, int, int] | None: (interface, name, input, output, opened) or None if invalid
"""
def time() -> int:
"""
Get current MIDI time.
Returns:
int: Current time in milliseconds
"""Real-time MIDI input for processing musical keyboard, controller, and sequencer data.
class Input:
def __init__(self, device_id: int, buffer_size: int = 4096):
"""
Initialize MIDI input device.
Parameters:
device_id: Input device ID from get_device_info()
buffer_size: Input buffer size in bytes
"""
def close(self) -> None:
"""Close input device and free resources."""
def read(self, num_events: int) -> list[list]:
"""
Read MIDI events from device.
Parameters:
num_events: Maximum number of events to read
Returns:
list[list]: List of MIDI events, each event is [[[status, data1, data2, data3], timestamp], ...]
"""
def poll(self) -> bool:
"""
Check if events are available to read.
Returns:
bool: True if events are pending in buffer
"""Real-time MIDI output for controlling synthesizers, sound modules, and external MIDI devices.
class Output:
def __init__(self, device_id: int, latency: int = 0, buffer_size: int = 256):
"""
Initialize MIDI output device.
Parameters:
device_id: Output device ID from get_device_info()
latency: Output latency in milliseconds
buffer_size: Output buffer size in bytes
"""
def close(self) -> None:
"""Close output device and free resources."""
def abort(self) -> None:
"""Abort all pending output immediately."""
def write(self, data: list) -> None:
"""
Write MIDI events to device.
Parameters:
data: List of MIDI events [[[status, data1, data2, data3], timestamp], ...]
"""
def write_short(self, status: int, data1: int = 0, data2: int = 0) -> None:
"""
Send short MIDI message immediately.
Parameters:
status: MIDI status byte (includes channel)
data1: First data byte
data2: Second data byte
"""
def write_sys_ex(self, when: int, msg: bytes | list) -> None:
"""
Send system exclusive message.
Parameters:
when: Timestamp when to send (milliseconds)
msg: System exclusive message data
"""
def note_on(self, note: int, velocity: int = 127, channel: int = 0) -> None:
"""
Send note on message.
Parameters:
note: MIDI note number (0-127)
velocity: Note velocity (0-127)
channel: MIDI channel (0-15)
"""
def note_off(self, note: int, velocity: int = 0, channel: int = 0) -> None:
"""
Send note off message.
Parameters:
note: MIDI note number (0-127)
velocity: Release velocity (0-127)
channel: MIDI channel (0-15)
"""
def set_instrument(self, instrument_id: int, channel: int = 0) -> None:
"""
Set instrument (program change).
Parameters:
instrument_id: General MIDI instrument ID (0-127)
channel: MIDI channel (0-15)
"""
def pitch_bend(self, value: int = 0, channel: int = 0) -> None:
"""
Send pitch bend message.
Parameters:
value: Pitch bend value (-8192 to 8191, 0 = no bend)
channel: MIDI channel (0-15)
"""Helper functions for musical calculations and conversions.
def frequency_to_midi(frequency: float) -> int:
"""
Convert frequency to nearest MIDI note number.
Parameters:
frequency: Frequency in Hz
Returns:
int: MIDI note number (0-127)
"""
def midi_to_frequency(midi_note: int) -> float:
"""
Convert MIDI note to frequency.
Parameters:
midi_note: MIDI note number (0-127)
Returns:
float: Frequency in Hz
"""
def midi_to_ansi_note(midi_note: int) -> str:
"""
Convert MIDI note to musical note name.
Parameters:
midi_note: MIDI note number (0-127)
Returns:
str: Note name (e.g., "C4", "F#3", "Bb5")
"""Functions for integrating MIDI with pygame's event system.
def midis2events(midis: list, device_id: int) -> list[Event]:
"""
Convert MIDI events to pygame events.
Parameters:
midis: List of MIDI events from Input.read()
device_id: Device ID that generated the events
Returns:
list[Event]: List of pygame MIDI events
"""class MidiException(Exception):
"""Exception raised by MIDI operations."""import pygame
import pygame.midi
pygame.init()
pygame.midi.init()
# List available input devices
print("MIDI input devices:")
for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
if info[2]: # if it's an input device
print(f" {i}: {info[1].decode()}")
# Open default input device
input_id = pygame.midi.get_default_input_id()
if input_id != -1:
midi_input = pygame.midi.Input(input_id)
print("Press MIDI keys (press Ctrl+C to quit)...")
try:
while True:
if midi_input.poll():
events = midi_input.read(10)
for event in events:
# event format: [[[status, data1, data2, data3], timestamp], ...]
data, timestamp = event
status, note, velocity = data[0], data[1], data[2]
if status == 144: # Note on
print(f"Note ON: {note} velocity {velocity}")
elif status == 128: # Note off
print(f"Note OFF: {note}")
except KeyboardInterrupt:
pass
midi_input.close()
pygame.midi.quit()
pygame.quit()import pygame
import pygame.midi
import time
pygame.init()
pygame.midi.init()
# List available output devices
print("MIDI output devices:")
for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
if info[3]: # if it's an output device
print(f" {i}: {info[1].decode()}")
# Open default output device
output_id = pygame.midi.get_default_output_id()
if output_id != -1:
midi_output = pygame.midi.Output(output_id)
# Set piano instrument
midi_output.set_instrument(0) # Acoustic Grand Piano
# Play a C major scale
notes = [60, 62, 64, 65, 67, 69, 71, 72] # C4 to C5
for note in notes:
midi_output.note_on(note, 100) # velocity 100
time.sleep(0.5)
midi_output.note_off(note)
time.sleep(0.1)
midi_output.close()
pygame.midi.quit()
pygame.quit()import pygame.midi
pygame.midi.init()
# Convert frequencies to MIDI notes
frequencies = [440.0, 523.25, 659.25, 783.99] # A4, C5, E5, G5
print("Frequency to MIDI conversion:")
for freq in frequencies:
midi_note = pygame.midi.frequency_to_midi(freq)
note_name = pygame.midi.midi_to_ansi_note(midi_note)
print(f" {freq} Hz = MIDI {midi_note} = {note_name}")
# Convert MIDI notes to frequencies
print("\nMIDI to frequency conversion:")
for midi_note in [60, 64, 67, 72]: # C4, E4, G4, C5
freq = pygame.midi.midi_to_frequency(midi_note)
note_name = pygame.midi.midi_to_ansi_note(midi_note)
print(f" MIDI {midi_note} ({note_name}) = {freq:.2f} Hz")
pygame.midi.quit()import pygame
import pygame.midi
pygame.init()
pygame.midi.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("MIDI Events Demo")
clock = pygame.time.Clock()
# Setup MIDI input
input_id = pygame.midi.get_default_input_id()
midi_input = None
if input_id != -1:
midi_input = pygame.midi.Input(input_id)
running = True
pressed_notes = set()
while running:
# Handle pygame events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Handle MIDI input
if midi_input and midi_input.poll():
midi_events = midi_input.read(10)
# Convert to pygame events
pygame_events = pygame.midi.midis2events(midi_events, input_id)
for event in pygame_events:
if event.type == pygame.MIDIIN:
status = event.status
note = event.data1
velocity = event.data2
if status == 144 and velocity > 0: # Note on
pressed_notes.add(note)
elif status == 128 or (status == 144 and velocity == 0): # Note off
pressed_notes.discard(note)
# Draw pressed notes
screen.fill((0, 0, 0))
y = 50
for note in sorted(pressed_notes):
note_name = pygame.midi.midi_to_ansi_note(note)
font = pygame.font.Font(None, 36)
text = font.render(f"Note: {note_name} ({note})", True, (255, 255, 255))
screen.blit(text, (50, y))
y += 40
pygame.display.flip()
clock.tick(60)
if midi_input:
midi_input.close()
pygame.midi.quit()
pygame.quit()import pygame
import pygame.midi
import time
class MIDIController:
def __init__(self):
pygame.midi.init()
self.input = None
self.output = None
self.setup_devices()
def setup_devices(self):
# Setup input
input_id = pygame.midi.get_default_input_id()
if input_id != -1:
self.input = pygame.midi.Input(input_id)
# Setup output
output_id = pygame.midi.get_default_output_id()
if output_id != -1:
self.output = pygame.midi.Output(output_id)
def process_input(self):
"""Process MIDI input and return note events"""
events = []
if self.input and self.input.poll():
midi_events = self.input.read(10)
for event in midi_events:
data, timestamp = event
status, note, velocity = data[0], data[1], data[2]
if status == 144: # Note on
events.append(('note_on', note, velocity))
elif status == 128: # Note off
events.append(('note_off', note, velocity))
elif status == 176: # Control change
events.append(('control_change', note, velocity))
return events
def play_chord(self, notes, velocity=100, duration=1.0):
"""Play a chord"""
if not self.output:
return
# Note on for all notes
for note in notes:
self.output.note_on(note, velocity)
time.sleep(duration)
# Note off for all notes
for note in notes:
self.output.note_off(note)
def close(self):
if self.input:
self.input.close()
if self.output:
self.output.close()
pygame.midi.quit()
# Example usage
controller = MIDIController()
# Play some chords
chords = [
[60, 64, 67], # C major
[65, 69, 72], # F major
[67, 71, 74], # G major
[60, 64, 67], # C major
]
for chord in chords:
controller.play_chord(chord, velocity=80, duration=0.8)
time.sleep(0.2)
controller.close()MIDI message types and device constants:
# Device types
MIDIIN: int # Input device flag
MIDIOUT: int # Output device flag
# Common MIDI status bytes
NOTE_OFF: int = 128 # 0x80
NOTE_ON: int = 144 # 0x90
CONTROL_CHANGE: int = 176 # 0xB0
PROGRAM_CHANGE: int = 192 # 0xC0
PITCH_BEND: int = 224 # 0xE0
# General MIDI Instruments (selection)
ACOUSTIC_GRAND_PIANO: int = 0
ELECTRIC_PIANO: int = 4
ORGAN: int = 16
ACOUSTIC_GUITAR: int = 24
VIOLIN: int = 40
TRUMPET: int = 56
FLUTE: int = 73Install with Tessl CLI
npx tessl i tessl/pypi-pygame-ce