multithreaded app
This commit is contained in:
		
							
								
								
									
										159
									
								
								RpiLedBars/res/src/cava/rpi_microphone.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								RpiLedBars/res/src/cava/rpi_microphone.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
#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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								RpiLedBars/res/src/cava/rpi_microphone.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								RpiLedBars/res/src/cava/rpi_microphone.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
#if !defined(__RPI_MICROPHONE_H__)
 | 
			
		||||
#define __RPI_MICROPHONE_H__
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  int FFTbassbufferSize;
 | 
			
		||||
  int FFTmidbufferSize;
 | 
			
		||||
  int FFTtreblebufferSize;
 | 
			
		||||
  int bass_index;
 | 
			
		||||
  int mid_index;
 | 
			
		||||
  int treble_index;
 | 
			
		||||
  double *bass_multiplier;
 | 
			
		||||
  double *mid_multiplier;
 | 
			
		||||
  double *treble_multiplier;
 | 
			
		||||
  double *in_bass_l_raw;
 | 
			
		||||
  double *in_mid_l_raw;
 | 
			
		||||
  double *in_treble_l_raw;
 | 
			
		||||
  double *in_bass_l;
 | 
			
		||||
  double *in_mid_l;
 | 
			
		||||
  double *in_treble_l;
 | 
			
		||||
  int format;
 | 
			
		||||
  unsigned int rate;
 | 
			
		||||
  char *source; // alsa device, fifo path or pulse source
 | 
			
		||||
  int im;       // input mode alsa, fifo or pulse
 | 
			
		||||
  unsigned int channels;
 | 
			
		||||
  bool left, right, average;
 | 
			
		||||
  int terminate; // shared variable used to terminate audio thread
 | 
			
		||||
  char error_message[1024];
 | 
			
		||||
  pthread_mutex_t lock;
 | 
			
		||||
} audio_data_t;
 | 
			
		||||
 | 
			
		||||
void *microphone_listen(void *arg);
 | 
			
		||||
 | 
			
		||||
void microphone_setup(audio_data_t *audio);
 | 
			
		||||
 | 
			
		||||
void microphone_exec(audio_data_t *audio);
 | 
			
		||||
 | 
			
		||||
void reset_output_buffers(audio_data_t *data);
 | 
			
		||||
 | 
			
		||||
#endif /* __RPI_MICROPHONE_H__ */
 | 
			
		||||
							
								
								
									
										447
									
								
								RpiLedBars/res/src/cava/rpi_spectrum.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								RpiLedBars/res/src/cava/rpi_spectrum.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,447 @@
 | 
			
		||||
#include "rpi_spectrum.h"
 | 
			
		||||
 | 
			
		||||
#include <fftw3.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "rpi_microphone.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  int framerate;
 | 
			
		||||
  int number_of_bars;
 | 
			
		||||
  int lower_cut_off, upper_cut_off;
 | 
			
		||||
} param_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  double sens;
 | 
			
		||||
  double gravity;
 | 
			
		||||
  double integral;
 | 
			
		||||
  double userEQ[128];
 | 
			
		||||
} config_t;
 | 
			
		||||
 | 
			
		||||
param_t param = {
 | 
			
		||||
    .framerate = 60, .number_of_bars = 128, .lower_cut_off = 50, .upper_cut_off = 10000};
 | 
			
		||||
config_t conf = {.sens = 1, .gravity = 0, .integral = 0, .userEQ = {1}};
 | 
			
		||||
 | 
			
		||||
pthread_t microphoneListener;
 | 
			
		||||
 | 
			
		||||
audio_data_t audio;
 | 
			
		||||
 | 
			
		||||
fftw_complex *out_bass_l;
 | 
			
		||||
fftw_plan p_bass_l;
 | 
			
		||||
fftw_complex *out_mid_l;
 | 
			
		||||
fftw_plan p_mid_l;
 | 
			
		||||
fftw_complex *out_treble_l;
 | 
			
		||||
fftw_plan p_treble_l;
 | 
			
		||||
 | 
			
		||||
// input: init
 | 
			
		||||
int *bars_left;
 | 
			
		||||
double *temp_l;
 | 
			
		||||
 | 
			
		||||
