Nota detección de inicio

Estoy desarrollando un sistema como una ayuda para los músicos que realizan la transcripción. El objective es realizar transcripciones de música automáticas (no tiene que ser perfecto, ya que el usuario corregirá fallas / errores más adelante) en una sola grabación monofónica de instrumento. ¿Alguien aquí tiene experiencia en la transcripción automática de música? O el procesamiento digital de señales en general? La ayuda de cualquier persona es muy apreciada sin importar su origen.

Hasta ahora he investigado el uso de la Transformada Rápida de Fourier para la detección del tono, y una serie de pruebas tanto en MATLAB como en mis propios progtwigs de prueba de Java han demostrado que es lo suficientemente rápido y preciso para mis necesidades. Otro elemento de la tarea que tendrá que abordarse es la visualización de los datos MIDI producidos en forma de partitura, pero esto es algo que no me preocupa en este momento.

En resumen, lo que estoy buscando es un buen método para la detección de inicio de notas, es decir, la posición en la señal donde comienza una nueva nota. Como los inicios lentos pueden ser bastante difíciles de detectar correctamente, inicialmente utilizaré el sistema con grabaciones de piano. Esto también se debe en parte al hecho de que toco el piano y debería estar en una mejor posición para obtener grabaciones adecuadas para las pruebas. Como se mencionó anteriormente, las primeras versiones de este sistema se usarán para grabaciones monofónicas simples, que posiblemente progresen más tarde a entradas más complejas dependiendo del progreso realizado en las próximas semanas.

Aquí hay un gráfico que ilustra el enfoque de umbral para detectar la aparición de notas:

texto alternativo

Esta imagen muestra un archivo WAV típico con tres notas discretas reproducidas en sucesión. La línea roja representa un umbral de señal elegido, y las líneas azules representan posiciones de inicio de nota devueltas por un algoritmo simple que marca un inicio cuando el nivel de señal cruza el umbral.

Como muestra la imagen, es difícil seleccionar un umbral absoluto adecuado. En este caso, la primera nota se recoge bien, la segunda nota se pierde por completo, y la tercera nota (apenas) se inicia muy tarde. En general, un umbral bajo hace que recojas notas fantasmas, mientras que alzarlo te hace perder notas. Una solución a este problema es usar un umbral relativo que desencadena un inicio si la señal aumenta en cierto porcentaje durante un cierto tiempo, pero esto tiene sus propios problemas.

Una solución más simple es usar la compresión con un nombre un tanto contradictorio ( no compresión MP3, eso es otra cosa completamente ) en su archivo wave primero. La compresión esencialmente aplana los picos en los datos de audio y amplifica todo para que la mayor parte del audio esté cerca de los valores máximos. El efecto en la muestra anterior se vería así (lo que muestra por qué el nombre de “compresión” parece no tener sentido – en el equipo de audio generalmente se denomina “volumen”):

texto alternativo

Después de la compresión, el enfoque de umbral absoluto funcionará mucho mejor (aunque es fácil sobrecomprimir y comenzar a detectar los inicios de notas ficticias, el mismo efecto que reducir el umbral). Hay muchos editores de onda que hacen un buen trabajo de compresión, y es mejor dejarlos manejar esta tarea. Probablemente necesites hacer una buena cantidad de trabajo “limpiando” tus archivos de onda antes de detectar notas en ellos de todos modos.

En términos de encoding, un archivo WAV cargado en la memoria es básicamente una matriz de enteros de dos bytes, donde 0 representa ninguna señal y 32.767 y -32.768 representan los picos. En su forma más simple, un algoritmo de detección de umbral simplemente comenzaría en la primera muestra y leería la matriz hasta que encuentre un valor mayor que el umbral.

