Esta é a versão em áudio do desafio de codificação de imagens do Twitter .
Crie um formato de compactação de áudio que possa representar pelo menos um minuto de música em 140 bytes ou menos de texto codificado em UTF-8 imprimível.
Implemente-o escrevendo um programa de linha de comando que use os três argumentos a seguir (após o nome do próprio programa):
- A sequência
encode
oudecode
. - O nome do arquivo de entrada.
- O nome do arquivo de saída.
(Se sua linguagem de programação preferida não possui a capacidade de usar argumentos de linha de comando, você pode usar uma abordagem alternativa, mas deve explicá-la em sua resposta.)
A encode
operação será convertida do formato de áudio escolhido para o formato compactado de "tweet" e a decode
operação será convertida do formato de "tweet" para o formato de áudio original. (Obviamente, você deve implementar a compactação com perdas, para que o arquivo de saída não precise ser idêntico à entrada, apenas no mesmo formato.)
Inclua na sua resposta:
- O código fonte do seu programa, na íntegra. (Se for muito longo para esta página, você pode hospedá-la em outro lugar e postar um link para ela.)
- Uma explicação de como isso funciona.
- Pelo menos um exemplo, com um link para o (s) arquivo (s) de áudio original (s), o texto do “tweet” que ele compacta e o arquivo de áudio obtido pela decodificação do tweet. (O respondente é responsável pelas afirmações de "uso justo" dos direitos autorais.)
Regras
- Reservo-me o direito de fechar as brechas nas regras do concurso a qualquer momento.
- [Editado em 24 de abril] Para a entrada de sua
encode
função (e a saída de suadecode
função), você pode usar qualquer formato de áudio comum e razoável, seja ele:- Forma de onda não compactada, como WAV.
- Forma de onda compactada, como MP3.
- Estilo "Partituras", como MIDI.
- Seu formato "tweet" compactado deve realmente codificar os sons no arquivo de entrada. Portanto, os seguintes tipos de saída não contam:
- Um caminho de arquivo ou URI que fornece o local onde a saída real está armazenada.
- Uma chave para uma tabela de banco de dados onde a saída real é armazenada como um blob.
- Qualquer coisa parecida.
- Seu programa deve ser projetado para compactar arquivos de música genéricos ; portanto, não faça coisas que obviamente estejam ligadas ao seu exemplo específico de música. Por exemplo, se você está demonstrando "Twinkle, Twinkle, Little Star", sua rotina de compactação não deve codificar um símbolo específico para a sequência faça-o-lo-la-la-lo.
- A saída do seu programa deve ser capaz de passar pelo Twitter e sair ilesa. Não tenho uma lista dos caracteres exatos suportados, mas tente seguir letras, dígitos, símbolos e pontuação; e evite caracteres de controle, combinando caracteres, marcadores BIDI ou outras coisas estranhas como essa.
- Você pode enviar mais de uma entrada.
Critérios de julgamento
Este é um concurso de popularidade (ou seja, a maioria das vitórias líquidas), mas os eleitores devem considerar o seguinte:
Precisão
- Você ainda consegue reconhecer a música depois de comprimida?
- Isso soa bem?
- Você ainda consegue reconhecer quais instrumentos estão sendo tocados?
- Você ainda consegue reconhecer a letra? (Isso provavelmente é impossível, mas seria impressionante se alguém conseguisse.)
Complexidade
A escolha da música de exemplo é importante aqui.
- [Adicionado em 24 de abril] Este desafio será mais fácil com formatos MIDI ou similares. No entanto, se você fizer um esforço extra para fazê-lo funcionar com formatos do tipo de forma de onda, isso merece crédito extra.
- Qual é a estrutura? Claro, você pode atender ao requisito de um minuto simplesmente repetindo as mesmas quatro medidas um número arbitrário de vezes. Mas estruturas musicais mais complexas merecem mais pontos.
- O formato pode lidar com muitas notas sendo tocadas ao mesmo tempo?
O código
- Mantenha-o o mais curto e simples possível. No entanto, como este não é um código de golfe, a legibilidade importa mais do que a contagem de caracteres.
- Algoritmos inteligentes e complicados também são bons, desde que justificados pela melhoria da qualidade dos resultados.
Respostas:
Scala
Claro, seria mais fácil codificar arquivos MIDI, mas quem tem um monte de arquivos MIDI por aí? Não é 1997!
Primeiras coisas: decidi interpretar um "byte Unicode" como um "caractere Unicode" e usar caracteres CJK, porque:
Existem alguns truques que eu uso para extrair toda última gota de entropia das fontes:
Em primeiro lugar, a música é feita com anotações. Além disso, geralmente consideramos a mesma nota em uma oitava diferente da mesma nota (e é por isso que um violão de 12 cordas soa bem), então só temos 12 possibilidades para codificar. (quando eu saio B, por exemplo, eu realmente saio um acorde, consistindo apenas de B em todas as oitavas, um pouco como um violão de 12 cordas).
Em seguida, lembro-me da aula de música do ensino médio que a maioria das transições de notas é pequena (uma nota para cima ou para baixo). Saltos são menos comuns. Isso nos diz que provavelmente há menos entropia nos tamanhos dos saltos do que nas próprias notas.
Portanto, nossa abordagem é dividir nossa fonte em vários blocos - descobri que 14 blocos por segundo funcionavam bem (nota lateral, eu sempre me perguntava por que o áudio era codificado em 44100 Hz. Acontece que o 44100 tem muitos fatores, então eu poderia ter escolhido 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 15, 18, 20, 21, 25, 28 ou 30 blocos por segundo, e teria dividido de maneira limpa ) Em seguida, transferimos esses blocos para FFT (bem, tecnicamente não é rápido, pois a biblioteca que eu usei não é rápida para blocos sem potência de 2.) E, tecnicamente, usei uma transformação de Hartley , não Fourier).
Em seguida, encontramos a nota que soa mais alta (usei a ponderação A , com cortes altos e baixos, principalmente porque é mais fácil de implementar) e codificamos essa nota ou codificamos o silêncio (a detecção de silêncio é baseada em SNR - SNR baixo é silêncio).
Em seguida, traduzimos nossas notas codificadas em saltos e as alimentamos com um codificador aritmético adaptativo. O processo de tradução para o texto é semelhante à questão da compactação de imagem (mas envolve algum uso abusivo do BigInteger).
Até agora, tudo bem, mas e se a amostra tiver muita entropia? Usamos um modelo psicoacústico bruto para remover alguns. O menor salto de entropia é "sem alteração"; portanto, examinamos nossos dados da FFT para tentar encontrar blocos nos quais o ouvinte provavelmente não notará se continuarmos tocando a nota anterior, procurando blocos onde a nota do bloco anterior é quase tão alto quanto a nota mais alta (onde "quase" é controlado pelo parâmetro de qualidade).
Então, temos um alvo de 140 caracteres. Começamos codificando na qualidade 1.0 (qualidade máxima) e ver quantos caracteres são. Se for demais, caímos para 0,95 e repetimos, até chegarmos a 140 caracteres (ou desistimos após a qualidade 0,05). Isso torna o codificador um codificador n-pass, para n <= 20 (embora seja massivamente ineficiente em outras áreas também, então m'eh).
O codificador / decodificador espera áudio no formato s16be mono. Isso pode ser alcançado usando o avconv como:
Para executar o codificador:
Código completo em https://github.com/jamespic/twelvestring .
Armadilha a ser observada: você precisará da biblioteca Aritmetic Coding de nayuki, que atualmente não possui artefatos do Maven disponíveis. Em vez disso, você precisará construir e instalar localmente o fork do developerster .
E aqui estão algumas amostras. Eles soam horríveis, mas quase reconhecíveis:
Atualizar
Apertei o limiar do silêncio no código e recodifiquei. As codificações foram atualizadas de acordo. Além disso, adicionei outra música (tecnicamente não é de código aberto, mas duvido que o detentor dos direitos autorais originais sinta que seu IP está ameaçado), apenas por diversão:
Mais atualizações
Ajustei um pouco o codificador e isso teve um impacto surpreendente na qualidade (eu havia esquecido que, no DHT, os sinais fora de fase são efetivamente negativos, então eu estava ignorando os sinais fora de fase).
Uma versão anterior do código apenas absorveu o maior desses sinais fora de fase, mas agora usamos o RMS. Além disso, adicionei uma função de janela bastante conservadora ao codificador (Tukey, alpha 0.3), para tentar combater artefatos.
Tudo é atualizado de acordo.
fonte
BitOutputStream::close
método que eu tinha esquecido de chamar. Vou corrigir o código e atualizar as saídas.Python
Eu não faço nenhuma manipulação especial em relação ao UTF-8; portanto, meu envio passa o requisito de 140 bytes. Não reivindico a utilidade, precisão ou eficiência da minha solução.
Eu usei uma taxa de amostragem de 44100 Hz para a entrada e saída. SAMPLES_PER_BYTE controla a qualidade da conversão. Quanto menor o número, melhor a qualidade do som. Os valores que eu usei são dados na seção de resultados.
Uso
Codificar
O arquivo de entrada deve ser um wav. Ele codifica apenas o primeiro canal.
Decodificar
Tocando a música decodificada
O código
As entradas
Minha submissão oficial é Impromptu para Pianoforte e Beatbox por Kevin MacLeod . Para este arquivo, usei um SAMPLES_PER_BYTE de 25450.
Também tomei a liberdade de codificar Twinkle, Twinkle, Little Star com um SAMPLES_PER_BYTE de 10200. Parece muito melhor.
A saída
Impromptu para Pianoforte e Beatbox
Ligação
Brilha Brilha Estrelinha
Ligação
fonte