/** * Real `TransportLike` implementation backed by an in-memory event log. * Mirrors the fixture shipped by `@suaveplan/audio-controllers/tests/ * fake-transport.ts`. Lives outside `src/` so it is excluded from * coverage but available to every test in this package. */ import type { BarsBeatsSixteenths, SignalLike, TransportCallback, TransportLike, TransportTime, } from "@suaveplan/audio-transport"; interface ScheduledRepeat { readonly id: number; readonly callback: TransportCallback; readonly interval: TransportTime; } interface ScheduledOnce { readonly id: number; readonly callback: TransportCallback; readonly time: number; } const NOOP_BBS: BarsBeatsSixteenths = "0:0:0"; function makeFakeSignal(): SignalLike { let v = 120; const points: { time: number; value: number; type: "set" }[] = []; const sig: SignalLike = { get points() { return points.slice(); }, get initialValue() { return 120; }, get value() { return v; }, setValueAtTime(value: number, time: number) { v = value; points.push({ time, value, type: "set" }); }, linearRampToValueAtTime(value: number) { v = value; }, exponentialRampToValueAtTime(value: number) { v = value; }, getValueAtTime() { return v; }, cancelScheduledValues() { points.length = 0; }, }; return sig; } export class FakeTransport implements TransportLike { public bpm: SignalLike = makeFakeSignal(); public readonly ppq = 192; public readonly timeSignature = 4; public swing = 0; public swingSubdivision: TransportTime = "8n"; public loop = false; public loopStart: TransportTime = 0; public loopEnd: TransportTime = 0; public state: "stopped" | "playing" | "paused" = "stopped"; public position: BarsBeatsSixteenths = NOOP_BBS; public ticks = 0; public seconds = 0; public readonly repeats = new Map(); public readonly onces = new Map(); private nextId = 1; start(): void { this.state = "playing"; } stop(): void { this.state = "stopped"; } pause(): void { this.state = "paused"; } schedule(callback: TransportCallback, time: TransportTime): number { return this.scheduleOnce(callback, time); } scheduleOnce(callback: TransportCallback, time: TransportTime): number { const id = this.nextId++; const num = typeof time === "number" ? time : 0; this.onces.set(id, { id, callback, time: num }); return id; } scheduleRepeat( callback: TransportCallback, interval: TransportTime ): number { const id = this.nextId++; this.repeats.set(id, { id, callback, interval }); return id; } cancel(eventId: number): void { this.repeats.delete(eventId); this.onces.delete(eventId); } cancelAfter(_time: TransportTime): void { // unused } toSeconds(time: TransportTime): number { return typeof time === "number" ? time / this.ppq : 0; } toTicks(time: TransportTime): number { return typeof time === "number" ? time * this.ppq : 0; } }