Esta es la versión de audio del desafío de codificación de imágenes de Twitter .
Diseñe un formato de compresión de audio que pueda representar al menos un minuto de música en 140 bytes o menos de texto imprimible codificado en UTF-8.
Impleméntelo escribiendo un programa de línea de comandos que tome los siguientes 3 argumentos (después del nombre del programa en sí):
- La cuerda
encode
odecode
. - El nombre del archivo de entrada.
- El nombre del archivo de salida.
(Si su lenguaje de programación preferido carece de la capacidad de usar argumentos de línea de comandos, puede usar un enfoque alternativo, pero debe explicarlo en su respuesta).
La encode
operación se convertirá de su formato de audio elegido a su formato de "tweet" comprimido, y la decode
operación se convertirá desde su formato de "tweet" al formato de audio original. (Por supuesto, se espera que implemente una compresión con pérdida, por lo que el archivo de salida no necesita ser idéntico a la entrada, solo en el mismo formato).
Incluye en tu respuesta:
- El código fuente de su programa, en su totalidad. (Si es demasiado larga para esta página, puede alojarla en otro lugar y publicar un enlace).
- Una explicación de cómo funciona.
- Al menos un ejemplo, con un enlace a los archivos de audio originales, el texto "tweet" al que se comprime y el archivo de audio obtenido al decodificar el tweet. (El respondedor es responsable de las afirmaciones de "uso justo" de los derechos de autor).
Reglas
- Me reservo el derecho de cerrar cualquier laguna en las reglas del concurso en cualquier momento.
- [Editado el 24 de abril] Para la entrada de su
encode
función (y la salida de sudecode
función), puede usar cualquier formato de audio común y razonable, ya sea:- Forma de onda sin comprimir, como WAV.
- Forma de onda comprimida, como MP3.
- Estilo de "partitura", como MIDI.
- Su formato comprimido de "tweet" debe codificar los sonidos en el archivo de entrada. Por lo tanto, los siguientes tipos de salida no cuentan:
- Un URI o ruta de archivo que proporciona la ubicación donde se almacena la salida real.
- Una clave para una tabla de base de datos donde la salida real se almacena como un blob.
- Algo similar.
- Tu programa debe estar diseñado para comprimir archivos de música genéricos , así que no hagas cosas que obviamente estén demasiado vinculadas a tu canción de ejemplo específica. Por ejemplo, si está demostrando "Twinkle, Twinkle, Little Star", su rutina de compresión no debería codificar un símbolo específico para la secuencia do-do-so-so-la-la-so.
- La salida de su programa debería poder pasar por Twitter y salir ilesa. No tengo una lista de los caracteres exactos que son compatibles, pero trato de mantener letras, dígitos, símbolos y signos de puntuación; y evite los caracteres de control, combinando caracteres, marcadores BIDI u otras cosas extrañas como esa.
- Puede enviar más de una entrada.
Criterio de juzgar
Este es un concurso de popularidad (es decir, gana la mayoría de los votos positivos), pero se insta a los votantes a considerar lo siguiente:
Exactitud
- ¿Todavía puedes reconocer la canción después de que se ha comprimido?
- ¿Suena bien?
- ¿Todavía puedes reconocer qué instrumentos se están tocando?
- ¿Todavía puedes reconocer la letra? (Esto es probablemente imposible, pero sería impresionante si alguien lo lograra).
Complejidad
La elección de la canción de ejemplo es importante aquí.
- [Agregado el 24 de abril] Este desafío será más fácil con MIDI o formatos similares. Sin embargo, si hace un esfuerzo adicional para que funcione con formatos de forma de onda, eso merece un crédito adicional.
- Cual es la estructura Claro, puede cumplir el requisito de un minuto simplemente repitiendo las mismas 4 medidas un número arbitrario de veces. Pero las estructuras de canciones más complejas merecen más puntos.
- ¿Puede el formato manejar muchas notas que se reproducen al mismo tiempo?
El código
- Mantenlo lo más corto y simple posible. Sin embargo, este no es un código de golf, por lo que la legibilidad importa más que el recuento de caracteres.
- Los algoritmos inteligentes y complicados también están bien, siempre que estén justificados por una mejor calidad de resultados.
Respuestas:
Scala
Claro, sería más fácil codificar archivos MIDI, pero ¿quién tiene un montón de archivos MIDI por ahí? ¡No es 1997!
Primero lo primero: he decidido interpretar un "byte Unicode" como un "char Unicode" y usar caracteres CJK, porque:
Hay algunos trucos que uso para exprimir hasta la última gota de entropía de las fuentes:
En primer lugar, la música está hecha con notas. Además, generalmente consideramos la misma nota en una octava diferente como la misma nota (razón por la cual una guitarra de 12 cuerdas suena bien), por lo que solo tenemos 12 posibilidades de codificación. (cuando saco B, por ejemplo, realmente saco un acorde, que consiste únicamente en B en todas las octavas, un poco como una guitarra de 12 cuerdas).
A continuación, recuerdo de la clase de música de la escuela secundaria que la mayoría de las transiciones de notas son pequeñas (una nota hacia arriba o hacia abajo). Los saltos son menos comunes. Esto nos dice que probablemente haya menos entropía en los tamaños de salto que en las notas mismas.
Entonces, nuestro enfoque es dividir nuestra fuente en varios bloques: encontré que 14 bloques por segundo funcionaron bien (nota al margen, siempre me pregunté por qué el audio estaba codificado a 44100 Hz. Resulta que 44100 tiene muchos factores, entonces podría haber elegido 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 15, 18, 20, 21, 25, 28 o 30 bloques por segundo, y se habría dividido limpiamente ) Luego FFT estos bloques (bueno, técnicamente no es rápido, ya que la biblioteca que utilicé no es rápida para bloques sin potencia de 2. Y técnicamente utilicé una transformación de Hartley , no Fourier).
Luego encontramos la nota que suena más fuerte (utilicé la ponderación A , con cortes altos y bajos, principalmente porque es más fácil de implementar) y codificamos esta nota o codificamos silencio (la detección de silencio se basa en SNR - baja SNR es silencio)
Luego traducimos nuestras notas codificadas en saltos y las enviamos a un codificador aritmético adaptativo. El proceso de traducción al texto es similar a la pregunta de compresión de imagen (pero implica un uso abusivo de BigInteger).
Hasta ahora, todo bien, pero ¿qué pasa si la muestra tiene demasiada entropía? Usamos un modelo psicoacústico crudo para eliminar algunos. El salto de entropía más bajo es "sin cambios", por lo que miramos nuestros datos FFT para tratar de encontrar bloques donde el oyente probablemente no se dará cuenta si seguimos tocando la nota anterior, buscando bloques donde está la nota del bloque anterior. casi tan alto como la nota más alta (donde "casi" está controlado por el parámetro de calidad).
Entonces, tenemos un objetivo de 140 caracteres. Comenzamos codificando con la calidad 1.0 (calidad máxima) y vemos cuántos caracteres hay. Si es demasiado, bajamos a 0.95 y repetimos, hasta llegar a 140 caracteres (o renunciamos después de la calidad 0.05). Esto hace que el codificador sea un codificador de paso n, para n <= 20 (aunque también es enormemente ineficiente en otras áreas, entonces m'eh).
El codificador / decodificador espera audio en formato s16be mono. Esto se puede lograr usando avconv como:
Para ejecutar el codificador:
Código completo en https://github.com/jamespic/twelvestring .
Errores a tener en cuenta: necesitará la biblioteca de codificación aritmética de nayuki, que actualmente no tiene artefactos Maven disponibles. En su lugar, deberá construir e instalar localmente la bifurcación del desarrollador .
Y aquí hay algunas muestras. Suenan horribles, pero casi reconocibles:
Actualizar
Ajusté el umbral de silencio en el código y volví a codificarlo. Las codificaciones se han actualizado en consecuencia. Además, agregué otra canción (técnicamente no es de código abierto, pero dudo que el titular original de los derechos de autor sienta que su IP está bajo amenaza), solo por diversión:
Más actualizaciones
He ajustado un poco el codificador, y ha tenido un impacto sorprendente en la calidad (había olvidado que en DHT, las señales desfasadas son efectivamente negativas, por lo que estaba ignorando las señales desfasadas).
Una versión anterior del código simplemente tomó la mayor de estas señales desfasadas, pero ahora tomamos el RMS. Además, agregué una función de ventana bastante conservadora al codificador (Tukey, alpha 0.3), para tratar de combatir los artefactos.
Todo se actualiza en consecuencia.
fuente
BitOutputStream::close
método que había olvidado llamar. Arreglaré el código y actualizaré las salidas.Pitón
No hago ningún cambio especial con respecto a UTF-8, por lo que mi envío pasa el requisito de 140 bytes. No hago declaraciones sobre la utilidad, precisión o eficiencia de mi solución.
Usé una frecuencia de muestreo de 44100 Hz para la entrada y la salida. SAMPLES_PER_BYTE controla la calidad de la conversión. Cuanto menor sea el número, mejor será la calidad del sonido. Los valores que utilicé se dan en la sección de resultados.
Uso
Codificar
El archivo de entrada debe ser un wav. Solo codifica el primer canal.
Descodificar
Tocando la música decodificada
El código
Las entradas
Mi presentación oficial es Impromptu para Pianoforte y Beatbox por Kevin MacLeod . Para este archivo utilicé un SAMPLES_PER_BYTE de 25450.
También me tomé la libertad de codificar Twinkle, Twinkle, Little Star con un SAMPLES_PER_BYTE de 10200. Suena mucho mejor.
La salida
Impromptu para Pianoforte y Beatbox
Enlazar
Brilla brilla pequeña estrella
Enlazar
fuente