1 /* Copyright (C) 2005-2006 Jean-Marc Valin
2 File: fftwrap.c
3
4 Wrapper for various FFTs
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 - Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12
13 - Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16
17 - Neither the name of the Xiph.org Foundation nor the names of its
18 contributors may be used to endorse or promote products derived from
19 this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
25 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include "arch.h"
40 #include "os_support.h"
41
42 #define MAX_FFT_SIZE 2048
43
44 #ifdef FIXED_POINT
maximize_range(spx_word16_t * in,spx_word16_t * out,spx_word16_t bound,int len)45 static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t bound, int len)
46 {
47 int i, shift;
48 spx_word16_t max_val = 0;
49 for (i=0;i<len;i++)
50 {
51 if (in[i]>max_val)
52 max_val = in[i];
53 if (-in[i]>max_val)
54 max_val = -in[i];
55 }
56 shift=0;
57 while (max_val <= (bound>>1) && max_val != 0)
58 {
59 max_val <<= 1;
60 shift++;
61 }
62 for (i=0;i<len;i++)
63 {
64 out[i] = SHL16(in[i], shift);
65 }
66 return shift;
67 }
68
renorm_range(spx_word16_t * in,spx_word16_t * out,int shift,int len)69 static void renorm_range(spx_word16_t *in, spx_word16_t *out, int shift, int len)
70 {
71 int i;
72 for (i=0;i<len;i++)
73 {
74 out[i] = PSHR16(in[i], shift);
75 }
76 }
77 #endif
78
79 #ifdef USE_SMALLFT
80
81 #include "smallft.h"
82 #include <math.h>
83
spx_fft_init(int size)84 void *spx_fft_init(int size)
85 {
86 struct drft_lookup *table;
87 table = speex_alloc(sizeof(struct drft_lookup));
88 spx_drft_init((struct drft_lookup *)table, size);
89 return (void*)table;
90 }
91
spx_fft_destroy(void * table)92 void spx_fft_destroy(void *table)
93 {
94 spx_drft_clear(table);
95 speex_free(table);
96 }
97
spx_fft(void * table,float * in,float * out)98 void spx_fft(void *table, float *in, float *out)
99 {
100 if (in==out)
101 {
102 int i;
103 float scale = 1./((struct drft_lookup *)table)->n;
104 speex_warning("FFT should not be done in-place");
105 for (i=0;i<((struct drft_lookup *)table)->n;i++)
106 out[i] = scale*in[i];
107 } else {
108 int i;
109 float scale = 1./((struct drft_lookup *)table)->n;
110 for (i=0;i<((struct drft_lookup *)table)->n;i++)
111 out[i] = scale*in[i];
112 }
113 spx_drft_forward((struct drft_lookup *)table, out);
114 }
115
spx_ifft(void * table,float * in,float * out)116 void spx_ifft(void *table, float *in, float *out)
117 {
118 if (in==out)
119 {
120 speex_warning("FFT should not be done in-place");
121 } else {
122 int i;
123 for (i=0;i<((struct drft_lookup *)table)->n;i++)
124 out[i] = in[i];
125 }
126 spx_drft_backward((struct drft_lookup *)table, out);
127 }
128
129 #elif defined(USE_INTEL_MKL)
130 #include <mkl.h>
131
132 struct mkl_config {
133 DFTI_DESCRIPTOR_HANDLE desc;
134 int N;
135 };
136
spx_fft_init(int size)137 void *spx_fft_init(int size)
138 {
139 struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config));
140 table->N = size;
141 DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size);
142 DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT);
143 DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
144 DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size);
145 DftiCommitDescriptor(table->desc);
146 return table;
147 }
148
spx_fft_destroy(void * table)149 void spx_fft_destroy(void *table)
150 {
151 struct mkl_config *t = (struct mkl_config *) table;
152 DftiFreeDescriptor(t->desc);
153 speex_free(table);
154 }
155
spx_fft(void * table,spx_word16_t * in,spx_word16_t * out)156 void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
157 {
158 struct mkl_config *t = (struct mkl_config *) table;
159 DftiComputeForward(t->desc, in, out);
160 }
161
spx_ifft(void * table,spx_word16_t * in,spx_word16_t * out)162 void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
163 {
164 struct mkl_config *t = (struct mkl_config *) table;
165 DftiComputeBackward(t->desc, in, out);
166 }
167
168 #elif defined(USE_INTEL_IPP)
169
170 #include <ipps.h>
171
172 struct ipp_fft_config
173 {
174 IppsDFTSpec_R_32f *dftSpec;
175 Ipp8u *buffer;
176 };
177
spx_fft_init(int size)178 void *spx_fft_init(int size)
179 {
180 int bufferSize = 0;
181 int hint;
182 struct ipp_fft_config *table;
183
184 table = (struct ipp_fft_config *)speex_alloc(sizeof(struct ipp_fft_config));
185
186 /* there appears to be no performance difference between ippAlgHintFast and
187 ippAlgHintAccurate when using the with the floating point version
188 of the fft. */
189 hint = ippAlgHintAccurate;
190
191 ippsDFTInitAlloc_R_32f(&table->dftSpec, size, IPP_FFT_DIV_FWD_BY_N, hint);
192
193 ippsDFTGetBufSize_R_32f(table->dftSpec, &bufferSize);
194 table->buffer = ippsMalloc_8u(bufferSize);
195
196 return table;
197 }
198
spx_fft_destroy(void * table)199 void spx_fft_destroy(void *table)
200 {
201 struct ipp_fft_config *t = (struct ipp_fft_config *)table;
202 ippsFree(t->buffer);
203 ippsDFTFree_R_32f(t->dftSpec);
204 speex_free(t);
205 }
206
spx_fft(void * table,spx_word16_t * in,spx_word16_t * out)207 void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
208 {
209 struct ipp_fft_config *t = (struct ipp_fft_config *)table;
210 ippsDFTFwd_RToPack_32f(in, out, t->dftSpec, t->buffer);
211 }
212
spx_ifft(void * table,spx_word16_t * in,spx_word16_t * out)213 void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
214 {
215 struct ipp_fft_config *t = (struct ipp_fft_config *)table;
216 ippsDFTInv_PackToR_32f(in, out, t->dftSpec, t->buffer);
217 }
218
219 #elif defined(USE_GPL_FFTW3)
220
221 #include <fftw3.h>
222
223 struct fftw_config {
224 float *in;
225 float *out;
226 fftwf_plan fft;
227 fftwf_plan ifft;
228 int N;
229 };
230
spx_fft_init(int size)231 void *spx_fft_init(int size)
232 {
233 struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config));
234 table->in = fftwf_malloc(sizeof(float) * (size+2));
235 table->out = fftwf_malloc(sizeof(float) * (size+2));
236
237 table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT);
238 table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT);
239
240 table->N = size;
241 return table;
242 }
243
spx_fft_destroy(void * table)244 void spx_fft_destroy(void *table)
245 {
246 struct fftw_config *t = (struct fftw_config *) table;
247 fftwf_destroy_plan(t->fft);
248 fftwf_destroy_plan(t->ifft);
249 fftwf_free(t->in);
250 fftwf_free(t->out);
251 speex_free(table);
252 }
253
254
spx_fft(void * table,spx_word16_t * in,spx_word16_t * out)255 void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
256 {
257 int i;
258 struct fftw_config *t = (struct fftw_config *) table;
259 const int N = t->N;
260 float *iptr = t->in;
261 float *optr = t->out;
262 const float m = 1.0 / N;
263 for(i=0;i<N;++i)
264 iptr[i]=in[i] * m;
265
266 fftwf_execute(t->fft);
267
268 out[0] = optr[0];
269 for(i=1;i<N;++i)
270 out[i] = optr[i+1];
271 }
272
spx_ifft(void * table,spx_word16_t * in,spx_word16_t * out)273 void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
274 {
275 int i;
276 struct fftw_config *t = (struct fftw_config *) table;
277 const int N = t->N;
278 float *iptr = t->in;
279 float *optr = t->out;
280
281 iptr[0] = in[0];
282 iptr[1] = 0.0f;
283 for(i=1;i<N;++i)
284 iptr[i+1] = in[i];
285 iptr[N+1] = 0.0f;
286
287 fftwf_execute(t->ifft);
288
289 for(i=0;i<N;++i)
290 out[i] = optr[i];
291 }
292
293 #elif defined(USE_KISS_FFT)
294
295 #include "kiss_fftr.h"
296 #include "kiss_fft.h"
297
298 struct kiss_config {
299 kiss_fftr_cfg forward;
300 kiss_fftr_cfg backward;
301 int N;
302 };
303
spx_fft_init(int size)304 void *spx_fft_init(int size)
305 {
306 struct kiss_config *table;
307 table = (struct kiss_config*)speex_alloc(sizeof(struct kiss_config));
308 table->forward = kiss_fftr_alloc(size,0,NULL,NULL);
309 table->backward = kiss_fftr_alloc(size,1,NULL,NULL);
310 table->N = size;
311 return table;
312 }
313
spx_fft_destroy(void * table)314 void spx_fft_destroy(void *table)
315 {
316 struct kiss_config *t = (struct kiss_config *)table;
317 kiss_fftr_free(t->forward);
318 kiss_fftr_free(t->backward);
319 speex_free(table);
320 }
321
322 #ifdef FIXED_POINT
323
spx_fft(void * table,spx_word16_t * in,spx_word16_t * out)324 void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
325 {
326 int shift;
327 struct kiss_config *t = (struct kiss_config *)table;
328 shift = maximize_range(in, in, 32000, t->N);
329 kiss_fftr2(t->forward, in, out);
330 renorm_range(in, in, shift, t->N);
331 renorm_range(out, out, shift, t->N);
332 }
333
334 #else
335
spx_fft(void * table,spx_word16_t * in,spx_word16_t * out)336 void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
337 {
338 int i;
339 float scale;
340 struct kiss_config *t = (struct kiss_config *)table;
341 scale = 1./t->N;
342 kiss_fftr2(t->forward, in, out);
343 for (i=0;i<t->N;i++)
344 out[i] *= scale;
345 }
346 #endif
347
spx_ifft(void * table,spx_word16_t * in,spx_word16_t * out)348 void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
349 {
350 struct kiss_config *t = (struct kiss_config *)table;
351 kiss_fftri2(t->backward, in, out);
352 }
353
354
355 #else
356
357 #error No other FFT implemented
358
359 #endif
360
361
362 #ifdef FIXED_POINT
363 /*#include "smallft.h"*/
364
365
spx_fft_float(void * table,float * in,float * out)366 void spx_fft_float(void *table, float *in, float *out)
367 {
368 int i;
369 #ifdef USE_SMALLFT
370 int N = ((struct drft_lookup *)table)->n;
371 #elif defined(USE_KISS_FFT)
372 int N = ((struct kiss_config *)table)->N;
373 #else
374 #endif
375 #ifdef VAR_ARRAYS
376 spx_word16_t _in[N];
377 spx_word16_t _out[N];
378 #else
379 spx_word16_t _in[MAX_FFT_SIZE];
380 spx_word16_t _out[MAX_FFT_SIZE];
381 #endif
382 for (i=0;i<N;i++)
383 _in[i] = (int)floor(.5+in[i]);
384 spx_fft(table, _in, _out);
385 for (i=0;i<N;i++)
386 out[i] = _out[i];
387 #if 0
388 if (!fixed_point)
389 {
390 float scale;
391 struct drft_lookup t;
392 spx_drft_init(&t, ((struct kiss_config *)table)->N);
393 scale = 1./((struct kiss_config *)table)->N;
394 for (i=0;i<((struct kiss_config *)table)->N;i++)
395 out[i] = scale*in[i];
396 spx_drft_forward(&t, out);
397 spx_drft_clear(&t);
398 }
399 #endif
400 }
401
spx_ifft_float(void * table,float * in,float * out)402 void spx_ifft_float(void *table, float *in, float *out)
403 {
404 int i;
405 #ifdef USE_SMALLFT
406 int N = ((struct drft_lookup *)table)->n;
407 #elif defined(USE_KISS_FFT)
408 int N = ((struct kiss_config *)table)->N;
409 #else
410 #endif
411 #ifdef VAR_ARRAYS
412 spx_word16_t _in[N];
413 spx_word16_t _out[N];
414 #else
415 spx_word16_t _in[MAX_FFT_SIZE];
416 spx_word16_t _out[MAX_FFT_SIZE];
417 #endif
418 for (i=0;i<N;i++)
419 _in[i] = (int)floor(.5+in[i]);
420 spx_ifft(table, _in, _out);
421 for (i=0;i<N;i++)
422 out[i] = _out[i];
423 #if 0
424 if (!fixed_point)
425 {
426 int i;
427 struct drft_lookup t;
428 spx_drft_init(&t, ((struct kiss_config *)table)->N);
429 for (i=0;i<((struct kiss_config *)table)->N;i++)
430 out[i] = in[i];
431 spx_drft_backward(&t, out);
432 spx_drft_clear(&t);
433 }
434 #endif
435 }
436
437 #else
438
spx_fft_float(void * table,float * in,float * out)439 void spx_fft_float(void *table, float *in, float *out)
440 {
441 spx_fft(table, in, out);
442 }
spx_ifft_float(void * table,float * in,float * out)443 void spx_ifft_float(void *table, float *in, float *out)
444 {
445 spx_ifft(table, in, out);
446 }
447
448 #endif
449