156 lines
3.0 KiB
C
156 lines
3.0 KiB
C
/*
|
|
ruby-kissfft: a simple ruby module embedding the Kiss FFT library
|
|
Copyright (C) 2009-2010 Rapid7 LLC - 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 <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 @ %s(%d): %s\n",__FILE__,__LINE__,#p );exit(1);} while(0)
|
|
|
|
static VALUE
|
|
rbkiss_s_fftr(VALUE class, VALUE r_nfft, VALUE r_rate, VALUE r_buckets, VALUE r_data)
|
|
{
|
|
kiss_fftr_cfg cfg=NULL;
|
|
kiss_fft_scalar *tbuf;
|
|
kiss_fft_cpx *fbuf;
|
|
float *mag2buf;
|
|
int i;
|
|
int avgctr=0;
|
|
int nrows=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_LEN(r_data) == 0) {
|
|
return Qnil;
|
|
}
|
|
|
|
if(TYPE(RARRAY_PTR(r_data)[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 + 2) ) );
|
|
CHECKNULL( fbuf=(kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx)*(nfft + 2)) );
|
|
CHECKNULL( mag2buf=(float*)malloc(sizeof(float)*(nfft + 2) ));
|
|
|
|
memset(mag2buf,0,sizeof(mag2buf)*nfreqs);
|
|
|
|
inp_len = RARRAY_LEN(r_data);
|
|
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_PTR(r_data)[ inp_idx + i ]) != T_FIXNUM) {
|
|
tbuf[i] = 0;
|
|
} else {
|
|
tbuf[i] = NUM2INT( RARRAY_PTR(r_data)[ inp_idx + i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* 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) {
|
|
float eps = 1;
|
|
avgctr=0;
|
|
++nrows;
|
|
|
|
// RESULTS
|
|
set = rb_ary_new();
|
|
for (i=0;i<nfreqs;++i) {
|
|
float pwr = 10 * log10( mag2buf[i] / navg + eps );
|
|
tmp = rb_ary_new();
|
|
rb_ary_push(tmp, rb_float_new( (float)i * ( ( (float)rate / 2) / (float)nfreqs) ));
|
|
rb_ary_push(tmp, rb_float_new( pwr));
|
|
rb_ary_push(set, tmp);
|
|
}
|
|
rb_ary_push(res, set);
|
|
memset(mag2buf,0,sizeof(mag2buf[0])*nfreqs);
|
|
}
|
|
inp_idx += nfft;
|
|
}
|
|
|
|
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);
|
|
}
|