You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

92 lines
2.9 KiB

"""
Fallback RTMIDI implementation using pygame.midi for Windows compatibility.
"""
import pygame.midi
import time
from typing import List, Optional, Callable
class MidiOut:
def __init__(self, device_id):
pygame.midi.init()
self.device_id = device_id
self.midi_out = pygame.midi.Output(device_id)
def send_message(self, message):
"""Send MIDI message"""
if hasattr(message, 'bytes'):
# mido message
data = message.bytes()
else:
# Raw bytes
data = message
if len(data) == 3:
self.midi_out.write_short(data[0], data[1], data[2])
elif len(data) == 2:
self.midi_out.write_short(data[0], data[1])
def close(self):
if hasattr(self, 'midi_out'):
self.midi_out.close()
class MidiIn:
def __init__(self, device_id, callback=None):
pygame.midi.init()
self.device_id = device_id
self.midi_in = pygame.midi.Input(device_id)
self.callback = callback
def set_callback(self, callback):
self.callback = callback
def poll(self):
"""Poll for MIDI input (call this regularly)"""
if self.midi_in.poll() and self.callback:
midi_events = self.midi_in.read(10)
for event in midi_events:
# Convert pygame midi event to mido-like message
if self.callback:
self.callback(event)
def close(self):
if hasattr(self, 'midi_in'):
self.midi_in.close()
def get_output_names() -> List[str]:
"""Get available MIDI output device names"""
pygame.midi.init()
devices = []
for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
if info[3]: # is_output
devices.append(info[1].decode())
return devices
def get_input_names() -> List[str]:
"""Get available MIDI input device names"""
pygame.midi.init()
devices = []
for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
if info[2]: # is_input
devices.append(info[1].decode())
return devices
def open_output(name: str) -> MidiOut:
"""Open MIDI output by name"""
pygame.midi.init()
for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
if info[3] and info[1].decode() == name: # is_output and name matches
return MidiOut(i)
raise ValueError(f"MIDI output '{name}' not found")
def open_input(name: str, callback=None) -> MidiIn:
"""Open MIDI input by name"""
pygame.midi.init()
for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
if info[2] and info[1].decode() == name: # is_input and name matches
return MidiIn(i, callback)
raise ValueError(f"MIDI input '{name}' not found")