160 lines
5.2 KiB
C
160 lines
5.2 KiB
C
#include "rpi_microphone.h"
|
|
|
|
#include <alsa/asoundlib.h>
|
|
#include <stdio.h>
|
|
|
|
#define CHANNELS_COUNT 1
|
|
#define SAMPLE_RATE 44100
|
|
|
|
snd_pcm_t *capture_handle;
|
|
|
|
int write_to_fftw_input_buffers(int16_t frames, int16_t buf[frames * 2], audio_data_t *audio);
|
|
|
|
void *microphone_listen(void *arg) {
|
|
audio_data_t *audio = (audio_data_t *)arg;
|
|
microphone_setup(audio);
|
|
while (1) {
|
|
microphone_exec(audio);
|
|
}
|
|
}
|
|
|
|
void microphone_setup(audio_data_t *audio) {
|
|
int err;
|
|
snd_pcm_hw_params_t *hw_params;
|
|
snd_pcm_uframes_t frames = audio->FFTtreblebufferSize;
|
|
unsigned int sampleRate = SAMPLE_RATE;
|
|
|
|
if ((err = snd_pcm_open(&capture_handle, audio->source, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
|
|
fprintf(stderr, "cannot open audio device %s (%s)\n", audio->source, snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
|
|
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) {
|
|
fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params,
|
|
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
|
fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
|
|
fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, CHANNELS_COUNT)) < 0) {
|
|
fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &sampleRate, NULL)) < 0) {
|
|
fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, &frames, NULL)) <
|
|
0) {
|
|
fprintf(stderr, "cannot set period size (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) {
|
|
fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
|
|
snd_pcm_hw_params_get_rate(hw_params, &audio->rate, NULL);
|
|
|
|
snd_pcm_hw_params_free(hw_params);
|
|
|
|
if ((err = snd_pcm_prepare(capture_handle)) < 0) {
|
|
fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void microphone_exec(audio_data_t *audio) {
|
|
int err;
|
|
snd_pcm_uframes_t buffer_size;
|
|
snd_pcm_uframes_t period_size;
|
|
snd_pcm_uframes_t frames = audio->FFTtreblebufferSize;
|
|
|
|
snd_pcm_get_params(capture_handle, &buffer_size, &period_size);
|
|
int16_t buf[period_size];
|
|
frames = period_size / 2;
|
|
|
|
err = snd_pcm_readi(capture_handle, buf, frames);
|
|
|
|
if (err == -EPIPE) {
|
|
/* EPIPE means overrun */
|
|
fprintf(stderr, "overrun occurred\n");
|
|
snd_pcm_prepare(capture_handle);
|
|
} else if (err < 0) {
|
|
fprintf(stderr, "error from read: %s\n", snd_strerror(err));
|
|
} else if (err != (int)frames) {
|
|
fprintf(stderr, "short read, read %d %d frames\n", err, (int)frames);
|
|
}
|
|
|
|
pthread_mutex_lock(&audio->lock);
|
|
write_to_fftw_input_buffers(frames, buf, audio);
|
|
pthread_mutex_unlock(&audio->lock);
|
|
}
|
|
|
|
void reset_output_buffers(audio_data_t *data) {
|
|
memset(data->in_bass_l, 0, sizeof(double) * data->FFTbassbufferSize);
|
|
memset(data->in_mid_l, 0, sizeof(double) * data->FFTmidbufferSize);
|
|
memset(data->in_treble_l, 0, sizeof(double) * data->FFTtreblebufferSize);
|
|
memset(data->in_bass_l_raw, 0, sizeof(double) * data->FFTbassbufferSize);
|
|
memset(data->in_mid_l_raw, 0, sizeof(double) * data->FFTmidbufferSize);
|
|
memset(data->in_treble_l_raw, 0, sizeof(double) * data->FFTtreblebufferSize);
|
|
}
|
|
|
|
int write_to_fftw_input_buffers(int16_t frames, int16_t buf[frames * 2], audio_data_t *audio) {
|
|
if (frames == 0)
|
|
return 0;
|
|
|
|
for (uint16_t n = audio->FFTbassbufferSize; n > frames; n = n - frames) {
|
|
for (uint16_t i = 1; i <= frames; i++) {
|
|
audio->in_bass_l_raw[n - i] = audio->in_bass_l_raw[n - i - frames];
|
|
}
|
|
}
|
|
for (uint16_t n = audio->FFTmidbufferSize; n > frames; n = n - frames) {
|
|
for (uint16_t i = 1; i <= frames; i++) {
|
|
audio->in_mid_l_raw[n - i] = audio->in_mid_l_raw[n - i - frames];
|
|
}
|
|
}
|
|
for (uint16_t n = audio->FFTtreblebufferSize; n > frames; n = n - frames) {
|
|
for (uint16_t i = 1; i <= frames; i++) {
|
|
audio->in_treble_l_raw[n - i] = audio->in_treble_l_raw[n - i - frames];
|
|
}
|
|
}
|
|
uint16_t n = frames - 1;
|
|
|
|
for (uint16_t i = 0; i < frames; i++) {
|
|
audio->in_bass_l_raw[n] = buf[i * 2];
|
|
audio->in_mid_l_raw[n] = audio->in_bass_l_raw[n];
|
|
audio->in_treble_l_raw[n] = audio->in_bass_l_raw[n];
|
|
n--;
|
|
}
|
|
|
|
// Hann Window
|
|
for (int i = 0; i < audio->FFTbassbufferSize; i++) {
|
|
audio->in_bass_l[i] = audio->bass_multiplier[i] * audio->in_bass_l_raw[i];
|
|
}
|
|
for (int i = 0; i < audio->FFTmidbufferSize; i++) {
|
|
audio->in_mid_l[i] = audio->mid_multiplier[i] * audio->in_mid_l_raw[i];
|
|
}
|
|
for (int i = 0; i < audio->FFTtreblebufferSize; i++) {
|
|
audio->in_treble_l[i] = audio->treble_multiplier[i] * audio->in_treble_l_raw[i];
|
|
}
|
|
return 0;
|
|
}
|