xref: /aosp_15_r20/external/speex/libspeexdsp/kiss_fft.c (revision 28e138c64d234588b5cd2a8a403b584bd3036e4e)
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