1*49fe348cSAndroid Build Coastguard Worker /******************************************************************************
2*49fe348cSAndroid Build Coastguard Worker *
3*49fe348cSAndroid Build Coastguard Worker * Copyright 2022 Google LLC
4*49fe348cSAndroid Build Coastguard Worker *
5*49fe348cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*49fe348cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*49fe348cSAndroid Build Coastguard Worker * You may obtain a copy of the License at:
8*49fe348cSAndroid Build Coastguard Worker *
9*49fe348cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*49fe348cSAndroid Build Coastguard Worker *
11*49fe348cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*49fe348cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*49fe348cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*49fe348cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*49fe348cSAndroid Build Coastguard Worker * limitations under the License.
16*49fe348cSAndroid Build Coastguard Worker *
17*49fe348cSAndroid Build Coastguard Worker ******************************************************************************/
18*49fe348cSAndroid Build Coastguard Worker
19*49fe348cSAndroid Build Coastguard Worker #include "mdct.h"
20*49fe348cSAndroid Build Coastguard Worker #include "tables.h"
21*49fe348cSAndroid Build Coastguard Worker
22*49fe348cSAndroid Build Coastguard Worker #include "mdct_neon.h"
23*49fe348cSAndroid Build Coastguard Worker
24*49fe348cSAndroid Build Coastguard Worker
25*49fe348cSAndroid Build Coastguard Worker /* ----------------------------------------------------------------------------
26*49fe348cSAndroid Build Coastguard Worker * FFT processing
27*49fe348cSAndroid Build Coastguard Worker * -------------------------------------------------------------------------- */
28*49fe348cSAndroid Build Coastguard Worker
29*49fe348cSAndroid Build Coastguard Worker /**
30*49fe348cSAndroid Build Coastguard Worker * FFT 5 Points
31*49fe348cSAndroid Build Coastguard Worker * x, y Input and output coefficients, of size 5xn
32*49fe348cSAndroid Build Coastguard Worker * n Number of interleaved transform to perform (n % 2 = 0)
33*49fe348cSAndroid Build Coastguard Worker */
34*49fe348cSAndroid Build Coastguard Worker #ifndef fft_5
fft_5(const struct lc3_complex * x,struct lc3_complex * y,int n)35*49fe348cSAndroid Build Coastguard Worker LC3_HOT static inline void fft_5(
36*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x, struct lc3_complex *y, int n)
37*49fe348cSAndroid Build Coastguard Worker {
38*49fe348cSAndroid Build Coastguard Worker static const float cos1 = 0.3090169944; /* cos(-2Pi 1/5) */
39*49fe348cSAndroid Build Coastguard Worker static const float cos2 = -0.8090169944; /* cos(-2Pi 2/5) */
40*49fe348cSAndroid Build Coastguard Worker
41*49fe348cSAndroid Build Coastguard Worker static const float sin1 = -0.9510565163; /* sin(-2Pi 1/5) */
42*49fe348cSAndroid Build Coastguard Worker static const float sin2 = -0.5877852523; /* sin(-2Pi 2/5) */
43*49fe348cSAndroid Build Coastguard Worker
44*49fe348cSAndroid Build Coastguard Worker for (int i = 0; i < n; i++, x++, y+= 5) {
45*49fe348cSAndroid Build Coastguard Worker
46*49fe348cSAndroid Build Coastguard Worker struct lc3_complex s14 =
47*49fe348cSAndroid Build Coastguard Worker { x[1*n].re + x[4*n].re, x[1*n].im + x[4*n].im };
48*49fe348cSAndroid Build Coastguard Worker struct lc3_complex d14 =
49*49fe348cSAndroid Build Coastguard Worker { x[1*n].re - x[4*n].re, x[1*n].im - x[4*n].im };
50*49fe348cSAndroid Build Coastguard Worker
51*49fe348cSAndroid Build Coastguard Worker struct lc3_complex s23 =
52*49fe348cSAndroid Build Coastguard Worker { x[2*n].re + x[3*n].re, x[2*n].im + x[3*n].im };
53*49fe348cSAndroid Build Coastguard Worker struct lc3_complex d23 =
54*49fe348cSAndroid Build Coastguard Worker { x[2*n].re - x[3*n].re, x[2*n].im - x[3*n].im };
55*49fe348cSAndroid Build Coastguard Worker
56*49fe348cSAndroid Build Coastguard Worker y[0].re = x[0].re + s14.re + s23.re;
57*49fe348cSAndroid Build Coastguard Worker
58*49fe348cSAndroid Build Coastguard Worker y[0].im = x[0].im + s14.im + s23.im;
59*49fe348cSAndroid Build Coastguard Worker
60*49fe348cSAndroid Build Coastguard Worker y[1].re = x[0].re + s14.re * cos1 - d14.im * sin1
61*49fe348cSAndroid Build Coastguard Worker + s23.re * cos2 - d23.im * sin2;
62*49fe348cSAndroid Build Coastguard Worker
63*49fe348cSAndroid Build Coastguard Worker y[1].im = x[0].im + s14.im * cos1 + d14.re * sin1
64*49fe348cSAndroid Build Coastguard Worker + s23.im * cos2 + d23.re * sin2;
65*49fe348cSAndroid Build Coastguard Worker
66*49fe348cSAndroid Build Coastguard Worker y[2].re = x[0].re + s14.re * cos2 - d14.im * sin2
67*49fe348cSAndroid Build Coastguard Worker + s23.re * cos1 + d23.im * sin1;
68*49fe348cSAndroid Build Coastguard Worker
69*49fe348cSAndroid Build Coastguard Worker y[2].im = x[0].im + s14.im * cos2 + d14.re * sin2
70*49fe348cSAndroid Build Coastguard Worker + s23.im * cos1 - d23.re * sin1;
71*49fe348cSAndroid Build Coastguard Worker
72*49fe348cSAndroid Build Coastguard Worker y[3].re = x[0].re + s14.re * cos2 + d14.im * sin2
73*49fe348cSAndroid Build Coastguard Worker + s23.re * cos1 - d23.im * sin1;
74*49fe348cSAndroid Build Coastguard Worker
75*49fe348cSAndroid Build Coastguard Worker y[3].im = x[0].im + s14.im * cos2 - d14.re * sin2
76*49fe348cSAndroid Build Coastguard Worker + s23.im * cos1 + d23.re * sin1;
77*49fe348cSAndroid Build Coastguard Worker
78*49fe348cSAndroid Build Coastguard Worker y[4].re = x[0].re + s14.re * cos1 + d14.im * sin1
79*49fe348cSAndroid Build Coastguard Worker + s23.re * cos2 + d23.im * sin2;
80*49fe348cSAndroid Build Coastguard Worker
81*49fe348cSAndroid Build Coastguard Worker y[4].im = x[0].im + s14.im * cos1 - d14.re * sin1
82*49fe348cSAndroid Build Coastguard Worker + s23.im * cos2 - d23.re * sin2;
83*49fe348cSAndroid Build Coastguard Worker }
84*49fe348cSAndroid Build Coastguard Worker }
85*49fe348cSAndroid Build Coastguard Worker #endif /* fft_5 */
86*49fe348cSAndroid Build Coastguard Worker
87*49fe348cSAndroid Build Coastguard Worker /**
88*49fe348cSAndroid Build Coastguard Worker * FFT Butterfly 3 Points
89*49fe348cSAndroid Build Coastguard Worker * x, y Input and output coefficients
90*49fe348cSAndroid Build Coastguard Worker * twiddles Twiddles factors, determine size of transform
91*49fe348cSAndroid Build Coastguard Worker * n Number of interleaved transforms
92*49fe348cSAndroid Build Coastguard Worker */
93*49fe348cSAndroid Build Coastguard Worker #ifndef fft_bf3
fft_bf3(const struct lc3_fft_bf3_twiddles * twiddles,const struct lc3_complex * x,struct lc3_complex * y,int n)94*49fe348cSAndroid Build Coastguard Worker LC3_HOT static inline void fft_bf3(
95*49fe348cSAndroid Build Coastguard Worker const struct lc3_fft_bf3_twiddles *twiddles,
96*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x, struct lc3_complex *y, int n)
97*49fe348cSAndroid Build Coastguard Worker {
98*49fe348cSAndroid Build Coastguard Worker int n3 = twiddles->n3;
99*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex (*w0)[2] = twiddles->t;
100*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex (*w1)[2] = w0 + n3, (*w2)[2] = w1 + n3;
101*49fe348cSAndroid Build Coastguard Worker
102*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x0 = x, *x1 = x0 + n*n3, *x2 = x1 + n*n3;
103*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *y0 = y, *y1 = y0 + n3, *y2 = y1 + n3;
104*49fe348cSAndroid Build Coastguard Worker
105*49fe348cSAndroid Build Coastguard Worker for (int i = 0; i < n; i++, y0 += 3*n3, y1 += 3*n3, y2 += 3*n3)
106*49fe348cSAndroid Build Coastguard Worker for (int j = 0; j < n3; j++, x0++, x1++, x2++) {
107*49fe348cSAndroid Build Coastguard Worker
108*49fe348cSAndroid Build Coastguard Worker y0[j].re = x0->re + x1->re * w0[j][0].re - x1->im * w0[j][0].im
109*49fe348cSAndroid Build Coastguard Worker + x2->re * w0[j][1].re - x2->im * w0[j][1].im;
110*49fe348cSAndroid Build Coastguard Worker
111*49fe348cSAndroid Build Coastguard Worker y0[j].im = x0->im + x1->im * w0[j][0].re + x1->re * w0[j][0].im
112*49fe348cSAndroid Build Coastguard Worker + x2->im * w0[j][1].re + x2->re * w0[j][1].im;
113*49fe348cSAndroid Build Coastguard Worker
114*49fe348cSAndroid Build Coastguard Worker y1[j].re = x0->re + x1->re * w1[j][0].re - x1->im * w1[j][0].im
115*49fe348cSAndroid Build Coastguard Worker + x2->re * w1[j][1].re - x2->im * w1[j][1].im;
116*49fe348cSAndroid Build Coastguard Worker
117*49fe348cSAndroid Build Coastguard Worker y1[j].im = x0->im + x1->im * w1[j][0].re + x1->re * w1[j][0].im
118*49fe348cSAndroid Build Coastguard Worker + x2->im * w1[j][1].re + x2->re * w1[j][1].im;
119*49fe348cSAndroid Build Coastguard Worker
120*49fe348cSAndroid Build Coastguard Worker y2[j].re = x0->re + x1->re * w2[j][0].re - x1->im * w2[j][0].im
121*49fe348cSAndroid Build Coastguard Worker + x2->re * w2[j][1].re - x2->im * w2[j][1].im;
122*49fe348cSAndroid Build Coastguard Worker
123*49fe348cSAndroid Build Coastguard Worker y2[j].im = x0->im + x1->im * w2[j][0].re + x1->re * w2[j][0].im
124*49fe348cSAndroid Build Coastguard Worker + x2->im * w2[j][1].re + x2->re * w2[j][1].im;
125*49fe348cSAndroid Build Coastguard Worker }
126*49fe348cSAndroid Build Coastguard Worker }
127*49fe348cSAndroid Build Coastguard Worker #endif /* fft_bf3 */
128*49fe348cSAndroid Build Coastguard Worker
129*49fe348cSAndroid Build Coastguard Worker /**
130*49fe348cSAndroid Build Coastguard Worker * FFT Butterfly 2 Points
131*49fe348cSAndroid Build Coastguard Worker * twiddles Twiddles factors, determine size of transform
132*49fe348cSAndroid Build Coastguard Worker * x, y Input and output coefficients
133*49fe348cSAndroid Build Coastguard Worker * n Number of interleaved transforms
134*49fe348cSAndroid Build Coastguard Worker */
135*49fe348cSAndroid Build Coastguard Worker #ifndef fft_bf2
fft_bf2(const struct lc3_fft_bf2_twiddles * twiddles,const struct lc3_complex * x,struct lc3_complex * y,int n)136*49fe348cSAndroid Build Coastguard Worker LC3_HOT static inline void fft_bf2(
137*49fe348cSAndroid Build Coastguard Worker const struct lc3_fft_bf2_twiddles *twiddles,
138*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x, struct lc3_complex *y, int n)
139*49fe348cSAndroid Build Coastguard Worker {
140*49fe348cSAndroid Build Coastguard Worker int n2 = twiddles->n2;
141*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *w = twiddles->t;
142*49fe348cSAndroid Build Coastguard Worker
143*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x0 = x, *x1 = x0 + n*n2;
144*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *y0 = y, *y1 = y0 + n2;
145*49fe348cSAndroid Build Coastguard Worker
146*49fe348cSAndroid Build Coastguard Worker for (int i = 0; i < n; i++, y0 += 2*n2, y1 += 2*n2) {
147*49fe348cSAndroid Build Coastguard Worker
148*49fe348cSAndroid Build Coastguard Worker for (int j = 0; j < n2; j++, x0++, x1++) {
149*49fe348cSAndroid Build Coastguard Worker
150*49fe348cSAndroid Build Coastguard Worker y0[j].re = x0->re + x1->re * w[j].re - x1->im * w[j].im;
151*49fe348cSAndroid Build Coastguard Worker y0[j].im = x0->im + x1->im * w[j].re + x1->re * w[j].im;
152*49fe348cSAndroid Build Coastguard Worker
153*49fe348cSAndroid Build Coastguard Worker y1[j].re = x0->re - x1->re * w[j].re + x1->im * w[j].im;
154*49fe348cSAndroid Build Coastguard Worker y1[j].im = x0->im - x1->im * w[j].re - x1->re * w[j].im;
155*49fe348cSAndroid Build Coastguard Worker }
156*49fe348cSAndroid Build Coastguard Worker }
157*49fe348cSAndroid Build Coastguard Worker }
158*49fe348cSAndroid Build Coastguard Worker #endif /* fft_bf2 */
159*49fe348cSAndroid Build Coastguard Worker
160*49fe348cSAndroid Build Coastguard Worker /**
161*49fe348cSAndroid Build Coastguard Worker * Perform FFT
162*49fe348cSAndroid Build Coastguard Worker * x, y0, y1 Input, and 2 scratch buffers of size `n`
163*49fe348cSAndroid Build Coastguard Worker * n Number of points 30, 40, 60, 80, 90, 120, 160, 180, 240, 480
164*49fe348cSAndroid Build Coastguard Worker * return The buffer `y0` or `y1` that hold the result
165*49fe348cSAndroid Build Coastguard Worker *
166*49fe348cSAndroid Build Coastguard Worker * Input `x` can be the same as the `y0` second scratch buffer
167*49fe348cSAndroid Build Coastguard Worker */
fft(const struct lc3_complex * x,int n,struct lc3_complex * y0,struct lc3_complex * y1)168*49fe348cSAndroid Build Coastguard Worker static struct lc3_complex *fft(const struct lc3_complex *x, int n,
169*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *y0, struct lc3_complex *y1)
170*49fe348cSAndroid Build Coastguard Worker {
171*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *y[2] = { y1, y0 };
172*49fe348cSAndroid Build Coastguard Worker int i2, i3, is = 0;
173*49fe348cSAndroid Build Coastguard Worker
174*49fe348cSAndroid Build Coastguard Worker /* The number of points `n` can be decomposed as :
175*49fe348cSAndroid Build Coastguard Worker *
176*49fe348cSAndroid Build Coastguard Worker * n = 5^1 * 3^n3 * 2^n2
177*49fe348cSAndroid Build Coastguard Worker *
178*49fe348cSAndroid Build Coastguard Worker * for n = 10, 20, 40, 80, 160 n3 = 0, n2 = [1..5]
179*49fe348cSAndroid Build Coastguard Worker * n = 30, 60, 120, 240, 480 n3 = 1, n2 = [1..5]
180*49fe348cSAndroid Build Coastguard Worker * n = 90, 180 n3 = 2, n2 = [1..2]
181*49fe348cSAndroid Build Coastguard Worker *
182*49fe348cSAndroid Build Coastguard Worker * Note that the expression `n & (n-1) == 0` is equivalent
183*49fe348cSAndroid Build Coastguard Worker * to the check that `n` is a power of 2. */
184*49fe348cSAndroid Build Coastguard Worker
185*49fe348cSAndroid Build Coastguard Worker fft_5(x, y[is], n /= 5);
186*49fe348cSAndroid Build Coastguard Worker
187*49fe348cSAndroid Build Coastguard Worker for (i3 = 0; n & (n-1); i3++, is ^= 1)
188*49fe348cSAndroid Build Coastguard Worker fft_bf3(lc3_fft_twiddles_bf3[i3], y[is], y[is ^ 1], n /= 3);
189*49fe348cSAndroid Build Coastguard Worker
190*49fe348cSAndroid Build Coastguard Worker for (i2 = 0; n > 1; i2++, is ^= 1)
191*49fe348cSAndroid Build Coastguard Worker fft_bf2(lc3_fft_twiddles_bf2[i2][i3], y[is], y[is ^ 1], n >>= 1);
192*49fe348cSAndroid Build Coastguard Worker
193*49fe348cSAndroid Build Coastguard Worker return y[is];
194*49fe348cSAndroid Build Coastguard Worker }
195*49fe348cSAndroid Build Coastguard Worker
196*49fe348cSAndroid Build Coastguard Worker
197*49fe348cSAndroid Build Coastguard Worker /* ----------------------------------------------------------------------------
198*49fe348cSAndroid Build Coastguard Worker * MDCT processing
199*49fe348cSAndroid Build Coastguard Worker * -------------------------------------------------------------------------- */
200*49fe348cSAndroid Build Coastguard Worker
201*49fe348cSAndroid Build Coastguard Worker /**
202*49fe348cSAndroid Build Coastguard Worker * Windowing of samples before MDCT
203*49fe348cSAndroid Build Coastguard Worker * dt, sr Duration and samplerate
204*49fe348cSAndroid Build Coastguard Worker * x, y Input current and delayed samples
205*49fe348cSAndroid Build Coastguard Worker * y, d Output windowed samples, and delayed ones
206*49fe348cSAndroid Build Coastguard Worker */
mdct_window(enum lc3_dt dt,enum lc3_srate sr,const float * x,float * d,float * y)207*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void mdct_window(
208*49fe348cSAndroid Build Coastguard Worker enum lc3_dt dt, enum lc3_srate sr,
209*49fe348cSAndroid Build Coastguard Worker const float *x, float *d, float *y)
210*49fe348cSAndroid Build Coastguard Worker {
211*49fe348cSAndroid Build Coastguard Worker const float *win = lc3_mdct_win[dt][sr];
212*49fe348cSAndroid Build Coastguard Worker int ns = lc3_ns(dt, sr), nd = lc3_nd(dt, sr);
213*49fe348cSAndroid Build Coastguard Worker
214*49fe348cSAndroid Build Coastguard Worker const float *w0 = win, *w1 = w0 + ns;
215*49fe348cSAndroid Build Coastguard Worker const float *w2 = w1, *w3 = w2 + nd;
216*49fe348cSAndroid Build Coastguard Worker
217*49fe348cSAndroid Build Coastguard Worker const float *x0 = x + ns-nd, *x1 = x0;
218*49fe348cSAndroid Build Coastguard Worker float *y0 = y + ns/2, *y1 = y0;
219*49fe348cSAndroid Build Coastguard Worker float *d0 = d, *d1 = d + nd;
220*49fe348cSAndroid Build Coastguard Worker
221*49fe348cSAndroid Build Coastguard Worker while (x1 > x) {
222*49fe348cSAndroid Build Coastguard Worker *(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1);
223*49fe348cSAndroid Build Coastguard Worker *(y1++) = (*(d0++) = *(x0++)) * *(w2++);
224*49fe348cSAndroid Build Coastguard Worker
225*49fe348cSAndroid Build Coastguard Worker *(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1);
226*49fe348cSAndroid Build Coastguard Worker *(y1++) = (*(d0++) = *(x0++)) * *(w2++);
227*49fe348cSAndroid Build Coastguard Worker }
228*49fe348cSAndroid Build Coastguard Worker
229*49fe348cSAndroid Build Coastguard Worker for (x1 += ns; x0 < x1; ) {
230*49fe348cSAndroid Build Coastguard Worker *(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1);
231*49fe348cSAndroid Build Coastguard Worker *(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3);
232*49fe348cSAndroid Build Coastguard Worker
233*49fe348cSAndroid Build Coastguard Worker *(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1);
234*49fe348cSAndroid Build Coastguard Worker *(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3);
235*49fe348cSAndroid Build Coastguard Worker }
236*49fe348cSAndroid Build Coastguard Worker }
237*49fe348cSAndroid Build Coastguard Worker
238*49fe348cSAndroid Build Coastguard Worker /**
239*49fe348cSAndroid Build Coastguard Worker * Pre-rotate MDCT coefficients of N/2 points, before FFT N/4 points FFT
240*49fe348cSAndroid Build Coastguard Worker * def Size and twiddles factors
241*49fe348cSAndroid Build Coastguard Worker * x, y Input and output coefficients
242*49fe348cSAndroid Build Coastguard Worker *
243*49fe348cSAndroid Build Coastguard Worker * `x` and y` can be the same buffer
244*49fe348cSAndroid Build Coastguard Worker */
mdct_pre_fft(const struct lc3_mdct_rot_def * def,const float * x,struct lc3_complex * y)245*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void mdct_pre_fft(const struct lc3_mdct_rot_def *def,
246*49fe348cSAndroid Build Coastguard Worker const float *x, struct lc3_complex *y)
247*49fe348cSAndroid Build Coastguard Worker {
248*49fe348cSAndroid Build Coastguard Worker int n4 = def->n4;
249*49fe348cSAndroid Build Coastguard Worker
250*49fe348cSAndroid Build Coastguard Worker const float *x0 = x, *x1 = x0 + 2*n4;
251*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
252*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *y0 = y, *y1 = y0 + n4;
253*49fe348cSAndroid Build Coastguard Worker
254*49fe348cSAndroid Build Coastguard Worker while (x0 < x1) {
255*49fe348cSAndroid Build Coastguard Worker struct lc3_complex u, uw = *(w0++);
256*49fe348cSAndroid Build Coastguard Worker u.re = - *(--x1) * uw.re + *x0 * uw.im;
257*49fe348cSAndroid Build Coastguard Worker u.im = *(x0++) * uw.re + *x1 * uw.im;
258*49fe348cSAndroid Build Coastguard Worker
259*49fe348cSAndroid Build Coastguard Worker struct lc3_complex v, vw = *(--w1);
260*49fe348cSAndroid Build Coastguard Worker v.re = - *(--x1) * vw.im + *x0 * vw.re;
261*49fe348cSAndroid Build Coastguard Worker v.im = - *(x0++) * vw.im - *x1 * vw.re;
262*49fe348cSAndroid Build Coastguard Worker
263*49fe348cSAndroid Build Coastguard Worker *(y0++) = u;
264*49fe348cSAndroid Build Coastguard Worker *(--y1) = v;
265*49fe348cSAndroid Build Coastguard Worker }
266*49fe348cSAndroid Build Coastguard Worker }
267*49fe348cSAndroid Build Coastguard Worker
268*49fe348cSAndroid Build Coastguard Worker /**
269*49fe348cSAndroid Build Coastguard Worker * Post-rotate FFT N/4 points coefficients, resulting MDCT N points
270*49fe348cSAndroid Build Coastguard Worker * def Size and twiddles factors
271*49fe348cSAndroid Build Coastguard Worker * x, y Input and output coefficients
272*49fe348cSAndroid Build Coastguard Worker *
273*49fe348cSAndroid Build Coastguard Worker * `x` and y` can be the same buffer
274*49fe348cSAndroid Build Coastguard Worker */
mdct_post_fft(const struct lc3_mdct_rot_def * def,const struct lc3_complex * x,float * y)275*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void mdct_post_fft(const struct lc3_mdct_rot_def *def,
276*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x, float *y)
277*49fe348cSAndroid Build Coastguard Worker {
278*49fe348cSAndroid Build Coastguard Worker int n4 = def->n4, n8 = n4 >> 1;
279*49fe348cSAndroid Build Coastguard Worker
280*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *w0 = def->w + n8, *w1 = w0 - 1;
281*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x0 = x + n8, *x1 = x0 - 1;
282*49fe348cSAndroid Build Coastguard Worker
283*49fe348cSAndroid Build Coastguard Worker float *y0 = y + n4, *y1 = y0;
284*49fe348cSAndroid Build Coastguard Worker
285*49fe348cSAndroid Build Coastguard Worker for ( ; y1 > y; x0++, x1--, w0++, w1--) {
286*49fe348cSAndroid Build Coastguard Worker
287*49fe348cSAndroid Build Coastguard Worker float u0 = x0->im * w0->im + x0->re * w0->re;
288*49fe348cSAndroid Build Coastguard Worker float u1 = x1->re * w1->im - x1->im * w1->re;
289*49fe348cSAndroid Build Coastguard Worker
290*49fe348cSAndroid Build Coastguard Worker float v0 = x0->re * w0->im - x0->im * w0->re;
291*49fe348cSAndroid Build Coastguard Worker float v1 = x1->im * w1->im + x1->re * w1->re;
292*49fe348cSAndroid Build Coastguard Worker
293*49fe348cSAndroid Build Coastguard Worker *(y0++) = u0; *(y0++) = u1;
294*49fe348cSAndroid Build Coastguard Worker *(--y1) = v0; *(--y1) = v1;
295*49fe348cSAndroid Build Coastguard Worker }
296*49fe348cSAndroid Build Coastguard Worker }
297*49fe348cSAndroid Build Coastguard Worker
298*49fe348cSAndroid Build Coastguard Worker /**
299*49fe348cSAndroid Build Coastguard Worker * Pre-rotate IMDCT coefficients of N points, before FFT N/4 points FFT
300*49fe348cSAndroid Build Coastguard Worker * def Size and twiddles factors
301*49fe348cSAndroid Build Coastguard Worker * x, y Input and output coefficients
302*49fe348cSAndroid Build Coastguard Worker *
303*49fe348cSAndroid Build Coastguard Worker * `x` and `y` can be the same buffer
304*49fe348cSAndroid Build Coastguard Worker * The real and imaginary parts of `y` are swapped,
305*49fe348cSAndroid Build Coastguard Worker * to operate on FFT instead of IFFT
306*49fe348cSAndroid Build Coastguard Worker */
imdct_pre_fft(const struct lc3_mdct_rot_def * def,const float * x,struct lc3_complex * y)307*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void imdct_pre_fft(const struct lc3_mdct_rot_def *def,
308*49fe348cSAndroid Build Coastguard Worker const float *x, struct lc3_complex *y)
309*49fe348cSAndroid Build Coastguard Worker {
310*49fe348cSAndroid Build Coastguard Worker int n4 = def->n4;
311*49fe348cSAndroid Build Coastguard Worker
312*49fe348cSAndroid Build Coastguard Worker const float *x0 = x, *x1 = x0 + 2*n4;
313*49fe348cSAndroid Build Coastguard Worker
314*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
315*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *y0 = y, *y1 = y0 + n4;
316*49fe348cSAndroid Build Coastguard Worker
317*49fe348cSAndroid Build Coastguard Worker while (x0 < x1) {
318*49fe348cSAndroid Build Coastguard Worker float u0 = *(x0++), u1 = *(--x1);
319*49fe348cSAndroid Build Coastguard Worker float v0 = *(x0++), v1 = *(--x1);
320*49fe348cSAndroid Build Coastguard Worker struct lc3_complex uw = *(w0++), vw = *(--w1);
321*49fe348cSAndroid Build Coastguard Worker
322*49fe348cSAndroid Build Coastguard Worker (y0 )->re = - u0 * uw.re - u1 * uw.im;
323*49fe348cSAndroid Build Coastguard Worker (y0++)->im = - u1 * uw.re + u0 * uw.im;
324*49fe348cSAndroid Build Coastguard Worker
325*49fe348cSAndroid Build Coastguard Worker (--y1)->re = - v1 * vw.re - v0 * vw.im;
326*49fe348cSAndroid Build Coastguard Worker ( y1)->im = - v0 * vw.re + v1 * vw.im;
327*49fe348cSAndroid Build Coastguard Worker }
328*49fe348cSAndroid Build Coastguard Worker }
329*49fe348cSAndroid Build Coastguard Worker
330*49fe348cSAndroid Build Coastguard Worker /**
331*49fe348cSAndroid Build Coastguard Worker * Post-rotate FFT N/4 points coefficients, resulting IMDCT N points
332*49fe348cSAndroid Build Coastguard Worker * def Size and twiddles factors
333*49fe348cSAndroid Build Coastguard Worker * x, y Input and output coefficients
334*49fe348cSAndroid Build Coastguard Worker *
335*49fe348cSAndroid Build Coastguard Worker * `x` and y` can be the same buffer
336*49fe348cSAndroid Build Coastguard Worker * The real and imaginary parts of `x` are swapped,
337*49fe348cSAndroid Build Coastguard Worker * to operate on FFT instead of IFFT
338*49fe348cSAndroid Build Coastguard Worker */
imdct_post_fft(const struct lc3_mdct_rot_def * def,const struct lc3_complex * x,float * y)339*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void imdct_post_fft(const struct lc3_mdct_rot_def *def,
340*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x, float *y)
341*49fe348cSAndroid Build Coastguard Worker {
342*49fe348cSAndroid Build Coastguard Worker int n4 = def->n4;
343*49fe348cSAndroid Build Coastguard Worker
344*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
345*49fe348cSAndroid Build Coastguard Worker const struct lc3_complex *x0 = x, *x1 = x0 + n4;
346*49fe348cSAndroid Build Coastguard Worker
347*49fe348cSAndroid Build Coastguard Worker float *y0 = y, *y1 = y0 + 2*n4;
348*49fe348cSAndroid Build Coastguard Worker
349*49fe348cSAndroid Build Coastguard Worker while (x0 < x1) {
350*49fe348cSAndroid Build Coastguard Worker struct lc3_complex uz = *(x0++), vz = *(--x1);
351*49fe348cSAndroid Build Coastguard Worker struct lc3_complex uw = *(w0++), vw = *(--w1);
352*49fe348cSAndroid Build Coastguard Worker
353*49fe348cSAndroid Build Coastguard Worker *(y0++) = uz.re * uw.im - uz.im * uw.re;
354*49fe348cSAndroid Build Coastguard Worker *(--y1) = uz.re * uw.re + uz.im * uw.im;
355*49fe348cSAndroid Build Coastguard Worker
356*49fe348cSAndroid Build Coastguard Worker *(--y1) = vz.re * vw.im - vz.im * vw.re;
357*49fe348cSAndroid Build Coastguard Worker *(y0++) = vz.re * vw.re + vz.im * vw.im;
358*49fe348cSAndroid Build Coastguard Worker }
359*49fe348cSAndroid Build Coastguard Worker }
360*49fe348cSAndroid Build Coastguard Worker
361*49fe348cSAndroid Build Coastguard Worker /**
362*49fe348cSAndroid Build Coastguard Worker * Apply windowing of samples
363*49fe348cSAndroid Build Coastguard Worker * dt, sr Duration and samplerate
364*49fe348cSAndroid Build Coastguard Worker * x, d Middle half of IMDCT coefficients and delayed samples
365*49fe348cSAndroid Build Coastguard Worker * y, d Output samples and delayed ones
366*49fe348cSAndroid Build Coastguard Worker */
imdct_window(enum lc3_dt dt,enum lc3_srate sr,const float * x,float * d,float * y)367*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void imdct_window(
368*49fe348cSAndroid Build Coastguard Worker enum lc3_dt dt, enum lc3_srate sr,
369*49fe348cSAndroid Build Coastguard Worker const float *x, float *d, float *y)
370*49fe348cSAndroid Build Coastguard Worker {
371*49fe348cSAndroid Build Coastguard Worker /* The full MDCT coefficients is given by symmetry :
372*49fe348cSAndroid Build Coastguard Worker * T[ 0 .. n/4-1] = -half[n/4-1 .. 0 ]
373*49fe348cSAndroid Build Coastguard Worker * T[ n/4 .. n/2-1] = half[0 .. n/4-1]
374*49fe348cSAndroid Build Coastguard Worker * T[ n/2 .. 3n/4-1] = half[n/4 .. n/2-1]
375*49fe348cSAndroid Build Coastguard Worker * T[3n/4 .. n-1] = half[n/2-1 .. n/4 ] */
376*49fe348cSAndroid Build Coastguard Worker
377*49fe348cSAndroid Build Coastguard Worker const float *win = lc3_mdct_win[dt][sr];
378*49fe348cSAndroid Build Coastguard Worker int n4 = lc3_ns(dt, sr) >> 1, nd = lc3_nd(dt, sr);
379*49fe348cSAndroid Build Coastguard Worker const float *w2 = win, *w0 = w2 + 3*n4, *w1 = w0;
380*49fe348cSAndroid Build Coastguard Worker
381*49fe348cSAndroid Build Coastguard Worker const float *x0 = d + nd-n4, *x1 = x0;
382*49fe348cSAndroid Build Coastguard Worker float *y0 = y + nd-n4, *y1 = y0, *y2 = d + nd, *y3 = d;
383*49fe348cSAndroid Build Coastguard Worker
384*49fe348cSAndroid Build Coastguard Worker while (y0 > y) {
385*49fe348cSAndroid Build Coastguard Worker *(--y0) = *(--x0) - *(x ) * *(w1++);
386*49fe348cSAndroid Build Coastguard Worker *(y1++) = *(x1++) + *(x++) * *(--w0);
387*49fe348cSAndroid Build Coastguard Worker
388*49fe348cSAndroid Build Coastguard Worker *(--y0) = *(--x0) - *(x ) * *(w1++);
389*49fe348cSAndroid Build Coastguard Worker *(y1++) = *(x1++) + *(x++) * *(--w0);
390*49fe348cSAndroid Build Coastguard Worker }
391*49fe348cSAndroid Build Coastguard Worker
392*49fe348cSAndroid Build Coastguard Worker while (y1 < y + nd) {
393*49fe348cSAndroid Build Coastguard Worker *(y1++) = *(x1++) + *(x++) * *(--w0);
394*49fe348cSAndroid Build Coastguard Worker *(y1++) = *(x1++) + *(x++) * *(--w0);
395*49fe348cSAndroid Build Coastguard Worker }
396*49fe348cSAndroid Build Coastguard Worker
397*49fe348cSAndroid Build Coastguard Worker while (y1 < y + 2*n4) {
398*49fe348cSAndroid Build Coastguard Worker *(y1++) = *(x ) * *(--w0);
399*49fe348cSAndroid Build Coastguard Worker *(--y2) = *(x++) * *(w2++);
400*49fe348cSAndroid Build Coastguard Worker
401*49fe348cSAndroid Build Coastguard Worker *(y1++) = *(x ) * *(--w0);
402*49fe348cSAndroid Build Coastguard Worker *(--y2) = *(x++) * *(w2++);
403*49fe348cSAndroid Build Coastguard Worker }
404*49fe348cSAndroid Build Coastguard Worker
405*49fe348cSAndroid Build Coastguard Worker while (y2 > y3) {
406*49fe348cSAndroid Build Coastguard Worker *(y3++) = *(x ) * *(--w0);
407*49fe348cSAndroid Build Coastguard Worker *(--y2) = *(x++) * *(w2++);
408*49fe348cSAndroid Build Coastguard Worker
409*49fe348cSAndroid Build Coastguard Worker *(y3++) = *(x ) * *(--w0);
410*49fe348cSAndroid Build Coastguard Worker *(--y2) = *(x++) * *(w2++);
411*49fe348cSAndroid Build Coastguard Worker }
412*49fe348cSAndroid Build Coastguard Worker }
413*49fe348cSAndroid Build Coastguard Worker
414*49fe348cSAndroid Build Coastguard Worker /**
415*49fe348cSAndroid Build Coastguard Worker * Rescale samples
416*49fe348cSAndroid Build Coastguard Worker * x, n Input and count of samples, scaled as output
417*49fe348cSAndroid Build Coastguard Worker * scale Scale factor
418*49fe348cSAndroid Build Coastguard Worker */
rescale(float * x,int n,float f)419*49fe348cSAndroid Build Coastguard Worker LC3_HOT static void rescale(float *x, int n, float f)
420*49fe348cSAndroid Build Coastguard Worker {
421*49fe348cSAndroid Build Coastguard Worker for (int i = 0; i < (n >> 2); i++) {
422*49fe348cSAndroid Build Coastguard Worker *(x++) *= f; *(x++) *= f;
423*49fe348cSAndroid Build Coastguard Worker *(x++) *= f; *(x++) *= f;
424*49fe348cSAndroid Build Coastguard Worker }
425*49fe348cSAndroid Build Coastguard Worker }
426*49fe348cSAndroid Build Coastguard Worker
427*49fe348cSAndroid Build Coastguard Worker /**
428*49fe348cSAndroid Build Coastguard Worker * Forward MDCT transformation
429*49fe348cSAndroid Build Coastguard Worker */
lc3_mdct_forward(enum lc3_dt dt,enum lc3_srate sr,enum lc3_srate sr_dst,const float * x,float * d,float * y)430*49fe348cSAndroid Build Coastguard Worker void lc3_mdct_forward(
431*49fe348cSAndroid Build Coastguard Worker enum lc3_dt dt, enum lc3_srate sr, enum lc3_srate sr_dst,
432*49fe348cSAndroid Build Coastguard Worker const float *x, float *d, float *y)
433*49fe348cSAndroid Build Coastguard Worker {
434*49fe348cSAndroid Build Coastguard Worker const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
435*49fe348cSAndroid Build Coastguard Worker int ns_dst = lc3_ns(dt, sr_dst);
436*49fe348cSAndroid Build Coastguard Worker int ns = lc3_ns(dt, sr);
437*49fe348cSAndroid Build Coastguard Worker
438*49fe348cSAndroid Build Coastguard Worker struct lc3_complex buffer[LC3_MAX_NS / 2];
439*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *z = (struct lc3_complex *)y;
440*49fe348cSAndroid Build Coastguard Worker union { float *f; struct lc3_complex *z; } u = { .z = buffer };
441*49fe348cSAndroid Build Coastguard Worker
442*49fe348cSAndroid Build Coastguard Worker mdct_window(dt, sr, x, d, u.f);
443*49fe348cSAndroid Build Coastguard Worker
444*49fe348cSAndroid Build Coastguard Worker mdct_pre_fft(rot, u.f, u.z);
445*49fe348cSAndroid Build Coastguard Worker u.z = fft(u.z, ns/2, u.z, z);
446*49fe348cSAndroid Build Coastguard Worker mdct_post_fft(rot, u.z, y);
447*49fe348cSAndroid Build Coastguard Worker
448*49fe348cSAndroid Build Coastguard Worker if (ns != ns_dst)
449*49fe348cSAndroid Build Coastguard Worker rescale(y, ns_dst, sqrtf((float)ns_dst / ns));
450*49fe348cSAndroid Build Coastguard Worker }
451*49fe348cSAndroid Build Coastguard Worker
452*49fe348cSAndroid Build Coastguard Worker /**
453*49fe348cSAndroid Build Coastguard Worker * Inverse MDCT transformation
454*49fe348cSAndroid Build Coastguard Worker */
lc3_mdct_inverse(enum lc3_dt dt,enum lc3_srate sr,enum lc3_srate sr_src,const float * x,float * d,float * y)455*49fe348cSAndroid Build Coastguard Worker void lc3_mdct_inverse(
456*49fe348cSAndroid Build Coastguard Worker enum lc3_dt dt, enum lc3_srate sr, enum lc3_srate sr_src,
457*49fe348cSAndroid Build Coastguard Worker const float *x, float *d, float *y)
458*49fe348cSAndroid Build Coastguard Worker {
459*49fe348cSAndroid Build Coastguard Worker const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
460*49fe348cSAndroid Build Coastguard Worker int ns_src = lc3_ns(dt, sr_src);
461*49fe348cSAndroid Build Coastguard Worker int ns = lc3_ns(dt, sr);
462*49fe348cSAndroid Build Coastguard Worker
463*49fe348cSAndroid Build Coastguard Worker struct lc3_complex buffer[LC3_MAX_NS / 2];
464*49fe348cSAndroid Build Coastguard Worker struct lc3_complex *z = (struct lc3_complex *)y;
465*49fe348cSAndroid Build Coastguard Worker union { float *f; struct lc3_complex *z; } u = { .z = buffer };
466*49fe348cSAndroid Build Coastguard Worker
467*49fe348cSAndroid Build Coastguard Worker imdct_pre_fft(rot, x, z);
468*49fe348cSAndroid Build Coastguard Worker z = fft(z, ns/2, z, u.z);
469*49fe348cSAndroid Build Coastguard Worker imdct_post_fft(rot, z, u.f);
470*49fe348cSAndroid Build Coastguard Worker
471*49fe348cSAndroid Build Coastguard Worker if (ns != ns_src)
472*49fe348cSAndroid Build Coastguard Worker rescale(u.f, ns, sqrtf((float)ns / ns_src));
473*49fe348cSAndroid Build Coastguard Worker
474*49fe348cSAndroid Build Coastguard Worker imdct_window(dt, sr, u.f, d, y);
475*49fe348cSAndroid Build Coastguard Worker }
476