Files
deepdrft/DeepDrftPublic/Interop/audio/IFormatDecoder.ts
T
daniel-c-harvey 0b0bcb3dee refactor(audio): extract IFormatDecoder/WavFormatDecoder and wire Content-Type to JS format selection
StreamDecoder is now format-agnostic; WavFormatDecoder delegates to WavUtils; contentType flows C# to JS.
2026-06-11 06:08:09 -04:00

101 lines
4.2 KiB
TypeScript

/**
* FormatInfo: parsed header data needed to stream and seek an audio file.
* Populated by IFormatDecoder.tryParseHeader; used by StreamDecoder throughout playback.
*/
export interface FormatInfo {
/** Samples per second (e.g. 44100). */
sampleRate: number;
/** Number of audio channels. */
channels: number;
/**
* Nominal bit depth — 16 for MP3 (conventional), 16/24/32 for WAV/FLAC.
* Used for display; decoders handle the actual sample format internally.
*/
bitsPerSample: number;
/**
* Average bytes per second. Used for CBR byte-offset estimation.
* For WAV: exact (sampleRate * blockAlign).
* For MP3 CBR: bitrate_kbps * 125.
* For FLAC: approximate (fileSize / duration).
*/
byteRate: number;
/**
* For WAV: PCM frame size in bytes (channels * bitsPerSample / 8).
* For MP3: frame size in bytes (constant for CBR, 0 for VBR with TOC).
* For FLAC: 0 (frame sizes vary; use sync scan instead).
* Used by getAlignedSegmentSize to round to clean frame boundaries.
*/
blockAlign: number;
/** Total duration in seconds, from the header (null if unavailable). */
totalDuration: number | null;
/** Byte offset where audio frames begin in the original file. */
audioDataOffset: number;
/**
* Format-specific accelerator for seek-beyond-buffer byte calculation.
* WAV: null (uses byteRate/blockAlign directly).
* MP3 VBR: Xing/VBRI TOC (100-entry Uint8Array, values are file-percentage * 255).
* FLAC: SeekTable (array of {sampleNumber: number, streamOffset: number} — stream_offset
* is bytes from the start of audio frames, i.e. after all metadata blocks).
*/
seekData?: Mp3VbrSeekData | FlacSeekData | null;
}
export interface Mp3VbrSeekData {
kind: 'mp3-vbr';
toc: Uint8Array; // 100 entries; toc[i] = file-byte-fraction at i% of duration
totalBytes: number; // total audio bytes (from Xing header)
}
export interface FlacSeekData {
kind: 'flac-seektable';
points: Array<{ sampleNumber: number; streamOffset: number }>;
streamInfoBytes: Uint8Array; // raw STREAMINFO metadata block for segment wrapping
metadataBlocksSize: number; // total bytes of all metadata blocks (for stream_offset relative math)
}
/**
* IFormatDecoder: per-format strategy for header parsing, segment boundary detection,
* segment wrapping, and seek offset calculation.
*
* Implementations: WavFormatDecoder (Wave 1), Mp3FormatDecoder (Wave 2), FlacFormatDecoder (Wave 2).
*/
export interface IFormatDecoder {
/**
* Attempt to parse the header from accumulated bytes. Returns null if more bytes are needed.
* Called with growing chunks array until it succeeds or exceeds MAX_HEADER_SEARCH_BYTES.
*/
tryParseHeader(chunks: Uint8Array[], totalSize: number): FormatInfo | null;
/**
* Return the largest decodable byte count ≤ requestedSize that ends on a clean frame/block
* boundary in the audio data (post-header). Returns 0 if not enough data yet.
* @param info - the parsed FormatInfo
* @param availableBytes - bytes available starting at the current processedBytes position
* @param requestedSize - maximum desired segment size
* @param streamComplete - true when the stream has ended (allows draining the tail)
*/
getAlignedSegmentSize(
info: FormatInfo,
availableBytes: number,
requestedSize: number,
streamComplete: boolean
): number;
/**
* Wrap raw audio bytes in the minimal decodable container for decodeAudioData.
* WAV: prepend a 44-byte standard PCM header.
* MP3: pass through unchanged (raw frames are self-contained).
* FLAC: prepend fLaC marker + STREAMINFO metadata block.
*/
wrapSegment(info: FormatInfo, rawBytes: Uint8Array): Uint8Array;
/**
* Calculate the file-absolute byte offset for a seek-beyond-buffer Range request.
* The returned value includes the header offset (result ≥ info.audioDataOffset).
* WAV: exact PCM frame alignment.
* MP3 CBR: frame-aligned estimate; MP3 VBR: TOC interpolation.
* FLAC: SEEKTABLE lookup when available.
*/
calculateByteOffset(info: FormatInfo, positionSeconds: number): number;
}