Adblock para rádio

O autor do artigo é o programador polonês Tomek Rekavek, que está desenvolvendo o projeto Jackrabbit Oak como parte da Apache Software Foundation for Adobe. O artigo foi publicado no blog pessoal do autor em 24 de fevereiro de 2016.

O “Radio-3” polonês (a chamada “Troika”) é famoso pela boa música e pelos apresentadores inteligentes. Por outro lado, sofre da presença de blocos de anúncios altos e irritantes nas transmissões, que geralmente anunciam algum tipo de eletrônica ou medicamento. Eu ouço Troika quase constantemente no trabalho e em casa, então me perguntei: como remover anúncios? Eu acho que consegui encontrar uma solução.

Processamento de sinal digital


Meu objetivo é criar um aplicativo que mude os anúncios. O bloco comercial começa e termina com jingles; portanto, o programa deve reconhecer esses sons específicos e desativar o som entre eles.

Eu sei que essa área da matemática / ciência da computação é chamada processamento de sinal digital , mas o DSP sempre me pareceu mágico. Bem, uma ótima oportunidade para aprender algo novo. Passei um dia ou dois tentando descobrir qual mecanismo usar para analisar o fluxo de áudio. E no final, encontrei o que precisava: é correlação cruzada ou correlação cruzada (correlação cruzada).

Octave


Geralmente, todo mundo se refere à implementação do MATLAB. Mas o MATLAB é um aplicativo caro que simplifica a execução de operações matemáticas complexas, incluindo o DSP. Felizmente, existe uma alternativa gratuita chamada Octave . Parece que no Octave é fácil executar correlação cruzada em dois arquivos de áudio. Só é necessário executar os seguintes comandos:

pkg load signal jingle = wavread('jingle.wav')(:,1); audio = wavread ('audio.wav')(:,1); [R, lag] = xcorr(jingle, audio); plot(R); 

Você obtém o seguinte gráfico:



É claramente visível um pico que descreve a posição de jingle.wav em audio.wav . O que me surpreendeu foi a simplicidade do método: xcorr() faz todo o trabalho, o restante do código é apenas para ler arquivos e exibir o resultado.

Eu queria implementar o mesmo algoritmo em Java e, em seguida, terei uma ferramenta que:

  1. lê o fluxo de áudio da entrada padrão (por exemplo, de ffmpeg),
  2. analisa-o em busca de jingles,
  3. imprime o mesmo fluxo em stdout e / ou o desativa.

O uso de stdin e stdout permitirá conectar o novo analisador a outros aplicativos responsáveis ​​pela transmissão de áudio e pela reprodução do resultado.

Lendo arquivos de som


A primeira coisa que um programa Java deve ler é um jingle (salvo como um arquivo .wav ) em uma matriz. Existem algumas informações adicionais no arquivo, como cabeçalhos, metadados e muito mais, mas precisamos apenas de som. Um formato adequado é chamado PCM, é apenas uma lista de números que representam sons. Converter WAV em PCM pode ffmpeg:

 ffmpeg -i input.wav -f s16le -acodec pcm_s16le output.raw 

Aqui, cada amostra é salva como um número de 16 bits com ordem de bytes reversa (little endian). Em Java, esse número é chamado short , e você pode usar a classe ByteBuffer para converter automaticamente o fluxo de entrada em uma lista de valores short :

 ByteBuffer buf = ByteBuffer.allocate(4); buf.order(ByteOrder.LITTLE_ENDIAN); buf.put(bytes); short leftChannel = buf.readShort(); // stereo stream short rightChannel = buf.readShort(); 

Xcorr engenharia reversa


Para implementar a função xcorr() em Java, estudei o código fonte do Octave. Sem alterar o resultado final, consegui substituir a chamada xcorr () pelas seguintes linhas - elas precisam ser reescritas em Java:

 N = length(audio); M = 2 ^ nextpow2(2 * N - 1); pre = fft(postpad(prepad(jingle(:), length(jingle) + N - 1), M)); post = fft(postpad(audio(:), M)); cor = ifft(pre .* conj(post)); R = real(cor(1:2 * N)); 

Parece assustador, mas a maioria das funções são operações triviais com matrizes. A correlação cruzada é baseada na aplicação da transformada rápida de Fourier em uma amostra de som.

Transformação rápida de Fourier


Como uma pessoa que não tem experiência com DSP, apenas vejo a FFT como uma função que pega uma matriz com a descrição de uma amostra de som - e retorna uma matriz com números complexos que representam frequências. Essa abordagem minimalista funcionou bem: lancei a implementação da FFT a partir do pacote JTransforms e obtive os mesmos resultados que no Octave. Eu acho que isso é parcialmente um culto à carga , mas droga, funciona!

Executando o xcorr em um thread


O algoritmo acima pressupõe que o audio é a matriz na qual estamos procurando jingle . Isso não é totalmente adequado para transmissão, onde temos um fluxo contínuo de som. Para executar a análise, criei um buffer cíclico um pouco mais do que a duração do jingle a ser reconhecido. O fluxo de entrada preenche o buffer e, assim que estiver cheio, o teste de correlação cruzada é executado. Se nada for encontrado, a parte mais antiga do buffer será descartada - e novamente esperamos que seja preenchido.

Eu experimentei um pouco o comprimento do buffer e obtive os melhores resultados com um tamanho de buffer de 1,5 vezes o tamanho do jingle.

Juntando tudo


Obter um fluxo no formato PCM é fácil. Isso pode ser feito usando o ffmpeg acima. O comando abaixo redireciona o fluxo para a entrada java padrão e, em seguida, gera o Got jingle 0 ou o Got jingle 1 quando o padrão correspondente é encontrado no fluxo.

 ffmpeg -loglevel -8 \ -i http://stream3.polskieradio.pl:8904/\;stream \ -f s16le -acodec pcm_s16le - \ | java -jar target/analyzer-1.0.0-SNAPSHOT-jar-with-dependencies.jar \ 2 \ src/test/resources/commercial-start-44.1k.raw 500 \ src/test/resources/commercial-end-44.1k.raw 700 

Versão autônoma


Também preparei uma versão simples e simples do analisador, que se conecta ao fluxo da Troika (sem ffmpeg externo) e reproduz o resultado usando javax.sound . Tudo se encaixa em um único arquivo JAR e contém uma interface básica com os botões Estrela e Parar. Pode ser baixado aqui . Se você não gosta de executar JARs de outras pessoas na sua máquina (o que é absolutamente correto), todas as fontes estão no GitHub .



Tudo parece funcionar como deveria :)

Trabalho adicional


O objetivo final é desativar os anúncios no nível de um amplificador de hardware, recebendo um sinal de FM "real" e não algum fluxo da Internet. Isso é descrito no próximo artigo .

Atualização (junho de 2018)


Discussão em Hacker News
Discussão sobre Wykop
Discussão no Reddit

Source: https://habr.com/ru/post/pt415469/


All Articles