I have a method that handles incoming MIDI messages just fine.
It listen on ALL input devices, and not just on the first one.
I would like to write it using RxJS observables.
Here is the working (non RxJS observables) one:
public initMidiInputBis() {
if (navigator.requestMIDIAccess) {
console.log('This browser supports MIDI');
navigator.requestMIDIAccess().then(
(midiAccess: WebMidi.MIDIAccess) => this.onMIDISuccess(midiAccess),
(midiAccess: WebMidi.MIDIAccess) => this.onMIDIFailure(midiAccess)
);
} else {
console.log('This browser does not support MIDI');
}
}
private onMIDISuccess(midiAccess: WebMidi.MIDIAccess) {
for (const inputDevice of Array.from(midiAccess.inputs)) {
inputDevice[1].onmidimessage = (message: WebMidi.MIDIMessageEvent) => this.onMIDIMessage(message);
}
}
private onMIDIFailure(error: any) {
console.log('The browser could not access any MIDI device');
console.log(error);
}
This above method works fine, the VMPK virtual keyboard is seen as an input MIDI device and its MIDI messages are received.
Here is my attempt at writing it again using observables:
public initMidiInput() {
if (navigator.requestMIDIAccess) {
console.log('This browser supports MIDI');
const midiAccess$: Observable<WebMidi.MIDIAccess> = from(navigator.requestMIDIAccess());
const midiInput$: Observable<WebMidi.MIDIInput> = midiAccess$.pipe(
map((midiAccess: WebMidi.MIDIAccess) => {
return midiAccess.inputs.values().next().value;
})
);
midiInput$.pipe(
flatMap((midiInput: WebMidi.MIDIInput) => this.midiMessageAsObservable(midiInput)),
).subscribe((message: WebMidi.MIDIMessageEvent) => {
this.onMIDIMessage(message);
});
midiAccess$.subscribe(midiAccess => {
this.logOutputDevices(midiAccess);
});
} else {
console.log('This browser does not support MIDI');
}
}
With this above method, the VMPK virtual keyboard is NOT seen as an input MIDI device.
This method contains the following line of code midiAccess.inputs.values().next().value;
which only retrieves the first input MIDI device.
How can I consider ALL input MIDI devices ?
UPDATE: After adding some logger I can see the VMPK
virtual keyboard is listed as an input device:
MIDIInput {onmidimessage: null, connection: "closed", id: "2A23249CBCD506F53AE4731A4FE186844C42191D517EC71DFC9813E84A1D2F87", manufacturer: "", name: "VMPK Output", …}
connection: "closed"
id: "2A23249CBCD506F53AE4731A4FE186844C42191D517EC71DFC9813E84A1D2F87"
manufacturer: ""
name: "VMPK Output"
onmidimessage: null
onstatechange: null
state: "connected"
type: "input"
version: "ALSA library version 1.1.6"
I find puzzling that its connection is closed while its state is connected.
Here is how I logged the above output:
const midiAccess$: Observable<WebMidi.MIDIAccess> = from(navigator.requestMIDIAccess());
const midiInput$: Observable<WebMidi.MIDIInput> = midiAccess$.pipe(
map((midiAccess: WebMidi.MIDIAccess) => {
Array.from(midiAccess.inputs.entries()).forEach(entry => {
console.log('Key: ' + entry[0]);
console.log(entry[1]);
});
return midiAccess.inputs.values().next().value;
})
);