diff --git a/makefile b/makefile index 10afcde..b45c68b 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -SRC = src/settings.h src/fft.c src/utils_curses.c src/music_visualizer.c src/utils_mpd.c src/mt/mt19937ar.c +SRC = src/settings.h src/fft.c src/utils_curses.c src/music_visualizer.c src/utils_mpd.c src/mt/mt19937ar.c src/beat_track.c LOCPATH = ./bin INSTALLPATH = /usr/local CFLAGS = -O3 diff --git a/src/beat_track.c b/src/beat_track.c new file mode 100644 index 0000000..7ad0ed0 --- /dev/null +++ b/src/beat_track.c @@ -0,0 +1,77 @@ +#include "beat_track.h" +#include "settings.h" + +#include + +void cb_init(cebuffer *cb, const int capacity) +{ + cb->buffer = (energy_t*)malloc(capacity*sizeof(energy_t)); + memset(cb->buffer, 0, capacity*sizeof(energy_t)); + cb->capacity = capacity; + cb->count = 0; + cb->head = 0; + cb->tail = 0; +} + +void cb_free(cebuffer *cb) +{ + free(cb->buffer); + cb->count = 0; + cb->head = 0; + cb->tail = 0; +} + +// insert, deleting oldest element if needed +void cb_push_back(cebuffer *cb, const energy_t item) +{ + // insert on head+1 + cb->buffer[cb->head % 43] = item; + cb->head++; + if(cb->count >= cb->capacity) { + cb->tail++; + } else { + cb->count++; + } +} + +unsigned int cb_avg(cebuffer *cb) +{ + unsigned int avg = 0; + unsigned int i = 0; + + for(i=cb->tail; ihead; ++i) { + avg += cb->buffer[i % cb->capacity]; + } + return (int)(avg / cb->count); +} + +int cb_variance(cebuffer *cb) +{ + double variance = 0; + unsigned int i = 0; + unsigned int avg = cb_avg(cb); + + for(i=cb->tail; ihead; ++i) { + variance += pow(cb->buffer[i % cb->capacity] - avg, 2); + fprintf(stderr, "head: %d, tail: %d, i: %d, buffer: %d, avg: %d\t", cb->head, cb->tail, i%cb->capacity, cb->buffer[i % cb->capacity], avg); + fprintf(stderr, "variance: %f\n", variance); + } + fprintf(stderr, "variance TOTAL: %f\n", variance / cb->count); + return (int)(variance / cb->count); +} + +bool cb_beat(cebuffer *cb, const energy_t item, energy_t* energyThreshold) +{ + bool beat = false; + + // compute the avg of the circular buffer up to now + *energyThreshold = (int)(-15*cb_variance(cb) + 1.55); + + if(item > *energyThreshold + *energyThreshold/2) { + beat = true; + } + + fprintf(stderr, "threshold: %d, item: %d\n", *energyThreshold, item); + + return beat; +} diff --git a/src/beat_track.h b/src/beat_track.h new file mode 100644 index 0000000..f6a58a5 --- /dev/null +++ b/src/beat_track.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include +#include +#include + +typedef unsigned int energy_t; + +// circular energy buffer +typedef struct cebuffer +{ + energy_t* buffer; // data buffer + int capacity; // maximum number of items in the buffer + int count; // number of items in the buffer + int head; // pointer to head + int tail; // pointer to tail +} cebuffer; + +void cb_init(cebuffer *cb, int capacity); +void cb_free(cebuffer *cb); +void cb_push_back(cebuffer *cb, const energy_t item); +bool cb_beat(cebuffer *cb, const energy_t item, energy_t* energyThreshold); diff --git a/src/fft.c b/src/fft.c index 39a4a68..a21c3d5 100644 --- a/src/fft.c +++ b/src/fft.c @@ -71,19 +71,6 @@ return round(20*log10(sq)); // dB scale } -/** - * Not used anymore -void -normalize_fft(const int inLen, unsigned int* fftSig) -{ - int i; - for(i=0; i // status #include "utils_mpd.h" static _Atomic bool getstatus = true; -#endif - -#define BEATC 25 // experiment with it - -static int maxR = 0; -static int maxC = 0; - -#ifdef STATUS_CHECK -void -get_mpd_status(struct mpd_connection* session, STATUS* status) -{ - if(!session) { - session = open_connection(); - } - status = get_current_status(session); -} - void alarm_status() { @@ -46,42 +30,36 @@ } #endif -// TODO improve and use -int -test_beat(unsigned int* fftEHist, int sEnergyLen, unsigned int* sEnergy) -{ - int i,j; - for(i=0; i=0; j--) { - fftEHist[j] = fftEHist[j-1]; - } +#define BEATC 25 // experiment with it - // insert element - fftEHist[0] = sEnergy[i]; - - // check sound energy for beat - for(j=0; j fftEHist[j]+BEATC && sEnergy[i] < 200) { // 200 avg would be false read - return 1; - } - } - } - return 0; -} +static int maxR = 0; +static int maxC = 0; void process_fifo (uint16_t* buf, unsigned int* fftBuf, unsigned int* fftAvg, \ - unsigned int* sEnergy, int nsamples, int sEnergyLen) + cebuffer* energyBuffer, int nsamples, unsigned int* energyThreshold) { + // fft of samples array fast_fft(nsamples, (uint16_t*)buf, fftBuf); // computes an average of the signals in fftBuf // based on the number of columns of the screen average_signal(fftBuf, nsamples, maxC, fftAvg); - // compute the energy of each subband - energy_sub_signal(fftBuf, nsamples, nsamples/sEnergyLen, sEnergy); + unsigned int avg = 0; + if(energyBuffer->count > 0) { + // compute the energy of the samples array + avgEnergy(fftBuf, nsamples, &avg); + fprintf(stderr, "Computed avg: %d\n", avg); + + bool beat = cb_beat(energyBuffer, avg, energyThreshold); + if(beat) { + fprintf(stderr, "BEAT!\n"); + } + } + + // insert the current energy sample into the circular buffer + cb_push_back(energyBuffer, avg); } void @@ -122,12 +100,13 @@ int cnt = 0; // used to set resolution (wether to skip / not to skip a read) uint32_t sampleRate = 0; int nsamples = N_SAMPLES; // adapt processing to sample rate - int sEnergyLen = N_SAMPLES/32; + int sEnergyLen = N_SAMPLES; PATTERN pattern = ANOTHER; int statusHeight = 0; int statusCol = 0; bool toggleStatus = true; short cnt_over = 0; // in case no data is available for too much + unsigned int energyThreshold = 0; // add it to select() set FD_ZERO(&set); @@ -136,13 +115,13 @@ // allocate buffers used unsigned int* fftBuf= (unsigned int*)malloc(N_SAMPLES*sizeof(unsigned int)); unsigned int* fftAvg = (unsigned int*)malloc(N_SAMPLES*sizeof(unsigned int)); - unsigned int* fftEHist = (unsigned int*)malloc(sEnergyLen*sizeof(unsigned int)); - unsigned int* sEnergy = (unsigned int*)malloc(sEnergyLen*sizeof(unsigned int)); + cebuffer energyBuffer; + + cb_init(&energyBuffer, 43); + // set the result buffer to 0s memset(fftBuf, 0, N_SAMPLES*sizeof(unsigned int)); memset(fftAvg, 0, N_SAMPLES*sizeof(unsigned int)); - memset(fftEHist, 0, sEnergyLen*sizeof(unsigned int)); - memset(sEnergy, 0, sEnergyLen*sizeof(unsigned int)); // open connection to mpd and set alarm to refresh status #ifdef STATUS_CHECK @@ -194,7 +173,7 @@ ret = read(fifo, (uint16_t*)buf, 2*nsamples); // process read buffer if(cnt == NICENESS) { - process_fifo(buf, fftBuf, fftAvg, sEnergy, nsamples, sEnergyLen); + process_fifo(buf, fftBuf, fftAvg, &energyBuffer, nsamples, &energyThreshold); cnt = 0; } else { cnt++; @@ -251,11 +230,10 @@ #endif free(fftAvg); free(fftBuf); - free(fftEHist); - free(sEnergy); + // cb_free(&energyBuffer); close(fifo); - if(cnt_over) return 1; + if(cnt_over) return 1; return 0; } diff --git a/src/settings.h b/src/settings.h index fd66ae9..56fef15 100644 --- a/src/settings.h +++ b/src/settings.h @@ -78,8 +78,8 @@ // adjust lateral shift on screen // some optimal values are provided // adjust based on terminal dimensions -#define X_CORRECTION 1 // 1280x1024 screens (5:4) -//#define X_CORRECTION 8 // 1920x1080 screens (16:9) +/* #define X_CORRECTION 0 // 1280x1024 screens (5:4) */ +#define X_CORRECTION 8 // 1920x1080 screens (16:9) /* =========== ALSA Support (WIP) ============ */