2010-12-13 19 views
8

Lo que estoy tratando de lograr es lo siguiente: Necesito los valores de frecuencia de un archivo de sonido (.wav) para el análisis. Sé que muchos programas darán un gráfico visual (espectrograma) de los valores, pero necesito datos brutos. Sé que esto se puede hacer con FFT y debería ser bastante fácil de programar en Python, pero no estoy seguro de cómo hacerlo exactamente. Digamos que una señal en un archivo tiene una duración de .4s, luego me gustaría obtener múltiples mediciones dando como resultado una matriz para cada punto de tiempo que el programa mide y qué valor (frecuencia) encontró (y posiblemente potencia (dB) también). Lo complicado es que quiero analizar canciones de pájaros, y a menudo tienen armónicos o la señal está en un rango de frecuencia (por ejemplo, 1000-2000 Hz). Me gustaría que el programa también produzca esta información, ya que esto es importante para el análisis que me gustaría hacer con los datos :)Detección de frecuencia de un archivo de sonido

Ahora hay un código que se parecía mucho a lo que yo quería, pero Creo que no me da todos los valores que quiero ... (gracias a Justin Peel por publicar esto en una pregunta diferente :)) Así que deduzco que necesito un numpy y un pyaudio, pero desafortunadamente no estoy familiarizado con Python, así que estoy ¿Espero que un experto en Python pueda ayudarme con esto?

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() 
+3

¿Has intentado "buscar" todavía? Esta pregunta ha sido hecha. http://stackoverflow.com/questions/2648151/python-frequency-detection por ejemplo. –

+1

Sí, esta es al menos la quinta vez que esta pregunta ha aparecido en SO en las últimas 2 semanas. – Brad

+0

Sí, busqué y miré ... pero no encontré la respuesta exacta que necesitaba. Pero mientras buscaba más encontré un programa que hace exactamente lo que necesito gratis :) análisis de sonido pro si alguien más lee esta pregunta y está buscando hacer cosas similares. ¡Puede obtener los datos (frecuencia, etc.) con este programa exportado a Excel o a Matlab! –

Respuesta

8

No estoy seguro si esto es lo que quieres, si lo que desea la FFT:

import scikits.audiolab, scipy 
x, fs, nbits = scikits.audiolab.wavread(filename) 
X = scipy.fft(x) 

Si desea que la respuesta de magnitud:

import pylab 
Xdb = 20*scipy.log10(scipy.absolute(X)) 
f = scipy.linspace(0, fs, len(Xdb)) 
pylab.plot(f, Xdb) 
pylab.show() 
+0

Lo hice funcionar pero solo en archivos de sonido mono. Stereo parece ser un problema –

+0

Use 'x [:, 0]' en lugar de 'x'. –

+1

Impresión del valor X dando esta salida '[-1.15917969 + 0.j -0.06542969 + 0.j -0.06542969 + 0.j ..., -0.06542969 + 0.j -0.06542969 + 0.j -0.06542969 + 0 .j] 'Pero debería obtener solo una frecuencia, ¿verdad? donde es la frecuencia – AQU

5

Creo que lo que necesita hacer es un Short-time Fourier Transform (STFT). Básicamente, realiza múltiples FFT parcialmente superpuestas y las agrega juntas para cada punto en el tiempo. Luego, encontrarías el pico para cada punto en el tiempo. No he hecho esto por mí mismo, pero lo he analizado en el pasado y esta es definitivamente la manera de seguir adelante.

Hay un código de Python para hacer un STFT here y here.

+0

Gracias! El segundo enlace definitivamente se ve como lo que necesito. Voy a probar esto! –

Cuestiones relacionadas