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 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 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 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 92 void spx_fft_destroy(void *table) 93 { 94 spx_drft_clear(table); 95 speex_free(table); 96 } 97 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 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 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 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 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 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_GPL_FFTW3) 169 170 #include <fftw3.h> 171 172 struct fftw_config { 173 float *in; 174 float *out; 175 fftwf_plan fft; 176 fftwf_plan ifft; 177 int N; 178 }; 179 180 void *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 193 void 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 204 void 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 222 void 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 247 struct kiss_config { 248 kiss_fftr_cfg forward; 249 kiss_fftr_cfg backward; 250 int N; 251 }; 252 253 void *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 263 void 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 273 void 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 285 void 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 297 void 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 315 void 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 351 void 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 388 void spx_fft_float(void *table, float *in, float *out) 389 { 390 spx_fft(table, in, out); 391 } 392 void spx_ifft_float(void *table, float *in, float *out) 393 { 394 spx_ifft(table, in, out); 395 } 396 397 #endif 398