153a5a1b3Sopenharmony_ci/* 253a5a1b3Sopenharmony_ciCopyright (c) 2003-2004, Mark Borgerding 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ciAll rights reserved. 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ciRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 753a5a1b3Sopenharmony_ci 853a5a1b3Sopenharmony_ci * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 953a5a1b3Sopenharmony_ci * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 1053a5a1b3Sopenharmony_ci * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ciTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1353a5a1b3Sopenharmony_ci*/ 1453a5a1b3Sopenharmony_ci 1553a5a1b3Sopenharmony_ci#define MIN(a,b) ((a)<(b) ? (a):(b)) 1653a5a1b3Sopenharmony_ci#define MAX(a,b) ((a)>(b) ? (a):(b)) 1753a5a1b3Sopenharmony_ci 1853a5a1b3Sopenharmony_ci/* kiss_fft.h 1953a5a1b3Sopenharmony_ci defines kiss_fft_scalar as either short or a float type 2053a5a1b3Sopenharmony_ci and defines 2153a5a1b3Sopenharmony_ci typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ 2253a5a1b3Sopenharmony_ci#include "kiss_fft.h" 2353a5a1b3Sopenharmony_ci#include "math_approx.h" 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#define MAXFACTORS 32 2653a5a1b3Sopenharmony_ci/* e.g. an fft of length 128 has 4 factors 2753a5a1b3Sopenharmony_ci as far as kissfft is concerned 2853a5a1b3Sopenharmony_ci 4*4*4*2 2953a5a1b3Sopenharmony_ci */ 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_cistruct kiss_fft_state{ 3253a5a1b3Sopenharmony_ci int nfft; 3353a5a1b3Sopenharmony_ci int inverse; 3453a5a1b3Sopenharmony_ci int factors[2*MAXFACTORS]; 3553a5a1b3Sopenharmony_ci kiss_fft_cpx twiddles[1]; 3653a5a1b3Sopenharmony_ci}; 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci/* 3953a5a1b3Sopenharmony_ci Explanation of macros dealing with complex math: 4053a5a1b3Sopenharmony_ci 4153a5a1b3Sopenharmony_ci C_MUL(m,a,b) : m = a*b 4253a5a1b3Sopenharmony_ci C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise 4353a5a1b3Sopenharmony_ci C_SUB( res, a,b) : res = a - b 4453a5a1b3Sopenharmony_ci C_SUBFROM( res , a) : res -= a 4553a5a1b3Sopenharmony_ci C_ADDTO( res , a) : res += a 4653a5a1b3Sopenharmony_ci * */ 4753a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 4853a5a1b3Sopenharmony_ci#include "arch.h" 4953a5a1b3Sopenharmony_ci# define FRACBITS 15 5053a5a1b3Sopenharmony_ci# define SAMPPROD spx_int32_t 5153a5a1b3Sopenharmony_ci#define SAMP_MAX 32767 5253a5a1b3Sopenharmony_ci 5353a5a1b3Sopenharmony_ci#define SAMP_MIN -SAMP_MAX 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci#if defined(CHECK_OVERFLOW) 5653a5a1b3Sopenharmony_ci# define CHECK_OVERFLOW_OP(a,op,b) \ 5753a5a1b3Sopenharmony_ci if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ 5853a5a1b3Sopenharmony_ci fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } 5953a5a1b3Sopenharmony_ci#endif 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci 6253a5a1b3Sopenharmony_ci# define smul(a,b) ( (SAMPPROD)(a)*(b) ) 6353a5a1b3Sopenharmony_ci# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_ci# define S_MUL(a,b) sround( smul(a,b) ) 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_ci# define C_MUL(m,a,b) \ 6853a5a1b3Sopenharmony_ci do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ 6953a5a1b3Sopenharmony_ci (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci# define C_MUL4(m,a,b) \ 7253a5a1b3Sopenharmony_ci do{ (m).r = PSHR32( smul((a).r,(b).r) - smul((a).i,(b).i),17 ); \ 7353a5a1b3Sopenharmony_ci (m).i = PSHR32( smul((a).r,(b).i) + smul((a).i,(b).r),17 ); }while(0) 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ci# define DIVSCALAR(x,k) \ 7653a5a1b3Sopenharmony_ci (x) = sround( smul( x, SAMP_MAX/k ) ) 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci# define C_FIXDIV(c,div) \ 7953a5a1b3Sopenharmony_ci do { DIVSCALAR( (c).r , div); \ 8053a5a1b3Sopenharmony_ci DIVSCALAR( (c).i , div); }while (0) 8153a5a1b3Sopenharmony_ci 8253a5a1b3Sopenharmony_ci# define C_MULBYSCALAR( c, s ) \ 8353a5a1b3Sopenharmony_ci do{ (c).r = sround( smul( (c).r , s ) ) ;\ 8453a5a1b3Sopenharmony_ci (c).i = sround( smul( (c).i , s ) ) ; }while(0) 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_ci#else /* not FIXED_POINT*/ 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_ci# define S_MUL(a,b) ( (a)*(b) ) 8953a5a1b3Sopenharmony_ci#define C_MUL(m,a,b) \ 9053a5a1b3Sopenharmony_ci do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ 9153a5a1b3Sopenharmony_ci (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci#define C_MUL4(m,a,b) C_MUL(m,a,b) 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_ci# define C_FIXDIV(c,div) /* NOOP */ 9653a5a1b3Sopenharmony_ci# define C_MULBYSCALAR( c, s ) \ 9753a5a1b3Sopenharmony_ci do{ (c).r *= (s);\ 9853a5a1b3Sopenharmony_ci (c).i *= (s); }while(0) 9953a5a1b3Sopenharmony_ci#endif 10053a5a1b3Sopenharmony_ci 10153a5a1b3Sopenharmony_ci#ifndef CHECK_OVERFLOW_OP 10253a5a1b3Sopenharmony_ci# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ 10353a5a1b3Sopenharmony_ci#endif 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci#define C_ADD( res, a,b)\ 10653a5a1b3Sopenharmony_ci do { \ 10753a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((a).r,+,(b).r)\ 10853a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((a).i,+,(b).i)\ 10953a5a1b3Sopenharmony_ci (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ 11053a5a1b3Sopenharmony_ci }while(0) 11153a5a1b3Sopenharmony_ci#define C_SUB( res, a,b)\ 11253a5a1b3Sopenharmony_ci do { \ 11353a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((a).r,-,(b).r)\ 11453a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((a).i,-,(b).i)\ 11553a5a1b3Sopenharmony_ci (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ 11653a5a1b3Sopenharmony_ci }while(0) 11753a5a1b3Sopenharmony_ci#define C_ADDTO( res , a)\ 11853a5a1b3Sopenharmony_ci do { \ 11953a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((res).r,+,(a).r)\ 12053a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((res).i,+,(a).i)\ 12153a5a1b3Sopenharmony_ci (res).r += (a).r; (res).i += (a).i;\ 12253a5a1b3Sopenharmony_ci }while(0) 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci#define C_SUBFROM( res , a)\ 12553a5a1b3Sopenharmony_ci do {\ 12653a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((res).r,-,(a).r)\ 12753a5a1b3Sopenharmony_ci CHECK_OVERFLOW_OP((res).i,-,(a).i)\ 12853a5a1b3Sopenharmony_ci (res).r -= (a).r; (res).i -= (a).i; \ 12953a5a1b3Sopenharmony_ci }while(0) 13053a5a1b3Sopenharmony_ci 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci#ifdef FIXED_POINT 13353a5a1b3Sopenharmony_ci# define KISS_FFT_COS(phase) floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) 13453a5a1b3Sopenharmony_ci# define KISS_FFT_SIN(phase) floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase)))) 13553a5a1b3Sopenharmony_ci# define HALF_OF(x) ((x)>>1) 13653a5a1b3Sopenharmony_ci#elif defined(USE_SIMD) 13753a5a1b3Sopenharmony_ci# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) 13853a5a1b3Sopenharmony_ci# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) 13953a5a1b3Sopenharmony_ci# define HALF_OF(x) ((x)*_mm_set1_ps(.5)) 14053a5a1b3Sopenharmony_ci#else 14153a5a1b3Sopenharmony_ci# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) 14253a5a1b3Sopenharmony_ci# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) 14353a5a1b3Sopenharmony_ci# define HALF_OF(x) ((x)*.5) 14453a5a1b3Sopenharmony_ci#endif 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_ci#define kf_cexp(x,phase) \ 14753a5a1b3Sopenharmony_ci do{ \ 14853a5a1b3Sopenharmony_ci (x)->r = KISS_FFT_COS(phase);\ 14953a5a1b3Sopenharmony_ci (x)->i = KISS_FFT_SIN(phase);\ 15053a5a1b3Sopenharmony_ci }while(0) 15153a5a1b3Sopenharmony_ci#define kf_cexp2(x,phase) \ 15253a5a1b3Sopenharmony_ci do{ \ 15353a5a1b3Sopenharmony_ci (x)->r = spx_cos_norm((phase));\ 15453a5a1b3Sopenharmony_ci (x)->i = spx_cos_norm((phase)-32768);\ 15553a5a1b3Sopenharmony_ci}while(0) 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_ci/* a debugging function */ 15953a5a1b3Sopenharmony_ci#define pcpx(c)\ 16053a5a1b3Sopenharmony_ci fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) 161