use super::{cic5::Downsample2CIC5, fir, upsampler::SimpleUpsampler, Stream, Tag};
use num_complex::Complex;
pub struct SampleRateAdapter {
upsampler: Option<SimpleUpsampler>,
chain: DecimationChain,
}
enum DecimationChain {
Direct96k,
From192k { ds1: Downsample2CIC5 },
From384k {
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
},
From768k {
ds3: Downsample2CIC5,
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
},
From1536k {
ds4: Downsample2CIC5,
ds3: Downsample2CIC5,
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
},
From3072k {
ds5: Downsample2CIC5,
ds4: Downsample2CIC5,
ds3: Downsample2CIC5,
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
},
From6144k {
ds6: Downsample2CIC5,
ds5: Downsample2CIC5,
ds4: Downsample2CIC5,
ds3: Downsample2CIC5,
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
},
From12288k {
ds7: Downsample2CIC5,
ds6: Downsample2CIC5,
ds5: Downsample2CIC5,
ds4: Downsample2CIC5,
ds3: Downsample2CIC5,
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
},
From288k { dsk: fir::DownsampleKFilter },
From576k {
ds1: Downsample2CIC5,
dsk: fir::DownsampleKFilter,
},
From1152k {
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
dsk: fir::DownsampleKFilter,
},
From2304k {
ds3: Downsample2CIC5,
ds2: Downsample2CIC5,
ds1: Downsample2CIC5,
dsk: fir::DownsampleKFilter,
},
}
impl SampleRateAdapter {
pub fn new(sample_rate: u32) -> Self {
const STANDARD_RATES: &[u32] = &[
96_000, 192_000, 288_000, 384_000, 576_000, 768_000, 1_152_000, 1_536_000, 2_304_000,
3_072_000, 6_144_000, 12_288_000,
];
if STANDARD_RATES.contains(&sample_rate) {
return Self {
upsampler: None,
chain: DecimationChain::new(sample_rate),
};
}
let target_rate = STANDARD_RATES
.iter()
.find(|&&r| r > sample_rate)
.copied()
.unwrap_or_else(|| {
panic!(
"Sample rate {} Hz is too high (max supported: {} Hz)",
sample_rate, 12_288_000
)
});
Self {
upsampler: Some(SimpleUpsampler::new(sample_rate, target_rate)),
chain: DecimationChain::new(target_rate),
}
}
pub fn process(&mut self, samples: &[Complex<f32>]) -> Vec<Complex<f32>> {
let mut tag = Tag::default();
let upsampled = if let Some(ref mut upsampler) = self.upsampler {
upsampler.receive(samples, &mut tag)
} else {
samples.to_vec()
};
self.chain.receive(&upsampled, &mut tag)
}
pub fn reset(&mut self) {
if let Some(ref mut upsampler) = self.upsampler {
upsampler.reset();
}
self.chain.reset();
}
pub fn input_sample_rate(&self) -> u32 {
if let Some(ref upsampler) = self.upsampler {
upsampler.input_rate()
} else {
self.chain.input_rate()
}
}
pub const fn output_sample_rate(&self) -> u32 {
96_000
}
}
impl DecimationChain {
fn new(sample_rate: u32) -> Self {
match sample_rate {
96_000 => Self::Direct96k,
192_000 => Self::From192k {
ds1: Downsample2CIC5::new(),
},
384_000 => Self::From384k {
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
},
768_000 => Self::From768k {
ds3: Downsample2CIC5::new(),
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
},
1_536_000 => Self::From1536k {
ds4: Downsample2CIC5::new(),
ds3: Downsample2CIC5::new(),
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
},
3_072_000 => Self::From3072k {
ds5: Downsample2CIC5::new(),
ds4: Downsample2CIC5::new(),
ds3: Downsample2CIC5::new(),
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
},
6_144_000 => Self::From6144k {
ds6: Downsample2CIC5::new(),
ds5: Downsample2CIC5::new(),
ds4: Downsample2CIC5::new(),
ds3: Downsample2CIC5::new(),
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
},
12_288_000 => Self::From12288k {
ds7: Downsample2CIC5::new(),
ds6: Downsample2CIC5::new(),
ds5: Downsample2CIC5::new(),
ds4: Downsample2CIC5::new(),
ds3: Downsample2CIC5::new(),
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
},
288_000 => Self::From288k {
dsk: fir::DownsampleKFilter::with_params(3, fir::BLACKMAN_HARRIS_28_3),
},
576_000 => Self::From576k {
ds1: Downsample2CIC5::new(),
dsk: fir::DownsampleKFilter::with_params(3, fir::BLACKMAN_HARRIS_28_3),
},
1_152_000 => Self::From1152k {
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
dsk: fir::DownsampleKFilter::with_params(3, fir::BLACKMAN_HARRIS_28_3),
},
2_304_000 => Self::From2304k {
ds3: Downsample2CIC5::new(),
ds2: Downsample2CIC5::new(),
ds1: Downsample2CIC5::new(),
dsk: fir::DownsampleKFilter::with_params(3, fir::BLACKMAN_HARRIS_28_3),
},
_ => panic!(
"Unsupported standard sample rate: {}. This is an internal error.",
sample_rate
),
}
}
fn receive(&mut self, samples: &[Complex<f32>], tag: &mut Tag) -> Vec<Complex<f32>> {
match self {
Self::Direct96k => samples.to_vec(),
Self::From192k { ds1 } => ds1.receive(samples, tag),
Self::From384k { ds2, ds1 } => {
let temp = ds2.receive(samples, tag);
ds1.receive(&temp, tag)
}
Self::From768k { ds3, ds2, ds1 } => {
let temp1 = ds3.receive(samples, tag);
let temp2 = ds2.receive(&temp1, tag);
ds1.receive(&temp2, tag)
}
Self::From1536k { ds4, ds3, ds2, ds1 } => {
let temp1 = ds4.receive(samples, tag);
let temp2 = ds3.receive(&temp1, tag);
let temp3 = ds2.receive(&temp2, tag);
ds1.receive(&temp3, tag)
}
Self::From3072k {
ds5,
ds4,
ds3,
ds2,
ds1,
} => {
let temp1 = ds5.receive(samples, tag);
let temp2 = ds4.receive(&temp1, tag);
let temp3 = ds3.receive(&temp2, tag);
let temp4 = ds2.receive(&temp3, tag);
ds1.receive(&temp4, tag)
}
Self::From6144k {
ds6,
ds5,
ds4,
ds3,
ds2,
ds1,
} => {
let temp1 = ds6.receive(samples, tag);
let temp2 = ds5.receive(&temp1, tag);
let temp3 = ds4.receive(&temp2, tag);
let temp4 = ds3.receive(&temp3, tag);
let temp5 = ds2.receive(&temp4, tag);
ds1.receive(&temp5, tag)
}
Self::From12288k {
ds7,
ds6,
ds5,
ds4,
ds3,
ds2,
ds1,
} => {
let temp1 = ds7.receive(samples, tag);
let temp2 = ds6.receive(&temp1, tag);
let temp3 = ds5.receive(&temp2, tag);
let temp4 = ds4.receive(&temp3, tag);
let temp5 = ds3.receive(&temp4, tag);
let temp6 = ds2.receive(&temp5, tag);
ds1.receive(&temp6, tag)
}
Self::From288k { dsk } => dsk.receive(samples, tag),
Self::From576k { ds1, dsk } => {
let temp = ds1.receive(samples, tag);
dsk.receive(&temp, tag)
}
Self::From1152k { ds2, ds1, dsk } => {
let temp1 = ds2.receive(samples, tag);
let temp2 = ds1.receive(&temp1, tag);
dsk.receive(&temp2, tag)
}
Self::From2304k { ds3, ds2, ds1, dsk } => {
let temp1 = ds3.receive(samples, tag);
let temp2 = ds2.receive(&temp1, tag);
let temp3 = ds1.receive(&temp2, tag);
dsk.receive(&temp3, tag)
}
}
}
fn reset(&mut self) {
match self {
Self::Direct96k => {}
Self::From192k { ds1 } => {
ds1.reset();
}
Self::From384k { ds2, ds1 } => {
ds2.reset();
ds1.reset();
}
Self::From768k { ds3, ds2, ds1 } => {
ds3.reset();
ds2.reset();
ds1.reset();
}
Self::From1536k { ds4, ds3, ds2, ds1 } => {
ds4.reset();
ds3.reset();
ds2.reset();
ds1.reset();
}
Self::From3072k {
ds5,
ds4,
ds3,
ds2,
ds1,
} => {
ds5.reset();
ds4.reset();
ds3.reset();
ds2.reset();
ds1.reset();
}
Self::From6144k {
ds6,
ds5,
ds4,
ds3,
ds2,
ds1,
} => {
ds6.reset();
ds5.reset();
ds4.reset();
ds3.reset();
ds2.reset();
ds1.reset();
}
Self::From12288k {
ds7,
ds6,
ds5,
ds4,
ds3,
ds2,
ds1,
} => {
ds7.reset();
ds6.reset();
ds5.reset();
ds4.reset();
ds3.reset();
ds2.reset();
ds1.reset();
}
Self::From288k { dsk } => {
dsk.reset();
}
Self::From576k { ds1, dsk } => {
ds1.reset();
dsk.reset();
}
Self::From1152k { ds2, ds1, dsk } => {
ds2.reset();
ds1.reset();
dsk.reset();
}
Self::From2304k { ds3, ds2, ds1, dsk } => {
ds3.reset();
ds2.reset();
ds1.reset();
dsk.reset();
}
}
}
fn input_rate(&self) -> u32 {
match self {
Self::Direct96k => 96_000,
Self::From192k { .. } => 192_000,
Self::From384k { .. } => 384_000,
Self::From768k { .. } => 768_000,
Self::From1536k { .. } => 1_536_000,
Self::From3072k { .. } => 3_072_000,
Self::From6144k { .. } => 6_144_000,
Self::From12288k { .. } => 12_288_000,
Self::From288k { .. } => 288_000,
Self::From576k { .. } => 576_000,
Self::From1152k { .. } => 1_152_000,
Self::From2304k { .. } => 2_304_000,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_adapter_creation_96k() {
let adapter = SampleRateAdapter::new(96_000);
assert_eq!(adapter.input_sample_rate(), 96_000);
assert_eq!(adapter.output_sample_rate(), 96_000);
}
#[test]
fn test_adapter_creation_288k() {
let adapter = SampleRateAdapter::new(288_000);
assert_eq!(adapter.input_sample_rate(), 288_000);
assert_eq!(adapter.output_sample_rate(), 96_000);
}
#[test]
fn test_adapter_creation_3m_upsampled() {
let adapter = SampleRateAdapter::new(3_000_000);
assert_eq!(adapter.input_sample_rate(), 3_000_000);
assert_eq!(adapter.output_sample_rate(), 96_000);
}
#[test]
fn test_adapter_creation_3072k_exact() {
let adapter = SampleRateAdapter::new(3_072_000);
assert_eq!(adapter.input_sample_rate(), 3_072_000);
assert_eq!(adapter.output_sample_rate(), 96_000);
}
#[test]
fn test_direct_96k_passthrough() {
let mut adapter = SampleRateAdapter::new(96_000);
let input: Vec<Complex<f32>> = vec![Complex::new(1.0, 0.5); 960];
let output = adapter.process(&input);
assert_eq!(output.len(), 960);
}
#[test]
fn test_from_192k() {
let mut adapter = SampleRateAdapter::new(192_000);
let input: Vec<Complex<f32>> = vec![Complex::new(1.0, 0.0); 1920]; let output = adapter.process(&input);
assert_eq!(output.len(), 960); }
#[test]
fn test_from_3m_upsampled() {
let mut adapter = SampleRateAdapter::new(3_000_000);
let input: Vec<Complex<f32>> = vec![Complex::new(1.0, 0.0); 30000]; let output = adapter.process(&input);
assert!(output.len() > 900 && output.len() < 1000);
}
#[test]
fn test_from_6m_upsampled() {
let mut adapter = SampleRateAdapter::new(6_000_000);
let input: Vec<Complex<f32>> = vec![Complex::new(1.0, 0.0); 60000]; let output = adapter.process(&input);
assert!(output.len() > 900 && output.len() < 1000);
}
#[test]
fn test_reset() {
let mut adapter = SampleRateAdapter::new(288_000);
let input: Vec<Complex<f32>> = vec![Complex::new(1.0, 0.0); 2880];
let _ = adapter.process(&input);
adapter.reset();
let output = adapter.process(&input);
assert!(!output.is_empty());
}
}