Files
whisper_web/tests/meetingFixture.ts
T

65 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* SYNTHETIC meeting stand-in (spec 001 "Measurement fallback", coordination
* plan 001-0): no real meeting recording exists, so this joins the repo's
* own English clips with meeting-like pauses. Built at test time from
* tests/audio_files — nothing new is checked in. Every number measured on it
* is labelled synthetic.
*
* Layout (≈ 2 min 45 s): 2 s lead-in, en_aiproblem (whole), then three
* en_alien excerpts, each clip followed by a pause of 3, 8, 2 and 5 s. Pauses and lead-in carry
* deterministic room noise at about −60 dBFS (a real recording is never
* digital silence). Excerpts are cut on reference-line boundaries; their
* times were read once from a timestamped Large v3 Turbo transcript of
* en_alien (2026-10-29) and land in the pause before the line, so each
* excerpt's reference is exactly its lines of en_alien.txt.
*/
import { decodeClip, readReference } from "./clips";
const RATE = 16_000;
const LEAD_IN_SECONDS = 2;
const PAUSES_SECONDS = [3, 8, 2, 5];
const NOISE_AMPLITUDE = 0.001; // ≈ −60 dBFS
/** en_alien excerpts: [start s, end s) and the 1-based reference lines they contain. */
export const ALIEN_EXCERPTS: { start: number; end: number; firstLine: number; lastLine: number }[] = [
{ start: 0, end: 36.8, firstLine: 1, lastLine: 9 },
{ start: 36.8, end: 99.0, firstLine: 10, lastLine: 28 },
{ start: 165.4, end: 196.1, firstLine: 45, lastLine: 58 },
];
function roomNoise(seconds: number, seed: number): Float32Array {
let state = seed;
return new Float32Array(Math.round(seconds * RATE)).map(() => {
state = (state * 1_103_515_245 + 12_345) % 2 ** 31;
return NOISE_AMPLITUDE * (state / 2 ** 30 - 1);
});
}
export async function buildMeetingFixture(): Promise<{ audio: Float32Array; reference: string }> {
const aiproblem = await decodeClip("en_aiproblem.m4a");
const alien = await decodeClip("en_alien.opus");
const alienLines = (await readReference("en_alien")).split("\n");
const speech: Float32Array[] = [aiproblem];
const references: string[] = [(await readReference("en_aiproblem")).trim()];
for (const excerpt of ALIEN_EXCERPTS) {
speech.push(alien.subarray(Math.round(excerpt.start * RATE), Math.round(excerpt.end * RATE)));
references.push(alienLines.slice(excerpt.firstLine - 1, excerpt.lastLine).join(" ").trim());
}
const parts: Float32Array[] = [roomNoise(LEAD_IN_SECONDS, 1)];
// A pause after every clip — the last one is the meeting's trailing room tone.
speech.forEach((clip, i) => {
parts.push(clip);
parts.push(roomNoise(PAUSES_SECONDS[i % PAUSES_SECONDS.length]!, i + 2));
});
const audio = new Float32Array(parts.reduce((n, p) => n + p.length, 0));
let at = 0;
for (const part of parts) {
audio.set(part, at);
at += part.length;
}
return { audio, reference: references.join(" ") };
}