Sunday, April 10, 2016

bpm beats frequency detection in audio wav file: pyaudio, wave

https://linuxaudiostudio.wordpress.com/2012/07/06/some-python-code-for-calculating-bpm-and-delay-times/

http://stackoverflow.com/questions/12344951/detect-beat-and-play-wav-file-in-a-syncronised-manner

https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=python%20audio%20beats%20bpm%20detection

https://wiki.python.org/moin/PythonInMusic

# Beats detection

#!/usr/bin/env python

import wave
from string import capitalize, capwords
from optparse import OptionParser


def ms_to_bpm(length, measures = 1, beat = 1):
    """Calculates beat per minute of a soundfile given the lenght in
    milliseconds, the number of measures and the beat, where 4/4 is 1.
    Returns bpm
    """
    bpm = round(60000/((float(length/beat)/measures)/4),2)
    return bpm

def wavduration(wavfile):
    """Returns the duration of a wavfile in milliseconds"""
    myfile = wave.open(wavfile, "r")
    frames = (1.0 * myfile.getnframes ())
    sr = myfile.getframerate ()
    time = (1.0 *(frames/sr))
    return int(round(time * 1000))

def delay_times(bpm = 120):
    """Returns delay times for the specified bpm, in milliseconds"""
    result = []
    durations = [
        (1,"whole"),
        ((3.0/4),"dotted half"),
        ((1.0/2),"half"),
        ((3.0/8),"dotted quarter"),
        ((1.0/4),"quarter"),
        ((3.0/16),"dotted eight"),
        (round(((1.0/2)/3),5),"quarter triplet"),
        ((1.0/8),"eight"),
        ((3.0/32),"dotted sixteenth"),
        (round(((1.0/4)/3),5),"eight triplet"),
        ((1.0/16),"sixteenth"),
        ((3.0/64),"dotted thirty second"),
        (round(((1.0/8)/3),5),"sixteenth triplet"),
        ((1.0/32),"thirty second")
        ]
    for duration, description in durations:
        title = capwords(description)
        delay = (duration * 4000) / (bpm/60.0)
        frequency = 1000 / delay
        result.append({"title": title, "delay": delay,"frequency": frequency})
    return result

def delay_times_format(bpm = 120):
    a = delay_times(bpm)
    a.sort()
    a.reverse()
    print "\n",bpm,"beats per minute (bpm):"
    print
    print "Note                            Delay time                       LFO freq"
    print 75 * "-"
    for line in a:
        title = line["title"].ljust(30," ")
        delay = round(line["delay"],3)
        frequency = round(line["frequency"],2)
        print title,delay.__str__().rjust(8), "ms ",20*" ", frequency.__str__().rjust(5), "Hz"

 

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("-f", "--file", dest="filename", default="none",
                      help="wave FILE to load", metavar="FILE")
    parser.add_option("-b", "--bpm",
                      dest="bpm", default="analize",
                      help="beats per minute")
    parser.add_option("-B", "--bars", dest ="bars", help="number of bars in the wav file")
    parser.add_option("-m", "--meter", dest ="meter", help="as in 3/4 or 12/8, default 4/4")
 

    (options, args) = parser.parse_args()

    # print options, args

    if options.meter:
        a = options.meter.split("/")
        meter = (float(a[0])/float(a[1]))
        print "\nMeter is", options.meter
    else:
        meter = 1
        print "\nMeter is 4/4"


    if options.bars:
        bars = int(options.bars)
    else:
        bars = 1
    wavfile = options.filename

    if wavfile == "none":
        print "No wavfiles to analize, defaulting to bpm provided, or 120"
        if options.bpm == "analize":
            bpm = 120
        else:
            bpm = float(options.bpm)
    else:

        if options.bpm != "analize":
            bpm = float(options.bpm)
            delay_times_format(bpm)
        else:
            bpm = 120

        print 75*"-","\n"

        wavduration = wavduration(wavfile)
        print wavfile,"is",wavduration, "milliseconds"
        bpm = ms_to_bpm(wavduration,bars,meter)

    # bpm = ms_to_bpm(3850,2,1)
        print "Bpm of",wavfile, "is", bpm

 
    delay_times_format(bpm)

# Frequency detection:
# Read in a WAV and find the freq's
import pyaudio
import wave
import numpy as np

chunk = 2048

# open up a wave
wf = wave.open('test-tones/440hz.wav', 'rb')
swidth = wf.getsampwidth()
RATE = wf.getframerate()
# use a Blackman window
window = np.blackman(chunk)
# open stream
p = pyaudio.PyAudio()
stream = p.open(format =
                p.get_format_from_width(wf.getsampwidth()),
                channels = wf.getnchannels(),
                rate = RATE,
                output = True)

# read some data
data = wf.readframes(chunk)
# play stream and find the frequency of each chunk
while len(data) == chunk*swidth:
    # write data out to the audio stream
    stream.write(data)
    # unpack the data and times by the hamming window
    indata = np.array(wave.struct.unpack("%dh"%(len(data)/swidth),\
                                         data))*window
    # Take the fft and square each value
    fftData=abs(np.fft.rfft(indata))**2
    # find the maximum
    which = fftData[1:].argmax() + 1
    # use quadratic interpolation around the max
    if which != len(fftData)-1:
        y0,y1,y2 = np.log(fftData[which-1:which+2:])
        x1 = (y2 - y0) * .5 / (2 * y1 - y2 - y0)
        # find the frequency and output it
        thefreq = (which+x1)*RATE/chunk
        print "The freq is %f Hz." % (thefreq)
    else:
        thefreq = which*RATE/chunk
        print "The freq is %f Hz." % (thefreq)
    # read some more data
    data = wf.readframes(chunk)
if data:
    stream.write(data)
stream.close()
p.terminate()

 

No comments:

Post a Comment