2010-12-13 76 views
8

Ce que j'essaie de réaliser est la suivante: J'ai besoin des valeurs de fréquence d'un fichier son (.wav) pour l'analyse. Je sais que beaucoup de programmes donneront un graphique visuel (spectrogramme) des valeurs mais j'ai besoin de données brutes. Je sais que cela peut être fait avec FFT et devrait être assez facilement scriptable en python, mais je ne sais pas comment le faire exactement. Donc disons qu'un signal dans un fichier a une longueur de .4s alors je voudrais que plusieurs mesures donnent une sortie sous forme de tableau pour chaque point temporel mesuré par le programme et quelle valeur (fréquence) il trouve (et éventuellement puissance (dB)). La chose compliquée est que je veux analyser les chants d'oiseaux, et ils ont souvent des harmoniques ou le signal est sur une gamme de fréquence (par exemple 1000-2000 Hz). Je voudrais que le programme produise également cette information, puisque c'est important pour l'analyse que je voudrais faire avec les données :)Détection de fréquence à partir d'un fichier son

Maintenant, il y a un morceau de code qui ressemblait beaucoup à ce que je voulais, mais je pense que ça ne me donne pas toutes les valeurs que je veux ... (merci à Justin Peel d'avoir posté cette question à une autre :)) Donc je comprends que j'ai besoin de numpy et pyaudio mais malheureusement je ne suis pas familier avec python En espérant qu'un expert en Python puisse m'aider à ce sujet?

Code Source:

# 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

Avez-vous déjà essayé "search"? Cette question a été posée. http://stackoverflow.com/questions/2648151/python-frequency-detection par exemple. –

+1

Oui, c'est au moins la 5ème fois que cette question a été soulevée sur SO au cours des 2 dernières semaines. – Brad

+0

Oui, j'avais cherché et regardé autour .. mais je n'ai pas trouvé la réponse exacte dont j'avais besoin. Mais tout en cherchant plus loin j'ai trouvé un programme qui fait exactement ce dont j'ai besoin gratuitement :) analyse sonore pro si quelqu'un d'autre lit cette question et cherche à faire des choses similaires. Vous pouvez obtenir les données (fréquence, etc.) avec ce programme exporté vers Excel ou matlab! –

Répondre

8

Je ne sais pas si c'est ce que vous voulez, si vous voulez juste la FFT:

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

Si vous voulez que la réponse d'amplitude:

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

Je l'ai eu pour fonctionner mais seulement sur les fichiers son mono. Stéréo semble être un problème –

+0

Utilisez 'x [:, 0]' au lieu de 'x'. –

+1

Impression de la valeur X donnant cette sortie '[-1.15917969 + 0.j -0.06542969 + 0.j -0.06542969 + 0.j ..., -0.06542969 + 0.j -0.06542969 + 0.j -0.06542969 + 0 .j] 'Mais je devrais avoir une seule fréquence, non? où est la fréquence – AQU

5

Je pense que ce que vous devez faire est un Short-time Fourier Transform (STFT). Fondamentalement, vous faites plusieurs FFT se chevauchant partiellement et les ajouter ensemble pour chaque moment. Ensuite, vous trouverez le pic pour chaque moment. Je ne l'ai pas fait moi-même, mais j'ai déjà étudié la question par le passé et c'est certainement le moyen d'aller de l'avant.

Il y a du code Python pour faire un STFT here et here.

+0

Merci! Le deuxième lien ressemble vraiment à ce dont j'ai besoin. Je vais essayer ça! –