int bass_cut_off = 150;
 | 
			
		||||
int treble_cut_off = 2500;
 | 
			
		||||
 | 
			
		||||
void init_plan(int bufferSize, double **in, double **in_raw, fftw_complex **out, fftw_plan *p);
 | 
			
		||||
 | 
			
		||||
void spectrum_start_bg_worker();
 | 
			
		||||
 | 
			
		||||
void spectrum_stop_bg_worker();
 | 
			
		||||
 | 
			
		||||
void spectrum_setup(char *audio_source) {
 | 
			
		||||
  for (size_t i = 0; i < 128; i++) {
 | 
			
		||||
    conf.userEQ[i] = 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  memset(&audio, 0, sizeof(audio));
 | 
			
		||||
 | 
			
		||||
  audio.source = malloc(1 + strlen(audio_source));
 | 
			
		||||
  strcpy(audio.source, audio_source);
 | 
			
		||||
 | 
			
		||||
  audio.format = -1;
 | 
			
		||||
  audio.rate = 0;
 | 
			
		||||
  audio.FFTbassbufferSize = 4096;
 | 
			
		||||
  audio.FFTmidbufferSize = 2048;
 | 
			
		||||
  audio.FFTtreblebufferSize = 1024;
 | 
			
		||||
  audio.terminate = 0;
 | 
			
		||||
  audio.channels = 1;
 | 
			
		||||
  audio.average = false;
 | 
			
		||||
  audio.left = true;
 | 
			
		||||
  audio.right = false;
 | 
			
		||||
  audio.bass_index = 0;
 | 
			
		||||
  audio.mid_index = 0;
 | 
			
		||||
  audio.treble_index = 0;
 | 
			
		||||
  audio.bass_multiplier = (double *)malloc(audio.FFTbassbufferSize * sizeof(double));
 | 
			
		||||
  audio.mid_multiplier = (double *)malloc(audio.FFTmidbufferSize * sizeof(double));
 | 
			
		||||
  audio.treble_multiplier = (double *)malloc(audio.FFTtreblebufferSize * sizeof(double));
 | 
			
		||||
 | 
			
		||||
  temp_l = (double *)malloc((audio.FFTbassbufferSize / 2 + 1) * sizeof(double));
 | 
			
		||||
 | 
			
		||||
  bars_left = (int *)malloc(256 * sizeof(int));
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < audio.FFTbassbufferSize; i++) {
 | 
			
		||||
    audio.bass_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (audio.FFTbassbufferSize - 1)));
 | 
			
		||||
  }
 | 
			
		||||
  for (int i = 0; i < audio.FFTmidbufferSize; i++) {
 | 
			
		||||
    audio.mid_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (audio.FFTmidbufferSize - 1)));
 | 
			
		||||
  }
 | 
			
		||||
  for (int i = 0; i < audio.FFTtreblebufferSize; i++) {
 | 
			
		||||
    audio.treble_multiplier[i] = 0.5 * (1 - cos(2 * M_PI * i / (audio.FFTtreblebufferSize - 1)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // BASS
 | 
			
		||||
  // audio.FFTbassbufferSize =  audio.rate / 20; // audio.FFTbassbufferSize;
 | 
			
		||||
  // audio.in_bass_l = fftw_alloc_real(audio.FFTbassbufferSize);
 | 
			
		||||
  // audio.in_bass_l_raw = fftw_alloc_real(audio.FFTbassbufferSize);
 | 
			
		||||
 | 
			
		||||
  // out_bass_l = fftw_alloc_complex(audio.FFTbassbufferSize / 2 + 1);
 | 
			
		||||
  // memset(out_bass_l, 0, (audio.FFTbassbufferSize / 2 + 1) * sizeof(fftw_complex));
 | 
			
		||||
 | 
			
		||||
  // p_bass_l =
 | 
			
		||||
  //     fftw_plan_dft_r2c_1d(audio.FFTbassbufferSize, audio.in_bass_l, out_bass_l, FFTW_MEASURE);
 | 
			
		||||
 | 
			
		||||
  init_plan(audio.FFTbassbufferSize, &audio.in_bass_l, &audio.in_bass_l_raw, &out_bass_l,
 | 
			
		||||
            &p_bass_l);
 | 
			
		||||
 | 
			
		||||
  // MID
 | 
			
		||||
  // audio.FFTmidbufferSize =  audio.rate / bass_cut_off; // audio.FFTbassbufferSize;
 | 
			
		||||
  // audio.in_mid_l = fftw_alloc_real(audio.FFTmidbufferSize);
 | 
			
		||||
  // audio.in_mid_l_raw = fftw_alloc_real(audio.FFTmidbufferSize);
 | 
			
		||||
 | 
			
		||||
  // out_mid_l = fftw_alloc_complex(audio.FFTmidbufferSize / 2 + 1);
 | 
			
		||||
  // memset(out_mid_l, 0, (audio.FFTmidbufferSize / 2 + 1) * sizeof(fftw_complex));
 | 
			
		||||
 | 
			
		||||
  // p_mid_l = fftw_plan_dft_r2c_1d(audio.FFTmidbufferSize, audio.in_mid_l, out_mid_l,
 | 
			
		||||
  // FFTW_MEASURE);
 | 
			
		||||
 | 
			
		||||
  init_plan(audio.FFTmidbufferSize, &audio.in_mid_l, &audio.in_mid_l_raw, &out_mid_l, &p_mid_l);
 | 
			
		||||
 | 
			
		||||
  // TRIEBLE
 | 
			
		||||
  // audio.FFTtreblebufferSize =  audio.rate / treble_cut_off; // audio.FFTbassbufferSize;
 | 
			
		||||
  // audio.in_treble_l = fftw_alloc_real(audio.FFTtreblebufferSize);
 | 
			
		||||
  // audio.in_treble_l_raw = fftw_alloc_real(audio.FFTtreblebufferSize);
 | 
			
		||||
 | 
			
		||||
  // out_treble_l = fftw_alloc_complex(audio.FFTtreblebufferSize / 2 + 1);
 | 
			
		||||
  // memset(out_treble_l, 0, (audio.FFTtreblebufferSize / 2 + 1) * sizeof(fftw_complex));
 | 
			
		||||
 | 
			
		||||
  // p_treble_l = fftw_plan_dft_r2c_1d(audio.FFTtreblebufferSize, audio.in_treble_l,
 | 
			
		||||
  // out_treble_l,
 | 
			
		||||
  //                                   FFTW_MEASURE);
 | 
			
		||||
 | 
			
		||||
  init_plan(audio.FFTtreblebufferSize, &audio.in_treble_l, &audio.in_treble_l_raw, &out_treble_l,
 | 
			
		||||
            &p_treble_l);
 | 
			
		||||
 | 
			
		||||
  reset_output_buffers(&audio);
 | 
			
		||||
 | 
			
		||||
  spectrum_start_bg_worker();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spectrum_start_bg_worker() {
 | 
			
		||||
  pthread_mutex_init(&audio.lock, NULL);
 | 
			
		||||
  if (pthread_create(µphoneListener, NULL, microphone_listen, (void *)&audio) < 0) {
 | 
			
		||||
    perror("pthread_create");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int timeout_counter = 0;
 | 
			
		||||
  while (audio.rate == 0) {
 | 
			
		||||
    usleep(2000);
 | 
			
		||||
    ++timeout_counter;
 | 
			
		||||
    if (timeout_counter > 2000) {
 | 
			
		||||
      fprintf(stderr, "could not get rate and/or format, problems with audio thread? "
 | 
			
		||||
                      "quiting...\n");
 | 
			
		||||
      exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spectrum_stop_bg_worker() {
 | 
			
		||||
  if (pthread_cancel(microphoneListener) != 0) {
 | 
			
		||||
    perror("pthread_cancel");
 | 
			
		||||
  }
 | 
			
		||||
  if (pthread_join(microphoneListener, NULL) != 0) {
 | 
			
		||||
    perror("pthread_join");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void spectrum_execute() {
 | 
			
		||||
  int bars[256];
 | 
			
		||||
  int bars_mem[256];
 | 
			
		||||
  int bars_last[256];
 | 
			
		||||
  int previous_frame[256];
 | 
			
		||||
  int fall[256];
 | 
			
		||||
  float bars_peak[256];
 | 
			
		||||
 | 
			
		||||
  int height, lines, width, remainder, fp;
 | 
			
		||||
 | 
			
		||||
  bool reloadConf = false;
 | 
			
		||||
 | 
			
		||||
  for (int n = 0; n < 256; n++) {
 | 
			
		||||
    bars_last[n] = 0;
 | 
			
		||||
    previous_frame[n] = 0;
 | 
			
		||||
    fall[n] = 0;
 | 
			
		||||
    bars_peak[n] = 0;
 | 
			
		||||
    bars_mem[n] = 0;
 | 
			
		||||
    bars[n] = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  width = 256;
 | 
			
		||||
  height = UINT16_MAX;
 | 
			
		||||
 | 
			
		||||
  // getting numbers of bars
 | 
			
		||||
  int number_of_bars = param.number_of_bars;
 | 
			
		||||
 | 
			
		||||
  if (number_of_bars > 256)
 | 
			
		||||
    number_of_bars = 256; // cant have more than 256 bars
 | 
			
		||||
 | 
			
		||||
  // process [smoothing]: calculate gravity
 | 
			
		||||
  float g = conf.gravity * ((float)height / 2160) * pow((60 / (float)param.framerate), 2.5);
 | 
			
		||||
 | 
			
		||||
  // calculate integral value, must be reduced with height
 | 
			
		||||
  double integral = conf.integral;
 | 
			
		||||
  if (height > 320)
 | 
			
		||||
    integral = conf.integral * 1 / sqrt((log10((float)height / 10)));
 | 
			
		||||
 | 
			
		||||
  // process: calculate cutoff frequencies and eq
 | 
			
		||||
 | 
			
		||||
  double userEQ_keys_to_bars_ratio;
 | 
			
		||||
 | 
			
		||||
  if (number_of_bars > 0) {
 | 
			
		||||
    userEQ_keys_to_bars_ratio = (double)(((double)(number_of_bars < 128 ? number_of_bars : 128)) /
 | 
			
		||||
                                         ((double)number_of_bars));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // calculate frequency constant (used to distribute bars across the frequency band)
 | 
			
		||||
  double frequency_constant = log10((float)param.lower_cut_off / (float)param.upper_cut_off) /
 | 
			
		||||
                              (1 / ((float)number_of_bars + 1) - 1);
 | 
			
		||||
 | 
			
		||||
  float cut_off_frequency[256];
 | 
			
		||||
  float upper_cut_off_frequency[256];
 | 
			
		||||
  float relative_cut_off[256];
 | 
			
		||||
  double center_frequencies[256];
 | 
			
		||||
  int FFTbuffer_lower_cut_off[256];
 | 
			
		||||
  int FFTbuffer_upper_cut_off[256];
 | 
			
		||||
  double eq[256];
 | 
			
		||||
 | 
			
		||||
  int bass_cut_off_bar = -1;
 | 
			
		||||
  int treble_cut_off_bar = -1;
 | 
			
		||||
  bool first_bar = true;
 | 
			
		||||
  int first_treble_bar = 0;
 | 
			
		||||
  int bar_buffer[number_of_bars + 1];
 | 
			
		||||
 | 
			
		||||
  for (int n = 0; n < number_of_bars + 1; n++) {
 | 
			
		||||
    double bar_distribution_coefficient = frequency_constant * (-1);
 | 
			
		||||
    bar_distribution_coefficient +=
 | 
			
		||||
        ((float)n + 1) / ((float)number_of_bars + 1) * frequency_constant;
 | 
			
		||||
    cut_off_frequency[n] = param.upper_cut_off * pow(10, bar_distribution_coefficient);
 | 
			
		||||
 | 
			
		||||
    if (n > 0) {
 | 
			
		||||
      if (cut_off_frequency[n - 1] >= cut_off_frequency[n] &&
 | 
			
		||||
          cut_off_frequency[n - 1] > bass_cut_off)
 | 
			
		||||
        cut_off_frequency[n] =
 | 
			
		||||
            cut_off_frequency[n - 1] + (cut_off_frequency[n - 1] - cut_off_frequency[n - 2]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    relative_cut_off[n] = cut_off_frequency[n] / (audio.rate / 2);
 | 
			
		||||
    // remember nyquist!, per my calculations this should be rate/2
 | 
			
		||||
    // and nyquist freq in M/2 but testing shows it is not...
 | 
			
		||||
    // or maybe the nq freq is in M/4
 | 
			
		||||
 | 
			
		||||
    eq[n] = pow(cut_off_frequency[n], 1);
 | 
			
		||||
 | 
			
		||||
    // the numbers that come out of the FFT are very high
 | 
			
		||||
    // the EQ is used to "normalize" them by dividing with this very huge number
 | 
			
		||||
    eq[n] *= (float)height / pow(2, 28);
 | 
			
		||||
 | 
			
		||||
    eq[n] *= conf.userEQ[(int)floor(((double)n) * userEQ_keys_to_bars_ratio)];
 | 
			
		||||
 | 
			
		||||
    eq[n] /= log2(audio.FFTbassbufferSize);
 | 
			
		||||
 | 
			
		||||
    if (cut_off_frequency[n] < bass_cut_off) {
 | 
			
		||||
      // BASS
 | 
			
		||||
      bar_buffer[n] = 1;
 | 
			
		||||
      FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTbassbufferSize / 2);
 | 
			
		||||
      bass_cut_off_bar++;
 | 
			
		||||
      treble_cut_off_bar++;
 | 
			
		||||
      if (bass_cut_off_bar > 0)
 | 
			
		||||
        first_bar = false;
 | 
			
		||||
 | 
			
		||||
      eq[n] *= log2(audio.FFTbassbufferSize);
 | 
			
		||||
    } else if (cut_off_frequency[n] > bass_cut_off && cut_off_frequency[n] < treble_cut_off) {
 | 
			
		||||
      // MID
 | 
			
		||||
      bar_buffer[n] = 2;
 | 
			
		||||
      FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTmidbufferSize / 2);
 | 
			
		||||
      treble_cut_off_bar++;
 | 
			
		||||
      if ((treble_cut_off_bar - bass_cut_off_bar) == 1) {
 | 
			
		||||
        first_bar = true;
 | 
			
		||||
        FFTbuffer_upper_cut_off[n - 1] = relative_cut_off[n] * (audio.FFTbassbufferSize / 2);
 | 
			
		||||
      } else {
 | 
			
		||||
        first_bar = false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      eq[n] *= log2(audio.FFTmidbufferSize);
 | 
			
		||||
    } else {
 | 
			
		||||
      // TREBLE
 | 
			
		||||
      bar_buffer[n] = 3;
 | 
			
		||||
      FFTbuffer_lower_cut_off[n] = relative_cut_off[n] * (audio.FFTtreblebufferSize / 2);
 | 
			
		||||
      first_treble_bar++;
 | 
			
		||||
      if (first_treble_bar == 1) {
 | 
			
		||||
        first_bar = true;
 | 
			
		||||
        FFTbuffer_upper_cut_off[n - 1] = relative_cut_off[n] * (audio.FFTmidbufferSize / 2);
 | 
			
		||||
      } else {
 | 
			
		||||
        first_bar = false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      eq[n] *= log2(audio.FFTtreblebufferSize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (n > 0) {
 | 
			
		||||
      if (!first_bar) {
 | 
			
		||||
        FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
 | 
			
		||||
 | 
			
		||||
        // pushing the spectrum up if the exponential function gets "clumped" in the
 | 
			
		||||
        // bass and caluclating new cut off frequencies
 | 
			
		||||
        if (FFTbuffer_lower_cut_off[n] <= FFTbuffer_lower_cut_off[n - 1]) {
 | 
			
		||||
 | 
			
		||||
          FFTbuffer_lower_cut_off[n] = FFTbuffer_lower_cut_off[n - 1] + 1;
 | 
			
		||||
          FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n] - 1;
 | 
			
		||||
 | 
			
		||||
          if (bar_buffer[n] == 1)
 | 
			
		||||
            relative_cut_off[n] =
 | 
			
		||||
                (float)(FFTbuffer_lower_cut_off[n]) / ((float)audio.FFTbassbufferSize / 2);
 | 
			
		||||
          else if (bar_buffer[n] == 2)
 | 
			
		||||
            relative_cut_off[n] =
 | 
			
		||||
                (float)(FFTbuffer_lower_cut_off[n]) / ((float)audio.FFTmidbufferSize / 2);
 | 
			
		||||
          else if (bar_buffer[n] == 3)
 | 
			
		||||
            relative_cut_off[n] =
 | 
			
		||||
                (float)(FFTbuffer_lower_cut_off[n]) / ((float)audio.FFTtreblebufferSize / 2);
 | 
			
		||||
 | 
			
		||||
          cut_off_frequency[n] = relative_cut_off[n] * ((float)audio.rate / 2);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        if (FFTbuffer_upper_cut_off[n - 1] <= FFTbuffer_lower_cut_off[n - 1])
 | 
			
		||||
          FFTbuffer_upper_cut_off[n - 1] = FFTbuffer_lower_cut_off[n - 1] + 1;
 | 
			
		||||
      }
 | 
			
		||||
      upper_cut_off_frequency[n - 1] =
 | 
			
		||||
          cut_off_frequency[n]; // high_relative_cut_off * ((float)audio.rate / 2);
 | 
			
		||||
      center_frequencies[n - 1] =
 | 
			
		||||
          pow((cut_off_frequency[n - 1] * upper_cut_off_frequency[n - 1]), 0.5);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // process: execute FFT and sort frequency bands
 | 
			
		||||
  pthread_mutex_lock(&audio.lock);
 | 
			
		||||
  fftw_execute(p_bass_l);
 | 
			
		||||
  fftw_execute(p_mid_l);
 | 
			
		||||
  fftw_execute(p_treble_l);
 | 
			
		||||
  pthread_mutex_unlock(&audio.lock);
 | 
			
		||||
 | 
			
		||||
  // process: separate frequency bands
 | 
			
		||||
  for (int n = 0; n < number_of_bars; n++) {
 | 
			
		||||
 | 
			
		||||
    temp_l[n] = 0;
 | 
			
		||||
 | 
			
		||||
    // process: add upp FFT values within bands
 | 
			
		||||
    for (int i = FFTbuffer_lower_cut_off[n]; i <= FFTbuffer_upper_cut_off[n]; i++) {
 | 
			
		||||
      if (n <= bass_cut_off_bar) {
 | 
			
		||||
 | 
			
		||||
        temp_l[n] += hypot(out_bass_l[i][0], out_bass_l[i][1]);
 | 
			
		||||
 | 
			
		||||
      } else if (n > bass_cut_off_bar && n <= treble_cut_off_bar) {
 | 
			
		||||
 | 
			
		||||
        temp_l[n] += hypot(out_mid_l[i][0], out_mid_l[i][1]);
 | 
			
		||||
 | 
			
		||||
      } else if (n > treble_cut_off_bar) {
 | 
			
		||||
 | 
			
		||||
        temp_l[n] += hypot(out_treble_l[i][0], out_treble_l[i][1]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // getting average multiply with sens and eq
 | 
			
		||||
    temp_l[n] /= FFTbuffer_upper_cut_off[n] - FFTbuffer_lower_cut_off[n] + 1;
 | 
			
		||||
    temp_l[n] *= conf.sens * eq[n];
 | 
			
		||||
 | 
			
		||||
    bars_left[n] = temp_l[n];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // process [filter]
 | 
			
		||||
 | 
			
		||||
  // if (p.monstercat) {
 | 
			
		||||
  //   if (p.stereo) {
 | 
			
		||||
  //     bars_left = monstercat_filter(bars_left, number_of_bars / 2, p.waves, p.monstercat);
 | 
			
		||||
  //     bars_right = monstercat_filter(bars_right, number_of_bars / 2, p.waves, p.monstercat);
 | 
			
		||||
  //   } else {
 | 
			
		||||
  //     bars_left = monstercat_filter(bars_left, number_of_bars, p.waves, p.monstercat);
 | 
			
		||||
  //   }
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  // processing signal
 | 
			
		||||
 | 
			
		||||
  // bool senselow = true;
 | 
			
		||||
 | 
			
		||||
  for (int n = 0; n < number_of_bars; n++) {
 | 
			
		||||
    //   // mirroring stereo channels
 | 
			
		||||
    //   if (p.stereo) {
 | 
			
		||||
    //     if (n < number_of_bars / 2) {
 | 
			
		||||
    //       bars[n] = bars_left[number_of_bars / 2 - n - 1];
 | 
			
		||||
    //     } else {
 | 
			
		||||
    //       bars[n] = bars_right[n - number_of_bars / 2];
 | 
			
		||||
    //     }
 | 
			
		||||
 | 
			
		||||
    //   } else {
 | 
			
		||||
    bars[n] = bars_left[n];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // process [smoothing]: falloff
 | 
			
		||||
  // if (g > 0) {
 | 
			
		||||
  //   if (bars[n] < bars_last[n]) {
 | 
			
		||||
  //     bars[n] = bars_peak[n] - (g * fall[n] * fall[n]);
 | 
			
		||||
  //     if (bars[n] < 0)
 | 
			
		||||
  //       bars[n] = 0;
 | 
			
		||||
  //     fall[n]++;
 | 
			
		||||
  //   } else {
 | 
			
		||||
  //     bars_peak[n] = bars[n];
 | 
			
		||||
  //     fall[n] = 0;
 | 
			
		||||
  //   }
 | 
			
		||||
 | 
			
		||||
  //   bars_last[n] = bars[n];
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  // process [smoothing]: integral
 | 
			
		||||
  //   if (p.integral > 0) {
 | 
			
		||||
  //     bars[n] = bars_mem[n] * integral + bars[n];
 | 
			
		||||
  //     bars_mem[n] = bars[n];
 | 
			
		||||
 | 
			
		||||
  //     int diff = height - bars[n];
 | 
			
		||||
  //     if (diff < 0)
 | 
			
		||||
  //       diff = 0;
 | 
			
		||||
  //     double div = 1 / (diff + 1);
 | 
			
		||||
  //     // bars[n] = bars[n] - pow(div, 10) * (height + 1);
 | 
			
		||||
  //     bars_mem[n] = bars_mem[n] * (1 - div / 20);
 | 
			
		||||
  //   }
 | 
			
		||||
 | 
			
		||||
  memcpy(previous_frame, bars, 256 * sizeof(int));
 | 
			
		||||
 | 
			
		||||
  for (size_t i = 0; i < number_of_bars; i++) {
 | 
			
		||||
    printf("%5d, ", bars[i]);
 | 
			
		||||
  }
 | 
			
		||||
  printf("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int *spectrum_display_bars() { return bars_left; }
 | 
			
		||||
 | 
			
		||||
void init_plan(int bufferSize, double **in, double **in_raw, fftw_complex **out, fftw_plan *p) {
 | 
			
		||||
  *in = fftw_alloc_real(bufferSize);
 | 
			
		||||
  *in_raw = fftw_alloc_real(bufferSize);
 | 
			
		||||
 | 
			
		||||
  *out = fftw_alloc_complex(bufferSize / 2 + 1);
 | 
			
		||||
  memset(*out, 0, (bufferSize / 2 + 1) * sizeof(fftw_complex));
 | 
			
		||||
 | 
			
		||||
  *p = fftw_plan_dft_r2c_1d(bufferSize, *in, *out, FFTW_MEASURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void compute_param() {}
 | 
			
		||||
 | 
			
		||||
void compute_config() {}
 | 
			
		||||
							
								
								
									
										14
									
								
								RpiLedBars/res/src/cava/rpi_spectrum.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								RpiLedBars/res/src/cava/rpi_spectrum.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#if !defined(__RPI_SPECTRUM_H__)
 | 
			
		||||
#define __RPI_SPECTRUM_H__
 | 
			
		||||
 | 
			
		||||
void spectrum_setup(char *audio_source);
 | 
			
		||||
 | 
			
		||||
void spectrum_start_bg_worker();
 | 
			
		||||
 | 
			
		||||
void spectrum_stop_bg_worker();
 | 
			
		||||
 | 
			
		||||
void spectrum_execute();
 | 
			
		||||
 | 
			
		||||
int *spectrum_get_bars();
 | 
			
		||||
 | 
			
		||||
#endif /* __RPI_SPECTRUM_H__ */
 | 
			
		||||
		Reference in New Issue
	
	Block a user