// moonmp3-encoder — pure MoonBit MP3 encoder.
// Copyright 2026 Sakuraqwq1
// Licensed under the Apache License, Version 2.0.
// Scalefactor bands and their transmission, ISO/IEC 11172-3 §2.4.2.7 and
// Table B.8.
//
// A long block at 44.1 kHz partitions the 576 frequency lines into 22 bands,
// but only the first 21 carry a scalefactor. The last band (lines 418..575)
// has no transmitted scalefactor, so its only step control is `global_gain`.
// The 21 values are split into two groups: sfb 0..10 use `slen1` bits each and
// sfb 11..20 use `slen2` bits each, with the pair selected by the four-bit
// `scalefac_compress` field (Table B.8 / 3-B.32).
//
// Each scalefactor is an attenuation, not an amplification: the decoder
// multiplies the requantised line by
//
// 2^(-(1 + scalefac_scale) / 2 * scalefac)
//
// so a larger value means a coarser step for that band. The encoder therefore
// quantises a band as if its `global_gain` were lowered by
// `4 * (1 + scalefac_scale) / 2 * scalefac` steps.
///|
/// 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.
pub const LongScalefactorBandCount : Int32 = 21
///|
/// Number of actual frequency partitions in a long block, including the
/// unscaled band 21.
pub const LongFrequencyBandCount : Int32 = 22
///|
/// Start line of each transmitted scalefactor band, ISO/IEC 11172-3
/// Table B.8.b (44.1 kHz). The width of band `b` is
/// `start(b + 1) - start(b)`; the last transmitted band ends at 418 and the
/// unscaled band 21 covers 418..575.
let long_scalefactor_starts : Array[Int32] = [
0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288,
342,
]
///|
/// Short-window scalefactor bands transmitted per granule: 12 bands, each with
/// three window values.
pub const ShortScalefactorCount : Int32 = 36
///|
/// Number of short frequency partitions including the unscaled 136..191 tail.
pub const ShortFrequencyBandCount : Int32 = 37
///|
/// Start frequency of each 44.1 kHz short-window band within one 192-line
/// window, plus the 192-line sentinel. Bands 0..11 carry scalefactors; band 12
/// is the unscaled tail.
let short_scalefactor_starts : Array[Int32] = [
0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192,
]
///|
/// Short band of one frequency within a 192-line window, 0..12.
pub fn short_scalefactor_band_of_frequency(frequency : Int32) -> Int32 {
if frequency < 0 {
return 0
}
if frequency >= 136 {
return 12
}
for band = 1; band < 13; band = band + 1 {
if frequency < short_scalefactor_starts[band] {
return band - 1
}
}
12
}
///|
/// Start of a short scalefactor partition in one 192-line window.
pub fn short_scalefactor_band_start(band : Int32) -> Int32 {
if band <= 0 {
0
} else if band < 13 {
short_scalefactor_starts[band]
} else {
192
}
}
///|
/// End of a short scalefactor partition in one 192-line window.
pub fn short_scalefactor_band_end(band : Int32) -> Int32 {
short_scalefactor_band_start(band + 1)
}
///|
/// Width of a short scalefactor partition.
pub fn short_scalefactor_band_width(band : Int32) -> Int32 {
short_scalefactor_band_end(band) - short_scalefactor_band_start(band)
}
///|
/// 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.
pub fn short_huffman_index(
subband : Int32,
window : Int32,
line : Int32,
) -> Int32 {
let frequency = subband * 6 + line
let band = short_scalefactor_band_of_frequency(frequency)
let width = short_scalefactor_band_width(band)
short_scalefactor_band_start(band) * 3 +
window * width +
(frequency - short_scalefactor_band_start(band))
}
///|
/// 36-entry vector of zero short-block scalefactors.
pub fn zero_short_scalefactors() -> Array[Int32] {
Array::make(ShortScalefactorCount, 0)
}
///|
/// Independent copy of a 36-entry short-block vector.
pub fn copy_short_scalefactors(scalefactors : Array[Int32]) -> Array[Int32] {
let out = Array::make(ShortScalefactorCount, 0)
for index = 0
index < ShortScalefactorCount && index < scalefactors.length()
index = index + 1 {
out[index] = scalefactors[index]
}
out
}
///|
/// 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.
pub fn short_scalefactor_of_line(line : Int32) -> Int32 {
if line < 0 {
return 0
}
for band = 0; band < 12; band = band + 1 {
let width = short_scalefactor_band_width(band)
let start = short_scalefactor_band_start(band) * 3
let stop = start + width * 3
if line < stop {
return band * 3 + (line - start) / width
}
}
ShortScalefactorCount
}
///|
/// Bits spent on the 36 short-block scalefactors for `compress`.
pub fn short_scalefactor_bit_count(compress : Int32) -> Int32 {
let (slen1, slen2) = scalefactor_widths(compress)
18 * (slen1 + slen2)
}
///|
/// Maximum values in the two short groups, each `sfb × window`.
pub fn short_scalefactor_group_maxima(
scalefactors : Array[Int32],
) -> (Int32, Int32) {
let mut max1 = 0
let mut max2 = 0
for index = 0; index < 18 && index < scalefactors.length(); index = index + 1 {
if scalefactors[index] > max1 {
max1 = scalefactors[index]
}
}
for index = 18; index < 36 && index < scalefactors.length(); index = index + 1 {
if scalefactors[index] > max2 {
max2 = scalefactors[index]
}
}
(max1, max2)
}
///|
/// `scalefac_compress` that covers a 36-value short-block vector, priced at
/// 18 values in each slen group.
pub fn short_scalefactor_compress(scalefactors : Array[Int32]) -> Int32 {
let (max1, max2) = short_scalefactor_group_maxima(scalefactors)
if max1 > 15 || max2 > 7 {
return -1
}
let mut best = -1
let mut best_bits = 0x7fffffff
for compress = 0; compress < 16; compress = compress + 1 {
let (slen1, slen2) = scalefactor_widths(compress)
let capacity1 = (1 << slen1) - 1
let capacity2 = (1 << slen2) - 1
if capacity1 < max1 || capacity2 < max2 {
continue
}
let bits = short_scalefactor_bit_count(compress)
if bits < best_bits {
best = compress
best_bits = bits
}
}
best
}
///|
/// Write the 36 short-block scalefactors as `sfb 0..5 × window 0..2` with
/// slen1, then `sfb 6..11 × window 0..2` with slen2.
pub fn write_short_scalefactors(
w : @bits.BitWriter,
scalefactors : Array[Int32],
compress : Int32,
) -> Int32 {
let (slen1, slen2) = scalefactor_widths(compress)
for band = 0; band < 6; band = band + 1 {
for window = 0; window < 3; window = window + 1 {
let index = band * 3 + window
if slen1 > 0 {
w.write_bits(scalefactors[index].to_int64(), slen1)
}
}
}
for band = 6; band < 12; band = band + 1 {
for window = 0; window < 3; window = window + 1 {
let index = band * 3 + window
if slen2 > 0 {
w.write_bits(scalefactors[index].to_int64(), slen2)
}
}
}
18 * (slen1 + slen2)
}
///|
/// `slen1` for every `scalefac_compress` value, ISO/IEC 11172-3 Table B.8.
let slen1_table : Array[Int32] = [
0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4,
]
///|
/// `slen2` for every `scalefac_compress` value.
let slen2_table : Array[Int32] = [
0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3,
]
///|
/// Number of transmitted scalefactors in the `slen1` group (sfb 0..10).
pub const ScalefactorsInGroup1 : Int32 = 11
///|
/// Number of transmitted scalefactors in the `slen2` group (sfb 11..20).
pub const ScalefactorsInGroup2 : Int32 = 10
///|
/// `(slen1, slen2)` selected by a four-bit `scalefac_compress`.
pub fn scalefactor_widths(compress : Int32) -> (Int32, Int32) {
if compress < 0 || compress > 15 {
return (0, 0)
}
(slen1_table[compress], slen2_table[compress])
}
///|
/// Bits spent on the 21 scalefactors for a given `scalefac_compress`.
pub fn scalefactor_bit_count(compress : Int32) -> Int32 {
let (slen1, slen2) = scalefactor_widths(compress)
ScalefactorsInGroup1 * slen1 + ScalefactorsInGroup2 * slen2
}
///|
/// 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.
pub fn scalefactor_compress_for(max1 : Int32, max2 : Int32) -> Int32 {
if max1 < 0 || max2 < 0 || max1 > 15 || max2 > 15 {
return -1
}
let mut best = -1
let mut best_bits = 0x7fffffff
for compress = 0; compress < 16; compress = compress + 1 {
let (slen1, slen2) = scalefactor_widths(compress)
// A field of `slen` bits holds values 0 .. 2^slen - 1, not 0 .. slen.
let capacity1 = (1 << slen1) - 1
let capacity2 = (1 << slen2) - 1
if capacity1 < max1 || capacity2 < max2 {
continue
}
let bits = scalefactor_bit_count(compress)
if bits < best_bits {
best = compress
best_bits = bits
}
}
best
}
///|
/// Maximum scalefactor in each transmission group, for a 21-value vector.
pub fn scalefactor_group_maxima(scalefactors : Array[Int32]) -> (Int32, Int32) {
let mut max1 = 0
let mut max2 = 0
for band = 0
band < ScalefactorsInGroup1 && band < scalefactors.length()
band = band + 1 {
if scalefactors[band] > max1 {
max1 = scalefactors[band]
}
}
for band = ScalefactorsInGroup1
band < LongScalefactorBandCount && band < scalefactors.length()
band = band + 1 {
if scalefactors[band] > max2 {
max2 = scalefactors[band]
}
}
(max1, max2)
}
///|
/// The `scalefac_compress` that exactly covers a 21-value vector.
pub fn scalefactor_compress(scalefactors : Array[Int32]) -> Int32 {
let (max1, max2) = scalefactor_group_maxima(scalefactors)
scalefactor_compress_for(max1, max2)
}
///|
/// Start line of a transmitted scalefactor band, 0..20.
pub fn scalefactor_band_start(band : Int32) -> Int32 {
if band <= 0 {
0
} else if band < LongScalefactorBandCount {
long_scalefactor_starts[band]
} else if band == LongScalefactorBandCount {
// The unscaled tail is a partition of its own, starting where sfb 20 ends.
418
} else {
576
}
}
///|
/// End line (exclusive) of a frequency partition, 0..21.
pub fn scalefactor_band_end(band : Int32) -> Int32 {
if band < 0 {
0
} else if band < LongScalefactorBandCount - 1 {
long_scalefactor_starts[band + 1]
} else if band == LongScalefactorBandCount - 1 {
// sfb 20 is the last transmitted band, 342..417.
418
} else if band == LongScalefactorBandCount {
576
} else {
576
}
}
///|
/// Width of a frequency partition, 0..21.
pub fn scalefactor_band_width(band : Int32) -> Int32 {
scalefactor_band_end(band) - scalefactor_band_start(band)
}
///|
/// Frequency partition that owns a line, 0..21. Band 21 has no transmitted
/// scalefactor but is still a distinct partition for error accounting.
pub fn scalefactor_band_of_line(line : Int32) -> Int32 {
if line < 0 {
return 0
}
if line >= 418 {
return 21
}
for band = 1; band < LongScalefactorBandCount; band = band + 1 {
if line < long_scalefactor_starts[band] {
return band - 1
}
}
20
}
///|
/// 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)`.
pub fn scalefactor_step_multiplier(scalefac_scale : Int32) -> Double {
if scalefac_scale == 0 {
0.5
} else {
1.0
}
}
///|
/// A 21-entry vector of zero scalefactors.
pub fn zero_scalefactors() -> Array[Int32] {
Array::make(LongScalefactorBandCount, 0)
}
///|
/// Independent copy, because a plan must not be mutated after it is recorded.
pub fn copy_scalefactors(scalefactors : Array[Int32]) -> Array[Int32] {
let out = Array::make(LongScalefactorBandCount, 0)
for band = 0
band < LongScalefactorBandCount && band < scalefactors.length()
band = band + 1 {
out[band] = scalefactors[band]
}
out
}
///|
/// 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.
pub fn write_scalefactors(
w : @bits.BitWriter,
scalefactors : Array[Int32],
compress : Int32,
) -> Int32 {
let (slen1, slen2) = scalefactor_widths(compress)
for band = 0; band < ScalefactorsInGroup1; band = band + 1 {
let value = if band < scalefactors.length() {
scalefactors[band]
} else {
0
}
if slen1 > 0 {
w.write_bits(value.to_int64(), slen1)
}
}
for band = ScalefactorsInGroup1
band < LongScalefactorBandCount
band = band + 1 {
let value = if band < scalefactors.length() {
scalefactors[band]
} else {
0
}
if slen2 > 0 {
w.write_bits(value.to_int64(), slen2)
}
}
ScalefactorsInGroup1 * slen1 + ScalefactorsInGroup2 * slen2
}