En continuant à naviguer sur mon site, vous consentez à ce que j'utilise des cookies pour collecter les statistiques de visites. En savoir plus

#Informatique Radiomino, mise à jour

De temps à autres, j'ajoute quelques titres dans la rotation de Radiomino, mais histoire de proposer une radio au vrai sens du terme, j'y apporte également quelques améliorations sur la forme.

Je suis actuellement en train d'ajouter à Radiomino un traitement de son qui n'est pas terminé. « Impossible ! » me direz-vous, « Radionomy ne permet pas d'ajouter de traitement de son. »

Oui et non. Effectivement, avec Radionomy, le seul TDS possible est un régulateur de gain abomiffreux, et c'est le principal reproche que je ferai à cette plateforme, bien que l'absence de TDS peut aussi s'expliquer par la complexité de mise en place pour l'utilisateur et l'utilisation gourmande des ressources serveurs. Bref, il était nécessaire pour moi, d'apporter une couleur sonore à ma petite radio, et surtout un contrôle du gain automatique, histoire d'amplifier les chanson moins audibles.

J'avais au départ songé à utiliser mon Raspberry Pi, y installer une machine virtuelle Windows et y faire tourner Sam Broadcaster avec un traitement de son SoundSolution (version 1.31, que j'affectionne tout particulièrement bien qu'il ne soit pas compatible facilement avec des logiciels qui ne connaissent pas les DSP Winamp) pour rediffuser vers un Shoutcast. C'aurait été idéal, si seulement les Raspi avaient plus de performances…

Du coup j'ai tenté de faire tourner le plugin StereoTool en ligne de commande, mais j'ai du me résigner à le faire, étant donné que StereoTool n'est pas compilé pour les architectures ARM… et il n'est pas open source ! Le son aurait ensuite été envoyé à un Shoutcast.

Alors je joue mon avant dernière carte : utiliser Liquidsoap et Shoutcast. Je connaissais déjà Liquidsoap pour ma précédente expérience pendant l'existence de la webradio JNT. Cependant, le Raspi n'est vraiment pas fait pour le son en temps réel. J'ai donc balancé mes scripts sur un serveur Linux classique, et tout tourne à merveille ! Liquidsoap était d'ailleurs la première solution à laquelle j'aurais dû penser, puisqu'il permet vraiment de manipuler le son en temps réel, voire de construire une petite radio avec sélection des morceaux au hasard, etc.

Pour ce qui est du traitement de son, il n'est pas terminé puisqu'il comporte des imperfections, notamment sur la gestion de la grosse caisse qui a tendance à compresser le reste de la mélodie si elle est un peu trop forte, et sur l'égalisation des niveaux entre les moments calmes des musiques et ceux qui le sont moins.

Voici donc la chaîne de traitement qui est actuellement en place (qui reprend le modèle de SoundSolution) :

  1. Je récupère le flux audio de radiomino dans mon script Liquidsoap (en OCAML fallu-t-il le préciser).
  2. Un AGC (contrôle du gain automatique) vient augmenter le niveau des musiques trop faibles. Pour le moment, il est réalisé à l'aide du "normalizer" de Liquidsoap qui est plutôt efficace mais qui ne me satisfait pas, car je n'ai pas vraiment le détail de son fonctionnement (à part peut-être en fouillant bien les sources de Liquidsoap). Ce que je souhaiterais réussir à mettre en place, c'est un AGC fait à partir d'un compresseur qui compresserait le signal en se basant sur un sidechain, qui lui-même recevrait exactement le même signal, mais en ayant retiré les fréquences basses (< 300Hz env.) Pour avoir déjà essayé de faire des contrôles du gain automatique sans sidechain, je peux vous dire que chaque coup de grosse caisse va compresser le reste de la musique, étant donné que le threshold du compresseur relativement bas, et que son attaque est rapide, ce qui n'est pas souhaitable, et pas agréable du tout à l'écoute. Malheureusement je n'ai pas encore trouvé comment faire avec Liquidsoap (à bon entendeur…).
  3. Vient ensuite un compresseur multibande, qui, à mon impression, ne ressort pas encore assez dans le mixage final de mon flux, cependant, il possède déjà un peu la couleur que je veux donner à ma radio… ne reste plus qu'à ajuster les différents réglages de mon compresseur, mais le faire dans un script sans mise à jour automatique à chaque réglage différent ce n'est pas très pratique non plus. Si vous connaissez un moyen de recharger Liquisoap à chaud je suis preneur.
  4. Après, on a un "Dual-band compressor-limiter-clipper" dixit SoundSolution. J'ai de nouveau essayé de reprendre le même principe, mais cette partie du traitement, dans le plugin SoundSolution, a l'air bien plus efficace que mon traitement fait maison. Affaire à suivre…
  5. On poursuit avec un "Bass Enhancer", conséquence probable de tous les compresseurs précédents et de leurs réglages, on a vite fait de perdre des basse en sortie, il est donc utile de les rehausser après toute compression, et seulement après (rehausser les basses avant de compresser la mélodie, c'est risquer d'influencer nos compresseurs sur la grosse caisse… et oui, encore elle !)
  6. Enfin, j'ai ajouté un "Stereo Enhancer" avec un chorus à une seule voix supplémentaire, mais je doute de son efficacité ; il faut dire que la documentation de Liquidsoap n'est pas très précise quant aux résultats des effets sonores.
  7. Il ne reste plus qu'à réamplifier le tout et à envoyer ça au Shoutcast qui diffuse le tout.

