Objective: Finding the BPM of a short drum loop.
Approach:
% Step 1: Get audio signal and sample rate
[audio_signal, Fs] = audioread(".\90-bpm.wav"); % Drum loop recorded at 90bpm
audio_signal = audio_signal(:,1); % Only use 1 channel
short_signal = audio_signal(1:1e5,:); % Get short version of sample
% Step 2: Get the audio signal length
audio_length = length(audio_signal);
% Step 3: Create the time vector based on the audio signal length and sampling rate
time = (0:audio_length-1) / Fs; % Used for plotting time axis
% Step 4: Plot the audio signal
plot(time, audio_signal);
xlabel('Time (seconds)');
ylabel('Amplitude');
title('Audio Signal');
grid on;
% Use correlation with a shorter version of the signal
[result, lags] = xcorr(audio_signal, short_signal);
plot(lags/Fs, result); % Normalized lag-axis
xlabel('Lag');
ylabel('xcrorr result');
grid on;
% Find the peaks at their locations
[peaks, locs] = findpeaks(result);
Interpretation
The result shows two large peaks, where I assume the first one corresponds to the start of both samples (highest point of similarity at lag = 0) and the second largest peak where I assume both samples are most likely repeating itself.
Questions
I would like to understand how I can use this result to find the bpm of the drum loop. Would I have to find the time between each peak? How could I determine the bpm using the smaller peaks seen through the result? How does "lag/delay" translate to time?
Thank you in advance!
EDIT: Added plotting lines to show normalization of lag scale.
FOLLOW-UP
Based on @Jdip answer I have added the following code:
% Use correlation with a shorter version of the signal
[result, lags] = xcorr(audio_signal, short_signal);
plot(lags, result); % Normalized lag-axis
xlabel('Lag');
ylabel('xcrorr result');
grid on;
% Find the peaks at their locations
[pksort, locsort] = findpeaks(result, lags, "SortStr", "descend");
pkpairs= pksort(1:2,:);
locpairs = locsort(:, 1:2);
loc_time = locpairs(:,2)/Fs;
beat_sec = 1/loc_time;
Result
>> locpairs/Fs
ans =
0 2.6667
>> loc_time = locpairs(:,2)/Fs;
>> loc_time
loc_time =
2.6667
>> beat_sec = 1/loc_time;
>> beat_sec
beat_sec =
0.3750
>> beat_sec * 60
ans =
22.5000
Original Signal