#ifndef ANALYZER_H #define ANALYZER_H #include #include #include #include #include "BiquadFilterGate.h" #include "MovingAVG.h" #include "EndlessAVG.h" #include template struct BeatBand { BiquadFilterGate<1> filter; MovingAVG avgShort; MovingAVG avgLong; EndlessAVG 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 class BeatDetection { K::Gnuplot gp; K::GnuplotPlot plot; K::GnuplotPlotElementLines lines0; BeatBand band0; BeatBand band1; BeatBand band2; BeatBand band3; MovingAVG avg1; MovingAVG avg2; public: /** setup */ BeatDetection() : avg1(600), avg2(10000) { setSampleRate(44100); plot.add(&lines0); } 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; // } if (xxx % 8 == 0) { lines0.add(K::GnuplotPoint2(x, yy)); } } // debug view? if (xxx % 5000 == 0) {show();} 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; } 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 // ANALYZER_H