3

I'm looking to detect the tempo of an audio file in python 3.6, but I don't really understand the doc about aubio. Would someone please indicate how to extract the tempo with aubio or another library?

user32882
  • 5,094
  • 5
  • 43
  • 82
P G
  • 31
  • 1
  • 3

2 Answers2

9

Updated

This command will give you the tempo estimate of the entire file (available in 0.4.5):

aubio tempo foo.wav

There is a simple demo in aubio's python/demos: demo_bpm_extract.py.

The most important part is the following two lines, which compute the periods between each consecutive beats (np.diff), convert these periods in bpm (60./), and takes the median (np.median) as the most likely bpm candidate for this series of beats:

#!/usr/bin/env python
import numpy as np
bpms = 60./np.diff(beats)
median_bpm = np.median(bpms)

Note how the median is better suited than the mean here, since it will always give an estimate which exists in the original population bpms.

piem
  • 390
  • 2
  • 11
  • 5
    it feels somewhat ironic to get downvoted as i'm the upstream author. a comment on this would have been appreciated. – piem Mar 23 '17 at 08:10
  • thanks for the answer, I upvoted you. But anyway, aubio isn't very good at detecting tempo/bpm it seems. I just tried it with a few songs and the values are way off, for example it gives `Smokey Robinson - Cruisin'` a bpm score of 168.3 which can't be true. Any song with live music or ambient noise is also very wrong. Any suggestions for alternative lib? – supersan May 04 '18 at 18:22
  • @supersan did you find a good alternative lib? I've experienced the same thing where the results aren't ideal. – Patrick Mar 02 '20 at 11:52
  • 1
    @Patrick sorry I never did though i barely remember any details because it was a long time back. If I were to do it now I'd probably try doing it using machine learning. The first step would to be find an accurate bpm dataset and songs using which you can train the model. Maybe it will be a nice weekend project for me. I'll update you if I ever get the chance to work on it. – supersan Mar 02 '20 at 13:06
  • No worries, thanks for getting back to me @supersan – Patrick Mar 03 '20 at 09:09
3

I found this code by Paul Brossier that could help you, here it is:

#! /usr/bin/env python

from aubio import source, tempo
from numpy import median, diff

def get_file_bpm(path, params = None):
    """ Calculate the beats per minute (bpm) of a given file.
        path: path to the file
        param: dictionary of parameters
    """
    if params is None:
        params = {}
    try:
        win_s = params['win_s']
        samplerate = params['samplerate']
        hop_s = params['hop_s']
    except KeyError:
        """
        # super fast
        samplerate, win_s, hop_s = 4000, 128, 64 
        # fast
        samplerate, win_s, hop_s = 8000, 512, 128
        """
        # default:
        samplerate, win_s, hop_s = 44100, 1024, 512

    s = source(path, samplerate, hop_s)
    samplerate = s.samplerate
    o = tempo("specdiff", win_s, hop_s, samplerate)
    # List of beats, in samples
    beats = []
    # Total number of frames read
    total_frames = 0

    while True:
        samples, read = s()
        is_beat = o(samples)
        if is_beat:
            this_beat = o.get_last_s()
            beats.append(this_beat)
            #if o.get_confidence() > .2 and len(beats) > 2.:
            #    break
        total_frames += read
        if read < hop_s:
            break

    # Convert to periods and to bpm 
    if len(beats) > 1:
        if len(beats) < 4:
            print("few beats found in {:s}".format(path))
        bpms = 60./diff(beats)
        b = median(bpms)
    else:
        b = 0
        print("not enough beats found in {:s}".format(path))
    return b

if __name__ == '__main__':
    import sys
    for f in sys.argv[1:]:
        bpm = get_file_bpm(f)
print("{:6s} {:s}".format("{:2f}".format(bpm), f))

this is the key part:

bpms = 60./np.diff(beats)
median_bpm = np.median(bpms)
Liam
  • 6,009
  • 4
  • 39
  • 53
  • you forgot to mention your source, and the indentation got messed up somehow. ;-) pointing to the original resource seemed more appropriate here. also, I added some insights about the conversion from beat locations to bpm. – piem Mar 22 '17 at 16:34