]>
Commit | Line | Data |
---|---|---|
4e034a32 | 1 | //! Modified Discrete Cosine transform functionality. |
f1f6f4aa KS |
2 | use std::f32::consts; |
3 | use super::fft::*; | |
4 | ||
4e034a32 | 5 | /// IMDCT working context. |
f1f6f4aa KS |
6 | pub struct IMDCT { |
7 | twiddle: Vec<FFTComplex>, | |
8 | fft: FFT, | |
9 | size: usize, | |
10 | z: Vec<FFTComplex>, | |
11 | } | |
12 | ||
13 | /* | |
14 | fn imdct(src: &[f32], dst: &mut [f32], length: usize) { | |
15 | for n in 0..length*2 { | |
16 | dst[n] = 0.0; | |
17 | for k in 0..length { | |
18 | dst[n] += src[k] * (consts::PI / (length as f32) * ((n as f32) + 0.5 + ((length/2) as f32)) * ((k as f32) + 0.5)).cos(); | |
19 | } | |
20 | } | |
21 | }*/ | |
22 | ||
23 | impl IMDCT { | |
4e034a32 | 24 | /// Constructs a new instance of `IMDCT` context. |
9e78289c | 25 | pub fn new(size: usize, scaledown: bool) -> Self { |
f1f6f4aa KS |
26 | let mut twiddle: Vec<FFTComplex> = Vec::with_capacity(size / 4); |
27 | let factor = 2.0 * consts::PI / ((8 * size) as f32); | |
8cb5b63b | 28 | let scale = if scaledown { (1.0 / (size as f32)).sqrt() } else { 1.0 }; |
f1f6f4aa | 29 | for k in 0..size/4 { |
8cb5b63b | 30 | twiddle.push(FFTComplex::exp(factor * ((8 * k + 1) as f32)).scale(scale)); |
f1f6f4aa | 31 | } |
9e78289c | 32 | let fft = FFTBuilder::new_fft(size/4, false); |
f1f6f4aa KS |
33 | let mut z: Vec<FFTComplex> = Vec::with_capacity(size / 2); |
34 | z.resize(size / 2, FFTC_ZERO); | |
35 | IMDCT { twiddle, fft, size, z } | |
36 | } | |
4e034a32 | 37 | /// Calculates IMDCT. |
f1f6f4aa KS |
38 | pub fn imdct(&mut self, src: &[f32], dst: &mut [f32]) { |
39 | let size2 = self.size / 2; | |
40 | let size4 = self.size / 4; | |
41 | let size8 = self.size / 8; | |
42 | for k in 0..size4 { | |
43 | let c = FFTComplex { re: src[size2 - 2 * k - 1], im: src[ 2 * k] }; | |
44 | self.z[k] = c * self.twiddle[k]; | |
45 | } | |
9e78289c | 46 | self.fft.do_ifft_inplace(&mut self.z); |
f1f6f4aa KS |
47 | for k in 0..size4 { |
48 | self.z[k] *= self.twiddle[k]; | |
49 | } | |
50 | for n in 0..size8 { | |
51 | dst[ 2 * n] = -self.z[size8 + n] .im; | |
52 | dst[ 2 * n + 1] = self.z[size8 - n - 1].re; | |
53 | dst[ size4 + 2 * n] = -self.z[ n] .re; | |
54 | dst[ size4 + 2 * n + 1] = self.z[size4 - n - 1].im; | |
55 | dst[ size2 + 2 * n] = -self.z[size8 + n] .re; | |
56 | dst[ size2 + 2 * n + 1] = self.z[size8 - n - 1].im; | |
57 | dst[3 * size4 + 2 * n] = self.z[ n] .im; | |
58 | dst[3 * size4 + 2 * n + 1] = -self.z[size4 - n - 1].re; | |
59 | } | |
60 | } | |
4e034a32 | 61 | /// Calculates only non-mirrored part of IMDCT. |
9e424d2f KS |
62 | pub fn imdct_half(&mut self, src: &[f32], dst: &mut [f32]) { |
63 | let size2 = self.size / 2; | |
64 | let size4 = self.size / 4; | |
65 | let size8 = self.size / 8; | |
66 | for k in 0..size4 { | |
67 | let c = FFTComplex { re: src[size2 - 2 * k - 1], im: src[ 2 * k] }; | |
68 | self.z[k] = c * self.twiddle[k]; | |
69 | } | |
70 | self.fft.do_ifft_inplace(&mut self.z); | |
71 | for k in 0..size4 { | |
72 | self.z[k] *= self.twiddle[k]; | |
73 | } | |
74 | for n in 0..size8 { | |
75 | dst[ 2 * n] = -self.z[ n] .re; | |
76 | dst[ 2 * n + 1] = self.z[size4 - n - 1].im; | |
77 | dst[size4 + 2 * n] = -self.z[size8 + n] .re; | |
78 | dst[size4 + 2 * n + 1] = self.z[size8 - n - 1].im; | |
79 | } | |
80 | } | |
f1f6f4aa | 81 | } |