1*28e138c6SAndroid Build Coastguard Worker /*
2*28e138c6SAndroid Build Coastguard Worker Copyright (c) 2003-2004, Mark Borgerding
3*28e138c6SAndroid Build Coastguard Worker Copyright (c) 2005-2007, Jean-Marc Valin
4*28e138c6SAndroid Build Coastguard Worker
5*28e138c6SAndroid Build Coastguard Worker All rights reserved.
6*28e138c6SAndroid Build Coastguard Worker
7*28e138c6SAndroid Build Coastguard Worker Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
8*28e138c6SAndroid Build Coastguard Worker
9*28e138c6SAndroid Build Coastguard Worker * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
10*28e138c6SAndroid Build Coastguard Worker * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11*28e138c6SAndroid Build Coastguard Worker * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12*28e138c6SAndroid Build Coastguard Worker
13*28e138c6SAndroid Build Coastguard Worker THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14*28e138c6SAndroid Build Coastguard Worker */
15*28e138c6SAndroid Build Coastguard Worker
16*28e138c6SAndroid Build Coastguard Worker
17*28e138c6SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
18*28e138c6SAndroid Build Coastguard Worker #include "config.h"
19*28e138c6SAndroid Build Coastguard Worker #endif
20*28e138c6SAndroid Build Coastguard Worker
21*28e138c6SAndroid Build Coastguard Worker #include "_kiss_fft_guts.h"
22*28e138c6SAndroid Build Coastguard Worker #include "arch.h"
23*28e138c6SAndroid Build Coastguard Worker #include "os_support.h"
24*28e138c6SAndroid Build Coastguard Worker
25*28e138c6SAndroid Build Coastguard Worker /* The guts header contains all the multiplication and addition macros that are defined for
26*28e138c6SAndroid Build Coastguard Worker fixed or floating point complex numbers. It also delares the kf_ internal functions.
27*28e138c6SAndroid Build Coastguard Worker */
28*28e138c6SAndroid Build Coastguard Worker
kf_bfly2(kiss_fft_cpx * Fout,const size_t fstride,const kiss_fft_cfg st,int m,int N,int mm)29*28e138c6SAndroid Build Coastguard Worker static void kf_bfly2(
30*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout,
31*28e138c6SAndroid Build Coastguard Worker const size_t fstride,
32*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cfg st,
33*28e138c6SAndroid Build Coastguard Worker int m,
34*28e138c6SAndroid Build Coastguard Worker int N,
35*28e138c6SAndroid Build Coastguard Worker int mm
36*28e138c6SAndroid Build Coastguard Worker )
37*28e138c6SAndroid Build Coastguard Worker {
38*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout2;
39*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * tw1;
40*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx t;
41*28e138c6SAndroid Build Coastguard Worker if (!st->inverse) {
42*28e138c6SAndroid Build Coastguard Worker int i,j;
43*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout_beg = Fout;
44*28e138c6SAndroid Build Coastguard Worker for (i=0;i<N;i++)
45*28e138c6SAndroid Build Coastguard Worker {
46*28e138c6SAndroid Build Coastguard Worker Fout = Fout_beg + i*mm;
47*28e138c6SAndroid Build Coastguard Worker Fout2 = Fout + m;
48*28e138c6SAndroid Build Coastguard Worker tw1 = st->twiddles;
49*28e138c6SAndroid Build Coastguard Worker for(j=0;j<m;j++)
50*28e138c6SAndroid Build Coastguard Worker {
51*28e138c6SAndroid Build Coastguard Worker /* Almost the same as the code path below, except that we divide the input by two
52*28e138c6SAndroid Build Coastguard Worker (while keeping the best accuracy possible) */
53*28e138c6SAndroid Build Coastguard Worker spx_word32_t tr, ti;
54*28e138c6SAndroid Build Coastguard Worker tr = SHR32(SUB32(MULT16_16(Fout2->r , tw1->r),MULT16_16(Fout2->i , tw1->i)), 1);
55*28e138c6SAndroid Build Coastguard Worker ti = SHR32(ADD32(MULT16_16(Fout2->i , tw1->r),MULT16_16(Fout2->r , tw1->i)), 1);
56*28e138c6SAndroid Build Coastguard Worker tw1 += fstride;
57*28e138c6SAndroid Build Coastguard Worker Fout2->r = PSHR32(SUB32(SHL32(EXTEND32(Fout->r), 14), tr), 15);
58*28e138c6SAndroid Build Coastguard Worker Fout2->i = PSHR32(SUB32(SHL32(EXTEND32(Fout->i), 14), ti), 15);
59*28e138c6SAndroid Build Coastguard Worker Fout->r = PSHR32(ADD32(SHL32(EXTEND32(Fout->r), 14), tr), 15);
60*28e138c6SAndroid Build Coastguard Worker Fout->i = PSHR32(ADD32(SHL32(EXTEND32(Fout->i), 14), ti), 15);
61*28e138c6SAndroid Build Coastguard Worker ++Fout2;
62*28e138c6SAndroid Build Coastguard Worker ++Fout;
63*28e138c6SAndroid Build Coastguard Worker }
64*28e138c6SAndroid Build Coastguard Worker }
65*28e138c6SAndroid Build Coastguard Worker } else {
66*28e138c6SAndroid Build Coastguard Worker int i,j;
67*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout_beg = Fout;
68*28e138c6SAndroid Build Coastguard Worker for (i=0;i<N;i++)
69*28e138c6SAndroid Build Coastguard Worker {
70*28e138c6SAndroid Build Coastguard Worker Fout = Fout_beg + i*mm;
71*28e138c6SAndroid Build Coastguard Worker Fout2 = Fout + m;
72*28e138c6SAndroid Build Coastguard Worker tw1 = st->twiddles;
73*28e138c6SAndroid Build Coastguard Worker for(j=0;j<m;j++)
74*28e138c6SAndroid Build Coastguard Worker {
75*28e138c6SAndroid Build Coastguard Worker C_MUL (t, *Fout2 , *tw1);
76*28e138c6SAndroid Build Coastguard Worker tw1 += fstride;
77*28e138c6SAndroid Build Coastguard Worker C_SUB( *Fout2 , *Fout , t );
78*28e138c6SAndroid Build Coastguard Worker C_ADDTO( *Fout , t );
79*28e138c6SAndroid Build Coastguard Worker ++Fout2;
80*28e138c6SAndroid Build Coastguard Worker ++Fout;
81*28e138c6SAndroid Build Coastguard Worker }
82*28e138c6SAndroid Build Coastguard Worker }
83*28e138c6SAndroid Build Coastguard Worker }
84*28e138c6SAndroid Build Coastguard Worker }
85*28e138c6SAndroid Build Coastguard Worker
kf_bfly4(kiss_fft_cpx * Fout,const size_t fstride,const kiss_fft_cfg st,int m,int N,int mm)86*28e138c6SAndroid Build Coastguard Worker static void kf_bfly4(
87*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout,
88*28e138c6SAndroid Build Coastguard Worker const size_t fstride,
89*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cfg st,
90*28e138c6SAndroid Build Coastguard Worker int m,
91*28e138c6SAndroid Build Coastguard Worker int N,
92*28e138c6SAndroid Build Coastguard Worker int mm
93*28e138c6SAndroid Build Coastguard Worker )
94*28e138c6SAndroid Build Coastguard Worker {
95*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx *tw1,*tw2,*tw3;
96*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx scratch[6];
97*28e138c6SAndroid Build Coastguard Worker const size_t m2=2*m;
98*28e138c6SAndroid Build Coastguard Worker const size_t m3=3*m;
99*28e138c6SAndroid Build Coastguard Worker int i, j;
100*28e138c6SAndroid Build Coastguard Worker
101*28e138c6SAndroid Build Coastguard Worker if (st->inverse)
102*28e138c6SAndroid Build Coastguard Worker {
103*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout_beg = Fout;
104*28e138c6SAndroid Build Coastguard Worker for (i=0;i<N;i++)
105*28e138c6SAndroid Build Coastguard Worker {
106*28e138c6SAndroid Build Coastguard Worker Fout = Fout_beg + i*mm;
107*28e138c6SAndroid Build Coastguard Worker tw3 = tw2 = tw1 = st->twiddles;
108*28e138c6SAndroid Build Coastguard Worker for (j=0;j<m;j++)
109*28e138c6SAndroid Build Coastguard Worker {
110*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[0],Fout[m] , *tw1 );
111*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[1],Fout[m2] , *tw2 );
112*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[2],Fout[m3] , *tw3 );
113*28e138c6SAndroid Build Coastguard Worker
114*28e138c6SAndroid Build Coastguard Worker C_SUB( scratch[5] , *Fout, scratch[1] );
115*28e138c6SAndroid Build Coastguard Worker C_ADDTO(*Fout, scratch[1]);
116*28e138c6SAndroid Build Coastguard Worker C_ADD( scratch[3] , scratch[0] , scratch[2] );
117*28e138c6SAndroid Build Coastguard Worker C_SUB( scratch[4] , scratch[0] , scratch[2] );
118*28e138c6SAndroid Build Coastguard Worker C_SUB( Fout[m2], *Fout, scratch[3] );
119*28e138c6SAndroid Build Coastguard Worker tw1 += fstride;
120*28e138c6SAndroid Build Coastguard Worker tw2 += fstride*2;
121*28e138c6SAndroid Build Coastguard Worker tw3 += fstride*3;
122*28e138c6SAndroid Build Coastguard Worker C_ADDTO( *Fout , scratch[3] );
123*28e138c6SAndroid Build Coastguard Worker
124*28e138c6SAndroid Build Coastguard Worker Fout[m].r = scratch[5].r - scratch[4].i;
125*28e138c6SAndroid Build Coastguard Worker Fout[m].i = scratch[5].i + scratch[4].r;
126*28e138c6SAndroid Build Coastguard Worker Fout[m3].r = scratch[5].r + scratch[4].i;
127*28e138c6SAndroid Build Coastguard Worker Fout[m3].i = scratch[5].i - scratch[4].r;
128*28e138c6SAndroid Build Coastguard Worker ++Fout;
129*28e138c6SAndroid Build Coastguard Worker }
130*28e138c6SAndroid Build Coastguard Worker }
131*28e138c6SAndroid Build Coastguard Worker } else
132*28e138c6SAndroid Build Coastguard Worker {
133*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout_beg = Fout;
134*28e138c6SAndroid Build Coastguard Worker for (i=0;i<N;i++)
135*28e138c6SAndroid Build Coastguard Worker {
136*28e138c6SAndroid Build Coastguard Worker Fout = Fout_beg + i*mm;
137*28e138c6SAndroid Build Coastguard Worker tw3 = tw2 = tw1 = st->twiddles;
138*28e138c6SAndroid Build Coastguard Worker for (j=0;j<m;j++)
139*28e138c6SAndroid Build Coastguard Worker {
140*28e138c6SAndroid Build Coastguard Worker C_MUL4(scratch[0],Fout[m] , *tw1 );
141*28e138c6SAndroid Build Coastguard Worker C_MUL4(scratch[1],Fout[m2] , *tw2 );
142*28e138c6SAndroid Build Coastguard Worker C_MUL4(scratch[2],Fout[m3] , *tw3 );
143*28e138c6SAndroid Build Coastguard Worker
144*28e138c6SAndroid Build Coastguard Worker Fout->r = PSHR16(Fout->r, 2);
145*28e138c6SAndroid Build Coastguard Worker Fout->i = PSHR16(Fout->i, 2);
146*28e138c6SAndroid Build Coastguard Worker C_SUB( scratch[5] , *Fout, scratch[1] );
147*28e138c6SAndroid Build Coastguard Worker C_ADDTO(*Fout, scratch[1]);
148*28e138c6SAndroid Build Coastguard Worker C_ADD( scratch[3] , scratch[0] , scratch[2] );
149*28e138c6SAndroid Build Coastguard Worker C_SUB( scratch[4] , scratch[0] , scratch[2] );
150*28e138c6SAndroid Build Coastguard Worker Fout[m2].r = PSHR16(Fout[m2].r, 2);
151*28e138c6SAndroid Build Coastguard Worker Fout[m2].i = PSHR16(Fout[m2].i, 2);
152*28e138c6SAndroid Build Coastguard Worker C_SUB( Fout[m2], *Fout, scratch[3] );
153*28e138c6SAndroid Build Coastguard Worker tw1 += fstride;
154*28e138c6SAndroid Build Coastguard Worker tw2 += fstride*2;
155*28e138c6SAndroid Build Coastguard Worker tw3 += fstride*3;
156*28e138c6SAndroid Build Coastguard Worker C_ADDTO( *Fout , scratch[3] );
157*28e138c6SAndroid Build Coastguard Worker
158*28e138c6SAndroid Build Coastguard Worker Fout[m].r = scratch[5].r + scratch[4].i;
159*28e138c6SAndroid Build Coastguard Worker Fout[m].i = scratch[5].i - scratch[4].r;
160*28e138c6SAndroid Build Coastguard Worker Fout[m3].r = scratch[5].r - scratch[4].i;
161*28e138c6SAndroid Build Coastguard Worker Fout[m3].i = scratch[5].i + scratch[4].r;
162*28e138c6SAndroid Build Coastguard Worker ++Fout;
163*28e138c6SAndroid Build Coastguard Worker }
164*28e138c6SAndroid Build Coastguard Worker }
165*28e138c6SAndroid Build Coastguard Worker }
166*28e138c6SAndroid Build Coastguard Worker }
167*28e138c6SAndroid Build Coastguard Worker
kf_bfly3(kiss_fft_cpx * Fout,const size_t fstride,const kiss_fft_cfg st,size_t m)168*28e138c6SAndroid Build Coastguard Worker static void kf_bfly3(
169*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout,
170*28e138c6SAndroid Build Coastguard Worker const size_t fstride,
171*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cfg st,
172*28e138c6SAndroid Build Coastguard Worker size_t m
173*28e138c6SAndroid Build Coastguard Worker )
174*28e138c6SAndroid Build Coastguard Worker {
175*28e138c6SAndroid Build Coastguard Worker size_t k=m;
176*28e138c6SAndroid Build Coastguard Worker const size_t m2 = 2*m;
177*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx *tw1,*tw2;
178*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx scratch[5];
179*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx epi3;
180*28e138c6SAndroid Build Coastguard Worker epi3 = st->twiddles[fstride*m];
181*28e138c6SAndroid Build Coastguard Worker
182*28e138c6SAndroid Build Coastguard Worker tw1=tw2=st->twiddles;
183*28e138c6SAndroid Build Coastguard Worker
184*28e138c6SAndroid Build Coastguard Worker do{
185*28e138c6SAndroid Build Coastguard Worker if (!st->inverse) {
186*28e138c6SAndroid Build Coastguard Worker C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
187*28e138c6SAndroid Build Coastguard Worker }
188*28e138c6SAndroid Build Coastguard Worker
189*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[1],Fout[m] , *tw1);
190*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[2],Fout[m2] , *tw2);
191*28e138c6SAndroid Build Coastguard Worker
192*28e138c6SAndroid Build Coastguard Worker C_ADD(scratch[3],scratch[1],scratch[2]);
193*28e138c6SAndroid Build Coastguard Worker C_SUB(scratch[0],scratch[1],scratch[2]);
194*28e138c6SAndroid Build Coastguard Worker tw1 += fstride;
195*28e138c6SAndroid Build Coastguard Worker tw2 += fstride*2;
196*28e138c6SAndroid Build Coastguard Worker
197*28e138c6SAndroid Build Coastguard Worker Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
198*28e138c6SAndroid Build Coastguard Worker Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
199*28e138c6SAndroid Build Coastguard Worker
200*28e138c6SAndroid Build Coastguard Worker C_MULBYSCALAR( scratch[0] , epi3.i );
201*28e138c6SAndroid Build Coastguard Worker
202*28e138c6SAndroid Build Coastguard Worker C_ADDTO(*Fout,scratch[3]);
203*28e138c6SAndroid Build Coastguard Worker
204*28e138c6SAndroid Build Coastguard Worker Fout[m2].r = Fout[m].r + scratch[0].i;
205*28e138c6SAndroid Build Coastguard Worker Fout[m2].i = Fout[m].i - scratch[0].r;
206*28e138c6SAndroid Build Coastguard Worker
207*28e138c6SAndroid Build Coastguard Worker Fout[m].r -= scratch[0].i;
208*28e138c6SAndroid Build Coastguard Worker Fout[m].i += scratch[0].r;
209*28e138c6SAndroid Build Coastguard Worker
210*28e138c6SAndroid Build Coastguard Worker ++Fout;
211*28e138c6SAndroid Build Coastguard Worker }while(--k);
212*28e138c6SAndroid Build Coastguard Worker }
213*28e138c6SAndroid Build Coastguard Worker
kf_bfly5(kiss_fft_cpx * Fout,const size_t fstride,const kiss_fft_cfg st,int m)214*28e138c6SAndroid Build Coastguard Worker static void kf_bfly5(
215*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout,
216*28e138c6SAndroid Build Coastguard Worker const size_t fstride,
217*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cfg st,
218*28e138c6SAndroid Build Coastguard Worker int m
219*28e138c6SAndroid Build Coastguard Worker )
220*28e138c6SAndroid Build Coastguard Worker {
221*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
222*28e138c6SAndroid Build Coastguard Worker int u;
223*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx scratch[13];
224*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * twiddles = st->twiddles;
225*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx *tw;
226*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx ya,yb;
227*28e138c6SAndroid Build Coastguard Worker ya = twiddles[fstride*m];
228*28e138c6SAndroid Build Coastguard Worker yb = twiddles[fstride*2*m];
229*28e138c6SAndroid Build Coastguard Worker
230*28e138c6SAndroid Build Coastguard Worker Fout0=Fout;
231*28e138c6SAndroid Build Coastguard Worker Fout1=Fout0+m;
232*28e138c6SAndroid Build Coastguard Worker Fout2=Fout0+2*m;
233*28e138c6SAndroid Build Coastguard Worker Fout3=Fout0+3*m;
234*28e138c6SAndroid Build Coastguard Worker Fout4=Fout0+4*m;
235*28e138c6SAndroid Build Coastguard Worker
236*28e138c6SAndroid Build Coastguard Worker tw=st->twiddles;
237*28e138c6SAndroid Build Coastguard Worker for ( u=0; u<m; ++u ) {
238*28e138c6SAndroid Build Coastguard Worker if (!st->inverse) {
239*28e138c6SAndroid Build Coastguard Worker C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
240*28e138c6SAndroid Build Coastguard Worker }
241*28e138c6SAndroid Build Coastguard Worker scratch[0] = *Fout0;
242*28e138c6SAndroid Build Coastguard Worker
243*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
244*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
245*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
246*28e138c6SAndroid Build Coastguard Worker C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
247*28e138c6SAndroid Build Coastguard Worker
248*28e138c6SAndroid Build Coastguard Worker C_ADD( scratch[7],scratch[1],scratch[4]);
249*28e138c6SAndroid Build Coastguard Worker C_SUB( scratch[10],scratch[1],scratch[4]);
250*28e138c6SAndroid Build Coastguard Worker C_ADD( scratch[8],scratch[2],scratch[3]);
251*28e138c6SAndroid Build Coastguard Worker C_SUB( scratch[9],scratch[2],scratch[3]);
252*28e138c6SAndroid Build Coastguard Worker
253*28e138c6SAndroid Build Coastguard Worker Fout0->r += scratch[7].r + scratch[8].r;
254*28e138c6SAndroid Build Coastguard Worker Fout0->i += scratch[7].i + scratch[8].i;
255*28e138c6SAndroid Build Coastguard Worker
256*28e138c6SAndroid Build Coastguard Worker scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
257*28e138c6SAndroid Build Coastguard Worker scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
258*28e138c6SAndroid Build Coastguard Worker
259*28e138c6SAndroid Build Coastguard Worker scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
260*28e138c6SAndroid Build Coastguard Worker scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
261*28e138c6SAndroid Build Coastguard Worker
262*28e138c6SAndroid Build Coastguard Worker C_SUB(*Fout1,scratch[5],scratch[6]);
263*28e138c6SAndroid Build Coastguard Worker C_ADD(*Fout4,scratch[5],scratch[6]);
264*28e138c6SAndroid Build Coastguard Worker
265*28e138c6SAndroid Build Coastguard Worker scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
266*28e138c6SAndroid Build Coastguard Worker scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
267*28e138c6SAndroid Build Coastguard Worker scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
268*28e138c6SAndroid Build Coastguard Worker scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
269*28e138c6SAndroid Build Coastguard Worker
270*28e138c6SAndroid Build Coastguard Worker C_ADD(*Fout2,scratch[11],scratch[12]);
271*28e138c6SAndroid Build Coastguard Worker C_SUB(*Fout3,scratch[11],scratch[12]);
272*28e138c6SAndroid Build Coastguard Worker
273*28e138c6SAndroid Build Coastguard Worker ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
274*28e138c6SAndroid Build Coastguard Worker }
275*28e138c6SAndroid Build Coastguard Worker }
276*28e138c6SAndroid Build Coastguard Worker
277*28e138c6SAndroid Build Coastguard Worker /* perform the butterfly for one stage of a mixed radix FFT */
kf_bfly_generic(kiss_fft_cpx * Fout,const size_t fstride,const kiss_fft_cfg st,int m,int p)278*28e138c6SAndroid Build Coastguard Worker static void kf_bfly_generic(
279*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout,
280*28e138c6SAndroid Build Coastguard Worker const size_t fstride,
281*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cfg st,
282*28e138c6SAndroid Build Coastguard Worker int m,
283*28e138c6SAndroid Build Coastguard Worker int p
284*28e138c6SAndroid Build Coastguard Worker )
285*28e138c6SAndroid Build Coastguard Worker {
286*28e138c6SAndroid Build Coastguard Worker int u,k,q1,q;
287*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * twiddles = st->twiddles;
288*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx t;
289*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx scratchbuf[17];
290*28e138c6SAndroid Build Coastguard Worker int Norig = st->nfft;
291*28e138c6SAndroid Build Coastguard Worker
292*28e138c6SAndroid Build Coastguard Worker /*CHECKBUF(scratchbuf,nscratchbuf,p);*/
293*28e138c6SAndroid Build Coastguard Worker if (p>17)
294*28e138c6SAndroid Build Coastguard Worker speex_fatal("KissFFT: max radix supported is 17");
295*28e138c6SAndroid Build Coastguard Worker
296*28e138c6SAndroid Build Coastguard Worker for ( u=0; u<m; ++u ) {
297*28e138c6SAndroid Build Coastguard Worker k=u;
298*28e138c6SAndroid Build Coastguard Worker for ( q1=0 ; q1<p ; ++q1 ) {
299*28e138c6SAndroid Build Coastguard Worker scratchbuf[q1] = Fout[ k ];
300*28e138c6SAndroid Build Coastguard Worker if (!st->inverse) {
301*28e138c6SAndroid Build Coastguard Worker C_FIXDIV(scratchbuf[q1],p);
302*28e138c6SAndroid Build Coastguard Worker }
303*28e138c6SAndroid Build Coastguard Worker k += m;
304*28e138c6SAndroid Build Coastguard Worker }
305*28e138c6SAndroid Build Coastguard Worker
306*28e138c6SAndroid Build Coastguard Worker k=u;
307*28e138c6SAndroid Build Coastguard Worker for ( q1=0 ; q1<p ; ++q1 ) {
308*28e138c6SAndroid Build Coastguard Worker int twidx=0;
309*28e138c6SAndroid Build Coastguard Worker Fout[ k ] = scratchbuf[0];
310*28e138c6SAndroid Build Coastguard Worker for (q=1;q<p;++q ) {
311*28e138c6SAndroid Build Coastguard Worker twidx += fstride * k;
312*28e138c6SAndroid Build Coastguard Worker if (twidx>=Norig) twidx-=Norig;
313*28e138c6SAndroid Build Coastguard Worker C_MUL(t,scratchbuf[q] , twiddles[twidx] );
314*28e138c6SAndroid Build Coastguard Worker C_ADDTO( Fout[ k ] ,t);
315*28e138c6SAndroid Build Coastguard Worker }
316*28e138c6SAndroid Build Coastguard Worker k += m;
317*28e138c6SAndroid Build Coastguard Worker }
318*28e138c6SAndroid Build Coastguard Worker }
319*28e138c6SAndroid Build Coastguard Worker }
320*28e138c6SAndroid Build Coastguard Worker
321*28e138c6SAndroid Build Coastguard Worker static
kf_shuffle(kiss_fft_cpx * Fout,const kiss_fft_cpx * f,const size_t fstride,int in_stride,int * factors,const kiss_fft_cfg st)322*28e138c6SAndroid Build Coastguard Worker void kf_shuffle(
323*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout,
324*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cpx * f,
325*28e138c6SAndroid Build Coastguard Worker const size_t fstride,
326*28e138c6SAndroid Build Coastguard Worker int in_stride,
327*28e138c6SAndroid Build Coastguard Worker int * factors,
328*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cfg st
329*28e138c6SAndroid Build Coastguard Worker )
330*28e138c6SAndroid Build Coastguard Worker {
331*28e138c6SAndroid Build Coastguard Worker const int p=*factors++; /* the radix */
332*28e138c6SAndroid Build Coastguard Worker const int m=*factors++; /* stage's fft length/p */
333*28e138c6SAndroid Build Coastguard Worker
334*28e138c6SAndroid Build Coastguard Worker /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
335*28e138c6SAndroid Build Coastguard Worker if (m==1)
336*28e138c6SAndroid Build Coastguard Worker {
337*28e138c6SAndroid Build Coastguard Worker int j;
338*28e138c6SAndroid Build Coastguard Worker for (j=0;j<p;j++)
339*28e138c6SAndroid Build Coastguard Worker {
340*28e138c6SAndroid Build Coastguard Worker Fout[j] = *f;
341*28e138c6SAndroid Build Coastguard Worker f += fstride*in_stride;
342*28e138c6SAndroid Build Coastguard Worker }
343*28e138c6SAndroid Build Coastguard Worker } else {
344*28e138c6SAndroid Build Coastguard Worker int j;
345*28e138c6SAndroid Build Coastguard Worker for (j=0;j<p;j++)
346*28e138c6SAndroid Build Coastguard Worker {
347*28e138c6SAndroid Build Coastguard Worker kf_shuffle( Fout , f, fstride*p, in_stride, factors,st);
348*28e138c6SAndroid Build Coastguard Worker f += fstride*in_stride;
349*28e138c6SAndroid Build Coastguard Worker Fout += m;
350*28e138c6SAndroid Build Coastguard Worker }
351*28e138c6SAndroid Build Coastguard Worker }
352*28e138c6SAndroid Build Coastguard Worker }
353*28e138c6SAndroid Build Coastguard Worker
354*28e138c6SAndroid Build Coastguard Worker static
kf_work(kiss_fft_cpx * Fout,const kiss_fft_cpx * f,const size_t fstride,int in_stride,int * factors,const kiss_fft_cfg st,int N,int s2,int m2)355*28e138c6SAndroid Build Coastguard Worker void kf_work(
356*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout,
357*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cpx * f,
358*28e138c6SAndroid Build Coastguard Worker const size_t fstride,
359*28e138c6SAndroid Build Coastguard Worker int in_stride,
360*28e138c6SAndroid Build Coastguard Worker int * factors,
361*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cfg st,
362*28e138c6SAndroid Build Coastguard Worker int N,
363*28e138c6SAndroid Build Coastguard Worker int s2,
364*28e138c6SAndroid Build Coastguard Worker int m2
365*28e138c6SAndroid Build Coastguard Worker )
366*28e138c6SAndroid Build Coastguard Worker {
367*28e138c6SAndroid Build Coastguard Worker int i;
368*28e138c6SAndroid Build Coastguard Worker kiss_fft_cpx * Fout_beg=Fout;
369*28e138c6SAndroid Build Coastguard Worker const int p=*factors++; /* the radix */
370*28e138c6SAndroid Build Coastguard Worker const int m=*factors++; /* stage's fft length/p */
371*28e138c6SAndroid Build Coastguard Worker #if 0
372*28e138c6SAndroid Build Coastguard Worker /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
373*28e138c6SAndroid Build Coastguard Worker if (m==1)
374*28e138c6SAndroid Build Coastguard Worker {
375*28e138c6SAndroid Build Coastguard Worker /* int j;
376*28e138c6SAndroid Build Coastguard Worker for (j=0;j<p;j++)
377*28e138c6SAndroid Build Coastguard Worker {
378*28e138c6SAndroid Build Coastguard Worker Fout[j] = *f;
379*28e138c6SAndroid Build Coastguard Worker f += fstride*in_stride;
380*28e138c6SAndroid Build Coastguard Worker }*/
381*28e138c6SAndroid Build Coastguard Worker } else {
382*28e138c6SAndroid Build Coastguard Worker int j;
383*28e138c6SAndroid Build Coastguard Worker for (j=0;j<p;j++)
384*28e138c6SAndroid Build Coastguard Worker {
385*28e138c6SAndroid Build Coastguard Worker kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
386*28e138c6SAndroid Build Coastguard Worker f += fstride*in_stride;
387*28e138c6SAndroid Build Coastguard Worker Fout += m;
388*28e138c6SAndroid Build Coastguard Worker }
389*28e138c6SAndroid Build Coastguard Worker }
390*28e138c6SAndroid Build Coastguard Worker
391*28e138c6SAndroid Build Coastguard Worker Fout=Fout_beg;
392*28e138c6SAndroid Build Coastguard Worker
393*28e138c6SAndroid Build Coastguard Worker switch (p) {
394*28e138c6SAndroid Build Coastguard Worker case 2: kf_bfly2(Fout,fstride,st,m); break;
395*28e138c6SAndroid Build Coastguard Worker case 3: kf_bfly3(Fout,fstride,st,m); break;
396*28e138c6SAndroid Build Coastguard Worker case 4: kf_bfly4(Fout,fstride,st,m); break;
397*28e138c6SAndroid Build Coastguard Worker case 5: kf_bfly5(Fout,fstride,st,m); break;
398*28e138c6SAndroid Build Coastguard Worker default: kf_bfly_generic(Fout,fstride,st,m,p); break;
399*28e138c6SAndroid Build Coastguard Worker }
400*28e138c6SAndroid Build Coastguard Worker #else
401*28e138c6SAndroid Build Coastguard Worker /*printf ("fft %d %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N, m2);*/
402*28e138c6SAndroid Build Coastguard Worker if (m==1)
403*28e138c6SAndroid Build Coastguard Worker {
404*28e138c6SAndroid Build Coastguard Worker /*for (i=0;i<N;i++)
405*28e138c6SAndroid Build Coastguard Worker {
406*28e138c6SAndroid Build Coastguard Worker int j;
407*28e138c6SAndroid Build Coastguard Worker Fout = Fout_beg+i*m2;
408*28e138c6SAndroid Build Coastguard Worker const kiss_fft_cpx * f2 = f+i*s2;
409*28e138c6SAndroid Build Coastguard Worker for (j=0;j<p;j++)
410*28e138c6SAndroid Build Coastguard Worker {
411*28e138c6SAndroid Build Coastguard Worker *Fout++ = *f2;
412*28e138c6SAndroid Build Coastguard Worker f2 += fstride*in_stride;
413*28e138c6SAndroid Build Coastguard Worker }
414*28e138c6SAndroid Build Coastguard Worker }*/
415*28e138c6SAndroid Build Coastguard Worker }else{
416*28e138c6SAndroid Build Coastguard Worker kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
417*28e138c6SAndroid Build Coastguard Worker }
418*28e138c6SAndroid Build Coastguard Worker
419*28e138c6SAndroid Build Coastguard Worker
420*28e138c6SAndroid Build Coastguard Worker
421*28e138c6SAndroid Build Coastguard Worker
422*28e138c6SAndroid Build Coastguard Worker switch (p) {
423*28e138c6SAndroid Build Coastguard Worker case 2: kf_bfly2(Fout,fstride,st,m, N, m2); break;
424*28e138c6SAndroid Build Coastguard Worker case 3: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly3(Fout,fstride,st,m);} break;
425*28e138c6SAndroid Build Coastguard Worker case 4: kf_bfly4(Fout,fstride,st,m, N, m2); break;
426*28e138c6SAndroid Build Coastguard Worker case 5: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly5(Fout,fstride,st,m);} break;
427*28e138c6SAndroid Build Coastguard Worker default: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly_generic(Fout,fstride,st,m,p);} break;
428*28e138c6SAndroid Build Coastguard Worker }
429*28e138c6SAndroid Build Coastguard Worker #endif
430*28e138c6SAndroid Build Coastguard Worker }
431*28e138c6SAndroid Build Coastguard Worker
432*28e138c6SAndroid Build Coastguard Worker /* facbuf is populated by p1,m1,p2,m2, ...
433*28e138c6SAndroid Build Coastguard Worker where
434*28e138c6SAndroid Build Coastguard Worker p[i] * m[i] = m[i-1]
435*28e138c6SAndroid Build Coastguard Worker m0 = n */
436*28e138c6SAndroid Build Coastguard Worker static
kf_factor(int n,int * facbuf)437*28e138c6SAndroid Build Coastguard Worker void kf_factor(int n,int * facbuf)
438*28e138c6SAndroid Build Coastguard Worker {
439*28e138c6SAndroid Build Coastguard Worker int p=4;
440*28e138c6SAndroid Build Coastguard Worker
441*28e138c6SAndroid Build Coastguard Worker /*factor out powers of 4, powers of 2, then any remaining primes */
442*28e138c6SAndroid Build Coastguard Worker do {
443*28e138c6SAndroid Build Coastguard Worker while (n % p) {
444*28e138c6SAndroid Build Coastguard Worker switch (p) {
445*28e138c6SAndroid Build Coastguard Worker case 4: p = 2; break;
446*28e138c6SAndroid Build Coastguard Worker case 2: p = 3; break;
447*28e138c6SAndroid Build Coastguard Worker default: p += 2; break;
448*28e138c6SAndroid Build Coastguard Worker }
449*28e138c6SAndroid Build Coastguard Worker if (p>32000 || (spx_int32_t)p*(spx_int32_t)p > n)
450*28e138c6SAndroid Build Coastguard Worker p = n; /* no more factors, skip to end */
451*28e138c6SAndroid Build Coastguard Worker }
452*28e138c6SAndroid Build Coastguard Worker n /= p;
453*28e138c6SAndroid Build Coastguard Worker *facbuf++ = p;
454*28e138c6SAndroid Build Coastguard Worker *facbuf++ = n;
455*28e138c6SAndroid Build Coastguard Worker } while (n > 1);
456*28e138c6SAndroid Build Coastguard Worker }
457*28e138c6SAndroid Build Coastguard Worker /*
458*28e138c6SAndroid Build Coastguard Worker *
459*28e138c6SAndroid Build Coastguard Worker * User-callable function to allocate all necessary storage space for the fft.
460*28e138c6SAndroid Build Coastguard Worker *
461*28e138c6SAndroid Build Coastguard Worker * The return value is a contiguous block of memory, allocated with malloc. As such,
462*28e138c6SAndroid Build Coastguard Worker * It can be freed with free(), rather than a kiss_fft-specific function.
463*28e138c6SAndroid Build Coastguard Worker * */
kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)464*28e138c6SAndroid Build Coastguard Worker kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
465*28e138c6SAndroid Build Coastguard Worker {
466*28e138c6SAndroid Build Coastguard Worker kiss_fft_cfg st=NULL;
467*28e138c6SAndroid Build Coastguard Worker size_t memneeded = sizeof(struct kiss_fft_state)
468*28e138c6SAndroid Build Coastguard Worker + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
469*28e138c6SAndroid Build Coastguard Worker
470*28e138c6SAndroid Build Coastguard Worker if ( lenmem==NULL ) {
471*28e138c6SAndroid Build Coastguard Worker st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
472*28e138c6SAndroid Build Coastguard Worker }else{
473*28e138c6SAndroid Build Coastguard Worker if (mem != NULL && *lenmem >= memneeded)
474*28e138c6SAndroid Build Coastguard Worker st = (kiss_fft_cfg)mem;
475*28e138c6SAndroid Build Coastguard Worker *lenmem = memneeded;
476*28e138c6SAndroid Build Coastguard Worker }
477*28e138c6SAndroid Build Coastguard Worker if (st) {
478*28e138c6SAndroid Build Coastguard Worker int i;
479*28e138c6SAndroid Build Coastguard Worker st->nfft=nfft;
480*28e138c6SAndroid Build Coastguard Worker st->inverse = inverse_fft;
481*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
482*28e138c6SAndroid Build Coastguard Worker for (i=0;i<nfft;++i) {
483*28e138c6SAndroid Build Coastguard Worker spx_word32_t phase = i;
484*28e138c6SAndroid Build Coastguard Worker if (!st->inverse)
485*28e138c6SAndroid Build Coastguard Worker phase = -phase;
486*28e138c6SAndroid Build Coastguard Worker kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft));
487*28e138c6SAndroid Build Coastguard Worker }
488*28e138c6SAndroid Build Coastguard Worker #else
489*28e138c6SAndroid Build Coastguard Worker for (i=0;i<nfft;++i) {
490*28e138c6SAndroid Build Coastguard Worker const double pi=3.14159265358979323846264338327;
491*28e138c6SAndroid Build Coastguard Worker double phase = ( -2*pi /nfft ) * i;
492*28e138c6SAndroid Build Coastguard Worker if (st->inverse)
493*28e138c6SAndroid Build Coastguard Worker phase *= -1;
494*28e138c6SAndroid Build Coastguard Worker kf_cexp(st->twiddles+i, phase );
495*28e138c6SAndroid Build Coastguard Worker }
496*28e138c6SAndroid Build Coastguard Worker #endif
497*28e138c6SAndroid Build Coastguard Worker kf_factor(nfft,st->factors);
498*28e138c6SAndroid Build Coastguard Worker }
499*28e138c6SAndroid Build Coastguard Worker return st;
500*28e138c6SAndroid Build Coastguard Worker }
501*28e138c6SAndroid Build Coastguard Worker
502*28e138c6SAndroid Build Coastguard Worker
503*28e138c6SAndroid Build Coastguard Worker
504*28e138c6SAndroid Build Coastguard Worker
kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx * fin,kiss_fft_cpx * fout,int in_stride)505*28e138c6SAndroid Build Coastguard Worker void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
506*28e138c6SAndroid Build Coastguard Worker {
507*28e138c6SAndroid Build Coastguard Worker if (fin == fout)
508*28e138c6SAndroid Build Coastguard Worker {
509*28e138c6SAndroid Build Coastguard Worker speex_fatal("In-place FFT not supported");
510*28e138c6SAndroid Build Coastguard Worker /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
511*28e138c6SAndroid Build Coastguard Worker kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
512*28e138c6SAndroid Build Coastguard Worker SPEEX_MOVE(fout,tmpbuf,st->nfft);*/
513*28e138c6SAndroid Build Coastguard Worker } else {
514*28e138c6SAndroid Build Coastguard Worker kf_shuffle( fout, fin, 1,in_stride, st->factors,st);
515*28e138c6SAndroid Build Coastguard Worker kf_work( fout, fin, 1,in_stride, st->factors,st, 1, in_stride, 1);
516*28e138c6SAndroid Build Coastguard Worker }
517*28e138c6SAndroid Build Coastguard Worker }
518*28e138c6SAndroid Build Coastguard Worker
kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx * fin,kiss_fft_cpx * fout)519*28e138c6SAndroid Build Coastguard Worker void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
520*28e138c6SAndroid Build Coastguard Worker {
521*28e138c6SAndroid Build Coastguard Worker kiss_fft_stride(cfg,fin,fout,1);
522*28e138c6SAndroid Build Coastguard Worker }
523*28e138c6SAndroid Build Coastguard Worker
524