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
37
38#include "saf_utilities.h"
39#include "saf_externals.h"
40#if defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
41# include "AvailabilityVersions.h"
42# ifdef __MAC_12_0
43# define SAF_USE_INTERLEAVED_VDSP
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_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
81# ifdef SAF_USE_INTERLEAVED_VDSP
82 vDSP_DFT_Interleaved_Setup DFT_fwd;
83 vDSP_DFT_Interleaved_Setup DFT_bwd;
84 float* tempBuffer;
85# else
86 vDSP_DFT_Setup DFT_fwd;
87 vDSP_DFT_Setup DFT_bwd;
88 DSPSplitComplex VDSP_split;
89 DSPSplitComplex VDSP_split_tmp;
90# endif
91#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
92 DFTI_DESCRIPTOR_HANDLE MKL_FFT_Handle;
93 MKL_LONG input_strides[2], output_strides[2], Status;
94#endif
95 /* DEFAULT: */
96 kiss_fftr_cfg kissFFThandle_fwd;
97 kiss_fftr_cfg kissFFThandle_bkw;
98
100
102typedef struct _saf_fft_data {
103 int N;
104 float Scale;
105 int useKissFFT_FLAG;
106#if defined(SAF_USE_FFTW)
107 fftwf_plan p_fwd;
108 fftwf_plan p_bwd;
109 fftwf_complex* fwd_bufferTD;
110 fftwf_complex* bwd_bufferTD;
111 fftwf_complex* fwd_bufferFD;
112 fftwf_complex* bwd_bufferFD;
113#elif defined(SAF_USE_INTEL_IPP)
114 int useIPPfft_FLAG;
115 int specSize, specBufferSize, bufferSize, log2n;
116 IppsDFTSpec_C_32fc* hDFTspec;
117 IppsFFTSpec_C_32fc* hFFTspec;
118 Ipp8u* memSpec;
119 Ipp8u* buffer;
120 Ipp8u* memInit;
121#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
122# ifdef SAF_USE_INTERLEAVED_VDSP
123 vDSP_DFT_Interleaved_Setup DFT_fwd;
124 vDSP_DFT_Interleaved_Setup DFT_bwd;
125# else
126 vDSP_DFT_Setup DFT_fwd;
127 vDSP_DFT_Setup DFT_bwd;
128 DSPSplitComplex VDSP_split;
129 DSPSplitComplex VDSP_split_tmp;
130# endif
131#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
132 DFTI_DESCRIPTOR_HANDLE MKL_FFT_Handle;
133 MKL_LONG Status;
134#endif
135 /* DEFAULT: */
136 kiss_fft_cfg kissFFThandle_fwd;
137 kiss_fft_cfg kissFFThandle_bkw;
138
140
141
142/* ========================================================================== */
143/* Misc. Functions */
144/* ========================================================================== */
145
147(
148 int fftSize,
149 float fs,
150 float* freqVector
151)
152{
153 int k;
154 for(k=0; k<fftSize/2+1; k++)
155 freqVector[k] = (float)k * fs/(float)fftSize;
156}
157
159(
160 float* x,
161 float* h,
162 int x_len,
163 int h_len,
164 int nCH,
165 float* y
166)
167{
168 int i, y_len, fftSize, nBins;
169 float* h0, *x0, *y0;
170 float_complex* H, *X, *Y;
171 void* hfft;
172
173 /* prep */
174 y_len = x_len + h_len - 1;
175 fftSize = (int)((float)nextpow2(y_len)+0.5f);
176 nBins = fftSize/2+1;
177 h0 = calloc1d(fftSize, sizeof(float));
178 x0 = calloc1d(fftSize, sizeof(float));
179 y0 = malloc1d(fftSize * sizeof(float));
180 H = malloc1d(nBins*sizeof(float_complex));
181 X = malloc1d(nBins*sizeof(float_complex));
182 Y = malloc1d(nBins*sizeof(float_complex));
183 saf_rfft_create(&hfft, fftSize);
184
185 /* apply convolution per channel */
186 for(i=0; i<nCH; i++){
187 /* zero pad to avoid circular convolution artefacts, prior to fft */
188 memcpy(h0, &h[i*h_len], h_len*sizeof(float));
189 memcpy(x0, &x[i*x_len], x_len*sizeof(float));
190 saf_rfft_forward(hfft, x0, X);
191 saf_rfft_forward(hfft, h0, H);
192
193 /* multiply the two spectra */
194 utility_cvvmul(X, H, nBins, Y);
195
196 /* ifft, truncate and store to output */
197 saf_rfft_backward(hfft, Y, y0);
198 memcpy(&y[i*y_len], y0, y_len*sizeof(float));
199 }
200
201 /* tidy up */
202 saf_rfft_destroy(&hfft);
203 free(h0);
204 free(x0);
205 free(y0);
206 free(H);
207 free(X);
208 free(Y);
209}
210
212(
213 float* x,
214 float* h,
215 int x_len,
216 int h_len,
217 int nCH,
218 float* y
219)
220{
221 int i;
222 float* y_tmp;
223
224 y_tmp = malloc1d(nCH*(x_len+h_len-1)*sizeof(float));
225 fftconv(x, h, x_len, h_len, nCH, y_tmp);
226 for(i=0; i<nCH; i++)
227 memcpy(&y[i*x_len], &y_tmp[i*(x_len+h_len-1)], x_len*sizeof(float));
228 free(y_tmp);
229}
230
232(
233 float_complex* x,
234 int x_len,
235 float_complex* y
236)
237{
238#if defined(SAF_USE_INTEL_IPP) && 0 /* Untested: */
239 IppsHilbertSpec* ippSpec;
240 int ippSpecSize;
241 int ippBufferSize;
242 Ipp8u* buffer;
243
244 saf_assert(!ippsHilbertGetSize_32f32fc(x_len, ippAlgHintNone, &ippSpecSize, &ippBufferSize), "IPP error!");
245 ippSpec = (IppsHilbertSpec*)ippsMalloc_8u(ippSpecSize);
246 buffer = ippsMalloc_8u(ippBufferSize);
247 saf_assert(!ippsHilbertInit_32f32fc(x_len, ippAlgHintNone, ippSpec, buffer), "IPP error!");
248 saf_assert(!ippsHilbert_32f32fc(x, (Ipp32fc*)y, ippSpec, buffer), "IPP error!");
249
250 ippsFree(ippSpec);
251 ippsFree(buffer);
252#else
253 int i;
254 float_complex *xfft, *h, *xhfft;
255 void* hfft;
256
257 saf_fft_create(&hfft, x_len);
258 xfft = malloc1d(x_len*sizeof(float_complex));
259 h = malloc1d(x_len*sizeof(float_complex));
260 xhfft = malloc1d(x_len*sizeof(float_complex));
261
262 /* Forward fft */
263 saf_fft_forward(hfft, x, xfft);
264
265 /* define vector h */
266 memset(h, 0, sizeof(float_complex)*x_len);
267 if(x_len % 2 == 0){
268 /* even */
269 h[0] = cmplxf(1.0f, 0.0f);
270 h[x_len/2] = cmplxf(1.0f, 0.0f);
271 for(i=1;i<x_len/2;i++)
272 h[i] = cmplxf(2.0f, 0.0f);
273 }
274 else{
275 saf_assert(x_len % 2 == 0, "Uneven lengths are not supported by saf_fft");
276 /* odd */
277 h[0] = cmplxf(1.0f, 0.0f);
278 for(i=1;i<(x_len+1)/2;i++)
279 h[i] = cmplxf(2.0f, 0.0f);
280 }
281
282 /* apply h, and ifft */
283 utility_cvvmul(xfft, h, x_len, xhfft);
284 saf_fft_backward(hfft, xhfft, y);
285
286 /* tidy up */
287 saf_fft_destroy(&hfft);
288 free(xfft);
289 free(h);
290 free(xhfft);
291#endif
292}
293
294/* ========================================================================== */
295/* Short-time Fourier Transform (STFT) */
296/* ========================================================================== */
297
299(
300 void ** const phSTFT,
301 int winsize,
302 int hopsize,
303 int nCHin,
304 int nCHout,
306)
307{
308 *phSTFT = malloc1d(sizeof(saf_stft_data));
309 saf_stft_data *h = (saf_stft_data*)(*phSTFT);
310
311 h->nCHin = nCHin;
312 h->nCHout = nCHout;
313 h->winsize = winsize;
314 h->hopsize = hopsize;
315 h->nBands = winsize+1;
316 h->FDformat = FDformat;
317
318 /* set-up FFT */
319 h->fftsize = 2*winsize;
320 saf_rfft_create(&(h->hFFT), h->fftsize);
321 h->insig_rect_win = calloc1d(h->fftsize, sizeof(float));
322 h->insig_win = calloc1d(h->fftsize, sizeof(float));
323
324 /* Intermediate buffers */
325 h->tmp_fft = malloc1d(h->nBands * sizeof(float_complex));
326 h->outsig_win = malloc1d(h->fftsize*sizeof(float));
327 h->nPrevHops = winsize/hopsize-1;
328 if (h->nPrevHops>0)
329 h->prev_inhops = (float***)calloc3d(h->nPrevHops, nCHin, hopsize, sizeof(float));
330 else
331 h->prev_inhops = NULL;
332
333 /* Windowing function */
334 if(winsize==hopsize)
335 h->window = NULL;
336 else{
337 h->window = malloc1d(winsize*sizeof(float));
339 }
340
341 /* Overlap-add buffer */
342 h->numOvrlpAddBlocks = winsize/hopsize;
343 h->bufferlength = h->numOvrlpAddBlocks * (h->fftsize);
344 h->overlapAddBuffer = (float**)calloc2d(nCHout, h->bufferlength, sizeof(float));
345}
346
348(
349 void ** const phSTFT
350)
351{
352 saf_stft_data *h = (saf_stft_data*)(*phSTFT);
353 if(h!=NULL){
354 saf_rfft_destroy(&(h->hFFT));
355 free(h->window);
356 free(h->overlapAddBuffer);
357 free(h->insig_rect_win);
358 free(h->insig_win);
359 free(h->tmp_fft);
360 free(h->prev_inhops);
361 free(h);
362 h=NULL;
363 *phSTFT = NULL;
364 }
365}
366
368(
369 void * const hSTFT,
370 float** dataTD,
371 int framesize,
372 float_complex*** dataFD
373
374)
375{
376 saf_stft_data *h = (saf_stft_data*)(hSTFT);
377 int ch, j, nHops, t, band, idx, hIdx;
378
379 saf_assert(framesize % h->hopsize == 0, "framesize must be multiple of hopsize");
380 nHops = framesize/h->hopsize;
381
382 /* For linear time-invariant (LTI) operation (i.e. no previous hops are
383 * required) */
384 if(h->winsize==h->hopsize){
385 for (t = 0; t<nHops; t++){
386 for(ch=0; ch < h->nCHin; ch++){
387 /* Window input signal (Rectangular) */
388 memcpy(h->insig_rect_win, &dataTD[ch][t*(h->hopsize)], h->winsize*sizeof(float));
389
390 /* Apply FFT and copy data to output dataFD buffer */
391 switch(h->FDformat){
393 saf_rfft_forward(h->hFFT, h->insig_rect_win, dataFD[t][ch]);
394 break;
395
397 saf_rfft_forward(h->hFFT, h->insig_rect_win, h->tmp_fft);
398 for(band=0; band<h->nBands; band++)
399 dataFD[band][ch][t] = h->tmp_fft[band];
400 break;
401 }
402 }
403 }
404 }
405 /* For oversampled TF transforms */
406 else{
407 idx = 0;
408 for (t = 0; t<nHops; t++){
409 for(ch=0; ch < h->nCHin; ch++){
410 hIdx = 0;
411 /* Window input signal */
412 while (hIdx < h->winsize){
413 memcpy(&(h->insig_rect_win[hIdx]), h->prev_inhops[0][ch], h->hopsize*sizeof(float));
414 for(j=0; j< h->nPrevHops-1; j++)
415 memcpy(h->prev_inhops[j][ch], h->prev_inhops[j+1][ch], h->hopsize*sizeof(float));
416 memcpy(h->prev_inhops[h->nPrevHops-1][ch], &dataTD[ch][idx], h->hopsize*sizeof(float));
417 hIdx += h->hopsize;
418 }
419 utility_svvmul(h->insig_rect_win, h->window, h->winsize, h->insig_win);
420
421 /* Apply FFT and copy data to output dataFD buffer */
422 switch(h->FDformat){
424 saf_rfft_forward(h->hFFT, h->insig_win, dataFD[t][ch]);
425 break;
426
428 saf_rfft_forward(h->hFFT, h->insig_win, h->tmp_fft);
429 for(band=0; band<h->nBands; band++)
430 dataFD[band][ch][t] = h->tmp_fft[band];
431 break;
432 }
433 }
434 idx += h->hopsize;
435 }
436 }
437}
438
440(
441 void * const hSTFT,
442 float_complex*** dataFD,
443 int framesize,
444 float** dataTD
445)
446{
447 saf_stft_data *h = (saf_stft_data*)(hSTFT);
448 int t, ch, nHops, band;
449
450 saf_assert(framesize % h->hopsize == 0, "framesize must be multiple of hopsize");
451 nHops = framesize/h->hopsize;
452
453 for (t = 0; t<nHops; t++){
454 for(ch=0; ch < h->nCHout; ch++){
455 /* Shift data down */
456 memcpy(h->overlapAddBuffer[ch], h->overlapAddBuffer[ch] + h->hopsize, (h->numOvrlpAddBlocks-1)*(h->hopsize)*sizeof(float));
457
458 /* Append with zeros */
459 memset(h->overlapAddBuffer[ch] + (h->numOvrlpAddBlocks-1)*(h->hopsize), 0, h->hopsize*sizeof(float));
460
461 /* Apply inverse FFT */
462 switch(h->FDformat){
464 saf_rfft_backward(h->hFFT, dataFD[t][ch], h->outsig_win);
465 break;
467 for(band=0; band<h->nBands; band++)
468 h->tmp_fft[band] = dataFD[band][ch][t];
469 saf_rfft_backward(h->hFFT, h->tmp_fft, h->outsig_win);
470 break;
471 }
472
473 /* Overlap-Add 1:hopsize to output buffer */
474 cblas_saxpy(h->fftsize, 1.0f, h->outsig_win, 1, h->overlapAddBuffer[ch], 1);
475 memcpy(dataTD[ch] + t*(h->hopsize), h->overlapAddBuffer[ch], h->hopsize*sizeof(float));
476 }
477 }
478}
479
481(
482 void * const hSTFT
483)
484{
485 saf_stft_data *h = (saf_stft_data*)(hSTFT);
486 if(h->nPrevHops > 0)
487 memset(FLATTEN3D(h->prev_inhops), 0, h->nPrevHops * (h->nCHin) * (h->hopsize) * sizeof(float));
488 memset(FLATTEN2D(h->overlapAddBuffer), 0, h->nCHout * (h->bufferlength) * sizeof(float));
489}
490
492(
493 void * const hSTFT,
494 int new_nCHin,
495 int new_nCHout
496)
497{
498 saf_stft_data *h = (saf_stft_data*)(hSTFT);
499 int i, ch;
500
501 if(new_nCHin != h->nCHin && h->nPrevHops > 0){
502 /* Reallocate memory while retaining previous values (which will be
503 * truncated if new_nCHin < nCHin) */
504 h->prev_inhops = (float***)realloc3d_r((void***)h->prev_inhops, h->nPrevHops, new_nCHin, h->hopsize,
505 h->nPrevHops, h->nCHin, h->hopsize, sizeof(float));
506 /* Zero new channels if new_nCHin > nCHin */
507 for(i=0; i< h->nPrevHops; i++)
508 for(ch=h->nCHin; ch<new_nCHin; ch++)
509 memset(h->prev_inhops[i][ch], 0, h->hopsize * sizeof(float));
510
511 h->nCHin = new_nCHin;
512 }
513
514 if(new_nCHout != h->nCHout){
515 /* Reallocate memory while retaining previous values (which will be
516 * truncated if new_nCHout < nCHout) */
517 h->overlapAddBuffer = (float**)realloc2d_r((void**)h->overlapAddBuffer, new_nCHout, h->bufferlength,
518 h->nCHout, h->bufferlength, sizeof(float));
519 /* Zero new channels if new_nCHout > nCHout */
520 for(ch=h->nCHout; ch<new_nCHout; ch++)
521 memset(h->overlapAddBuffer[ch], 0, h->bufferlength * sizeof(float));
522
523 h->nCHout = new_nCHout;
524 }
525}
526
527
528/* ========================================================================== */
529/* Real<->Half-Complex (Conjugate-Symmetric) FFT */
530/* ========================================================================== */
531
533(
534 void ** const phFFT,
535 int N
536)
537{
538 *phFFT = malloc1d(sizeof(saf_rfft_data));
539 saf_rfft_data *h = (saf_rfft_data*)(*phFFT);
540
541 h->N = N;
542 h->Scale = 1.0f/(float)N; /* output scaling after ifft */
543 saf_assert(N>=2 && ISEVEN(N), "Only even (non zero) FFT sizes are supported");
544 h->useKissFFT_FLAG = 0;
545#if defined(SAF_USE_FFTW)
546 h->fwd_bufferTD = malloc1d(h->N*sizeof(float));
547 h->bwd_bufferTD = malloc1d(h->N*sizeof(float));
548 h->fwd_bufferFD = malloc1d((h->N/2+1)*sizeof(fftwf_complex));
549 h->bwd_bufferFD = malloc1d((h->N/2+1)*sizeof(fftwf_complex));
550 h->p_fwd = fftwf_plan_dft_r2c_1d(h->N, h->fwd_bufferTD, h->fwd_bufferFD, FFTW_ESTIMATE);
551 h->p_bwd = fftwf_plan_dft_c2r_1d(h->N, h->bwd_bufferFD, h->bwd_bufferTD, FFTW_ESTIMATE);
552#elif defined(SAF_USE_INTEL_IPP)
553 /* Use ippsFFT if N is 2^x, otherwise, use ippsDFT */
554 if((int)(log2f((float)N)+1.0f) == (int)(log2f((float)N))){
555 h->useIPPfft_FLAG = 1;
556 h->log2n = (int)(log2f((float)N)+0.1f);
557 ippsFFTGetSize_R_32f(h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
558 h->hFFTspec = NULL;
559 h->memSpec = (Ipp8u*) ippMalloc(h->specSize);
560 h->buffer = (Ipp8u*) ippMalloc(h->bufferSize);
561 h->memInit = (Ipp8u*) ippMalloc(h->specBufferSize);
562 ippsFFTInit_R_32f(&(h->hFFTspec), h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->memSpec, h->memInit);
563 }
564 else{
565 h->useIPPfft_FLAG = 0;
566 ippsDFTGetSize_R_32f(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
567 h->hDFTspec = (IppsDFTSpec_R_32f*) ippMalloc(h->specSize);
568 h->buffer = (Ipp8u*) ippMalloc(h->bufferSize);
569 h->memInit = (Ipp8u*) ippMalloc(h->specBufferSize);
570 ippsDFTInit_R_32f(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->hDFTspec, h->memInit);
571 }
572 if (h->memInit)
573 ippFree(h->memInit);
574#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
575# ifdef SAF_USE_INTERLEAVED_VDSP
576 h->DFT_fwd = vDSP_DFT_Interleaved_CreateSetup(0, N/2, vDSP_DFT_FORWARD, vDSP_DFT_Interleaved_RealtoComplex);
577 h->DFT_bwd = vDSP_DFT_Interleaved_CreateSetup(0, N/2, vDSP_DFT_INVERSE, vDSP_DFT_Interleaved_RealtoComplex);
578# else
579 h->DFT_fwd = vDSP_DFT_zrop_CreateSetup(0, N, vDSP_DFT_FORWARD);
580 h->DFT_bwd = vDSP_DFT_zrop_CreateSetup(0, N, vDSP_DFT_INVERSE);
581# endif
582 if(h->DFT_fwd==0 || h->DFT_bwd==0) /* specified N not supported by vDSP, so must use the default */
583 h->useKissFFT_FLAG = 1;
584 else{
585 /* Note that DFT lengths must satisfy: f * 2.^g, where f is 1, 3, 5, or 15, and g >=4 */
586 saf_assert(h->DFT_fwd!=0 && h->DFT_bwd!=0, "Failed to create vDSP DFT");
587# ifdef SAF_USE_INTERLEAVED_VDSP
588 h->tempBuffer = malloc1d(2*(h->N/2+1)*sizeof(float));
589# else
590 h->VDSP_split_tmp.realp = malloc1d((h->N/2)*sizeof(float));
591 h->VDSP_split_tmp.imagp = malloc1d((h->N/2)*sizeof(float));
592 h->VDSP_split.realp = malloc1d((h->N/2)*sizeof(float));
593 h->VDSP_split.imagp = malloc1d((h->N/2)*sizeof(float));
594# endif
595 }
596#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
597 h->MKL_FFT_Handle = 0;
598 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 */
599 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); /* Not inplace, i.e. output has its own dedicated memory */
600 /* specify output format as complex conjugate-symmetric data. This is the same as MatLab, except only the
601 * first N/2+1 elements are returned. The inverse transform will automatically symmetrically+conjugate
602 * replicate these elements, in order to get the required N elements internally. */
603 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX);
604 /* Configuration parameters for backward-FFT */
605 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_BACKWARD_SCALE, h->Scale); /* scalar applied after ifft */
606 /* commit these chosen parameters */
607 h->Status = DftiCommitDescriptor(h->MKL_FFT_Handle);
608#else
609 /* Must use default FFT: */
610 h->useKissFFT_FLAG = 1;
611#endif
612 /* DEFAULT: */
613 if(h->useKissFFT_FLAG){
614 h->kissFFThandle_fwd = kiss_fftr_alloc(h->N, 0, NULL, NULL);
615 h->kissFFThandle_bkw = kiss_fftr_alloc(h->N, 1, NULL, NULL);
616 }
617}
618
620(
621 void ** const phFFT
622)
623{
624 saf_rfft_data *h = (saf_rfft_data*)(*phFFT);
625 if(h!=NULL){
626#if defined(SAF_USE_FFTW)
627 free(h->fwd_bufferTD);
628 free(h->bwd_bufferTD);
629 free(h->fwd_bufferFD);
630 free(h->bwd_bufferFD);
631 fftwf_destroy_plan(h->p_bwd);
632 fftwf_destroy_plan(h->p_fwd);
633#elif defined(SAF_USE_INTEL_IPP)
634 if(h->useIPPfft_FLAG){
635 if(h->memSpec)
636 ippFree(h->memSpec);
637 }
638 else {
639 if(h->hDFTspec)
640 ippFree(h->hDFTspec);
641 }
642 if(h->buffer)
643 ippFree(h->buffer);
644#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
645 if(!h->useKissFFT_FLAG){
646# ifdef SAF_USE_INTERLEAVED_VDSP
647 vDSP_DFT_Interleaved_DestroySetup(h->DFT_fwd);
648 vDSP_DFT_Interleaved_DestroySetup(h->DFT_bwd);
649 free(h->tempBuffer);
650# else
651 vDSP_DFT_DestroySetup(h->DFT_fwd);
652 vDSP_DFT_DestroySetup(h->DFT_bwd);
653 free(h->VDSP_split_tmp.realp);
654 free(h->VDSP_split_tmp.imagp);
655 free(h->VDSP_split.realp);
656 free(h->VDSP_split.imagp);
657# endif
658 }
659#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
660 h->Status = DftiFreeDescriptor(&(h->MKL_FFT_Handle));
661#endif
662 if(h->useKissFFT_FLAG){
663 kiss_fftr_free(h->kissFFThandle_fwd);
664 kiss_fftr_free(h->kissFFThandle_bkw);
665 }
666
667 free(h);
668 h = NULL;
669 *phFFT = NULL;
670 }
671}
672
674(
675 void * const hFFT,
676 float* inputTD,
677 float_complex* outputFD
678)
679{
680 saf_rfft_data *h = (saf_rfft_data*)(hFFT);
681
682#if defined(SAF_USE_FFTW)
683 cblas_scopy(h->N, inputTD, 1, h->fwd_bufferTD, 1);
684 fftwf_execute(h->p_fwd);
685 cblas_ccopy(h->N/2+1, h->fwd_bufferFD, 1, outputFD, 1);
686#elif defined(SAF_USE_INTEL_IPP)
687 if(h->useIPPfft_FLAG)
688 ippsFFTFwd_RToCCS_32f((Ipp32f*)inputTD, (Ipp32f*)outputFD, h->hFFTspec, h->buffer);
689 else
690 ippsDFTFwd_RToCCS_32f((Ipp32f*)inputTD, (Ipp32f*)outputFD, h->hDFTspec, h->buffer);
691#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
692 if(!h->useKissFFT_FLAG){
693# ifdef SAF_USE_INTERLEAVED_VDSP
694 vDSP_DFT_Interleaved_Execute(h->DFT_fwd, (DSPComplex*)inputTD, (DSPComplex*)outputFD);
695 outputFD[h->N/2] = cmplxf(((float*)(&outputFD[0]))[1], 0.0f);
696 outputFD[0] = cmplxf(((float*)(&outputFD[0]))[0], 0.0f);
697# else
698 vDSP_ctoz((DSPComplex*)inputTD, 2, &(h->VDSP_split_tmp), 1, (h->N)/2);
699 vDSP_DFT_Execute(h->DFT_fwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
700 /* DC */
701 outputFD[0] = cmplxf(h->VDSP_split.realp[0], 0.0f);
702 cblas_scopy(h->N/2-1, &h->VDSP_split.realp[1], 1, &((float*)(outputFD))[2], 2);
703 cblas_scopy(h->N/2-1, &h->VDSP_split.imagp[1], 1, &((float*)(outputFD))[3], 2);
704 /* the real part of the Nyquist value is the imaginary part of DC. */
705 /* https://stackoverflow.com/questions/43289265/implementing-an-fft-using-vdsp */
706 outputFD[h->N/2] = cmplxf(h->VDSP_split.imagp[0], 0.0f);
707 /* Note: the output is scaled by 2, because vDSP_fft automatically compensates for the loss of energy
708 * when removing the symmetric/conjugate (N/2+2:N) bins. However, this is dumb... so the 2x scaling
709 * is removed here; so it has parity with the other FFT implementations supported by SAF. */
710# endif
711 cblas_sscal(2*(h->N/2+1), 0.5f, (float*)outputFD, 1);
712 }
713#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
714 h->Status = DftiComputeForward(h->MKL_FFT_Handle, inputTD, outputFD);
715#endif
716 if(h->useKissFFT_FLAG)
717 kiss_fftr(h->kissFFThandle_fwd, inputTD, (kiss_fft_cpx*)outputFD);
718}
719
721(
722 void * const hFFT,
723 float_complex* inputFD,
724 float* outputTD
725)
726{
727 saf_rfft_data *h = (saf_rfft_data*)(hFFT);
728
729#if defined(SAF_USE_FFTW)
730 cblas_ccopy(h->N/2+1, inputFD, 1, h->bwd_bufferFD, 1);
731 fftwf_execute(h->p_bwd);
732 cblas_scopy(h->N, h->bwd_bufferTD, 1, outputTD, 1);
733 cblas_sscal(h->N, h->Scale, outputTD, 1);
734#elif defined(SAF_USE_INTEL_IPP)
735 if(h->useIPPfft_FLAG)
736 ippsFFTInv_CCSToR_32f((Ipp32f*)inputFD, (Ipp32f*)outputTD, h->hFFTspec, h->buffer);
737 else
738 ippsDFTInv_CCSToR_32f((Ipp32f*)inputFD, (Ipp32f*)outputTD, h->hDFTspec, h->buffer);
739#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
740 if(!h->useKissFFT_FLAG){
741# ifdef SAF_USE_INTERLEAVED_VDSP
742 memcpy(h->tempBuffer, inputFD, (h->N/2+1)*sizeof(float_complex));
743 h->tempBuffer[1/*imag*/] = crealf(inputFD[h->N/2]);
744 vDSP_DFT_Interleaved_Execute(h->DFT_bwd, (DSPComplex*)h->tempBuffer, (DSPComplex*)outputTD);
745# else
746 h->VDSP_split_tmp.realp[0] = crealf(inputFD[0]);
747 h->VDSP_split_tmp.imagp[0] = crealf(inputFD[h->N/2]);
748 cblas_scopy(h->N/2-1, &((float*)(inputFD))[2], 2, &h->VDSP_split_tmp.realp[1], 1);
749 cblas_scopy(h->N/2-1, &((float*)(inputFD))[3], 2, &h->VDSP_split_tmp.imagp[1], 1);
750 vDSP_DFT_Execute(h->DFT_bwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
751 vDSP_ztoc(&(h->VDSP_split), 1, (DSPComplex*)outputTD, 2, (h->N)/2);
752
753# endif
754 vDSP_vsmul(outputTD, 1, &(h->Scale), outputTD, 1, h->N);
755 }
756#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
757 h->Status = DftiComputeBackward(h->MKL_FFT_Handle, inputFD, outputTD);
758#endif
759 if(h->useKissFFT_FLAG){
760 kiss_fftri(h->kissFFThandle_bkw, (kiss_fft_cpx*)inputFD, outputTD);
761 cblas_sscal(h->N, 1.0f/(float)(h->N), outputTD, 1);
762 }
763}
764
765
766/* ========================================================================== */
767/* Complex<->Complex FFT */
768/* ========================================================================== */
769
771(
772 void ** const phFFT,
773 int N
774)
775{
776 *phFFT = malloc1d(sizeof(saf_fft_data));
777 saf_fft_data *h = (saf_fft_data*)(*phFFT);
778
779 h->N = N;
780 h->Scale = 1.0f/(float)N; /* output scaling after ifft */
781 saf_assert(N>=2, "Only even (non zero) FFT sizes are supported");
782 h->useKissFFT_FLAG = 0;
783#if defined(SAF_USE_FFTW)
784 h->fwd_bufferTD = malloc1d(h->N*sizeof(fftwf_complex));
785 h->bwd_bufferTD = malloc1d(h->N*sizeof(fftwf_complex));
786 h->fwd_bufferFD = malloc1d(h->N*sizeof(fftwf_complex));
787 h->bwd_bufferFD = malloc1d(h->N*sizeof(fftwf_complex));
788 h->p_fwd = fftwf_plan_dft_1d(h->N, h->fwd_bufferTD, h->fwd_bufferFD, FFTW_FORWARD, FFTW_ESTIMATE);
789 h->p_bwd = fftwf_plan_dft_1d(h->N, h->bwd_bufferFD, h->bwd_bufferTD, FFTW_BACKWARD, FFTW_ESTIMATE);
790#elif defined(SAF_USE_INTEL_IPP)
791 /* Use ippsFFT if N is 2^x, otherwise, use ippsDFT */
792 if((int)(log2f((float)N) + 1.0f) == (int)(log2f((float)N))){
793 h->useIPPfft_FLAG = 1;
794 h->log2n = (int)(log2f((float)N)+0.1f);
795 ippsFFTGetSize_C_32fc(h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
796 h->hFFTspec = NULL;
797 h->memSpec = (Ipp8u*)ippMalloc(h->specSize);
798 h->buffer = (Ipp8u*)ippMalloc(h->bufferSize);
799 h->memInit = (Ipp8u*)ippMalloc(h->specBufferSize);
800 ippsFFTInit_C_32fc(&(h->hFFTspec), h->log2n, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->memSpec, h->memInit);
801 }
802 else{
803 h->useIPPfft_FLAG = 0;
804 ippsDFTGetSize_C_32fc(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &(h->specSize), &(h->specBufferSize), &(h->bufferSize));
805 h->hDFTspec = (IppsDFTSpec_C_32fc*)ippMalloc(h->specSize);
806 h->buffer = (Ipp8u*)ippMalloc(h->bufferSize);
807 h->memInit = (Ipp8u*)ippMalloc(h->specBufferSize);
808 ippsDFTInit_C_32fc(N, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, h->hDFTspec, h->memInit);
809 }
810 if (h->memInit)
811 ippFree(h->memInit);
812#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
813# ifdef SAF_USE_INTERLEAVED_VDSP
814 h->DFT_fwd = vDSP_DFT_Interleaved_CreateSetup(0, N, vDSP_DFT_FORWARD, vDSP_DFT_Interleaved_ComplextoComplex);
815 h->DFT_bwd = vDSP_DFT_Interleaved_CreateSetup(0, N, vDSP_DFT_INVERSE, vDSP_DFT_Interleaved_ComplextoComplex);
816# else
817 h->DFT_fwd = vDSP_DFT_zop_CreateSetup(0, N, vDSP_DFT_FORWARD);
818 h->DFT_bwd = vDSP_DFT_zop_CreateSetup(0, N, vDSP_DFT_INVERSE);
819# endif
820 if(h->DFT_fwd==0 || h->DFT_bwd==0) /* specified N not supported by vDSP, so must use the default */
821 h->useKissFFT_FLAG = 1;
822 else{
823 /* Note that DFT lengths must satisfy: f * 2.^g, where f is 1, 3, 5, or 15, and g >=3 */
824 saf_assert(h->DFT_fwd!=0 && h->DFT_bwd!=0, "Failed to create vDSP DFT");
825# ifndef SAF_USE_INTERLEAVED_VDSP
826 h->VDSP_split_tmp.realp = malloc1d((h->N)*sizeof(float));
827 h->VDSP_split_tmp.imagp = malloc1d((h->N)*sizeof(float));
828 h->VDSP_split.realp = malloc1d((h->N)*sizeof(float));
829 h->VDSP_split.imagp = malloc1d((h->N)*sizeof(float));
830# endif
831 }
832#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
833 h->MKL_FFT_Handle = 0;
834 h->Status = DftiCreateDescriptor( &(h->MKL_FFT_Handle), DFTI_SINGLE,
835 DFTI_COMPLEX, 1, h->N); /* 1-D, single precision, complex_input_td->fft->complex_input_fd->ifft->complex_output_td */
836 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE); /* Not inplace, i.e. output has its own dedicated memory */
837 /* Configuration parameters for backward-FFT */
838 h->Status = DftiSetValue(h->MKL_FFT_Handle, DFTI_BACKWARD_SCALE, h->Scale); /* scalar applied after ifft */
839 /* commit these chosen parameters */
840 h->Status = DftiCommitDescriptor(h->MKL_FFT_Handle);
841#else
842 /* Must use default FFT: */
843 h->useKissFFT_FLAG = 1;
844#endif
845 /* DEFAULT: */
846 if(h->useKissFFT_FLAG){
847 h->kissFFThandle_fwd = kiss_fft_alloc(h->N, 0, NULL, NULL);
848 h->kissFFThandle_bkw = kiss_fft_alloc(h->N, 1, NULL, NULL);
849 }
850}
851
853(
854 void ** const phFFT
855)
856{
857 saf_fft_data *h = (saf_fft_data*)(*phFFT);
858
859 if(h!=NULL){
860#if defined(SAF_USE_FFTW)
861 free(h->fwd_bufferTD);
862 free(h->bwd_bufferTD);
863 free(h->fwd_bufferFD);
864 free(h->bwd_bufferFD);
865 fftwf_destroy_plan(h->p_bwd);
866 fftwf_destroy_plan(h->p_fwd);
867#elif defined(SAF_USE_INTEL_IPP)
868 if(h->useIPPfft_FLAG){
869 if(h->memSpec)
870 ippFree(h->memSpec);
871 }
872 else {
873 if(h->hDFTspec)
874 ippFree(h->hDFTspec);
875 }
876 if (h->buffer)
877 ippFree(h->buffer);
878#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
879 if(!h->useKissFFT_FLAG){
880# ifdef SAF_USE_INTERLEAVED_VDSP
881 vDSP_DFT_Interleaved_DestroySetup(h->DFT_fwd);
882 vDSP_DFT_Interleaved_DestroySetup(h->DFT_bwd);
883# else
884 vDSP_DFT_DestroySetup(h->DFT_fwd);
885 vDSP_DFT_DestroySetup(h->DFT_bwd);
886 free(h->VDSP_split_tmp.realp);
887 free(h->VDSP_split_tmp.imagp);
888 free(h->VDSP_split.realp);
889 free(h->VDSP_split.imagp);
890# endif
891 }
892#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
893 h->Status = DftiFreeDescriptor(&(h->MKL_FFT_Handle));
894#endif
895 if(h->useKissFFT_FLAG){
896 kiss_fft_free(h->kissFFThandle_fwd);
897 kiss_fft_free(h->kissFFThandle_bkw);
898 }
899
900 free(h);
901 h = NULL;
902 *phFFT = NULL;
903 }
904}
905
907(
908 void * const hFFT,
909 float_complex* inputTD,
910 float_complex* outputFD
911)
912{
913 saf_fft_data *h = (saf_fft_data*)(hFFT);
914
915#if defined(SAF_USE_FFTW)
916 cblas_ccopy(h->N, inputTD, 1, h->fwd_bufferTD, 1);
917 fftwf_execute(h->p_fwd);
918 cblas_ccopy(h->N, h->fwd_bufferFD, 1, outputFD, 1);
919#elif defined(SAF_USE_INTEL_IPP)
920 if(h->useIPPfft_FLAG)
921 ippsFFTFwd_CToC_32fc((Ipp32fc*)inputTD, (Ipp32fc*)outputFD, h->hFFTspec, h->buffer);
922 else
923 ippsDFTFwd_CToC_32fc((Ipp32fc*)inputTD, (Ipp32fc*)outputFD, h->hDFTspec, h->buffer);
924#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
925 if(!h->useKissFFT_FLAG){
926# ifdef SAF_USE_INTERLEAVED_VDSP
927 vDSP_DFT_Interleaved_Execute(h->DFT_fwd, (DSPComplex*)inputTD, (DSPComplex*)outputFD);
928# else
929 cblas_scopy(h->N, &((float*)(inputTD))[0], 2, h->VDSP_split_tmp.realp, 1);
930 cblas_scopy(h->N, &((float*)(inputTD))[1], 2, h->VDSP_split_tmp.imagp, 1);
931 vDSP_DFT_Execute(h->DFT_fwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
932 cblas_scopy(h->N, h->VDSP_split.realp, 1, &((float*)(outputFD))[0], 2);
933 cblas_scopy(h->N, h->VDSP_split.imagp, 1, &((float*)(outputFD))[1], 2);
934# endif
935 }
936#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
937 h->Status = DftiComputeForward(h->MKL_FFT_Handle, inputTD, outputFD);
938#endif
939 if(h->useKissFFT_FLAG)
940 kiss_fft(h->kissFFThandle_fwd, (kiss_fft_cpx*)inputTD, (kiss_fft_cpx*)outputFD);
941}
942
944(
945 void * const hFFT,
946 float_complex* inputFD,
947 float_complex* outputTD
948)
949{
950 saf_fft_data *h = (saf_fft_data*)(hFFT);
951
952#if defined(SAF_USE_FFTW)
953 cblas_ccopy(h->N, inputFD, 1, h->bwd_bufferFD, 1);
954 fftwf_execute(h->p_bwd);
955 cblas_ccopy(h->N, h->bwd_bufferTD, 1, outputTD, 1);
956 cblas_sscal(/*re+im*/2 * h->N, h->Scale, (float*)outputTD, 1);
957#elif defined(SAF_USE_INTEL_IPP)
958 if(h->useIPPfft_FLAG)
959 ippsFFTInv_CToC_32fc((Ipp32fc*)inputFD, (Ipp32fc*)outputTD, h->hFFTspec, h->buffer);
960 else
961 ippsDFTInv_CToC_32fc((Ipp32fc*)inputFD, (Ipp32fc*)outputTD, h->hDFTspec, h->buffer);
962#elif defined(SAF_USE_APPLE_ACCELERATE_LP64) || defined(SAF_USE_APPLE_ACCELERATE_ILP64)
963 if(!h->useKissFFT_FLAG){
964# ifdef SAF_USE_INTERLEAVED_VDSP
965 vDSP_DFT_Interleaved_Execute(h->DFT_bwd, (DSPComplex*)inputFD, (DSPComplex*)outputTD);
966# else
967 cblas_scopy(h->N, &((float*)(inputFD))[0], 2, h->VDSP_split_tmp.realp, 1);
968 cblas_scopy(h->N, &((float*)(inputFD))[1], 2, h->VDSP_split_tmp.imagp, 1);
969 vDSP_DFT_Execute(h->DFT_bwd, h->VDSP_split_tmp.realp, h->VDSP_split_tmp.imagp, h->VDSP_split.realp, h->VDSP_split.imagp);
970 cblas_scopy(h->N, h->VDSP_split.realp, 1, &((float*)(outputTD))[0], 2);
971 cblas_scopy(h->N, h->VDSP_split.imagp, 1, &((float*)(outputTD))[1], 2);
972# endif
973 cblas_sscal(/*re+im*/2*(h->N), 1.0f/(float)(h->N), (float*)outputTD, 1);
974 }
975#elif defined(SAF_USE_INTEL_MKL_LP64) || defined(SAF_USE_INTEL_MKL_ILP64)
976 h->Status = DftiComputeBackward(h->MKL_FFT_Handle, inputFD, outputTD);
977#endif
978 if(h->useKissFFT_FLAG){
979 kiss_fft(h->kissFFThandle_bkw, (kiss_fft_cpx*)inputFD, (kiss_fft_cpx*)outputTD);
980 cblas_sscal(/*re+im*/2*(h->N), 1.0f/(float)(h->N), (float*)outputTD, 1);
981 }
982}
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.