20 May '13 - 00:49 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: New BPM Detection Try - Why still inaccuracies ?  (Read 1337 times)
gnag
Posts: 160


« on: 2 Jan '12 - 10:32 »
Reply with quoteQuote

Hello, I made another try at implementing BPM/Beat Detection, the idea im trying to implement is now the following:

  • Loop over FFT Samples,only take interest in Samples which have the highest amplitude at a Frequency with lower or equals 200 Hz
  • The found time position now mark each beat, there are multiple of this peaks in a row, then is silence or higher frequencies than 200 which shows me that the beat has ended.
  • Now that I have data showing me when there is bass and when it stops, Im marking Start and End of each of this blocks and sum the involved FFT Data which is returned by BASS_ChannelGetData to calculate the total length/duration of each beat, now I simply do 60/BEAT_LENGTH to get my BPM Value.

My problem is I am getting too inaccurate results, the problem is I think that I need to detect "half beats" too, for example I used a song with 150BPM which means 2,5 Beats per Second (150/60).
If I plot the data I have collected, I am already getting good results, just look at the Screenshot below, it shows clearly that there are 2.5 Beats per Second, my question is how can I tell the computer to recognize it too?



Please take a look at my project, you can find my full Visual Studio project here, I want to save you the time to copy my code, add StreamCreate, remove the graphing stuff etc: http://dl.dropbox.com/u/16576364/mtest.rar

If you dont have Visual Studio, please just take a look at the "DoBPMAnalyseLoop2" Function inside of ba_mainwindow.cs in my RAR Archive.
Logged
gnag
Posts: 160


« Reply #1 on: 3 Jan '12 - 15:49 »
Reply with quoteQuote

No one has tips for me how to improve accuracy or what I can optimize?
Ian or any hardcore pros maybe?
Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #2 on: 4 Jan '12 - 14:04 »
Reply with quoteQuote

I have never looked into implement BPM/beat detection myself, so I'm afraid I can't really advise on the best way to do that. But I had a look at your code, and it appears to be calculating the BPM based on how long the low (sub-200Hz) frequencies are louder than anything else in this line...

                     lbx_error.Items.Add("Possible BPM:" + 60 / beat_now.BeatLength);

I don't think that will work very well (if I'm reading the code correctly). It would be better to look at the timing of the beats to calculate the BPM, eg. if you find that there is a beat every 0.5s then the BPM is 120 (60/0.5).
Logged
gnag
Posts: 160


« Reply #3 on: 4 Jan '12 - 14:45 »
Reply with quoteQuote

Thanks for your reply, BPM Detection is a tricky thing to do right.

As the code is now, it just tries to find the beat length (how many samples have low freqs as its peak in  a row) and then uses this to calculate the BPM.
Please explain me how you plan to measure exactly, I see multiple ways how to do this:

  • Use the "white space", the tme between the red lines on my graph. As you can see on the graph, the white space is almost always the same so it would be a good value to use!
  • Use distance between the mountaintops of each beat
  • Use the distance between first or last bar of my each graphed beat.


As you can see on the picture I am visualising the beat like a mountain, has a top and some hills.
Logged
thisischris_ii
Posts: 13


« Reply #4 on: 4 Jan '12 - 17:19 »
Reply with quoteQuote

I remember trying to figure out something similar when there was a sudden change in volume in some project of mine.

Here's an idea: You keep a buffer of 'segments' of lets say each lasting 0.10 seconds each 'segment' is the average amplitude/volume over that duration of time. Now you record the 'average amplitude(volume)' over the past few seconds, if there is a great increase in volume (lets say 2 * previous segment) then you could assume it's a beat. Then every 15 seconds or so you could find the average(or lowest common factor) 'time difference' between beats.

Cheers
Logged
gnag
Posts: 160


« Reply #5 on: 4 Jan '12 - 21:57 »
Reply with quoteQuote

@Ian:
I just implemented the idea to check how much "space" between the beats is to calculate BPM then using the Formula  6/Space_Time , so basically the Time Between End of Current Beat an Begin of Next Beat, again it turned out to be a fail.

Pls check my Updated Version, using your Idea: http://dl.dropbox.com/u/16576364/mtest_v2.rar

@thisischris_ii:
I have tried this method too once, the difference is I was using an average amplitude multiplied with about 1.65 of the whole song as Minimum_Level, if any detected amplitude peak goes over this it was counted as a beat and as expected this method failed too, it was just too simple to take the whole average.

Can you confirm if the following procedure implements the idea of thisischris_ii?

