audio signal-processing fft pitch-tracking

audio - Reconocimiento de tono de notas musicales en un teléfono inteligente



signal-processing fft (5)

El cruce por cero no funcionará porque un sonido típico tiene armónicos y cruces por cero mucho más que la frecuencia base.

Algo con lo que experimenté (como un proyecto local) fue este:

  1. Pruebe el sonido con ADC a la frecuencia de muestreo que necesite.
  2. Detecta los niveles de los picos positivos y negativos a corto plazo de la forma de onda (ventana deslizante o similar). Es decir, un detector de envolvente.
  3. Haz una onda cuadrada que sube cuando la forma de onda va dentro del 90% (más o menos) de la envolvente positiva, y baja cuando la forma de onda va dentro del 90% de la envolvente negativa. Es decir, una onda cuadrada de seguimiento con histéresis.
  4. Mida la frecuencia de esa onda cuadrada con cálculos simples de recuento / tiempo, usando tantas muestras como necesite para obtener la precisión requerida.

Sin embargo, descubrí que con las entradas de mi teclado electrónico, para algunos sonidos de instrumento conseguía obtener 2 veces la frecuencia base (octava siguiente). Este fue un proyecto paralelo y nunca llegué a implementar una solución antes de pasar a otras cosas. Pero pensé que era prometedor ya que era mucho menos carga de CPU que FFT.

Con recursos limitados, como CPU más lentas, tamaño de código y RAM, ¿cuál es la mejor manera de detectar el tono de una nota musical, similar a lo que haría un sintonizador electrónico o de software?

Debería usar:

  • Beso FFT
  • FFTW
  • Transformada Wavelet Discreta
  • autocorrelación
  • análisis de cruce por cero
  • filtros de octava espaciados

¿otro?

En pocas palabras, lo que estoy tratando de hacer es reconocer una sola nota musical, dos octavas por debajo del medio-C a dos octavas por encima, reproducidas en cualquier instrumento (razonable). Me gustaría estar dentro del 20% del semitono; en otras palabras, si el usuario juega demasiado plano o demasiado agudo, necesito distinguirlo. Sin embargo, no necesitaré la precisión requerida para sintonizar.


En mi proyecto danstuner , tomé el código de Audacity . Básicamente tomó una FFT, luego encontró la potencia máxima al poner una curva cúbica en la FFT y encontrar el pico de esa curva. Funciona bastante bien, aunque tuve que protegerme contra el salto de octavas.

Ver Spectrum.cpp .


No estoy familiarizado con todos los métodos que menciona, pero lo que elija dependerá principalmente de la naturaleza de sus datos de entrada. ¿Estás analizando tonos puros o tu fuente de entrada tiene múltiples notas? ¿El habla es una característica de tu entrada? ¿Hay alguna limitación en el tiempo que tiene para muestrear la entrada? ¿Puedes intercambiar algo de precisión por velocidad?

Hasta cierto punto, lo que elijas también depende de si deseas realizar tus cálculos a time o en el espacio de frecuencia . Convertir una serie de tiempo en una representación de frecuencia lleva tiempo, pero en mi experiencia tiende a dar mejores resultados.

Autocorrelation compara dos señales en el dominio del tiempo. Una implementación ingenua es simple pero relativamente costosa de calcular, ya que requiere diferenciación por pares entre todos los puntos en las señales originales y desplazadas en el tiempo, seguida de la diferenciación para identificar puntos de inflexión en la función de autocorrelación, y luego la selección del mínimo correspondiente a la frecuencia fundamental. Hay métodos alternativos. Por ejemplo, la Diferencia de Magnitud Promedio es una forma muy barata de autocorrelación, pero la precisión sufre. Todas las técnicas de autocorrelación corren el riesgo de errores de octava, ya que existen picos distintos de los fundamentales en la función.

La medición de puntos de cruce por cero es simple y directa, pero tendrá problemas si tiene múltiples formas de onda presentes en la señal.

En el espacio de frecuencia, las técnicas basadas en FFT pueden ser lo suficientemente eficientes para sus propósitos. Un ejemplo es la técnica de espectro de producto armónico, que compara el espectro de potencia de la señal con versiones reducidas de muestreo en cada armónico, e identifica el tono multiplicando los espectros para producir un pico claro.

