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