From 73f0765519f9bd26f9c064620cfd40a9a2ad3ebc Mon Sep 17 00:00:00 2001 From: alban Date: Tue, 29 Sep 2020 15:50:00 +0200 Subject: [PATCH] [fix] Better bpm --- redilysis.py | 55 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/redilysis.py b/redilysis.py index 9e791bb..db486d2 100755 --- a/redilysis.py +++ b/redilysis.py @@ -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 new_bpm < bpm_min : - new_bpm = bpm_min - else : - new_bpm = bpm_max + 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,