diff options
author | waker <wakeroid@gmail.com> | 2012-10-25 21:51:08 +0200 |
---|---|---|
committer | waker <wakeroid@gmail.com> | 2012-10-25 21:51:08 +0200 |
commit | b013e081750203b795c4cdd0496110693f439ab3 (patch) | |
tree | a6853dbb35a2a81ff22671525bb2bf88f25b6a97 /fft.c | |
parent | d940812fafd1a71837a3bb3f1c1132c7beea5187 (diff) |
new fft code from audacious, now spectrum analyzer looks correctly
Diffstat (limited to 'fft.c')
-rw-r--r-- | fft.c | 113 |
1 files changed, 113 insertions, 0 deletions
@@ -0,0 +1,113 @@ +/* + * fft.c + * Copyright 2011 John Lindgren + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions, and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions, and the following disclaimer in the documentation + * provided with the distribution. + * + * This software is provided "as is" and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising from + * the use of this software. + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "deadbeef.h" +#include <math.h> +#include <complex.h> + +static float hamming[DDB_AUDIO_MEMORY_FRAMES]; /* hamming window, scaled to sum to 1 */ +static int reversed[DDB_AUDIO_MEMORY_FRAMES]; /* bit-reversal table */ +static float complex roots[DDB_AUDIO_MEMORY_FRAMES / 2]; /* N-th roots of unity */ +static int generated = 0; +static float LOGN; /* log N (base 2) */ + +/* Reverse the order of the lowest LOGN bits in an integer. */ + +static int bit_reverse (int x) +{ + int y = 0; + + for (int n = LOGN; n --; ) + { + y = (y << 1) | (x & 1); + x >>= 1; + } + + return y; +} + +#ifndef HAVE_LOG2 +static inline float log2(float x) {return (float)log(x)/M_LN2;} +#endif + +/* Generate lookup tables. */ + +static void generate_tables (void) +{ + if (generated) + return; + + const int N = DDB_AUDIO_MEMORY_FRAMES; + LOGN = log2(N); + for (int n = 0; n < N; n ++) + hamming[n] = 1 - 0.85 * cosf (2 * M_PI * n / N); + for (int n = 0; n < N; n ++) + reversed[n] = bit_reverse (n); + for (int n = 0; n < N / 2; n ++) + roots[n] = cexpf (2 * M_PI * I * n / N); + + generated = 1; +} + +static void do_fft (float complex a[DDB_AUDIO_MEMORY_FRAMES]) +{ + const int N = DDB_AUDIO_MEMORY_FRAMES; + int half = 1; /* (2^s)/2 */ + int inv = N / 2; /* N/(2^s) */ + + /* loop through steps */ + while (inv) + { + /* loop through groups */ + for (int g = 0; g < N; g += half << 1) + { + /* loop through butterflies */ + for (int b = 0, r = 0; b < half; b ++, r += inv) + { + float complex even = a[g + b]; + float complex odd = roots[r] * a[g + half + b]; + a[g + b] = even + odd; + a[g + half + b] = even - odd; + } + } + + half <<= 1; + inv >>= 1; + } +} + +void +calc_freq (float *data, float *freq) { + generate_tables (); + + // fft code shamelessly stolen from audacious + // thanks, John + int N = DDB_AUDIO_MEMORY_FRAMES; + float complex a[N]; + for (int n = 0; n < N; n ++) { + a[reversed[n]] = data[n] * hamming[n]; + } + do_fft(a); + + for (int n = 0; n < N / 2 - 1; n ++) + freq[n] = 2 * cabsf (a[1 + n]) / N; + freq[N / 2 - 1] = cabsf(a[N / 2]) / N; +} |