1use core::marker::PhantomData;
14use core::num::NonZeroUsize;
15use core::cell::Cell;
16use core::ops::AddAssign;
17
18use spectrusty_core::{
19 clock::FTs,
20 audio::{SampleDelta, Blep, IntoSample, FromSample, MulNorm}
21};
22
23const PI2: f64 = core::f64::consts::PI * 2.0;
24const PHASE_COUNT: usize = 32;
26const STEP_WIDTH: usize = 24;
28
29pub trait BandLimOpt {
31 const LOW_PASS: f64 = 0.999;
33 const HIGH_PASS: f32 = 0.999;
35}
36
37pub struct BandLimWide;
39impl BandLimOpt for BandLimWide {}
40
41pub struct BandLimLowTreb;
43impl BandLimOpt for BandLimLowTreb {
44 const LOW_PASS: f64 = 0.899;
45}
46
47pub struct BandLimLowBass;
49impl BandLimOpt for BandLimLowBass {
50 const HIGH_PASS: f32 = 0.899;
51}
52
53pub struct BandLimNarrow;
55impl BandLimOpt for BandLimNarrow {
56 const LOW_PASS: f64 = 0.899;
57 const HIGH_PASS: f32 = 0.899;
58}
59
60pub struct BandLimited<T, O=BandLimWide> {
66 steps: [[T; STEP_WIDTH]; PHASE_COUNT],
67 diffs: Vec<T>,
68 channels: NonZeroUsize,
69 time_rate: f64,
70 frame_time: f64,
71 start_time: f64,
72 sums: Box<[(T, Cell<Option<T>>)]>,
73 last_nsamples: Option<usize>,
74 _options: PhantomData<O>
75}
76
77impl<T: Copy + Default, O> BandLimited<T, O> {
78 pub fn reset(&mut self) {
80 for d in self.diffs.iter_mut() { *d = T::default(); }
81 for s in self.sums.iter_mut() { *s = (T::default(), Cell::default()); }
82 self.last_nsamples = None;
83 self.start_time = 0.0;
84 }
85 pub fn shrink_to_fit(&mut self) {
87 self.diffs.shrink_to_fit();
88 }
89 pub fn set_frame_time(&mut self, frame_time: f64, margin_time: f64) {
100 let max_samples = (frame_time + margin_time).ceil() as usize;
101 let required_len = (max_samples + STEP_WIDTH + 1) * self.channels.get();
102 if self.diffs.len() != required_len {
104 self.diffs.resize(required_len, T::default());
105 }
106 self.frame_time = frame_time;
107 }
108 pub fn is_frame_ended(&mut self) -> bool {
112 self.last_nsamples.is_some()
113 }
114 pub fn end_frame(&mut self, time_end: f64) -> usize {
121 if self.last_nsamples.is_none() {
122 let samples = (time_end - self.start_time).trunc();
123 let num_samples = samples as usize;
124 self.last_nsamples = Some(num_samples);
125 num_samples
126 }
127 else {
128 panic!("BandLimited frame already over");
129 }
130 }
131
132 #[inline]
133 fn prepare_next_frame(&mut self, num_samples: usize) {
134 let channels = self.channels.get();
135 let chans_nsamples = num_samples*channels;
136 let chans_step_width = STEP_WIDTH*channels;
137 self.diffs.copy_within(chans_nsamples..chans_nsamples+chans_step_width, 0);
138 for p in self.diffs[chans_step_width..chans_nsamples+chans_step_width].iter_mut() {
139 *p = T::default();
140 }
141 }
142}
143
144impl<T,O> BandLimited<T,O>
145where T: Copy + Default + AddAssign + MulNorm + FromSample<f32>,
146 O: BandLimOpt,
147 {
149 pub fn new(channels: usize) -> Self {
159 let channels = NonZeroUsize::new(channels).expect("BandLimited: channels should be 1 or more");
160 let mut steps = [[T::default();STEP_WIDTH];PHASE_COUNT];
162 const MASTER_SIZE: usize = STEP_WIDTH * PHASE_COUNT;
163 let mut master = [0.5f64;MASTER_SIZE];
164 let mut gain: f64 = 0.5 / 0.777; const SINE_SIZE: usize = 256 * PHASE_COUNT + 2;
166 let max_harmonic: usize = SINE_SIZE / 2 / PHASE_COUNT;
167 for h in (1..=max_harmonic).step_by(2) {
168 let amplitude: f64 = gain / h as f64;
169 let to_angle: f64 = PI2 / SINE_SIZE as f64 * h as f64;
170 for (i, m) in master.iter_mut().enumerate() {
173 *m += ( (i as isize - MASTER_SIZE as isize / 2) as f64 * to_angle ).sin() * amplitude;
174 }
175 gain *= O::LOW_PASS;
176 }
177 for (phase, step) in steps.iter_mut().enumerate() {
179 let mut error: f64 = 1.0;
180 let mut prev: f64 = 0.0;
181 for (i, s) in step.iter_mut().enumerate() {
182 let cur: f64 = master[i * PHASE_COUNT + (PHASE_COUNT - 1 - phase)];
183 let delta: f64 = cur - prev;
184 error -= delta;
185 prev = cur;
186 *s = T::from_sample(delta as f32);
187 }
188 step[STEP_WIDTH / 2 ] += T::from_sample((error * 0.5) as f32);
195 if phase < 16 {
196 step[STEP_WIDTH / 2 - 1] += T::from_sample((error * 0.5) as f32);
197 }
198 else {
199 step[STEP_WIDTH / 2 + 1] += T::from_sample((error * 0.5) as f32);
200 }
201 }
208
209 BandLimited {
210 steps,
211 diffs: Vec::new(),
212 channels,
213 time_rate: 0.0,
214 frame_time: 0.0,
215 start_time: 0.0,
216 sums: vec![(T::default(), Cell::default()); channels.get()].into_boxed_slice(),
217 last_nsamples: None,
218 _options: PhantomData
219 }
220 }
221 pub fn next_frame(&mut self) {
226 let num_samples = self.last_nsamples.take().expect("BandLimited frame not ended");
227 self.start_time += num_samples as f64 - self.frame_time;
228 for (channel, (sum_tgt, sum_end)) in self.sums.iter_mut().enumerate() {
229 *sum_tgt = match sum_end.take() {
230 Some(sum) => sum,
231 None => {
232 let channels = self.channels.get();
233 let mut sum = *sum_tgt;
234 for diff in self.diffs[..num_samples*channels].iter().skip(channel).step_by(channels) {
235 sum = sum.saturating_add(*diff)
236 .mul_norm(T::from_sample(O::HIGH_PASS));
237 }
238 sum
239 }
240 };
241 }
242 self.prepare_next_frame(num_samples);
243 }
244}
245
246impl<T,O> BandLimited<T,O>
247where T: Copy + MulNorm + FromSample<f32>,
248 O: BandLimOpt
249{
250 pub fn sum_iter<'a, S: 'a>(&'a self, channel: usize) -> impl Iterator<Item=S> + ExactSizeIterator + 'a
256 where T: IntoSample<S>
257 {
258 let channels = self.channels.get();
259 if channel >= channels {
260 panic!("Invalid channel: {}, should match: 0..{}", channel, channels);
261 }
262 let num_samples = self.last_nsamples.expect("BandLimited frame not ended");
263 let diffs = self.diffs[..num_samples*channels].iter().skip(channel).step_by(channels);
264 BandLimitedSumIter {
265 diffs,
266 sum_end: &self.sums[channel].1,
267 sum: self.sums[channel].0,
268 _output: PhantomData::<S>,
269 _options: PhantomData::<O>,
270 }
271 }
272}
273
274struct BandLimitedSumIter<'a, T: Copy + MulNorm + IntoSample<S> + FromSample<f32>,
275 O: BandLimOpt,
276 I: Iterator<Item=&'a T>,
277 S> {
278 diffs: I,
279 sum_end: &'a Cell<Option<T>>,
280 sum: T,
281 _output: PhantomData<S>,
282 _options: PhantomData<O>,
283}
284
285impl<'a, T, O, I, S> Drop for BandLimitedSumIter<'a, T, O, I, S>
286where I: Iterator<Item=&'a T>,
287 O: BandLimOpt,
288 T: Copy + MulNorm + IntoSample<S> + FromSample<f32>
289{
290 #[allow(clippy::useless_conversion)]
291 fn drop(&mut self) {
292 if self.sum_end.get().is_none() {
293 for _ in self.into_iter() {}
294 self.sum_end.set(Some(self.sum))
295 }
296 }
297}
298
299impl<'a, T, O, I, S> std::iter::ExactSizeIterator for BandLimitedSumIter<'a, T, O, I, S>
300where I: Iterator<Item=&'a T> + ExactSizeIterator,
301 T: Copy + MulNorm + IntoSample<S> + FromSample<f32>,
302 O: BandLimOpt
303{
304 fn len(&self) -> usize {
305 self.diffs.len()
306 }
307}
308
309impl<'a, T, O, I, S> Iterator for BandLimitedSumIter<'a, T, O, I, S>
310where I: Iterator<Item=&'a T>,
311 T: Copy + MulNorm + IntoSample<S> + FromSample<f32>,
312 O: BandLimOpt
313{
314 type Item = S;
315
316 fn next(&mut self) -> Option<S> {
317 self.diffs.next().map(|&delta| {
318 let sum = self.sum.saturating_add(delta);
319 self.sum = sum.mul_norm(T::from_sample(O::HIGH_PASS));
320 sum.into_sample()
321 })
322 }
323}
324
325impl<T, O> Blep for BandLimited<T, O>
326where T: Copy + Default + SampleDelta + MulNorm
327{
328 type SampleDelta = T;
329
330 #[inline]
331 fn ensure_frame_time(&mut self, sample_rate: u32, ts_rate: f64, frame_ts: FTs, margin_ts: FTs) {
332 let time_rate = sample_rate as f64 / ts_rate;
333 assert!(time_rate > 0.0);
334 let frame_time = time_rate * frame_ts as f64;
335 assert!(frame_time > 0.0);
336 let margin_time = time_rate * 2.0 * margin_ts as f64;
337 assert!(margin_time >= 0.0);
338 self.time_rate = time_rate;
339 self.set_frame_time(frame_time, margin_time);
340 }
341
342 #[inline]
343 fn end_frame(&mut self, timestamp: FTs) -> usize {
344 debug_assert!(timestamp > 0);
345 self.end_frame(self.time_rate * timestamp as f64)
346 }
347
348 #[inline]
349 fn add_step(&mut self, channel: usize, timestamp: FTs, delta: T) {
350 let channels = self.channels.get();
351 debug_assert!(channel < channels);
352 let time = self.time_rate * timestamp as f64 - self.start_time;
353 let index = time.trunc() as usize * channels + channel;
354 let phase = ((time.fract() * PHASE_COUNT as f64).trunc() as usize).rem_euclid(PHASE_COUNT);
356 for (dp, phase) in self.diffs[index..index + STEP_WIDTH*channels]
357 .iter_mut().step_by(channels)
358 .zip(self.steps[phase].iter()) {
359 *dp = dp.saturating_add(phase.mul_norm(delta));
360 }
361 }
362}