121 lines
3.3 KiB
TypeScript
121 lines
3.3 KiB
TypeScript
/**
|
|
* 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<number, ScheduledRepeat>();
|
|
public readonly onces = new Map<number, ScheduledOnce>();
|
|
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;
|
|
}
|
|
}
|