pub fn encode_extended(value: f64) -> [u8; 10] {
if value == 0.0 {
return [0u8; 10];
}
let bits = value.to_bits();
let sign = ((bits >> 63) as u16) << 15;
let exp_f64 = ((bits >> 52) & 0x7FF) as i32;
let frac = bits & 0x000F_FFFF_FFFF_FFFF;
if exp_f64 == 0 || exp_f64 == 0x7FF {
return [0u8; 10];
}
let exponent = (exp_f64 - 1023 + 16383) as u16 | sign;
let mantissa: u64 = (1u64 << 63) | (frac << 11);
let mut out = [0u8; 10];
out[0..2].copy_from_slice(&exponent.to_be_bytes());
out[2..10].copy_from_slice(&mantissa.to_be_bytes());
out
}
pub fn decode_extended(bytes: &[u8; 10]) -> f64 {
let exponent_field = u16::from_be_bytes([bytes[0], bytes[1]]);
let mantissa = u64::from_be_bytes(bytes[2..10].try_into().expect("8-byte slice"));
if mantissa == 0 && exponent_field & 0x7FFF == 0 {
return 0.0;
}
let sign = if exponent_field & 0x8000 != 0 { -1.0 } else { 1.0 };
let exponent = (exponent_field & 0x7FFF) as i32 - 16383;
sign * (mantissa as f64) * ((exponent - 63) as f64).exp2()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_common_sample_rates() {
for rate in [8_000.0, 11_025.0, 22_050.0, 44_100.0, 48_000.0, 96_000.0, 192_000.0] {
let encoded = encode_extended(rate);
assert_eq!(decode_extended(&encoded), rate, "rate {rate}");
}
}
#[test]
fn matches_known_encoding_of_44100() {
let expected: [u8; 10] = [0x40, 0x0E, 0xAC, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
assert_eq!(encode_extended(44_100.0), expected);
assert_eq!(decode_extended(&expected), 44_100.0);
}
#[test]
fn zero_encodes_to_zero() {
assert_eq!(encode_extended(0.0), [0u8; 10]);
assert_eq!(decode_extended(&[0u8; 10]), 0.0);
}
}