Beat Detector Class

References : Posted by DSPMaster[at]free[dot]fr
Notes :
This class was designed for a VST plugin. Basically, it's just a 2nd order LP filter, followed by an enveloppe detector (thanks Bram), feeding a Schmitt trigger. The rising edge detector provides a 1-sample pulse each time a beat is detected. Code is self documented...
Note : The class uses a fixed comparison level, you may need to change it.
Code :
// ***** BEATDETECTOR.H *****
#ifndef BeatDetectorH
#define BeatDetectorH

class TBeatDetector
{
private:
  float KBeatFilter;        // Filter coefficient
  float Filter1Out, Filter2Out;
  float BeatRelease;        // Release time coefficient
  float PeakEnv;            // Peak enveloppe follower
  bool BeatTrigger;         // Schmitt trigger output
  bool PrevBeatPulse;       // Rising edge memory
public:
  bool BeatPulse;           // Beat detector output

  TBeatDetector();
  ~TBeatDetector();
  virtual void setSampleRate(float SampleRate);
  virtual void AudioProcess (float input);
};
#endif


// ***** BEATDETECTOR.CPP *****
#include "BeatDetector.h"
#include "math.h"

#define FREQ_LP_BEAT 150.0f    // Low Pass filter frequency
#define T_FILTER 1.0f/(2.0f*M_PI*FREQ_LP_BEAT)  // Low Pass filter time constant
#define BEAT_RTIME 0.02f  // Release time of enveloppe detector in second

TBeatDetector::TBeatDetector()
// Beat detector constructor
{
  Filter1Out=0.0;
  Filter2Out=0.0;
  PeakEnv=0.0;
  BeatTrigger=false;
  PrevBeatPulse=false;
  setSampleRate(44100);
}

TBeatDetector::~TBeatDetector()
{
  // Nothing specific to do...
}

void TBeatDetector::setSampleRate (float sampleRate)
// Compute all sample frequency related coeffs
{
  KBeatFilter=1.0/(sampleRate*T_FILTER);
  BeatRelease=(float)exp(-1.0f/(sampleRate*BEAT_RTIME));
}

void TBeatDetector::AudioProcess (float input)
// Process incoming signal
{
  float EnvIn;

  // Step 1 : 2nd order low pass filter (made of two 1st order RC filter)
  Filter1Out=Filter1Out+(KBeatFilter*(input-Filter1Out));
  Filter2Out=Filter2Out+(KBeatFilter*(Filter1Out-Filter2Out));

  // Step 2 : peak detector
  EnvIn=fabs(Filter2Out);
  if (EnvIn>PeakEnv) PeakEnv=EnvIn;  // Attack time = 0
  else
  {
    PeakEnv*=BeatRelease;
    PeakEnv+=(1.0f-BeatRelease)*EnvIn;
  }

  // Step 3 : Schmitt trigger
  if (!BeatTrigger)
  {
    if (PeakEnv>0.3) BeatTrigger=true;
  }
  else
  {
    if (PeakEnv<0.15) BeatTrigger=false;
  }

  // Step 4 : rising edge detector
  BeatPulse=false;
  if ((BeatTrigger)&&(!PrevBeatPulse))
    BeatPulse=true;
  PrevBeatPulse=BeatTrigger;
}

