L'auteur de l'article est le programmeur polonais Tomek Rekavek, qui développe le projet Jackrabbit Oak dans le cadre de la Apache Software Foundation pour Adobe. L'article a été publié sur le blog personnel de l'auteur le 24 février 2016.La «Radio-3» polonaise (la «Troïka») est célèbre pour sa bonne musique et ses présentateurs intelligents. En revanche, il souffre de la présence de blocs d'annonces bruyants et ennuyeux dans les émissions, qui font généralement la publicité d'une sorte d'électronique ou de médicaments. J'écoute Troika presque constamment au travail et à la maison, alors je me suis demandé: comment supprimer les publicités? Je pense que j'ai réussi à trouver une solution.
Traitement numérique du signal
Mon objectif est de créer une application qui coupe les publicités. Le bloc commercial
commence et
se termine par des jingles, le programme doit donc reconnaître ces sons spécifiques et désactiver le son entre eux.
Je sais que ce domaine des mathématiques / informatique s'appelle
le traitement numérique du signal , mais le DSP m'a toujours semblé magique. Eh bien, une excellente occasion d'apprendre quelque chose de nouveau. J'ai passé un jour ou deux à essayer de trouver le mécanisme à utiliser pour analyser le flux audio. Et à la fin, j'ai trouvé ce dont j'avais besoin: c'est la
corrélation croisée ou la
corrélation croisée (corrélation croisée).
Octave
Généralement, tout le monde fait référence à la mise en œuvre de MATLAB. Mais MATLAB est une application coûteuse qui simplifie l'exécution d'opérations mathématiques complexes, y compris DSP. Heureusement, il existe une alternative gratuite appelée
Octave . Il semble que dans Octave, il est facile d'exécuter une corrélation croisée sur deux fichiers audio. Il suffit d'exécuter les commandes suivantes:
pkg load signal jingle = wavread('jingle.wav')(:,1); audio = wavread ('audio.wav')(:,1); [R, lag] = xcorr(jingle, audio); plot(R);
Vous obtenez le graphique suivant:

Un pic est clairement visible qui décrit la position de
jingle.wav
dans
audio.wav
. Ce qui m'a surpris, c'est la simplicité de la méthode:
xcorr()
fait tout le travail, le reste du code ne sert qu'à lire les fichiers et à afficher le résultat.
Je voulais implémenter le même algorithme en Java, puis j'aurai un outil qui:
- lit le flux audio à partir de l'entrée standard (par exemple, à partir de ffmpeg),
- analyse à la recherche de jingles,
- imprime le même flux sur stdout et / ou le désactive.
L'utilisation de stdin et stdout vous permettra de connecter le nouvel
analyseur à d'autres applications chargées de la diffusion audio et de la lecture du résultat.
Lecture de fichiers audio
La première chose qu'un programme Java doit lire est un jingle (enregistré en tant que fichier
.wav
) dans un tableau. Il y a des informations supplémentaires dans le fichier comme les en-têtes, les métadonnées, etc., mais nous n'avons besoin que du son. Un format approprié est appelé PCM, c'est juste une liste de nombres représentant des sons. Convertir WAV en PCM peut ffmpeg:
ffmpeg -i input.wav -f s16le -acodec pcm_s16le output.raw
Ici, chaque échantillon est enregistré sous la forme d'un nombre de 16 bits avec un ordre d'octets inversé (petit endian). En Java, ce nombre est appelé
short
et vous pouvez utiliser la classe
ByteBuffer
pour convertir automatiquement le flux d'entrée en une liste de valeurs
short
:
ByteBuffer buf = ByteBuffer.allocate(4); buf.order(ByteOrder.LITTLE_ENDIAN); buf.put(bytes); short leftChannel = buf.readShort();
Ingénierie inverse Xcorr
Pour implémenter la fonction
xcorr()
en Java, j'ai étudié le
code source d' Octave. Sans changer le résultat final, j'ai pu remplacer l'appel xcorr () par les lignes suivantes - elles doivent être réécrites en 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));
Cela semble effrayant, mais la plupart des fonctions sont des opérations triviales avec des tableaux. La corrélation croisée est basée sur l'application de la
transformée de Fourier rapide sur un échantillon sonore.
Transformation de Fourier rapide
En tant que personne qui n'a aucune expérience avec DSP, je vois simplement la FFT comme une fonction qui prend un tableau avec une description d'un échantillon sonore - et renvoie un tableau avec des nombres complexes représentant des fréquences. Cette approche minimaliste a bien fonctionné: j'ai lancé l'implémentation FFT à partir du package
JTransforms et obtenu les mêmes résultats que dans Octave. Je pense que c'est en partie un
culte du cargo , mais bon sang, ça marche!
Exécuter xcorr sur un thread
L'algorithme ci-dessus suppose que l'
audio
est le tableau dans lequel nous recherchons le
jingle
. Ce n'est pas entièrement adapté à la diffusion, où nous avons un flux continu de son. Pour exécuter l'analyse, j'ai créé un tampon cyclique un peu plus long que la durée du jingle à reconnaître. Le flux entrant remplit le tampon et dès qu'il est plein, le test de corrélation croisée est exécuté. Si rien n'est trouvé, alors la partie la plus ancienne du tampon est jetée - et nous nous attendons à nouveau à ce qu'elle soit remplie.
J'ai expérimenté un peu la longueur du tampon et j'ai obtenu les meilleurs résultats avec une taille de tampon de 1,5 fois la taille du jingle.
Tout mettre ensemble
Obtenir un flux au format PCM est facile. Cela peut être fait en utilisant le
ffmpeg
ci-dessus. La commande ci-dessous redirige le flux vers une entrée
java
standard, puis génère
Got jingle 0
ou
Got jingle 1
lorsque le modèle correspondant est trouvé dans le flux.
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
Version autonome
J'ai également préparé une version autonome simple de l'analyseur, qui se connecte lui-même au flux Troika (sans
ffmpeg
externe) et reproduit le résultat en utilisant
javax.sound
. Tout tient dans un seul fichier JAR et contient une interface utilisateur de base avec des boutons Star et Stop. Il peut être téléchargé
ici . Si vous n'aimez pas exécuter les fichiers JAR d'autres personnes sur votre machine (ce qui est absolument correct), toutes les sources sont sur
GitHub .
Tout semble
fonctionner comme il se doit :)
Travaux ultérieurs
Le but ultime est de désactiver les publicités au niveau d'un amplificateur matériel, en recevant un «vrai» signal FM, et non un flux Internet. Ceci est décrit dans l'
article suivant .
Mise à jour (juin 2018)
Discussion chez Hacker NewsDiscussion sur WykopDiscussion sur Reddit