xref: /aosp_15_r20/external/speex/libspeexdsp/kiss_fftr.c (revision 28e138c64d234588b5cd2a8a403b584bd3036e4e)
1*28e138c6SAndroid Build Coastguard Worker /*
2*28e138c6SAndroid Build Coastguard Worker Copyright (c) 2003-2004, Mark Borgerding
3*28e138c6SAndroid Build Coastguard Worker 
4*28e138c6SAndroid Build Coastguard Worker All rights reserved.
5*28e138c6SAndroid Build Coastguard Worker 
6*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:
7*28e138c6SAndroid Build Coastguard Worker 
8*28e138c6SAndroid Build Coastguard Worker     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9*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.
10*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.
11*28e138c6SAndroid Build Coastguard Worker 
12*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.
13*28e138c6SAndroid Build Coastguard Worker */
14*28e138c6SAndroid Build Coastguard Worker 
15*28e138c6SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
16*28e138c6SAndroid Build Coastguard Worker #include "config.h"
17*28e138c6SAndroid Build Coastguard Worker #endif
18*28e138c6SAndroid Build Coastguard Worker 
19*28e138c6SAndroid Build Coastguard Worker #include "os_support.h"
20*28e138c6SAndroid Build Coastguard Worker #include "kiss_fftr.h"
21*28e138c6SAndroid Build Coastguard Worker #include "_kiss_fft_guts.h"
22*28e138c6SAndroid Build Coastguard Worker 
23*28e138c6SAndroid Build Coastguard Worker struct kiss_fftr_state{
24*28e138c6SAndroid Build Coastguard Worker     kiss_fft_cfg substate;
25*28e138c6SAndroid Build Coastguard Worker     kiss_fft_cpx * tmpbuf;
26*28e138c6SAndroid Build Coastguard Worker     kiss_fft_cpx * super_twiddles;
27*28e138c6SAndroid Build Coastguard Worker #ifdef USE_SIMD
28*28e138c6SAndroid Build Coastguard Worker     long pad;
29*28e138c6SAndroid Build Coastguard Worker #endif
30*28e138c6SAndroid Build Coastguard Worker };
31*28e138c6SAndroid Build Coastguard Worker 
kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)32*28e138c6SAndroid Build Coastguard Worker kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
33*28e138c6SAndroid Build Coastguard Worker {
34*28e138c6SAndroid Build Coastguard Worker     int i;
35*28e138c6SAndroid Build Coastguard Worker     kiss_fftr_cfg st = NULL;
36*28e138c6SAndroid Build Coastguard Worker     size_t subsize, memneeded;
37*28e138c6SAndroid Build Coastguard Worker 
38*28e138c6SAndroid Build Coastguard Worker     if (nfft & 1) {
39*28e138c6SAndroid Build Coastguard Worker         speex_warning("Real FFT optimization must be even.\n");
40*28e138c6SAndroid Build Coastguard Worker         return NULL;
41*28e138c6SAndroid Build Coastguard Worker     }
42*28e138c6SAndroid Build Coastguard Worker     nfft >>= 1;
43*28e138c6SAndroid Build Coastguard Worker 
44*28e138c6SAndroid Build Coastguard Worker     kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
45*28e138c6SAndroid Build Coastguard Worker     memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 2);
46*28e138c6SAndroid Build Coastguard Worker 
47*28e138c6SAndroid Build Coastguard Worker     if (lenmem == NULL) {
48*28e138c6SAndroid Build Coastguard Worker         st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
49*28e138c6SAndroid Build Coastguard Worker     } else {
50*28e138c6SAndroid Build Coastguard Worker         if (*lenmem >= memneeded)
51*28e138c6SAndroid Build Coastguard Worker             st = (kiss_fftr_cfg) mem;
52*28e138c6SAndroid Build Coastguard Worker         *lenmem = memneeded;
53*28e138c6SAndroid Build Coastguard Worker     }
54*28e138c6SAndroid Build Coastguard Worker     if (!st)
55*28e138c6SAndroid Build Coastguard Worker         return NULL;
56*28e138c6SAndroid Build Coastguard Worker 
57*28e138c6SAndroid Build Coastguard Worker     st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
58*28e138c6SAndroid Build Coastguard Worker     st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
59*28e138c6SAndroid Build Coastguard Worker     st->super_twiddles = st->tmpbuf + nfft;
60*28e138c6SAndroid Build Coastguard Worker     kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
61*28e138c6SAndroid Build Coastguard Worker 
62*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
63*28e138c6SAndroid Build Coastguard Worker     for (i=0;i<nfft;++i) {
64*28e138c6SAndroid Build Coastguard Worker        spx_word32_t phase = i+(nfft>>1);
65*28e138c6SAndroid Build Coastguard Worker        if (!inverse_fft)
66*28e138c6SAndroid Build Coastguard Worker           phase = -phase;
67*28e138c6SAndroid Build Coastguard Worker        kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft));
68*28e138c6SAndroid Build Coastguard Worker     }
69*28e138c6SAndroid Build Coastguard Worker #else
70*28e138c6SAndroid Build Coastguard Worker     for (i=0;i<nfft;++i) {
71*28e138c6SAndroid Build Coastguard Worker        const double pi=3.14159265358979323846264338327;
72*28e138c6SAndroid Build Coastguard Worker        double phase = pi*(((double)i) /nfft + .5);
73*28e138c6SAndroid Build Coastguard Worker        if (!inverse_fft)
74*28e138c6SAndroid Build Coastguard Worker           phase = -phase;
75*28e138c6SAndroid Build Coastguard Worker        kf_cexp(st->super_twiddles+i, phase );
76*28e138c6SAndroid Build Coastguard Worker     }
77*28e138c6SAndroid Build Coastguard Worker #endif
78*28e138c6SAndroid Build Coastguard Worker     return st;
79*28e138c6SAndroid Build Coastguard Worker }
80*28e138c6SAndroid Build Coastguard Worker 
kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar * timedata,kiss_fft_cpx * freqdata)81*28e138c6SAndroid Build Coastguard Worker void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
82*28e138c6SAndroid Build Coastguard Worker {
83*28e138c6SAndroid Build Coastguard Worker     /* input buffer timedata is stored row-wise */
84*28e138c6SAndroid Build Coastguard Worker     int k,ncfft;
85*28e138c6SAndroid Build Coastguard Worker     kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
86*28e138c6SAndroid Build Coastguard Worker 
87*28e138c6SAndroid Build Coastguard Worker     if ( st->substate->inverse) {
88*28e138c6SAndroid Build Coastguard Worker         speex_fatal("kiss fft usage error: improper alloc\n");
89*28e138c6SAndroid Build Coastguard Worker     }
90*28e138c6SAndroid Build Coastguard Worker 
91*28e138c6SAndroid Build Coastguard Worker     ncfft = st->substate->nfft;
92*28e138c6SAndroid Build Coastguard Worker 
93*28e138c6SAndroid Build Coastguard Worker     /*perform the parallel fft of two real signals packed in real,imag*/
94*28e138c6SAndroid Build Coastguard Worker     kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
95*28e138c6SAndroid Build Coastguard Worker     /* The real part of the DC element of the frequency spectrum in st->tmpbuf
96*28e138c6SAndroid Build Coastguard Worker      * contains the sum of the even-numbered elements of the input time sequence
97*28e138c6SAndroid Build Coastguard Worker      * The imag part is the sum of the odd-numbered elements
98*28e138c6SAndroid Build Coastguard Worker      *
99*28e138c6SAndroid Build Coastguard Worker      * The sum of tdc.r and tdc.i is the sum of the input time sequence.
100*28e138c6SAndroid Build Coastguard Worker      *      yielding DC of input time sequence
101*28e138c6SAndroid Build Coastguard Worker      * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
102*28e138c6SAndroid Build Coastguard Worker      *      yielding Nyquist bin of input time sequence
103*28e138c6SAndroid Build Coastguard Worker      */
104*28e138c6SAndroid Build Coastguard Worker 
105*28e138c6SAndroid Build Coastguard Worker     tdc.r = st->tmpbuf[0].r;
106*28e138c6SAndroid Build Coastguard Worker     tdc.i = st->tmpbuf[0].i;
107*28e138c6SAndroid Build Coastguard Worker     C_FIXDIV(tdc,2);
108*28e138c6SAndroid Build Coastguard Worker     CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
109*28e138c6SAndroid Build Coastguard Worker     CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
110*28e138c6SAndroid Build Coastguard Worker     freqdata[0].r = tdc.r + tdc.i;
111*28e138c6SAndroid Build Coastguard Worker     freqdata[ncfft].r = tdc.r - tdc.i;
112*28e138c6SAndroid Build Coastguard Worker #ifdef USE_SIMD
113*28e138c6SAndroid Build Coastguard Worker     freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
114*28e138c6SAndroid Build Coastguard Worker #else
115*28e138c6SAndroid Build Coastguard Worker     freqdata[ncfft].i = freqdata[0].i = 0;
116*28e138c6SAndroid Build Coastguard Worker #endif
117*28e138c6SAndroid Build Coastguard Worker 
118*28e138c6SAndroid Build Coastguard Worker     for ( k=1;k <= ncfft/2 ; ++k ) {
119*28e138c6SAndroid Build Coastguard Worker         fpk    = st->tmpbuf[k];
120*28e138c6SAndroid Build Coastguard Worker         fpnk.r =   st->tmpbuf[ncfft-k].r;
121*28e138c6SAndroid Build Coastguard Worker         fpnk.i = - st->tmpbuf[ncfft-k].i;
122*28e138c6SAndroid Build Coastguard Worker         C_FIXDIV(fpk,2);
123*28e138c6SAndroid Build Coastguard Worker         C_FIXDIV(fpnk,2);
124*28e138c6SAndroid Build Coastguard Worker 
125*28e138c6SAndroid Build Coastguard Worker         C_ADD( f1k, fpk , fpnk );
126*28e138c6SAndroid Build Coastguard Worker         C_SUB( f2k, fpk , fpnk );
127*28e138c6SAndroid Build Coastguard Worker         C_MUL( tw , f2k , st->super_twiddles[k]);
128*28e138c6SAndroid Build Coastguard Worker 
129*28e138c6SAndroid Build Coastguard Worker         freqdata[k].r = HALF_OF(f1k.r + tw.r);
130*28e138c6SAndroid Build Coastguard Worker         freqdata[k].i = HALF_OF(f1k.i + tw.i);
131*28e138c6SAndroid Build Coastguard Worker         freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
132*28e138c6SAndroid Build Coastguard Worker         freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
133*28e138c6SAndroid Build Coastguard Worker     }
134*28e138c6SAndroid Build Coastguard Worker }
135*28e138c6SAndroid Build Coastguard Worker 
kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx * freqdata,kiss_fft_scalar * timedata)136*28e138c6SAndroid Build Coastguard Worker void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata)
137*28e138c6SAndroid Build Coastguard Worker {
138*28e138c6SAndroid Build Coastguard Worker     /* input buffer timedata is stored row-wise */
139*28e138c6SAndroid Build Coastguard Worker     int k, ncfft;
140*28e138c6SAndroid Build Coastguard Worker 
141*28e138c6SAndroid Build Coastguard Worker     if (st->substate->inverse == 0) {
142*28e138c6SAndroid Build Coastguard Worker         speex_fatal("kiss fft usage error: improper alloc\n");
143*28e138c6SAndroid Build Coastguard Worker     }
144*28e138c6SAndroid Build Coastguard Worker 
145*28e138c6SAndroid Build Coastguard Worker     ncfft = st->substate->nfft;
146*28e138c6SAndroid Build Coastguard Worker 
147*28e138c6SAndroid Build Coastguard Worker     st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
148*28e138c6SAndroid Build Coastguard Worker     st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
149*28e138c6SAndroid Build Coastguard Worker     /*C_FIXDIV(st->tmpbuf[0],2);*/
150*28e138c6SAndroid Build Coastguard Worker 
151*28e138c6SAndroid Build Coastguard Worker     for (k = 1; k <= ncfft / 2; ++k) {
152*28e138c6SAndroid Build Coastguard Worker         kiss_fft_cpx fk, fnkc, fek, fok, tmp;
153*28e138c6SAndroid Build Coastguard Worker         fk = freqdata[k];
154*28e138c6SAndroid Build Coastguard Worker         fnkc.r = freqdata[ncfft - k].r;
155*28e138c6SAndroid Build Coastguard Worker         fnkc.i = -freqdata[ncfft - k].i;
156*28e138c6SAndroid Build Coastguard Worker         /*C_FIXDIV( fk , 2 );
157*28e138c6SAndroid Build Coastguard Worker         C_FIXDIV( fnkc , 2 );*/
158*28e138c6SAndroid Build Coastguard Worker 
159*28e138c6SAndroid Build Coastguard Worker         C_ADD (fek, fk, fnkc);
160*28e138c6SAndroid Build Coastguard Worker         C_SUB (tmp, fk, fnkc);
161*28e138c6SAndroid Build Coastguard Worker         C_MUL (fok, tmp, st->super_twiddles[k]);
162*28e138c6SAndroid Build Coastguard Worker         C_ADD (st->tmpbuf[k],     fek, fok);
163*28e138c6SAndroid Build Coastguard Worker         C_SUB (st->tmpbuf[ncfft - k], fek, fok);
164*28e138c6SAndroid Build Coastguard Worker #ifdef USE_SIMD
165*28e138c6SAndroid Build Coastguard Worker         st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
166*28e138c6SAndroid Build Coastguard Worker #else
167*28e138c6SAndroid Build Coastguard Worker         st->tmpbuf[ncfft - k].i *= -1;
168*28e138c6SAndroid Build Coastguard Worker #endif
169*28e138c6SAndroid Build Coastguard Worker     }
170*28e138c6SAndroid Build Coastguard Worker     kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
171*28e138c6SAndroid Build Coastguard Worker }
172*28e138c6SAndroid Build Coastguard Worker 
kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar * timedata,kiss_fft_scalar * freqdata)173*28e138c6SAndroid Build Coastguard Worker void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata)
174*28e138c6SAndroid Build Coastguard Worker {
175*28e138c6SAndroid Build Coastguard Worker    /* input buffer timedata is stored row-wise */
176*28e138c6SAndroid Build Coastguard Worker    int k,ncfft;
177*28e138c6SAndroid Build Coastguard Worker    kiss_fft_cpx f2k,tdc;
178*28e138c6SAndroid Build Coastguard Worker    spx_word32_t f1kr, f1ki, twr, twi;
179*28e138c6SAndroid Build Coastguard Worker 
180*28e138c6SAndroid Build Coastguard Worker    if ( st->substate->inverse) {
181*28e138c6SAndroid Build Coastguard Worker       speex_fatal("kiss fft usage error: improper alloc\n");
182*28e138c6SAndroid Build Coastguard Worker    }
183*28e138c6SAndroid Build Coastguard Worker 
184*28e138c6SAndroid Build Coastguard Worker    ncfft = st->substate->nfft;
185*28e138c6SAndroid Build Coastguard Worker 
186*28e138c6SAndroid Build Coastguard Worker    /*perform the parallel fft of two real signals packed in real,imag*/
187*28e138c6SAndroid Build Coastguard Worker    kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
188*28e138c6SAndroid Build Coastguard Worker     /* The real part of the DC element of the frequency spectrum in st->tmpbuf
189*28e138c6SAndroid Build Coastguard Worker    * contains the sum of the even-numbered elements of the input time sequence
190*28e138c6SAndroid Build Coastguard Worker    * The imag part is the sum of the odd-numbered elements
191*28e138c6SAndroid Build Coastguard Worker    *
192*28e138c6SAndroid Build Coastguard Worker    * The sum of tdc.r and tdc.i is the sum of the input time sequence.
193*28e138c6SAndroid Build Coastguard Worker    *      yielding DC of input time sequence
194*28e138c6SAndroid Build Coastguard Worker    * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
195*28e138c6SAndroid Build Coastguard Worker    *      yielding Nyquist bin of input time sequence
196*28e138c6SAndroid Build Coastguard Worker     */
197*28e138c6SAndroid Build Coastguard Worker 
198*28e138c6SAndroid Build Coastguard Worker    tdc.r = st->tmpbuf[0].r;
199*28e138c6SAndroid Build Coastguard Worker    tdc.i = st->tmpbuf[0].i;
200*28e138c6SAndroid Build Coastguard Worker    C_FIXDIV(tdc,2);
201*28e138c6SAndroid Build Coastguard Worker    CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
202*28e138c6SAndroid Build Coastguard Worker    CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
203*28e138c6SAndroid Build Coastguard Worker    freqdata[0] = tdc.r + tdc.i;
204*28e138c6SAndroid Build Coastguard Worker    freqdata[2*ncfft-1] = tdc.r - tdc.i;
205*28e138c6SAndroid Build Coastguard Worker 
206*28e138c6SAndroid Build Coastguard Worker    for ( k=1;k <= ncfft/2 ; ++k )
207*28e138c6SAndroid Build Coastguard Worker    {
208*28e138c6SAndroid Build Coastguard Worker       /*fpk    = st->tmpbuf[k];
209*28e138c6SAndroid Build Coastguard Worker       fpnk.r =   st->tmpbuf[ncfft-k].r;
210*28e138c6SAndroid Build Coastguard Worker       fpnk.i = - st->tmpbuf[ncfft-k].i;
211*28e138c6SAndroid Build Coastguard Worker       C_FIXDIV(fpk,2);
212*28e138c6SAndroid Build Coastguard Worker       C_FIXDIV(fpnk,2);
213*28e138c6SAndroid Build Coastguard Worker 
214*28e138c6SAndroid Build Coastguard Worker       C_ADD( f1k, fpk , fpnk );
215*28e138c6SAndroid Build Coastguard Worker       C_SUB( f2k, fpk , fpnk );
216*28e138c6SAndroid Build Coastguard Worker 
217*28e138c6SAndroid Build Coastguard Worker       C_MUL( tw , f2k , st->super_twiddles[k]);
218*28e138c6SAndroid Build Coastguard Worker 
219*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k-1] = HALF_OF(f1k.r + tw.r);
220*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k] = HALF_OF(f1k.i + tw.i);
221*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r);
222*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i);
223*28e138c6SAndroid Build Coastguard Worker       */
224*28e138c6SAndroid Build Coastguard Worker 
225*28e138c6SAndroid Build Coastguard Worker       /*f1k.r = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
226*28e138c6SAndroid Build Coastguard Worker       f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
227*28e138c6SAndroid Build Coastguard Worker       f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
228*28e138c6SAndroid Build Coastguard Worker       f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
229*28e138c6SAndroid Build Coastguard Worker 
230*28e138c6SAndroid Build Coastguard Worker       C_MUL( tw , f2k , st->super_twiddles[k]);
231*28e138c6SAndroid Build Coastguard Worker 
232*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k-1] = HALF_OF(f1k.r + tw.r);
233*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k] = HALF_OF(f1k.i + tw.i);
234*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r);
235*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i);
236*28e138c6SAndroid Build Coastguard Worker    */
237*28e138c6SAndroid Build Coastguard Worker       f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
238*28e138c6SAndroid Build Coastguard Worker       f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
239*28e138c6SAndroid Build Coastguard Worker 
240*28e138c6SAndroid Build Coastguard Worker       f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13);
241*28e138c6SAndroid Build Coastguard Worker       f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13);
242*28e138c6SAndroid Build Coastguard Worker 
243*28e138c6SAndroid Build Coastguard Worker       twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1);
244*28e138c6SAndroid Build Coastguard Worker       twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1);
245*28e138c6SAndroid Build Coastguard Worker 
246*28e138c6SAndroid Build Coastguard Worker #ifdef FIXED_POINT
247*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k-1] = PSHR32(f1kr + twr, 15);
248*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k] = PSHR32(f1ki + twi, 15);
249*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)-1] = PSHR32(f1kr - twr, 15);
250*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)] = PSHR32(twi - f1ki, 15);
251*28e138c6SAndroid Build Coastguard Worker #else
252*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k-1] = .5f*(f1kr + twr);
253*28e138c6SAndroid Build Coastguard Worker       freqdata[2*k] = .5f*(f1ki + twi);
254*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr);
255*28e138c6SAndroid Build Coastguard Worker       freqdata[2*(ncfft-k)] = .5f*(twi - f1ki);
256*28e138c6SAndroid Build Coastguard Worker 
257*28e138c6SAndroid Build Coastguard Worker #endif
258*28e138c6SAndroid Build Coastguard Worker    }
259*28e138c6SAndroid Build Coastguard Worker }
260*28e138c6SAndroid Build Coastguard Worker 
kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar * freqdata,kiss_fft_scalar * timedata)261*28e138c6SAndroid Build Coastguard Worker void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata)
262*28e138c6SAndroid Build Coastguard Worker {
263*28e138c6SAndroid Build Coastguard Worker    /* input buffer timedata is stored row-wise */
264*28e138c6SAndroid Build Coastguard Worker    int k, ncfft;
265*28e138c6SAndroid Build Coastguard Worker 
266*28e138c6SAndroid Build Coastguard Worker    if (st->substate->inverse == 0) {
267*28e138c6SAndroid Build Coastguard Worker       speex_fatal ("kiss fft usage error: improper alloc\n");
268*28e138c6SAndroid Build Coastguard Worker    }
269*28e138c6SAndroid Build Coastguard Worker 
270*28e138c6SAndroid Build Coastguard Worker    ncfft = st->substate->nfft;
271*28e138c6SAndroid Build Coastguard Worker 
272*28e138c6SAndroid Build Coastguard Worker    st->tmpbuf[0].r = freqdata[0] + freqdata[2*ncfft-1];
273*28e138c6SAndroid Build Coastguard Worker    st->tmpbuf[0].i = freqdata[0] - freqdata[2*ncfft-1];
274*28e138c6SAndroid Build Coastguard Worker    /*C_FIXDIV(st->tmpbuf[0],2);*/
275*28e138c6SAndroid Build Coastguard Worker 
276*28e138c6SAndroid Build Coastguard Worker    for (k = 1; k <= ncfft / 2; ++k) {
277*28e138c6SAndroid Build Coastguard Worker       kiss_fft_cpx fk, fnkc, fek, fok, tmp;
278*28e138c6SAndroid Build Coastguard Worker       fk.r = freqdata[2*k-1];
279*28e138c6SAndroid Build Coastguard Worker       fk.i = freqdata[2*k];
280*28e138c6SAndroid Build Coastguard Worker       fnkc.r = freqdata[2*(ncfft - k)-1];
281*28e138c6SAndroid Build Coastguard Worker       fnkc.i = -freqdata[2*(ncfft - k)];
282*28e138c6SAndroid Build Coastguard Worker         /*C_FIXDIV( fk , 2 );
283*28e138c6SAndroid Build Coastguard Worker       C_FIXDIV( fnkc , 2 );*/
284*28e138c6SAndroid Build Coastguard Worker 
285*28e138c6SAndroid Build Coastguard Worker       C_ADD (fek, fk, fnkc);
286*28e138c6SAndroid Build Coastguard Worker       C_SUB (tmp, fk, fnkc);
287*28e138c6SAndroid Build Coastguard Worker       C_MUL (fok, tmp, st->super_twiddles[k]);
288*28e138c6SAndroid Build Coastguard Worker       C_ADD (st->tmpbuf[k],     fek, fok);
289*28e138c6SAndroid Build Coastguard Worker       C_SUB (st->tmpbuf[ncfft - k], fek, fok);
290*28e138c6SAndroid Build Coastguard Worker #ifdef USE_SIMD
291*28e138c6SAndroid Build Coastguard Worker       st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
292*28e138c6SAndroid Build Coastguard Worker #else
293*28e138c6SAndroid Build Coastguard Worker       st->tmpbuf[ncfft - k].i *= -1;
294*28e138c6SAndroid Build Coastguard Worker #endif
295*28e138c6SAndroid Build Coastguard Worker    }
296*28e138c6SAndroid Build Coastguard Worker    kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
297*28e138c6SAndroid Build Coastguard Worker }
298