-
Notifications
You must be signed in to change notification settings - Fork 2
/
beat_detect.py
89 lines (69 loc) · 2.62 KB
/
beat_detect.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import librosa # audio analysis
import numpy as np
from pydub import AudioSegment # to read mp3s
from scipy.stats import lognorm, uniform
def read_mp3(filename):
"""MP3 to numpy array"""
a = AudioSegment.from_mp3(filename)
y = np.array(a.get_array_of_samples(), dtype=np.float32) / 2 ** 15
if a.channels == 2:
y = y.reshape((-1, 2))
y = y.mean(axis=1) # stripping to mono
# reducing sample rate (div by 2)
y = y[::2]
sr = a.frame_rate // 2
return y, sr
def read_wav(filename):
"""WAV to numpy array"""
y, sr = librosa.load(filename)
return y, sr
def read_any(filename):
"""WAV or MP3 to numpy array"""
if filename.endswith(".mp3"):
return read_mp3(filename)
elif filename.endswith(".wav"):
return read_wav(filename)
else:
print("Unknown file extension")
# exception or sth
return
def mp3_to_wav(src, dst=None):
"""Exports mp3 file to wav"""
dst = dst or src.replace(".mp3", ".wav")
audio = AudioSegment.from_mp3(src)
audio.export(dst, format="wav")
def get_beat_times(filename=None, y=None, sr=None):
"""Detects beat times from filename or np.arrray"""
if filename is not None:
y, sr = read_any(filename)
if y is not None and sr is not None:
pass # y, sr already loaded
else:
print("Something wrong with the arguments")
return
onset_env = librosa.onset.onset_strength(y, sr=sr)
prior = uniform(30, 300) # uniform over 30-300 BPM
utempo = librosa.beat.tempo(onset_envelope=onset_env, sr=sr, prior=prior)[0]
_, beat_times = librosa.beat.beat_track(y=y, sr=sr, units="time", bpm=utempo)
return beat_times, utempo
def get_beat_times_plp(filename=None, y=None, sr=None, lognorm_val=None):
"""
Detects beat times from filename or np.arrray using different method
Doesnt work very well :o
"""
if filename is not None:
y, sr = read_any(filename)
if y is not None and sr is not None:
pass # y, sr already loaded
else:
print("Something wrong with the arguments")
return
onset_env = librosa.onset.onset_strength(y=y, sr=sr)
if lognorm:
prior = lognorm(loc=np.log(lognorm_val), scale=lognorm_val, s=1)
pulse = librosa.beat.plp(onset_envelope=onset_env, sr=sr, prior=prior)
else:
pulse = librosa.beat.plp(onset_envelope=onset_env, sr=sr)
beats_plp = np.flatnonzero(librosa.util.localmax(pulse))
beat_times = librosa.frames_to_time(beats_plp, sr=sr)
return beat_times, None