190 lines
3.7 KiB
C++
Executable File
190 lines
3.7 KiB
C++
Executable File
#ifndef ANALYZER_H
|
|
#define ANALYZER_H
|
|
|
|
//#define PLOT_ME
|
|
|
|
#ifdef PLOT_ME
|
|
#include <KLib/misc/gnuplot/Gnuplot.h>
|
|
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
|
#include <KLib/misc/gnuplot/GnuplotPlotElementLines.h>
|
|
#include <KLib/misc/gnuplot/GnuplotSplot.h>
|
|
#endif
|
|
|
|
#include "BiquadFilterGate.h"
|
|
#include "MovingAVG.h"
|
|
#include "EndlessAVG.h"
|
|
|
|
#include <iostream>
|
|
|
|
|
|
template <typename Scalar> struct BeatBand {
|
|
|
|
BiquadFilterGate<1> filter;
|
|
MovingAVG<Scalar> avgShort;
|
|
MovingAVG<Scalar> avgLong;
|
|
EndlessAVG<Scalar> avgAll;
|
|
|
|
BeatBand() : avgShort(800), avgLong(40000) {
|
|
avgAll.add(1);
|
|
}
|
|
|
|
float getMul() const {
|
|
return avgAll.get();
|
|
}
|
|
|
|
float add(Scalar s) {
|
|
|
|
const Scalar filtered = filter.filter(0, s) / getMul();
|
|
const Scalar filtered2 = filtered*filtered;
|
|
avgShort.add(filtered2); // short-term average (1/40 sec)
|
|
avgLong.add(filtered2); // long-term average (1sec)
|
|
avgAll.add(filtered2); // whole average (everything)
|
|
|
|
if (avgLong.get() < 0.0001) {return 0;}
|
|
|
|
const float delta = std::abs(avgShort.get()) / std::abs(avgLong.get());
|
|
//return (delta);
|
|
return avgShort.get();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
template <typename Scalar> class BeatDetection {
|
|
|
|
#ifdef PLOT_ME
|
|
K::Gnuplot gp;
|
|
K::GnuplotPlot plot;
|
|
K::GnuplotPlotElementLines lines0;
|
|
#endif
|
|
|
|
BeatBand<float> band0;
|
|
BeatBand<float> band1;
|
|
BeatBand<float> band2;
|
|
BeatBand<float> band3;
|
|
|
|
MovingAVG<float> avg1;
|
|
MovingAVG<float> avg2;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/** setup */
|
|
BeatDetection() : avg1(600), avg2(10000) {
|
|
setSampleRate(44100);
|
|
#ifdef PLOT_ME
|
|
plot.add(&lines0);
|
|
#endif
|
|
}
|
|
|
|
void setSampleRate(int srate) {
|
|
|
|
std::cout << "setting sample-rate to " << srate << std::endl;
|
|
//band0.filter.setBandPass(70, 1, srate); // base
|
|
band0.filter.setLowPass(100, 1, srate);
|
|
//band0.mul = 1;
|
|
band1.filter.setBandPass(3500, 1.0, srate); // claps
|
|
//band1.mul = 3.5;
|
|
band2.filter.setBandPass(10000, 0.4, srate); // snare???
|
|
//band2.mul = 5.5;
|
|
|
|
}
|
|
|
|
float area = 0;
|
|
int block = 0;
|
|
|
|
/** add single value */
|
|
bool add(Scalar s) {
|
|
|
|
// debug view
|
|
static int xxx = 0; ++xxx;
|
|
|
|
bool beat = false;
|
|
const float val = s / 32768.0f; // not needed
|
|
static int x = 0; x += 1;
|
|
float y0 = band0.add(val);
|
|
float y1 = 0;//band1.add(val);
|
|
float y2 = 0;//band2.add(val);
|
|
float y = std::abs(y0)+std::abs(y1*0.5)+std::abs(y2*0.7);
|
|
|
|
if (block > 0) {--block;}
|
|
|
|
if (y == y) {
|
|
//yy = yy * 0.99 + y * 0.01;
|
|
avg1.add(y);
|
|
avg2.add(y);
|
|
float yy = avg1.get() - avg2.get();
|
|
|
|
if (yy > 0.5 && !block) {
|
|
beat = true;
|
|
block = 9000;
|
|
}
|
|
|
|
// worked somewhat
|
|
// float limit = 0.10;
|
|
// if (yy > limit && block == 0) {
|
|
// area += (yy-limit);
|
|
// if (area > 1000) {
|
|
// beat = true;
|
|
// area = 0;
|
|
// block = 9000;
|
|
// }
|
|
// } else {
|
|
// area = 0;
|
|
// }
|
|
|
|
#ifdef PLOT_ME
|
|
if (xxx % 8 == 0) {
|
|
lines0.add(K::GnuplotPoint2(x, yy));
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
// debug view?
|
|
#ifdef PLOT_ME
|
|
if (xxx % 5000 == 0) {show();}
|
|
#endif
|
|
|
|
if (beat) {
|
|
std::cout << band0.getMul() << " " << band1.getMul() << " " << band2.getMul() << std::endl;
|
|
}
|
|
|
|
return beat;
|
|
|
|
}
|
|
|
|
/** add multiple values */
|
|
bool add(Scalar* s, int num) {
|
|
bool beat = false;
|
|
for (int i = 0; i < num; ++i) {
|
|
if (add(s[i])) {beat = true;}
|
|
}
|
|
return beat;
|
|
}
|
|
|
|
#ifdef PLOT_ME
|
|
void show() {
|
|
|
|
int limit = 8000;
|
|
int d0 = lines0.size() - limit;
|
|
if (d0 > 0) {
|
|
lines0.remove(0, d0);
|
|
}
|
|
|
|
int x0 = lines0[0].x;
|
|
int x1 = lines0[lines0.size()-1].x;
|
|
plot.getAxisX().setRange(x0, x1);
|
|
plot.getAxisY().setRange(-1, +5);
|
|
//plot.getAxisY().setRange(-32768, +32768);
|
|
gp.draw(plot);
|
|
gp.flush();
|
|
|
|
}
|
|
#endif
|
|
|
|
};
|
|
|
|
#endif // ANALYZER_H
|