scaperot / the-bpm-detector-python Goto Github PK
View Code? Open in Web Editor NEWBPM detection for audio files (currently just .wav). Takes in the whole file, and prints out the BPM.
BPM detection for audio files (currently just .wav). Takes in the whole file, and prints out the BPM.
Hey :) love this program. It didn't work with python3 so I did some fixes if you want:
`
import wave, array, math, time, argparse, sys
import numpy, pywt
from scipy import signal
import pdb
import matplotlib.pyplot as plt
def read_wav(filename):
try:
wf = wave.open(filename,'rb')
except IOError as e:
print(e)
return
nsamps = wf.getnframes();
assert(nsamps > 0);
fs = wf.getframerate()
assert(fs > 0)
samps = list(array.array('i',wf.readframes(nsamps)))
try:
assert(nsamps == len(samps))
except AssertionError as e:
print(nsamps, "not equal to", len(samps))
return samps, fs
def no_audio_data():
print("No audio data for sample, skipping...")
return None, None
def peak_detect(data):
max_val = numpy.amax(numpy.abs(data))
peak_ndx = numpy.where(data==max_val)
if len(peak_ndx[0]) == 0:
peak_ndx = numpy.where(data==-max_val)
return peak_ndx
def bpm_detector(data,fs):
cA = []
cD = []
correl = []
cD_sum = []
levels = 4
max_decimation = 2**(levels-1);
min_ndx = int(60./ 220 * (fs/max_decimation))
max_ndx = int(60./ 40 * (fs/max_decimation))
for loop in range(0,levels):
cD = []
if loop == 0:
[cA,cD] = pywt.dwt(data,'db4');
cD_minlen = int(len(cD)/max_decimation+1);
cD_sum = numpy.zeros(cD_minlen);
else:
[cA,cD] = pywt.dwt(cA,'db4');
cD = signal.lfilter([0.01],[1 -0.99],cD);
cD = numpy.abs(cD[::(2**(levels-loop-1))]);
cD = cD - numpy.mean(cD);
cD_sum = cD[0:cD_minlen] + cD_sum;
if [b for b in cA if b != 0.0] == []:
return no_audio_data()
cA = signal.lfilter([0.01],[1 -0.99],cA);
cA = numpy.abs(cA);
cA = cA - numpy.mean(cA);
cD_sum = cA[0:cD_minlen] + cD_sum;
correl = numpy.correlate(cD_sum,cD_sum,'full')
midpoint = int(len(correl) / 2)
correl_midpoint_tmp = correl[midpoint:]
peak_ndx = peak_detect(correl_midpoint_tmp[min_ndx:max_ndx]);
if len(peak_ndx) > 1:
return no_audio_data()
peak_ndx_adjusted = peak_ndx[0]+min_ndx;
bpm = 60./ peak_ndx_adjusted * (fs/max_decimation)
print(bpm)
return bpm,correl
if name == 'main':
parser = argparse.ArgumentParser(description='Process .wav file to determine the Beats Per Minute.')
parser.add_argument('--filename', required=True,
help='.wav file for processing')
parser.add_argument('--window', type=float, default=3,
help='size of the the window (seconds) that will be scanned to determine the bpm. Typically less than 10 seconds. [3]')
args = parser.parse_args()
samps,fs = read_wav(args.filename)
data = []
correl=[]
bpm = 0
n=0;
nsamps = len(samps)
window_samps = int(args.window*fs)
print("this is window_samps: " +str(window_samps))
samps_ndx = 0; #first sample in window_ndx
max_window_ndx = int(nsamps / window_samps);
bpms = numpy.zeros(max_window_ndx)
for window_ndx in range(0,max_window_ndx):
data = samps[samps_ndx:samps_ndx+window_samps]
if not ((len(data) % window_samps) == 0):
raise AssertionError( str(len(data) ) )
bpm, correl_temp = bpm_detector(data,fs)
if bpm == None:
continue
bpms[window_ndx] = bpm
correl = correl_temp
samps_ndx = samps_ndx+window_samps;
n=n+1;
bpm = numpy.median(bpms)
print('Completed. Estimated Beats Per Minute:', bpm)
n = range(0,len(correl))
plt.plot(n,numpy.abs(correl));
plt.show(False);
time.sleep(10);
plt.close();
`
I'm testing this code and it seems the module pywt does not exist and cannot be downloaded from anywhere?
I've analyzed a 15 minute long .wav file and set the window for 060 seconds, and I get only 13 distinct
BPM estimations. Does the script ignore sections of the file that it cannot get a rythym from (ie, in the 15 minute file, only 13 minute's worth were able to be analyzed.) Thanks!
Something I plan to work on!
I've run using python 3.6 and OS windows. But it can't define xrange. Am I do wrong in the program?
this error:
Traceback (most recent call last):
File "C:\Users\user\PycharmProjects\pythonProject22\TuneBot.py", line 111, in
parser.add_argument(x, required=False, help=".wav file for processing")
File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\argparse.py", line 1405, in add_argument
kwargs = self._get_positional_kwargs(*args, **kwargs)
File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\argparse.py", line 1521, in _get_positional_kwargs
raise TypeError(msg)
TypeError: 'required' is an invalid argument for positionals
dwt is an attribute of the pywt, not sure why I am getting this error.
See title.
All code should have one, just in case!
Find a wav file with no audio for a part of the song (longer than the 'window' period) and the script fails to correlate.
Here is a gist of the changes I made (probably not the best solution):
I have two files, both generated in GarageBand. They were played along with a click track, and quantized to quarter notes, so the timing should be pretty spot on. The 120bpm sample gets detected correctly, but the 80bpm sample gets detected as 160bpm.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.