mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-06 00:55:30 +00:00
attempt to improve freq responsiveness
This commit is contained in:
@ -74,11 +74,15 @@ void PCM::_initPCM(int samples) {
|
||||
start=0;
|
||||
|
||||
//Allocate FFT workspace
|
||||
w= (double *)wipemalloc(maxsamples*sizeof(double));
|
||||
ip= (int *)wipemalloc(maxsamples*sizeof(int));
|
||||
// per rdft() documentation
|
||||
// length of ip >= 2+sqrt(n) and length of w == n/2
|
||||
#if FFT_LENGTH > 1024
|
||||
#error update this code
|
||||
#endif
|
||||
w = (double *)wipemalloc(FFT_LENGTH/2*sizeof(double));
|
||||
ip = (int *)wipemalloc(34 * sizeof(int));
|
||||
ip[0]=0;
|
||||
|
||||
|
||||
/** PCM data */
|
||||
// this->maxsamples = 2048;
|
||||
// this->numsamples = 0;
|
||||
@ -134,8 +138,8 @@ void PCM::addPCMfloat(const float *PCMdata, int samples)
|
||||
if (newsamples>maxsamples) newsamples=maxsamples;
|
||||
numsamples = getPCMnew(pcmdataR,1,0,waveSmoothing,0,0);
|
||||
getPCMnew(pcmdataL,0,0,waveSmoothing,0,1);
|
||||
getPCM(vdataL,512,0,1,0,0);
|
||||
getPCM(vdataR,512,1,1,0,0);
|
||||
getPCM(vdataL,FFT_LENGTH,0,1,0,0);
|
||||
getPCM(vdataR,FFT_LENGTH,1,1,0,0);
|
||||
}
|
||||
|
||||
|
||||
@ -158,8 +162,8 @@ void PCM::addPCMfloat_2ch(const float *PCMdata, int samples)
|
||||
newsamples=maxsamples;
|
||||
numsamples = getPCMnew(pcmdataR,1,0,waveSmoothing,0,0);
|
||||
getPCMnew(pcmdataL,0,0,waveSmoothing,0,1);
|
||||
getPCM(vdataL,512,0,1,0,0);
|
||||
getPCM(vdataR,512,1,1,0,0);
|
||||
getPCM(vdataL,FFT_LENGTH,0,1,0,0);
|
||||
getPCM(vdataR,FFT_LENGTH,1,1,0,0);
|
||||
}
|
||||
|
||||
|
||||
@ -178,8 +182,8 @@ void PCM::addPCM16Data(const short* pcm_data, short samples) {
|
||||
if (newsamples>maxsamples) newsamples=maxsamples;
|
||||
numsamples = getPCMnew(pcmdataR,1,0,waveSmoothing,0,0);
|
||||
getPCMnew(pcmdataL,0,0,waveSmoothing,0,1);
|
||||
getPCM(vdataL,512,0,1,0,0);
|
||||
getPCM(vdataR,512,1,1,0,0);
|
||||
getPCM(vdataL,FFT_LENGTH,0,1,0,0);
|
||||
getPCM(vdataR,FFT_LENGTH,1,1,0,0);
|
||||
}
|
||||
|
||||
|
||||
@ -210,8 +214,8 @@ void PCM::addPCM16(short PCMdata[2][512])
|
||||
|
||||
numsamples = getPCMnew(pcmdataR,1,0,waveSmoothing,0,0);
|
||||
getPCMnew(pcmdataL,0,0,waveSmoothing,0,1);
|
||||
getPCM(vdataL,512,0,1,0,0);
|
||||
getPCM(vdataR,512,1,1,0,0);
|
||||
getPCM(vdataL,FFT_LENGTH,0,1,0,0);
|
||||
getPCM(vdataR,FFT_LENGTH,1,1,0,0);
|
||||
}
|
||||
|
||||
|
||||
@ -243,8 +247,8 @@ void PCM::addPCM8( unsigned char PCMdata[2][1024])
|
||||
if (newsamples>maxsamples) newsamples=maxsamples;
|
||||
numsamples = getPCMnew(pcmdataR,1,0,waveSmoothing,0,0);
|
||||
getPCMnew(pcmdataL,0,0,waveSmoothing,0,1);
|
||||
getPCM(vdataL,512,0,1,0,0);
|
||||
getPCM(vdataR,512,1,1,0,0);
|
||||
getPCM(vdataL,FFT_LENGTH,0,1,0,0);
|
||||
getPCM(vdataR,FFT_LENGTH,1,1,0,0);
|
||||
}
|
||||
|
||||
void PCM::addPCM8_512( const unsigned char PCMdata[2][512])
|
||||
@ -275,8 +279,8 @@ void PCM::addPCM8_512( const unsigned char PCMdata[2][512])
|
||||
if (newsamples>maxsamples) newsamples=maxsamples;
|
||||
numsamples = getPCMnew(pcmdataR,1,0,waveSmoothing,0,0);
|
||||
getPCMnew(pcmdataL,0,0,waveSmoothing,0,1);
|
||||
getPCM(vdataL,512,0,1,0,0);
|
||||
getPCM(vdataR,512,1,1,0,0);
|
||||
getPCM(vdataL,FFT_LENGTH,0,1,0,0);
|
||||
getPCM(vdataR,FFT_LENGTH,1,1,0,0);
|
||||
}
|
||||
|
||||
|
||||
@ -291,43 +295,57 @@ void PCM::addPCM8_512( const unsigned char PCMdata[2][512])
|
||||
|
||||
void PCM::getPCM(float *PCMdata, int samples, int channel, int freq, float smoothing, int derive)
|
||||
{
|
||||
int index;
|
||||
|
||||
index=start-1;
|
||||
|
||||
if (index<0) index=maxsamples+index;
|
||||
|
||||
PCMdata[0]=PCMd[channel][index];
|
||||
|
||||
for(int i=1;i<samples;i++)
|
||||
if (smoothing == 0)
|
||||
{
|
||||
index=start-1-i;
|
||||
if (index<0) index=maxsamples+index;
|
||||
for (int i = 0; i < samples; i++)
|
||||
{
|
||||
int index = start - 1 - i;
|
||||
if (index < 0)
|
||||
index = maxsamples + index;
|
||||
PCMdata[i] = PCMd[channel][index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index=start-1;
|
||||
|
||||
PCMdata[i]=(1-smoothing)*PCMd[channel][index]+smoothing*PCMdata[i-1];
|
||||
if (index<0)
|
||||
index=maxsamples+index;
|
||||
|
||||
PCMdata[0] = PCMd[channel][index];
|
||||
|
||||
for (int i = 1; i < samples; i++)
|
||||
{
|
||||
index = start - 1 - i;
|
||||
if (index < 0)
|
||||
index = maxsamples + index;
|
||||
PCMdata[i] = (1 - smoothing) * PCMd[channel][index] + smoothing * PCMdata[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
//return derivative of PCM data
|
||||
if(derive)
|
||||
if (derive)
|
||||
{
|
||||
for(int i=0;i<samples-1;i++)
|
||||
{
|
||||
PCMdata[i]=PCMdata[i]-PCMdata[i+1];
|
||||
}
|
||||
{
|
||||
PCMdata[i]=PCMdata[i]-PCMdata[i+1];
|
||||
}
|
||||
PCMdata[samples-1]=0;
|
||||
}
|
||||
|
||||
//return frequency data instead of PCM (perform FFT)
|
||||
|
||||
if (freq)
|
||||
|
||||
{
|
||||
// NOTE some presets set bSpectrum=1 and samples!=2^n, not sure what rdft() does with that
|
||||
assert(samples <= 1024);
|
||||
samples = std::min(1024,samples);
|
||||
double temppcm[1024];
|
||||
for (int i=0;i<samples;i++)
|
||||
{temppcm[i]=(double)PCMdata[i];}
|
||||
{temppcm[i]=(double)PCMdata[i];}
|
||||
rdft(samples, 1, temppcm, ip, w);
|
||||
for (int j=0;j<samples;j++)
|
||||
{PCMdata[j]=(float)temppcm[j];}
|
||||
{PCMdata[j]=(float)temppcm[j];}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,11 @@
|
||||
|
||||
#include "dlldefs.h"
|
||||
|
||||
|
||||
// 1024 is more computationally intensive, but maybe better at detecting lower bass
|
||||
#define FFT_LENGTH 512
|
||||
|
||||
|
||||
class
|
||||
#ifdef WIN32
|
||||
DLLEXPORT
|
||||
@ -52,8 +57,8 @@ public:
|
||||
float *pcmdataR; //holder for most recent pcm data
|
||||
|
||||
/** PCM data */
|
||||
float vdataL[512]; //holders for FFT data (spectrum)
|
||||
float vdataR[512];
|
||||
float vdataL[FFT_LENGTH]; //holders for FFT data (spectrum)
|
||||
float vdataR[FFT_LENGTH];
|
||||
|
||||
static int maxsamples;
|
||||
PCM();
|
||||
|
||||
@ -36,31 +36,32 @@
|
||||
#include <cmath>
|
||||
#include "BeatDetect.hpp"
|
||||
|
||||
BeatDetect::BeatDetect(PCM *_pcm) {
|
||||
int x,y;
|
||||
|
||||
this->pcm=_pcm;
|
||||
BeatDetect::BeatDetect(PCM *_pcm)
|
||||
{
|
||||
this->pcm=_pcm;
|
||||
|
||||
this->vol_instant=0;
|
||||
this->vol_history=0;
|
||||
this->vol_instant=0;
|
||||
this->vol_history=0;
|
||||
for (unsigned y=0;y<80;y++)
|
||||
this->vol_buffer[y]=0;
|
||||
|
||||
for (y=0;y<80;y++)
|
||||
{
|
||||
this->vol_buffer[y]=0;
|
||||
}
|
||||
this->beat_buffer_pos=0;
|
||||
|
||||
this->beat_buffer_pos=0;
|
||||
this->bass_instant = 0;
|
||||
this->bass_history = 0;
|
||||
for (unsigned y=0;y<80;y++)
|
||||
this->bass_buffer[y]=0;
|
||||
|
||||
for (x=0;x<32;x++) {
|
||||
this->beat_instant[x]=0;
|
||||
this->beat_history[x]=0;
|
||||
this->beat_val[x]=1.0;
|
||||
this->beat_att[x]=1.0;
|
||||
this->beat_variance[x]=0;
|
||||
for (y=0;y<80;y++) {
|
||||
this->beat_buffer[x][y]=0;
|
||||
}
|
||||
}
|
||||
this->mid_instant = 0;
|
||||
this->mid_history = 0;
|
||||
for (unsigned y=0;y<80;y++)
|
||||
this->mid_buffer[y]=0;
|
||||
|
||||
this->treb_instant = 0;
|
||||
this->treb_history = 0;
|
||||
for (unsigned y=0;y<80;y++)
|
||||
this->treb_buffer[y]=0;
|
||||
|
||||
this->treb = 0;
|
||||
this->mid = 0;
|
||||
@ -72,119 +73,119 @@ BeatDetect::BeatDetect(PCM *_pcm) {
|
||||
this->bass_att = 0;
|
||||
this->vol_att = 0;
|
||||
this->vol = 0;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BeatDetect::~BeatDetect()
|
||||
|
||||
BeatDetect::~BeatDetect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BeatDetect::reset() {
|
||||
this->treb = 0;
|
||||
this->mid = 0;
|
||||
this->bass = 0;
|
||||
this->treb_att = 0;
|
||||
this->mid_att = 0;
|
||||
this->bass_att = 0;
|
||||
this->vol_att = 0;
|
||||
}
|
||||
|
||||
void BeatDetect::detectFromSamples() {
|
||||
vol_old = vol;
|
||||
bass=0;mid=0;treb=0;
|
||||
|
||||
getBeatVals(pcm->pcmdataL,pcm->pcmdataR);
|
||||
}
|
||||
|
||||
void BeatDetect::getBeatVals( float *vdataL,float *vdataR ) {
|
||||
|
||||
int linear=0;
|
||||
int x,y;
|
||||
float temp2=0;
|
||||
|
||||
vol_instant=0;
|
||||
for ( x=0;x<16;x++)
|
||||
{
|
||||
|
||||
beat_instant[x]=0;
|
||||
for ( y=linear*2;y<(linear+8+x)*2;y++)
|
||||
{
|
||||
beat_instant[x]+=((vdataL[y]*vdataL[y])+(vdataR[y]*vdataR[y]))*(1.0/(8+x));
|
||||
// printf( "beat_instant[%d]: %f %f %f\n", x, beat_instant[x], vdataL[y], vdataR[y] );
|
||||
vol_instant+=((vdataL[y]*vdataL[y])+(vdataR[y]*vdataR[y]))*(1.0/512.0);
|
||||
|
||||
}
|
||||
//printf("1");
|
||||
linear=y/2;
|
||||
beat_history[x]-=(beat_buffer[x][beat_buffer_pos])*.0125;
|
||||
beat_buffer[x][beat_buffer_pos]=beat_instant[x];
|
||||
beat_history[x]+=(beat_instant[x])*.0125;
|
||||
|
||||
beat_val[x]=(beat_instant[x])/(beat_history[x]);
|
||||
|
||||
beat_att[x]+=(beat_instant[x])/(beat_history[x]);
|
||||
|
||||
//printf("2\n");
|
||||
|
||||
}
|
||||
//printf("b\n");
|
||||
vol_history-=(vol_buffer[beat_buffer_pos])*.0125;
|
||||
vol_buffer[beat_buffer_pos]=vol_instant;
|
||||
vol_history+=(vol_instant)*.0125;
|
||||
|
||||
mid=0;
|
||||
for(x=1;x<10;x++)
|
||||
{
|
||||
mid+=(beat_instant[x]);
|
||||
temp2+=(beat_history[x]);
|
||||
|
||||
}
|
||||
|
||||
mid=mid/(1.5*temp2);
|
||||
temp2=0;
|
||||
treb=0;
|
||||
for(x=10;x<16;x++)
|
||||
{
|
||||
treb+=(beat_instant[x]);
|
||||
temp2+=(beat_history[x]);
|
||||
}
|
||||
//printf("c\n");
|
||||
treb=treb/(1.5*temp2);
|
||||
// *vol=vol_instant/(1.5*vol_history);
|
||||
vol=vol_instant/(1.5*vol_history);
|
||||
|
||||
bass=(beat_instant[0])/(1.5*beat_history[0]);
|
||||
|
||||
|
||||
if ( projectM_isnan( treb ) ) {
|
||||
treb = 0.0;
|
||||
}
|
||||
if ( projectM_isnan( mid ) ) {
|
||||
mid = 0.0;
|
||||
}
|
||||
if ( projectM_isnan( bass ) ) {
|
||||
bass = 0.0;
|
||||
}
|
||||
treb_att=.6 * treb_att + .4 * treb;
|
||||
mid_att=.6 * mid_att + .4 * mid;
|
||||
bass_att=.6 * bass_att + .4 * bass;
|
||||
vol_att=.6 * vol_att + .4 * vol;
|
||||
|
||||
if(bass_att>100)bass_att=100;
|
||||
if(bass >100)bass=100;
|
||||
if(mid_att>100)mid_att=100;
|
||||
if(mid >100)mid=100;
|
||||
if(treb_att>100)treb_att=100;
|
||||
if(treb >100)treb=100;
|
||||
if(vol_att>100)vol_att=100;
|
||||
if(vol>100)vol=100;
|
||||
|
||||
// *vol=(beat_instant[3])/(beat_history[3]);
|
||||
beat_buffer_pos++;
|
||||
if( beat_buffer_pos>79)beat_buffer_pos=0;
|
||||
|
||||
void BeatDetect::reset()
|
||||
{
|
||||
this->treb = 0;
|
||||
this->mid = 0;
|
||||
this->bass = 0;
|
||||
this->treb_att = 0;
|
||||
this->mid_att = 0;
|
||||
this->bass_att = 0;
|
||||
this->vol_att = 0;
|
||||
this->vol_old = 0;
|
||||
this->vol_instant=0;
|
||||
}
|
||||
|
||||
|
||||
void BeatDetect::detectFromSamples()
|
||||
{
|
||||
vol_old = vol;
|
||||
bass=0;
|
||||
mid=0;
|
||||
treb=0;
|
||||
vol=0;
|
||||
|
||||
// TODO: get sample rate from PCM? Assume 44100
|
||||
getBeatVals(44100.0f, FFT_LENGTH, pcm->pcmdataL, pcm->pcmdataR);
|
||||
}
|
||||
|
||||
|
||||
void BeatDetect::getBeatVals( float samplerate, unsigned fft_length, float *vdataL, float *vdataR )
|
||||
{
|
||||
assert( 512==fft_length || 1024==fft_length ); // should be power of 2, expect >= 512
|
||||
|
||||
// TODO: compute ranges based on samplerate
|
||||
unsigned ranges512[4] = {0, 3, 23, 200};
|
||||
unsigned ranges1024[4] = {0, 5, 46, 400};
|
||||
unsigned *ranges = fft_length==1024 ? ranges1024 : ranges512;
|
||||
|
||||
bass_instant = 0;
|
||||
for (unsigned i=ranges[0]+1 ; i<=ranges[1] ; i++)
|
||||
{
|
||||
bass_instant += (vdataL[i*2]*vdataL[i*2]) + (vdataR[i*2]*vdataR[i*2]);
|
||||
}
|
||||
bass_instant *= 100.0/(ranges[1]-ranges[0]);
|
||||
bass_history -= bass_buffer[beat_buffer_pos] *.0125;
|
||||
bass_buffer[beat_buffer_pos] = bass_instant;
|
||||
bass_history += bass_instant *.0125;
|
||||
|
||||
mid_instant = 0;
|
||||
for (unsigned i=ranges[1]+1 ; i<=ranges[2] ; i++)
|
||||
{
|
||||
mid_instant += (vdataL[i*2]*vdataL[i*2]) + (vdataR[i*2]*vdataR[i*2]);
|
||||
}
|
||||
mid_instant *= 100.0/(ranges[2]-ranges[1]);
|
||||
mid_history -= mid_buffer[beat_buffer_pos] *.0125;
|
||||
mid_buffer[beat_buffer_pos] = mid_instant;
|
||||
mid_history += mid_instant *.0125;
|
||||
|
||||
treb_instant = 0;
|
||||
for (unsigned i=ranges[2]+1 ; i<=ranges[3] ; i++)
|
||||
{
|
||||
treb_instant += (vdataL[i*2]*vdataL[i*2]) + (vdataR[i*2]*vdataR[i*2]);
|
||||
}
|
||||
treb_instant *= 90.0/(ranges[3]-ranges[2]);
|
||||
treb_history -= treb_buffer[beat_buffer_pos] *.0125;
|
||||
treb_buffer[beat_buffer_pos] = treb_instant;
|
||||
treb_history += treb_instant *.0125;
|
||||
|
||||
vol_instant = (bass_instant + mid_instant + treb_instant) / 3.0f;
|
||||
vol_history -= (vol_buffer[beat_buffer_pos])*.0125;
|
||||
vol_buffer[beat_buffer_pos] = vol_instant;
|
||||
vol_history += (vol_instant)*.0125;
|
||||
|
||||
// fprintf(stderr, "%6.3f %6.2f %6.3f\n", bass_history/vol_history, mid_history/vol_history, treb_history/vol_history);
|
||||
bass = bass_instant / fmax(0.0001, bass_history + 0.5*vol_history);
|
||||
mid = mid_instant / fmax(0.0001, mid_history + 0.5*vol_history);
|
||||
treb = treb_instant / fmax(0.0001, treb_history + 0.5*vol_history);
|
||||
vol = vol_instant / fmax(0.0001, 1.5f * vol_history);
|
||||
|
||||
if ( projectM_isnan( treb ) ) {
|
||||
treb = 0.0;
|
||||
}
|
||||
if ( projectM_isnan( mid ) ) {
|
||||
mid = 0.0;
|
||||
}
|
||||
if ( projectM_isnan( bass ) ) {
|
||||
bass = 0.0;
|
||||
}
|
||||
|
||||
treb_att = .6f * treb_att + .4f * treb;
|
||||
mid_att = .6f * mid_att + .4f * mid;
|
||||
bass_att = .6f * bass_att + .4f * bass;
|
||||
vol_att = .6f * vol_att + .4f * vol;
|
||||
|
||||
if (bass_att>100) bass_att=100;
|
||||
if (bass >100) bass=100;
|
||||
if (mid_att>100) mid_att=100;
|
||||
if (mid >100) mid=100;
|
||||
if (treb_att>100) treb_att=100;
|
||||
if (treb >100) treb=100;
|
||||
if (vol_att>100) vol_att=100;
|
||||
if (vol>100) vol=100;
|
||||
|
||||
beat_buffer_pos++;
|
||||
if (beat_buffer_pos>79)
|
||||
beat_buffer_pos=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ class DLLEXPORT BeatDetect
|
||||
void initBeatDetect();
|
||||
void reset();
|
||||
void detectFromSamples();
|
||||
void getBeatVals ( float *vdataL, float *vdataR );
|
||||
void getBeatVals( float samplerate, unsigned fft_length, float *vdataL, float *vdataR );
|
||||
float getPCMScale()
|
||||
{
|
||||
// added to address https://github.com/projectM-visualizer/projectm/issues/161
|
||||
@ -74,17 +74,34 @@ class DLLEXPORT BeatDetect
|
||||
}
|
||||
|
||||
private:
|
||||
/** Vars */
|
||||
float beat_buffer[32][80],
|
||||
beat_instant[32],
|
||||
beat_history[32];
|
||||
float beat_val[32],
|
||||
beat_att[32],
|
||||
beat_variance[32];
|
||||
int beat_buffer_pos;
|
||||
float vol_buffer[80],
|
||||
vol_instant;
|
||||
float vol_history;
|
||||
float bass_buffer[80];
|
||||
float bass_history;
|
||||
float bass_instant;
|
||||
|
||||
float mid_buffer[80];
|
||||
float mid_history;
|
||||
float mid_instant;
|
||||
|
||||
float treb_buffer[80];
|
||||
float treb_history;
|
||||
float treb_instant;
|
||||
|
||||
float vol_buffer[80];
|
||||
float vol_history;
|
||||
float vol_instant;
|
||||
|
||||
// /** Vars */
|
||||
// float beat_buffer[32][80],
|
||||
// beat_instant[32],
|
||||
// beat_history[32];
|
||||
// float beat_val[32],
|
||||
// beat_att[32],
|
||||
// beat_variance[32];
|
||||
// int beat_buffer_pos;
|
||||
// float vol_buffer[80],
|
||||
// vol_instant;
|
||||
// float vol_history;
|
||||
};
|
||||
|
||||
#endif /** !_BEAT_DETECT_H */
|
||||
|
||||
Reference in New Issue
Block a user