¿Como funciona Shazam en su esplendor? Aquí se lo explicamos.
Hola muy buenas a todos bienvenidos a otro post más de este maravilloso
blog TecnologiasRapida, este post no va dedicado a ningún aficionado a un Sistema
operativo si no que va destinado a todas esas personas curiosas que le interesa
saber como funcionan las aplicaciones como shazam o como siri o el asistente de
google es capaz de reconocer las canciones.
Oyes una canción familiar en el club o en el restaurante. Has escuchado
esta canción miles de veces desde hace mucho tiempo y el sentimentalismo de la
canción realmente toca tu corazón. ¡Desesperadamente la quieres volver a
escuchar en la mañana, pero no recuerdas su nombre! Afortunadamente, en nuestro
increíble mundo futurista, tienes un teléfono con software de reconocimiento de música instalado. Puedes relajarte,
ya que el Software te dijo el nombre de la canción, así que sabes que la puedes
escuchar una y otra vez hasta que se convierta en una parte de ti…o te llegue a
desesperar…
Mobile technologies, junto con el progreso del procesamiento de la señal de audio, nos han
dado, algorithm developers, la habilidad de crear reconocedores de música., la
aplicación creará una huella digital de la muestra grabada, consultará la base
de datos, y utilizará su algoritmo de reconocimiento de música para decirte
exactamente cual es la canción que estás escuchando.
¿Como funciona Shazam realmente? Shazam’s algorithm La
aplicación fue expuesta por primera vez por su inventor Avery Li-Chung Wang en
el 2003. En este artículo hablaremos de los fundamentos del algoritmo de
reconocimiento de música Shazam.
Capturando el sonido (Grabando)
Grabar una señal de audio muestreado es fácil. Ya que las tarjetas de
sonido modernas ya vienen con convertidores analógicos-digitales, sólo tienes
que seleccionar un lenguaje de programación, encontrar una biblioteca adecuada
y establecer la frecuencia de la muestra, el número de canales (mono o estéreo)
y normalmente, el tamaño de la muestra (por ej. Muestras de 16 bits). Después
abre la línea de tu tarjeta de sonido, al igual que cualquier flujo de entrada,
y escribe en una matriz de bytes. Así es cómo puedes hacerla en Java:
private AudioFormat getFormat() {
float sampleRate = 44100;
int sampleSizeInBits = 16;
int channels = 1; //mono
boolean signed = true; //Indicates whether the data is signed or unsigned
boolean bigEndian = true; //Indicates whether the audio data is stored in big-endian or little-endian order
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}
final AudioFormat format = getFormat(); //Fill AudioFormat with the settings
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
final TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
Lee los datos de ‘TargetDataLine’:
OutputStream out = new ByteArrayOutputStream();
running = true;
try {
while (running) {
int count = line.read(buffer, 0, buffer.length);
if (count > 0) {
out.write(buffer, 0, count);
}
}
out.close();
} catch (IOException e) {
System.err.println("I/O problems: " + e);
System.exit(-1);
}
Dominio de tiempo y frecuencias
Lo que tenemos en esta matriz de bytes es la
señal grabada en el tiempo del dominio. La señal de dominio de tiempo
representa el cambio de amplitud de la señal a lo largo del tiempo.
Es posible representar cualquier señal en el
dominio del tiempo simplemente dando el conjunto de frecuencias, amplitudes y
fases correspondientes a cada sinusoide que compone la señal. Esta
representación de la señal es conocida como la frecuencia de dominio. En cierto
modo, el dominio de la frecuencia actúa como un tipo de huella dactilar o firma
para la señal de dominio de tiempo, proporcionando una representación estática
de una señal dinámica.
La siguiente foto muestra la serie de Fourier de
una onda cuadrada de 1 HZ y cómo
una onda cuadrada (aproximada) puede ser generada a partir de componentes
sinusoidales. La señal se muestra en el dominio del tiempo anterior y en el
dominio de la frecuencia a continuación
Analizar una señal en el dominio de la frecuencia simplifica muchas cosas
inmensamente. Después de eso, uno puede hacer el filtrado, aumentar o disminuir
algunas frecuencias, o simplemente reconocer el tono exacto de las frecuencias.
Transformación de Fourier
Por lo tanto, necesitamos encontrar una
manera de convertir nuestra señal desde el momento de dominio para el dominio
de la frecuencia. Aquí lo llamamos la transformación discreta de Fourie (DFT) para ayudar. La DFT es un
método matemático para realizar analisis
de Fourie en una muestra de la
señal. Convierte una lista finita de muestras equidistantes de una función en
la lista de los coeficientes de una combinación finita de complejas sinusoides,
ordenadas por sus frecuencias, considerando si las sinusoides habían sido
muestreadas en la misma proporción.
Uno de los algoritmos numéricos más
populares para el cálculo de la DFT es la Fast
Fourier Transform (FFT). El más
utilizado es la variación de FFT Cooley–Tukey algorithm.
Este algoritmo es del tipo divide-y-vencerás que recursivamente divide una DFT
en varias y pequeñas DFTs. Mientras que la evaluación de un DFT requiere
directamente O(n2) operations, with a Cooley-Tukey FFT el mismo se computa en
iO(n log n) operations.
No es difícil encontrar una biblioteca adecuada para la FFT. Aquí están
algunos de ellos:
·C – FFTW
·C++ – EigenFFT
·Java – JTransform
·Python – NumPy
·Ruby – Ruby-FFTW3 (Interface to FFTW)
A continuación se muestra un ejemplo de una
función FFT escrita en Java:
public static Complex[] fft(Complex[] x) {
int N = x.length;
// fft of even terms
Complex[] even = new Complex[N / 2];
for (int k = 0; k < N / 2; k++) {
even[k] = x[2 * k];
}
Complex[] q = fft(even);
// fft of odd terms
Complex[] odd = even; // reuse the array
for (int k = 0; k < N / 2; k++) {
odd[k] = x[2 * k + 1];
}
Complex[] r = fft(odd);
// combine
Complex[] y = new Complex[N];
for (int k = 0; k < N / 2; k++) {
double kth = -2 * k * Math.PI / N;
Complex wk = new Complex(Math.cos(kth), Math.sin(kth));
y[k] = q[k].plus(wk.times(r[k]));
y[k + N / 2] = q[k].minus(wk.times(r[k]));
}
return y;
}
Y aquí está un ejemplo de una señal antes y después del análisis FFT:
Huellas digitales en una canción
Un desafortunado efecto colateral de FFT es que perdemos una gran
cantidad de información acerca de la sincronización para una canción de 3
minutos, es por eso que introducimos el tipo de ventana deslizante, o fragmento
de datos así como la transformación de esta parte de la información. El tamaño
de cada fragmento puede determinarse de distintas formas. Por ejemplo, si
queremos grabar el sonido en estéreo, con muestras de 16 bits, a 44.100 Hz, un
segundo de ese sonido será de 44.100 muestras * 2 bytes * 2 canales ≈ 176 kB.
Si cogemos 4 kB para el tamaño de un segmento, tendremos 44 porciones de datos
para analizar en cada segundo de la canción. Esa es una buena densidad
suficiente para el análisis detallado.
Ahora volvamos a la programación:
byte audio [] = out.toByteArray()
int totalSize = audio.length
int sampledChunkSize = totalSize/chunkSize;
Complex[][] result = ComplexMatrix[sampledChunkSize][];
for(int j = 0;i < sampledChunkSize; j++) {
Complex[chunkSize] complexArray;
for(int i = 0; i < chunkSize; i++) {
complexArray[i] = Complex(audio[(j*chunkSize)+i], 0);
}
result[j] = FFT.fft(complexArray);
}
Vamos a formar nuestra huella digital de la
canción. Esta es la parte más importante de todo el proceso de reconocimiento
de música de Shazam. El principal desafío es cómo distinguir, en el océano de
las frecuencias capturadas, las frecuencias que son las más importantes.
Intuitivamente, podemos buscar las frecuencias con mayor magnitud.
Sin embargo, en una canción de la gama de
frecuencias fuerte puede variar entre baja C - C1 (32,70 Hz) y alta C - C8
(4,186.01 Hz). Así que en lugar de analizar toda la gama de frecuencias a la
vez, podemos elegir varios intervalos más pequeños. Elige en base a las
frecuencias comunes de componentes musicales importantes y analiza cada uno por
separado. Por ejemplo, estos son los 30 Hz - 40 Hz, 40 Hz - 80 Hz y 80 Hz - 120
Hz para los tonos bajos (cubriendo bass guitar, por ejemplo), y 120 Hz - 180 Hz
y 180 Hz - 300 Hz para el oriente y los tonos más altos (que cubre la mayoría
de los demás instrumentos y voces).
Ahora, dentro de cada intervalo podemos determinar la frecuencia con la
mayor magnitud. Esta información constituye una firma para esta parte de la
canción y esta firma se convierte en parte de la huella digital de la canción
como un todo.
public final int[] RANGE = new int[] { 40, 80, 120, 180, 300 };
// find out in which range is frequency
public int getIndex(int freq) {
int i = 0;
while (RANGE[i] < freq)
i++;
return i;
}
// result is complex matrix obtained in previous step
for (int t = 0; t < result.length; t++) {
for (int freq = 40; freq < 300 ; freq++) {
// Get the magnitude:
double mag = Math.log(results[t][freq].abs() + 1);
// Find out which range we are in:
int index = getIndex(freq);
// Save the highest magnitude and corresponding frequency:
if (mag > highscores[t][index]) {
points[t][index] = freq;
}
}
// form hash tag
long h = hash(points[t][0], points[t][1], points[t][2], points[t][3]);
}
private static final int FUZ_FACTOR = 2;
private long hash(long p1, long p2, long p3, long p4) {
return (p4 - (p4 % FUZ_FACTOR)) * 100000000 + (p3 - (p3 % FUZ_FACTOR))
* 100000 + (p2 - (p2 % FUZ_FACTOR)) * 100
+ (p1 - (p1 % FUZ_FACTOR));
}
Debemos incluir un factor de
aproximación ya que esto no esta echo a la perfección. Un análisis del factor
de aproximación debe ser tomado en serio y en un sistema real, el programa debe
tener una opción para establecer este parámetro en función a las condiciones de
la grabación.
Para facilitar la búsqueda, esta firma se convierte en la clave en una
tabla de hashtag. El valor correspondiente es el tiempo en el que este conjunto
de frecuencias apareció en la canción, junto con el ID de la canción (título de
la canción y del artista). Aquí está un ejemplo de cómo pueden aparecer estos
registros en la base de datos.
Si ejecutamos toda una biblioteca de canciones a
través de este proceso, podemos construir una base de datos completa con una
huella digital de cada canción en la biblioteca.
Elegir una canción
Como sucede, muchos de los hashtags corresponden a varias canciones. Por
ejemplo, puede ser que alguna pieza de una canción suena exactamente como algún
fragmento de canción E. Por supuesto, esto no es sorprendente – los músicos
siempre han “prestado” letras de canciones unos de otros y, en estos días, los
productores muestran otras canciones todo el tiempo. Cada vez que hemos partido
de un hashtag, el número de coincidencias posibles se hace más pequeño, pero es
probable que esta información por sí sola no va a reducir el partido a una sola
canción. Así que hay una cosa más que tenemos que verificar con nuestro
algoritmo de reconocimiento de música, y esa es la distribución ,con varios algoritmos de hashtags que coinciden, podemos analizar el
tiempo relativo de la combinación, y por tanto, aumentar nuestra seguridad.
// Class that represents specific moment in a song
private class DataPoint {
private int time;
private int songId;
public DataPoint(int songId, int time) {
this.songId = songId;
this.time = time;
}
public int getTime() {
return time;
}
public int getSongId() {
return songId;
}
}
La grabación seguro que incluye un montón de ruido que introducirá
algunos errores en los partidos. Así que en lugar de tratar de eliminar todo
pero la canción correcta de nuestra lista de partidos, al final, hemos
conciliado ordenar todas las canciones en orden descendente de probabilidad, y
nuestra favorita es la primera canción en la lista de clasificación.
Conclusión y ultimo punto
Este tipo de software de reconocimiento de música
puede ser utilizado para encontrar las similitudes entre las canciones. Ahora
que entiendes cómo funciona Shazam, puedes ver cómo esto puede tener
aplicaciones más allá de la simple Shazaming que esa nostálgica canción que
suena en la radio del taxi. Y para acabar les dejo un imagen donde se resume el proceso.
Y bueno hasta aquí todo espero que les halla gustado este artículo tan interesante y sobre todo el ultimo de este año, les deseo muy buen feliz año nuevo y espero que disfruten esta noche, y no os paséis con el alcohol eeee pillines😉😊
Y por ultimo darle las gracias a Toptal por cerrar el año conmigo y seguir confiando en mi.
Si les ha gustado compartanlo denle a
seguir y dejen sus comentarios ya que nos ayudan a crecer más y saber si lo
hacemos bien o no. Hasta Luegoo people...
Twitter:
@tecnologiasrapi
Enlace del post:https://www.toptal.com/algorithms/shazam-reconocimiento-de-algoritmos-de-m%C3%BAsica-huellas-dactilares-y-procesamiento/es
Instagram/Snapchat:rubenvrodriguez
Contacto en: rubenvargasrodriguez4@gmail.com
Comentarios
Publicar un comentario