const TP_OVERSAMPLE: usize = 4;
const TP_FIR_LEN: usize = 48;
const TP_TAPS: usize = TP_FIR_LEN / TP_OVERSAMPLE;
#[rustfmt::skip]
pub const BS1770_PHASES: [[f64; TP_TAPS]; TP_OVERSAMPLE] = [
[
0.0017089843750, 0.0109863281250, -0.0196533203125, 0.0332031250000,
-0.0594482421875, 0.1373291015625, 0.9721679687500, -0.1022949218750,
0.0476074218750, -0.0266113281250, 0.0148925781250, -0.0083007812500,
],
[
-0.0291748046875, 0.0292968750000, -0.0517578125000, 0.0891113281250,
-0.1665039062500, 0.4650878906250, 0.7797851562500, -0.2003173828125,
0.1015625000000, -0.0582275390625, 0.0330810546875, -0.0189208984375,
],
[
-0.0189208984375, 0.0330810546875, -0.0582275390625, 0.1015625000000,
-0.2003173828125, 0.7797851562500, 0.4650878906250, -0.1665039062500,
0.0891113281250, -0.0517578125000, 0.0292968750000, -0.0291748046875,
],
[
-0.0083007812500, 0.0148925781250, -0.0266113281250, 0.0476074218750,
-0.1022949218750, 0.9721679687500, 0.1373291015625, -0.0594482421875,
0.0332031250000, -0.0196533203125, 0.0109863281250, 0.0017089843750,
],
];
fn oversample_4x_bs1770(samples: &[f32]) -> Vec<f64> {
let in_len = samples.len();
if in_len == 0 {
return Vec::new();
}
let out_len = in_len * TP_OVERSAMPLE;
let mut out = vec![0.0f64; out_len];
for n in 0..in_len {
let base = n * TP_OVERSAMPLE;
for p in 0..TP_OVERSAMPLE {
let phase = &BS1770_PHASES[p];
let mut acc = 0.0f64;
for k in 0..TP_TAPS {
if k > n {
break;
}
acc += (samples[n - k] as f64) * phase[k];
}
out[base + p] = acc;
}
}
out
}
pub fn compute_true_peak_db(samples: &[f32]) -> f64 {
if samples.is_empty() {
return f64::NEG_INFINITY;
}
let upsampled = oversample_4x_bs1770(samples);
let peak_abs = upsampled.iter().fold(0.0f64, |max, &x| max.max(x.abs()));
if peak_abs <= 1e-15 {
f64::NEG_INFINITY
} else {
20.0 * peak_abs.log10()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TruePeakOver {
pub position: usize,
pub dbtp: f64,
}
pub fn find_true_peak_overs(samples: &[f32]) -> Vec<TruePeakOver> {
let upsampled = oversample_4x_bs1770(samples);
let mut overs = Vec::new();
let len = upsampled.len();
let mut i = 0;
while i < len {
if upsampled[i].abs() > 1.0 {
let start_sample = i / TP_OVERSAMPLE;
let mut peak = upsampled[i].abs();
i += 1;
while i < len && i / TP_OVERSAMPLE == start_sample {
if upsampled[i].abs() > 1.0 {
peak = peak.max(upsampled[i].abs());
}
i += 1;
}
overs.push(TruePeakOver {
position: start_sample,
dbtp: 20.0 * peak.log10(),
});
} else {
i += 1;
}
}
overs
}
pub fn oversample_4x(samples: &[f32]) -> Vec<f64> {
oversample_4x_bs1770(samples)
}