[c911b12] | 1 | #! /usr/bin/env python |
---|
| 2 | |
---|
| 3 | from aubio import source, tempo |
---|
| 4 | from numpy import median, diff |
---|
| 5 | |
---|
[4d1bf0e] | 6 | def get_file_bpm(path, params=None): |
---|
[c911b12] | 7 | """ Calculate the beats per minute (bpm) of a given file. |
---|
| 8 | path: path to the file |
---|
| 9 | param: dictionary of parameters |
---|
| 10 | """ |
---|
[dc654f8] | 11 | if params is None: |
---|
[494df02] | 12 | params = {} |
---|
[5db398e] | 13 | # default: |
---|
| 14 | samplerate, win_s, hop_s = 44100, 1024, 512 |
---|
| 15 | if 'mode' in params: |
---|
| 16 | if params.mode in ['super-fast']: |
---|
| 17 | # super fast |
---|
| 18 | samplerate, win_s, hop_s = 4000, 128, 64 |
---|
| 19 | elif params.mode in ['fast']: |
---|
| 20 | # fast |
---|
| 21 | samplerate, win_s, hop_s = 8000, 512, 128 |
---|
| 22 | elif params.mode in ['default']: |
---|
| 23 | pass |
---|
| 24 | else: |
---|
| 25 | print("unknown mode {:s}".format(params.mode)) |
---|
| 26 | # manual settings |
---|
| 27 | if 'samplerate' in params: |
---|
| 28 | samplerate = params.samplerate |
---|
| 29 | if 'win_s' in params: |
---|
| 30 | win_s = params.win_s |
---|
| 31 | if 'hop_s' in params: |
---|
| 32 | hop_s = params.hop_s |
---|
[c911b12] | 33 | |
---|
| 34 | s = source(path, samplerate, hop_s) |
---|
| 35 | samplerate = s.samplerate |
---|
| 36 | o = tempo("specdiff", win_s, hop_s, samplerate) |
---|
| 37 | # List of beats, in samples |
---|
| 38 | beats = [] |
---|
| 39 | # Total number of frames read |
---|
| 40 | total_frames = 0 |
---|
| 41 | |
---|
| 42 | while True: |
---|
| 43 | samples, read = s() |
---|
| 44 | is_beat = o(samples) |
---|
| 45 | if is_beat: |
---|
| 46 | this_beat = o.get_last_s() |
---|
| 47 | beats.append(this_beat) |
---|
| 48 | #if o.get_confidence() > .2 and len(beats) > 2.: |
---|
| 49 | # break |
---|
| 50 | total_frames += read |
---|
| 51 | if read < hop_s: |
---|
| 52 | break |
---|
| 53 | |
---|
[4d1bf0e] | 54 | def beats_to_bpm(beats, path): |
---|
| 55 | # if enough beats are found, convert to periods then to bpm |
---|
| 56 | if len(beats) > 1: |
---|
| 57 | if len(beats) < 4: |
---|
| 58 | print("few beats found in {:s}".format(path)) |
---|
| 59 | bpms = 60./diff(beats) |
---|
| 60 | return median(bpms) |
---|
| 61 | else: |
---|
| 62 | print("not enough beats found in {:s}".format(path)) |
---|
| 63 | return 0 |
---|
| 64 | |
---|
| 65 | return beats_to_bpm(beats, path) |
---|
[c911b12] | 66 | |
---|
| 67 | if __name__ == '__main__': |
---|
[5db398e] | 68 | import argparse |
---|
| 69 | parser = argparse.ArgumentParser() |
---|
| 70 | parser.add_argument('-m', '--mode', |
---|
| 71 | help="mode [default|fast|super-fast]", |
---|
| 72 | dest="mode") |
---|
| 73 | parser.add_argument('sources', |
---|
| 74 | nargs='*', |
---|
| 75 | help="input_files") |
---|
| 76 | args = parser.parse_args() |
---|
| 77 | for f in args.sources: |
---|
| 78 | bpm = get_file_bpm(f, params = args) |
---|
[4120fbc] | 79 | print("{:6s} {:s}".format("{:2f}".format(bpm), f)) |
---|