跳转到内容

能力中的 API

Web MIDI API

发布于

Web MIDI API 让页面在取得权限后访问 MIDI 输入与输出端口;navigator.requestMIDIAccess() 返回 MIDIAccess 对象的 Promise,对象的 inputs 和 outputs 集合保存可用端口。

BCD 记录桌面版 Chrome 43 和 Firefox 108 起提供 requestMIDIAccess()。Firefox 条目注明需要站点权限附加组件;Firefox Android 与 Safari 记为不支持(BCD api.Navigator.requestMIDIAccess)。

navigator.requestMIDIAccess()
navigator.requestMIDIAccess(options)

此方法只在安全上下文中暴露;浏览器可以询问权限,也可以采用之前保存的选择,Promise 兑现后得到 MIDIAccess 对象。

可选的 options 对象控制普通硬件 MIDI 端口以外的访问。

成员 类型 默认值 含义
sysex boolean false 请求收发系统独占消息的权限。
software boolean false 请求访问已安装的软件合成器。

MIDIAccess.inputs 和 MIDIAccess.outputs 是只读映射,分别保存 MIDIInput 与 MIDIOutput 端口。端口连接或状态改变时会触发 statechange 事件。

requestMIDIAccess()(MDN)记载了返回的 Promise 会因以下 DOMException 拒绝。

异常 条件
AbortError 导航关闭了文档或页面。
InvalidStateError 底层 MIDI 系统报告错误。
NotSupportedError 系统不支持请求的功能或选项。
NotAllowedError 用户或系统拒绝访问,或 Permissions Policy 不允许访问。

请求访问前先检查方法是否存在。方法缺失或请求失败时,保留不依赖 MIDI 的控件。

下面的代码创建 MIDI 按钮、状态文字和屏幕键盘。没有 MIDI 访问权限时,音符按钮仍可使用。

const midiButton = document.body.appendChild(document.createElement("button"));
const status = document.body.appendChild(document.createElement("p"));
const keyboard = document.body.appendChild(document.createElement("div"));
midiButton.textContent = "连接 MIDI";
keyboard.setAttribute("role", "group");
keyboard.setAttribute("aria-label", "屏幕键盘");
for (const note of ["C4", "D4", "E4", "F4", "G4"]) {
const key = keyboard.appendChild(document.createElement("button"));
key.textContent = note;
key.addEventListener("click", () => {
status.textContent = `屏幕键盘音符:${note}`;
});
}
if (!("requestMIDIAccess" in navigator)) {
midiButton.disabled = true;
status.textContent = "MIDI 不可用,请使用屏幕键盘。";
} else {
midiButton.addEventListener("click", async () => {
midiButton.disabled = true;
try {
const access = await navigator.requestMIDIAccess();
status.textContent = `MIDI 输入数:${access.inputs.size}`;
} catch (error) {
status.textContent = `MIDI 访问失败:${error.name}。请使用屏幕键盘。`;
}
});
}

不支持与请求被拒绝两条路径都会保留可用的音符按钮,并禁用 MIDI 按钮。

取得权限后,给返回映射中的每个输入端口添加监听器。事件的 data 值保存 MIDI 消息字节。

async function listenForMidi(onMessage) {
if (!("requestMIDIAccess" in navigator)) return false;
const access = await navigator.requestMIDIAccess();
for (const input of access.inputs.values()) {
input.addEventListener("midimessage", (event) => onMessage(event.data));
}
return true;
}
listenForMidi((bytes) => console.log(Array.from(bytes))).catch(console.error);

API 缺失时函数返回 false,调用方可以据此启用屏幕乐器。

规范

规范状态
Web MIDI API: requestMIDIAccess()社区草案