Comments
from : thaddy[AT]thaddy[DOT]com
comment : // Nice work! //Here's a Delphi and freepascal version: unit beattrigger; interface type TBeatDetector = class private KBeatFilter, // Filter coefficient Filter1Out, Filter2Out, BeatRelease, // Release time coefficient PeakEnv:single; // Peak enveloppe follower BeatTrigger, // Schmitt trigger output PrevBeatPulse:Boolean; // Rising edge memory public BeatPulse:Boolean; // Beat detector output constructor Create; procedure setSampleRate(SampleRate:single); procedure AudioProcess (input:single); end; function fabs(value:single):Single; implementation const FREQ_LP_BEAT = 150.0; // Low Pass filter frequency T_FILTER = 1.0/(2.0 * PI*FREQ_LP_BEAT); // Low Pass filter time constant BEAT_RTIME = 0.02; // Release time of enveloppe detector in second constructor TBeatDetector.create; // Beat detector constructor begin inherited; Filter1Out:=0.0; Filter2Out:=0.0; PeakEnv:=0.0; BeatTrigger:=false; PrevBeatPulse:=false; setSampleRate(44100); end; procedure TBeatDetector.setSampleRate (sampleRate:single); // Compute all sample frequency related coeffs begin KBeatFilter:=1.0/(sampleRate*T_FILTER); BeatRelease:= exp(-1.0/(sampleRate*BEAT_RTIME)); end; function fabs(value:single):Single; asm fld value fabs fwait end; procedure TBeatDetector.AudioProcess (input:single); var EnvIn:Single; // Process incoming signal begin // Step 1 : 2nd order low pass filter (made of two 1st order RC filter) Filter1Out:=Filter1Out+(KBeatFilter*(input-Filter1Out)); Filter2Out:=Filter2Out+(KBeatFilter*(Filter1Out-Filter2Out)); // Step 2 : peak detector EnvIn:=fabs(Filter2Out); if EnvIn>PeakEnv then PeakEnv:=EnvIn // Attack time = 0 else begin PeakEnv:=PeakEnv*BeatRelease; PeakEnv:=PeakEnv+(1.0-BeatRelease)*EnvIn; end; // Step 3 : Schmitt trigger if not BeatTrigger then begin if PeakEnv>0.3 then BeatTrigger:=true; end else begin if PeakEnv<0.15 then BeatTrigger:=false; end; // Step 4 : rising edge detector BeatPulse:=false; if (BeatTrigger = true ) and( not PrevBeatPulse) then BeatPulse:=true; PrevBeatPulse:=BeatTrigger; end; end.

from : foo[AT]bar[DOT]baz
comment : If you have virtual methods the destructor should be virtual as well as otherwise the destruction of derived objects is undefined.

from : thaddy[AT]thaddy[DOT]com
comment : This already - implied - the case in the PAS version. The above comment holds only for the C++ version, but makes sense to me.

from : kwolff[AT]intra-team[DOT]de
comment : Can you tell me how to implement the variable bpm, to get the beats per minute? Thanx, Kris

from : ata_n[AT]hotmail[DOT]com
comment : Im having a hard time setting the comparison level. My audio data is signed 16 bit integers, so I have set the levels at (0.3*32768) and (0.15*32768)... ive tried different levels, nothing responds correctly.. any ideas anyone? Thanks, Ata

from : lindathorn[AT]mail15[DOT]com
comment : Following my own monitoring, thousands of people on our planet receive the <a href="http://bestfinance-blog.com/topics/mortgage-loans">mortgage loans</a> from good creditors. Thus, there is good possibilities to find a auto loan in all countries.

from : lindathorn[AT]mail15[DOT]com
comment : Some time before, I needed to buy a car for my corporation but I didn't have enough money and couldn't order something. Thank God my father suggested to try to take the loan from reliable creditors. Therefore, I did so and used to be happy with my small business loan.

from : nyc10003[AT]nyc[DOT]rr[DOT]com
comment : Can I use the code on the Schmitt trigger for an iPhone app that I may be selling? Is there a fee?

from : nikolatesla20[AT]gmail[DOT]com
comment : I can't seem to actually get this to work at all...

from : sadsakurasad[AT]yahoo[DOT]com
comment : This is really good content, I praise what you've done right here, along with sharing excellent information with great tips. Thank you! http://www.friv3go.com

from : htmlfriv
comment : like my content of the ban, it is very hay and really is meaningful for me http://www.bestgamesy8.org/ | y8 |http://www.games2girlsdressup.com/ http://www.kizi100games.info/ Kizi