short threshold = 10000; for (int i = 0; i < samples.Length; i++) { if ((short)Math.Abs(samples[i]) > threshold) { // here is one note onset point } } 

En la práctica, esto funciona de manera horrible, ya que el audio normal tiene todo tipo de picos transitorios por encima de un umbral determinado. Una solución es usar una intensidad de señal media en funcionamiento (es decir, no marque un inicio hasta que el promedio de las últimas n muestras esté por encima del umbral).

 short threshold = 10000; int window_length = 100; int running_total = 0; // tally up the first window_length samples for (int i = 0; i < window_length; i++) { running_total += samples[i]; } // calculate moving average for (int i = window_length; i < samples.Length; i++) { // remove oldest sample and add current running_total -= samples[i - window_length]; running_total += samples[i]; short moving_average = running_total / window_length; if (moving_average > threshold) { // here is one note onset point int onset_point = i - (window_length / 2); } } 

Todo esto requiere mucho ajuste y jugar con la configuración para que encuentre las posiciones de inicio de un archivo WAV con precisión, y generalmente lo que funciona para un archivo no funcionará muy bien en otro. Este es un dominio de problema muy difícil y no perfectamente resuelto que ha elegido, pero creo que es genial que lo esté abordando.

Actualización: este gráfico muestra un detalle de detección de notas que omití, es decir, detectar cuándo termina la nota:

texto alternativo

La línea amarilla representa el fuera de umbral. Una vez que el algoritmo ha detectado un inicio de nota, asume que la nota continúa hasta que la intensidad de la señal promedio en curso cae por debajo de este valor (se muestra aquí con las líneas violetas). Esta es, por supuesto, otra fuente de dificultades, como es el caso donde dos o más notas se superponen (polifonía).

Una vez que haya detectado los puntos de inicio y fin de cada nota, ahora puede analizar cada porción de datos de archivos WAV para determinar los tonos.

Actualización 2: acabo de leer su pregunta actualizada. La detección de tono a través de la autocorrelación es mucho más fácil de implementar que la FFT si está escribiendo la suya desde el principio, pero si ya ha prestado y usado una biblioteca FFT preconstruida, es mejor que la use para asegurarse . Una vez que haya identificado las posiciones de inicio y finalización de cada nota (e incluyó algo de relleno al principio y al final para las partes de ataque y liberación perdidas), ahora puede extraer cada porción de datos de audio y pasarla a una función FFT para determinar el tono.

Un punto importante aquí es no usar una porción de los datos de audio comprimidos, sino utilizar una porción de los datos originales no modificados. El proceso de compresión distorsiona el audio y puede producir una lectura de tono incorrecta.

Un último punto sobre los tiempos de ataque de las notas es que puede ser menos problemático de lo que piensas. A menudo, en la música, un instrumento con un ataque lento (como un sintetizador suave) comenzará una nota antes que un instrumento de ataque fuerte (como un piano) y ambas notas sonarán como si estuvieran comenzando al mismo tiempo. Si está tocando instrumentos de esta manera, el algoritmo recoge el mismo tiempo de inicio para ambos tipos de instrumentos, lo cual es bueno desde una perspectiva WAV a MIDI.

Última actualización (espero): Olviden lo que dije sobre incluir algunas muestras de paddings de la parte de ataque inicial de cada nota. Olvidé que esta es una mala idea para la detección de tono. Las porciones de ataque de muchos instrumentos (especialmente el piano y otros instrumentos de tipo percusivo) contienen transitorios que no son múltiplos del tono fundamental, y tenderán a estropear la detección de tono. En realidad, desea comenzar cada porción un poco después del ataque por este motivo.

Ah, y algo importante: el término “compresión” aquí no se refiere a la compresión de estilo MP3 .

Actualizar nuevamente: aquí hay una función simple que no hace compresión dinámica:

 public void StaticCompress(short[] samples, float param) { for (int i = 0; i < samples.Length; i++) { int sign = (samples[i] < 0) ? -1 : 1; float norm = ABS(samples[i] / 32768); // NOT short.MaxValue norm = 1.0 - POW(1.0 - norm, param); samples[i] = 32768 * norm * sign; } } 

Cuando param = 1.0, esta función no tendrá efecto en el audio. Los valores de param más grandes (2.0 es bueno, que cuadrará la diferencia normalizada entre cada muestra y el valor máximo de pico) producirán más compresión y un sonido general más fuerte (pero horrible). Los valores por debajo de 1.0 producirán un efecto de expansión.

Otro punto probablemente obvio: debes grabar la música en una sala pequeña y no ecoica, ya que los ecos a menudo son captados por este algoritmo como notas fantasmas.

Actualización: aquí hay una versión de StaticCompress que se comstackrá en C # y explicity arroja todo. Esto devuelve el resultado esperado:

 public void StaticCompress(short[] samples, double param) { for (int i = 0; i < samples.Length; i++) { Compress(ref samples[i], param); } } public void Compress(ref short orig, double param) { double sign = 1; if (orig < 0) { sign = -1; } // 32768 is max abs value of a short. best practice is to pre- // normalize data or use peak value in place of 32768 double norm = Math.Abs((double)orig / 32768.0); norm = 1.0 - Math.Pow(1.0 - norm, param); orig = (short)(32768.0 * norm * sign); // should round before cast, // but won't affect note onset detection } 

Lo siento, mi puntaje de conocimiento en Matlab es 0. Si publicaste otra pregunta sobre por qué tu función de Matlab no funciona como se espera, se responderá (no solo yo).

Lo que quiere hacer a menudo se llama WAV-to-MIDI (google “wav-to-midi”). Ha habido muchos bashs en este proceso, con resultados variables (la aparición de notas es una de las dificultades, la polifonía es mucho más difícil de tratar). Recomiendo comenzar con una búsqueda exhaustiva de las soluciones estándar, y solo comenzar a trabajar por su cuenta si no hay nada aceptable por ahí.

La otra parte del proceso que necesitaría es algo para renderizar la salida MIDI como un puntaje musical tradicional, pero hay miles de millones de productos que lo hacen.

Otra respuesta es: sí, he hecho un montón de procesamiento de señales digitales (vea el software en mi sitio web, es un sintetizador de software de voz infinita escrito en VB y C), y estoy interesado en ayudarlo con este problema. La parte de WAV a MIDI no es realmente tan difícil conceptualmente, solo hace que funcione de manera confiable en la práctica, eso es difícil. El inicio de la nota es simplemente establecer un umbral: los errores se pueden ajustar fácilmente hacia adelante o hacia atrás en el tiempo para compensar las diferencias de ataque de notas. La detección de tono es mucho más fácil de hacer en una grabación que lo que se hace en tiempo real, y solo implica la implementación de una rutina de autocorrelación.

Deberías mirar MIRToolbox – está escrito para Matlab y tiene un detector de inicio incorporado – funciona bastante bien. El código fuente es GPL’d, por lo que puede implementar el algoritmo en cualquier idioma que funcione para usted. ¿Qué idioma va a usar su código de producción?

esta biblioteca se centra en el etiquetado de audio:

aubio

aubio es una biblioteca para el etiquetado de audio. Sus características incluyen segmentar un archivo de sonido antes de cada uno de sus ataques, realizar la detección de tono, tocar el ritmo y producir transmisiones midi a partir de audio en vivo. El nombre aubio proviene de ‘audio’ con un error tipográfico: es probable que también se encuentren varios errores de transcripción en los resultados.

y he tenido buena suerte con esto para detección de inicio y detección de tono. Está en c, pero hay envoltorios swig / python.

también, el autor de la biblioteca tiene un pdf de su tesis en la página, que tiene gran información y antecedentes sobre etiquetado.

Los inicios difíciles se detectan fácilmente en el dominio del tiempo mediante el uso de una medición de energía promedio.

SUM desde 0 a N (X ^ 2)

Haz esto con trozos de la señal completa. Debería ver los picos cuando ocurren los inicios (el tamaño de la ventana depende de usted, mi sugerencia es de 50 ms o más).

Extensivos documentos sobre detección de inicio:

Para los ingenieros Hardcore:

http://www.nyu.edu/classes/bello/MIR_files/2005_BelloEtAl_IEEE_TSALP.pdf

Más fácil para la persona promedio entender:

http://bingweb.binghamton.edu/~ahess2/Onset_Detection_Nov302011.pdf

Podría tratar de transformar la señal wav en un gráfico de amplitud en función del tiempo. Entonces, una forma de determinar un inicio consistente es calcular la intersección de una tangente en el punto de inflexión del flanco ascendente de una señal con el eje x.