Requires: bass.dll - available @ www.un4seen.com.
Assembly: Bass.Net (in Bass.Net.dll) Version: 188.8.131.52
public sealed class BPMCounter
Public NotInheritable Class BPMCounter
public ref class BPMCounter sealed
[<SealedAttribute>] type BPMCounter = class end
Thetype exposes the following members.
The contructor of the beat detection class.
Gets or sets the currently detected live BPM value (detected via ProcessAudio(Int32, Boolean)).
Gets or Sets the BPM history buffer size (Minimum=2, Maximum=50, Default=10).
Gets or sets the maximum BPM value (default is 180, maximum is 250).
Gets or sets the minimum BPM value (default is 60, minimum is 30).
Gets or sets the manually tapped BPM value (detected via TapBeat).
Processes the audio data (gets instant FFT samples) and calculates the live BPM.
Call this to reset all internal buffers and/or to change the current samplerate of the audio signal to be processed.
Call this method to change the current samplerate of the audio signal to be processed.
Call this to set (tap) a beat manually (e.g. on a mouse click event). The resulting (tapped) BPM value is available at TappedBPM.
The BPMCounter class is an internal implementation of the BASS.NET API and does not require any additional extension or add-on to the BASS audio library, meaning only bass.dll is required.
However, BASS_Init(Int32, Int32, BASSInit, IntPtr) must have been called before using any method within this class!
NOTE: When using the BPMCounter class with an already existing decoding channel (created with the BASS_STREAM_DECODE flag) the data will be retrieved from that channel, meaning the data will be 'stolen'. So it is NOT recommended to use this class with any decoding streams.
Internally the algo is based on human ear simulation - meaning an average energy history of 1 second is used, since this is what the human ear can keep - so the BPM results might change and vary more often as with systems scanning the whole file or bigger parts of it. The advantage is therefore that this system might be used with live data and has a fast reaction time of about 1 second only - like our human ear.
The typical use of this class is as followed:
a) create an instance of this class (e.g. at the beginning of your application)
b) use a timer callback (e.g. every 20ms or every 25ms) to process the audio signal (the timer frequency must be specified when creating the class instance).
c) in the timer callback call ProcessAudio(Int32, Boolean) to detect a beat.
d) retrieve the BPM propertiy to get the calculated Beats Per Minute value.
You should call the Reset(Int32) method whenever you play another stream or if the returned BPM looks completely wrong.
There are also methods to calculate the BPM manually using a TAP click button. E.g. call TapBeat on a mouse click event to tap (set) a beat manually and call TappedBPM to retrieve the manually tapped BPM value.
Beat detection is a very very complex task and it is almost impossible to implement it matching for any kind of audio signal. So please note, that it might NOT work with all tracks in the same way - with some tracks it might return really bad results. This implementation is a 'simple' one (not needing too much CPU power). It is based on instant energy calculation on 128 frequency bands and comparing them with it's average engery for that band. The variation of the energy of each frequency band is used as a dynamic sensitivity factor. The peak detector uses an attack time of 0ms and there is a dynamic release envelop for the release time - plus we have a Schmitt triggers and a rising edge detectors implemented for each frequency band. The low pass frequency has a fixed value of 350Hz (for detecting bass drums) and the mid range frequency is set to be between 1500Hz and 4000Hz (to detect e.g. snare drums). This to calculate an overall trigger value for all frequency bands. Finally there is a Schmitt trigger again to detect the final beat for each call to the audio signal processing.
You might notice, that often more beats are detected as you would recognize them with your ear (when doing manual tapping). These are intermediate beats or simply lound noise in the signal (which the algo did not filter good enough). So the BPM calculation uses a time spotting approximation to determine when a beat is a good beat to count. 'No-good' beats are simply not counted. So it sometimes might take some time until the live BPM value reaches a good value!
Note: 1 BPM is worth about 5ms (at 120BMP) - or in other words: if your time intervall differs in 5ms the resulting BPM might have a difference of about 1 BPM. Therefor we use a BPM history buffer which we interleave and calculate the average to equalize this effect.
The BPM results are not equally good for all music tracks and genres. However, beat detection and BPM calculation is mostly needed for DJ applications with music having mostly clear and distinct beats and for this kind of music the class produces very good results. Also keep in mind, that when working with highly compressed or equalized tracks (e.g. badly encoded MP3 tracks) the quality might also suffer - so for best results use good audio material.