Traitement du signal : applications aux effets audio Ce tutoriel présente quelques effets numériques audio et leur implémentation en C sur PC.
Les différents effets présentés sont illustrés
par des exemples audio : une voix chantée est utilisée
comme signal d’origine.
6) Réverbération
En général, dans les applications de traitement de signal,
on cherche à effectuer les traitements en temps réel. Le système
de traitement numérique, à chaque instant discret nT, où
T est la période d’échantillonnage, possède une entrée
x(nT) et fournit une sortie y(nT). L’échantillon résultant
du traitement y(nT) doit être disponible avant que le prochain échantillon
à traiter x(nT) arrive. La durée entre l’arrivée de
deux échantillons successifs est la période d’échantillonnage
du signal. Pour simplifier l’écriture dans tout ce qui suit, on peut
omettre la variable T.
Ce traitement en temps réel est possible dans le cas d’un traitement
réalisé par un processeur spécialisé (DSP), puisque
ce système est complètement programmable et contrôlable.
Par contre, dans le cas d’un traitement réalisé par ordinateur,
le signal doit être traité blocs par blocs, parce que l’ordinateur
effectue la plupart du temps plusieurs tâches en parallèle sans
que l’utilisateur ait le contrôle de celles-ci.
Dans le cas d’un traitement par ordinateur, on peut donc définir
l’algorithme de traitement général d’un bloc audio par :
L’algorithme de traitement d’un bloc pourrait prendre la forme ci-dessous. Dans une implémentation en C, les arguments d’une fonction de traitement « traite_ech » seraient : · buf_e : le bloc à traiter (bloc d’entrée) · buf_mem : le buffer mémoire du module de traitement ; ses éléments doivent être initialisés à 0
·
ind : un indice de pointage dans le tampon mémoire du module
de traitement
On caractérise souvent un filtre numérique par sa réponse implusionnelle. La réponse impulsionnelle est la réponse à une suite de nombre dont seul le premier est différent de 0. Par convention ce premier échantillon est égal à 1. La réponse impulsionnelle permet de comprendre l’effet du système sur un signal d’entrée plus complexe, comme un son par exemple : ce son serait répété à intervalles réguliers, tout en étant atténué.
L’effet de panoramique est un effet stéréo qui permet de
simuler un positionnement d'une source sonore par rapport à l'auditeur.
Cet effet est obtenu simplement en appliquant un volume différents
aux deux voies gauche et droite.
Pour obtenir la sensation d'une source sonore se déplaçant de gauche à droite ou de gauche à droite, il suffit de moduler les amplitudes, la somme des volumes des deux voies restant constante. Par exemple, si ag est le volume de la voie gauche, le volume de la voie droite sera égal à :
ad=1-ag
Exemple audio
Dans cet exemple, le volume d’un des deux canaux stéréo
est modulé par une sinusoïde de fréquence de l’ordre
du Hertz. Le volume de l'autre canal est obtenu de la manière décrite
ci-dessus. voix_sanseffet.wav voix_panor.wav
Un des traitements les plus simples que l’on peut appliquer à un signal est un retard temporel. Un retard constant appliqué à un signal n’est pas perceptible si le signal non-retardé n'est pas utilisé également (et donc n’a aucune utilité ). Par contre, en modulant ce retard en fonction du temps, il devient perceptible.
La relation entrée/sortie est définie par :
y(n)=x(n-d)
où d est le décalage temporel (un retard) en nombre d’échantillons.
La relation entre le décalage en échantillons
de
et le décalage en secondes
ds
est : de = ds × fe
où fe est la fréquence d’échantillonnage. Qu'il s'agisse d'une implémentation logicielle ou matérielle, le bloc de retard doit comporter de la mémoire : en effet, au moment de la génération de l’échantillon y(n), seul l’échantillon x(n) est présenté en entrée du bloc. Or y(n) dépend d’une valeur passée de l’entrée : x(n-d). Cette valeur doit donc être mémorisée à l’intérieur du bloc. La taille de ce tampon doit au moins être égale au délai d.
L’algorithme pour générer l’échantillon y(n) en fonction de x(n) nécessite les paramètres d’entrée suivants : · x : échantillon d’entrée courant · buf[ ] : tampon mémoire pour les échantillons d’entrée (x) passés nécessaires · d : la taille de ce buffer · i : indice de pointage dans le buffer ; cet indice doit rester compris entre 0 et d-1 L’algorithme génère l’échantillon de sortie y.
Exemple avec d=2 Dans les tableaux ci-dessous, l’élément mis à jour dans le tampon à chaque itération est mis en gras.
L'implémentation en C de l'algorithme défini ci-dessus, est directe :
Cette première implémentation est simple mais limitée aux délais fixes. Si l’on souhaite un délai variable, pour programmer les effets chorus ou flanger par exemple, il est nécessaire d'utiliser un tampon mémoire de taille au moins égale à la valeur maximale du délai variable, et d'utiliser 2 pointeurs : un pour la mise à jour du tampon et l’autre pour obtenir l'échantillon de sortie. Une deuxième implémentation en C, plus complète donc, est donnée ci-dessous.
Deuxième implémentation en C
Dans l’exemple ci-dessous, on choisit de décrémenter le
pointeur du tampon, contrairement à la première implémentation,
pour éviter d’avoir à utiliser un pointeur supplémentaire
pour l’échantillon utilisé.
Exemple audio
Le délai appliqué au signal original varie en cours du temps
de manière sinusoïdale (fréquence de l’ordre du Hertz). voix_sanseffet.wav voix_delai.wav
L'effet de panoramique décrit plus haut était un premier effet stéréo. Pour accroître la sensation de positionnement d'une source sonore dans l'espace situé autour de l'auditeur, un deuxième effet consiste à appliquer un léger décalage temporel (retard) sur l'une des deux voies. Le son d'une source située sur la gauche ou la droite de l'auditeur, parvient en effet à l'oreille opposée avec un volume un peu inférieur à celui qui parvient à l'autre, mais aussi avec un très léger retard temporel.
Exemple audio
Dans cet exemple, un décalage temporel est appliqué sur le canal de droite.
Les effets flanger et chorus consistent à ajouter à chaque échantillon d'un son un échantillon passé, comme dans l'écho unique, mais avec les différences suivantes :
- le retard est beaucoup plus réduit
voix_sanseffet.wav voix_flanger.wav
La relation entrée/sortie est définie par :
y(n)=x(n)+a.x(n-d) Là encore le buffer mémoire doit avoir une taille au moins égale au retard d.
Implémentation en C
5.2)
Echos multiples
Dans le cas d'échos multiples, on utilise la structure de filtre dite en peigne (en référence à sa réponse fréquentielle, qui ne laisse passer que certaines fréquences, régulièrement espacées). Contrairement au filtre utilisé pour l'écho simple, ici l'échantillon de sortie y(n) dépend d'échantillons passés de la sortie. Cette structure est celle d'un filtre à réponse impulsionnelle infinie (RIF).
Filtre en peigne
y(n)=x(n)+a.y(n-d)
avec a<1, sinon on aurait une divergence des valeurs de y(n), c’est
à dire que la valeur des échantillons de sortie augmenterait
indéfiniment. 'a' peut être vu comme un taux de ré-injection.
d est un retard temporel, en nombre d’échantillons.
L’implémentation de ce bloc nécessite un tampon mémoire de 'd' échantillons. On pourrait penser initialement qu’il suffit de mémoriser 2 échantillons : x(n) et y(n-d), mais ça n’est pas suffisant. En effet, quand on calcul par exemple l’échantillon y(n), il dépend de l’échantillon passé y(n-d), qui doit avoir été mémorisé. L’échantillon suivant y(n+1) dépend quant à lui de l’échantillon y(n-d+1) qui doit donc lui aussi avoir été mémorisé.
Implémentation en C du filtre en peigne
Exemple de réponse impulsionnelle avec D=5 et d=3 :
Une structure de réverbérateur très connue est celle de Schroëder.
Le réverbérateur de Schroëder est composé de filtres en peigne en parallèle, suivis de filtres passe-tout en série.
Structure du réverbérateur de Schroëder |