From 17533a10a90c9d7adbe58e255b98602ab93a427e Mon Sep 17 00:00:00 2001 From: Reiner Herrmann Date: Sun, 9 Apr 2017 13:28:25 +0200 Subject: Apply Harmonic Product Spectrum to emphasize fundamental frequencies --- tuner.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/tuner.c b/tuner.c index 4fcae2d..ec2ebb9 100644 --- a/tuner.c +++ b/tuner.c @@ -13,11 +13,14 @@ #define SAMPLE_RATE 8000 #define FFT_SIZE (1<<13) -#define ACCURACY 1.0 // Hz +#define ACCURACY 2.0 // Hz -static double *fft_in; +#define FFT_INDEX_TO_FREQ(i) ((float)i * SAMPLE_RATE / FFT_SIZE) + +static double *fft_in, *magnitudes, *processed; static fftw_complex *fft_out; static fftw_plan fft_plan; +static double peak_freq = -1.0; static int capturing = 1; @@ -68,6 +71,8 @@ static int set_alsa_params(snd_pcm_t *pcm_handle) static void fft_init() { + magnitudes = fftw_alloc_real(FFT_SIZE); + processed = fftw_alloc_real(FFT_SIZE); fft_in = fftw_alloc_real(FFT_SIZE); fft_out = fftw_alloc_complex(FFT_SIZE); fft_plan = fftw_plan_dft_r2c_1d(FFT_SIZE, fft_in, fft_out, FFTW_ESTIMATE); @@ -76,6 +81,8 @@ static void fft_init() static void fft_cleanup() { fftw_destroy_plan(fft_plan); + fftw_free(magnitudes); + fftw_free(processed); fftw_free(fft_in); fftw_free(fft_out); } @@ -109,27 +116,67 @@ static void find_note(double freq) dir = 0; } - printf("\rNote: %c%c%c Frequency: %.2f Hz ", dir<0?'>':' ', note, dir>0?'<':' ', freq); + printf("\rNote: %c%c%c Frequency: %.2f Hz, Peak: %.2f Hz ", dir<0?'>':' ', note, dir>0?'<':' ', freq, peak_freq); fflush(stdout); } +static void calculate_magnitudes() +{ + int i, max_i = -1; + + for (i=0; i magnitudes[max_i]) { + max_i = i; + } + } + peak_freq = FFT_INDEX_TO_FREQ(max_i); +} + +static void apply_hps() +{ + /* Harmonic Product Spectrum + enhance magnitude of fundamental frequency by multiplying with harmonics/overtones + which can have higher magnitudes than fundamentals */ + + int i; + + for (i=0; i= FFT_SIZE) { + break; + } + if (magnitudes[i*j] < 0.00001) { + /* too close to zero */ + continue; + } + processed[i] *= magnitudes[i*j]; + } + } +} + static void process_frames() { - int i, index = -1; - double largest = -1, freq; + int i, max_i = -1; + double freq; fftw_execute(fft_plan); + calculate_magnitudes(); + apply_hps(); /* find point with largest magnitude */ for (i=0; i largest) { - largest = a; - index = i; + if (processed[i] > processed[max_i]) { + max_i = i; } } - freq = (float)index * SAMPLE_RATE / FFT_SIZE; + freq = FFT_INDEX_TO_FREQ(max_i); find_note(freq); } @@ -142,6 +189,7 @@ static void capture(snd_pcm_t *pcm_handle) printf("overrun\n"); } if (read == FFT_SIZE) { + apply_hps(); process_frames(); } } -- cgit v1.2.3