Análisis armónico

 

*Necesitas utilizar Google Chrome
  • Volumen:
  • NOTA:  --
  • Tamaño de la FFT 0
  • Frecuencia de Muestreo: 0
  • Frecuencia de Nyquist: 0
  • Long. del Array de datos de frec. 8 Bits : 0
  • Valor del máximo:  0
  • Posiciones de los armónicos: posicion
  • Posiciones -
  • Picos de frecuencia: picos Hz
  • Frecuencias: -
  • Mayor Frecuencia: frecuencia Hz
  • Umbral de detección: -6 dB

El proceso de detección

El principal problema de utilizar el Nodo Analizador como elemento base en la detección de frecuencias, es la resolución en la parte baja del espectro. Nuesto ContextodeAudio utiliza una frecuencia de muestreo de 44100Hz, y ajustando el valor del tamaño de la Trasformada de Fourier a 2048, podemos crear vectores de 1024 muestras, que en este caso se cuantifican con 1Byte. En este contexto, podemos rastrear en nuestro array de datos la secuencia armónica de cada nota y crear un filtro comparador para aproximar un valor. Las desviaciones de frecuencia de la muestra tomada, respecto al valor armónico original, están categorizadas en 3 tipos (±1Hz, ±5Hz y ±10Hz). a partir de las desviaciones de los cuatro primeros armónicos de cada cuerda, podemos aproximar una nota.

En el display superior aparecen destacados los picos de frecuencia que superan el umbral de amplitud de 128. Este vector de picos es el que compararemos con un banco de notas. Por ejemplo un MI de la sexta cuerda se mostrará cuando los 3 picos de más amplitud, correspondan a las posiciones 8, 15 y 31.

Las desviaciones de ¼ de tono sobre la nota, las determinará los armónicos superiores, en este caso el que ocupa la posición 31, centrado en 667 Hz. La precisión aumentaría a un ⅙ de tono si añadiéramos el valor del siguiente armonico (61) y podría mejorar si añadiésemos el siguiente (122), pero son armónicos de poco nivel que se enmascaran rápido.

Correspondencia de frecuencias
  C C# D Eb E F F# G G# A Bb B
2 65.41 69.30 73.42 77.78 82.41 87.31 92.50 98.00 103.8 110.0 116.5 123.5
3 130.8 138.6 146.8 155.6 164.8 174.6 185.0 196.0 207.7 220.0 233.1 246.9
4 261.6 277.2 293.7 311.1 329.6 349.2 370.0 392.0 415.3 440.0 466.2 493.9
5 523.3 554.4 587.3 622.3 659.3 698.5 740.0 784.0 830.6 880.0 932.3 987.8
6 1047 1109 1175 1245 1319 1397 1480 1568 1661 1760 1865 1976
7 2093 2217 2349 2489 2637 2794 2960 3136 3322 3520 3729 3951
8 4186 4435 4699 4978 5274 5588 5920 6272 6645 7040 7459 7902
Código de colores: Nota- Nota Nota+ Armónico centrado en ±1Hz Armónico centrado en ±5Hz Armónico centrado en ±10Hz

Resolución

Precisión

La detección basada en la carga armónica tiene una precisión limitada, sobre ¼ de tono para la parte baja de la guitarra y casi el doble para las 3 primeras cuerdas. Este ajuste se realiza con los armónicos superiores, donde la resolución de la trasformada nos permite distingir con más exactitud los intervalos de frecuencia. En la tabla de la izquierda aparecerán sombreadas las celdas de los armónicos detectados, y en caso de corresponder a una serie armónica determinada, se sombreará la cabecera con los códigos de las notas musicales.

El tamaño de cada muestra es de 21.53Hz, que es la máxima resolución del analizador. Esta resolución es insuficiente para medir pasos <5Hz en la parte baja del espectro de la guitarra, pero si seguimos el rastro armónico de la nota en la tabla de frecuencia y comparamos este grupo de valores con los armónicos de cada nota podemos mostrar en pantalla un resultado bastante aproximado.

Funcionamiento

