[ci] add pip install to readthedocs.yaml
[aubio.git] / python / demos / demo_bpm_extract.py
1 #! /usr/bin/env python
2
3 from aubio import source, tempo
4 from numpy import median, diff
5
6 def get_file_bpm(path, params=None):
7     """ Calculate the beats per minute (bpm) of a given file.
8         path: path to the file
9         param: dictionary of parameters
10     """
11     if params is None:
12         params = {}
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             raise ValueError("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
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
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)
66
67 if __name__ == '__main__':
68     import argparse
69     parser = argparse.ArgumentParser()
70     parser.add_argument('-m', '--mode',
71             help="mode [default|fast|super-fast]",
72             dest="mode", default='default')
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)
79         print("{:6s} {:s}".format("{:2f}".format(bpm), f))