peterf@2
|
1 #!/usr/bin/env python
|
peterf@2
|
2 '''
|
peterf@2
|
3 CREATED:2013-02-12 16:33:40 by Brian McFee <brm2132@columbia.edu>
|
peterf@2
|
4
|
peterf@2
|
5 Beat tracking with HPSS filtering
|
peterf@2
|
6
|
peterf@2
|
7 Usage: ./hpss_beats.py [-h] input_audio.mp3 output_beats.csv
|
peterf@2
|
8 '''
|
peterf@2
|
9 from __future__ import print_function
|
peterf@2
|
10
|
peterf@2
|
11 import argparse
|
peterf@2
|
12 import numpy as np
|
peterf@2
|
13 import sys
|
peterf@2
|
14 import librosa
|
peterf@2
|
15
|
peterf@2
|
16 # Some magic number defaults, FFT window and hop length
|
peterf@2
|
17 N_FFT = 2048
|
peterf@2
|
18
|
peterf@2
|
19 # We use a hop of 64 here so that the HPSS spectrogram input
|
peterf@2
|
20 # matches the default beat tracker parameters
|
peterf@2
|
21 HOP_LENGTH = 64
|
peterf@2
|
22
|
peterf@2
|
23
|
peterf@2
|
24 def hpss_beats(input_file, output_csv):
|
peterf@2
|
25 '''HPSS beat tracking
|
peterf@2
|
26
|
peterf@2
|
27 :parameters:
|
peterf@2
|
28 - input_file : str
|
peterf@2
|
29 Path to input audio file (wav, mp3, m4a, flac, etc.)
|
peterf@2
|
30
|
peterf@2
|
31 - output_file : str
|
peterf@2
|
32 Path to save beat event timestamps as a CSV file
|
peterf@2
|
33 '''
|
peterf@2
|
34
|
peterf@2
|
35 # Load the file
|
peterf@2
|
36 print('Loading ', input_file)
|
peterf@2
|
37 y, sr = librosa.load(input_file)
|
peterf@2
|
38
|
peterf@2
|
39 # Do HPSS
|
peterf@2
|
40 print('Harmonic-percussive separation ... ')
|
peterf@2
|
41 y = librosa.effects.percussive(y)
|
peterf@2
|
42
|
peterf@2
|
43 # Construct onset envelope from percussive component
|
peterf@2
|
44 print('Tracking beats on percussive component')
|
peterf@2
|
45 onset_env = librosa.onset.onset_strength(y=y,
|
peterf@2
|
46 sr=sr,
|
peterf@2
|
47 hop_length=HOP_LENGTH,
|
peterf@2
|
48 n_fft=N_FFT,
|
peterf@2
|
49 aggregate=np.median)
|
peterf@2
|
50
|
peterf@2
|
51 # Track the beats
|
peterf@2
|
52 tempo, beats = librosa.beat.beat_track(onset_envelope=onset_env,
|
peterf@2
|
53 sr=sr,
|
peterf@2
|
54 hop_length=HOP_LENGTH)
|
peterf@2
|
55
|
peterf@2
|
56 beat_times = librosa.frames_to_time(beats,
|
peterf@2
|
57 sr=sr,
|
peterf@2
|
58 hop_length=HOP_LENGTH)
|
peterf@2
|
59
|
peterf@2
|
60 # Save the output
|
peterf@2
|
61 print('Saving beats to ', output_csv)
|
peterf@2
|
62 librosa.output.times_csv(output_csv, beat_times)
|
peterf@2
|
63
|
peterf@2
|
64
|
peterf@2
|
65 def process_arguments(args):
|
peterf@2
|
66 '''Argparse function to get the program parameters'''
|
peterf@2
|
67
|
peterf@2
|
68 parser = argparse.ArgumentParser(description='HPSS beat-tracking example')
|
peterf@2
|
69
|
peterf@2
|
70 parser.add_argument('input_file',
|
peterf@2
|
71 action='store',
|
peterf@2
|
72 help='path to the input file (wav, mp3, etc)')
|
peterf@2
|
73
|
peterf@2
|
74 parser.add_argument('output_file',
|
peterf@2
|
75 action='store',
|
peterf@2
|
76 help='path to the output file (csv of beat times)')
|
peterf@2
|
77
|
peterf@2
|
78 return vars(parser.parse_args(args))
|
peterf@2
|
79
|
peterf@2
|
80
|
peterf@2
|
81 if __name__ == '__main__':
|
peterf@2
|
82 # Get the parameters
|
peterf@2
|
83 parameters = process_arguments(sys.argv[1:])
|
peterf@2
|
84
|
peterf@2
|
85 # Run the beat tracker
|
peterf@2
|
86 hpss_beats(parameters['input_file'], parameters['output_file'])
|