1use crate::dsp::{Complex32, DefaultPlanner, Fft, FftPlanner};
5use alloc::boxed::Box;
6use alloc::vec;
7use alloc::vec::Vec;
8use core::f32::consts::PI;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum WindowType {
13 Sine,
15 KaiserBesselDerived,
17 Vorbis,
19}
20
21pub const LONG_BLOCK_SIZE: usize = 2048;
23pub const SHORT_BLOCK_SIZE: usize = 256;
25pub const SHORTS_PER_GROUP: usize = 8;
27pub const SHORT_GROUP_OFFSET: usize = 448;
29pub const FRAME_COEFFICIENTS: usize = LONG_BLOCK_SIZE / 2;
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum BlockSize {
35 Long,
37 Short,
39 Start,
41 Stop,
43}
44
45impl BlockSize {
46 pub fn samples(self) -> usize {
48 match self {
49 BlockSize::Long | BlockSize::Start | BlockSize::Stop => LONG_BLOCK_SIZE,
50 BlockSize::Short => SHORT_BLOCK_SIZE,
51 }
52 }
53
54 pub fn coefficients(self) -> usize {
56 self.samples() / 2
57 }
58
59 pub fn frame_input_size(self) -> usize {
61 LONG_BLOCK_SIZE
62 }
63
64 pub fn frame_coefficients(self) -> usize {
66 match self {
67 BlockSize::Short => SHORTS_PER_GROUP * (SHORT_BLOCK_SIZE / 2),
68 _ => LONG_BLOCK_SIZE / 2,
69 }
70 }
71
72 pub fn is_short_group(self) -> bool {
74 matches!(self, BlockSize::Short)
75 }
76}
77
78struct MdctTransform {
80 n: usize,
82 n2: usize,
84 n4: usize,
86 window: Vec<f32>,
88 fft: Box<dyn Fft>,
90 twiddle: Vec<Complex32>,
92}
93
94impl MdctTransform {
95 fn build_window(n: usize, window_type: WindowType) -> Vec<f32> {
97 match window_type {
98 WindowType::Sine => Self::sine_window(n),
99 WindowType::KaiserBesselDerived => Self::kbd_window(n, 4.0),
100 WindowType::Vorbis => Self::vorbis_window(n),
101 }
102 }
103
104 fn from_window(window_size: usize, window: Vec<f32>) -> Self {
106 let n = window_size;
107 let n2 = n / 2;
108 let n4 = n / 4;
109
110 let mut planner = DefaultPlanner::new();
112 let fft = planner.plan_fft_forward(n4);
113
114 let twiddle: Vec<Complex32> = (0..n4)
116 .map(|k| {
117 let theta = PI / n2 as f32 * (k as f32 + 0.125);
118 Complex32::new(libm::cosf(theta), libm::sinf(theta))
119 })
120 .collect();
121
122 Self {
123 n,
124 n2,
125 n4,
126 window,
127 fft,
128 twiddle,
129 }
130 }
131
132 fn sine_window(n: usize) -> Vec<f32> {
134 (0..n)
135 .map(|i| libm::sinf(PI * (i as f32 + 0.5) / n as f32))
136 .collect()
137 }
138
139 fn vorbis_window(n: usize) -> Vec<f32> {
141 (0..n)
142 .map(|i| {
143 let x = libm::sinf(PI * (i as f32 + 0.5) / n as f32);
144 libm::sinf(PI / 2.0 * x * x)
145 })
146 .collect()
147 }
148
149 fn kbd_window(n: usize, alpha: f32) -> Vec<f32> {
151 let half = n / 2;
152
153 let kaiser: Vec<f32> = (0..=half)
155 .map(|i| {
156 let t = 2.0 * i as f32 / half as f32 - 1.0;
157 Self::bessel_i0(PI * alpha * libm::sqrtf(1.0 - t * t))
158 })
159 .collect();
160
161 let mut cumsum = vec![0.0f32; half + 1];
163 cumsum[0] = kaiser[0];
164 for i in 1..=half {
165 cumsum[i] = cumsum[i - 1] + kaiser[i];
166 }
167 let total = cumsum[half];
168
169 let mut window = vec![0.0f32; n];
171 for i in 0..half {
172 window[i] = libm::sqrtf(cumsum[i] / total);
173 window[n - 1 - i] = window[i];
174 }
175
176 window
177 }
178
179 fn bessel_i0(x: f32) -> f32 {
181 let mut sum = 1.0f32;
182 let mut term = 1.0f32;
183 let x_sq = x * x / 4.0;
184
185 for k in 1..20 {
186 term *= x_sq / (k * k) as f32;
187 sum += term;
188 if term < 1e-10 {
189 break;
190 }
191 }
192
193 sum
194 }
195
196 fn forward(&self, samples: &[f32]) -> Vec<f32> {
200 let n = self.n;
201 let n2 = self.n2;
202 let n4 = self.n4;
203 let n8 = n4 / 2;
204 let n3 = 3 * n4;
205
206 let x: Vec<f32> = samples
208 .iter()
209 .zip(self.window.iter())
210 .map(|(&s, &w)| s * w)
211 .collect();
212
213 let mut z: Vec<Complex32> = vec![Complex32::new(0.0, 0.0); n4];
215
216 for i in 0..n8 {
217 let re = -x[2 * i + n3] - x[n3 - 1 - 2 * i];
219 let im = -x[n4 + 2 * i] + x[n4 - 1 - 2 * i];
220
221 let w = &self.twiddle[i];
222 z[i] = Complex32::new(-re * w.re - im * w.im, re * w.im - im * w.re);
223
224 let re2 = x[2 * i] - x[n2 - 1 - 2 * i];
226 let im2 = -x[n2 + 2 * i] - x[n - 1 - 2 * i];
227
228 let w2 = &self.twiddle[n8 + i];
229 z[n8 + i] = Complex32::new(-re2 * w2.re - im2 * w2.im, re2 * w2.im - im2 * w2.re);
230 }
231
232 self.fft.process(&mut z);
234
235 let mut output = vec![0.0; n2];
237
238 for i in 0..n8 {
239 let idx1 = n8 - i - 1;
240 let idx2 = n8 + i;
241
242 let w1 = &self.twiddle[idx1];
243 let z1 = z[idx1];
244 let i1 = -z1.re * w1.im + z1.im * w1.re;
245 let r0 = -z1.re * w1.re - z1.im * w1.im;
246
247 let w2 = &self.twiddle[idx2];
248 let z2 = z[idx2];
249 let i0 = -z2.re * w2.im + z2.im * w2.re;
250 let r1 = -z2.re * w2.re - z2.im * w2.im;
251
252 output[2 * idx1] = r0;
253 output[2 * idx1 + 1] = i0;
254 output[2 * idx2] = r1;
255 output[2 * idx2 + 1] = i1;
256 }
257
258 output
259 }
260
261 fn inverse(&self, spec: &[f32]) -> Vec<f32> {
265 let n = self.n;
266 let n2 = self.n2;
267 let n4 = self.n4;
268 let n8 = n4 / 2;
269
270 let mut z: Vec<Complex32> = Vec::with_capacity(n4);
272
273 for i in 0..n4 {
274 let even = spec[i * 2];
275 let odd = -spec[n2 - 1 - i * 2];
276
277 let w = &self.twiddle[i];
278 z.push(Complex32::new(
279 odd * w.im - even * w.re,
280 odd * w.re + even * w.im,
281 ));
282 }
283
284 self.fft.process(&mut z);
286
287 let mut output = vec![0.0; n];
289 let scale = 2.0 / n2 as f32;
290
291 for i in 0..n8 {
293 let w = &self.twiddle[i];
294 let val_re = w.re * z[i].re + w.im * z[i].im;
295 let val_im = w.im * z[i].re - w.re * z[i].im;
296
297 let fi = 2 * i;
298 let ri = n4 - 1 - 2 * i;
299
300 output[ri] = -val_im * scale * self.window[ri];
301 output[n4 + fi] = val_im * scale * self.window[n4 + fi];
302 output[n2 + ri] = val_re * scale * self.window[n2 + ri];
303 output[n2 + n4 + fi] = val_re * scale * self.window[n2 + n4 + fi];
304 }
305
306 for i in 0..n8 {
308 let idx = n8 + i;
309 let w = &self.twiddle[idx];
310 let val_re = w.re * z[idx].re + w.im * z[idx].im;
311 let val_im = w.im * z[idx].re - w.re * z[idx].im;
312
313 let fi = 2 * i;
314 let ri = n4 - 1 - 2 * i;
315
316 output[fi] = -val_re * scale * self.window[fi];
317 output[n4 + ri] = val_re * scale * self.window[n4 + ri];
318 output[n2 + fi] = val_im * scale * self.window[n2 + fi];
319 output[n2 + n4 + ri] = val_im * scale * self.window[n2 + n4 + ri];
320 }
321
322 output
323 }
324}
325
326pub struct Mdct {
331 long_transform: MdctTransform,
333 short_transform: MdctTransform,
335 start_transform: MdctTransform,
337 stop_transform: MdctTransform,
339 overlap_buffer: Vec<Vec<f32>>,
341 channels: usize,
343}
344
345impl Mdct {
346 pub fn new(channels: usize, window_type: WindowType) -> Self {
348 let long_window = MdctTransform::build_window(LONG_BLOCK_SIZE, window_type);
349 let short_window = MdctTransform::build_window(SHORT_BLOCK_SIZE, window_type);
350
351 let start_transform = MdctTransform::from_window(
352 LONG_BLOCK_SIZE,
353 Self::start_window(&long_window, &short_window),
354 );
355 let stop_transform = MdctTransform::from_window(
356 LONG_BLOCK_SIZE,
357 Self::stop_window(&long_window, &short_window),
358 );
359
360 let overlap_buffer = vec![vec![0.0f32; LONG_BLOCK_SIZE / 2]; channels];
362
363 Self {
364 long_transform: MdctTransform::from_window(LONG_BLOCK_SIZE, long_window),
365 short_transform: MdctTransform::from_window(SHORT_BLOCK_SIZE, short_window),
366 start_transform,
367 stop_transform,
368 overlap_buffer,
369 channels,
370 }
371 }
372
373 pub fn start_window(long_win: &[f32], short_win: &[f32]) -> Vec<f32> {
375 debug_assert_eq!(long_win.len(), LONG_BLOCK_SIZE);
376 debug_assert_eq!(short_win.len(), SHORT_BLOCK_SIZE);
377 let mut w = vec![0.0f32; LONG_BLOCK_SIZE];
378 w[..LONG_BLOCK_SIZE / 2].copy_from_slice(&long_win[..LONG_BLOCK_SIZE / 2]);
379 w[LONG_BLOCK_SIZE / 2..1472].fill(1.0);
380 for i in 0..SHORT_BLOCK_SIZE / 2 {
381 w[1472 + i] = short_win[SHORT_BLOCK_SIZE / 2 + i];
382 }
383 w
384 }
385
386 pub fn stop_window(long_win: &[f32], short_win: &[f32]) -> Vec<f32> {
388 debug_assert_eq!(long_win.len(), LONG_BLOCK_SIZE);
389 debug_assert_eq!(short_win.len(), SHORT_BLOCK_SIZE);
390 let mut w = vec![0.0f32; LONG_BLOCK_SIZE];
391 w[SHORT_GROUP_OFFSET..SHORT_GROUP_OFFSET + SHORT_BLOCK_SIZE / 2]
392 .copy_from_slice(&short_win[..SHORT_BLOCK_SIZE / 2]);
393 w[576..LONG_BLOCK_SIZE / 2].fill(1.0);
394 for i in 0..LONG_BLOCK_SIZE / 2 {
395 w[LONG_BLOCK_SIZE / 2 + i] = long_win[1023 - i];
396 }
397 w
398 }
399
400 pub fn sine_window(n: usize) -> Vec<f32> {
402 MdctTransform::sine_window(n)
403 }
404
405 pub fn vorbis_window(n: usize) -> Vec<f32> {
407 MdctTransform::vorbis_window(n)
408 }
409
410 pub fn forward(&self, samples: &[f32], block_size: BlockSize) -> Vec<f32> {
414 assert!(
415 samples.len() >= block_size.frame_input_size(),
416 "Not enough samples for MDCT"
417 );
418
419 match block_size {
420 BlockSize::Long => self.long_transform.forward(&samples[..LONG_BLOCK_SIZE]),
421 BlockSize::Start => self.start_transform.forward(&samples[..LONG_BLOCK_SIZE]),
422 BlockSize::Stop => self.stop_transform.forward(&samples[..LONG_BLOCK_SIZE]),
423 BlockSize::Short => {
424 let mut coeffs = Vec::with_capacity(FRAME_COEFFICIENTS);
427 for w in 0..SHORTS_PER_GROUP {
428 let start = SHORT_GROUP_OFFSET + w * (SHORT_BLOCK_SIZE / 2);
429 coeffs.extend(
430 self.short_transform
431 .forward(&samples[start..start + SHORT_BLOCK_SIZE]),
432 );
433 }
434 coeffs
435 }
436 }
437 }
438
439 pub fn inverse(&self, coeffs: &[f32], block_size: BlockSize) -> Vec<f32> {
443 match block_size {
444 BlockSize::Long => {
445 assert!(
446 coeffs.len() >= LONG_BLOCK_SIZE / 2,
447 "Not enough coefficients for IMDCT"
448 );
449 self.long_transform.inverse(&coeffs[..LONG_BLOCK_SIZE / 2])
450 }
451 BlockSize::Start => {
452 assert!(
453 coeffs.len() >= LONG_BLOCK_SIZE / 2,
454 "Not enough coefficients for IMDCT"
455 );
456 self.start_transform.inverse(&coeffs[..LONG_BLOCK_SIZE / 2])
457 }
458 BlockSize::Stop => {
459 assert!(
460 coeffs.len() >= LONG_BLOCK_SIZE / 2,
461 "Not enough coefficients for IMDCT"
462 );
463 self.stop_transform.inverse(&coeffs[..LONG_BLOCK_SIZE / 2])
464 }
465 BlockSize::Short => {
466 assert!(
469 coeffs.len() >= SHORTS_PER_GROUP * (SHORT_BLOCK_SIZE / 2),
470 "Not enough coefficients for IMDCT"
471 );
472 let mut time = vec![0.0f32; LONG_BLOCK_SIZE];
473 for w in 0..SHORTS_PER_GROUP {
474 let off = SHORT_GROUP_OFFSET + w * (SHORT_BLOCK_SIZE / 2);
475 let blk = self.short_transform.inverse(
476 &coeffs[w * (SHORT_BLOCK_SIZE / 2)..(w + 1) * (SHORT_BLOCK_SIZE / 2)],
477 );
478 for (j, &v) in blk.iter().enumerate() {
479 time[off + j] += v;
480 }
481 }
482 time
483 }
484 }
485 }
486
487 pub fn process_frame(
490 &mut self,
491 samples: &[f32],
492 channel: usize,
493 block_size: BlockSize,
494 ) -> (Vec<f32>, Vec<f32>) {
495 let coeffs = self.forward(samples, block_size);
497
498 let reconstructed = self.inverse(&coeffs, block_size);
500
501 let n2 = LONG_BLOCK_SIZE / 2;
503 let mut output = vec![0.0f32; n2];
504 for i in 0..n2 {
505 output[i] = reconstructed[i] + self.overlap_buffer[channel][i];
506 }
507
508 self.overlap_buffer[channel].copy_from_slice(&reconstructed[n2..n2 + n2]);
510
511 (coeffs, output)
512 }
513
514 pub fn reset(&mut self) {
516 for buf in &mut self.overlap_buffer {
517 buf.fill(0.0);
518 }
519 }
520
521 pub fn analyze(&mut self, samples: &[f32], block_size: BlockSize) -> Vec<Vec<f32>> {
525 let n = block_size.frame_input_size();
526 let samples_per_channel = samples.len() / self.channels;
527
528 let mut channel_data: Vec<Vec<f32>> = (0..self.channels)
530 .map(|_| Vec::with_capacity(samples_per_channel))
531 .collect();
532
533 for (i, &s) in samples.iter().enumerate() {
534 channel_data[i % self.channels].push(s);
535 }
536
537 let mut all_coeffs = Vec::with_capacity(self.channels);
539 for data in &channel_data {
540 let mut padded = data.clone();
541 padded.resize(n, 0.0);
542 let coeffs = self.forward(&padded, block_size);
543 all_coeffs.push(coeffs);
544 }
545
546 all_coeffs
547 }
548
549 pub fn synthesize(&mut self, coeffs: &[Vec<f32>], block_size: BlockSize) -> Vec<f32> {
553 let n2 = LONG_BLOCK_SIZE / 2;
554
555 let mut channel_outputs: Vec<Vec<f32>> = Vec::with_capacity(self.channels);
557
558 for (ch, ch_coeffs) in coeffs.iter().enumerate() {
559 let reconstructed = self.inverse(ch_coeffs, block_size);
560
561 let mut output = vec![0.0f32; n2];
563 for i in 0..n2 {
564 output[i] = reconstructed[i] + self.overlap_buffer[ch][i];
565 }
566
567 self.overlap_buffer[ch].copy_from_slice(&reconstructed[n2..n2 + n2]);
569
570 channel_outputs.push(output);
571 }
572
573 let mut output = Vec::with_capacity(n2 * self.channels);
575 for i in 0..n2 {
576 for ch in 0..self.channels {
577 output.push(channel_outputs[ch][i]);
578 }
579 }
580
581 output
582 }
583}