[fix] Better bpm

This commit is contained in:
alban 2020-09-29 15:50:00 +02:00
parent 6ae754e893
commit 73f0765519

View File

@ -38,8 +38,12 @@ _BPM_MIN=10
_BPM_MAX=400
# Argument parsing
# Audio Args
parser = argparse.ArgumentParser(prog='realtime_redis')
# Standard Args
parser.add_argument("-v","--verbose",action="store_true",help="Verbose")
# Redis Args
parser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
parser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
# Audio Capture Args
parser.add_argument('--list-devices','-L', action='store_true', help='Which devices are detected by pyaudio')
parser.add_argument('--mode','-m', required=False, default='spectrum', choices=['spectrum', 'bpm'], type=str, help='Which mode to use. Default=spectrum')
@ -47,16 +51,11 @@ parser.add_argument('--device','-d', required=False, type=int, help='Which pyaud
parser.add_argument('--sampling-frequency','-s', required=False, default=0.1, type=float, help='Which frequency, in seconds. Default={}f '.format(_SAMPLING_FREQUENCY))
parser.add_argument('--channels','-c', required=False, default=_CHANNELS, type=int, help='How many channels. Default={} '.format(_CHANNELS))
parser.add_argument('--rate','-r', required=False, default=44100, type=int, help='The audio capture rate in Hz. Default={} '.format(_RATE))
#parser.add_argument('--frames','-f', required=False, default=4410, type=int, help='How many frames per buffer. Default={}'.format(_FRAMES_PER_BUFFER))
parser.add_argument('--frames','-f', required=False, default=4410, type=int, help='How many frames per buffer. Default={}'.format(_FRAMES_PER_BUFFER))
# BPM Mode Args
parser.add_argument('--bpm-min', required=False, default=_BPM_MIN, type=int, help='BPM mode only. The low BPM threshold. Default={} '.format(_BPM_MIN))
parser.add_argument('--bpm-max', required=False, default=_BPM_MAX, type=int, help='BPM mode only. The high BPM threshold. Default={} '.format(_BPM_MAX))
# Redis Args
parser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
parser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
# Standard Args
parser.add_argument("-v","--verbose",action="store_true",help="Verbose")
args = parser.parse_args()
# global
@ -110,7 +109,6 @@ if( LIST_DEVICES ):
list_devices()
os._exit(1)
p = pyaudio.PyAudio()
def m_bpm(audio_data):
@ -122,7 +120,6 @@ def m_bpm(audio_data):
global bpm
global start
bpm_delay = SAMPLING_FREQUENCY + start - time.time()
# Detect tempo / bpm
new_bpm, beats = librosa.beat.beat_track(
@ -138,19 +135,25 @@ def m_bpm(audio_data):
'''
# Correct the eventual octave error
if new_bpm < bpm_min or new_bpm > bpm_max:
found = False
octaveErrorList = [ 0.5, 2, 0.3333, 3 ]
for key,factor in enumerate(octaveErrorList):
correction = new_bpm * factor
if correction > bpm_min and correction < bpm_max:
debug( "Corrected bpm to:{}".format(correction))
debug( "Corrected high/low bpm:{} to:{}".format(new_bpm, correction))
new_bpm = correction
found = True
break
if found == False:
if new_bpm < bpm_min :
new_bpm = bpm_min
else :
new_bpm = bpm_max
debug("new_bpm:{}".format(new_bpm))
'''
How to guess the next beats based on the data sent to redis
~~ A Dirty Graph ~~
|start end|
Capture |........................|
@ -167,22 +170,29 @@ def m_bpm(audio_data):
. passed (...b....b....b.)
. guessed (..b....b....b....b...
Next Beat Calculation b....b....b....b.|..b
Beats |last beat
0 1 2 3 4
=> (Delay - last beat) + x*BPM/60 (with x >= read_delay/BPM/60)
Redis:
bpm_sample_interval
|........................|
bpm_delay
|.........................|
key bpm_sample_interval
visual |........................|
key bpm_delay
visual |.........................|
'''
bpm = new_bpm
bpm_sample_interval = SAMPLING_FREQUENCY * 1000
bpm_delay = (SAMPLING_FREQUENCY + time.time() - start ) * 1000
pexpireat = int( 2 * bpm_sample_interval);
# Save to Redis
r.set( 'bpm', new_bpm, px=( 2* int(SAMPLING_FREQUENCY * 1000)))
r.set( 'bpm_sample_interval', SAMPLING_FREQUENCY )
r.set( 'bpm', round(bpm,2), px = pexpireat )
r.set( 'bpm_sample_interval', bpm_sample_interval )
r.set( 'bpm_delay', bpm_delay )
r.set( 'beats', json.dumps( beats.tolist() ) )
debug( "bpm:{} bpm_delay:{} beats:{}".format(bpm,bpm_delay,beats) )
#debug( "pexpireat:{}".format(pexpireat))
debug( "bpm:{} bpm_delay:{} bpm_sample_interval:{} beats:{}".format(bpm,bpm_delay,bpm_sample_interval,beats) )
return True
def m_spectrum(audio_data):
@ -250,6 +260,7 @@ if MODE == 'spectrum':
elif MODE == 'bpm':
debug("In this mode, we will set keys: onset, bpm, beats")
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32,
channels=CHANNELS,
rate=RATE,