In [1]:
import numpy, scipy, matplotlib.pyplot as plt, pandas, librosa, mir_eval
import IPython.display
from IPython.html.widgets import interact
plt.rcParams['figure.figsize'] = (14,5)
:0: FutureWarning: IPython widgets are experimental and may change in the future.

Beat Tracking

librosa.beat.beat_track

Download an audio file:

In [2]:
import urllib
urllib.urlretrieve('http://audio.musicinformationretrieval.com/1_bar_funk_groove.mp3', 
                    filename='1_bar_funk_groove.mp3')
Out[2]:
('1_bar_funk_groove.mp3', <httplib.HTTPMessage instance at 0x10f3d96c8>)

Read the file:

In [3]:
x, fs = librosa.load('1_bar_funk_groove.mp3')
print fs
IPython.display.Audio(x, rate=fs)
22050
Out[3]:

Use librosa.beat.beat_track to estimate the beat locations and the global tempo:

In [4]:
tempo, beat_frames = librosa.beat.beat_track(x, fs, start_bpm=60)
print tempo
print beat_frames
56.1735733696
[ 47  92 138 184 231 275 321 366 412 459 504 550 595 641]

Plot the beat locations over the waveform:

In [5]:
def plot_beats(beat_frames):
    plt.figure()
    plt.plot(x, alpha=0.5)
    beat_samples = librosa.frames_to_samples(beat_frames)
    plt.vlines(beat_samples, -1, 1, color='r')
plot_beats(beat_frames)

Plot a histogram of the intervals between adjacent beats:

In [6]:
def plot_beat_histogram(beat_frames):
    beat_times = librosa.frames_to_time(beat_frames)
    beat_times_diff = numpy.diff(beat_times)
    plt.figure()
    plt.hist(beat_times_diff, bins=50, range=(0,4))
    plt.xlabel('Beat Length (seconds)')
    plt.ylabel('Count')
plot_beat_histogram(beat_frames)

Visually, it's difficult to tell how correct the estimated beats are. Let's listen to a click track:

In [7]:
def sonify_beats(beat_frames):
    beat_times = librosa.frames_to_time(beat_frames)
    clicks = mir_eval.sonify.clicks(beat_times, fs, length=len(x))
    return IPython.display.Audio(x + clicks, rate=fs)
sonify_beats(beat_frames)
Out[7]:
In [8]:
@interact(start_bpm=(30, 180, 20), tightness_exp=(-1, 4, 0.5))
def interact_f(start_bpm=60, tightness_exp=2):
    tempo, beat_frames = librosa.beat.beat_track(x, fs, start_bpm=start_bpm, tightness=10**tightness_exp)
    plot_beats(beat_frames)
    plot_beat_histogram(beat_frames)
    IPython.display.display(sonify_beats(beat_frames))