aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReiner Herrmann <reiner@reiner-h.de>2017-04-08 23:58:24 +0200
committerReiner Herrmann <reiner@reiner-h.de>2017-04-08 23:58:24 +0200
commitd79f95d0f2f761b40ffee2ab5858a39310c2bb79 (patch)
tree0790900a0a3732e168a7435b4b9348fcda4ea73c
parentba0b4e0db50c3f04e0b96dcc44ac8ed75679c945 (diff)
Calculate FFT over audio samples and print peak frequency
-rw-r--r--Makefile2
-rw-r--r--tuner.c60
2 files changed, 52 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index 19fe7e6..1940004 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
CFLAGS = -Wall -Wextra -Werror -ggdb3 -O3
-LDFLAGS = -lasound -lm -lrt
+LDFLAGS = -lasound -lfftw3 -lm -lrt
METRONOME_OBJS = metronome.o
METRONOME_BIN = metronome
diff --git a/tuner.c b/tuner.c
index 0747f3f..67cfadb 100644
--- a/tuner.c
+++ b/tuner.c
@@ -2,10 +2,16 @@
#include <stdio.h>
#include <signal.h>
+#include <complex.h>
+#include <fftw3.h>
#include <alsa/asoundlib.h>
#define SAMPLE_RATE 8000
-#define BUFFER_SIZE 4096
+#define FFT_SIZE (1<<13)
+
+static double *fft_in;
+static fftw_complex *fft_out;
+static fftw_plan fft_plan;
static int capturing = 1;
@@ -18,7 +24,7 @@ static int set_alsa_params(snd_pcm_t *pcm_handle)
{
snd_pcm_hw_params_t *hwparams;
unsigned int rate = SAMPLE_RATE;
- snd_pcm_uframes_t bufsize = BUFFER_SIZE;
+ snd_pcm_uframes_t bufsize = FFT_SIZE;
snd_pcm_hw_params_alloca(&hwparams);
@@ -30,7 +36,7 @@ static int set_alsa_params(snd_pcm_t *pcm_handle)
fprintf(stderr, "Failed setting access mode\n");
return -1;
}
- if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
+ if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_FLOAT64_LE) < 0) {
fprintf(stderr, "Failed setting format\n");
return -1;
}
@@ -54,20 +60,53 @@ static int set_alsa_params(snd_pcm_t *pcm_handle)
return 0;
}
+static void fft_init()
+{
+ 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);
+}
+
+static void fft_cleanup()
+{
+ fftw_destroy_plan(fft_plan);
+ fftw_free(fft_in);
+ fftw_free(fft_out);
+}
+
+static void process_frames()
+{
+ int i, freq, index = -1;
+ double largest = -1;
+
+ fftw_execute(fft_plan);
+
+ /* find point with largest magnitude */
+ for (i=0; i<FFT_SIZE; i++) {
+ /* +1 because out[0] is DC result */
+ double a = cabs(fft_out[i+1]);
+ if (a > largest) {
+ largest = a;
+ index = i;
+ }
+ }
+ freq = index * SAMPLE_RATE / FFT_SIZE;
+ printf("freq: %d Hz\n", freq);
+}
+
static void capture(snd_pcm_t *pcm_handle)
{
- char tonebuf[BUFFER_SIZE];
- int n_frames = 0;
- FILE* f = fopen("capture.raw", "w");
+ int read;
while(capturing) {
- while ((n_frames = snd_pcm_readi(pcm_handle, tonebuf, sizeof(tonebuf) / 2)) < 0) {
+ while ((read = snd_pcm_readi(pcm_handle, fft_in, FFT_SIZE)) < 0) {
snd_pcm_prepare(pcm_handle);
printf("overrun\n");
}
- fwrite(tonebuf, n_frames*2, 1, f);
+ if (read == FFT_SIZE) {
+ process_frames();
+ }
}
- fclose(f);
}
int main()
@@ -86,9 +125,12 @@ int main()
signal(SIGINT, handle_signals);
signal(SIGTERM, handle_signals);
+ fft_init();
+
capture(pcm_handle);
snd_pcm_close(pcm_handle);
+ fft_cleanup();
return 0;
}