Una manera sencilla de realizar FFT desde cualquier sistema operativo sin necesidad de disponer de programas como MATLAB, Octave o Mathematica, es utilizando un script de Python. Este lenguaje cuenta con la ventaja de ser muy sencillo y además de disponer una ingente cantidad de librerías para poder hacer casi cualquier cosa.
El objetivo de este pequeño programa es realizar una FFT de un trozo de audio grabado directamente desde un micrófono. Para ello se realiza una escucha pasiva a la espera de un sonido cuyo volumen esté por encima de un determinado umbral. Este umbral se puede modificar con la variable threshold, y dependiendo del micrófono y su sensibilidad debe de ser ajustado de manera diferente. Una vez detectado, se graba unos pocos segundos de audio, cuya longitud puede ser modificada en el segundo bucle for. Actualmente graba aproximadamente 1 segundo, pero si se cambia el 7 por un 100 la longitud es de 13 segundos.
El audio se guarda como un archivo para ser posteriormente utilizado en el cálculo de la FFT y ser graficada al momento. Todo este procedimiento está dentro de un bucle infinito, por lo que, aunque la ventana de la gráfica es bloqueante, está continuamente escuchando.
Las librerías necesarias para poder ejecutar este script son: numpy, matplotlib, pyaudio y scipy.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import pyaudio
import struct
import math
import wave
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile
#import urllib
#import urllib2
import os
class Microphone:
def rms(self,frame):
count = len(frame)/2
format = "%dh"%(count)
shorts = struct.unpack( format, frame )
sum_squares = 0.0
for sample in shorts:
n = sample * (1.0/32768.0)
sum_squares += n*n
rms = math.pow(sum_squares/count,0.5);
return rms * 1000
def passiveListen(self,persona):
CHUNK = 1024; RATE = 8000; THRESHOLD = 200; LISTEN_TIME = 5
didDetect = False
# prepare recording stream
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=RATE, input=True, frames_per_buffer=CHUNK)
# stores the audio data
all =[]
# starts passive listening for disturbances
print RATE / CHUNK * LISTEN_TIME
for i in range(0, RATE / CHUNK * LISTEN_TIME):
input = stream.read(CHUNK)
rms_value = self.rms(input)
print rms_value
if (rms_value < THRESHOLD):
didDetect = True
print "Listening...\n"
break
if not didDetect:
stream.stop_stream()
stream.close()
return False
# append all the chunks
all.append(input)
for i in range(0, 7):
data = stream.read(CHUNK)
all.append(data)
# save the audio data
data = ''.join(all)
stream.stop_stream()
stream.close()
wf = wave.open('audio.wav', 'wb')
wf.setnchannels(1)
wf.setsampwidth(p.get_sample_size(pyaudio.paInt16))
wf.setframerate(RATE)
wf.writeframes(data)
wf.close()
return True
if __name__ == '__main__':
mic = Microphone()
while True:
if mic.passiveListen('ok Google'):
fs, data = wavfile.read('audio.wav')
L = len(data)
c = np.fft.fft(data) # create a list of complex number
freq = np.fft.fftfreq(L)
#freq = np.linspace(0, 1/(2L), L/2)
print freq
freq_in_hertz = abs(freq * fs)
plt.plot(freq_in_hertz, abs(c))
plt.show()
Buenas el trozo de codigo que has dejado me ha sido muy util para aprender a usar una FFT en sonido. Muchas gracias. Por cierto en la linea 48. if (rms_value > THRESHOLD): me daba fallo el copilador de python lo he sustituido por: if (rms_value >= THRESHOLD): y el programa funciona correctamente. Un saludo
Hola Francisco,
me alegro de que te haya sido de ayuda. Revisaré el código y lo corregiré, ¡muchas gracias!
Hola, muy bueno este código, en la línea 37 me marca un error, dice que es en passiveListen, podrían ayudarme a corregir esto, se los agradecería mucho.