-
Notifications
You must be signed in to change notification settings - Fork 0
/
getaudiobpms.m
72 lines (55 loc) · 2.54 KB
/
getaudiobpms.m
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
%GETAUDIOBPMS Function for extracting the global and local BPMs from a clip
% of audio.
% Uses the spectral flux autocorrelation method to estimate an approximate
% global tempo. This approximate global tempo is then used to segment the
% audio into approximately 2 bar sections, which then each have their tempo
% calculated. The global BPM is then taken as the mean of these tempos.
% Input arguments:
% audio - the audio signal to analyse the BPM of
% Fs - the sampling frequency of the audio
% timeSigNumerator - the number of beats in each bar
function[bpm, localBpms] = getaudiobpms(audio, Fs, timeSigNumerator)
% Calculate the spectral flux of the signal and crop all zeros below 0
flux = getspectralflux(audio, Fs, 512, 0, 2048);
flux(flux < 0) = 0;
% Calculate the 10 most likely BPMs using autocorrelation and peak
% picking
possibleBpms = autocorrelationbpm(flux, 10);
% Pick the most likely BPM from these 10 BPMs
approxBpm = pickbpm(possibleBpms);
% Calculate the local BPMs over each segment of audio
localBpms = getlocalbpms(audio, Fs, approxBpm, timeSigNumerator);
% Calculate the mean of the local BPMs
bpm = mean(localBpms);
% Calculate the segments of audio based on the new mean BPM
[nSegments, ~] = segmentaudio(bpm, length(audio), Fs, timeSigNumerator, 2);
% Calculate the divisor for matching the previously calculated local
% BPMs to the new segments
divisor = floor(length(localBpms) / nSegments);
% If the divisor is less than two then take the moving average across
% the local BPMs, by averaging each 2 samples
if divisor < 2
localBpms = movmean(localBpms, 2);
return;
end
% Calculate the moving average of the local BPMs by whatever the
% divisor is
localBpms = movmean(localBpms, divisor);
% Initialise a variable for the updated local BPM values
newLocalBpms = zeros(nSegments, 1);
% Loop through each segment
for n=1:nSegments
% Determine the start and end segment
startSeg = divisor * (n - 1) + 1;
endSeg = startSeg + divisor - 1;
% If the end position is longer than the length of the local BPMs,
% then crop it to the length of the array
if endSeg > length(localBpms)
endSeg = length(localBpms);
end
% Calculate the mean of the segments
newLocalBpms(n) = mean(localBpms(startSeg:endSeg));
end
% Output the new local BPM values
localBpms = newLocalBpms;
end