LedBars/RpiLedBars/res/src/cava/rpi_microphone.c
2021-07-28 21:26:40 +01:00

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;
}