cjcliffe / beatdetektor

BeatDetektor BPM detection / visualization library
http://www.beatdetektor.com
325 stars 54 forks source link

Please document expected FFT input format #5

Open SamBallantyne opened 8 years ago

SamBallantyne commented 8 years ago

How is the FFT input scaled? Decibels? Logarithmically? Should the input data be interleaved? Is it just the magnitudes?

I'm passing decibel-scaled FFT magnitudes, and getting BPM's in the range of 0.5.

cjcliffe commented 8 years ago

The raw output from your standard real FFT/DFT is all that's needed; no scaling, interleaving, etc. is required but usually it won't affect the output as long as it's not averaging it.

It's not really any sort of signal processing it's just performing statistics on the relative activity of the bins so no particular levels or ranges are required; you can use a multitude of things that aren't FFT too as long as it looks like one and is mirrored about the X axis and the "low" frequencies are on the outsides -- same as it already comes out of most FFT functions -- usually you cut the output in half and swap sides so baseband is at center for display but for beatdetektor just leave it as is (or mirror/cut what you have as as necessary to match).

Beatdetektor uses it like that so that the BPM detection defaults can be distributed linearly from LOW->HIGH BPM across the bins (with less deviation in the "highs" as it crosses the middle bins) so that they balance into detection from symmetrically opposed defaults instead of jumping to an immediate match -- this default distribution is also re-initialized when you reset the detection.

If you're already doing all that and getting weird BPMs check the time input; it should be the source audio time (in seconds) that the FFT frame was sampled from and also make sure it's floating point.

SamBallantyne commented 8 years ago

The beatDetektor instance is still returning values between 0 and 1 for current_bpm. Is this expected behavior?

cjcliffe commented 8 years ago

Hmm, doesn't sound right, you sure the time is a float in seconds the sample was taken? Can I see a plot of your FFT bins and your BeatDetektor init code? Are you feeding it the same number of FFT bins each sample?

cjcliffe commented 8 years ago

Whoops my bad, just double checked the code; yes current_bpm is totally in the range 0..1; it's the winning bpm time interval in seconds for the last pass; so 60.0/current_bpm will give you the best guess from the last pass -- this number may wander from the detection value each time process is called and shouldn't be used directly.

what you want is actually:

winning_bpm = Current BPM winner in the stats contest with 1 decimal place resolution (if not 0) winning_bpm_lo = Current BPM winner in the stats contest (if not 0)

winning_bpm_lo is more likely to be set than winning_bpm; and you can probably ignore winning_bpm as an errant value if it's more than 1 BPM different from winning_bpm_lo.