Como siempre, no hay sustituto para probar y perfilar varias técnicas, para determinar empíricamente qué funcionará mejor para su problema y sus limitaciones.

Una respuesta como esta solo puede rayar la superficie de este tema. Además de los enlaces anteriores, aquí hay algunas referencias relevantes para lecturas adicionales.


Si desea realizar el reconocimiento de tono en tiempo real (y con una precisión de 1/100 de un semitono), su única esperanza real es el enfoque de cruce por cero. Y es una débil esperanza, siento decirlo. El cruce por cero puede estimar el tono desde solo un par de longitudes de onda de datos, y puede hacerse con la potencia de procesamiento de un teléfono inteligente, pero no es especialmente preciso, ya que pequeños errores en la medición de las longitudes de onda resultan en errores grandes en la frecuencia estimada. Dispositivos como los sintetizadores de guitarra (que deducen el tono de una cuerda de guitarra con solo un par de longitudes de onda) funcionan cuantificando las medidas a las notas de la escala. Esto puede funcionar para sus propósitos, pero tenga en cuenta que el cruce por cero funciona muy bien con formas de onda simples, pero tiende a funcionar cada vez menos bien con sonidos de instrumentos más complejos.

En mi aplicación (un sintetizador de software que se ejecuta en teléfonos inteligentes) uso grabaciones de notas de instrumentos individuales como materia prima para la síntesis wavetable, y para producir notas en un tono particular, necesito conocer el tono fundamental de una grabación, precisa dentro de 1/1000 de un semitono (realmente solo necesito 1/100 de precisión, pero soy TOC sobre esto). El enfoque de cruce por cero es demasiado impreciso para esto, y los enfoques basados ​​en FFT son demasiado imprecisos o demasiado lentos (o ambos a veces).

El mejor enfoque que he encontrado en este caso es utilizar la autocorrelación. Con la autocorrelación, básicamente adivina el tono y luego mide la autocorrelación de la muestra en esa longitud de onda correspondiente. Al escanear el rango de tonos plausibles (por ejemplo, A = 55 Hz hasta A = 880 Hz) por semitonos, ubico el tono más correlacionado, luego realizo un escaneo más fino en las cercanías de ese tono para obtener un valor más preciso.

El enfoque que mejor se adapta a usted depende completamente de lo que esté tratando de usar.


Si no necesita tanta precisión, una FFT podría ser suficiente. Primero, escanee el fragmento de audio para obtener picos bien definidos y luego encuentre el primer pico significativo.

Ancho del contenedor = velocidad de muestreo / tamaño de FFT:

Los fundamentos varían de 20 Hz a 7 kHz, por lo que una frecuencia de muestreo de 14 kHz sería suficiente. La siguiente tasa de muestreo "estándar" es 22050 Hz.

El tamaño de FFT se determina por la precisión que desea. La salida de FFT es de frecuencia lineal, mientras que los tonos musicales son de frecuencia logarítmica, por lo que la peor de las situaciones será a bajas frecuencias. Para el 20% de un semitono a 20 Hz, necesita un ancho de 1,2 Hz , lo que significa una longitud de FFT de 18545 . La siguiente potencia de dos es 2 15 = 32768. Esto es 1.5 segundos de datos, y toma el procesador de mi computadora portátil 3 ms para calcular.

Esto no funcionará con señales que tienen un " fundamental perdido ", y encontrar el pico "primero significativo" es algo difícil (ya que los armónicos son a menudo más altos que el fundamental ), pero puedes encontrar la manera que se adapte a tu situación.

La autocorrelación y el espectro de productos armónicos son mejores para encontrar el verdadero fundamental para una onda en lugar de uno de los armónicos, pero no creo que se manejen tan bien con inharmonicity , y la mayoría de los instrumentos como el piano o la guitarra son inarmónicos (los armónicos son ligeramente agudos de lo que deberían ser). Sin embargo, realmente depende de tus circunstancias.

Además, puede ahorrar aún más ciclos de procesador calculando solo dentro de una banda de frecuencia de interés específica, utilizando la transformación Chirp-Z .

He escrito algunos métodos diferentes en Python para fines de comparación.