split nihav-codec-support crate from nihav-core
[nihav.git] / nihav-codec-support / src / dsp / mdct.rs
1 //! Modified Discrete Cosine transform functionality.
2 use std::f32::consts;
3 use super::fft::*;
4
5 /// IMDCT working context.
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 {
24 /// Constructs a new instance of `IMDCT` context.
25 pub fn new(size: usize, scaledown: bool) -> Self {
26 let mut twiddle: Vec<FFTComplex> = Vec::with_capacity(size / 4);
27 let factor = 2.0 * consts::PI / ((8 * size) as f32);
28 let scale = if scaledown { (1.0 / (size as f32)).sqrt() } else { 1.0 };
29 for k in 0..size/4 {
30 twiddle.push(FFTComplex::exp(factor * ((8 * k + 1) as f32)).scale(scale));
31 }
32 let fft = FFTBuilder::new_fft(size/4, false);
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 }
37 /// Calculates IMDCT.
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 }
46 self.fft.do_ifft_inplace(&mut self.z);
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 }
61 /// Calculates only non-mirrored part of IMDCT.
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 }
81 }