blob: 4f37e1b3fb23f43bf165a631b09f6b8d5754588f [file] [log] [blame]
The Android Open Source Project98913fe2009-03-15 16:47:32 -07001/* 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
45static 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
69static 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
84void *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
92void spx_fft_destroy(void *table)
93{
94 spx_drft_clear(table);
95 speex_free(table);
96}
97
98void 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
116void 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
132struct mkl_config {
133 DFTI_DESCRIPTOR_HANDLE desc;
134 int N;
135};
136
137void *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
149void 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
156void 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
162void 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_GPL_FFTW3)
169
170#include <fftw3.h>
171
172struct fftw_config {
173 float *in;
174 float *out;
175 fftwf_plan fft;
176 fftwf_plan ifft;
177 int N;
178};
179
180void *spx_fft_init(int size)
181{
182 struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config));
183 table->in = fftwf_malloc(sizeof(float) * (size+2));
184 table->out = fftwf_malloc(sizeof(float) * (size+2));
185
186 table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT);
187 table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT);
188
189 table->N = size;
190 return table;
191}
192
193void spx_fft_destroy(void *table)
194{
195 struct fftw_config *t = (struct fftw_config *) table;
196 fftwf_destroy_plan(t->fft);
197 fftwf_destroy_plan(t->ifft);
198 fftwf_free(t->in);
199 fftwf_free(t->out);
200 speex_free(table);
201}
202
203
204void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
205{
206 int i;
207 struct fftw_config *t = (struct fftw_config *) table;
208 const int N = t->N;
209 float *iptr = t->in;
210 float *optr = t->out;
211 const float m = 1.0 / N;
212 for(i=0;i<N;++i)
213 iptr[i]=in[i] * m;
214
215 fftwf_execute(t->fft);
216
217 out[0] = optr[0];
218 for(i=1;i<N;++i)
219 out[i] = optr[i+1];
220}
221
222void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
223{
224 int i;
225 struct fftw_config *t = (struct fftw_config *) table;
226 const int N = t->N;
227 float *iptr = t->in;
228 float *optr = t->out;
229
230 iptr[0] = in[0];
231 iptr[1] = 0.0f;
232 for(i=1;i<N;++i)
233 iptr[i+1] = in[i];
234 iptr[N+1] = 0.0f;
235
236 fftwf_execute(t->ifft);
237
238 for(i=0;i<N;++i)
239 out[i] = optr[i];
240}
241
242#elif defined(USE_KISS_FFT)
243
244#include "kiss_fftr.h"
245#include "kiss_fft.h"
246
247struct kiss_config {
248 kiss_fftr_cfg forward;
249 kiss_fftr_cfg backward;
250 int N;
251};
252
253void *spx_fft_init(int size)
254{
255 struct kiss_config *table;
256 table = (struct kiss_config*)speex_alloc(sizeof(struct kiss_config));
257 table->forward = kiss_fftr_alloc(size,0,NULL,NULL);
258 table->backward = kiss_fftr_alloc(size,1,NULL,NULL);
259 table->N = size;
260 return table;
261}
262
263void spx_fft_destroy(void *table)
264{
265 struct kiss_config *t = (struct kiss_config *)table;
266 kiss_fftr_free(t->forward);
267 kiss_fftr_free(t->backward);
268 speex_free(table);
269}
270
271#ifdef FIXED_POINT
272
273void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
274{
275 int shift;
276 struct kiss_config *t = (struct kiss_config *)table;
277 shift = maximize_range(in, in, 32000, t->N);
278 kiss_fftr2(t->forward, in, out);
279 renorm_range(in, in, shift, t->N);
280 renorm_range(out, out, shift, t->N);
281}
282
283#else
284
285void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
286{
287 int i;
288 float scale;
289 struct kiss_config *t = (struct kiss_config *)table;
290 scale = 1./t->N;
291 kiss_fftr2(t->forward, in, out);
292 for (i=0;i<t->N;i++)
293 out[i] *= scale;
294}
295#endif
296
297void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
298{
299 struct kiss_config *t = (struct kiss_config *)table;
300 kiss_fftri2(t->backward, in, out);
301}
302
303
304#else
305
306#error No other FFT implemented
307
308#endif
309
310
311#ifdef FIXED_POINT
312/*#include "smallft.h"*/
313
314
315void spx_fft_float(void *table, float *in, float *out)
316{
317 int i;
318#ifdef USE_SMALLFT
319 int N = ((struct drft_lookup *)table)->n;
320#elif defined(USE_KISS_FFT)
321 int N = ((struct kiss_config *)table)->N;
322#else
323#endif
324#ifdef VAR_ARRAYS
325 spx_word16_t _in[N];
326 spx_word16_t _out[N];
327#else
328 spx_word16_t _in[MAX_FFT_SIZE];
329 spx_word16_t _out[MAX_FFT_SIZE];
330#endif
331 for (i=0;i<N;i++)
332 _in[i] = (int)floor(.5+in[i]);
333 spx_fft(table, _in, _out);
334 for (i=0;i<N;i++)
335 out[i] = _out[i];
336#if 0
337 if (!fixed_point)
338 {
339 float scale;
340 struct drft_lookup t;
341 spx_drft_init(&t, ((struct kiss_config *)table)->N);
342 scale = 1./((struct kiss_config *)table)->N;
343 for (i=0;i<((struct kiss_config *)table)->N;i++)
344 out[i] = scale*in[i];
345 spx_drft_forward(&t, out);
346 spx_drft_clear(&t);
347 }
348#endif
349}
350
351void spx_ifft_float(void *table, float *in, float *out)
352{
353 int i;
354#ifdef USE_SMALLFT
355 int N = ((struct drft_lookup *)table)->n;
356#elif defined(USE_KISS_FFT)
357 int N = ((struct kiss_config *)table)->N;
358#else
359#endif
360#ifdef VAR_ARRAYS
361 spx_word16_t _in[N];
362 spx_word16_t _out[N];
363#else
364 spx_word16_t _in[MAX_FFT_SIZE];
365 spx_word16_t _out[MAX_FFT_SIZE];
366#endif
367 for (i=0;i<N;i++)
368 _in[i] = (int)floor(.5+in[i]);
369 spx_ifft(table, _in, _out);
370 for (i=0;i<N;i++)
371 out[i] = _out[i];
372#if 0
373 if (!fixed_point)
374 {
375 int i;
376 struct drft_lookup t;
377 spx_drft_init(&t, ((struct kiss_config *)table)->N);
378 for (i=0;i<((struct kiss_config *)table)->N;i++)
379 out[i] = in[i];
380 spx_drft_backward(&t, out);
381 spx_drft_clear(&t);
382 }
383#endif
384}
385
386#else
387
388void spx_fft_float(void *table, float *in, float *out)
389{
390 spx_fft(table, in, out);
391}
392void spx_ifft_float(void *table, float *in, float *out)
393{
394 spx_ifft(table, in, out);
395}
396
397#endif