Una vez procesamos la petición .webkitGetUserMedia y creada la fuente de audio, podemos enrutar la señal en nuestra cadena de audio y comenzar el procesado. El nodo analizador es clave para el análisis, pues nos proveerá los datos necesarios para realizar el cálculo o aproximación de nota, y utilizaremos la función requestAnimationFrame para realizar el análisis y el dibujo, solicitaremos los datos de la salida del nodo analizador para trabajar con ellos.



//Tomamos un byte de enteros, array de 256 valores de amplitud y 1028 muestras

var ByteDatosFrec = new Uint8Array(analizador.frequencyBinCount);

analizador.getByteFrequencyData(ByteDatosFrec);



    

Una vez contamos con un array de datos de la ventana de frecuencia, podemos recorrerlo para obtener sus picos, que serán los valores máximos del vector que superen un umbral. Para optimizar el funcionamiento y descartar sonidos de fondo, se ha establecido un umbral en la detección de pico de valor 128 en la escala de amplitud de la señal, esto es la mitad del valor máximo que se puede detectar. Este sería el primer bloque del algoritmo de análisis.




//Recorrer el array de datos de frecuencia Comparar valores mayores que el umbral

for (var m = 0; m <= (ByteDatosFrec.length); m++) {

    var magnitud = ByteDatosFrec[m];

    var siguiente = ByteDatosFrec[m + 1];

    var anterior = ByteDatosFrec[m - 1];

    // se establece el umbral a 128. 

    if ((magnitud > maximo) && (magnitud > siguiente) && (magnitud > anterior) && (magnitud > 128)) {



        pico = magnitud;

        //Creamos nuestra matriz de valores y posiciones

        valores.push(pico);

        posiciones.push(m);



        var pos = m;

        var frecuencia = ((pos * contextoDeAudio.sampleRate) / contextoDeAudio.analizador.fftSize);

    }

    

Podemos enumerar las etapas del algoritmo de detección, de la siguiente manera:

Bloques de procesado

  • Bucle Comparador: recorre el vector de datos de frecuencia y selecciona los picos y sus posiciones. Sólo añade los valores detectados como pico y que superen el umbral de 128 valores del Byte. Se crean 2 vectores que formarán la matriz de posiciones y valores
  • Adecuación de valores para visualización: se ordenan los picos por amplitud y se limitan a un número de entradas para una visualización óptima.
  • Declaración de notas: Se declara un banco de 12 notas y sus desviaciones altas y bajas. Se utiliza una nemotécnica de incrementar o disminuir el valor del último armónico para el ajuste fino, por ejemplo:
  • 
    
    
             //A
    
            var A5 = [5, 10, 20, 41];
    
            var A5b = [5, 10, 20, 40];
    
            var A5bb = [5, 10, 20, 39];
    
            var A5a = [5, 10, 20, 42];
    
            var A5aa = [5, 10, 21, 42];
    
            var A2 = [10, 20, 41];
    
            
    
    
    
    

    En este fragmento de código se observa la declaración de la nota LA. Esta declaración de variables se ha optimizado para las notas susceptibles de mostrarse en la guitarra. En el ejemplo se observa la declaración de A5, que corresponde al LA de la 5ª cuerda tocada al aire, este valor es imprescindible durante el proceso de afinación general de una guitarra, así como el LA de la segunda cuerda al aire, por el que posiblemente pasemos al tensar la cuerda hacia el SI que corresponde a la 2ª cuerda en la afinación estándar. Los sufijos a, aa y b, bb indican los valores altos de esta nota que mostraremos en el display y que servirán al usuario para ajustar la tensión de la cuerda en una dirección y aproximarse al valor correcto de afinación.

  • Selección de nota: Este es el apartado que más se puede optimizar dentro bucle de análisis ya que por el momento consta de un condicional por cada posible nota.
  • Visualización: Los valores se imprimen en pantalla en tiempo de ejecución de la interfaz requestAnimationFrame, por lo que el parpadeo es rápido. Esto es una buena cualidad para variaciones de tensión rápidas en la cuerda, que generen cambios de afinación repentinos.

Forma de onda