symphonia_core/dsp/mdct/
mod.rs

1// Symphonia
2// Copyright (c) 2019-2022 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8//! The `mdct` module implements the Modified Discrete Cosine Transform (MDCT).
9//!
10//! The MDCT in this module is implemented in-terms of a forward FFT.
11
12#[cfg(any(feature = "opt-simd-sse", feature = "opt-simd-avx", feature = "opt-simd-neon"))]
13mod simd;
14
15#[cfg(any(feature = "opt-simd-sse", feature = "opt-simd-avx", feature = "opt-simd-neon"))]
16pub use simd::*;
17
18#[cfg(not(any(feature = "opt-simd-sse", feature = "opt-simd-avx", feature = "opt-simd-neon")))]
19mod no_simd;
20#[cfg(not(any(
21    feature = "opt-simd-sse",
22    feature = "opt-simd-avx",
23    feature = "opt-simd-neon"
24)))]
25pub use no_simd::*;
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30    use std::f64;
31
32    fn imdct_analytical(x: &[f32], y: &mut [f32], scale: f64) {
33        assert!(y.len() == 2 * x.len());
34
35        // Generates 2N outputs from N inputs.
36        let n_in = x.len();
37        let n_out = x.len() << 1;
38
39        let pi_2n = f64::consts::PI / (2 * n_out) as f64;
40
41        for (i, item) in y.iter_mut().enumerate().take(n_out) {
42            let accum: f64 = x
43                .iter()
44                .copied()
45                .map(f64::from)
46                .enumerate()
47                .take(n_in)
48                .map(|(j, jtem)| jtem * (pi_2n * ((2 * i + 1 + n_in) * (2 * j + 1)) as f64).cos())
49                .sum();
50
51            *item = (scale * accum) as f32;
52        }
53    }
54
55    #[test]
56    fn verify_imdct() {
57        #[rustfmt::skip]
58        const TEST_VECTOR: [f32; 32] = [
59             1.0,  2.0,  3.0,  4.0,  5.0,  6.0,  7.0,  8.0,
60             9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
61            17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0,
62            25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0,
63        ];
64
65        let mut actual = [0f32; 64];
66        let mut expected = [0f32; 64];
67
68        let scale = (2.0f64 / 64.0).sqrt();
69
70        imdct_analytical(&TEST_VECTOR, &mut expected, scale);
71
72        let mut mdct = Imdct::new_scaled(32, scale);
73        mdct.imdct(&TEST_VECTOR, &mut actual);
74
75        for i in 0..64 {
76            let delta = f64::from(actual[i]) - f64::from(expected[i]);
77            assert!(delta.abs() < 0.00001);
78        }
79    }
80}