Sakuraqwq1/moonmp3-encoder/src/mp3 does not have a README file

    AnalysisError

    pub suberror AnalysisError {
    BadStepLength(Int)
    BadGranuleLength(Int)
    BadBlockLength(Int)
    }

    Failures reported by the analysis stages.

    Count1Error

    pub suberror Count1Error {
    BadLength(Int)
    BadValue(Int)
    BadChannels(Int)
    BadFrames(Int)
    BadGain(Int)
    FrameOverflow(Int)
    }

    Errors reported by the count1 writer and its fixed-spectrum test encoder.

    EncodeError

    pub suberror EncodeError {
    UnsupportedSampleRate(Int)
    UnsupportedChannels(Int)
    NotInterleaved(Int)
    EmptyInput
    AnalysisFailed(Int)
    HuffmanFailed(Int)
    }

    Failures the encoder can report.

    HuffmanError

    pub suberror HuffmanError {
    Unrepresentable(Int)
    BadRegion(Int)
    }

    Failures of the big_values writer.

    AnalysisFilterbank

    pub struct AnalysisFilterbank {
    history : Array[Double]
    matrix : Array[Double]
    step : Int
    }

    State of the 32-band polyphase analysis filterbank for one channel.

    The filterbank is a sliding window: it needs the 512 most recent input samples, newest first, and shapes each step out of them. history is kept as a plain array and is mutated in place, so the struct itself never has to be reassigned; step is the one mutable scalar, and only its parity is read.

    AnalysisFilterbank::new

    A filterbank with an empty 512-sample history, ready for the first step.

    AnalysisFilterbank::step

    fn AnalysisFilterbank::step(self : AnalysisFilterbank, samples : Array[Double]) -> Array[Double] raise AnalysisError

    Feed one step of 32 PCM samples, oldest first, and return the 32 subband samples that step produces.

    In matrix form the analysis filterbank is

    S[m] = sum(n = 0..511) x[n] C[n] cos((2m + 1)(n mod 64 - 16) pi / 64)

    so this windows the 512-sample history, sums the eight 64-sample blocks column by column and applies the 32x64 cosine matrix. ISO 11172-3 reaches the same sum through a mirror-symmetric folding of the windowed samples; that folding is only an optimisation of this sum, and a wrong one produces an encoder that runs, decodes and leaks four decibels into every neighbouring band, so the sum is written out directly here.

    Layer III orientation: a real-valued filterbank samples band m with a carrier at the band edge, so the raw sum has the odd bands mirrored inside themselves. The decoder undoes that after its inverse MDCT (minimp3's L3_change_sign, ISO 11172-3 §2.4.2.3); the encoder has to apply the same (-1)^n to odd bands before the MDCT, or the mirror survives the round trip. Measured through the verified decoder: with the flip 84 dB, without it 1.2 dB, so this is load-bearing and not a cosmetic sign convention.

    ChannelAnalysis

    pub struct ChannelAnalysis {
    filterbank : AnalysisFilterbank
    carry : Array[Double]
    }

    One channel of long-block analysis: the filterbank plus the 18 subband samples per subband that the previous granule leaves behind, which is the first half of the next granule's MDCT input.

    ChannelAnalysis::granule

    fn ChannelAnalysis::granule(self : ChannelAnalysis, pcm : Array[Double]) -> Array[Double] raise AnalysisError

    Long-block granule analysis; kept as the stable entry point for callers and tests that do not schedule window switching.

    ChannelAnalysis::granule_block

    fn ChannelAnalysis::granule_block(self : ChannelAnalysis, pcm : Array[Double], block_type : Int) -> Array[Double] raise AnalysisError

    Turn 576 PCM samples, in the same -1..1 scale the decoder produces, into the 576 frequency lines of one granule, ordered subband-major for long blocks.

    The 18 samples of the previous granule are prepended, so consecutive granules overlap by half a block exactly as §2.4.2.2 requires. The result is divided by the transform's synthesis gain, so the lines are already in the units the decoder's requantisation expects. For a pure short block the result is already in the [sfb][window][line] order Huffman coding requires; for long/start/stop blocks it is the usual frequency order and receives the decoder's antialias pre-compensation.

    ChannelAnalysis::new

    A channel analyser positioned at the start of a stream, with zero history.

    FrameSizer

    pub struct FrameSizer {
    numer : Int64
    denom : Int64
    base : Int
    emitted : Int
    total : Int64
    }

    Exact frame-size bookkeeping for CBR output.

    144 * bitrate / samplerate is not an integer at 44.1 kHz — 417.96 bytes at 128 kbps — so the padding bit has to track the accumulated error. The invariant is that after n frames the emitted byte total equals floor(n * 144 * bitrate / samplerate); this sizer derives each frame's size from that total instead of guessing a padding pattern, so the average bitrate is exactly 128 kbps and the frame grid never drifts.

    FrameSizer::new

    fn FrameSizer::new(bitrate : Int, samplerate : Int) -> FrameSizer

    Track frame sizes for a CBR stream of bitrate bits per second at samplerate samples per second.

    FrameSizer::next_frame_size

    fn FrameSizer::next_frame_size(self : FrameSizer) -> Int

    Size in bytes of the next frame, padding already included.

    At 128 kbps / 44.1 kHz this is 417 for the first frame and 418 for almost every one after it: 47 of every 49 frames carry the padding bit.

    FrameSizer::padding_of

    fn FrameSizer::padding_of(self : FrameSizer, size : Int) -> Int

    The padding bit value for a frame of size bytes.

    GranuleInfo

    pub(all) struct GranuleInfo {
    part2_3_length : Int
    big_values : Int
    global_gain : Int
    scalefac_compress : Int
    window_switching_flag : Int
    block_type : Int
    mixed_block_flag : Int
    table_select0 : Int
    table_select1 : Int
    table_select2 : Int
    subblock_gain0 : Int
    subblock_gain1 : Int
    subblock_gain2 : Int
    region0_count : Int
    region1_count : Int
    preflag : Int
    scalefac_scale : Int
    count1table_select : Int
    }

    Layer III side information for one granule of one channel.

    GranuleInfo::big_values

    fn GranuleInfo::big_values(part2_3_length : Int, big_values : Int, global_gain : Int, table : Int) -> GranuleInfo

    Side information for one granule coded with a big_values region.

    The same table is written to all three table_select fields: the region boundaries are then irrelevant to the decoder, which keeps the encoder from depending on the scalefactor band table until stage 1's scalefactor work lands. region0_count and region1_count are written as zero, which is legal and leaves the whole pair list on table_select0 where it fits.

    GranuleInfo::count1

    fn GranuleInfo::count1(part2_3_length : Int, global_gain : Int) -> GranuleInfo

    Side information for one count1-only granule with no scalefactor bytes.

    GranuleInfo::scaled

    fn GranuleInfo::scaled(part2_3_length : Int, big_values : Int, global_gain : Int, table : Int, scalefac_compress : Int) -> GranuleInfo

    Side information for one granule whose main data starts with scalefactors.

    scalefac_compress selects the slen1/slen2 widths of the 21 scalefactors; zero means no scalefactor bits. The Huffman tables remain the same in all three regions, so region0_count and region1_count stay zero and the decoder simply keeps the single selected table across the pair list.

    GranuleInfo::short

    fn GranuleInfo::short(part2_3_length : Int, big_values : Int, global_gain : Int, table : Int, scalefac_compress : Int) -> GranuleInfo

    Side information for one short-window granule.

    A pure short block transmits no region boundaries: the switched-window side-info form carries table_select0, table_select2 and three subblock gains instead. The encoder still uses one table across the whole pair list, so both selects are the same and the gains are zero.

    GranuleInfo::silent

    fn GranuleInfo::silent() -> GranuleInfo

    Huffman data, no big values. A frame made of this plus an empty reservoir carries 1152 zero samples and still parses everywhere.

    GranuleInfo::switched_long

    fn GranuleInfo::switched_long(part2_3_length : Int, big_values : Int, global_gain : Int, table : Int, scalefac_compress : Int, block_type : Int) -> GranuleInfo

    Side information for a start or stop granule. These are long-block coefficient layouts under a switching window, so they keep the long scalefactor transmission but set window_switching_flag and block_type.

    GranuleQuantiser

    pub struct GranuleQuantiser {
    powers : Array[Double]
    lines : Array[Double]
    bands : Array[Int]
    }

    A granule's |xr|^(3/4), precomputed once so that every candidate gain costs one multiply and one truncation per line instead of a pow.

    This is what makes an error-minimising gain search affordable: the encoder can price a dozen gains per granule and keep the best that fits, rather than taking the first that fits.

    GranuleQuantiser::band_error

    fn GranuleQuantiser::band_error(self : GranuleQuantiser, values : Array[Int], gain : Int, scalefactors : Array[Int], scalefac_scale : Int, band : Int) -> Double

    Squared reconstruction error restricted to one frequency partition. Used by the scalefactor allocator to price a band without making the other bands pay for a full-granule scan.

    GranuleQuantiser::error

    fn GranuleQuantiser::error(self : GranuleQuantiser, values : Array[Int], gain : Int) -> Double

    Squared reconstruction error of values: the sum over the lines of (sign(is) |is|^(4/3) 2^((gain-210)/4) - xr)^2.

    The sign matters twice: the decoder requantises sign(is) * |is|^(4/3) * ..., so a coefficient's reconstruction is only comparable with the line it came from once the sign is back on it. Without that, a granule whose coefficients alternate sign scores an error larger than its own energy at every gain, and the search that minimises this number picks essentially arbitrary gains — the 2026-11-02 build wrote gains up to 7 steps coarser than the peak-matching one for a steady tone and lost about 3.5 dB of end-to-end SNR to it.

    GranuleQuantiser::error_scaled

    fn GranuleQuantiser::error_scaled(self : GranuleQuantiser, values : Array[Int], gain : Int, scalefactors : Array[Int], scalefac_scale : Int) -> Double

    Squared reconstruction error of values under a per-band scalefactor vector. The scalefactor attenuation is applied after the global dequantisation, exactly where the decoder applies it.

    GranuleQuantiser::error_scaled_short

    fn GranuleQuantiser::error_scaled_short(self : GranuleQuantiser, values : Array[Int], gain : Int, scalefactors : Array[Int], scalefac_scale : Int) -> Double

    Squared reconstruction error of a short block under its 36-value scalefactor vector.

    GranuleQuantiser::new

    fn GranuleQuantiser::new(lines : Array[Double]) -> GranuleQuantiser

    Prepare a granule for repeated quantisation.

    GranuleQuantiser::new_typed

    fn GranuleQuantiser::new_typed(lines : Array[Double], block_type : Int) -> GranuleQuantiser

    Prepare a granule for repeated quantisation, mapping every line to its scalefactor field according to the block type.

    GranuleQuantiser::quantise

    fn GranuleQuantiser::quantise(self : GranuleQuantiser, gain : Int) -> Array[Int]

    Quantise with gain, using the same arithmetic as quantize_with_gain.

    GranuleQuantiser::quantise_scaled

    fn GranuleQuantiser::quantise_scaled(self : GranuleQuantiser, gain : Int, scalefactors : Array[Int], scalefac_scale : Int) -> Array[Int]

    Quantise with a per-band scalefactor vector.

    The decoder attenuates band b by 2^(-m * sf[b]), where m is 0.5 * (1 + scalefac_scale). Inverting that before quantisation is the same as lowering the band's gain by 4 * m * sf[b], which is why the per-line scale below is 2^(0.75 * m * sf[b]) on top of the global step.

    GranuleQuantiser::quantise_scaled_short

    fn GranuleQuantiser::quantise_scaled_short(self : GranuleQuantiser, gain : Int, scalefactors : Array[Int], scalefac_scale : Int) -> Array[Int]

    Quantise a short block with its 36-value scalefactor vector. The decoder's attenuation is 2^(-m * sf[3*sfb + window]); here it is inverted and folded into the per-line scale exactly as in quantise_scaled.

    MainDataReservoir

    pub struct MainDataReservoir {
    bytes : Array[Byte]
    length : Int
    placed : Int
    }

    A growable MSB-first bit buffer that keeps the whole main-data stream.

    MainDataReservoir::align

    fn MainDataReservoir::align(self : MainDataReservoir) -> Int

    Pad to the next byte boundary and return the new length.

    MainDataReservoir::append

    fn MainDataReservoir::append(self : MainDataReservoir, bytes : Bytes, count : Int) -> Unit

    Append the low count bits of a packed MSB-first byte array.

    MainDataReservoir::bit

    fn MainDataReservoir::bit(self : MainDataReservoir, index : Int) -> Int

    Bit index of the stream, zero past the end.

    MainDataReservoir::byte_at

    fn MainDataReservoir::byte_at(self : MainDataReservoir, index : Int) -> Int

    The eight bits starting at index, most significant first.

    MainDataReservoir::new

    An empty reservoir.

    MainDataReservoir::pad

    fn MainDataReservoir::pad(self : MainDataReservoir, count : Int) -> Unit

    Append count zero bits: the stream's unused space between frames.

    MainDataReservoir::pending

    fn MainDataReservoir::pending(self : MainDataReservoir) -> Int

    Bits held in the reservoir beyond the areas already written.

    MainDataReservoir::placed

    fn MainDataReservoir::placed(self : MainDataReservoir) -> Int

    Bits written into frame areas so far.

    MainDataReservoir::push

    fn MainDataReservoir::push(self : MainDataReservoir, bit : Int) -> Unit

    Append one bit.

    MainDataReservoir::take

    Hand count bits of the stream to one frame's main-data area.

    The area is a fixed number of bytes; whatever the stream does not have yet reads as zero, which is exactly the padding the frame needs.

    BaseFrameBytes

    let BaseFrameBytes : Int

    Unpadded frame size at 128 kbps / 44100 Hz, floor(144 * bitrate /samplerate) bytes.

    Bitrate128kbps

    let Bitrate128kbps : Int

    Output bitrate of v1, in bits per second.

    BitrateIndex128

    let BitrateIndex128 : Int

    v1 encodes at a constant 128 kbps; its Layer III bitrate index.

    BlockTypeLong

    let BlockTypeLong : Int

    MPEG-1 Layer III block types in side information order.

    BlockTypeShort

    let BlockTypeShort : Int

    BlockTypeStart

    let BlockTypeStart : Int

    BlockTypeStop

    let BlockTypeStop : Int

    FrameSamples

    let FrameSamples : Int

    Samples carried by one Layer III frame, per channel.

    GranulePcm

    let GranulePcm : Int

    PCM samples in one granule of one channel.

    HuffmanSymbols

    let HuffmanSymbols : Int

    Number of symbols each table stores, and the stride of huffman_codes.

    LinesPerGranule

    let LinesPerGranule : Int

    Subband samples per granule: 576 PCM samples / 32 subbands.

    LinesPerGranuleCount

    let LinesPerGranuleCount : Int

    Frequency lines in one granule.

    LongBlockLines

    let LongBlockLines : Int

    Frequency lines a long block produces.

    LongBlockSamples

    let LongBlockSamples : Int

    Length of a long-block MDCT, in subband samples.

    LongFrequencyBandCount

    let LongFrequencyBandCount : Int

    Number of actual frequency partitions in a long block, including the unscaled band 21.

    LongScalefactorBandCount

    let LongScalefactorBandCount : Int

    Number of long-block scalefactor bands that carry a transmitted scalefactor at 44.1 kHz: sfb 0..20. Band 21 exists as a frequency partition but has no scalefactor field in the bitstream.

    MaxQuantLevel

    let MaxQuantLevel : Int

    Largest magnitude an MPEG-1 big_values table can carry.

    ModeMono

    let ModeMono : Int

    The mono value of the channel mode field.

    ModeStereo

    let ModeStereo : Int

    Channel mode field: 00 stereo, 01 joint stereo, 10 dual, 11 mono.

    QuantizeOffset

    let QuantizeOffset : Double

    Rounding offset of the ISO quantiser; 0.4054^(4/3) = 0.5.

    SampleRate44100

    let SampleRate44100 : Int

    The fixed output sample rate of v1, 44100 Hz.

    SampleRateIndex44100

    let SampleRateIndex44100 : Int

    Layer III samplerate table index of 44100 Hz under MPEG-1.

    ScalefactorsInGroup1

    let ScalefactorsInGroup1 : Int

    Number of transmitted scalefactors in the slen1 group (sfb 0..10).

    ScalefactorsInGroup2

    let ScalefactorsInGroup2 : Int

    Number of transmitted scalefactors in the slen2 group (sfb 11..20).

    ShortBlockLines

    let ShortBlockLines : Int

    Frequency lines a short-window transform produces.

    ShortBlockSamples

    let ShortBlockSamples : Int

    Subband samples consumed by one short-window transform.

    ShortFrequencyBandCount

    let ShortFrequencyBandCount : Int

    Number of short frequency partitions including the unscaled 136..191 tail.

    ShortScalefactorCount

    let ShortScalefactorCount : Int

    Short-window scalefactor bands transmitted per granule: 12 bands, each with three window values.

    ShortSynthesisGain

    let ShortSynthesisGain : Double

    Synthesis gain of the 12-sample short transform: N / 4 = 3.

    StepSamples

    let StepSamples : Int

    PCM samples consumed per filterbank step: one sample per subband.

    SubbandCount

    let SubbandCount : Int

    Number of subbands produced by the polyphase filterbank.

    SynthesisGain

    let SynthesisGain : Double

    Gain the decoder's synthesis applies to the lines an encoder writes.

    The decoder's inverse MDCT is the untransposed kernel of mdct_long, and overlap-adding consecutive blocks scales a subband sample by 36 / 4 = 9 (the N / 4 of a sine-windowed MDCT pair). The synthesis filterbank itself is unity gain for the subband stream it is given, so a line coefficient of 1.0 comes back as a 9 times larger sample stream.

    Dividing the analysis output by that is what puts the encoder's lines on the scale of the xr values §2.4.2.7 requantises, and it is why one unit coefficient at global_gain = 210 decodes to a peak near 1.0. Measured on white noise against the verified decoder (tools/decoder_ref.py --score--noise): the fitted gain is 1.00000 at 84 dB with this constant, and 32 times off without it, because the analysis window is D / 32 (Table C.1) while the lines have to land in the synthesis units of Table D.

    WindowTaps

    let WindowTaps : Int

    Taps of the prototype window, four per subband.

    big_values_cost

    fn big_values_cost(values : Array[Int], table : Int, big_values : Int) -> Int

    Bits needed to code [0, 2 * big_values) with table.

    big_values_needed

    fn big_values_needed(values : Array[Int]) -> Int

    Number of pairs a granule must code as big_values.

    The count1 region may only carry -1/0/1, so big_values has to cover every coefficient whose magnitude is 2 or more. Coefficients of +-1 beyond that point are cheaper in count1 (four mask bits for four values) than as pairs (at least two bits each plus signs), so the boundary stops at the last "big" coefficient instead of the last non-zero one.

    block_window

    fn block_window(block_type : Int, index : Int) -> Double

    Window selected by a block type.

    choose_table

    fn choose_table(values : Array[Int], big_values : Int) -> Int

    Cheapest legal table for the pairs in [0, 2 * big_values).

    Ties go to the lower table number so the choice is deterministic. Returns 0 when there is nothing to code and -1 when no table can express the values.

    copy_scalefactors

    fn copy_scalefactors(scalefactors : Array[Int]) -> Array[Int]

    Independent copy, because a plan must not be mutated after it is recorded.

    copy_short_scalefactors

    fn copy_short_scalefactors(scalefactors : Array[Int]) -> Array[Int]

    Independent copy of a 36-entry short-block vector.

    count1_bits

    fn count1_bits(values : Array[Int]) -> Int raise Count1Error

    Number of bits needed for a count1-region sequence.

    Every group of four coefficients costs four bits for its mask, plus one sign bit for each non-zero coefficient. The length must be a non-zero multiple of four and every value must be -1, 0 or 1.

    count1_nonzero

    fn count1_nonzero(values : Array[Int]) -> Int

    Non-zero coefficients in a quantised granule.

    encode

    fn encode(samples : Array[Int], sample_rate : Int, channels : Int) -> Bytes raise EncodeError

    Encode interleaved signed 16-bit PCM as an MPEG-1 Layer III stream.

    Each granule is analysed with the 32-band polyphase filterbank and an MDCT, quantised to the magnitudes MPEG-1 tables can carry and written as a big_values region plus a count1 tail, with per-band scalefactors. The window scheduler may switch a granule to a short or start/stop window.

    Main data is one continuous bit stream cut into the frames' areas, so the whole stream has to exist before any area is written: a frame's data may begin up to 511 bytes before that frame's area, i.e. inside areas that are emitted earlier. Hence two passes — analyse and plan every frame into the reservoir, then lay the areas out. The input is already in memory, so the buffering costs no more than the sample array does.

    encode_count1_spectrum

    fn encode_count1_spectrum(frames : Int, channels : Int, spectrum : Array[Int], global_gain : Int) -> Bytes raise Count1Error

    Encode a fixed 576-line count1 spectrum into a sequence of MP3 frames.

    Each value must be -1, 0 or 1. Every granule and every channel carries the same spectrum and global gain. main_data_begin is always zero and no scalefactors are transmitted, so each granule is self-contained.

    encode_headroom

    fn encode_headroom(samples : Array[Int]) -> Double

    Headroom shared by every channel and granule of one encode call.

    A small quantisation error can add in phase with a near-full-scale waveform after IMDCT overlap and synthesis, so a stream with an already-correct mean gain can still peak above 1.0. A full-scale sine measures about 1.15x, so the rule holds the input's peak at 0.87 of full scale: at or below that the factor is exactly 1.0 and ordinary streams are bit-for-bit unchanged, above it the call is attenuated by 0.87 / peak. The factor is continuous, so no signal level falls in an unprotected band (a step threshold used to leave 0.87..0.95 overshooting by 2-4 %). Keeping it constant for the whole call matters too: a per-frame switch would itself become audible amplitude modulation and would disturb the stereo balance.

    The cost is level, not noise: a 100 % input comes out about 1.2 dB quiet, so a full-scale probe scores below LAME against the original level and matches it once normalised. tools/selftest.py pins both ends — decoded peak ≤ 1.00 and level loss ≤ 1.3 dB.

    global_gain_for_peak

    fn global_gain_for_peak(peak : Double, top : Int) -> Int

    Gain that maps a line of magnitude peak onto top.

    Solving (|xr| / 2^((g - 210)/4))^(3/4) = top gives g = 210 + 4 log2(peak / top^(4/3)). The result is clamped to the 8-bit side-info field.

    granule_cost

    fn granule_cost(values : Array[Int], table : Int, big_values : Int) -> Int

    Exact bits for one granule: big_values pairs, then the count1 tail.

    long_block_window

    fn long_block_window(index : Int) -> Double

    Sine window of the long block. ISO/IEC 11172-3 §2.4.2.2 uses sin(pi/36 (n + 0.5)) for the 36-sample long-block window.

    matrix_element

    fn matrix_element(subband : Int, tap : Int) -> Double

    Filterbank matrix element (subband, tap): cos((2 subband + 1)(tap - 16)pi / 64). Precomputing the 32x64 matrix turns the per-step cost into plain multiplies; without it every step would need 2048 cosines.

    tap - 16 is not a rewriting of 16 + tap: the two differ by (2m + 1) pi / 2, which is not a multiple of pi, so they are different matrices. 16 + tap is the synthesis matrix; using it on the analysis side makes the modulation double-sideband, mirrors every odd subband inside its own band, and leaves the encoder unable to invert the decoder. On white noise through the verified decoder this form reconstructs at 84 dB and the synthesis form at 0.01 dB; see docs/handoff-2026-11-02-night.md.

    mdct_long

    fn mdct_long(block : Array[Double]) -> Array[Double] raise AnalysisError

    Long-block MDCT: 36 subband samples in, 18 frequency lines out.

    X[k] = sum(n = 0..35) x[n] w[n] cos(pi/72 (2n + 19)(2k + 1)) with the 36-point sine window of §2.4.2.2. Line k is centred on (k + 0.5) times the 38.28125 Hz line spacing of an 1152-sample granule; the same mapping is what docs/line-frequencies.md measures.

    mdct_short

    fn mdct_short(block : Array[Double]) -> Array[Double] raise AnalysisError

    Short-block MDCT: 12 subband samples in, six frequency lines out.

    The transform is the same DCT-IV with N=12. In one 36-sample block the three windows start at offsets 6, 12 and 18, which is what lets a start window's last six samples overlap the first short window and a stop window's first six samples overlap the last one.

    mdct_switched_long

    fn mdct_switched_long(block : Array[Double], block_type : Int) -> Array[Double] raise AnalysisError

    One 36->18 transform with the window of a long, start or stop block.

    pair_cost

    fn pair_cost(table : Int, x : Int, y : Int) -> Int

    Bits a pair costs in table, or -1 when the pair is not representable.

    peak_absolute

    fn peak_absolute(values : Array[Double]) -> Double

    Largest absolute value in a line buffer.

    quantize_with_gain

    fn quantize_with_gain(lines : Array[Double], gain : Int) -> Array[Int]

    Quantise every line with an explicit gain.

    Magnitudes are clamped to MaxQuantLevel; with the gain chosen by global_gain_for_peak(peak, 15) the clamp only bites on rounding noise, but it has to be there because no MPEG-1 table can represent 16.

    region_peak

    fn region_peak(values : Array[Int], start : Int, stop : Int) -> Int

    Largest magnitude in [start, stop).

    scalefactor_band_end

    fn scalefactor_band_end(band : Int) -> Int

    End line (exclusive) of a frequency partition, 0..21.

    scalefactor_band_of_line

    fn scalefactor_band_of_line(line : Int) -> Int

    Frequency partition that owns a line, 0..21. Band 21 has no transmitted scalefactor but is still a distinct partition for error accounting.

    scalefactor_band_start

    fn scalefactor_band_start(band : Int) -> Int

    Start line of a transmitted scalefactor band, 0..20.

    scalefactor_band_width

    fn scalefactor_band_width(band : Int) -> Int

    Width of a frequency partition, 0..21.

    scalefactor_bit_count

    fn scalefactor_bit_count(compress : Int) -> Int

    Bits spent on the 21 scalefactors for a given scalefac_compress.

    scalefactor_compress

    fn scalefactor_compress(scalefactors : Array[Int]) -> Int

    The scalefac_compress that exactly covers a 21-value vector.

    scalefactor_compress_for

    fn scalefactor_compress_for(max1 : Int, max2 : Int) -> Int

    Smallest scalefac_compress that can transmit maxima max1 and max2.

    The table is not monotone in total width (compress 4 spends 33 bits where compress 3 spends 30, and compress 5 spends 21), so every entry is priced instead of walking a ramp. Ties go to the lower value, which keeps the bitstream deterministic. Returns -1 when a value needs more than four bits.

    scalefactor_group_maxima

    fn scalefactor_group_maxima(scalefactors : Array[Int]) -> (Int, Int)

    Maximum scalefactor in each transmission group, for a 21-value vector.

    scalefactor_step_multiplier

    fn scalefactor_step_multiplier(scalefac_scale : Int) -> Double

    Step-size multiplier selected by scalefac_scale: 0.5 (0.5 dB per scalefactor step) when the bit is zero and 1.0 (1 dB per step) when it is one. The decoder applies 2^(-multiplier * scalefactor).

    scalefactor_widths

    fn scalefactor_widths(compress : Int) -> (Int, Int)

    (slen1, slen2) selected by a four-bit scalefac_compress.

    short_block_window

    fn short_block_window(index : Int) -> Double

    Sine window of one 12-sample short block.

    short_huffman_index

    fn short_huffman_index(subband : Int, window : Int, line : Int) -> Int

    Index in the Huffman coefficient stream for a native short-block coefficient (subband, window, line).

    The bitstream orders short coefficients as [sfb][window][line], whereas analysis naturally produces [subband][window][line]. sfb is found in the 192-line per-window frequency domain; its start frequency occupies three consecutive window sections in the 576-line Huffman stream.

    short_scalefactor_band_end

    fn short_scalefactor_band_end(band : Int) -> Int

    End of a short scalefactor partition in one 192-line window.

    short_scalefactor_band_of_frequency

    fn short_scalefactor_band_of_frequency(frequency : Int) -> Int

    Short band of one frequency within a 192-line window, 0..12.

    short_scalefactor_band_start

    fn short_scalefactor_band_start(band : Int) -> Int

    Start of a short scalefactor partition in one 192-line window.

    short_scalefactor_band_width

    fn short_scalefactor_band_width(band : Int) -> Int

    Width of a short scalefactor partition.

    short_scalefactor_bit_count

    fn short_scalefactor_bit_count(compress : Int) -> Int

    Bits spent on the 36 short-block scalefactors for compress.

    short_scalefactor_compress

    fn short_scalefactor_compress(scalefactors : Array[Int]) -> Int

    scalefac_compress that covers a 36-value short-block vector, priced at 18 values in each slen group.

    short_scalefactor_group_maxima

    fn short_scalefactor_group_maxima(scalefactors : Array[Int]) -> (Int, Int)

    Maximum values in the two short groups, each sfb × window.

    short_scalefactor_of_line

    fn short_scalefactor_of_line(line : Int) -> Int

    Scalefactor field index for a line already in short-block Huffman order: 3*sfb + window. The sfb12 tail has no scalefactor and maps to the sentinel ShortScalefactorCount (36), which callers treat as a fixed zero.

    start_block_window

    fn start_block_window(index : Int) -> Double

    Window of a start block: long rising half, a flat bridge into the short block's first half, then the 6-sample short falling half.

    stop_block_window

    fn stop_block_window(index : Int) -> Double

    Window of a stop block, the reverse of a start block.

    table_extent

    fn table_extent(table : Int) -> Int

    Largest coefficient table can represent (0 for the empty tables).

    table_linbits

    fn table_linbits(table : Int) -> Int

    Extra bits a table appends when a coefficient reaches 15. Always zero for MPEG-1 tables; kept explicit so the writer cannot silently assume it.

    write_count1

    fn write_count1(w :
    BitWriter
    , values : Array[Int]) -> Int raise Count1Error

    Write a count1-region sequence using Huffman table B.

    The return value is the exact number of bits written and is suitable for part2_3_length when no scalefactors are transmitted.

    write_granule

    fn write_granule(w :
    BitWriter
    , values : Array[Int], table : Int, big_values : Int) -> Int raise HuffmanError

    Write a full granule's Huffman data, returning the exact bit count.

    write_header

    fn write_header(w :
    BitWriter
    , bitrate_index : Int, samplerate_index : Int, mode : Int, padding : Int) -> Unit

    Write the 4-byte MPEG-1 Layer III frame header.

    Protection is always set (no CRC): the v1 coder carries no protected frames, and every field the header still allows (private, mode extension, copyright, original, emphasis) is written as zero.

    write_pair

    fn write_pair(w :
    BitWriter
    , table : Int, x : Int, y : Int) -> Int raise HuffmanError

    Write one pair, returning the number of bits written (including the two sign bits). Sign is one bit per non-zero coefficient, and one means negative.

    write_scalefactors

    fn write_scalefactors(w :
    BitWriter
    , scalefactors : Array[Int], compress : Int) -> Int

    Write the 21 scalefactors for one granule/channel, in sfb order: sfb 0..10 with slen1 bits, then sfb 11..20 with slen2 bits.

    Returns the exact number of bits written. The caller must have chosen compress with scalefactor_compress, so every value fits its field.

    write_short_scalefactors

    fn write_short_scalefactors(w :
    BitWriter
    , scalefactors : Array[Int], compress : Int) -> Int

    Write the 36 short-block scalefactors as sfb 0..5 × window 0..2 with slen1, then sfb 6..11 × window 0..2 with slen2.

    write_side_info

    fn write_side_info(w :
    BitWriter
    , channels : Int, main_data_begin : Int, scfsi : Array[Int], granules : Array[GranuleInfo]) -> Unit

    Write the side information of one frame.

    scfsi holds one 4-bit scalefactor selector per channel and granules holds 2 * channels entries ordered granule-major: index granule * channels + channel. The writer ends byte aligned, which the spec guarantees because the field total is 136 bits in mono and 256 bits otherwise.

    zero_scalefactors

    fn zero_scalefactors() -> Array[Int]

    A 21-entry vector of zero scalefactors.

    zero_short_scalefactors

    fn zero_short_scalefactors() -> Array[Int]

    36-entry vector of zero short-block scalefactors.

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io