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 0x11496a5a8>)

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]:

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