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