tutorial ruby audio mp3 fft wav

ruby - fft matlab tutorial



Extraer datos de Fast Fourier Transform del archivo (2)

Estoy construyendo una herramienta que se supone que se ejecuta en un servidor y analiza archivos de sonido. Quiero hacer esto en Ruby ya que todas mis otras herramientas están escritas en Ruby también. Pero estoy teniendo problemas para encontrar una buena forma de lograr esto.

Muchos de los ejemplos que he encontrado han estado haciendo visualizadores y cosas gráficas. Solo necesito los datos de FFT, nada más. Necesito obtener los datos de audio y hacer una FFT en él. Mi objetivo final es calcular algunas cosas como la media / mediana / modo, percentil 25 y percentil 75 en todas las frecuencias (amplitud ponderada), el BPM, y tal vez alguna otra característica buena para luego poder agrupar sonidos similares juntos .

Primero traté de usar ruby-audio y fftw3 pero nunca voy a los dos para trabajar realmente juntos. La documentación tampoco era buena, así que realmente no sabía qué datos se barajaban. Luego traté de usar bplay / brec y limitar mi script de Ruby para simplemente usar STDIN y realizar una FFT en eso (aún usando fftw3). Pero no pude hacer que bplay / brec funcionara porque el servidor no tiene una tarjeta de sonido y no logré simplemente llevar el audio directamente a STDOUT sin tener que ir primero a un dispositivo de audio.

Esto es lo más cercano que he recibido:

# extracting audio from wav with ruby-audio buf = RubyAudio::Buffer.float(1024) RubyAudio::Sound.open(fname) do |snd| while snd.read(buf) != 0 # ??? end end # performing FFT on audio def get_fft(input, window_size) data = input.read(window_size).unpack("s*") na = NArray.to_na(data) fft = FFTW3.fft(na).to_a[0, window_size/2] return fft end

Así que ahora estoy atascado y no puedo encontrar más buenos resultados en Google. ¿Entonces tal vez ustedes, chicos, pueden ayudarme?

¡Gracias!


Creo que hay dos problemas aquí. Uno recibe las muestras, el otro realiza la FFT.

Para obtener las muestras, hay dos pasos principales: decodificación y downmixing. Para decodificar archivos wav, solo necesita analizar el encabezado para que pueda saber cómo interpretar las muestras. Para archivos mp3, necesitarás hacer una decodificación completa. Una vez que el audio ha sido decodificado, si no está interesado en procesar los canales estéreo por separado, puede necesitar mezclarlo en mono, ya que la FFT espera un solo canal como entrada. Si no te importa aventurarte fuera de Ruby, la herramienta sox lo hace fácil. Por ejemplo, sox song.mp3 -b 16 song.raw channels 1 debe convertir un mp3 en un archivo mono de muestras PCM puras (es decir, enteros de 16 bits). Por cierto, una búsqueda rápida reveló la biblioteca de ruby / audio (tal vez es la que se menciona en su publicación). Se ve bastante bien, especialmente porque envuelve libsndfile.

Para realizar la FFT, veo tres opciones. Una es usar este fragmento de código que realiza una FFT. No soy un experto en Ruby, pero parece que podría estar bien. La segunda opción es usar NArray . Tiene una tonelada de métodos matemáticos, incluyendo FFTW, disponible en un módulo separado, un tarball para el cual está vinculado en el medio de la página NArray. La tercera opción es escribir su propio código FFT. No es un algoritmo especialmente complicado, y podría darte una gran experiencia con el procesamiento numérico en Ruby (si lo necesitas).

Probablemente esté al tanto de esto, pero la FFT espera entradas complejas y genera resultados complejos. Las señales de audio son reales, por supuesto, por lo que el componente imaginario de la entrada siempre debe ser cero ( a + 0*i ). Como su entrada es real, la salida será simétrica alrededor del punto medio de la matriz de salida. Puede ignorar con seguridad la mitad superior. Si desea la energía en un contenedor de frecuencia particular (están espaciados linealmente hasta la mitad de la frecuencia de muestreo), necesitará calcular la magnitud del valor complejo ( sqrt(real*real + imag*imag) ).

Una cosa más: como la frecuencia cero (el desplazamiento de DC de la señal) y la frecuencia de Nyquist (la mitad de la frecuencia de muestreo) no tienen componentes de fase, algunas implementaciones de FFT los juntan en el mismo bin complejo (uno en el componente real, uno en el componente imaginario, típicamente del primer contenedor). Puede crear algunas señales simples (todas 1 para solo una señal de CC, y alternar +1, -1 para una señal de Nyquist) y ver cómo se ve la salida de FFT.


Aquí está la solución final a lo que estaba tratando de lograr, gracias a los consejos útiles de Randall Cook. El código para extraer la onda de sonido y FFT de un archivo wav en Ruby:

require "ruby-audio" require "fftw3" fname = ARGV[0] window_size = 1024 wave = Array.new fft = Array.new(window_size/2,[]) begin buf = RubyAudio::Buffer.float(window_size) RubyAudio::Sound.open(fname) do |snd| while snd.read(buf) != 0 wave.concat(buf.to_a) na = NArray.to_na(buf.to_a) fft_slice = FFTW3.fft(na).to_a[0, window_size/2] j=0 fft_slice.each { |x| fft[j] << x; j+=1 } end end rescue => err log.error "error reading audio file: " + err exit end # now I can work on analyzing the "fft" and "wave" arrays...