Skip to content

Commit

Permalink
Work around weird race when initializing midi devices
Browse files Browse the repository at this point in the history
  • Loading branch information
Ameobea committed Feb 3, 2025
1 parent 575b886 commit 47a560b
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
12 changes: 10 additions & 2 deletions src/midiKeyboard/midiInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Option } from 'funfix-core';
import * as R from 'ramda';

import type { MIDINode } from 'src/patchNetwork/midiNode';
import { UnreachableError, type IterableValueOf } from 'src/util';
import { delay, UnreachableError, type IterableValueOf } from 'src/util';

export type BuiltinMIDIInput = IterableValueOf<MIDIAccess['inputs']>;

Expand All @@ -28,9 +28,17 @@ export class MIDIInput {
let access: MIDIAccess;
let midiModule: typeof import('src/midi');
try {
// sometimes these requests just go into the ether, so kick off a few after a delay in case the first one gets lost
const accessPromise: Promise<MIDIAccess> = Promise.race([
navigator.requestMIDIAccess(),
delay(100).then(() => navigator.requestMIDIAccess()),
delay(500).then(() => navigator.requestMIDIAccess()),
delay(1000).then(() => navigator.requestMIDIAccess()),
]);

// Request MIDI access and load the Wasm MIDI module at the same time
[access, midiModule] = await Promise.all([
navigator.requestMIDIAccess(),
accessPromise,
this.midiModule || import('src/midi'),
] as [Promise<typeof access>, Promise<typeof midiModule>]);
} catch (err) {
Expand Down
14 changes: 13 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,22 @@ export class UnimplementedError extends Error {
export const retryAsync = async <T>(
fn: () => Promise<T>,
attempts = 3,
delayMs = 50
delayMs = 50,
timeout: number | null = null
): Promise<T> => {
for (let i = 0; i < attempts; i++) {
try {
if (typeof timeout === 'number') {
const res = await Promise.race([
fn().then(res => ({ type: 'ok' as const, res })),
delay(timeout).then(() => ({ type: 'timeout' as const })),
]);
if (res.type === 'timeout') {
throw new Error('timeout');
}
return res.res;
}

const res = await fn();
return res;
} catch (err) {
Expand Down

0 comments on commit 47a560b

Please sign in to comment.