// moonaudio — pure MoonBit audio decoding and DSP toolkit.
// Copyright 2026 Sakuraqwq1
// Licensed under the Apache License, Version 2.0.
///|
/// G.711 mu-law expansion, as used by `WAVE_FORMAT_MULAW` and Sun `.au`
/// encoding 1.
///
/// The table is generated arithmetically instead of stored, which keeps the
/// decoder allocation free and exact.
pub fn mulaw_decode(byte : Int32) -> Double {
let inverted = byte.lnot() & 0xFF
let sign = if (inverted & 0x80) != 0 { -1.0 } else { 1.0 }
let exponent = (inverted >> 4) & 0x07
let mantissa = inverted & 0x0F
let magnitude = (((mantissa << 3) + 0x84) << exponent) - 0x84
sign * magnitude.to_double() / 32768.0
}
///|
/// G.711 A-law expansion, as used by `WAVE_FORMAT_ALAW` and Sun `.au`
/// encoding 27.
pub fn alaw_decode(byte : Int32) -> Double {
let value = byte ^ 0x55
let sign = if (value & 0x80) != 0 { 1.0 } else { -1.0 }
let exponent = (value >> 4) & 0x07
let mantissa = value & 0x0F
let magnitude = if exponent == 0 {
(mantissa << 4) + 8
} else {
((mantissa << 4) + 0x108) << (exponent - 1)
}
sign * magnitude.to_double() / 32768.0
}
///|
/// G.711 mu-law compression, the inverse of [`mulaw_decode`].
pub fn mulaw_encode(sample : Double) -> Int32 {
let value = clamp_sample(sample) * 32768.0
let sign : Int32 = if value < 0.0 { 0x80 } else { 0x00 }
let magnitude = if value < 0.0 { -value } else { value }
let clipped = magnitude.to_int().min(32635)
let biased = clipped + 0x84
let exponent = highest_set_bit(biased >> 7)
let mantissa = (biased >> (exponent + 3)) & 0x0F
(sign | (exponent << 4) | mantissa).lnot() & 0xFF
}
///|
/// G.711 A-law compression, the inverse of [`alaw_decode`].
pub fn alaw_encode(sample : Double) -> Int32 {
let value = clamp_sample(sample) * 32768.0
let sign : Int32 = if value >= 0.0 { 0x80 } else { 0x00 }
let magnitude = if value < 0.0 { -value } else { value }
let mut biased = magnitude.to_int()
if biased > 32767 {
biased = 32767
}
let mut encoded = if biased < 256 {
biased >> 4
} else {
let exponent = highest_set_bit(biased >> 8)
((exponent + 1) << 4) | ((biased >> (exponent + 3)) & 0x0F)
}
encoded = (encoded | sign) ^ 0x55
encoded & 0xFF
}
///|
/// Index of the highest set bit of a non-negative `Int32`.
fn highest_set_bit(value : Int32) -> Int32 {
let mut index = 0
let mut remaining = value
while remaining > 1 {
remaining = remaining >> 1
index = index + 1
}
index
}