forked from whoozle/clunk
-
Notifications
You must be signed in to change notification settings - Fork 4
/
mdct_context.h
128 lines (103 loc) · 2.83 KB
/
mdct_context.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#ifndef MDCT_CONTEXT_H__
#define MDCT_CONTEXT_H__
#include "fft_context.h"
#include "clunk_assert.h"
#include <string.h>
namespace clunk {
template<int N, typename T>
struct window_func_base {
virtual ~window_func_base() {}
virtual T operator() (int x) const = 0;
void precalculate() {
for(int i = 0; i < N; ++i) {
cache[i] = (*this)(i);
}
}
T cache[N];
};
template<int BITS, template <int, typename> class window_func_type , typename T = float>
class mdct_context {
typedef fft_context<BITS - 2, T> fft_type;
fft_type fft;
public:
enum { N = 1 << BITS , M = N / 2, N4 = fft_type::N };
clunk_static_assert(N == N4 * 4);
typedef T value_type;
typedef std::complex<T> complex_type;
T data[N];
mdct_context() : sqrt_N((T)sqrt((T)N)) {
window_func.precalculate();
for(unsigned t = 0; t < N4; ++t) {
angle_cache[t] = std::polar<T>(1, 2 * T(M_PI) * (t + T(0.125)) / N);
}
}
void mdct() {
T rotate[N];
unsigned int t;
for(t = 0; t < N4; ++t) {
rotate[t] = -data[t + 3 * N4];
}
for(; t < N; ++t) {
rotate[t] = data[t - N4];
}
for(t = 0; t < N4; ++t) {
T re = (rotate[t * 2] - rotate[N - 1 - t * 2]) / 2;
T im = (rotate[M + t * 2] - rotate[M - 1 - t * 2]) / -2;
std::complex<T> a = angle_cache[t];
fft.data[t] = std::complex<T>(re * a.real() + im * a.imag(), -re * a.imag() + im * a.real());
}
fft.fft();
for(t = 0; t < N4; ++t) {
std::complex<T> a = angle_cache[t];
std::complex<T>& f = fft.data[t];
f = std::complex<T>(2 / sqrt_N * (f.real() * a.real() + f.imag() * a.imag()), 2 / sqrt_N * (-f.real() * a.imag() + f.imag() * a.real()));
}
for(t = 0; t < N4; ++t) {
data[2 * t] = fft.data[t].real();
data[M - 2 * t - 1] = -fft.data[t].imag();
}
}
void imdct() {
unsigned int t;
for(t = 0; t < N4; ++t) {
T re = data[t * 2] / 2, im = data[M - 1 - t * 2] / 2;
std::complex<T> a = angle_cache[t];
fft.data[t] = std::complex<T>(re * a.real() + im * a.imag(), - re * a.imag() + im * a.real());
}
fft.fft();
for(t = 0; t < N4; ++t) {
std::complex<T> a = angle_cache[t];
std::complex<T>& f = fft.data[t];
fft.data[t] = std::complex<T>(8 / sqrt_N * (f.real() * a.real() + f.imag() * a.imag()), 8 / sqrt_N * (-f.real() * a.imag() + f.imag() * a.real()));
}
T rotate[N];
for(t = 0; t < N4; ++t) {
rotate[2 * t] = fft.data[t].real();
rotate[M + 2 * t] = fft.data[t].imag();
}
for(t = 1; t < N; t += 2) {
rotate[t] = - rotate[N - t - 1];
}
//shift
for(t = 0; t < 3 * N4; ++t) {
data[t] = rotate[t + N4];
}
for(; t < N; ++t) {
data[t] = -rotate[t - 3 * N4];
}
}
void apply_window() {
for(unsigned i = 0; i < N; ++i) {
data[i] *= window_func.cache[i];
}
}
void clear() {
memset(data, 0, sizeof(data));
}
private:
window_func_type<N, T> window_func;
std::complex<T> angle_cache[N4];
T sqrt_N;
};
}
#endif