Voici le code de mon script Liquidsoap :


set("log.stdout", true)

def agc(stream, hpf_cutoff, attack, release, threshold)
        # stream_filtered = ladspa.hpf(cutoff_frequency=hpf_cutoff, stream)
        # stream_adjusted = compress_sidechain(attack=attack, release=release, ratio=100., threshold=threshold, sidechain=stream_filtered, stream)
        stream = normalize(gain_max=20., gain_min=0., threshold=threshold, stream)
        stream
end

def multiband_band(stream, from, to, attack, release, ratio, threshold, gain)
        stream_filtered = ladspa.lpf(cutoff_frequency=to, ladspa.hpf(cutoff_frequency=from, stream))
        stream_compressed = compress(attack=attack, release=release, threshold=threshold, ratio=ratio, gain=gain, stream_filtered)
        stream_compressed
end

def multiband(stream)
        stream = ladspa.amp(amps_gain=25., stream)
        stream_band1 = multiband_band(stream, 0., 580., 60., 600., 3., -5., -2.)
        stream_band2 = multiband_band(stream, 580., 1950., 50., 960., 4., -3., -0.5)
        stream_band3 = multiband_band(stream, 1950., 5560., 40., 800., 3., -4., 0.)
        stream_band4 = multiband_band(stream, 5560., 8870., 30., 1050., 4., -4., 0.)
        stream_band5 = multiband_band(stream, 8870., 22050., 30., 2700., 3., -5., 3.)
        stream_mix = add(weights=[1, 1, 1, 1, 1], [stream_band1, stream_band2, stream_band3, stream_band4, stream_band5])
        stream_mix
end

def limiter_band(stream, from, to, attack, release, ratio, threshold, gain)
        stream_filtered = ladspa.lpf(cutoff_frequency=to, ladspa.hpf(cutoff_frequency=from, stream))
        stream_compressed = limit(attack=attack, release=release, threshold=threshold, ratio=ratio, gain=gain, stream_filtered)
        stream_compressed
end

def dual_limiter(stream)
        stream = ladspa.amp(amps_gain=-10., stream)
        stream_band1 = multiband_band(stream, 0., 6000., 100., 400., 10., -6., 0.)
        stream_band2 = multiband_band(stream, 6000., 22050., 100., 400., 10., -6., 0.)
        stream_mix = add(weights=[1, 1], [stream_band1, stream_band2])
        stream_mix = clip(min=0., max=6., stream_mix)
        stream_mix
end

def loudness(stream, cutoff, gain)
        stream_low = ladspa.lpf(cutoff_frequency=cutoff, stream)
        stream_low = ladspa.amp(amps_gain=gain, stream_low)
        stream_high = ladspa.hpf(cutoff_frequency=cutoff, stream)
        stream_mix = add(weights=[1, 1], [stream_low, stream_high])
        stream_mix
end

stream = input.http(buffer=10., max=20., "http://listen.radionomy.com/radiomino")
stream = agc(stream, 200., 10., 2000., -50.)
stream = multiband(stream)
stream = dual_limiter(stream)
stream = ladspa.multivoicechorus(delay_base=10., detune=0., lfo_frequency=30., number_of_voices=1, voice_separation=0.5, stream)
stream = loudness(stream, 150., 14.)
stream = ladspa.amp(amps_gain=10., stream)
output.shoutcast(%mp3(bitrate=320), host="127.0.0.1", port=8000, password="lastone", genre="Musique", fallible=true, stream)

Ensuite, je voulais conserver la possibilité d'écouter le flux traité via le port 80. J'ai donc entamé un script PHP qui relayait le port 8000 sur le port 80, à une adresse bien précise, étant donné que le port 80 était déjà utilisé.

En utilisant PHP, j'ai réussi ce tour de passe-passe avec la bête combinaison fopen-while-echo-fread. Cependant, je souhaite également connaître l'audience exacte de ma radio. Une des solutions que j'ai trouvée est d'ouvrir deux flux : celui de radionomy et le mien, et de renvoyer dans les oreilles de l'auditeur, uniquement mon flux. Cependant, PHP n'a pas l'air d'apprécier les deux fopen que j'ai fait… ou alors, il n'aime pas les URLs de Shoutcast. Je n'ai pas encore trouvé le fin mot de l'histoire.

Si vous avez des suggestions à faire, les commentaires sont là pour ça :) .

À suivre…

PS : je vais tout de même vous donner le flux audio traité.

Rédigé le .

Commentaires

comments powered by Disqus