| Really simple wrapper around KissFFT for ruby - warvox - VoIP based wardialing … | |
| Log | |
| Files | |
| Refs | |
| README | |
| --- | |
| commit 426612920e87183e4d8580d4cb8b385e47ddb330 | |
| parent 00e2eaa7783695ad2026001f0ba0ed6e590c0a26 | |
| Author: HD Moore <[email protected]> | |
| Date: Sun, 22 Feb 2009 19:13:32 +0000 | |
| Really simple wrapper around KissFFT for ruby | |
| Diffstat: | |
| A src/ruby-kissfft/COPYING | 30 ++++++++++++++++++++++++++++++ | |
| A src/ruby-kissfft/_kiss_fft_guts.h | 150 +++++++++++++++++++++++++++++… | |
| A src/ruby-kissfft/extconf.rb | 5 +++++ | |
| A src/ruby-kissfft/kiss_fft.c | 427 +++++++++++++++++++++++++++++… | |
| A src/ruby-kissfft/kiss_fft.h | 123 +++++++++++++++++++++++++++++… | |
| A src/ruby-kissfft/kiss_fftr.c | 159 +++++++++++++++++++++++++++++… | |
| A src/ruby-kissfft/kiss_fftr.h | 46 +++++++++++++++++++++++++++++… | |
| A src/ruby-kissfft/main.c | 170 +++++++++++++++++++++++++++++… | |
| A src/ruby-kissfft/test_kissfft.rb | 35 +++++++++++++++++++++++++++++… | |
| 9 files changed, 1145 insertions(+), 0 deletions(-) | |
| --- | |
| diff --git a/src/ruby-kissfft/COPYING b/src/ruby-kissfft/COPYING | |
| @@ -0,0 +1,30 @@ | |
| +Kiss FFT library | |
| +================== | |
| + | |
| +Copyright (c) 2003-2006 Mark Borgerding | |
| + | |
| +All rights reserved. | |
| + | |
| +Redistribution and use in source and binary forms, with or without modificatio… | |
| + | |
| + * Redistributions of source code must retain the above copyright notice, t… | |
| + * Redistributions in binary form must reproduce the above copyright notice… | |
| + * Neither the author nor the names of any contributors may be used to endo… | |
| + | |
| +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN… | |
| + | |
| + | |
| +Ruby wrapper layer | |
| +================== | |
| + | |
| +Copyright (C) 2009 H D Moore | |
| + | |
| +All rights reserved. | |
| + | |
| +Redistribution and use in source and binary forms, with or without modificatio… | |
| + | |
| + * Redistributions of source code must retain the above copyright notice, t… | |
| + * Redistributions in binary form must reproduce the above copyright notice… | |
| + * Neither the author nor the names of any contributors may be used to endo… | |
| + | |
| +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN… | |
| diff --git a/src/ruby-kissfft/_kiss_fft_guts.h b/src/ruby-kissfft/_kiss_fft_gut… | |
| @@ -0,0 +1,150 @@ | |
| +/* | |
| +Copyright (c) 2003-2004, Mark Borgerding | |
| + | |
| +All rights reserved. | |
| + | |
| +Redistribution and use in source and binary forms, with or without modificatio… | |
| + | |
| + * Redistributions of source code must retain the above copyright notice, t… | |
| + * Redistributions in binary form must reproduce the above copyright notice… | |
| + * Neither the author nor the names of any contributors may be used to endo… | |
| + | |
| +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN… | |
| +*/ | |
| + | |
| +/* 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 <limits.h> | |
| + | |
| +#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 | |
| +#if (FIXED_POINT==32) | |
| +# define FRACBITS 31 | |
| +# define SAMPPROD int64_t | |
| +#define SAMP_MAX 2147483647 | |
| +#else | |
| +# define FRACBITS 15 | |
| +# define SAMPPROD int32_t | |
| +#define SAMP_MAX 32767 | |
| +#endif | |
| + | |
| +#define SAMP_MIN -SAMP_MAX | |
| + | |
| +#if defined(CHECK_OVERFLOW) | |
| +# define CHECK_OVERFLOW_OP(a,op,b) \ | |
| + if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SA… | |
| + fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op… | |
| +#endif | |
| + | |
| + | |
| +# define smul(a,b) ( (SAMPPROD)(a)*(b) ) | |
| +# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRAC… | |
| + | |
| +# 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) | |
| + | |
| + | |
| +#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) cos(phase) | |
| +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) | |
| +# define HALF_OF(x) ((x)*.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) ) | |
| diff --git a/src/ruby-kissfft/extconf.rb b/src/ruby-kissfft/extconf.rb | |
| @@ -0,0 +1,5 @@ | |
| +require 'mkmf' | |
| + | |
| +if(have_library("m")) | |
| + create_makefile("kissfft") | |
| +end | |
| diff --git a/src/ruby-kissfft/kiss_fft.c b/src/ruby-kissfft/kiss_fft.c | |
| @@ -0,0 +1,427 @@ | |
| +/* | |
| +Copyright (c) 2003-2004, Mark Borgerding | |
| + | |
| +All rights reserved. | |
| + | |
| +Redistribution and use in source and binary forms, with or without modificatio… | |
| + | |
| + * Redistributions of source code must retain the above copyright notice, t… | |
| + * Redistributions in binary form must reproduce the above copyright notice… | |
| + * Neither the author nor the names of any contributors may be used to endo… | |
| + | |
| +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN… | |
| +*/ | |
| + | |
| + | |
| +#include "_kiss_fft_guts.h" | |
| +/* The guts header contains all the multiplication and addition macros that ar… | |
| + fixed or floating point complex numbers. It also delares the kf_ internal fu… | |
| + */ | |
| + | |
| +static kiss_fft_cpx *scratchbuf=NULL; | |
| +static size_t nscratchbuf=0; | |
| +static kiss_fft_cpx *tmpbuf=NULL; | |
| +static size_t ntmpbuf=0; | |
| + | |
| +#define CHECKBUF(buf,nbuf,n) \ | |
| + do { \ | |
| + if ( nbuf < (size_t)(n) ) {\ | |
| + free(buf); \ | |
| + buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \ | |
| + nbuf = (size_t)(n); \ | |
| + } \ | |
| + }while(0) | |
| + | |
| + | |
| +static void kf_bfly2( | |
| + kiss_fft_cpx * Fout, | |
| + const size_t fstride, | |
| + const kiss_fft_cfg st, | |
| + int m | |
| + ) | |
| +{ | |
| + kiss_fft_cpx * Fout2; | |
| + kiss_fft_cpx * tw1 = st->twiddles; | |
| + kiss_fft_cpx t; | |
| + Fout2 = Fout + m; | |
| + do{ | |
| + C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); | |
| + | |
| + C_MUL (t, *Fout2 , *tw1); | |
| + tw1 += fstride; | |
| + C_SUB( *Fout2 , *Fout , t ); | |
| + C_ADDTO( *Fout , t ); | |
| + ++Fout2; | |
| + ++Fout; | |
| + }while (--m); | |
| +} | |
| + | |
| +static void kf_bfly4( | |
| + kiss_fft_cpx * Fout, | |
| + const size_t fstride, | |
| + const kiss_fft_cfg st, | |
| + const size_t m | |
| + ) | |
| +{ | |
| + kiss_fft_cpx *tw1,*tw2,*tw3; | |
| + kiss_fft_cpx scratch[6]; | |
| + size_t k=m; | |
| + const size_t m2=2*m; | |
| + const size_t m3=3*m; | |
| + | |
| + tw3 = tw2 = tw1 = st->twiddles; | |
| + | |
| + do { | |
| + C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV… | |
| + | |
| + C_MUL(scratch[0],Fout[m] , *tw1 ); | |
| + C_MUL(scratch[1],Fout[m2] , *tw2 ); | |
| + C_MUL(scratch[2],Fout[m3] , *tw3 ); | |
| + | |
| + C_SUB( scratch[5] , *Fout, scratch[1] ); | |
| + C_ADDTO(*Fout, scratch[1]); | |
| + C_ADD( scratch[3] , scratch[0] , scratch[2] ); | |
| + C_SUB( scratch[4] , scratch[0] , scratch[2] ); | |
| + C_SUB( Fout[m2], *Fout, scratch[3] ); | |
| + tw1 += fstride; | |
| + tw2 += fstride*2; | |
| + tw3 += fstride*3; | |
| + C_ADDTO( *Fout , scratch[3] ); | |
| + | |
| + if(st->inverse) { | |
| + Fout[m].r = scratch[5].r - scratch[4].i; | |
| + Fout[m].i = scratch[5].i + scratch[4].r; | |
| + Fout[m3].r = scratch[5].r + scratch[4].i; | |
| + Fout[m3].i = scratch[5].i - scratch[4].r; | |
| + }else{ | |
| + Fout[m].r = scratch[5].r + scratch[4].i; | |
| + Fout[m].i = scratch[5].i - scratch[4].r; | |
| + Fout[m3].r = scratch[5].r - scratch[4].i; | |
| + Fout[m3].i = scratch[5].i + scratch[4].r; | |
| + } | |
| + ++Fout; | |
| + }while(--k); | |
| +} | |
| + | |
| +static void kf_bfly3( | |
| + kiss_fft_cpx * Fout, | |
| + const size_t fstride, | |
| + const kiss_fft_cfg st, | |
| + size_t m | |
| + ) | |
| +{ | |
| + size_t k=m; | |
| + const size_t m2 = 2*m; | |
| + kiss_fft_cpx *tw1,*tw2; | |
| + kiss_fft_cpx scratch[5]; | |
| + kiss_fft_cpx epi3; | |
| + epi3 = st->twiddles[fstride*m]; | |
| + | |
| + tw1=tw2=st->twiddles; | |
| + | |
| + do{ | |
| + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); | |
| + | |
| + C_MUL(scratch[1],Fout[m] , *tw1); | |
| + C_MUL(scratch[2],Fout[m2] , *tw2); | |
| + | |
| + C_ADD(scratch[3],scratch[1],scratch[2]); | |
| + C_SUB(scratch[0],scratch[1],scratch[2]); | |
| + tw1 += fstride; | |
| + tw2 += fstride*2; | |
| + | |
| + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); | |
| + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); | |
| + | |
| + C_MULBYSCALAR( scratch[0] , epi3.i ); | |
| + | |
| + C_ADDTO(*Fout,scratch[3]); | |
| + | |
| + Fout[m2].r = Fout[m].r + scratch[0].i; | |
| + Fout[m2].i = Fout[m].i - scratch[0].r; | |
| + | |
| + Fout[m].r -= scratch[0].i; | |
| + Fout[m].i += scratch[0].r; | |
| + | |
| + ++Fout; | |
| + }while(--k); | |
| +} | |
| + | |
| +static void kf_bfly5( | |
| + kiss_fft_cpx * Fout, | |
| + const size_t fstride, | |
| + const kiss_fft_cfg st, | |
| + int m | |
| + ) | |
| +{ | |
| + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; | |
| + int u; | |
| + kiss_fft_cpx scratch[13]; | |
| + kiss_fft_cpx * twiddles = st->twiddles; | |
| + kiss_fft_cpx *tw; | |
| + kiss_fft_cpx ya,yb; | |
| + ya = twiddles[fstride*m]; | |
| + yb = twiddles[fstride*2*m]; | |
| + | |
| + Fout0=Fout; | |
| + Fout1=Fout0+m; | |
| + Fout2=Fout0+2*m; | |
| + Fout3=Fout0+3*m; | |
| + Fout4=Fout0+4*m; | |
| + | |
| + tw=st->twiddles; | |
| + for ( u=0; u<m; ++u ) { | |
| + C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDI… | |
| + scratch[0] = *Fout0; | |
| + | |
| + C_MUL(scratch[1] ,*Fout1, tw[u*fstride]); | |
| + C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]); | |
| + C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]); | |
| + C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]); | |
| + | |
| + C_ADD( scratch[7],scratch[1],scratch[4]); | |
| + C_SUB( scratch[10],scratch[1],scratch[4]); | |
| + C_ADD( scratch[8],scratch[2],scratch[3]); | |
| + C_SUB( scratch[9],scratch[2],scratch[3]); | |
| + | |
| + Fout0->r += scratch[7].r + scratch[8].r; | |
| + Fout0->i += scratch[7].i + scratch[8].i; | |
| + | |
| + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch… | |
| + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch… | |
| + | |
| + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); | |
| + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); | |
| + | |
| + C_SUB(*Fout1,scratch[5],scratch[6]); | |
| + C_ADD(*Fout4,scratch[5],scratch[6]); | |
| + | |
| + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratc… | |
| + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratc… | |
| + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); | |
| + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); | |
| + | |
| + C_ADD(*Fout2,scratch[11],scratch[12]); | |
| + C_SUB(*Fout3,scratch[11],scratch[12]); | |
| + | |
| + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; | |
| + } | |
| +} | |
| + | |
| +/* perform the butterfly for one stage of a mixed radix FFT */ | |
| +static void kf_bfly_generic( | |
| + kiss_fft_cpx * Fout, | |
| + const size_t fstride, | |
| + const kiss_fft_cfg st, | |
| + int m, | |
| + int p | |
| + ) | |
| +{ | |
| + int u,k,q1,q; | |
| + kiss_fft_cpx * twiddles = st->twiddles; | |
| + kiss_fft_cpx t; | |
| + int Norig = st->nfft; | |
| + | |
| + CHECKBUF(scratchbuf,nscratchbuf,p); | |
| + | |
| + for ( u=0; u<m; ++u ) { | |
| + k=u; | |
| + for ( q1=0 ; q1<p ; ++q1 ) { | |
| + scratchbuf[q1] = Fout[ k ]; | |
| + C_FIXDIV(scratchbuf[q1],p); | |
| + k += m; | |
| + } | |
| + | |
| + k=u; | |
| + for ( q1=0 ; q1<p ; ++q1 ) { | |
| + int twidx=0; | |
| + Fout[ k ] = scratchbuf[0]; | |
| + for (q=1;q<p;++q ) { | |
| + twidx += fstride * k; | |
| + if (twidx>=Norig) twidx-=Norig; | |
| + C_MUL(t,scratchbuf[q] , twiddles[twidx] ); | |
| + C_ADDTO( Fout[ k ] ,t); | |
| + } | |
| + k += m; | |
| + } | |
| + } | |
| +} | |
| + | |
| +static | |
| +void kf_work( | |
| + kiss_fft_cpx * Fout, | |
| + const kiss_fft_cpx * f, | |
| + const size_t fstride, | |
| + int in_stride, | |
| + int * factors, | |
| + const kiss_fft_cfg st | |
| + ) | |
| +{ | |
| + kiss_fft_cpx * Fout_beg=Fout; | |
| + const int p=*factors++; /* the radix */ | |
| + const int m=*factors++; /* stage's fft length/p */ | |
| + const kiss_fft_cpx * Fout_end = Fout + p*m; | |
| + | |
| +#ifdef _OPENMP | |
| + // use openmp extensions at the | |
| + // top-level (not recursive) | |
| + if (fstride==1) { | |
| + int k; | |
| + | |
| + // execute the p different work units in different threads | |
| +# pragma omp parallel for | |
| + for (k=0;k<p;++k) | |
| + kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,fac… | |
| + // all threads have joined by this point | |
| + | |
| + switch (p) { | |
| + case 2: kf_bfly2(Fout,fstride,st,m); break; | |
| + case 3: kf_bfly3(Fout,fstride,st,m); break; | |
| + case 4: kf_bfly4(Fout,fstride,st,m); break; | |
| + case 5: kf_bfly5(Fout,fstride,st,m); break; | |
| + default: kf_bfly_generic(Fout,fstride,st,m,p); break; | |
| + } | |
| + return; | |
| + } | |
| +#endif | |
| + | |
| + if (m==1) { | |
| + do{ | |
| + *Fout = *f; | |
| + f += fstride*in_stride; | |
| + }while(++Fout != Fout_end ); | |
| + }else{ | |
| + do{ | |
| + // recursive call: | |
| + // DFT of size m*p performed by doing | |
| + // p instances of smaller DFTs of size m, | |
| + // each one takes a decimated version of the input | |
| + kf_work( Fout , f, fstride*p, in_stride, factors,st); | |
| + f += fstride*in_stride; | |
| + }while( (Fout += m) != Fout_end ); | |
| + } | |
| + | |
| + Fout=Fout_beg; | |
| + | |
| + // recombine the p smaller DFTs | |
| + switch (p) { | |
| + case 2: kf_bfly2(Fout,fstride,st,m); break; | |
| + case 3: kf_bfly3(Fout,fstride,st,m); break; | |
| + case 4: kf_bfly4(Fout,fstride,st,m); break; | |
| + case 5: kf_bfly5(Fout,fstride,st,m); break; | |
| + default: kf_bfly_generic(Fout,fstride,st,m,p); break; | |
| + } | |
| +} | |
| + | |
| +/* facbuf is populated by p1,m1,p2,m2, ... | |
| + where | |
| + p[i] * m[i] = m[i-1] | |
| + m0 = n */ | |
| +static | |
| +void kf_factor(int n,int * facbuf) | |
| +{ | |
| + int p=4; | |
| + double floor_sqrt; | |
| + floor_sqrt = floor( sqrt((double)n) ); | |
| + | |
| + /*factor out powers of 4, powers of 2, then any remaining primes */ | |
| + do { | |
| + while (n % p) { | |
| + switch (p) { | |
| + case 4: p = 2; break; | |
| + case 2: p = 3; break; | |
| + default: p += 2; break; | |
| + } | |
| + if (p > floor_sqrt) | |
| + p = n; /* no more factors, skip to end */ | |
| + } | |
| + n /= p; | |
| + *facbuf++ = p; | |
| + *facbuf++ = n; | |
| + } while (n > 1); | |
| +} | |
| + | |
| +/* | |
| + * | |
| + * User-callable function to allocate all necessary storage space for the fft. | |
| + * | |
| + * The return value is a contiguous block of memory, allocated with malloc. A… | |
| + * It can be freed with free(), rather than a kiss_fft-specific function. | |
| + * */ | |
| +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme… | |
| +{ | |
| + kiss_fft_cfg st=NULL; | |
| + size_t memneeded = sizeof(struct kiss_fft_state) | |
| + + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ | |
| + | |
| + if ( lenmem==NULL ) { | |
| + st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); | |
| + }else{ | |
| + if (mem != NULL && *lenmem >= memneeded) | |
| + st = (kiss_fft_cfg)mem; | |
| + *lenmem = memneeded; | |
| + } | |
| + if (st) { | |
| + int i; | |
| + st->nfft=nfft; | |
| + st->inverse = inverse_fft; | |
| + | |
| + for (i=0;i<nfft;++i) { | |
| + const double pi=3.141592653589793238462643383279502884197169399375… | |
| + double phase = -2*pi*i / nfft; | |
| + if (st->inverse) | |
| + phase *= -1; | |
| + kf_cexp(st->twiddles+i, phase ); | |
| + } | |
| + | |
| + kf_factor(nfft,st->factors); | |
| + } | |
| + return st; | |
| +} | |
| + | |
| + | |
| + | |
| + | |
| +void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fou… | |
| +{ | |
| + if (fin == fout) { | |
| + CHECKBUF(tmpbuf,ntmpbuf,st->nfft); | |
| + kf_work(tmpbuf,fin,1,in_stride, st->factors,st); | |
| + memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); | |
| + }else{ | |
| + kf_work( fout, fin, 1,in_stride, st->factors,st ); | |
| + } | |
| +} | |
| + | |
| +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) | |
| +{ | |
| + kiss_fft_stride(cfg,fin,fout,1); | |
| +} | |
| + | |
| + | |
| +/* not really necessary to call, but if someone is doing in-place ffts, they m… | |
| + buffers from CHECKBUF | |
| + */ | |
| +void kiss_fft_cleanup(void) | |
| +{ | |
| + free(scratchbuf); | |
| + scratchbuf = NULL; | |
| + nscratchbuf=0; | |
| + free(tmpbuf); | |
| + tmpbuf=NULL; | |
| + ntmpbuf=0; | |
| +} | |
| + | |
| +int kiss_fft_next_fast_size(int n) | |
| +{ | |
| + while(1) { | |
| + int m=n; | |
| + while ( (m%2) == 0 ) m/=2; | |
| + while ( (m%3) == 0 ) m/=3; | |
| + while ( (m%5) == 0 ) m/=5; | |
| + if (m<=1) | |
| + break; /* n is completely factorable by twos, threes, and fives */ | |
| + n++; | |
| + } | |
| + return n; | |
| +} | |
| diff --git a/src/ruby-kissfft/kiss_fft.h b/src/ruby-kissfft/kiss_fft.h | |
| @@ -0,0 +1,123 @@ | |
| +#ifndef KISS_FFT_H | |
| +#define KISS_FFT_H | |
| + | |
| +#include <stdlib.h> | |
| +#include <stdio.h> | |
| +#include <math.h> | |
| +#include <string.h> | |
| +#include <malloc.h> | |
| + | |
| +#ifdef __cplusplus | |
| +extern "C" { | |
| +#endif | |
| + | |
| +/* | |
| + ATTENTION! | |
| + If you would like a : | |
| + -- a utility that will handle the caching of fft objects | |
| + -- real-only (no imaginary time component ) FFT | |
| + -- a multi-dimensional FFT | |
| + -- a command-line utility to perform ffts | |
| + -- a command-line utility to perform fast-convolution filtering | |
| + | |
| + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c | |
| + in the tools/ directory. | |
| +*/ | |
| + | |
| +#ifdef USE_SIMD | |
| +# include <xmmintrin.h> | |
| +# define kiss_fft_scalar __m128 | |
| +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) | |
| +#else | |
| +#define KISS_FFT_MALLOC malloc | |
| +#endif | |
| + | |
| + | |
| +#ifdef FIXED_POINT | |
| +#include <sys/types.h> | |
| +# if (FIXED_POINT == 32) | |
| +# define kiss_fft_scalar int32_t | |
| +# else | |
| +# define kiss_fft_scalar int16_t | |
| +# endif | |
| +#else | |
| +# ifndef kiss_fft_scalar | |
| +/* default is float */ | |
| +# define kiss_fft_scalar float | |
| +# endif | |
| +#endif | |
| + | |
| +typedef struct { | |
| + kiss_fft_scalar r; | |
| + kiss_fft_scalar i; | |
| +}kiss_fft_cpx; | |
| + | |
| +typedef struct kiss_fft_state* kiss_fft_cfg; | |
| + | |
| +/* | |
| + * kiss_fft_alloc | |
| + * | |
| + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. | |
| + * | |
| + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); | |
| + * | |
| + * The return value from fft_alloc is a cfg buffer used internally | |
| + * by the fft routine or NULL. | |
| + * | |
| + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using ma… | |
| + * The returned value should be free()d when done to avoid memory leaks. | |
| + * | |
| + * The state can be placed in a user supplied buffer 'mem': | |
| + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, | |
| + * then the function places the cfg in mem and the size used in *lenmem | |
| + * and returns mem. | |
| + * | |
| + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), | |
| + * then the function returns NULL and places the minimum cfg | |
| + * buffer size in *lenmem. | |
| + * */ | |
| + | |
| +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme… | |
| + | |
| +/* | |
| + * kiss_fft(cfg,in_out_buf) | |
| + * | |
| + * Perform an FFT on a complex input buffer. | |
| + * for a forward FFT, | |
| + * fin should be f[0] , f[1] , ... ,f[nfft-1] | |
| + * fout will be F[0] , F[1] , ... ,F[nfft-1] | |
| + * Note that each element is complex and can be accessed like | |
| + f[k].r and f[k].i | |
| + * */ | |
| +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); | |
| + | |
| +/* | |
| + A more generic version of the above function. It reads its input from every N… | |
| + * */ | |
| +void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fo… | |
| + | |
| +/* If kiss_fft_alloc allocated a buffer, it is one contiguous | |
| + buffer and can be simply free()d when no longer needed*/ | |
| +#define kiss_fft_free free | |
| + | |
| +/* | |
| + Cleans up some memory that gets managed internally. Not necessary to call, bu… | |
| + your compiler output to call this before you exit. | |
| +*/ | |
| +void kiss_fft_cleanup(void); | |
| + | |
| + | |
| +/* | |
| + * Returns the smallest integer k, such that k>=n and k has only "fast" factor… | |
| + */ | |
| +int kiss_fft_next_fast_size(int n); | |
| + | |
| +/* for real ffts, we need an even size */ | |
| +#define kiss_fftr_next_fast_size_real(n) \ | |
| + (kiss_fft_next_fast_size( ((n)+1)>>1)<<1) | |
| + | |
| +#ifdef __cplusplus | |
| +} | |
| +#endif | |
| + | |
| +#endif | |
| diff --git a/src/ruby-kissfft/kiss_fftr.c b/src/ruby-kissfft/kiss_fftr.c | |
| @@ -0,0 +1,159 @@ | |
| +/* | |
| +Copyright (c) 2003-2004, Mark Borgerding | |
| + | |
| +All rights reserved. | |
| + | |
| +Redistribution and use in source and binary forms, with or without modificatio… | |
| + | |
| + * Redistributions of source code must retain the above copyright notice, t… | |
| + * Redistributions in binary form must reproduce the above copyright notice… | |
| + * Neither the author nor the names of any contributors may be used to endo… | |
| + | |
| +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN… | |
| +*/ | |
| + | |
| +#include "kiss_fftr.h" | |
| +#include "_kiss_fft_guts.h" | |
| + | |
| +struct kiss_fftr_state{ | |
| + kiss_fft_cfg substate; | |
| + kiss_fft_cpx * tmpbuf; | |
| + kiss_fft_cpx * super_twiddles; | |
| +#ifdef USE_SIMD | |
| + long pad; | |
| +#endif | |
| +}; | |
| + | |
| +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * len… | |
| +{ | |
| + int i; | |
| + kiss_fftr_cfg st = NULL; | |
| + size_t subsize, memneeded; | |
| + | |
| + if (nfft & 1) { | |
| + fprintf(stderr,"Real FFT optimization must be even.\n"); | |
| + return NULL; | |
| + } | |
| + nfft >>= 1; | |
| + | |
| + kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); | |
| + memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx… | |
| + | |
| + if (lenmem == NULL) { | |
| + st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); | |
| + } else { | |
| + if (*lenmem >= memneeded) | |
| + st = (kiss_fftr_cfg) mem; | |
| + *lenmem = memneeded; | |
| + } | |
| + if (!st) | |
| + return NULL; | |
| + | |
| + st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state stru… | |
| + st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); | |
| + st->super_twiddles = st->tmpbuf + nfft; | |
| + kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); | |
| + | |
| + for (i = 0; i < nfft/2; ++i) { | |
| + double phase = | |
| + -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5); | |
| + if (inverse_fft) | |
| + phase *= -1; | |
| + kf_cexp (st->super_twiddles+i,phase); | |
| + } | |
| + return st; | |
| +} | |
| + | |
| +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *… | |
| +{ | |
| + /* input buffer timedata is stored row-wise */ | |
| + int k,ncfft; | |
| + kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; | |
| + | |
| + if ( st->substate->inverse) { | |
| + fprintf(stderr,"kiss fft usage error: improper alloc\n"); | |
| + exit(1); | |
| + } | |
| + | |
| + ncfft = st->substate->nfft; | |
| + | |
| + /*perform the parallel fft of two real signals packed in real,imag*/ | |
| + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); | |
| + /* The real part of the DC element of the frequency spectrum in st->tmpbuf | |
| + * contains the sum of the even-numbered elements of the input time sequen… | |
| + * The imag part is the sum of the odd-numbered elements | |
| + * | |
| + * The sum of tdc.r and tdc.i is the sum of the input time sequence. | |
| + * yielding DC of input time sequence | |
| + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [… | |
| + * yielding Nyquist bin of input time sequence | |
| + */ | |
| + | |
| + tdc.r = st->tmpbuf[0].r; | |
| + tdc.i = st->tmpbuf[0].i; | |
| + C_FIXDIV(tdc,2); | |
| + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); | |
| + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); | |
| + freqdata[0].r = tdc.r + tdc.i; | |
| + freqdata[ncfft].r = tdc.r - tdc.i; | |
| +#ifdef USE_SIMD | |
| + freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); | |
| +#else | |
| + freqdata[ncfft].i = freqdata[0].i = 0; | |
| +#endif | |
| + | |
| + for ( k=1;k <= ncfft/2 ; ++k ) { | |
| + fpk = st->tmpbuf[k]; | |
| + fpnk.r = st->tmpbuf[ncfft-k].r; | |
| + fpnk.i = - st->tmpbuf[ncfft-k].i; | |
| + C_FIXDIV(fpk,2); | |
| + C_FIXDIV(fpnk,2); | |
| + | |
| + C_ADD( f1k, fpk , fpnk ); | |
| + C_SUB( f2k, fpk , fpnk ); | |
| + C_MUL( tw , f2k , st->super_twiddles[k-1]); | |
| + | |
| + freqdata[k].r = HALF_OF(f1k.r + tw.r); | |
| + freqdata[k].i = HALF_OF(f1k.i + tw.i); | |
| + freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); | |
| + freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); | |
| + } | |
| +} | |
| + | |
| +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar … | |
| +{ | |
| + /* input buffer timedata is stored row-wise */ | |
| + int k, ncfft; | |
| + | |
| + if (st->substate->inverse == 0) { | |
| + fprintf (stderr, "kiss fft usage error: improper alloc\n"); | |
| + exit (1); | |
| + } | |
| + | |
| + ncfft = st->substate->nfft; | |
| + | |
| + st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; | |
| + st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; | |
| + C_FIXDIV(st->tmpbuf[0],2); | |
| + | |
| + for (k = 1; k <= ncfft / 2; ++k) { | |
| + kiss_fft_cpx fk, fnkc, fek, fok, tmp; | |
| + fk = freqdata[k]; | |
| + fnkc.r = freqdata[ncfft - k].r; | |
| + fnkc.i = -freqdata[ncfft - k].i; | |
| + C_FIXDIV( fk , 2 ); | |
| + C_FIXDIV( fnkc , 2 ); | |
| + | |
| + C_ADD (fek, fk, fnkc); | |
| + C_SUB (tmp, fk, fnkc); | |
| + C_MUL (fok, tmp, st->super_twiddles[k-1]); | |
| + C_ADD (st->tmpbuf[k], fek, fok); | |
| + C_SUB (st->tmpbuf[ncfft - k], fek, fok); | |
| +#ifdef USE_SIMD | |
| + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); | |
| +#else | |
| + st->tmpbuf[ncfft - k].i *= -1; | |
| +#endif | |
| + } | |
| + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); | |
| +} | |
| diff --git a/src/ruby-kissfft/kiss_fftr.h b/src/ruby-kissfft/kiss_fftr.h | |
| @@ -0,0 +1,46 @@ | |
| +#ifndef KISS_FTR_H | |
| +#define KISS_FTR_H | |
| + | |
| +#include "kiss_fft.h" | |
| +#ifdef __cplusplus | |
| +extern "C" { | |
| +#endif | |
| + | |
| + | |
| +/* | |
| + | |
| + Real optimized version can save about 45% cpu time vs. complex fft of a real … | |
| + | |
| + | |
| + | |
| + */ | |
| + | |
| +typedef struct kiss_fftr_state *kiss_fftr_cfg; | |
| + | |
| + | |
| +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * le… | |
| +/* | |
| + nfft must be even | |
| + | |
| + If you don't care to allocate space, use mem = lenmem = NULL | |
| +*/ | |
| + | |
| + | |
| +void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx … | |
| +/* | |
| + input timedata has nfft scalar points | |
| + output freqdata has nfft/2+1 complex points | |
| +*/ | |
| + | |
| +void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar… | |
| +/* | |
| + input freqdata has nfft/2+1 complex points | |
| + output timedata has nfft scalar points | |
| +*/ | |
| + | |
| +#define kiss_fftr_free free | |
| + | |
| +#ifdef __cplusplus | |
| +} | |
| +#endif | |
| +#endif | |
| diff --git a/src/ruby-kissfft/main.c b/src/ruby-kissfft/main.c | |
| @@ -0,0 +1,170 @@ | |
| +/* | |
| + ruby-kissfft: a simple ruby wrapper around the Kiss FFT library | |
| + Copyright (C) 2009 H D Moore <hdm[at]metasploit.com> | |
| + | |
| + Derived from "psdpng.c" from the KissFFT tools directory | |
| + Copyright (C) 2003-2006 Mark Borgerding | |
| +*/ | |
| + | |
| +#include "ruby.h" | |
| +#include "rubysig.h" | |
| + | |
| +#include <stdlib.h> | |
| +#include <math.h> | |
| +#include <stdio.h> | |
| +#include <string.h> | |
| +#include <unistd.h> | |
| + | |
| +#include "kiss_fft.h" | |
| +#include "kiss_fftr.h" | |
| + | |
| +static VALUE rb_cKissFFT; | |
| + | |
| +#define KISS_VERSION "1.2.8-1.0" | |
| + | |
| + | |
| +static VALUE | |
| +rbkiss_s_version(VALUE class) | |
| +{ | |
| + return rb_str_new2(KISS_VERSION); | |
| +} | |
| + | |
| +#define CHECKNULL(p) if ( (p)==NULL ) do { fprintf(stderr,"CHECKNULL failed @ … | |
| + | |
| +static VALUE | |
| +rbkiss_s_fftr(VALUE class, VALUE r_nfft, VALUE r_rate, VALUE r_buckets, VALUE … | |
| +{ | |
| + kiss_fftr_cfg cfg=NULL; | |
| + kiss_fft_scalar *tbuf; | |
| + kiss_fft_cpx *fbuf; | |
| + float *mag2buf; | |
| + int i; | |
| + int n; | |
| + int sidx; | |
| + int avgctr=0; | |
| + int remove_dc=0; | |
| + int nrows=0; | |
| + float * vals=NULL; | |
| + int stereo=0; | |
| + | |
| + int nfft; | |
| + int rate; | |
| + int navg; | |
| + int nfreqs; | |
| + | |
| + int inp_len; | |
| + int inp_idx; | |
| + | |
| + // Result set | |
| + VALUE res; | |
| + VALUE tmp; | |
| + VALUE set; | |
| + res = rb_ary_new(); | |
| + | |
| + if(TYPE(r_nfft) != T_FIXNUM) { | |
| + return Qnil; | |
| + } | |
| + nfft=NUM2INT(r_nfft); | |
| + | |
| + if(TYPE(r_rate) != T_FIXNUM) { | |
| + return Qnil; | |
| + } | |
| + rate=NUM2INT(r_rate); | |
| + | |
| + if(TYPE(r_buckets) != T_FIXNUM) { | |
| + return Qnil; | |
| + } | |
| + navg=NUM2INT(r_buckets); | |
| + | |
| + if(TYPE(r_data) != T_ARRAY) { | |
| + return Qnil; | |
| + } | |
| + | |
| + if(RARRAY(r_data)->len == 0) { | |
| + return Qnil; | |
| + } | |
| + | |
| + if(TYPE(RARRAY(r_data)->ptr[0]) != T_FIXNUM ) { | |
| + return Qnil; | |
| + } | |
| + | |
| + nfreqs=nfft/2+1; | |
| + | |
| + CHECKNULL( cfg=kiss_fftr_alloc(nfft,0,0,0) ); | |
| + CHECKNULL( tbuf=(kiss_fft_scalar*)malloc(sizeof(kiss_fft_scalar)*nfft ) ); | |
| + CHECKNULL( fbuf=(kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx)*nfreqs ) ); | |
| + CHECKNULL( mag2buf=(float*)malloc(sizeof(float)*nfreqs ) ); | |
| + | |
| + memset(mag2buf,0,sizeof(mag2buf)*nfreqs); | |
| + | |
| + inp_len = RARRAY(r_data)->len; | |
| + inp_idx = 0; | |
| + | |
| + while(inp_idx < inp_len) { | |
| + | |
| + // Fill tbuf with nfft samples | |
| + for(i=0;i<nfft;i++) { | |
| + if(inp_idx + i >= inp_len) { | |
| + tbuf[i] = 0; | |
| + } else { | |
| + if(TYPE(RARRAY(r_data)->ptr[ inp_idx + i ]) !=… | |
| + tbuf[i] = 0; | |
| + } else { | |
| + tbuf[i] = NUM2INT( RARRAY(r_data)->ptr… | |
| + } | |
| + } | |
| + } | |
| + | |
| + // Handle DC | |
| + if (remove_dc) { | |
| + float avg = 0; | |
| + for (i=0;i<nfft;++i) avg += tbuf[i]; | |
| + avg /= nfft; | |
| + for (i=0;i<nfft;++i) tbuf[i] -= (kiss_fft_scalar)avg; | |
| + } | |
| + | |
| + /* do FFT */ | |
| + kiss_fftr(cfg,tbuf,fbuf); | |
| + | |
| + for (i=0;i<nfreqs;++i) { | |
| + mag2buf[i] += fbuf[i].r * fbuf[i].r + fbuf[i].i * fbuf[i].i; | |
| + } | |
| + | |
| + if (++avgctr == navg) { | |
| + avgctr=0; | |
| + ++nrows; | |
| + vals = (float*)realloc(vals,sizeof(float)*nrows*nfreqs… | |
| + float eps = 1; | |
| + | |
| + set = rb_ary_new(); | |
| + // RESULTS | |
| + for (i=0;i<nfreqs;++i) { | |
| + vals[(nrows - 1) * nfreqs + i] = 10 * log10( m… | |
| + | |
| + tmp = rb_ary_new(); | |
| + rb_ary_push(tmp, rb_float_new( (float)i * ( ( … | |
| + rb_ary_push(tmp, rb_float_new( vals[(nrows - 1… | |
| + rb_ary_push(set, tmp); | |
| + } | |
| + rb_ary_push(res, set); | |
| + memset(mag2buf,0,sizeof(mag2buf[0])*nfreqs); | |
| + } | |
| + inp_idx += nfft; | |
| + } | |
| + | |
| +cleanup: | |
| + free(cfg); | |
| + free(tbuf); | |
| + free(fbuf); | |
| + free(mag2buf); | |
| + return(res); | |
| +} | |
| + | |
| +void | |
| +Init_kissfft() | |
| +{ | |
| + // KissFFT | |
| + rb_cKissFFT = rb_define_class("KissFFT", rb_cObject); | |
| + rb_define_module_function(rb_cKissFFT, "version", rbkiss_s_version, 0); | |
| + rb_define_module_function(rb_cKissFFT, "fftr", rbkiss_s_fftr, 4); | |
| +} | |
| diff --git a/src/ruby-kissfft/test_kissfft.rb b/src/ruby-kissfft/test_kissfft.rb | |
| @@ -0,0 +1,35 @@ | |
| +#!/usr/bin/ruby | |
| + | |
| +base = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__ | |
| +$:.unshift(File.join(File.dirname(base))) | |
| + | |
| +require 'test/unit' | |
| +require 'kissfft' | |
| +require 'pp' | |
| + | |
| +# | |
| +# Simple unit test | |
| +# | |
| + | |
| +class KissFFT::UnitTest < Test::Unit::TestCase | |
| + def test_version | |
| + assert_equal(String, KissFFT.version.class) | |
| + puts "KissFFT version: #{KissFFT.version}" | |
| + end | |
| + def test_fftr | |
| + data = ( [*(1..100)] * 1000).flatten | |
| + | |
| + r = KissFFT.fftr(8192, 8000, 1, data) | |
| + r.each do |x| | |
| + mf = 0 | |
| + mp = 0 | |
| + x.each do |o| | |
| + if(o[1] > mp) | |
| + mp = o[1] | |
| + mf = o[0] | |
| + end | |
| + end | |
| + puts "#{mf} @ #{mp}" | |
| + end | |
| + end | |
| +end |