In [1]:
%matplotlib inline
import seaborn
import numpy, scipy, matplotlib.pyplot as plt, pandas, librosa, mir_eval, IPython.display as ipd, urllib
from ipywidgets import interact
plt.rcParams['figure.figsize'] = (14,5)

Beat Tracking

librosa.beat.beat_track

Download an audio file:

In [2]:
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 0x1079c3a28>)

Read the file:

In [3]:
x, fs = librosa.load('1_bar_funk_groove.mp3')
print fs
ipd.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]
/Library/Python/2.7/site-packages/numpy/core/fromnumeric.py:2652: VisibleDeprecationWarning: `rank` is deprecated; use the `ndim` attribute or function instead. To find the rank of a matrix see `numpy.linalg.matrix_rank`.
  VisibleDeprecationWarning)

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 ipd.Audio(x + clicks, rate=fs)
sonify_beats(beat_frames)
Out[7]:

Use the IPython interactive widgets to observe how the output changes as we vary the parameters of the beat tracker. (The interactive widget is only visible in the editable IPython notebook, not the read-only version.)

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)
    ipd.display(sonify_beats(beat_frames))