pub const FINE_ENERGY_MAX_BITS: u32 = 14;
pub const FINE_ENERGY_Q15_ONE: i32 = 1 << 15;
pub const FINE_ENERGY_HALF_Q15: i32 = 1 << 14;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FineEnergyChannels {
Mono,
Stereo,
}
impl FineEnergyChannels {
pub const fn cost_per_band(self) -> u32 {
match self {
FineEnergyChannels::Mono => 1,
FineEnergyChannels::Stereo => 2,
}
}
pub const fn count(self) -> u32 {
self.cost_per_band()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FineEnergyError {
BitsOutOfRange {
provided: u32,
max: u32,
},
RefinementOutOfRange {
f: u32,
levels: u32,
},
}
impl core::fmt::Display for FineEnergyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match *self {
FineEnergyError::BitsOutOfRange { provided, max } => write!(
f,
"oxideav-opus: fine-energy bits B_i out of range: provided={provided}, max={max}"
),
FineEnergyError::RefinementOutOfRange { f: val, levels } => write!(
f,
"oxideav-opus: fine-energy refinement f={val} out of range \
(must be < 2**B_i = {levels})"
),
}
}
}
impl std::error::Error for FineEnergyError {}
pub fn fine_energy_levels(bits: u32) -> Result<u32, FineEnergyError> {
if bits > FINE_ENERGY_MAX_BITS {
return Err(FineEnergyError::BitsOutOfRange {
provided: bits,
max: FINE_ENERGY_MAX_BITS,
});
}
Ok(1u32 << bits)
}
pub fn fine_correction_ratio(bits: u32, f: u32) -> Result<(i32, i32), FineEnergyError> {
let levels = fine_energy_levels(bits)?;
if f >= levels {
return Err(FineEnergyError::RefinementOutOfRange { f, levels });
}
let numerator = (2 * f as i64) + 1 - levels as i64;
let denominator = (levels as i64) * 2;
Ok((numerator as i32, denominator as i32))
}
pub fn fine_correction_q15(bits: u32, f: u32) -> Result<i32, FineEnergyError> {
let (numerator, denominator) = fine_correction_ratio(bits, f)?;
let scaled = (numerator as i64) * (FINE_ENERGY_Q15_ONE as i64) / (denominator as i64);
Ok(scaled as i32)
}
pub fn fine_correction_q(bits: u32, f: u32, shift: u32) -> Result<i64, FineEnergyError> {
let (numerator, denominator) = fine_correction_ratio(bits, f)?;
let scaled = (numerator as i64) * (1i64 << shift) / (denominator as i64);
Ok(scaled)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FinalBitPriority {
Priority0,
Priority1,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FinalFineBitPlan {
pub granted: Vec<bool>,
pub bits_used: u32,
pub bits_unused: u32,
}
pub fn plan_final_fine_bits(
priorities: &[Option<FinalBitPriority>],
channels: FineEnergyChannels,
leftover_bits: u32,
) -> FinalFineBitPlan {
let cost = channels.cost_per_band();
let mut granted = vec![false; priorities.len()];
let mut remaining = leftover_bits;
let mut bits_used = 0u32;
for pass in [FinalBitPriority::Priority0, FinalBitPriority::Priority1] {
for (band, prio) in priorities.iter().enumerate() {
if *prio != Some(pass) {
continue;
}
if remaining < cost {
break;
}
granted[band] = true;
remaining -= cost;
bits_used += cost;
}
if remaining < cost {
break;
}
}
FinalFineBitPlan {
granted,
bits_used,
bits_unused: remaining,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn q15_one_is_two_pow_fifteen() {
assert_eq!(FINE_ENERGY_Q15_ONE, 32768);
}
#[test]
fn half_q15_is_two_pow_fourteen() {
assert_eq!(FINE_ENERGY_HALF_Q15, 16384);
assert_eq!(FINE_ENERGY_HALF_Q15 * 2, FINE_ENERGY_Q15_ONE);
}
#[test]
fn max_bits_keeps_q15_exact() {
const { assert!(FINE_ENERGY_MAX_BITS <= 15) };
}
#[test]
fn channel_costs() {
assert_eq!(FineEnergyChannels::Mono.cost_per_band(), 1);
assert_eq!(FineEnergyChannels::Stereo.cost_per_band(), 2);
assert_eq!(FineEnergyChannels::Mono.count(), 1);
assert_eq!(FineEnergyChannels::Stereo.count(), 2);
}
#[test]
fn levels_is_two_pow_bits() {
for b in 0..=FINE_ENERGY_MAX_BITS {
assert_eq!(fine_energy_levels(b), Ok(1u32 << b), "B_i = {b}");
}
}
#[test]
fn levels_rejects_over_max() {
assert_eq!(
fine_energy_levels(FINE_ENERGY_MAX_BITS + 1),
Err(FineEnergyError::BitsOutOfRange {
provided: FINE_ENERGY_MAX_BITS + 1,
max: FINE_ENERGY_MAX_BITS,
})
);
}
#[test]
fn ratio_b0_is_zero() {
assert_eq!(fine_correction_ratio(0, 0), Ok((0, 2)));
}
#[test]
fn ratio_b1() {
assert_eq!(fine_correction_ratio(1, 0), Ok((-1, 4)));
assert_eq!(fine_correction_ratio(1, 1), Ok((1, 4)));
}
#[test]
fn ratio_b2() {
assert_eq!(fine_correction_ratio(2, 0), Ok((-3, 8)));
assert_eq!(fine_correction_ratio(2, 1), Ok((-1, 8)));
assert_eq!(fine_correction_ratio(2, 2), Ok((1, 8)));
assert_eq!(fine_correction_ratio(2, 3), Ok((3, 8)));
}
#[test]
fn ratio_numerator_is_always_odd() {
for b in 1..=FINE_ENERGY_MAX_BITS {
let levels = 1u32 << b;
for f in 0..levels {
let (num, _den) = fine_correction_ratio(b, f).unwrap();
assert_eq!(num & 1, 1, "B_i = {b}, f = {f}, num = {num}");
}
}
}
#[test]
fn ratio_zero_mean_symmetry() {
for b in 1..=10u32 {
let levels = 1u32 << b;
for f in 0..levels {
let (num, den) = fine_correction_ratio(b, f).unwrap();
let (num_mirror, den_mirror) = fine_correction_ratio(b, levels - 1 - f).unwrap();
assert_eq!(den, den_mirror);
assert_eq!(num, -num_mirror, "B_i = {b}, f = {f}");
}
}
}
#[test]
fn ratio_rejects_f_out_of_range() {
assert_eq!(
fine_correction_ratio(2, 4),
Err(FineEnergyError::RefinementOutOfRange { f: 4, levels: 4 })
);
}
#[test]
fn ratio_rejects_bits_out_of_range() {
assert_eq!(
fine_correction_ratio(FINE_ENERGY_MAX_BITS + 1, 0),
Err(FineEnergyError::BitsOutOfRange {
provided: FINE_ENERGY_MAX_BITS + 1,
max: FINE_ENERGY_MAX_BITS,
})
);
}
#[test]
fn q15_b0_is_zero() {
assert_eq!(fine_correction_q15(0, 0), Ok(0));
}
#[test]
fn q15_b1_quarters() {
assert_eq!(fine_correction_q15(1, 0), Ok(-8192));
assert_eq!(fine_correction_q15(1, 1), Ok(8192));
}
#[test]
fn q15_b2_eighths() {
assert_eq!(fine_correction_q15(2, 0), Ok(-12288)); assert_eq!(fine_correction_q15(2, 1), Ok(-4096)); assert_eq!(fine_correction_q15(2, 2), Ok(4096)); assert_eq!(fine_correction_q15(2, 3), Ok(12288)); }
#[test]
fn q15_matches_ratio_exactly() {
for b in 0..=FINE_ENERGY_MAX_BITS {
let levels = 1u32 << b;
for f in 0..levels {
let (num, den) = fine_correction_ratio(b, f).unwrap();
let expect = (num as i64) * (FINE_ENERGY_Q15_ONE as i64) / (den as i64);
assert_eq!(
(num as i64) * (FINE_ENERGY_Q15_ONE as i64) % (den as i64),
0,
"B_i = {b}, f = {f} not exact in Q15"
);
assert_eq!(
fine_correction_q15(b, f),
Ok(expect as i32),
"B_i = {b}, f = {f}"
);
}
}
}
#[test]
fn q15_strictly_within_half() {
for b in 0..=FINE_ENERGY_MAX_BITS {
let levels = 1u32 << b;
for f in 0..levels {
let q = fine_correction_q15(b, f).unwrap();
assert!(
q > -FINE_ENERGY_HALF_Q15 && q < FINE_ENERGY_HALF_Q15,
"B_i = {b}, f = {f}, q = {q} escapes (-16384, 16384)"
);
}
}
}
#[test]
fn q15_monotone_increasing_in_f() {
for b in 1..=FINE_ENERGY_MAX_BITS {
let levels = 1u32 << b;
let mut prev = i32::MIN;
for f in 0..levels {
let q = fine_correction_q15(b, f).unwrap();
assert!(q > prev, "B_i = {b}, f = {f}: {q} <= {prev}");
prev = q;
}
}
}
#[test]
fn q15_step_is_uniform() {
for b in 1..=FINE_ENERGY_MAX_BITS {
let levels = 1u32 << b;
let step = (FINE_ENERGY_Q15_ONE as u32 >> b) as i32;
for f in 1..levels {
let here = fine_correction_q15(b, f).unwrap();
let before = fine_correction_q15(b, f - 1).unwrap();
assert_eq!(here - before, step, "B_i = {b}, f = {f}");
}
}
}
#[test]
fn q_generic_matches_q15_at_shift_15() {
for b in 0..=FINE_ENERGY_MAX_BITS {
let levels = 1u32 << b;
for f in 0..levels {
assert_eq!(
fine_correction_q(b, f, 15).unwrap(),
fine_correction_q15(b, f).unwrap() as i64,
"B_i = {b}, f = {f}"
);
}
}
}
#[test]
fn q_generic_db_shift_10_exact() {
assert_eq!(fine_correction_q(1, 0, 10).unwrap(), -256);
assert_eq!(fine_correction_q(1, 1, 10).unwrap(), 256);
assert_eq!(fine_correction_q(2, 0, 10).unwrap(), -384);
}
#[test]
fn final_priority0_before_priority1() {
let prios = vec![
Some(FinalBitPriority::Priority0),
Some(FinalBitPriority::Priority1),
Some(FinalBitPriority::Priority0),
];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Mono, 2);
assert_eq!(plan.granted, vec![true, false, true]);
assert_eq!(plan.bits_used, 2);
assert_eq!(plan.bits_unused, 0);
}
#[test]
fn final_priority1_after_all_priority0() {
let prios = vec![
Some(FinalBitPriority::Priority0),
Some(FinalBitPriority::Priority1),
Some(FinalBitPriority::Priority1),
];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Mono, 3);
assert_eq!(plan.granted, vec![true, true, true]);
assert_eq!(plan.bits_used, 3);
assert_eq!(plan.bits_unused, 0);
}
#[test]
fn final_band_order_within_priority() {
let prios = vec![
Some(FinalBitPriority::Priority0),
Some(FinalBitPriority::Priority0),
None,
None,
Some(FinalBitPriority::Priority0),
];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Mono, 2);
assert_eq!(plan.granted, vec![true, true, false, false, false]);
assert_eq!(plan.bits_used, 2);
assert_eq!(plan.bits_unused, 0);
}
#[test]
fn final_stereo_costs_two_per_band() {
let prios = vec![
Some(FinalBitPriority::Priority0),
Some(FinalBitPriority::Priority0),
];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Stereo, 3);
assert_eq!(plan.granted, vec![true, false]);
assert_eq!(plan.bits_used, 2);
assert_eq!(plan.bits_unused, 1);
}
#[test]
fn final_leftover_unused() {
let prios = vec![
Some(FinalBitPriority::Priority0),
Some(FinalBitPriority::Priority1),
];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Mono, 5);
assert_eq!(plan.granted, vec![true, true]);
assert_eq!(plan.bits_used, 2);
assert_eq!(plan.bits_unused, 3);
}
#[test]
fn final_none_bands_excluded() {
let prios = vec![None, None, None];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Mono, 10);
assert_eq!(plan.granted, vec![false, false, false]);
assert_eq!(plan.bits_used, 0);
assert_eq!(plan.bits_unused, 10);
}
#[test]
fn final_zero_budget_grants_nothing() {
let prios = vec![
Some(FinalBitPriority::Priority0),
Some(FinalBitPriority::Priority1),
];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Mono, 0);
assert_eq!(plan.granted, vec![false, false]);
assert_eq!(plan.bits_used, 0);
assert_eq!(plan.bits_unused, 0);
}
#[test]
fn final_priority0_exhausts_budget_priority1_gets_none() {
let prios = vec![
Some(FinalBitPriority::Priority1),
Some(FinalBitPriority::Priority0),
];
let plan = plan_final_fine_bits(&prios, FineEnergyChannels::Mono, 1);
assert_eq!(plan.granted, vec![false, true]);
assert_eq!(plan.bits_used, 1);
assert_eq!(plan.bits_unused, 0);
}
#[test]
fn final_bits_conserved() {
let prios = vec![
Some(FinalBitPriority::Priority0),
None,
Some(FinalBitPriority::Priority1),
Some(FinalBitPriority::Priority0),
];
for chan in [FineEnergyChannels::Mono, FineEnergyChannels::Stereo] {
for budget in 0..=12u32 {
let plan = plan_final_fine_bits(&prios, chan, budget);
assert_eq!(
plan.bits_used + plan.bits_unused,
budget,
"chan = {chan:?}, budget = {budget}"
);
}
}
}
#[test]
fn final_empty_priorities() {
let plan = plan_final_fine_bits(&[], FineEnergyChannels::Mono, 7);
assert_eq!(plan.granted, Vec::<bool>::new());
assert_eq!(plan.bits_used, 0);
assert_eq!(plan.bits_unused, 7);
}
#[test]
fn display_messages_mention_input() {
let e1 = FineEnergyError::BitsOutOfRange {
provided: 99,
max: FINE_ENERGY_MAX_BITS,
};
assert!(format!("{e1}").contains("99"));
let e2 = FineEnergyError::RefinementOutOfRange { f: 4, levels: 4 };
let m2 = format!("{e2}");
assert!(m2.contains("f=4"));
assert!(m2.contains("4"));
}
}