Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@J3698
Last active May 7, 2019 22:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save J3698/f32cc88daeefeb607dfdf080030332fb to your computer and use it in GitHub Desktop.
Save J3698/f32cc88daeefeb607dfdf080030332fb to your computer and use it in GitHub Desktop.
Lights Simple Visualizer
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
#include "moving_average.h"
// for audio
#include <jack/jack.h>
#include <jack/transport.h>
// for LEDs
#include <apa102.h>
#include <wiringPi.h>
#define FILTER_SAMPLES 512
#define STRIP_BRIGHTNESS 31
#define MAX_BRIGHTNESS 0x66
#define BRIGHTNESS_DECAY 10
#define BEAT_FACTOR 1.3
// LED strip(s)
struct APA102* led_strip;
// the datatype for audio (should be a double)
typedef jack_default_audio_sample_t sample_t;
// the client that interacts with jack
char *client_name = "Visualizer";
jack_client_t *client;
// ports for left and right audio sent to speaker
jack_port_t *output_port_l;
jack_port_t *output_port_r;
// ports for left and right audio coming from system (e.g. a connected phone)
jack_port_t *input_port_l;
jack_port_t *input_port_r;
void update_lights(bool);
bool has_beat();
double calc_volume(sample_t*, sample_t*, jack_nframes_t);
double sum_squares(sample_t*, size_t);
// this function is called whenever new data is available
int process(jack_nframes_t num_samples, void *arg) {
sample_t *out_buffer_left = (sample_t *) jack_port_get_buffer(output_port_l, num_samples);
sample_t *out_buffer_right = (sample_t *) jack_port_get_buffer(output_port_r, num_samples);
sample_t *in_buffer_left = (sample_t *) jack_port_get_buffer(input_port_l, num_samples);
sample_t *in_buffer_right = (sample_t *) jack_port_get_buffer(input_port_r, num_samples);
memcpy(out_buffer_left, in_buffer_left, sizeof(sample_t) * num_samples);
memcpy(out_buffer_right, in_buffer_right, sizeof(sample_t) * num_samples);
bool beat_detected = has_beat(in_buffer_left, in_buffer_right, num_samples);
update_lights(beat_detected);
return 0;
}
// set lights full if beat detected, else fade lights
void update_lights(bool beat_detected) {
static uint8_t blueness = 0;
if (beat_detected) {
blueness = MAX_BRIGHTNESS;
} else if (blueness >= BRIGHTNESS_DECAY) {
blueness = blueness - BRIGHTNESS_DECAY;
} else {
blueness = 0;
}
APA102_Fill(led_strip, APA102_CreateFrame(STRIP_BRIGHTNESS, 0, 0, blueness));
}
bool has_beat(sample_t *audio_left, sample_t *audio_right, jack_nframes_t num_samples) {
static movingAverage_t *moving_avg = NULL;
if (moving_avg == NULL) {
moving_avg = movingAverage_new(FILTER_SAMPLES);
}
// beat detected if volume much higher than moving avg
double volume = calc_volume(audio_left, audio_right, num_samples);
bool beat_detected =
volume * FILTER_SAMPLES > BEAT_FACTOR * moving_avg->average;
movingAverage_update(moving_avg, volume);
printf("w: %f t: %f\n", moving_avg->average, volume);
return beat_detected;
}
double calc_volume(sample_t *audio_left, sample_t *audio_right,
jack_nframes_t num_samples) {
return (sum_squares(audio_left, num_samples) +
sum_squares(audio_right, num_samples)) / FILTER_SAMPLES;
}
double sum_squares(sample_t *buf, jack_nframes_t len) {
double total = 0;
for (jack_nframes_t i = 0; i < len; i++) {
total += pow(buf[i], 2);
}
return total;
}
// start a connection to jack
bool startClient() {
jack_status_t status;
while ((client = jack_client_open(client_name, 0, &status)) == 0) {
fprintf(stderr, "jack server not running?\n");
return false;
}
printf("Client started\n");
return true;
}
// create ports in order to read and write audio data (possibly extraneous)
void createPorts() {
output_port_l = jack_port_register(client, "out_l", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
output_port_r = jack_port_register(client, "out_r", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
input_port_l = jack_port_register(client, "in_l", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
input_port_r = jack_port_register(client, "in_r", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
printf("Ports created\n");
}
// connect ports from the system and the speakers to our ports
void connectPorts() {
jack_connect(client, "PulseAudio JACK Sink:front-left", jack_port_name(input_port_l));
jack_connect(client, "PulseAudio JACK Sink:front-right", jack_port_name(input_port_r));
jack_connect(client, jack_port_name(output_port_l), "system:playback_1");
jack_connect(client, jack_port_name(output_port_r), "system:playback_2");
printf("Ports connected\n");
}
/**
* In the main function jack gets started, ports get created and connected,
* and jack is told to call the process function when more work is to be done.
*/
int main(int argc, char *argv[]) {
if (!startClient()) {
return -1;
}
createPorts();
led_strip = APA102_Init(60);
jack_set_process_callback(client, process, 0);
if (jack_activate(client)) {
fprintf(stderr, "cannot activate client");
return 1;
}
printf("Jack activated\n");
connectPorts();
sleep(180);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment