Skip to main content

web midi api

MIDIAccessについて

まず、flagsからWebMIDIAPIを有効にし、browserを再起動します。 次に、サーバーサイドや非対応の対策nativeRmaを用意します。

const options = { sysex: true, software: true }
const supported =
typeof navigator !== 'undefined' && // @ts-ignore
typeof navigator.requestMIDIAccess === 'function'
const nativeRma = () => {
if (!supported) console.warn('Cannot supported Web MIDI API') // @ts-ignore
else return navigator.requestMIDIAccess(options)
}

次のようにするとIllegal invocationエラーが起きます。 (ネイティブのコードなので、他に代入できません。)

nativeRma = navigator.requestMMIDIAccess
// TypeError: Failed to execute 'requestMIDIAccess' on 'Navigator': Illegal invocation

Promiseで取得できるMIDIAccessから、各MIDIPortを操作できます。

const change = (access: MIDIAccess) => {}
const error = console.error
nativeRma()?.then(change, error)

onstatechangeについて

change内でMIDIAccess.onstatechangeを指定すると、 portが変化するごとに実行してくれます。 onstatechangeMIDIPortからも指定できます。

MIDIAccess {
onstatechange: (e: MIDIConnectionEvent) => void
inputs: maplike <DOMString, MIDIInput>;
outputs: maplike <DOMString, MIDIInput>;
sysexEnabled: boolean
}

MIDIPort {
onstatechange: (e: MIDIConnectionEvent) => void
Promise<MIDIPort> open
Promize<MIDIPort> close
}

maplikeなので、clear(), delete(), set()が使用できません。 maplikeのkey名が長く、get(), has()も使いにくいです。 ですので、size, keys(), values(), entries(), forEach()を主に使います。

onmidimessage, sendについて

MIDIInput.onmidimessageからデータを受け取り、MIDIOutput.sendからデータを送信します。 両方ともMIDIPortを継承しているため、onstatechangeを指定することもできます。

MIDIInput extends MIDIPort {
onmidimessage: (e: MIDIMessageEvent) => void
}

MIDIOutput extends MIDIPort {
send (data, timestamp) => void
clear () => void
}

Eventについて

REF

onstatechangeの引数のMIDIConnectionEventと, onmidimessageの引数のMIDIMessageEventEventから継承されているので、 addEventListennerで関数を登録したり timeStampで時間を計測したりできます。

interface MIDIConnectionEvent extends Event {
target: MIDIAccess
port: MIDIPort
}

interface MIDIMessageEvent extends Event {
data: Unit8Array
}