Las bibliotecas aubio se han envuelto con SWIG y, por lo tanto, pueden ser utilizadas por Python. Entre sus muchas características se incluyen varios métodos para la detección/estimación de tonos, incluido el algoritmo YIN y algunos algoritmos de peine armónico.
Sin embargo, si quieres algo más simple, escribí un código para la estimación de tono hace algún tiempo y puedes tomarlo o dejarlo. No será tan preciso como usar los algoritmos en aubio, pero podría ser lo suficientemente bueno para sus necesidades. Básicamente, solo tomé FFT de los datos por una ventana (una ventana de Blackman en este caso), cuadre los valores de FFT, encontré el contenedor que tenía el valor más alto y usé una interpolación cuadrática alrededor del pico usando el registro del valor máximo y sus dos valores vecinos para encontrar la frecuencia fundamental. La interpolación cuadrática que tomé de un papel que encontré.
Funciona bastante bien en tonos de prueba, pero no será tan robusto ni tan preciso como los otros métodos mencionados anteriormente. La precisión se puede aumentar aumentando el tamaño del fragmento (o reduciéndolo disminuyéndolo). El tamaño del fragmento debe ser un múltiplo de 2 para hacer un uso completo de la FFT. Además, solo estoy determinando el tono fundamental para cada fragmento sin superposición. Utilicé PyAudio para reproducir el sonido mientras escribía el tono estimado. Código
Fuente:
# 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()
Esto puede ser útil (asegúrese de leer las respuestas): http://www.keyongtech.com/5003865-frequency-analysis-without-numpy – ChristopheD