Использование наблюдаемых RxJS для рассмотрения всех входных MIDI-устройств - PullRequest
0 голосов
/ 27 мая 2019

У меня есть метод, который прекрасно обрабатывает входящие MIDI-сообщения.

Он слушает на ВСЕХ устройствах ввода, а не только на первом.

Я хотел бы написать это, используя наблюдаемые RxJS.

Вот рабочая (не наблюдаемая RxJS):

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);
}

Этот метод работает хорошо, виртуальная клавиатура VMPK рассматривается как входное MIDI-устройство, и его MIDI-сообщения принимаются.

Вот моя попытка написать это снова, используя наблюдаемые:

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');
  }
}

При использовании вышеуказанного метода виртуальная клавиатура VMPK НЕ рассматривается в качестве входного MIDI-устройства.

Этот метод содержит следующую строку кода midiAccess.inputs.values().next().value;, которая извлекает только первое входное MIDI-устройство.

Как мне рассмотреть ВСЕ входные MIDI-устройства?

ОБНОВЛЕНИЕ: После добавления логгера я вижу виртуальную клавиатуру VMPK в качестве устройства ввода:

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"

Я нахожу озадачивающим, что его соединение закрыто, а его состояние подключено.

Вот как я зарегистрировал вышеприведенный вывод:

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;
  })
);

Ответы [ 2 ]

1 голос
/ 28 мая 2019

Я мог решить проблему следующим методом:

public initMidiInput() {
  if (navigator.requestMIDIAccess) {
    console.log('This browser supports MIDI');
    const midiAccess$: Observable<WebMidi.MIDIAccess> = from(navigator.requestMIDIAccess());
    midiAccess$.pipe(
      flatMap((midiAccess: WebMidi.MIDIAccess) => {
        return midiAccess.inputs;
      }),
      map((midiInput) => {
        return midiInput[1];
      }),
      filter((midiInput: WebMidi.MIDIInput) => midiInput !== undefined),
      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');
  }
}

private midiMessageAsObservable(inputDevice: WebMidi.MIDIInput): Observable<WebMidi.MIDIMessageEvent> {
  const source: Subject<WebMidi.MIDIMessageEvent> = new Subject<WebMidi.MIDIMessageEvent>();
  inputDevice.onmidimessage = (note: WebMidi.MIDIMessageEvent) => source.next(note);
  return source.asObservable();
}

Мне пришлось удалить вызов метода .next() и вернуть значение карты.

0 голосов
/ 27 мая 2019

Попробуйте это.

import { of, from, throwError } from 'rxjs';
import { map, switchMap, catchError } from 'rxjs/operators';

public initMidiInput() {
  if (navigator.requestMIDIAccess) {
    console.log('This browser supports MIDI');
    of(navigator.requestMIDIAccess())
    .pipe(
      map((midiAccess: WebMidi.MIDIAccess) => midiAccess.inputs),
      switchMap((inputs) => from(inputs)),
      catchError(error => {
        return throwError(error);
      })
    )
    .subscribe(inputDevice => {
      inputDevice[1].onmidimessage = (message: WebMidi.MIDIMessageEvent) => this.onMIDIMessage(message);
    }, error => {
        console.log('The browser could not access any MIDI device');
        console.log(error);
    });
  }
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...