/** * SRT (SubRip) writer. * * Standard format: * 1 * 00:00:01,000 --> 00:00:03,500 * Hello world. * * 2 * 00:00:04,000 --> 00:00:06,000 * Second cue. * * Cue numbering is 1-indexed. Timestamps are HH:MM:SS,mmm with comma decimal. * CRLF line endings are NOT required by the spec — most parsers accept LF * (we emit LF for simplicity and cross-platform sanity). * * ── Precision policy ───────────────────────────────────────── * SRT's wire precision is exactly 1ms. We canonicalise every timestamp to a * non-negative INTEGER millisecond at the boundary of this module: * * secondsToMs(s) = Math.max(0, Math.round(s * 1000)) * * All downstream math (cue ordering, gap extension, end>start validation, * grouping) runs on those ms-ints. This eliminates two whole classes of * float-arithmetic bugs: * * 1. Cues whose float `end > start` but whose ms-rounded values collide * (e.g. start=0.1001, end=0.1004 → both round to 100). The float check * would pass, then we'd emit `00:00:00,100 --> 00:00:00,100` — invalid. * 2. Drift when extending a cue's end up to the next cue's start: float * assignment can carry a 1e-15 epsilon that flips a Math.round at the * ms boundary. Integer assignment is exact. * * Callers pass seconds (the natural unit for whisper / OpenAI output); the * conversion happens exactly once per timestamp, here. If you already have * ms-ints upstream, use `formatSrtTimeMs` directly to skip the round trip. */ export interface SrtCue { /** Start time in seconds. Internally rounded to ms-int. */ start: number; /** End time in seconds. Must be > start AFTER ms-rounding (see policy above). */ end: number; /** Caption text. Multi-line OK. Trimmed. */ text: string; } /** * A word with its own timing. Used by `buildWordLevelSrt` to emit one cue per * word (TikTok / Reels burned-caption style). */ export interface WordCue { start: number; end: number; text: string; } /** * Word-level SRT — one cue per word. Useful for vertical-format burned-in * captions where each word pops as it's spoken. * * Behaviour: * - Skips empty / zero-duration words (post-rounding, so 0.1001s/0.1004s * pairs that collapse to the same ms are dropped instead of producing * invalid same-stamp cues). * - Optional `groupSize` clusters N consecutive words into one cue (e.g. 2-3 * words at a time for a more readable rhythm). Default 1. * - Optional `gapSec` extends a cue's end up to the next cue's start so the * caption stays on screen until the next word appears (closed-caption look). */ export declare function buildWordLevelSrt(words: WordCue[], opts?: { groupSize?: number; gapSec?: number; }): string; /** * Build an SRT string from cues. Cues are emitted in input order. Throws on * cues that collapse to zero or negative duration AFTER ms-rounding — * upstream code is expected to handle that ahead of time. */ export declare function buildSrt(cues: SrtCue[]): string; /** Format seconds → "HH:MM:SS,mmm" (SRT timestamp). Single rounding step. */ export declare function formatSrtTime(seconds: number): string; /** * Format ms-int → "HH:MM:SS,mmm". Use this when you already have ms-int * timing (e.g. straight off whisper.cpp's `offsets.from`) to avoid an * unnecessary round-trip through float seconds. */ export declare function msToSrtTime(ms: number): string; /** * Convert float seconds → integer milliseconds with the same rounding rule * used everywhere in this module. Negative inputs and NaN clamp to 0. */ export declare function secondsToMs(seconds: number): number; //# sourceMappingURL=srt.d.ts.map