1use std::f64::consts::PI;
2
3use crate::{Error, validate_rate};
4
5fn bessel_i0(x: f64) -> f64 {
6 let mut sum = 1.0;
7 let mut term = 1.0;
8 for k in 1..100 {
9 term *= (x / (2.0 * k as f64)).powi(2);
10 sum += term;
11 if term < sum * f64::EPSILON {
12 break;
13 }
14 }
15 sum
16}
17
18fn prototype(factor: u32, base_rate_hz: u32) -> Result<Vec<f64>, Error> {
19 validate_rate(base_rate_hz)?;
20 if !matches!(factor, 4 | 8 | 16) {
21 return Err(Error::InvalidConfig("factor must be 4, 8, or 16".into()));
22 }
23 let factor = factor as usize;
24 let attenuation = 100.0;
25 let beta = 0.1102 * (attenuation - 8.7);
26 let transition = PI * 0.186 / factor as f64;
27 let order = ((attenuation - 8.0) / (2.285 * transition)).ceil() as usize;
28 let order = ((order as f64 * 1.1).ceil() as usize).div_ceil(2 * factor) * 2 * factor;
31 let mid = order / 2;
32 let window_scale = bessel_i0(beta);
33 let mut taps = vec![0.0; order + 1];
34 for n in 0..=mid {
35 let distance = n as f64 - mid as f64;
36 let sinc = if distance == 0.0 {
37 1.0 / factor as f64
38 } else {
39 (PI * distance / factor as f64).sin() / (PI * distance)
40 };
41 let r = distance / mid as f64;
42 let window = bessel_i0(beta * (1.0 - r * r).max(0.0).sqrt()) / window_scale;
43 taps[n] = sinc * window;
44 taps[order - n] = taps[n];
45 }
46 let sum: f64 = taps.iter().sum();
47 for tap in &mut taps {
48 *tap /= sum;
49 }
50 Ok(taps)
51}
52
53#[derive(Clone, Debug)]
54struct History {
55 samples: Vec<f64>,
56 next: usize,
57 len: usize,
58}
59
60impl History {
61 fn new(len: usize) -> Self {
62 Self {
63 samples: vec![0.0; 2 * len],
64 next: 0,
65 len,
66 }
67 }
68
69 fn push(&mut self, sample: f32) {
70 self.next = if self.next == 0 {
71 self.len - 1
72 } else {
73 self.next - 1
74 };
75 self.samples[self.next] = sample as f64;
76 self.samples[self.next + self.len] = sample as f64;
77 }
78
79 fn dot(&self, taps: &[f64]) -> f32 {
80 let samples = &self.samples[self.next..self.next + taps.len()];
81 let mut sum = 0.0;
84 let mut coefficients = taps.chunks_exact(8);
85 let mut history = samples.chunks_exact(8);
86 for (t, x) in coefficients.by_ref().zip(history.by_ref()) {
87 let a = t[0] * x[0] + t[1] * x[1];
88 let b = t[2] * x[2] + t[3] * x[3];
89 let c = t[4] * x[4] + t[5] * x[5];
90 let d = t[6] * x[6] + t[7] * x[7];
91 sum += (a + b) + (c + d);
92 }
93 for (&tap, &sample) in coefficients.remainder().iter().zip(history.remainder()) {
94 sum += tap * sample;
95 }
96 sum as f32
97 }
98
99 fn reset(&mut self) {
100 self.samples.fill(0.0);
101 self.next = 0;
102 }
103}
104
105fn validate_block(input: &[f32], finished: bool) -> Result<(), Error> {
106 if finished {
107 return Err(Error::InvalidInput(
108 "process after flush requires reset".into(),
109 ));
110 }
111 if input.iter().any(|sample| !sample.is_finite()) {
112 return Err(Error::InvalidInput("non-finite sample".into()));
113 }
114 Ok(())
115}
116
117#[derive(Clone, Debug)]
119pub struct Upsampler {
120 phases: Vec<Vec<f64>>,
121 history: History,
122 delay: usize,
123 active: bool,
124 finished: bool,
125}
126
127impl Upsampler {
128 pub fn new(factor: u32, base_rate_hz: u32) -> Result<Self, Error> {
131 let taps = prototype(factor, base_rate_hz)?;
132 let factor = factor as usize;
133 let phases: Vec<Vec<f64>> = (0..factor)
134 .map(|phase| {
135 taps.iter()
136 .skip(phase)
137 .step_by(factor)
138 .map(|tap| tap * factor as f64)
139 .collect()
140 })
141 .collect();
142 let history = History::new(phases[0].len());
143 Ok(Self {
144 phases,
145 history,
146 delay: (taps.len() - 1) / 2,
147 active: false,
148 finished: false,
149 })
150 }
151
152 pub fn process(&mut self, input: &[f32], output: &mut Vec<f32>) -> Result<(), Error> {
155 validate_block(input, self.finished)?;
156 for &sample in input {
157 self.push(sample, output);
158 }
159 self.active |= !input.is_empty();
160 Ok(())
161 }
162
163 fn push(&mut self, sample: f32, output: &mut Vec<f32>) {
164 self.history.push(sample);
165 output.extend(self.phases.iter().map(|phase| self.history.dot(phase)));
166 }
167
168 pub fn flush(&mut self, output: &mut Vec<f32>) {
171 if self.active && !self.finished {
172 for _ in 0..self.history.len - 1 {
173 self.push(0.0, output);
174 }
175 }
176 self.finished = true;
177 }
178
179 pub fn delay(&self) -> usize {
181 self.delay
182 }
183
184 pub fn reset(&mut self) {
186 self.history.reset();
187 self.active = false;
188 self.finished = false;
189 }
190}
191
192#[derive(Clone, Debug)]
194pub struct Downsampler {
195 taps: Vec<f64>,
196 factor: usize,
197 history: History,
198 phase: usize,
199 active: bool,
200 finished: bool,
201}
202
203impl Downsampler {
204 pub fn new(factor: u32, base_rate_hz: u32) -> Result<Self, Error> {
207 let taps = prototype(factor, base_rate_hz)?;
208 let history = History::new(taps.len());
209 Ok(Self {
210 taps,
211 factor: factor as usize,
212 history,
213 phase: 0,
214 active: false,
215 finished: false,
216 })
217 }
218
219 pub fn process(&mut self, input: &[f32], output: &mut Vec<f32>) -> Result<(), Error> {
222 validate_block(input, self.finished)?;
223 for &sample in input {
224 self.push(sample, output);
225 }
226 self.active |= !input.is_empty();
227 Ok(())
228 }
229
230 fn push(&mut self, sample: f32, output: &mut Vec<f32>) {
231 self.history.push(sample);
232 if self.phase == 0 {
233 output.push(self.history.dot(&self.taps));
234 }
235 self.phase = (self.phase + 1) & (self.factor - 1);
236 }
237
238 pub fn flush(&mut self, output: &mut Vec<f32>) {
241 if self.active && !self.finished {
242 for _ in 0..self.taps.len() - 1 {
243 self.push(0.0, output);
244 }
245 }
246 self.finished = true;
247 }
248
249 pub fn delay(&self) -> usize {
251 (self.taps.len() - 1) / (2 * self.factor)
252 }
253
254 pub fn reset(&mut self) {
256 self.history.reset();
257 self.phase = 0;
258 self.active = false;
259 self.finished = false;
260 }
261}