views:

4220

answers:

11

I'd like to write a simple C# application to monitor the line-in audio and give me the current (well, the rolling average) beats per minute.

I've seen this gamedev article, and that was absolutely no help. I went through and tried to implement what he was doing but it just wasn't working.

I know there have to be tons of solutions for this, because lots of DJ software does it, but I'm not having any luck in finding any open-source library or instructions on doing it myself.

+3  A: 

This is by no means an easy problem. I'll try to give you an overview only.

What you could do is something like the following:

  1. Compute the average (root-mean-square) loudness of the signal over blocks of, say, 5 milliseconds. (Having never done this before, I don't know what a good block size would be.)
  2. Take the Fourier transform of the "blocked" signal, using the FFT algorithm.
  3. Find the component in the transformed signal that has the largest magnitude.

A Fourier transform is basically a way of computing the strength of all frequencies present in the signal. If you do that over the "blocked" signal, the frequency of the beat will hopefully be the strongest one.

Maybe you need to apply a filter first, to focus on specific frequencies (like the bass) that usually contain the most information about the BPM.

Thomas
A: 

And that's the problem... that's what the article went over. But changing that into working code is where I have the problems. I was using an FFT and what was supposed to have been an energy-finding algorithm, but I wasn't getting results that made any sense at all.

Karl
+3  A: 

Not that I have a clue how to implement this, but from an audio engineering perspective you'd need to filter first. Bass drum hits would be the first to check. A low pass filter that gives you anything under about 200Hz should give you a pretty clear picture of the bass drum. A gate might also be necessary to cleanup any clutter from other instruments with harmonics that low.

The next to check would be snare hits. You'd have to EQ this one. The "crack" from a snare is around 1.5kHz from memory, but you'd need to definitely gate this one.

The next challenge would be to work out an algorithm for funky beats. How would you programatically find beat 1? I guess you'd keep track of previous beats and use a pattern matching something-or-other. So, you'd probably need a few bars to accurately find the beat. Then there's timing issues like 4/4, 3/4, 6/8, wow, I can't imagine what would be required to do this accurately! I'm sure it'd be worth some serious money to audio hardware/software companies.

Dan Harper - Leopard CRM
+2  A: 

This is the article I had been reading: http://www.gamedev.net/reference/programming/features/beatdetection/

Karl
A: 

@Thomas:

  1. Compute the average (root-mean-square) loudness of the signal over blocks of, say, 5 milliseconds. (Having never done this before, I don't know what a good block size would be.)
  2. Take the Fourier transform of the "blocked" signal, using the FFT algorithm.
  3. Find the component in the transformed signal that has the largest magnitude.

I can't really see why you rms signal first, and why it is done on blocks (as FFT usually works on windows of the signal anyway). Further more the FFT would give you the signal shifted into an energy-time domain so that is really the same as the first step.

Disclaimer is that I haven't done this either and haven't really thought this through properly yet, but depending on how advanced you'd want this algorithm to be. The lowest level implementation that might work (depending on type of music) is just looking at RMS and timing the signal peak-to-peak. For music with typical heavy beats (ie. most "modern" music) this could potentially work. As other people wrote, passing it through a low-pass filter first might improve the results.

+8  A: 

There's an excellent project called Dancing Monkeys, which procedurally generates DDR dance steps from music. A large part of what it does is based on (necessarily very accurate) beat analysis, and their project paper goes into much detail describing the various beat detection algorithms and their suitability to the task. They include references to the original papers for each of the algorithms. They've also published the matlab code for their solution. I'm sure that between those you can find what you need.

It's all available here: http://monket.net/dancing-monkeys-v2/Main_Page

Nick Johnson
+13  A: 

Calculate a powerspectrum with a sliding window FFT: Take 1024 samples:

double[] signal = stream.Take(1024);

Feed it to an FFT algorithm:

double[] real = new double[signal.Length];
double[] imag = new double[signal.Length);
FFT(signal, out real, out imag);

You will get a real part and an imaginary part. Throw away the imaginary part. It is the phase and you do not need it.

Calculate the power as opposed to the amplitude so that you have a high number when it is loud and close to zero when it is quiet:

for (i=0; i < real.Length; i++) real[i] = real[i] * real[i];

Now you have a power spectrum for the last 1024 samples. Where the first part of the spectrum is the low frequencies and the last part of the spectrum is the high frequencies.

If you want to find BPM in popular music you should probably focus on the bass. You can pick up the bass intensity by summing the lower part of the power spectrum. Which numbers to use depends on the sampling frequency:

double bassIntensity = 0;
for (i=8; i < 96; i++) bassIntensity += real[i];

Now do the same again but move the window 256 samples before you calculate a new spectrum. Now you end up with calculating the bassIntensity for every 256 samples.

This is a good input for your BPM analysis. When the bass is quiet you do not have a beat and when it is loud you have a beat.

Good luck!

Hallgrim
You do realize that with just 1024 samples you will not be able to calculate the BPM (beats per MINUTE)... right? You are just calculating the top frequency in that "tiny" 1024-bytes long sample.
Sacha
It is correct that I calculate the top frequency in a tiny sample, but then I suggested to move the window 256 samples and calculate it again. The result is a series that can be used to calculate the BPM. I only described how to solve the first part of the problem.
Hallgrim
Sacha it's just a matter of scaling units. You don't need to analyze a minute's worth of samples before you can calculate the BPM. BPM is just a more musical way of conveying the period of a signal.
Bob Somers
Don't throw away the imaginary component, it is _not_ just the phase! The phase is given by the arctan(imag/real), which is uesless for this problem. The important part, the magnitude, is given by real^2 + imag^2, not just by real^2.
Adam Rosenfield
As you said, this is only the first part of the solution... In fact, you just have calculated a series that shows how the low frequencies magnitude changes with the time (almost like applying a low-pass filter). In other words, the solution is far harder than it looks in your answer.
Alceu Costa
In popular music you can *often* count on a bass drum, but in a lot of music the tempo is driven by the high hat, snare drum, or other broadband acoustic devices. Good luck find the BPM for a capella music with a chorus of singers. This approach will get something that sort of works, but only by measuring something incidentally related to BPM in some material. If you're at all concerned about accuracy, look at one of the academic papers other people have mentioned below.
jbarlow
A: 

I agree with Thomas, that this is absolutly no easy question. As far as I know there is no API for this yet.

But the Mirex 2006 has pretty much solved that problem, at least from a scientific point of view. Maybe you find something interesting there?

+3  A: 

Another article that might be interesting for you...

http://werner.yellowcouch.org/Papers/bpm04/

You can find existing BPM detection libraries here:

http://www.mmartins.com/mmartins/bpmdetection/bpmdetection.asp

...and a C# BPM detection library here:

http://adionsoft.net/bpm/

Sacha
+1  A: 

The easy way to do it is to have the user tap a button in rhythm with the beat, and count the number of taps divided by the time.

Tapping really isn't a good solution for what I'm trying to use the tool for. I'd like it to be fully automatic, which I know is possible.
Karl
+3  A: 

2 names :

Eric D. Scheirer
Masataka Goto

Google them, they have written about beat detection (realtime and offline) in great length. Very interesting material.

Also as a sidenote, I think besides beat-detection you might be interested in beat-prediction.

Led