SAF
Loading...
Searching...
No Matches
saf_utility_fft.c
Go to the documentation of this file.
1/*
2 * Copyright 2019 Leo McCormack
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
38#include "saf_utilities.h"
39#include "saf_externals.h"
40#ifdef SAF_USE_APPLE_ACCELERATE
41# include "AvailabilityVersions.h"
42# ifdef __MAC_12_0
43//# define SAF_USE_INTERLEAVED_VDSP /**< New interleaved implementation as of macOS 12.0+. UNFINISHED+UNTESTED! */
44# endif
45#endif
46
48typedef struct _saf_stft_data {
49 int winsize, hopsize, fftsize, nCHin, nCHout, nBands;
50 void* hFFT;
51 int numOvrlpAddBlocks, bufferlength, nPrevHops;
52 float* window, *insig_rect_win, *insig_win, *outsig_win;
53 float** overlapAddBuffer;
54 float*** prev_inhops;
55 float_complex* tmp_fft;
57
59
61typedef struct _saf_rfft_data {
62 int N;
63 float Scale;
64 int useKissFFT_FLAG;
65#if defined(SAF_USE_FFTW)
66 fftwf_plan p_fwd;
67 fftwf_plan p_bwd;
68 float* fwd_bufferTD;
69 float* bwd_bufferTD;
70 fftwf_complex* fwd_bufferFD;
71 fftwf_complex* bwd_bufferFD;
72#elif defined(SAF_USE_INTEL_IPP)
73 int useIPPfft_FLAG;
74 int specSize, specBufferSize, bufferSize, log2n;
75 IppsDFTSpec_R_32f* hDFTspec;
76 IppsFFTSpec_R_32f* hFFTspec;
77 Ipp8u* memSpec;
78 Ipp8u* buffer;
79 Ipp8u* memInit;
80#elif defined(SAF_USE_APPLE_ACCELERATE)
81# ifdef SAF_USE_INTERLEAVED_VDSP
82 vDSP_DFT_Interleaved_Setup DFT_fwd;
83 vDSP_DFT_Interleaved_Setup DFT_bwd;
84# else
85 vDSP_DFT_Setup DFT_fwd;
86 vDSP_DFT_Setup DFT_bwd;
87 DSPSplitComplex VDSP_split;
88 DSPSplitComplex VDSP_split_tmp;
89# endif
90#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
91 DFTI_DESCRIPTOR_HANDLE MKL_FFT_Handle;
92 MKL_LONG input_strides[2], output_strides[2], Status;
93#endif
94 /* DEFAULT: */
95 kiss_fftr_cfg kissFFThandle_fwd;
96 kiss_fftr_cfg kissFFThandle_bkw;
97
99
101typedef struct _saf_fft_data {
102 int N;
103 float Scale;
104 int useKissFFT_FLAG;
105#if defined(SAF_USE_FFTW)
106 fftwf_plan p_fwd;
107 fftwf_plan p_bwd;
108 fftwf_complex* fwd_bufferTD;
109 fftwf_complex* bwd_bufferTD;
110 fftwf_complex* fwd_bufferFD;
111 fftwf_complex* bwd_bufferFD;
112#elif defined(SAF_USE_INTEL_IPP)
113 int useIPPfft_FLAG;
114 int specSize, specBufferSize, bufferSize, log2n;
115 IppsDFTSpec_C_32fc* hDFTspec;
116 IppsFFTSpec_C_32fc* hFFTspec;
117 Ipp8u* memSpec;
118 Ipp8u* buffer;
119 Ipp8u* memInit;
120#elif defined(SAF_USE_APPLE_ACCELERATE)
121# ifdef SAF_USE_INTERLEAVED_VDSP
122 vDSP_DFT_Interleaved_Setup DFT_fwd;
123 vDSP_DFT_Interleaved_Setup DFT_bwd;
124# else
125 vDSP_DFT_Setup DFT_fwd;
126 vDSP_DFT_Setup DFT_bwd;
127 DSPSplitComplex VDSP_split;
128 DSPSplitComplex VDSP_split_tmp;
129# endif
130#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
131 DFTI_DESCRIPTOR_HANDLE MKL_FFT_Handle;
132 MKL_LONG Status;
133#endif
134 /* DEFAULT: */
135 kiss_fft_cfg kissFFThandle_fwd;
136 kiss_fft_cfg kissFFThandle_bkw;
137
139
140
141/* ========================================================================== */
142/* Misc. Functions */
143/* ========================================================================== */
144
146(
147 int fftSize,
148 float fs,
149 float* freqVector
150)
151{
152 int k;
153 for(k=0; k<fftSize/2+1; k++)
154 freqVector[k] = (float)k * fs/(float)fftSize;
155}
156
158(
159 float* x,
160 float* h,
161 int x_len,
162 int h_len,
163 int nCH,
164 float* y
165)
166{
167 int i, y_len, fftSize, nBins;
168 float* h0, *x0, *y0;
169 float_complex* H, *X, *Y;
170 void* hfft;
171
172 /* prep */
173 y_len = x_len + h_len - 1;
174 fftSize = (int)((float)nextpow2(y_len)+0.5f);
175 nBins = fftSize/2+1;
176 h0 = calloc1d(fftSize, sizeof(float));
177 x0 = calloc1d(fftSize, sizeof(float));
178 y0 = malloc1d(fftSize * sizeof(float));
179 H = malloc1d(nBins*sizeof(float_complex));
180 X = malloc1d(nBins*sizeof(float_complex));
181 Y = malloc1d(nBins*sizeof(float_complex));
182 saf_rfft_create(&hfft, fftSize);
183
184 /* apply convolution per channel */
185 for(i=0; i<nCH; i++){
186 /* zero pad to avoid circular convolution artefacts, prior to fft */
187 memcpy(h0, &h[i*h_len], h_len*sizeof(float));
188 memcpy(x0, &x[i*x_len], x_len*sizeof(float));
189 saf_rfft_forward(hfft, x0, X);
190 saf_rfft_forward(hfft, h0, H);
191
192 /* multiply the two spectra */
193 utility_cvvmul(X, H, nBins, Y);
194
195 /* ifft, truncate and store to output */
196 saf_rfft_backward(hfft, Y, y0);
197 memcpy(&y[i*y_len], y0, y_len*sizeof(float));
198 }
199
200 /* tidy up */
201 saf_rfft_destroy(&hfft);
202 free(h0);
203 free(x0);
204 free(y0);
205 free(H);
206 free(X);
207 free(Y);
208}
209
211(
212 float* x,
213 float* h,
214 int x_len,
215 int h_len,
216 int nCH,
217 float* y
218)
219{
220 int i;
221 float* y_tmp;
222
223 y_tmp = malloc1d(nCH*(x_len+h_len-1)*sizeof(float));
224 fftconv(x, h, x_len, h_len, nCH, y_tmp);
225 for(i=0; i<nCH; i++)
226 memcpy(&y[i*x_len], &y_tmp[i*(x_len+h_len-1)], x_len*sizeof(float));
227 free(y_tmp);
228}
229
231(
232 float_complex* x,
233 int x_len,
234 float_complex* y
235)
236{
237#if defined(SAF_USE_INTEL_IPP) && 0 /* Untested: */
238 IppsHilbertSpec* ippSpec;
239 int ippSpecSize;
240 int ippBufferSize;
241 Ipp8u* buffer;
242
243 saf_assert(!ippsHilbertGetSize_32f32fc(x_len, ippAlgHintNone, &ippSpecSize, &ippBufferSize), "IPP error!");
244 ippSpec = (IppsHilbertSpec*)ippsMalloc_8u(ippSpecSize);
245 buffer = ippsMalloc_8u(ippBufferSize);
246 saf_assert(!ippsHilbertInit_32f32fc(x_len, ippAlgHintNone, ippSpec, buffer), "IPP error!");
247 saf_assert(!ippsHilbert_32f32fc(x, (Ipp32fc*)y, ippSpec, buffer), "IPP error!");
248
249 ippsFree(ippSpec);
250 ippsFree(buffer);
251#else
252 int i;
253 float_complex *xfft, *h, *xhfft;
254 void* hfft;
255
256 saf_fft_create(&hfft, x_len);
257 xfft = malloc1d(x_len*sizeof(float_complex));
258 h = malloc1d(x_len*sizeof(float_complex));
259 xhfft = malloc1d(x_len*sizeof(float_complex));
260
261 /* Forward fft */
262 saf_fft_forward(hfft, x, xfft);
263
264 /* define vector h */
265 memset(h, 0, sizeof(float_complex)*x_len);
266 if(x_len % 2 == 0){
267 /* even */
268 h[0] = cmplxf(1.0f, 0.0f);
269 h[x_len/2] = cmplxf(1.0f, 0.0f);
270 for(i=1;i<x_len/2;i++)
271 h[i] = cmplxf(2.0f, 0.0f);
272 }
273 else{
274 saf_assert(x_len % 2 == 0, "Uneven lengths are not supported by saf_fft");
275 /* odd */
276 h[0] = cmplxf(1.0f, 0.0f);
277 for(i=1;i<(x_len+1)/2;i++)
278 h[i] = cmplxf(2.0f, 0.0f);
279 }
280
281 /* apply h, and ifft */
282 utility_cvvmul(xfft, h, x_len, xhfft);
283 saf_fft_backward(hfft, xhfft, y);
284
285 /* tidy up */
286 saf_fft_destroy(&hfft);
287 free(xfft);
288 free(h);
289 free(xhfft);
290#endif
291}
292
293/* ========================================================================== */
294/* Short-time Fourier Transform (STFT) */
295/* ========================================================================== */
296
298(
299 void ** const phSTFT,
300 int winsize,
301 int hopsize,
302 int nCHin,
303 int nCHout,
305)
306{
307 *phSTFT = malloc1d(sizeof(saf_stft_data));
308 saf_stft_data *h = (saf_stft_data*)(*phSTFT);
309
310 h->nCHin = nCHin;
311 h->nCHout = nCHout;
312 h->winsize = winsize;
313 h->hopsize = hopsize;
314 h->nBands = winsize+1;
315 h->FDformat = FDformat;
316
317 /* set-up FFT */
318 h->fftsize = 2*winsize;
319 saf_rfft_create(&(h->hFFT), h->fftsize);
320 h->insig_rect_win = calloc1d(h->fftsize, sizeof(float));
321 h->insig_win = calloc1d(h->fftsize, sizeof(float));
322
323 /* Intermediate buffers */
324 h->tmp_fft = malloc1d(h->nBands * sizeof(float_complex));
325 h->outsig_win = malloc1d(h->fftsize*sizeof(float));
326 h->nPrevHops = winsize/hopsize-1;
327 if (h->nPrevHops>0)
328 h->prev_inhops = (float***)calloc3d(h->nPrevHops, nCHin, hopsize, sizeof(float));
329 else
330 h->prev_inhops = NULL;
331
332 /* Windowing function */
333 if(winsize==hopsize)
334 h->window = NULL;
335 else{
336 h->window = malloc1d(winsize*sizeof(float));
338 }
339
340 /* Overlap-add buffer */
341 h->numOvrlpAddBlocks = winsize/hopsize;
342 h->bufferlength = h->numOvrlpAddBlocks * (h->fftsize);
343 h->overlapAddBuffer = (float**)calloc2d(nCHout, h->bufferlength, sizeof(float));
344}
345
347(
348 void ** const phSTFT
349)
350{
351 saf_stft_data *h = (saf_stft_data*)(*phSTFT);
352 if(h!=NULL){
353 saf_rfft_destroy(&(h->hFFT));
354 free(h->window);
355 free(h->overlapAddBuffer);
356 free(h->insig_rect_win);
357 free(h->insig_win);
358 free(h->tmp_fft);
359 free(h->prev_inhops);
360 free(h);
361 h=NULL;
362 *phSTFT = NULL;
363 }
364}
365
367(
368 void * const hSTFT,
369 float** dataTD,
370 int framesize,
371 float_complex*** dataFD
372
373)
374{
375 saf_stft_data *h = (saf_stft_data*)(hSTFT);
376 int ch, j, nHops, t, band, idx, hIdx;
377
378 saf_assert(framesize % h->hopsize == 0, "framesize must be multiple of hopsize");
379 nHops = framesize/h->hopsize;
380
381 /* For linear time-invariant (LTI) operation (i.e. no previous hops are
382 * required) */
383 if(h->winsize==h->hopsize){
384 for (t = 0; t<nHops; t++){
385 for(ch=0; ch < h->nCHin; ch++){
386 /* Window input signal (Rectangular) */
387 memcpy(h->insig_rect_win, &dataTD[ch][t*(h->hopsize)], h->winsize*sizeof(float));
388
389 /* Apply FFT and copy data to output dataFD buffer */
390 switch(h->FDformat){
392 saf_rfft_forward(h->hFFT, h->insig_rect_win, dataFD[t][ch]);
393 break;
394
396 saf_rfft_forward(h->hFFT, h->insig_rect_win, h->tmp_fft);
397 for(band=0; band<h->nBands; band++)
398 dataFD[band][ch][t] = h->tmp_fft[band];
399 break;
400 }
401 }
402 }
403 }
404 /* For oversampled TF transforms */
405 else{
406 idx = 0;
407 for (t = 0; t<nHops; t++){
408 for(ch=0; ch < h->nCHin; ch++){
409 hIdx = 0;
410 /* Window input signal */
411 while (hIdx < h->winsize){
412 memcpy(&(h->insig_rect_win[hIdx]), h->prev_inhops[0][ch], h->hopsize*sizeof(float));
413 for(j=0; j< h->nPrevHops-1; j++)
414 memcpy(h->prev_inhops[j][ch], h->prev_inhops[j+1][ch], h->hopsize*sizeof(float));
415 memcpy(h->prev_inhops[h->nPrevHops-1][ch], &dataTD[ch][idx], h->hopsize*sizeof(float));
416 hIdx += h->hopsize;
417 }
418 utility_svvmul(h->insig_rect_win, h->window, h->winsize, h->insig_win);
419
420 /* Apply FFT and copy data to output dataFD buffer */
421 switch(h->FDformat){
423 saf_rfft_forward(h->hFFT, h->insig_win, dataFD[t][ch]);
424 break;
425
427 saf_rfft_forward(h->hFFT, h->insig_win, h->tmp_fft);
428 for(band=0; band<h->nBands; band++)
429 dataFD[band][ch][t] = h->tmp_fft[band];
430 break;
431 }
432 }
433 idx += h->hopsize;
434 }
435 }
436}
437
439(
440 void * const hSTFT,
441 float_complex*** dataFD,
442 int framesize,
443 float** dataTD
444)
445{
446 saf_stft_data *h = (saf_stft_data*)(hSTFT);
447 int t, ch, nHops, band;
448
449 saf_assert(framesize % h->hopsize == 0, "framesize must be multiple of hopsize");
450 nHops = framesize/h->hopsize;
451
452 for (t = 0; t<nHops; t++){
453 for(ch=0; ch < h->nCHout; ch++){
454 /* Shift data down */
455 memcpy(h->overlapAddBuffer[ch], h->overlapAddBuffer[ch] + h->hopsize, (h->numOvrlpAddBlocks-1)*(h->hopsize)*sizeof(float));
456
457 /* Append with zeros */
458 memset(h->overlapAddBuffer[ch] + (h->numOvrlpAddBlocks-1)*(h->hopsize), 0, h->hopsize*sizeof(float));
459
460 /* Apply inverse FFT */
461 switch(h->FDformat){
463 saf_rfft_backward(h->hFFT, dataFD[t][ch], h->outsig_win);
464 break;
466 for(band=0; band<h->nBands; band++)
467 h->tmp_fft[band] = dataFD[band][ch][t];
468 saf_rfft_backward(h->hFFT, h->tmp_fft, h->outsig_win);
469 break;
470 }
471
472 /* Overlap-Add 1:hopsize to output buffer */
473 cblas_saxpy(h->fftsize, 1.0f, h->outsig_win, 1, h->overlapAddBuffer[ch], 1);
474 memcpy(dataTD[ch] + t*(h->hopsize), h->overlapAddBuffer[ch], h->hopsize*sizeof(float));
475 }
476 }
477}
478
480(
481 void * const hSTFT
482)
483{
484 saf_stft_data *h = (saf_stft_data*)(hSTFT);
485 if(h->nPrevHops > 0)
486 memset(FLATTEN3D(h->prev_inhops), 0, h->nPrevHops * (h->nCHin) * (h->hopsize) * sizeof(float));
487 memset(FLATTEN2D(h->overlapAddBuffer), 0, h->nCHout * (h->bufferlength) * sizeof(float));
488}
489
491(
492 void * const hSTFT,
493 int new_nCHin,
494 int new_nCHout
495)
496{
497 saf_stft_data *h = (saf_stft_data*)(hSTFT);
498 int i, ch;
499
500 if(new_nCHin != h->nCHin && h->nPrevHops > 0){
501 /* Reallocate memory while retaining previous values (which will be
502 * truncated if new_nCHin < nCHin) */
503 h->prev_inhops = (float***)realloc3d_r((void***)h->prev_inhops, h->nPrevHops, new_nCHin, h->hopsize,
504 h->nPrevHops, h->nCHin, h->hopsize, sizeof(float));
505 /* Zero new channels if new_nCHin > nCHin */
506 for(i=0; i< h->nPrevHops; i++)
507 for(ch=h->nCHin; ch<new_nCHin; ch++)
508 memset(h->prev_inhops[i][ch], 0, h->hopsize * sizeof(float));
509
510 h->nCHin = new_nCHin;
511 }
512
513 if(new_nCHout != h->nCHout){
514 /* Reallocate memory while retaining previous values (which will be
515 * truncated if new_nCHout < nCHout) */
516 h->overlapAddBuffer = (float**)realloc2d_r((void**)h->overlapAddBuffer, new_nCHout, h->bufferlength,
517 h->nCHout, h->bufferlength, sizeof(float));
518 /* Zero new channels if new_nCHout > nCHout */
519 for(ch=h->nCHout; ch<new_nCHout; ch++)
520 memset(h->overlapAddBuffer[ch], 0, h->bufferlength * sizeof(float));
521
522 h->nCHout = new_nCHout;
523 }
524}
525
526
527/* ========================================================================== */
528/* Real<->Half-Complex (Conjugate-Symmetric) FFT */
529/* ========================================================================== */
530
532(
533 void ** const phFFT,
534 int N
535)
536{
537 *phFFT = malloc1d(sizeof(saf_rfft_data));
538 saf_rfft_data *h = (saf_rfft_data*)(*phFFT);
539
540 h->N = N;
541 h->Scale = 1.0f/(float)N; /* output scaling after ifft */
542 saf_assert(N>=2 && ISEVEN(N), "Only even (non zero) FFT sizes are supported");
543 h->useKissFFT_FLAG = 0;
544#if defined(SAF_USE_FFTW)
545 h->fwd_bufferTD = malloc1d(h->N*sizeof(float));
546 h->bwd_bufferTD = malloc1d(h->N*sizeof(float));
547 h->fwd_bufferFD = malloc1d((h->N/2+1)*sizeof(fftwf_complex));
548 h->bwd_bufferFD = malloc1d((h->N/2+1)*sizeof(fftwf_complex));
549 h->p_fwd = fftwf_plan_dft_r2c_1d(h->N, h->fwd_bufferTD, h->fwd_bufferFD, FFTW_ESTIMATE);
550 h->p_bwd = fftwf_plan_dft_c2r_1d(h->N, h->bwd_bufferFD, h->bwd_bufferTD, FFTW_ESTIMATE);
551#elif defined(SAF_USE_INTEL_IPP)
552 /* Use ippsFFT if N is 2^x, otherwise, use ippsDFT */
553 if((int)(log2f((float)N)+1.0f) == (int)(log2f((float)N))){
554 h->useIPPfft_FLAG = 1;
555 h->log2n = (int)(log2f((float)N)+0.1f);
556 ippsFFTGetSize_R_32f(h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
557 h->hFFTspec = NULL;
558 h->memSpec = (Ipp8u*) ippMalloc(h->specSize);
559 h->buffer = (Ipp8u*) ippMalloc(h->bufferSize);
560 h->memInit = (Ipp8u*) ippMalloc(h->specBufferSize);
561 ippsFFTInit_R_32f(&(h->hFFTspec), h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->memSpec, h->memInit);
562 }
563 else{
564 h->useIPPfft_FLAG = 0;
565 ippsDFTGetSize_R_32f(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
566 h->hDFTspec = (IppsDFTSpec_R_32f*) ippMalloc(h->specSize);
567 h->buffer = (Ipp8u*) ippMalloc(h->bufferSize);
568 h->memInit = (Ipp8u*) ippMalloc(h->specBufferSize);
569 ippsDFTInit_R_32f(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->hDFTspec, h->memInit);
570 }
571 if (h->memInit)
572 ippFree(h->memInit);
573#elif defined(SAF_USE_APPLE_ACCELERATE)
574# ifdef SAF_USE_INTERLEAVED_VDSP
575 h->DFT_fwd = vDSP_DFT_Interleaved_CreateSetup(0, N, vDSP_DFT_FORWARD, vDSP_DFT_Interleaved_RealtoComplex);
576 h->DFT_bwd = vDSP_DFT_Interleaved_CreateSetup(0, N, vDSP_DFT_INVERSE, vDSP_DFT_Interleaved_RealtoComplex);
577# else
578 h->DFT_fwd = vDSP_DFT_zrop_CreateSetup(0, N, vDSP_DFT_FORWARD);
579 h->DFT_bwd = vDSP_DFT_zrop_CreateSetup(0, N, vDSP_DFT_INVERSE);
580# endif
581 if(h->DFT_fwd==0 || h->DFT_bwd==0) /* specified N not supported by vDSP, so must use the default */
582 h->useKissFFT_FLAG = 1;
583 else{
584 /* Note that DFT lengths must satisfy: f * 2.^g, where f is 1, 3, 5, or 15, and g >=4 */
585 saf_assert(h->DFT_fwd!=0 && h->DFT_bwd!=0, "Failed to create vDSP DFT");
586# ifndef SAF_USE_INTERLEAVED_VDSP
587 h->VDSP_split_tmp.realp = malloc1d((h->N/2)*sizeof(float));
588 h->VDSP_split_tmp.imagp = malloc1d((h->N/2)*sizeof(float));
589 h->VDSP_split.realp = malloc1d((h->N/2)*sizeof(float));
590 h->VDSP_split.imagp = malloc1d((h->N/2)*sizeof(float));
591# endif
592 }
593#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
594 h->MKL_FFT_Handle = 0;
595 h->Status = DftiCreateDescriptor(&(h->MKL_FFT_Handle), DFTI_SINGLE, DFTI_REAL, 1, h->N); /* 1-D, single precision, real_input->fft->half_complex->ifft->real_output */
596 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); /* Not inplace, i.e. output has its own dedicated memory */
597 /* specify output format as complex conjugate-symmetric data. This is the same as MatLab, except only the
598 * first N/2+1 elements are returned. The inverse transform will automatically symmetrically+conjugate
599 * replicate these elements, in order to get the required N elements internally. */
600 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX);
601 /* Configuration parameters for backward-FFT */
602 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_BACKWARD_SCALE, h->Scale); /* scalar applied after ifft */
603 /* commit these chosen parameters */
604 h->Status = DftiCommitDescriptor(h->MKL_FFT_Handle);
605#else
606 /* Must use default FFT: */
607 h->useKissFFT_FLAG = 1;
608#endif
609 /* DEFAULT: */
610 if(h->useKissFFT_FLAG){
611 h->kissFFThandle_fwd = kiss_fftr_alloc(h->N, 0, NULL, NULL);
612 h->kissFFThandle_bkw = kiss_fftr_alloc(h->N, 1, NULL, NULL);
613 }
614}
615
617(
618 void ** const phFFT
619)
620{
621 saf_rfft_data *h = (saf_rfft_data*)(*phFFT);
622 if(h!=NULL){
623#if defined(SAF_USE_FFTW)
624 free(h->fwd_bufferTD);
625 free(h->bwd_bufferTD);
626 free(h->fwd_bufferFD);
627 free(h->bwd_bufferFD);
628 fftwf_destroy_plan(h->p_bwd);
629 fftwf_destroy_plan(h->p_fwd);
630#elif defined(SAF_USE_INTEL_IPP)
631 if(h->useIPPfft_FLAG){
632 if(h->memSpec)
633 ippFree(h->memSpec);
634 }
635 else {
636 if(h->hDFTspec)
637 ippFree(h->hDFTspec);
638 }
639 if(h->buffer)
640 ippFree(h->buffer);
641#elif defined(SAF_USE_APPLE_ACCELERATE)
642 if(!h->useKissFFT_FLAG){
643# ifdef SAF_USE_INTERLEAVED_VDSP
644 vDSP_DFT_Interleaved_DestroySetup(h->DFT_fwd);
645 vDSP_DFT_Interleaved_DestroySetup(h->DFT_bwd);
646# else
647 vDSP_DFT_DestroySetup(h->DFT_fwd);
648 vDSP_DFT_DestroySetup(h->DFT_bwd);
649 free(h->VDSP_split_tmp.realp);
650 free(h->VDSP_split_tmp.imagp);
651 free(h->VDSP_split.realp);
652 free(h->VDSP_split.imagp);
653# endif
654 }
655#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
656 h->Status = DftiFreeDescriptor(&(h->MKL_FFT_Handle));
657#endif
658 if(h->useKissFFT_FLAG){
659 kiss_fftr_free(h->kissFFThandle_fwd);
660 kiss_fftr_free(h->kissFFThandle_bkw);
661 }
662
663 free(h);
664 h = NULL;
665 *phFFT = NULL;
666 }
667}
668
670(
671 void * const hFFT,
672 float* inputTD,
673 float_complex* outputFD
674)
675{
676 saf_rfft_data *h = (saf_rfft_data*)(hFFT);
677
678#if defined(SAF_USE_FFTW)
679 cblas_scopy(h->N, inputTD, 1, h->fwd_bufferTD, 1);
680 fftwf_execute(h->p_fwd);
681 cblas_ccopy(h->N/2+1, h->fwd_bufferFD, 1, outputFD, 1);
682#elif defined(SAF_USE_INTEL_IPP)
683 if(h->useIPPfft_FLAG)
684 ippsFFTFwd_RToCCS_32f((Ipp32f*)inputTD, (Ipp32f*)outputFD, h->hFFTspec, h->buffer);
685 else
686 ippsDFTFwd_RToCCS_32f((Ipp32f*)inputTD, (Ipp32f*)outputFD, h->hDFTspec, h->buffer);
687#elif defined(SAF_USE_APPLE_ACCELERATE)
688 if(!h->useKissFFT_FLAG){
689# ifdef SAF_USE_INTERLEAVED_VDSP
690 saf_print_error("Not implemented yet");
691# else
692 vDSP_ctoz((DSPComplex*)inputTD, 2, &(h->VDSP_split_tmp), 1, (h->N)/2);
693 vDSP_DFT_Execute(h->DFT_fwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
694 /* DC */
695 outputFD[0] = cmplxf(h->VDSP_split.realp[0], 0.0f);
696 cblas_scopy(h->N/2-1, &h->VDSP_split.realp[1], 1, &((float*)(outputFD))[2], 2);
697 cblas_scopy(h->N/2-1, &h->VDSP_split.imagp[1], 1, &((float*)(outputFD))[3], 2);
698 /* the real part of the Nyquist value is the imaginary part of DC. */
699 /* https://stackoverflow.com/questions/43289265/implementing-an-fft-using-vdsp */
700 outputFD[h->N/2] = cmplxf(h->VDSP_split.imagp[0], 0.0f);
701 /* Note: the output is scaled by 2, because vDSP_fft automatically compensates for the loss of energy
702 * when removing the symmetric/conjugate (N/2+2:N) bins. However, this is dumb... so the 2x scaling
703 * is removed here; so it has parity with the other FFT implementations supported by SAF. */
704# endif
705 cblas_sscal(2*(h->N/2+1), 0.5f, (float*)outputFD, 1);
706 }
707#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
708 h->Status = DftiComputeForward(h->MKL_FFT_Handle, inputTD, outputFD);
709#endif
710 if(h->useKissFFT_FLAG)
711 kiss_fftr(h->kissFFThandle_fwd, inputTD, (kiss_fft_cpx*)outputFD);
712}
713
715(
716 void * const hFFT,
717 float_complex* inputFD,
718 float* outputTD
719)
720{
721 saf_rfft_data *h = (saf_rfft_data*)(hFFT);
722
723#if defined(SAF_USE_FFTW)
724 cblas_ccopy(h->N/2+1, inputFD, 1, h->bwd_bufferFD, 1);
725 fftwf_execute(h->p_bwd);
726 cblas_scopy(h->N, h->bwd_bufferTD, 1, outputTD, 1);
727 cblas_sscal(h->N, h->Scale, outputTD, 1);
728#elif defined(SAF_USE_INTEL_IPP)
729 if(h->useIPPfft_FLAG)
730 ippsFFTInv_CCSToR_32f((Ipp32f*)inputFD, (Ipp32f*)outputTD, h->hFFTspec, h->buffer);
731 else
732 ippsDFTInv_CCSToR_32f((Ipp32f*)inputFD, (Ipp32f*)outputTD, h->hDFTspec, h->buffer);
733#elif defined(SAF_USE_APPLE_ACCELERATE)
734 if(!h->useKissFFT_FLAG){
735# ifdef SAF_USE_INTERLEAVED_VDSP
736 saf_print_error("Not implemented yet");
737# else
738 h->VDSP_split_tmp.realp[0] = crealf(inputFD[0]);
739 h->VDSP_split_tmp.imagp[0] = crealf(inputFD[h->N/2]);
740 cblas_scopy(h->N/2-1, &((float*)(inputFD))[2], 2, &h->VDSP_split_tmp.realp[1], 1);
741 cblas_scopy(h->N/2-1, &((float*)(inputFD))[3], 2, &h->VDSP_split_tmp.imagp[1], 1);
742 vDSP_DFT_Execute(h->DFT_bwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
743 vDSP_ztoc(&(h->VDSP_split), 1, (DSPComplex*)outputTD, 2, (h->N)/2);
744 vDSP_vsmul(outputTD, 1, &(h->Scale), outputTD, 1, h->N);
745# endif
746 }
747#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
748 h->Status = DftiComputeBackward(h->MKL_FFT_Handle, inputFD, outputTD);
749#endif
750 if(h->useKissFFT_FLAG){
751 kiss_fftri(h->kissFFThandle_bkw, (kiss_fft_cpx*)inputFD, outputTD);
752 cblas_sscal(h->N, 1.0f/(float)(h->N), outputTD, 1);
753 }
754}
755
756
757/* ========================================================================== */
758/* Complex<->Complex FFT */
759/* ========================================================================== */
760
762(
763 void ** const phFFT,
764 int N
765)
766{
767 *phFFT = malloc1d(sizeof(saf_fft_data));
768 saf_fft_data *h = (saf_fft_data*)(*phFFT);
769
770 h->N = N;
771 h->Scale = 1.0f/(float)N; /* output scaling after ifft */
772 saf_assert(N>=2, "Only even (non zero) FFT sizes are supported");
773 h->useKissFFT_FLAG = 0;
774#if defined(SAF_USE_FFTW)
775 h->fwd_bufferTD = malloc1d(h->N*sizeof(fftwf_complex));
776 h->bwd_bufferTD = malloc1d(h->N*sizeof(fftwf_complex));
777 h->fwd_bufferFD = malloc1d(h->N*sizeof(fftwf_complex));
778 h->bwd_bufferFD = malloc1d(h->N*sizeof(fftwf_complex));
779 h->p_fwd = fftwf_plan_dft_1d(h->N, h->fwd_bufferTD, h->fwd_bufferFD, FFTW_FORWARD, FFTW_ESTIMATE);
780 h->p_bwd = fftwf_plan_dft_1d(h->N, h->bwd_bufferFD, h->bwd_bufferTD, FFTW_BACKWARD, FFTW_ESTIMATE);
781#elif defined(SAF_USE_INTEL_IPP)
782 /* Use ippsFFT if N is 2^x, otherwise, use ippsDFT */
783 if((int)(log2f((float)N) + 1.0f) == (int)(log2f((float)N))){
784 h->useIPPfft_FLAG = 1;
785 h->log2n = (int)(log2f((float)N)+0.1f);
786 ippsFFTGetSize_C_32fc(h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
787 h->hFFTspec = NULL;
788 h->memSpec = (Ipp8u*)ippMalloc(h->specSize);
789 h->buffer = (Ipp8u*)ippMalloc(h->bufferSize);
790 h->memInit = (Ipp8u*)ippMalloc(h->specBufferSize);
791 ippsFFTInit_C_32fc(&(h->hFFTspec), h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->memSpec, h->memInit);
792 }
793 else{
794 h->useIPPfft_FLAG = 0;
795 ippsDFTGetSize_C_32fc(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
796 h->hDFTspec = (IppsDFTSpec_C_32fc*)ippMalloc(h->specSize);
797 h->buffer = (Ipp8u*)ippMalloc(h->bufferSize);
798 h->memInit = (Ipp8u*)ippMalloc(h->specBufferSize);
799 ippsDFTInit_C_32fc(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->hDFTspec, h->memInit);
800 }
801 if (h->memInit)
802 ippFree(h->memInit);
803#elif defined(SAF_USE_APPLE_ACCELERATE)
804# ifdef SAF_USE_INTERLEAVED_VDSP
805 h->DFT_fwd = vDSP_DFT_Interleaved_CreateSetup(0, N, vDSP_DFT_FORWARD, vDSP_DFT_Interleaved_RealtoComplex);
806 h->DFT_bwd = vDSP_DFT_Interleaved_CreateSetup(0, N, vDSP_DFT_INVERSE, vDSP_DFT_Interleaved_RealtoComplex);
807# else
808 h->DFT_fwd = vDSP_DFT_zop_CreateSetup(0, N, vDSP_DFT_FORWARD);
809 h->DFT_bwd = vDSP_DFT_zop_CreateSetup(0, N, vDSP_DFT_INVERSE);
810# endif
811 if(h->DFT_fwd==0 || h->DFT_bwd==0) /* specified N not supported by vDSP, so must use the default */
812 h->useKissFFT_FLAG = 1;
813 else{
814 /* Note that DFT lengths must satisfy: f * 2.^g, where f is 1, 3, 5, or 15, and g >=3 */
815 saf_assert(h->DFT_fwd!=0 && h->DFT_bwd!=0, "Failed to create vDSP DFT");
816# ifndef SAF_USE_INTERLEAVED_VDSP
817 h->VDSP_split_tmp.realp = malloc1d((h->N)*sizeof(float));
818 h->VDSP_split_tmp.imagp = malloc1d((h->N)*sizeof(float));
819 h->VDSP_split.realp = malloc1d((h->N)*sizeof(float));
820 h->VDSP_split.imagp = malloc1d((h->N)*sizeof(float));
821# endif
822 }
823#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
824 h->MKL_FFT_Handle = 0;
825 h->Status = DftiCreateDescriptor( &(h->MKL_FFT_Handle), DFTI_SINGLE,
826 DFTI_COMPLEX, 1, h->N); /* 1-D, single precision, complex_input_td->fft->complex_input_fd->ifft->complex_output_td */
827 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); /* Not inplace, i.e. output has its own dedicated memory */
828 /* Configuration parameters for backward-FFT */
829 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_BACKWARD_SCALE, h->Scale); /* scalar applied after ifft */
830 /* commit these chosen parameters */
831 h->Status = DftiCommitDescriptor(h->MKL_FFT_Handle);
832#else
833 /* Must use default FFT: */
834 h->useKissFFT_FLAG = 1;
835#endif
836 /* DEFAULT: */
837 if(h->useKissFFT_FLAG){
838 h->kissFFThandle_fwd = kiss_fft_alloc(h->N, 0, NULL, NULL);
839 h->kissFFThandle_bkw = kiss_fft_alloc(h->N, 1, NULL, NULL);
840 }
841}
842
844(
845 void ** const phFFT
846)
847{
848 saf_fft_data *h = (saf_fft_data*)(*phFFT);
849
850 if(h!=NULL){
851#if defined(SAF_USE_FFTW)
852 free(h->fwd_bufferTD);
853 free(h->bwd_bufferTD);
854 free(h->fwd_bufferFD);
855 free(h->bwd_bufferFD);
856 fftwf_destroy_plan(h->p_bwd);
857 fftwf_destroy_plan(h->p_fwd);
858#elif defined(SAF_USE_INTEL_IPP)
859 if(h->useIPPfft_FLAG){
860 if(h->memSpec)
861 ippFree(h->memSpec);
862 }
863 else {
864 if(h->hDFTspec)
865 ippFree(h->hDFTspec);
866 }
867 if (h->buffer)
868 ippFree(h->buffer);
869#elif defined(SAF_USE_APPLE_ACCELERATE)
870 if(!h->useKissFFT_FLAG){
871# ifdef SAF_USE_INTERLEAVED_VDSP
872 vDSP_DFT_Interleaved_DestroySetup(h->DFT_fwd);
873 vDSP_DFT_Interleaved_DestroySetup(h->DFT_bwd);
874# else
875 vDSP_DFT_DestroySetup(h->DFT_fwd);
876 vDSP_DFT_DestroySetup(h->DFT_bwd);
877 free(h->VDSP_split_tmp.realp);
878 free(h->VDSP_split_tmp.imagp);
879 free(h->VDSP_split.realp);
880 free(h->VDSP_split.imagp);
881# endif
882 }
883#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
884 h->Status = DftiFreeDescriptor(&(h->MKL_FFT_Handle));
885#endif
886 if(h->useKissFFT_FLAG){
887 kiss_fft_free(h->kissFFThandle_fwd);
888 kiss_fft_free(h->kissFFThandle_bkw);
889 }
890
891 free(h);
892 h = NULL;
893 *phFFT = NULL;
894 }
895}
896
898(
899 void * const hFFT,
900 float_complex* inputTD,
901 float_complex* outputFD
902)
903{
904 saf_fft_data *h = (saf_fft_data*)(hFFT);
905
906#if defined(SAF_USE_FFTW)
907 cblas_ccopy(h->N, inputTD, 1, h->fwd_bufferTD, 1);
908 fftwf_execute(h->p_fwd);
909 cblas_ccopy(h->N, h->fwd_bufferFD, 1, outputFD, 1);
910#elif defined(SAF_USE_INTEL_IPP)
911 if(h->useIPPfft_FLAG)
912 ippsFFTFwd_CToC_32fc((Ipp32fc*)inputTD, (Ipp32fc*)outputFD, h->hFFTspec, h->buffer);
913 else
914 ippsDFTFwd_CToC_32fc((Ipp32fc*)inputTD, (Ipp32fc*)outputFD, h->hDFTspec, h->buffer);
915#elif defined(SAF_USE_APPLE_ACCELERATE)
916 if(!h->useKissFFT_FLAG){
917# ifdef SAF_USE_INTERLEAVED_VDSP
918 saf_print_error("Not implemented yet");
919# else
920 cblas_scopy(h->N, &((float*)(inputTD))[0], 2, h->VDSP_split_tmp.realp, 1);
921 cblas_scopy(h->N, &((float*)(inputTD))[1], 2, h->VDSP_split_tmp.imagp, 1);
922 vDSP_DFT_Execute(h->DFT_fwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
923 cblas_scopy(h->N, h->VDSP_split.realp, 1, &((float*)(outputFD))[0], 2);
924 cblas_scopy(h->N, h->VDSP_split.imagp, 1, &((float*)(outputFD))[1], 2);
925# endif
926 }
927#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
928 h->Status = DftiComputeForward(h->MKL_FFT_Handle, inputTD, outputFD);
929#endif
930 if(h->useKissFFT_FLAG)
931 kiss_fft(h->kissFFThandle_fwd, (kiss_fft_cpx*)inputTD, (kiss_fft_cpx*)outputFD);
932}
933
935(
936 void * const hFFT,
937 float_complex* inputFD,
938 float_complex* outputTD
939)
940{
941 saf_fft_data *h = (saf_fft_data*)(hFFT);
942
943#if defined(SAF_USE_FFTW)
944 cblas_ccopy(h->N, inputFD, 1, h->bwd_bufferFD, 1);
945 fftwf_execute(h->p_bwd);
946 cblas_ccopy(h->N, h->bwd_bufferTD, 1, outputTD, 1);
947 cblas_sscal(/*re+im*/2 * h->N, h->Scale, (float*)outputTD, 1);
948#elif defined(SAF_USE_INTEL_IPP)
949 if(h->useIPPfft_FLAG)
950 ippsFFTInv_CToC_32fc((Ipp32fc*)inputFD, (Ipp32fc*)outputTD, h->hFFTspec, h->buffer);
951 else
952 ippsDFTInv_CToC_32fc((Ipp32fc*)inputFD, (Ipp32fc*)outputTD, h->hDFTspec, h->buffer);
953#elif defined(SAF_USE_APPLE_ACCELERATE)
954 if(!h->useKissFFT_FLAG){
955# ifdef SAF_USE_INTERLEAVED_VDSP
956 saf_print_error("Not implemented yet");
957# else
958 cblas_scopy(h->N, &((float*)(inputFD))[0], 2, h->VDSP_split_tmp.realp, 1);
959 cblas_scopy(h->N, &((float*)(inputFD))[1], 2, h->VDSP_split_tmp.imagp, 1);
960 vDSP_DFT_Execute(h->DFT_bwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
961 cblas_scopy(h->N, h->VDSP_split.realp, 1, &((float*)(outputTD))[0], 2);
962 cblas_scopy(h->N, h->VDSP_split.imagp, 1, &((float*)(outputTD))[1], 2);
963 cblas_sscal(/*re+im*/2*(h->N), 1.0f/(float)(h->N), (float*)outputTD, 1);
964# endif
965 }
966#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
967 h->Status = DftiComputeBackward(h->MKL_FFT_Handle, inputFD, outputTD);
968#endif
969 if(h->useKissFFT_FLAG){
970 kiss_fft(h->kissFFThandle_bkw, (kiss_fft_cpx*)inputFD, (kiss_fft_cpx*)outputTD);
971 cblas_sscal(/*re+im*/2*(h->N), 1.0f/(float)(h->N), (float*)outputTD, 1);
972 }
973}
#define saf_print_error(message)
Macro to print a error message along with the filename and line number.
void fftfilt(float *x, float *h, int x_len, int h_len, int nCH, float *y)
FFT-based convolution for FIR filters.
void saf_stft_backward(void *const hSTFT, float_complex ***dataFD, int framesize, float **dataTD)
Performs the backward-STFT operation for the current frame.
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
void saf_stft_forward(void *const hSTFT, float **dataTD, int framesize, float_complex ***dataFD)
Performs the forward-STFT operation for the current frame.
void utility_cvvmul(const float_complex *a, const float_complex *b, const int len, float_complex *c)
Single-precision, complex, element-wise vector-vector multiplication i.e.
void utility_svvmul(const float *a, const float *b, const int len, float *c)
Single-precision, element-wise vector-vector multiplication i.e.
void fftconv(float *x, float *h, int x_len, int h_len, int nCH, float *y)
FFT-based convolution of signal 'x' with filter 'h'.
SAF_STFT_FDDATA_FORMAT
Options for how the frequency domain data is permuted when using saf_stft.
void saf_fft_backward(void *const hFFT, float_complex *inputFD, float_complex *outputTD)
Performs the backward-FFT operation; use for complex to complex transformations.
void saf_fft_create(void **const phFFT, int N)
Creates an instance of saf_fft; complex<->complex FFT.
void saf_stft_channelChange(void *const hSTFT, int new_nCHin, int new_nCHout)
Changes the number of input/output channels.
void hilbert(float_complex *x, int x_len, float_complex *y)
Computes the discrete-time analytic signal via the Hilbert transform [1].
void saf_rfft_create(void **const phFFT, int N)
Creates an instance of saf_rfft; real<->half-complex (conjugate-symmetric) FFT.
void getWindowingFunction(WINDOWING_FUNCTION_TYPES type, int winlength, float *win)
Computes the weights of a specific windowing function.
void saf_fft_forward(void *const hFFT, float_complex *inputTD, float_complex *outputFD)
Performs the forward-FFT operation; use for complex to complex transformations.
void saf_rfft_forward(void *const hFFT, float *inputTD, float_complex *outputFD)
Performs the forward-FFT operation; use for real to complex (conjugate symmetric) transformations.
void getUniformFreqVector(int fftSize, float fs, float *freqVector)
Calculates the frequencies (in Hz) of uniformly spaced bins, for a given FFT size and sampling rate.
void saf_rfft_backward(void *const hFFT, float_complex *inputFD, float *outputTD)
Performs the backward-FFT operation; use for complex (conjugate symmetric) to real transformations.
void saf_rfft_destroy(void **const phFFT)
Destroys an instance of saf_rfft.
void saf_stft_destroy(void **const phSTFT)
Destroys an instance of saf_stft.
#define ISEVEN(n)
Returns 1 if "n" is even valued, and 0 if it is not.
int nextpow2(int numsamp)
A simple function which returns the next power of 2.
void saf_stft_flushBuffers(void *const hSTFT)
Flushes the internal buffers with zeros.
void saf_fft_destroy(void **const phFFT)
Destroys an instance of saf_fft.
void saf_stft_create(void **const phSTFT, int winsize, int hopsize, int nCHin, int nCHout, SAF_STFT_FDDATA_FORMAT FDformat)
Creates an instance of saf_stft.
@ WINDOWING_FUNCTION_HANN
Hann.
@ SAF_STFT_TIME_CH_BANDS
nTimeHops x nChannels x nBands
@ SAF_STFT_BANDS_CH_TIME
nBands x nChannels x nTimeHops
void kiss_fft(kiss_fft_cfg cfg, const kiss_fft_cpx *fin, kiss_fft_cpx *fout)
kiss_fft(cfg,in_out_buf)
Definition kiss_fft.c:386
kiss_fft_cfg kiss_fft_alloc(int nfft, int inverse_fft, void *mem, size_t *lenmem)
kiss_fft_alloc
Definition kiss_fft.c:340
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void * calloc1d(size_t dim1, size_t data_size)
1-D calloc (same as calloc, but with error checking)
Definition md_malloc.c:69
void *** realloc3d_r(void ***ptr, size_t new_dim1, size_t new_dim2, size_t new_dim3, size_t prev_dim1, size_t prev_dim2, size_t prev_dim3, size_t data_size)
3-D realloc which does retain previous data order
Definition md_malloc.c:207
void ** realloc2d_r(void **ptr, size_t new_dim1, size_t new_dim2, size_t prev_dim1, size_t prev_dim2, size_t data_size)
2-D realloc which does retain previous data order
Definition md_malloc.c:127
void ** calloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:102
void *** calloc3d(size_t dim1, size_t dim2, size_t dim3, size_t data_size)
3-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:170
#define FLATTEN2D(A)
Use this macro when passing a 2-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:65
#define FLATTEN3D(A)
Use this macro when passing a 3-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:72
Include header for SAF externals.
Main header for the utilities module (SAF_UTILITIES_MODULE)
Complex data type used by kissFFT.
Definition kiss_fft.h:79
Data structure for complex-complex FFT transforms.
Data structure for real-(half)complex FFT transforms.
Data structure for short-time Fourier transform.