新增模块覆盖: 系统层 (14): system, security, print, opengl, renderscript, transition, test, service_notification, service_controls, service_quicksettings, service_wallpaper, service_autofill, service_dreams, service_vr 应用层 (13): app_admin, app_backup, app_job, app_usage, app_role, app_people, appwidget, companion, credentials, mtp, sip, telecom, speech 硬件媒体层 (15): hardware_display, hardware_fingerprint, hardware_usb, hardware_input, media_audiofx, media_browse, media_session, media_tv, media_midi, media_projection, uwb, se, view_autofill, view_textclassifier, view_translation 总计 94 个模块,75,342 行代码
315 lines
11 KiB
Python
315 lines
11 KiB
Python
"""
|
|
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",
|
|
] |