Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
/**
* Real `MidiAccessLike` + `MidiAccessAdapter` fixtures — mirrors the
* `tests/fake-midi.ts` shipped by `@suaveplan/audio-controllers`. Lives
* outside `src/` so it does not appear in coverage reports yet remains
* shared by every Phase-3 unit / story / integration test.
*
* Re-implements the audio-controllers fixture locally because that
* fixture is not published through the package exports. The shape is
* intentionally identical so the controller plumbing is unchanged.
*/
import type {
MidiAccessAdapter,
MidiAccessLike,
MidiInputLike,
MidiOutputLike,
} from "@suaveplan/audio-controllers";
export interface FakeMidiInput extends MidiInputLike {
emit(data: ReadonlyArray<number>, timeStamp?: number): void;
}
export interface FakeMidiOutput extends MidiOutputLike {
readonly sent: number[][];
disconnect(): void;
}
export interface FakeMidiAccess extends MidiAccessLike {
readonly mutableInputs: Map<string, FakeMidiInput>;
readonly mutableOutputs: Map<string, FakeMidiOutput>;
disconnectPort(port: FakeMidiInput | FakeMidiOutput): void;
reconnectPort(port: FakeMidiInput | FakeMidiOutput): void;
}
function createInput(id: string, name: string): FakeMidiInput {
const port: FakeMidiInput = {
id,
name,
state: "connected",
type: "input",
onmidimessage: null,
emit(data: ReadonlyArray<number>, timeStamp = 0) {
port.onmidimessage?.({
data: new Uint8Array(data),
timeStamp,
});
},
} as FakeMidiInput;
return port;
}
function createOutput(id: string, name: string): FakeMidiOutput {
const sent: number[][] = [];
let connectedState: "connected" | "disconnected" = "connected";
const port = {
id,
name,
get state(): "connected" | "disconnected" {
return connectedState;
},
type: "output" as const,
sent,
send(data: ReadonlyArray<number> | Uint8Array) {
sent.push(Array.isArray(data) ? data.slice() : Array.from(data));
},
disconnect() {
connectedState = "disconnected";
},
} satisfies FakeMidiOutput;
return port;
}
export function createFakeAccess(
options: { readonly inputName?: string; readonly outputName?: string } = {}
): FakeMidiAccess {
const inputName = options.inputName ?? "Demo Input";
const outputName = options.outputName ?? "Demo Output";
const input = createInput("in-1", inputName);
const output = createOutput("out-1", outputName);
const mutableInputs = new Map<string, FakeMidiInput>([[input.id, input]]);
const mutableOutputs = new Map<string, FakeMidiOutput>([
[output.id, output],
]);
const access: FakeMidiAccess = {
get inputs(): ReadonlyMap<string, MidiInputLike> {
return mutableInputs;
},
get outputs(): ReadonlyMap<string, MidiOutputLike> {
return mutableOutputs;
},
mutableInputs,
mutableOutputs,
onstatechange: null,
disconnectPort(port) {
if (port.type === "input") mutableInputs.delete(port.id);
else {
port.disconnect();
mutableOutputs.delete(port.id);
}
access.onstatechange?.({
port: { ...port, state: "disconnected" },
});
},
reconnectPort(port) {
if (port.type === "input") mutableInputs.set(port.id, port);
else mutableOutputs.set(port.id, port);
access.onstatechange?.({
port: { ...port, state: "connected" },
});
},
};
return access;
}
export function createFakeAdapter(
access: FakeMidiAccess,
options: { readonly reject?: Error } = {}
): MidiAccessAdapter {
return {
async requestAccess() {
if (options.reject) throw options.reject;
return access;
},
};
}
export function getFirstInput(access: FakeMidiAccess): FakeMidiInput {
const first = access.mutableInputs.values().next().value;
if (!first) throw new Error("no input");
return first;
}