xref: /aosp_15_r20/external/pffft/pffastconv.c (revision 3f1979aa0d7ad34fcf3763de7b7b8f8cd67e5bdd)
1*3f1979aaSAndroid Build Coastguard Worker /*
2*3f1979aaSAndroid Build Coastguard Worker   Copyright (c) 2019  Hayati Ayguen ( [email protected] )
3*3f1979aaSAndroid Build Coastguard Worker  */
4*3f1979aaSAndroid Build Coastguard Worker 
5*3f1979aaSAndroid Build Coastguard Worker #include "pffastconv.h"
6*3f1979aaSAndroid Build Coastguard Worker #include "pffft.h"
7*3f1979aaSAndroid Build Coastguard Worker 
8*3f1979aaSAndroid Build Coastguard Worker #include <stdlib.h>
9*3f1979aaSAndroid Build Coastguard Worker #include <stdint.h>
10*3f1979aaSAndroid Build Coastguard Worker #include <stdio.h>
11*3f1979aaSAndroid Build Coastguard Worker #include <math.h>
12*3f1979aaSAndroid Build Coastguard Worker #include <assert.h>
13*3f1979aaSAndroid Build Coastguard Worker #include <string.h>
14*3f1979aaSAndroid Build Coastguard Worker 
15*3f1979aaSAndroid Build Coastguard Worker #define FASTCONV_DBG_OUT  0
16*3f1979aaSAndroid Build Coastguard Worker 
17*3f1979aaSAndroid Build Coastguard Worker 
18*3f1979aaSAndroid Build Coastguard Worker /* detect compiler flavour */
19*3f1979aaSAndroid Build Coastguard Worker #if defined(_MSC_VER)
20*3f1979aaSAndroid Build Coastguard Worker #  define RESTRICT __restrict
21*3f1979aaSAndroid Build Coastguard Worker #pragma warning( disable : 4244 4305 4204 4456 )
22*3f1979aaSAndroid Build Coastguard Worker #elif defined(__GNUC__)
23*3f1979aaSAndroid Build Coastguard Worker #  define RESTRICT __restrict
24*3f1979aaSAndroid Build Coastguard Worker #endif
25*3f1979aaSAndroid Build Coastguard Worker 
26*3f1979aaSAndroid Build Coastguard Worker 
pffastconv_malloc(size_t nb_bytes)27*3f1979aaSAndroid Build Coastguard Worker void *pffastconv_malloc(size_t nb_bytes)
28*3f1979aaSAndroid Build Coastguard Worker {
29*3f1979aaSAndroid Build Coastguard Worker   return pffft_aligned_malloc(nb_bytes);
30*3f1979aaSAndroid Build Coastguard Worker }
31*3f1979aaSAndroid Build Coastguard Worker 
pffastconv_free(void * p)32*3f1979aaSAndroid Build Coastguard Worker void pffastconv_free(void *p)
33*3f1979aaSAndroid Build Coastguard Worker {
34*3f1979aaSAndroid Build Coastguard Worker   pffft_aligned_free(p);
35*3f1979aaSAndroid Build Coastguard Worker }
36*3f1979aaSAndroid Build Coastguard Worker 
pffastconv_simd_size()37*3f1979aaSAndroid Build Coastguard Worker int pffastconv_simd_size()
38*3f1979aaSAndroid Build Coastguard Worker {
39*3f1979aaSAndroid Build Coastguard Worker   return pffft_simd_size();
40*3f1979aaSAndroid Build Coastguard Worker }
41*3f1979aaSAndroid Build Coastguard Worker 
42*3f1979aaSAndroid Build Coastguard Worker 
43*3f1979aaSAndroid Build Coastguard Worker 
44*3f1979aaSAndroid Build Coastguard Worker struct PFFASTCONV_Setup
45*3f1979aaSAndroid Build Coastguard Worker {
46*3f1979aaSAndroid Build Coastguard Worker   float * Xt;      /* input == x in time domain - copy for alignment */
47*3f1979aaSAndroid Build Coastguard Worker   float * Xf;      /* input == X in freq domain */
48*3f1979aaSAndroid Build Coastguard Worker   float * Hf;      /* filterCoeffs == H in freq domain */
49*3f1979aaSAndroid Build Coastguard Worker   float * Mf;      /* input * filterCoeffs in freq domain */
50*3f1979aaSAndroid Build Coastguard Worker   PFFFT_Setup *st;
51*3f1979aaSAndroid Build Coastguard Worker   int filterLen;   /* convolution length */
52*3f1979aaSAndroid Build Coastguard Worker   int Nfft;        /* FFT/block length */
53*3f1979aaSAndroid Build Coastguard Worker   int flags;
54*3f1979aaSAndroid Build Coastguard Worker   float scale;
55*3f1979aaSAndroid Build Coastguard Worker };
56*3f1979aaSAndroid Build Coastguard Worker 
57*3f1979aaSAndroid Build Coastguard Worker 
pffastconv_new_setup(const float * filterCoeffs,int filterLen,int * blockLen,int flags)58*3f1979aaSAndroid Build Coastguard Worker PFFASTCONV_Setup * pffastconv_new_setup( const float * filterCoeffs, int filterLen, int * blockLen, int flags )
59*3f1979aaSAndroid Build Coastguard Worker {
60*3f1979aaSAndroid Build Coastguard Worker   PFFASTCONV_Setup * s = NULL;
61*3f1979aaSAndroid Build Coastguard Worker   const int cplxFactor = ( (flags & PFFASTCONV_CPLX_INP_OUT) && (flags & PFFASTCONV_CPLX_SINGLE_FFT) ) ? 2 : 1;
62*3f1979aaSAndroid Build Coastguard Worker   const int minFftLen = 2*pffft_simd_size()*pffft_simd_size();
63*3f1979aaSAndroid Build Coastguard Worker   int i, Nfft = 2 * pffft_next_power_of_two(filterLen -1);
64*3f1979aaSAndroid Build Coastguard Worker #if FASTCONV_DBG_OUT
65*3f1979aaSAndroid Build Coastguard Worker   const int iOldBlkLen = *blockLen;
66*3f1979aaSAndroid Build Coastguard Worker #endif
67*3f1979aaSAndroid Build Coastguard Worker 
68*3f1979aaSAndroid Build Coastguard Worker   if ( Nfft < minFftLen )
69*3f1979aaSAndroid Build Coastguard Worker     Nfft = minFftLen;
70*3f1979aaSAndroid Build Coastguard Worker 
71*3f1979aaSAndroid Build Coastguard Worker   if ( flags & PFFASTCONV_CPLX_FILTER )
72*3f1979aaSAndroid Build Coastguard Worker     return NULL;
73*3f1979aaSAndroid Build Coastguard Worker 
74*3f1979aaSAndroid Build Coastguard Worker   s = pffastconv_malloc( sizeof(struct PFFASTCONV_Setup) );
75*3f1979aaSAndroid Build Coastguard Worker 
76*3f1979aaSAndroid Build Coastguard Worker   if ( *blockLen > Nfft ) {
77*3f1979aaSAndroid Build Coastguard Worker     Nfft = *blockLen;
78*3f1979aaSAndroid Build Coastguard Worker     Nfft = pffft_next_power_of_two(Nfft);
79*3f1979aaSAndroid Build Coastguard Worker   }
80*3f1979aaSAndroid Build Coastguard Worker   *blockLen = Nfft;  /* this is in (complex) samples */
81*3f1979aaSAndroid Build Coastguard Worker 
82*3f1979aaSAndroid Build Coastguard Worker   Nfft *= cplxFactor;
83*3f1979aaSAndroid Build Coastguard Worker 
84*3f1979aaSAndroid Build Coastguard Worker   if ( (flags & PFFASTCONV_DIRECT_INP) && !(flags & PFFASTCONV_CPLX_INP_OUT) )
85*3f1979aaSAndroid Build Coastguard Worker     s->Xt = NULL;
86*3f1979aaSAndroid Build Coastguard Worker   else
87*3f1979aaSAndroid Build Coastguard Worker     s->Xt = pffastconv_malloc((unsigned)Nfft * sizeof(float));
88*3f1979aaSAndroid Build Coastguard Worker   s->Xf = pffastconv_malloc((unsigned)Nfft * sizeof(float));
89*3f1979aaSAndroid Build Coastguard Worker   s->Hf = pffastconv_malloc((unsigned)Nfft * sizeof(float));
90*3f1979aaSAndroid Build Coastguard Worker   s->Mf = pffastconv_malloc((unsigned)Nfft * sizeof(float));
91*3f1979aaSAndroid Build Coastguard Worker   s->st = pffft_new_setup(Nfft, PFFFT_REAL);  /* with complex: we do 2 x fft() */
92*3f1979aaSAndroid Build Coastguard Worker   s->filterLen = filterLen;        /* filterLen == convolution length == length of impulse response */
93*3f1979aaSAndroid Build Coastguard Worker   if ( cplxFactor == 2 )
94*3f1979aaSAndroid Build Coastguard Worker     s->filterLen = 2 * filterLen - 1;
95*3f1979aaSAndroid Build Coastguard Worker   s->Nfft = Nfft;  /* FFT/block length */
96*3f1979aaSAndroid Build Coastguard Worker   s->flags = flags;
97*3f1979aaSAndroid Build Coastguard Worker   s->scale = (float)( 1.0 / Nfft );
98*3f1979aaSAndroid Build Coastguard Worker 
99*3f1979aaSAndroid Build Coastguard Worker   memset( s->Xt, 0, (unsigned)Nfft * sizeof(float) );
100*3f1979aaSAndroid Build Coastguard Worker   if ( flags & PFFASTCONV_CORRELATION ) {
101*3f1979aaSAndroid Build Coastguard Worker     for ( i = 0; i < filterLen; ++i )
102*3f1979aaSAndroid Build Coastguard Worker       s->Xt[ ( Nfft - cplxFactor * i ) & (Nfft -1) ] = filterCoeffs[ i ];
103*3f1979aaSAndroid Build Coastguard Worker   } else {
104*3f1979aaSAndroid Build Coastguard Worker     for ( i = 0; i < filterLen; ++i )
105*3f1979aaSAndroid Build Coastguard Worker       s->Xt[ ( Nfft - cplxFactor * i ) & (Nfft -1) ] = filterCoeffs[ filterLen - 1 - i ];
106*3f1979aaSAndroid Build Coastguard Worker   }
107*3f1979aaSAndroid Build Coastguard Worker 
108*3f1979aaSAndroid Build Coastguard Worker   pffft_transform(s->st, s->Xt, s->Hf, /* tmp = */ s->Mf, PFFFT_FORWARD);
109*3f1979aaSAndroid Build Coastguard Worker 
110*3f1979aaSAndroid Build Coastguard Worker #if FASTCONV_DBG_OUT
111*3f1979aaSAndroid Build Coastguard Worker   printf("\n  fastConvSetup(filterLen = %d, blockLen %d) --> blockLen %d, OutLen = %d\n"
112*3f1979aaSAndroid Build Coastguard Worker     , filterLen, iOldBlkLen, *blockLen, Nfft - filterLen +1 );
113*3f1979aaSAndroid Build Coastguard Worker #endif
114*3f1979aaSAndroid Build Coastguard Worker 
115*3f1979aaSAndroid Build Coastguard Worker   return s;
116*3f1979aaSAndroid Build Coastguard Worker }
117*3f1979aaSAndroid Build Coastguard Worker 
118*3f1979aaSAndroid Build Coastguard Worker 
pffastconv_destroy_setup(PFFASTCONV_Setup * s)119*3f1979aaSAndroid Build Coastguard Worker void pffastconv_destroy_setup( PFFASTCONV_Setup * s )
120*3f1979aaSAndroid Build Coastguard Worker {
121*3f1979aaSAndroid Build Coastguard Worker   if (!s)
122*3f1979aaSAndroid Build Coastguard Worker     return;
123*3f1979aaSAndroid Build Coastguard Worker   pffft_destroy_setup(s->st);
124*3f1979aaSAndroid Build Coastguard Worker   pffastconv_free(s->Mf);
125*3f1979aaSAndroid Build Coastguard Worker   pffastconv_free(s->Hf);
126*3f1979aaSAndroid Build Coastguard Worker   pffastconv_free(s->Xf);
127*3f1979aaSAndroid Build Coastguard Worker   if ( s->Xt )
128*3f1979aaSAndroid Build Coastguard Worker     pffastconv_free(s->Xt);
129*3f1979aaSAndroid Build Coastguard Worker   pffastconv_free(s);
130*3f1979aaSAndroid Build Coastguard Worker }
131*3f1979aaSAndroid Build Coastguard Worker 
132*3f1979aaSAndroid Build Coastguard Worker 
pffastconv_apply(PFFASTCONV_Setup * s,const float * input_,int cplxInputLen,float * output_,int applyFlush)133*3f1979aaSAndroid Build Coastguard Worker int pffastconv_apply(PFFASTCONV_Setup * s, const float *input_, int cplxInputLen, float *output_, int applyFlush)
134*3f1979aaSAndroid Build Coastguard Worker {
135*3f1979aaSAndroid Build Coastguard Worker   const float * RESTRICT X = input_;
136*3f1979aaSAndroid Build Coastguard Worker   float * RESTRICT Y = output_;
137*3f1979aaSAndroid Build Coastguard Worker   const int Nfft = s->Nfft;
138*3f1979aaSAndroid Build Coastguard Worker   const int filterLen = s->filterLen;
139*3f1979aaSAndroid Build Coastguard Worker   const int flags = s->flags;
140*3f1979aaSAndroid Build Coastguard Worker   const int cplxFactor = ( (flags & PFFASTCONV_CPLX_INP_OUT) && (flags & PFFASTCONV_CPLX_SINGLE_FFT) ) ? 2 : 1;
141*3f1979aaSAndroid Build Coastguard Worker   const int inputLen = cplxFactor * cplxInputLen;
142*3f1979aaSAndroid Build Coastguard Worker   int inpOff, procLen, numOut = 0, j, part, cplxOff;
143*3f1979aaSAndroid Build Coastguard Worker 
144*3f1979aaSAndroid Build Coastguard Worker   /* applyFlush != 0:
145*3f1979aaSAndroid Build Coastguard Worker    *     inputLen - inpOff -filterLen + 1 > 0
146*3f1979aaSAndroid Build Coastguard Worker    * <=> inputLen -filterLen + 1 > inpOff
147*3f1979aaSAndroid Build Coastguard Worker    * <=> inpOff < inputLen -filterLen + 1
148*3f1979aaSAndroid Build Coastguard Worker    *
149*3f1979aaSAndroid Build Coastguard Worker    * applyFlush == 0:
150*3f1979aaSAndroid Build Coastguard Worker    *     inputLen - inpOff >= Nfft
151*3f1979aaSAndroid Build Coastguard Worker    * <=> inputLen - Nfft >= inpOff
152*3f1979aaSAndroid Build Coastguard Worker    * <=> inpOff <= inputLen - Nfft
153*3f1979aaSAndroid Build Coastguard Worker    * <=> inpOff < inputLen - Nfft + 1
154*3f1979aaSAndroid Build Coastguard Worker    */
155*3f1979aaSAndroid Build Coastguard Worker 
156*3f1979aaSAndroid Build Coastguard Worker   if ( cplxFactor == 2 )
157*3f1979aaSAndroid Build Coastguard Worker   {
158*3f1979aaSAndroid Build Coastguard Worker     const int maxOff = applyFlush ? (inputLen -filterLen + 1) : (inputLen - Nfft + 1);
159*3f1979aaSAndroid Build Coastguard Worker #if 0
160*3f1979aaSAndroid Build Coastguard Worker     printf( "*** inputLen %d, filterLen %d, Nfft %d => maxOff %d\n", inputLen, filterLen, Nfft, maxOff);
161*3f1979aaSAndroid Build Coastguard Worker #endif
162*3f1979aaSAndroid Build Coastguard Worker     for ( inpOff = 0; inpOff < maxOff; inpOff += numOut )
163*3f1979aaSAndroid Build Coastguard Worker     {
164*3f1979aaSAndroid Build Coastguard Worker       procLen = ( (inputLen - inpOff) >= Nfft ) ? Nfft : (inputLen - inpOff);
165*3f1979aaSAndroid Build Coastguard Worker       numOut = ( procLen - filterLen + 1 ) & ( ~1 );
166*3f1979aaSAndroid Build Coastguard Worker       if (!numOut)
167*3f1979aaSAndroid Build Coastguard Worker         break;
168*3f1979aaSAndroid Build Coastguard Worker #if 0
169*3f1979aaSAndroid Build Coastguard Worker       if (!inpOff)
170*3f1979aaSAndroid Build Coastguard Worker         printf("*** inpOff = %d, numOut = %d\n", inpOff, numOut);
171*3f1979aaSAndroid Build Coastguard Worker       if (inpOff + filterLen + 2 >= maxOff )
172*3f1979aaSAndroid Build Coastguard Worker         printf("*** inpOff = %d, inpOff + numOut = %d\n", inpOff, inpOff + numOut);
173*3f1979aaSAndroid Build Coastguard Worker #endif
174*3f1979aaSAndroid Build Coastguard Worker 
175*3f1979aaSAndroid Build Coastguard Worker       if ( flags & PFFASTCONV_DIRECT_INP )
176*3f1979aaSAndroid Build Coastguard Worker       {
177*3f1979aaSAndroid Build Coastguard Worker         pffft_transform(s->st, X + inpOff, s->Xf, /* tmp = */ s->Mf, PFFFT_FORWARD);
178*3f1979aaSAndroid Build Coastguard Worker       }
179*3f1979aaSAndroid Build Coastguard Worker       else
180*3f1979aaSAndroid Build Coastguard Worker       {
181*3f1979aaSAndroid Build Coastguard Worker         memcpy( s->Xt, X + inpOff, (unsigned)procLen * sizeof(float) );
182*3f1979aaSAndroid Build Coastguard Worker         if ( procLen < Nfft )
183*3f1979aaSAndroid Build Coastguard Worker           memset( s->Xt + procLen, 0, (unsigned)(Nfft - procLen) * sizeof(float) );
184*3f1979aaSAndroid Build Coastguard Worker 
185*3f1979aaSAndroid Build Coastguard Worker         pffft_transform(s->st, s->Xt, s->Xf, /* tmp = */ s->Mf, PFFFT_FORWARD);
186*3f1979aaSAndroid Build Coastguard Worker       }
187*3f1979aaSAndroid Build Coastguard Worker 
188*3f1979aaSAndroid Build Coastguard Worker       pffft_zconvolve_no_accu(s->st, s->Xf, s->Hf, /* tmp = */ s->Mf, s->scale);
189*3f1979aaSAndroid Build Coastguard Worker 
190*3f1979aaSAndroid Build Coastguard Worker       if ( flags & PFFASTCONV_DIRECT_OUT )
191*3f1979aaSAndroid Build Coastguard Worker       {
192*3f1979aaSAndroid Build Coastguard Worker         pffft_transform(s->st, s->Mf, Y + inpOff, s->Xf, PFFFT_BACKWARD);
193*3f1979aaSAndroid Build Coastguard Worker       }
194*3f1979aaSAndroid Build Coastguard Worker       else
195*3f1979aaSAndroid Build Coastguard Worker       {
196*3f1979aaSAndroid Build Coastguard Worker         pffft_transform(s->st, s->Mf, s->Xf, /* tmp = */ s->Xt, PFFFT_BACKWARD);
197*3f1979aaSAndroid Build Coastguard Worker         memcpy( Y + inpOff, s->Xf, (unsigned)numOut * sizeof(float) );
198*3f1979aaSAndroid Build Coastguard Worker       }
199*3f1979aaSAndroid Build Coastguard Worker     }
200*3f1979aaSAndroid Build Coastguard Worker     return inpOff / cplxFactor;
201*3f1979aaSAndroid Build Coastguard Worker   }
202*3f1979aaSAndroid Build Coastguard Worker   else
203*3f1979aaSAndroid Build Coastguard Worker   {
204*3f1979aaSAndroid Build Coastguard Worker     const int maxOff = applyFlush ? (inputLen -filterLen + 1) : (inputLen - Nfft + 1);
205*3f1979aaSAndroid Build Coastguard Worker     const int numParts = (flags & PFFASTCONV_CPLX_INP_OUT) ? 2 : 1;
206*3f1979aaSAndroid Build Coastguard Worker 
207*3f1979aaSAndroid Build Coastguard Worker     for ( inpOff = 0; inpOff < maxOff; inpOff += numOut )
208*3f1979aaSAndroid Build Coastguard Worker     {
209*3f1979aaSAndroid Build Coastguard Worker       procLen = ( (inputLen - inpOff) >= Nfft ) ? Nfft : (inputLen - inpOff);
210*3f1979aaSAndroid Build Coastguard Worker       numOut = procLen - filterLen + 1;
211*3f1979aaSAndroid Build Coastguard Worker 
212*3f1979aaSAndroid Build Coastguard Worker       for ( part = 0; part < numParts; ++part )  /* iterate per real/imag component */
213*3f1979aaSAndroid Build Coastguard Worker       {
214*3f1979aaSAndroid Build Coastguard Worker 
215*3f1979aaSAndroid Build Coastguard Worker         if ( flags & PFFASTCONV_CPLX_INP_OUT )
216*3f1979aaSAndroid Build Coastguard Worker         {
217*3f1979aaSAndroid Build Coastguard Worker           cplxOff = 2 * inpOff + part;
218*3f1979aaSAndroid Build Coastguard Worker           for ( j = 0; j < procLen; ++j )
219*3f1979aaSAndroid Build Coastguard Worker             s->Xt[j] = X[cplxOff + 2 * j];
220*3f1979aaSAndroid Build Coastguard Worker           if ( procLen < Nfft )
221*3f1979aaSAndroid Build Coastguard Worker             memset( s->Xt + procLen, 0, (unsigned)(Nfft - procLen) * sizeof(float) );
222*3f1979aaSAndroid Build Coastguard Worker 
223*3f1979aaSAndroid Build Coastguard Worker           pffft_transform(s->st, s->Xt, s->Xf, /* tmp = */ s->Mf, PFFFT_FORWARD);
224*3f1979aaSAndroid Build Coastguard Worker         }
225*3f1979aaSAndroid Build Coastguard Worker         else if ( flags & PFFASTCONV_DIRECT_INP )
226*3f1979aaSAndroid Build Coastguard Worker         {
227*3f1979aaSAndroid Build Coastguard Worker           pffft_transform(s->st, X + inpOff, s->Xf, /* tmp = */ s->Mf, PFFFT_FORWARD);
228*3f1979aaSAndroid Build Coastguard Worker         }
229*3f1979aaSAndroid Build Coastguard Worker         else
230*3f1979aaSAndroid Build Coastguard Worker         {
231*3f1979aaSAndroid Build Coastguard Worker           memcpy( s->Xt, X + inpOff, (unsigned)procLen * sizeof(float) );
232*3f1979aaSAndroid Build Coastguard Worker           if ( procLen < Nfft )
233*3f1979aaSAndroid Build Coastguard Worker             memset( s->Xt + procLen, 0, (unsigned)(Nfft - procLen) * sizeof(float) );
234*3f1979aaSAndroid Build Coastguard Worker 
235*3f1979aaSAndroid Build Coastguard Worker           pffft_transform(s->st, s->Xt, s->Xf, /* tmp = */ s->Mf, PFFFT_FORWARD);
236*3f1979aaSAndroid Build Coastguard Worker         }
237*3f1979aaSAndroid Build Coastguard Worker 
238*3f1979aaSAndroid Build Coastguard Worker         pffft_zconvolve_no_accu(s->st, s->Xf, s->Hf, /* tmp = */ s->Mf, s->scale);
239*3f1979aaSAndroid Build Coastguard Worker 
240*3f1979aaSAndroid Build Coastguard Worker         if ( flags & PFFASTCONV_CPLX_INP_OUT )
241*3f1979aaSAndroid Build Coastguard Worker         {
242*3f1979aaSAndroid Build Coastguard Worker           pffft_transform(s->st, s->Mf, s->Xf, /* tmp = */ s->Xt, PFFFT_BACKWARD);
243*3f1979aaSAndroid Build Coastguard Worker 
244*3f1979aaSAndroid Build Coastguard Worker           cplxOff = 2 * inpOff + part;
245*3f1979aaSAndroid Build Coastguard Worker           for ( j = 0; j < numOut; ++j )
246*3f1979aaSAndroid Build Coastguard Worker             Y[ cplxOff + 2 * j ] = s->Xf[j];
247*3f1979aaSAndroid Build Coastguard Worker         }
248*3f1979aaSAndroid Build Coastguard Worker         else if ( flags & PFFASTCONV_DIRECT_OUT )
249*3f1979aaSAndroid Build Coastguard Worker         {
250*3f1979aaSAndroid Build Coastguard Worker           pffft_transform(s->st, s->Mf, Y + inpOff, s->Xf, PFFFT_BACKWARD);
251*3f1979aaSAndroid Build Coastguard Worker         }
252*3f1979aaSAndroid Build Coastguard Worker         else
253*3f1979aaSAndroid Build Coastguard Worker         {
254*3f1979aaSAndroid Build Coastguard Worker           pffft_transform(s->st, s->Mf, s->Xf, /* tmp = */ s->Xt, PFFFT_BACKWARD);
255*3f1979aaSAndroid Build Coastguard Worker           memcpy( Y + inpOff, s->Xf, (unsigned)numOut * sizeof(float) );
256*3f1979aaSAndroid Build Coastguard Worker         }
257*3f1979aaSAndroid Build Coastguard Worker 
258*3f1979aaSAndroid Build Coastguard Worker       }
259*3f1979aaSAndroid Build Coastguard Worker     }
260*3f1979aaSAndroid Build Coastguard Worker 
261*3f1979aaSAndroid Build Coastguard Worker     return inpOff;
262*3f1979aaSAndroid Build Coastguard Worker   }
263*3f1979aaSAndroid Build Coastguard Worker }
264*3f1979aaSAndroid Build Coastguard Worker 
265