""" Android media.midi 组件 — MidiManager, MidiDevice, MidiReceiver, MidiSender 等 方法签名完全对齐 Android SDK """ from typing import Any, Callable, Dict, List, Optional, Set from .._core import Stub, AndroidOnlyError # ═══════════════════════════════════════════════════════════════ # MidiManager # ═══════════════════════════════════════════════════════════════ class MidiManager(Stub): """MidiManager — MIDI 管理器""" def __init__(self): super().__init__() self._devices: Dict[int, MidiDevice] = {} self._callbacks: Dict[int, Callable] = {} self._next_device_id = 1 self._init_default_devices() def _init_default_devices(self): info = MidiDeviceInfo( id=0, inputPortCount=1, outputPortCount=1, type=MidiDeviceInfo.TYPE_VIRTUAL, properties={MidiDeviceInfo.PROPERTY_NAME: "Virtual MIDI"} ) device = MidiDevice(info) self._devices[0] = device def getDevices(self) -> List["MidiDeviceInfo"]: return [d.getInfo() for d in self._devices.values()] def registerDeviceCallback(self, callback: Callable, handler: Any = None): cid = id(callback) self._callbacks[cid] = callback def unregisterDeviceCallback(self, callback: Callable): cid = id(callback) self._callbacks.pop(cid, None) def openDevice(self, deviceInfo: "MidiDeviceInfo", callback: Callable, handler: Any = None): device = self._devices.get(deviceInfo.getId()) if device: callback(device) def openBluetoothDevice(self, bluetoothDevice: Any) -> Optional["MidiDevice"]: return None def getDefaultDevice(self) -> Optional["MidiDevice"]: for d in self._devices.values(): return d return None def deviceConnected(self, info: "MidiDeviceInfo"): pass def deviceDisconnected(self, info: "MidiDeviceInfo"): pass # ═══════════════════════════════════════════════════════════════ # MidiDevice # ═══════════════════════════════════════════════════════════════ class MidiDevice(Stub): """MidiDevice — MIDI 设备""" # ═══════════════════════════════════════════════════════════ # MidiConnection # ═══════════════════════════════════════════════════════════ class MidiConnection(Stub): """MidiDevice.MidiConnection — MIDI 连接""" def __init__(self): super().__init__() def close(self): pass def toString(self) -> str: return "MidiConnection" def __init__(self, info: "MidiDeviceInfo" = None): super().__init__() self._info = info or MidiDeviceInfo() self._input_ports: List[MidiInputPort] = [] self._output_ports: List[MidiOutputPort] = [] self._closed = False def getInfo(self) -> "MidiDeviceInfo": return self._info def openInputPort(self, portNumber: int) -> Optional["MidiInputPort"]: if self._closed: return None port = MidiInputPort(portNumber) self._input_ports.append(port) return port def openOutputPort(self, portNumber: int) -> Optional["MidiOutputPort"]: if self._closed: return None port = MidiOutputPort(portNumber) self._output_ports.append(port) return port def close(self): self._closed = True def toString(self) -> str: return f"MidiDevice(info={self._info})" # ═══════════════════════════════════════════════════════════════ # MidiDeviceInfo # ═══════════════════════════════════════════════════════════════ class MidiDeviceInfo(Stub): """MidiDeviceInfo — MIDI 设备信息""" TYPE_USB = 1 TYPE_BLUETOOTH = 2 TYPE_VIRTUAL = 3 PROPERTY_ALSA_CARD = "alsa_card" PROPERTY_ALSA_DEVICE = "alsa_device" PROPERTY_MANUFACTURER = "manufacturer" PROPERTY_NAME = "name" PROPERTY_PRODUCT = "product" PROPERTY_SERIAL_NUMBER = "serial_number" PROPERTY_USB_DEVICE = "usb_device" def __init__(self, id: int = 0, inputPortCount: int = 0, outputPortCount: int = 0, type_: int = TYPE_VIRTUAL, properties: Optional[Dict[str, str]] = None): super().__init__() self._id = id self._input_port_count = inputPortCount self._output_port_count = outputPortCount self._type = type_ self._properties = properties or {} def getId(self) -> int: return self._id def getProperties(self) -> Dict[str, str]: return dict(self._properties) def getInputPortCount(self) -> int: return self._input_port_count def getOutputPortCount(self) -> int: return self._output_port_count def getType(self) -> int: return self._type def equals(self, other: Any) -> bool: if not isinstance(other, MidiDeviceInfo): return False return self._id == other._id def hashCode(self) -> int: return hash(self._id) & 0x7FFFFFFF def toString(self) -> str: return f"MidiDeviceInfo(id={self._id}, type={self._type}," \ f" name={self._properties.get(MidiDeviceInfo.PROPERTY_NAME, '')})" # ═══════════════════════════════════════════════════════════════ # MidiReceiver # ═══════════════════════════════════════════════════════════════ class MidiReceiver(Stub): """MidiReceiver — MIDI 接收器""" def __init__(self, maxMessageSize: int = 1024): super().__init__() self._max_message_size = maxMessageSize def send(self, msg: bytes, offset: int, count: int): self.onSend(msg, offset, count) def onSend(self, msg: bytes, offset: int, count: int): pass def flush(self): pass def getMaxMessageSize(self) -> int: return self._max_message_size # ═══════════════════════════════════════════════════════════════ # MidiSender # ═══════════════════════════════════════════════════════════════ class MidiSender(Stub): """MidiSender — MIDI 发送器""" def __init__(self): super().__init__() self._receivers: List[MidiReceiver] = [] def send(self, msg: bytes, offset: int, count: int): for r in self._receivers: r.send(msg, offset, count) def onConnect(self, receiver: MidiReceiver): pass def onDisconnect(self, receiver: MidiReceiver): pass def connect(self, receiver: MidiReceiver): self._receivers.append(receiver) self.onConnect(receiver) def disconnect(self, receiver: MidiReceiver): if receiver in self._receivers: self._receivers.remove(receiver) self.onDisconnect(receiver) # ═══════════════════════════════════════════════════════════════ # MidiInputPort # ═══════════════════════════════════════════════════════════════ class MidiInputPort(MidiReceiver): """MidiInputPort — MIDI 输入端口""" def __init__(self, portNumber: int = 0): super().__init__() self._port_number = portNumber self._closed = False def send(self, msg: bytes, offset: int, count: int): if not self._closed: self.onSend(msg, offset, count) def onSend(self, msg: bytes, offset: int, count: int): pass def flush(self): pass def close(self): self._closed = True # ═══════════════════════════════════════════════════════════════ # MidiOutputPort # ═══════════════════════════════════════════════════════════════ class MidiOutputPort(MidiSender): """MidiOutputPort — MIDI 输出端口""" def __init__(self, portNumber: int = 0): super().__init__() self._port_number = portNumber def send(self, msg: bytes, offset: int, count: int): super().send(msg, offset, count) def onSend(self, msg: bytes, offset: int, count: int): pass def getPortNumber(self) -> int: return self._port_number # ═══════════════════════════════════════════════════════════════ # MidiEndpoint (stub) # ═══════════════════════════════════════════════════════════════ class MidiEndpoint(Stub): """MidiEndpoint — MIDI 端点""" def __init__(self): super().__init__() # ═══════════════════════════════════════════════════════════════ # MidiDeviceService # ═══════════════════════════════════════════════════════════════ class MidiDeviceService(Stub): """MidiDeviceService — MIDI 设备服务""" def __init__(self): super().__init__() # ═══════════════════════════════════════════════════════════════ # __all__ # ═══════════════════════════════════════════════════════════════ __all__ = [ "MidiManager", "MidiDevice", "MidiDeviceInfo", "MidiReceiver", "MidiSender", "MidiInputPort", "MidiOutputPort", "MidiEndpoint", "MidiDeviceService", ]