* Take 1024FFT Samples
* Find Peak Index (Highest Value)
* Calculate Amplitude of Peak
* Keep (Moving) Average of about 100MS worth of returned FFT Data.

Some Sidenotes:

I spent weeks and made lots of failed tries and tried out a lot of not accurate methods to detect BPM, I would really appreciate if any person would come up with a snippet like a proof of concept.

I will include any helpers into the credits of my application which will if it is finished/implemented good attract a lot of attention and lots of users, I already had a blog once which had hundred thousands of visitors in just hours, being linked to from Big Newspaper Websites to lots of Private Blogs and even in a Wikipedia article (they remove "private ad" links usually), having #1 Ranks in Google for the topic and about 10 involved persons.
Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #6 on: 5 Jan '12 - 18:05 »
Reply with quoteQuote

@Ian:
I just implemented the idea to check how much "space" between the beats is to calculate BPM then using the Formula  6/Space_Time , so basically the Time Between End of Current Beat an Begin of Next Beat, again it turned out to be a fail.

To account for funky patterns, you could try checking the gap to all beats that are within a certain time period of the current beat (eg. within 1 second), not just the next beat, and then use the most prevalent gap to calculate the BPM (60/gap) at the end. I haven't tried this myself, but it seems like it should give you an accurate BPM, if the beat detection is accurate. Note you would only need to know the start of a beat for this; it looks like your code is currently adding a beat entry ("beat_list.Add") whenever the low frequencies are loudest, not necessarily the start of a beat?
Logged
gnag
Posts: 160


« Reply #7 on: 5 Jan '12 - 21:05 »
Reply with quoteQuote

Firstly I add everything that could be a Beat (everything that has a Low Frequency as Peak) to my List, then it is filtered to mark Start&End of Beats, so for example if there are 10 Low Peaks and then Nothing and then 10 Loud Peaks again, it recognizes the gap between the Data and marks Start and End of the Beat, you can see in my example project it is getting colored Cyan (Start) and Red (Begin). There is also filtering applied to mark unusable results in the graph, in the last procedure which outputs possible BPM they are not recognized anymore, only marked Start/End-Having Beats where the Gap in between is in a "normal" Range to not find things like Beat Gaps of 4 Seconds if someone is singing ...

Please take a look at my latest source code: http://dl.dropbox.com/u/16576364/mtest_v4.rar

I dont think you need the file "The Pitcher - The Rising" which I am refering to in my code, just use any music you find having a "hard" beat.
Logged
thisischris_ii
Posts: 13


« Reply #8 on: 7 Jan '12 - 20:06 »
Reply with quoteQuote

>Use the distance between first or last bar of my each graphed beat.

I would go with this approach. I would then try find the most common(not average!) distance in the whole song. And hopefully that will be the song's BPM.
Logged
gnag
Posts: 160


« Reply #9 on: 9 Jan '12 - 17:00 »
Reply with quoteQuote

I removed my source codes, its outdated now.
« Last Edit: 10 Jan '12 - 22:35 by gnag » Logged
gnag
Posts: 160


« Reply #10 on: 18 Jan '12 - 23:47 »
Reply with quoteQuote

After days of experimenting around I have rethinked my initial attempt using FFT Data and now a simpler,faster and almost working BPM Detection is used which is described on the famous GameDEV Article.

The function works by getting the Actual Volume, putting these Volumes in a RingBuffer/Circular Array so it  will make a moving average. If a new Value is for example 1.3 times more than this moving average a beat will be detected and counted.
Now my Problem: Hardstyle and "Last Friday Night" get counted OK, but for example with "E.T." (Katy Perry ft. Kanye West) I have a problem which seems to be unsolvable to me. If you listen to the Song you will notice 2 strong drums being played one after another very fast which represent one beat, my Code Counts 150 BPM, it detects 2 edges which would be OK but since the beats are so close it should detect only the half, so 150/2 BPM.
I have set Min/Max BPM Limits to 50/200 which is required for my uses, I can not lower it.

How can I train my Algorithm to dont count the Beats twice with still limits set to 50/200 ?
There must be a way to tell the Algorithm to not count beats double, look at the graphs they look so different to me, the second Graph doesnt have these 2 high Peaks which the first one has!


BPM Detection Code: http://pastebin.com/raw.php?i=K0ftFayX
RingBuffer Class: http://pastebin.com/raw.php?i=LYMnVkd7

Wrong 150 BPM Detected (Should be 150/2)


Real 150 BPM Detected
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines