Colorear una forma de onda con centroide espectral o por otros medios

8

Actualización 8

Insatisfecho de tener que subir pistas al servicio y mirar el nuevo lanzamiento de RekordBox 3, he decidido volver a buscar un enfoque fuera de línea y una resolución más fina: D

Suena prometedor aunque todavía en un estado muy alfa:

Johnick - Buen tiempo

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Tenga en cuenta que no hay escala logarítmica ni ajuste de paleta, solo un mapeo bruto de frecuencia a HSL.

La idea : ahora un renderizador de forma de onda tiene un proveedor de color al que se le pregunta por un color para una posición específica. El que está viendo arriba obtiene la tasa de cruce cero para las 1024 muestras al lado de esa posición.

Obviamente, todavía hay mucho por hacer antes de obtener algo robusto, pero parece un buen camino ...

De RekordBox 3 :

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Actualización 7

La forma final que adoptaré, al igual que en la Actualización 3

ingrese la descripción de la imagen aquí

(se ha retocado un poco Photoshop para obtener transiciones suaves entre colores)

La conclusión es que estuve cerca hace meses, pero no consideré ese resultado pensando que era malo X)

Actualización 6

Descubrí el proyecto recientemente, así que pensé en actualizarlo aquí: D

Canción: Chic - Good Times 2001 (mezcla de Stonebridge Club)

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Es mucho mejor IMO, los ritmos tienen un color constante, etc. Sin embargo, no está optimizado.

Cómo ?

Todavía con http://developer.echonest.com/docs/v4/_static/AnalyzeDocumentation.pdf (página 6)

Para cada segmento:

public static int GetSegmentColorFromTimbre(Segment[] segments, Segment segment)
{
    var timbres = segment.Timbre;

    var avgLoudness = timbres[0];
    var avgLoudnesses = segments.Select(s => s.Timbre[0]).ToArray();
    double avgLoudnessNormalized = Normalize(avgLoudness, avgLoudnesses);

    var brightness = timbres[1];
    var brightnesses = segments.Select(s => s.Timbre[1]).ToArray();
    double brightnessNormalized = Normalize(brightness, brightnesses);

    ColorHSL hsl = new ColorHSL(brightnessNormalized, 1.0d, avgLoudnessNormalized);
    var i = hsl.ToInt32();
    return i;
}

public static double Normalize(double value, double[] values)
{
    var min = values.Min();
    var max = values.Max();
    return (value - min) / (max - min);
}

Obviamente, se necesita mucho más código antes de llegar aquí (subir al servicio, analizar JSON, etc.), pero ese no es el objetivo de este sitio, así que solo estoy publicando las cosas relevantes para obtener el resultado anterior.

Así que estoy usando las primeras 2 funciones del resultado del análisis, ciertamente hay más que ver, pero aún tengo que probar. Si alguna vez encuentro algo más genial que el anterior, volveré y actualizaré aquí.

Como siempre, cualquier sugerencia sobre el tema es más que bienvenida.

Actualización 5

Algún gradiente usando series armónicas

ingrese la descripción de la imagen aquí

El suavizado de color es sensible a la relación, de lo contrario se ve mal, necesitará algunos ajustes.

Actualización 4

Reescribió la coloración para que ocurra en la fuente y los colores suavizados utilizando un filtro Alfa beta con valores de 0.08 y 0.02.

ingrese la descripción de la imagen aquí

Un poco mejor cuando se aleja

ingrese la descripción de la imagen aquí

¡El siguiente paso es obtener una gran paleta de colores!

Actualización 3

ingrese la descripción de la imagen aquí

Los amarillos representan medios ingrese la descripción de la imagen aquí

No tan bueno cuando no está enfocado, todavía. ingrese la descripción de la imagen aquí

(la paleta necesita un trabajo serio)

Actualización 2

Prueba preliminar utilizando la segunda pista de coeficiente 'timbre' de pichenettes ingrese la descripción de la imagen aquí

Actualización 1

Una prueba preliminar que utiliza un resultado de análisis del servicio EchoNest , tenga en cuenta que no está muy bien alineado (es mi culpa) pero es mucho más coherente que el enfoque anterior.

ingrese la descripción de la imagen aquí

Para las personas interesadas en utilizar esta gran API, comience aquí: http://developer.echonest.com/docs/v4/track.html#profile

Además, no se confunda con estas formas de onda, ya que representan 3 canciones diferentes.

Pregunta inicial

Hasta ahora, este es el resultado que obtengo usando un FFT de 256 muestras y calculando el centroide espectral de cada fragmento .

Resultado bruto de los cálculos ingrese la descripción de la imagen aquí

Se aplicó algo de suavizado (la forma se ve mucho mejor con ella) ingrese la descripción de la imagen aquí

Forma de onda producida ingrese la descripción de la imagen aquí

Idealmente, así es como debería verse (tomado del software Serato DJ ) ingrese la descripción de la imagen aquí

¿Sabes qué técnica / algoritmo podría usar para poder dividir el audio cuando la frecuencia promedio cambia con el tiempo? (como la imagen de arriba)

Aybe
fuente
1
Creo que estás en el camino correcto usando el centroide espectral; tal vez solo necesite un mapeo no lineal del resultado para obtener una buena distribución de colores. Parece que solo se utiliza actualmente el segmento azul / cian de su paleta.
pichenettes
1
¿Tiene alguna pregunta sobre el algoritmo de pseudo-color o sobre dividir el audio en fragmentos de forma automatizada?
Bjorn Roche
@pichenettes: correcto, voy a abordar este problema usando una escala logarítmica.
Aybe
1
Esto es exactamente lo que freesound.org usa para colorear sus formas de onda. Ver su spectral_centroidcódigo . Lo que realmente me gustaría es mapear el espectro de audio en el espectro de color, por lo que una frecuencia baja es roja, la alta frecuencia es azul, la combinación de ambos es magenta, la frecuencia media es verde, el barrido de registro es arcoiris, el ruido blanco es blanco, el ruido rosa es rosa, el ruido rojo es rojo ... Sin embargo, no puedo entender cómo hacerlo, ya que un espectro es lineal y el otro es log. :) flic.kr/p/7S8oHA
endolito
1
@Aybe: Sí, sé cómo hacer que un barrido de registro se vea como un arcoíris, pero cuando se mide con un espaciado de frecuencia de registro (bandas de ancho proporcional), el ruido blanco tiene un espectro inclinado, no un espectro plano, por lo que no produciría luz blanca . Nuestros nombres para los colores del ruido se basan en bandas de ancho constante (espacio lineal), pero nuestra percepción de los tonos está en un espacio de registro (bandas de ancho proporcional). ¿Puedo preguntar qué planeas hacer con esto cuando lo hagas funcionar?
endolito

Respuestas:

4

Puede probar primero lo siguiente (sin segmentación):

  • Procese la señal en trozos pequeños (digamos de 10 ms a 50 ms de duración), si es necesario con una superposición del 50% entre ellos.
  • Calcule el centroide espectral en cada fragmento.
  • Aplique una función no lineal al valor del centroide espectral para obtener una distribución uniforme del color de la paleta utilizada. El logaritmo es un buen comienzo. Otra opción es calcular primero la distribución del valor del centroide en otro archivo completo, y luego colorear según los percentiles de esta distribución ( CDF ). Este enfoque adaptativo garantiza que cada color de la paleta se utilizará en igual proporción. El inconveniente es que lo que se traza en azul en un archivo no tendrá un sonido similar al que se traza en azul en otro archivo si se usa este enfoque adaptativo.

No está claro en la imagen si Serato hace esto, o de hecho va un paso más allá e intenta segmentar la señal; puede que no sea sorprendente que lo haga, ya que conocer los instantes en los que las notas están presentes en una señal de música puede ayudar a sincronizarlas. ! Los pasos serían:

  • Calcule una Transformada de Fourier a corto plazo (espectrograma) de la señal, utilizando la FFT en segmentos cortos superpuestos (comience con un tamaño de FFT de 1024 o 2048 con audio de 44.1 kHz).
  • Calcule una función de detección de inicio. Le recomiendo que lea este documento : el enfoque propuesto es muy efectivo e incluso una implementación de C ++ toma menos de 10 líneas. Puede encontrar una implementación en Yaafe - as ComplexDomainOnsetDetection.
  • Detecte picos en la función de detección de inicio para obtener la posición de inicio de nota.
  • Calcule el centroide espectral en todos los segmentos de tiempo delimitados por los inicios detectados (¡no olvide la ventana y / o la almohadilla cero!)
  • ¡Y no olvides el mapa no lineal! Tenga en cuenta que el efecto de gradiente que aparece entre cada nota en la forma de onda de Serato podría generarse artificialmente.

Una vez que haga que esto funcione, una "fruta baja" sería calcular algunas otras características en cada segmento (momentos, un puñado de MFCC ...), ejecutar k-means en estos vectores de características y decidir el color de el segmento usando el índice de clúster. Ver la sección II del artículo de Ravelli .

pichenettes
fuente
Comencé a trabajar en su solución número 2, afortunadamente, el servicio (EchoNest) que estoy usando proporciona detección de inicio en su análisis, ¡así que son buenas noticias y un ahorro en tiempo real! He actualizado mi respuesta con una pequeña prueba que hice y parece prometedora (tenga en cuenta que no está alineada correctamente, ya que es muy rápida y sucia). Publicaré un mejor resultado cuando haya hecho un progreso significativo. Gracias !
Aybe
1
Entonces no tienes trabajo que hacer. El segundo coeficiente de "timbre" en el análisis de EchoNest está muy relacionado con el centroide, por lo que no tiene que hacer ningún cálculo (a menos que eliminen el componente DC en su base, en cuyo caso es el primer coeficiente): simplemente use el valor de tiempo de compás o segmento del vector "timbre".
pichenettes
1
El "Brillo" medido por el segundo coeficiente "timbre" en el análisis de EN está muy relacionado con el centroide espectral (la diferencia es que el analizador EchoNest utiliza algún preprocesamiento perceptivo - filtrado del oído medio, enmascaramiento de tiempo / frecuencia - en lugar de tomando una FFT cruda). La codificación de colores usando el bin máximo en el vector 'pitch' sería útil para material monofónico y melódico muy puro, pero no tiene sentido para un loop de batería.
pichenettes
1
¿Sin límites? Todavía está limitado por la energía de la señal en el cuadro analizado ... Creo que para esta característica vale la pena mantener la escala consistente entre las pistas. Lo que haría: reunir una docena de canciones muy diversas para tener una idea de la distribución del valor. Si es necesario, aplique un mapa no lineal simple para que parezca más gaussiano. Luego elimine la media y divida por la desviación estándar. Luego aplique atan para hacerlo acotar, volviendo los valores atípicos más cerca de los deciles primero o noveno sin causar recorte.
pichenettes
1
Cuando la forma de onda se aleja, segmente su señal de acuerdo con elementos más grandes como barras o secciones, en lugar de intentar colorear notas / ritmos individuales.
pichenettes