/* * Copyright (c) 2003-2010, Mark Borgerding. All rights reserved. * This file is part of KISS FFT - https://github.com/mborgerding/kissfft * * SPDX-License-Identifier: BSD-3-Clause * See COPYING file for more information. */ /* kiss_fft.h defines kiss_fft_scalar as either short or a float type and defines typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ #include "kiss_fft.h" #include #define MAXFACTORS 32 /* e.g. an fft of length 128 has 4 factors as far as kissfft is concerned 4*4*4*2 */ struct kiss_fft_state{ int nfft; int inverse; int factors[2*MAXFACTORS]; kiss_fft_cpx twiddles[1]; }; /* Explanation of macros dealing with complex math: C_MUL(m,a,b) : m = a*b C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise C_SUB( res, a,b) : res = a - b C_SUBFROM( res , a) : res -= a C_ADDTO( res , a) : res += a * */ #ifdef FIXED_POINT #include #if (FIXED_POINT==32) # define FRACBITS 31 # define SAMPPROD int64_t #define SAMP_MAX INT32_MAX #define SAMP_MIN INT32_MIN #else # define FRACBITS 15 # define SAMPPROD int32_t #define SAMP_MAX INT16_MAX #define SAMP_MIN INT16_MIN #endif #if defined(CHECK_OVERFLOW) # define CHECK_OVERFLOW_OP(a,op,b) \ if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } #endif # define smul(a,b) ( (SAMPPROD)(a)*(b) ) # define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) # define S_MUL(a,b) sround( smul(a,b) ) # define C_MUL(m,a,b) \ do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) # define DIVSCALAR(x,k) \ (x) = sround( smul( x, SAMP_MAX/k ) ) # define C_FIXDIV(c,div) \ do { DIVSCALAR( (c).r , div); \ DIVSCALAR( (c).i , div); }while (0) # define C_MULBYSCALAR( c, s ) \ do{ (c).r = sround( smul( (c).r , s ) ) ;\ (c).i = sround( smul( (c).i , s ) ) ; }while(0) #else /* not FIXED_POINT*/ # define S_MUL(a,b) ( (a)*(b) ) #define C_MUL(m,a,b) \ do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) # define C_FIXDIV(c,div) /* NOOP */ # define C_MULBYSCALAR( c, s ) \ do{ (c).r *= (s);\ (c).i *= (s); }while(0) #endif #ifndef CHECK_OVERFLOW_OP # define CHECK_OVERFLOW_OP(a,op,b) /* noop */ #endif #define C_ADD( res, a,b)\ do { \ CHECK_OVERFLOW_OP((a).r,+,(b).r)\ CHECK_OVERFLOW_OP((a).i,+,(b).i)\ (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ }while(0) #define C_SUB( res, a,b)\ do { \ CHECK_OVERFLOW_OP((a).r,-,(b).r)\ CHECK_OVERFLOW_OP((a).i,-,(b).i)\ (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ }while(0) #define C_ADDTO( res , a)\ do { \ CHECK_OVERFLOW_OP((res).r,+,(a).r)\ CHECK_OVERFLOW_OP((res).i,+,(a).i)\ (res).r += (a).r; (res).i += (a).i;\ }while(0) #define C_SUBFROM( res , a)\ do {\ CHECK_OVERFLOW_OP((res).r,-,(a).r)\ CHECK_OVERFLOW_OP((res).i,-,(a).i)\ (res).r -= (a).r; (res).i -= (a).i; \ }while(0) // Normally same as kiss_fft_scalar, but for USE_SIMD this is only a single number #ifndef kiss_fft_scalar_one #define kiss_fft_scalar_one kiss_fft_scalar #endif // If kiss_fft_suffix is not provided, determine it automatically based on kiss_fft_scalar_one #if !defined (kiss_fft_suffix) && !defined (kiss_fft_suffix_empty) #ifdef FIXED_POINT #undef kiss_fft_suffix #define kiss_fft_suffix_empty 1 #endif #define KISS_X_float_X 1 #define KISS_X__X 2 #define KISS_X_long_X 3 #define KISS_concat2(a, b, c) a##b##c #define KISS_concat(a, b, c) KISS_concat2(a, b, c) #define double // This is because otherwise KISS_concat(KISS_X_, long double, _X) would produce two tokens which would break the preprocessor comparison #if KISS_concat(KISS_X_, kiss_fft_scalar_one, _X) == KISS_X_float_X // float #define kiss_fft_suffix f #elif KISS_concat(KISS_X_, kiss_fft_scalar_one, _X) == KISS_X__X // double #undef kiss_fft_suffix #define kiss_fft_suffix_empty 1 #elif KISS_concat(KISS_X_, kiss_fft_scalar_one, _X) == KISS_X_long_X // long double #define kiss_fft_suffix l #else #undef kiss_fft_suffix #define kiss_fft_suffix_empty 1 #warning "Unknown kiss_fft_scalar type" #endif #undef double #endif #ifdef kiss_fft_suffix_empty #define KISS_ADD_SUFFIX(x) x #else #define KISS_ADD_SUFFIX2(x, y) x##y #define KISS_ADD_SUFFIX1(x, y) KISS_ADD_SUFFIX2(x, y) #define KISS_ADD_SUFFIX(x) KISS_ADD_SUFFIX1(x, kiss_fft_suffix) #endif #ifdef FIXED_POINT # define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase)) # define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase)) # define HALF_OF(x) ((x)>>1) #elif defined(USE_SIMD) # define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) # define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) # define HALF_OF(x) ((x)*_mm_set1_ps(.5)) #else # define KISS_FFT_COS(phase) (kiss_fft_scalar) KISS_ADD_SUFFIX(cos)(phase) # define KISS_FFT_SIN(phase) (kiss_fft_scalar) KISS_ADD_SUFFIX(sin)(phase) # define HALF_OF(x) ((x)*KISS_ADD_SUFFIX(.5)) #endif #define kf_cexp(x,phase) \ do{ \ (x)->r = KISS_FFT_COS(phase);\ (x)->i = KISS_FFT_SIN(phase);\ }while(0) /* a debugging function */ #define pcpx(c)\ fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) #ifdef KISS_FFT_USE_ALLOCA // define this to allow use of alloca instead of malloc for temporary buffers // Temporary buffers are used in two case: // 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5 // 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform. #include #define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes) #define KISS_FFT_TMP_FREE(ptr) #else #define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes) #define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr) #endif