radiorust/blocks/
resampling.rs1use crate::bufferpool::*;
4use crate::flow::*;
5use crate::impl_block_trait;
6use crate::math::*;
7use crate::numbers::*;
8use crate::signal::*;
9use crate::windowing::{self, Window};
10
11use tokio::task::spawn;
12
13pub struct Downsampler<Flt> {
15 receiver_connector: ReceiverConnector<Signal<Complex<Flt>>>,
16 sender_connector: SenderConnector<Signal<Complex<Flt>>>,
17}
18
19impl_block_trait! { <Flt> Consumer<Signal<Complex<Flt>>> for Downsampler<Flt> }
20impl_block_trait! { <Flt> Producer<Signal<Complex<Flt>>> for Downsampler<Flt> }
21
22impl<Flt> Downsampler<Flt>
23where
24 Flt: Float,
25{
26 pub fn new(output_chunk_len: usize, output_rate: f64, bandwidth: f64) -> Self {
39 Self::with_quality(output_chunk_len, output_rate, bandwidth, 3.0)
40 }
41 pub fn with_quality(
46 output_chunk_len: usize,
47 output_rate: f64,
48 bandwidth: f64,
49 quality: f64,
50 ) -> Self {
51 assert!(output_rate >= 0.0, "output sample rate must be positive");
52 assert!(bandwidth >= 0.0, "bandwidth must be positive");
53 assert!(
54 bandwidth < output_rate,
55 "bandwidth must be smaller than output sample rate"
56 );
57 let (mut receiver, receiver_connector) = new_receiver::<Signal<Complex<Flt>>>();
58 let (sender, sender_connector) = new_sender::<Signal<Complex<Flt>>>();
59 let mut buf_pool = ChunkBufPool::<Complex<Flt>>::new();
60 let mut output_chunk = buf_pool.get_with_capacity(output_chunk_len);
61 spawn(async move {
62 let margin = (output_rate - bandwidth) / 2.0;
63 let mut prev_input_rate: Option<f64> = None;
64 let mut ir: Vec<Flt> = Default::default();
65 let mut ringbuf: Vec<Complex<Flt>> = Default::default();
66 let mut ringbuf_pos: usize = Default::default();
67 let mut pos: f64 = Default::default();
68 loop {
69 let Ok(signal) = receiver.recv().await else { return; };
70 match signal {
71 Signal::Samples {
72 sample_rate: input_rate,
73 chunk: input_chunk,
74 } => {
75 if Some(input_rate) != prev_input_rate {
76 prev_input_rate = Some(input_rate);
77 assert!(input_rate >= 0.0, "input sample rate must be positive");
78 assert!(
79 input_rate >= output_rate,
80 "input sample rate must be greater than or equal to output sample rate"
81 );
82 let ir_len: usize = (input_rate / margin * quality).ceil() as usize;
83 assert!(ir_len > 0);
84 let ir_len_flt = ir_len as f64;
85 let window = windowing::Kaiser::with_null_at_bin(
86 ir_len_flt * margin / input_rate,
87 );
88 let mut ir_buf: Vec<f64> = Vec::with_capacity(ir_len);
89 let mut energy = 0.0;
90 for i in 0..ir_len {
91 let x = (i as f64 + 0.5) - ir_len_flt / 2.0;
92 let y = sinc(x * output_rate / input_rate)
93 * window.relative_value_at(x * 2.0 / ir_len_flt);
94 ir_buf.push(y);
95 energy += y * y;
96 }
97 let scale = energy.sqrt().recip();
98 ir = ir_buf.into_iter().map(|y| flt!(y * scale)).collect();
99 ringbuf = vec![Complex::from(Flt::zero()); ir_len];
100 ringbuf_pos = 0;
101 pos = 0.0;
102 }
103 for &sample in input_chunk.iter() {
104 ringbuf[ringbuf_pos] = sample;
105 ringbuf_pos += 1;
106 if ringbuf_pos == ir.len() {
107 ringbuf_pos = 0;
108 }
109 pos += output_rate;
110 if pos >= input_rate {
111 pos -= input_rate;
112 let mut sum: Complex<Flt> = Complex::from(Flt::zero());
113 let mut ir_iter = ir.iter();
114 let mut next_ir = || *ir_iter.next().unwrap();
115 for i in ringbuf_pos..ir.len() {
116 sum += ringbuf[i] * next_ir();
117 }
118 for i in 0..ringbuf_pos {
119 sum += ringbuf[i] * next_ir();
120 }
121 output_chunk.push(sum);
122 if output_chunk.len() >= output_chunk_len {
123 let Ok(()) = sender
124 .send(Signal::Samples {
125 sample_rate: output_rate,
126 chunk: output_chunk.finalize(),
127 })
128 .await
129 else { return; };
130 output_chunk = buf_pool.get_with_capacity(output_chunk_len);
131 }
132 }
133 }
134 }
135 event @ Signal::Event { .. } => {
136 let Ok(()) = sender.send(event).await else { return; };
137 }
138 }
139 }
140 });
141 Self {
142 receiver_connector,
143 sender_connector,
144 }
145 }
146}
147
148pub struct Upsampler<Flt> {
150 receiver_connector: ReceiverConnector<Signal<Complex<Flt>>>,
151 sender_connector: SenderConnector<Signal<Complex<Flt>>>,
152}
153
154impl_block_trait! { <Flt> Consumer<Signal<Complex<Flt>>> for Upsampler<Flt> }
155impl_block_trait! { <Flt> Producer<Signal<Complex<Flt>>> for Upsampler<Flt> }
156
157impl<Flt> Upsampler<Flt>
158where
159 Flt: Float,
160{
161 pub fn new(output_chunk_len: usize, output_rate: f64, bandwidth: f64) -> Self {
174 Self::with_quality(output_chunk_len, output_rate, bandwidth, 3.0)
175 }
176 pub fn with_quality(
181 output_chunk_len: usize,
182 output_rate: f64,
183 bandwidth: f64,
184 quality: f64,
185 ) -> Self {
186 assert!(output_rate >= 0.0, "output sample rate must be positive");
187 assert!(bandwidth >= 0.0, "bandwidth must be positive");
188 let (mut receiver, receiver_connector) = new_receiver::<Signal<Complex<Flt>>>();
189 let (sender, sender_connector) = new_sender::<Signal<Complex<Flt>>>();
190 let mut buf_pool = ChunkBufPool::<Complex<Flt>>::new();
191 let mut output_chunk = buf_pool.get_with_capacity(output_chunk_len);
192 spawn(async move {
193 let mut prev_input_rate: Option<f64> = None;
194 let mut ir: Vec<Flt> = Default::default();
195 let mut ringbuf: Vec<Complex<Flt>> = Default::default();
196 let mut ringbuf_pos: usize = Default::default();
197 let mut pos: f64 = Default::default();
198 loop {
199 let Ok(signal) = receiver.recv().await else { return; };
200 match signal {
201 Signal::Samples {
202 sample_rate: input_rate,
203 chunk: input_chunk,
204 } => {
205 if Some(input_rate) != prev_input_rate {
206 prev_input_rate = Some(input_rate);
207 assert!(input_rate >= 0.0, "input sample rate must be positive");
208 assert!(
209 input_rate <= output_rate,
210 "input sample rate must be smaller than or equal to output sample rate"
211 );
212 assert!(
213 bandwidth < input_rate,
214 "bandwidth must be smaller than input sample rate"
215 );
216 let margin = (input_rate - bandwidth) / 2.0;
217 let ir_len: usize = (output_rate / margin * quality).ceil() as usize;
218 assert!(ir_len > 0);
219 let ir_len_flt = ir_len as f64;
220 let window = windowing::Kaiser::with_null_at_bin(
221 ir_len_flt * margin / output_rate,
222 );
223 let mut ir_buf: Vec<f64> = Vec::with_capacity(ir_len);
224 let mut energy = 0.0;
225 for i in 0..ir_len {
226 let x = (i as f64 + 0.5) - ir_len_flt / 2.0;
227 let y = sinc(x * input_rate / output_rate)
228 * window.relative_value_at(x * 2.0 / ir_len_flt);
229 ir_buf.push(y);
230 energy += y * y;
231 }
232 let scale = energy.sqrt().recip();
233 ir = ir_buf.into_iter().map(|y| flt!(y * scale)).collect();
234 ringbuf = vec![Complex::from(Flt::zero()); ir_len];
235 ringbuf_pos = 0;
236 pos = 0.0;
237 }
238 for &sample in input_chunk.iter() {
239 let mut ir_iter = ir.iter();
240 let mut next_ir = || *ir_iter.next().unwrap();
241 for i in ringbuf_pos..ir.len() {
242 ringbuf[i] += sample * next_ir();
243 }
244 for i in 0..ringbuf_pos {
245 ringbuf[i] += sample * next_ir();
246 }
247 while pos < output_rate {
248 output_chunk.push(ringbuf[ringbuf_pos]);
249 ringbuf[ringbuf_pos] = Complex::from(Flt::zero());
250 if output_chunk.len() >= output_chunk_len {
251 let Ok(()) = sender
252 .send(Signal::Samples {
253 sample_rate: output_rate,
254 chunk: output_chunk.finalize(),
255 })
256 .await
257 else { return; };
258 output_chunk = buf_pool.get_with_capacity(output_chunk_len);
259 }
260 ringbuf_pos += 1;
261 if ringbuf_pos >= ir.len() {
262 ringbuf_pos = 0;
263 }
264 pos += input_rate;
265 }
266 pos -= output_rate;
267 }
268 }
269 event @ Signal::Event { .. } => {
270 let Ok(()) = sender.send(event).await else { return; };
271 }
272 }
273 }
274 });
275 Upsampler {
276 receiver_connector,
277 sender_connector,
278 }
279 }
280}
281
282#[cfg(test)]
283mod tests {}