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が変化するごとに実行してくれます。
onstatechangeはMIDIPortからも指定できます。
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について
onstatechangeの引数のMIDIConnectionEventと,
onmidimessageの引数のMIDIMessageEventは
Eventから継承されているので、
addEventListennerで関数を登録したり
timeStampで時間を計測したりできます。
interface MIDIConnectionEvent extends Event {
target: MIDIAccess
port: MIDIPort
}
interface MIDIMessageEvent extends Event {
data: Unit8Array
}