/** * Writing the MP3 bitstream: frame headers, side information, scalefactors, and * the bit reservoir. * * ## The bit reservoir, from the writing side * * A frame is a fixed number of bytes, set by the bitrate. The audio in it is * not: a quiet passage needs fewer bits than a dense one. Layer III resolves * that by letting a frame's main data start *before* its own header — in space * left unused by earlier frames — and `main_data_begin` says how far back. * * So the encoder cannot emit a frame as a self-contained unit. It generates main * data into one continuous stream, and separately fills fixed-size slots from * that stream, tracking how far the two have diverged. That divergence is * `main_data_begin`, and the format caps it at 511 bytes — a limit the rate * control has to respect, since exceeding it produces frames no decoder can * reassemble. * * This mirrors `BitReservoir` in `sideinfo.ts`, which does the same bookkeeping * in reverse. */ import { BitWriter } from '../io/bits.js'; import type { ChannelMode } from './frame.js'; import type { GranuleInfo, SideInfo } from './sideinfo.js'; import type { Scalefactors } from './huffman.js'; /** The largest look-back the 9-bit `main_data_begin` field can express. */ export declare const MAX_MAIN_DATA_BEGIN = 511; export interface FrameParameters { bitrateKbps: number; sampleRate: number; channels: number; mode: ChannelMode; /** Intensity/MS flags. Only meaningful in joint stereo. */ modeExtension: number; padding: boolean; } /** * Writes a 4-byte MPEG-1 Layer III frame header. * * The CRC bit is written as "no CRC". A frame CRC protects only the header and * side information, every decoder tolerates its absence, and omitting it leaves * two more bytes per frame for audio. */ export declare function writeFrameHeader(writer: BitWriter, params: FrameParameters): void; /** * Writes the side information block. * * Field order and widths mirror `parseSideInfo` exactly; the two are read * together whenever either changes. */ export declare function writeSideInfo(writer: BitWriter, sideInfo: SideInfo, channels: number): void; /** * Writes one granule's scalefactors, honouring `scfsi`. * * `scfsi` lets granule 1 inherit a band group from granule 0 rather than * retransmitting it. The caller decides when that is safe; this only writes what * it is told to. * * @returns Bits written, which the caller folds into `part2_3_length`. */ export declare function writeScalefactors(writer: BitWriter, granule: GranuleInfo, scalefactors: Scalefactors, scfsi: readonly number[], granuleIndex: number): number; /** * Assembles frames, managing the bit reservoir. * * Fed one frame's worth of main data at a time, in order. State is explicit so * the same object can drive a streaming encoder later without restructuring. */ export declare class FrameAssembler { #private; constructor(params: Omit); get frameCount(): number; /** Bytes the reservoir currently holds for the next frame to borrow. */ get reservoirBytes(): number; /** * Bytes of main data the next frame can carry. * * The slot itself plus whatever the reservoir has banked, capped by the * `main_data_begin` field's reach. */ nextBudgetBytes(bitrateKbps?: number): number; /** * Appends one frame. * * @param sideInfo Side information; `mainDataBegin` is filled in here, since * only the assembler knows how far the reservoir has diverged. * @param mainData This frame's scalefactors and Huffman data, byte-aligned. */ addFrame(sideInfo: SideInfo, mainData: Uint8Array, bitrateOverride?: number): void; /** * Finishes the stream. * * Any main data still ahead of the slots would be lost, so trailing frames are * emitted until the reservoir drains — otherwise the last fraction of a second * simply disappears. */ finish(emptyFrames: (count: number) => SideInfo): Uint8Array; }