Instrument – Présentation de l’algo de génération

Aujourd’hui un billet plus technique expliquant en détail l’algo de génération de son sur le GPU. J’essais de pas mettre trop de termes techniques afin que le non-informaticien puisse comprendre le fonctionnement.

Rappels

schéma méthode Le projet a pour but de creer un instrument “live” qui permette à l’utilisateur de litéralement dessiner du son via une tablette graphique. L’algorithme consiste donc en la traduction d’une image en élement sonore. Conrètement le bas de l’image contiendras les sons graves et le haut les sons aigus. L’axe horizontal représente le temps, mais il faut savoir qu’à l’écran l’image est une boucle infinie, l’image défile de la droite vers la gauche. L’image peut être nettoyé (remise en noir) ou faire une vraie bande infinie, c’est à dire que ce que vous avez précedemment dessiné revient sur la “planche à dessin”.

Le stylet est utilisé d’une seule façon pour le moment, la pression augmente l’intensité de la couleur dessinée, l’inclinaison et la gomme ne sont pas encore gérés. Les boutons sur le stylet permettent de changer de brosse : pour le moment un trait vertical, une petite spirale et des traits horizontaux sont présents.

Pour la synthèse à proprement parler c’est une sorte de synthèse granulaire, on va additionner des petits blobs de son, de façon à obtenir des sons complexes. Chaque blob est une fréquence sinusoïdale simple sur laquelle on applique une envelope spécifique, si nous visualisons la forme de l’onde sonore d’un blob, nous obtiendrons quelque chose comme ça :

photo d'un blob Donc en bleu nous voyons notre blob, une sinusoïde (oui bon ok, fear my Photoshop skill). Les 2 trais au dessus du bidule bleu (un jour j’apprendrais à dessiner, un jour promis), représentent l’envelope du blob. L’envelope n’est pas choisi au hasard, si 2 blobs s’enchainent, nous aurons une phase montante, une phase stable (où le volume reste constant) et enfin une phase descendante. Nous remarquons 2 phase dans le blob une phase dite courante (montante) et une phase précédente (descendante). L’utilisation de ces 2 phases sera explicité plus en avant.



Algo je crirai ton nom

ALGOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO. Euh bref, maintenant l’algo de géneration à proprement parler :

schéma représentant l'algo

Le schéma ci-dessus présente un cheminement simplifié de l’algo de génération. Les losanges représentent des opérations et les bulles tentent de donner une interprétation au losange le plus proche. Vous remarquerez que chaque opération est affublé d’un horrible acronyme : HLSL, qui signifie High Level Shader Language. C’est le langage de shader de DirectX, concrétement, cela implique que le programme tourne sur la carte graphique au lieu du processeur central. Il y a 3 phases simples dans le logiciel :

  1. Le précalcul
  2. Le mixage des données (data grabber dans le schéma)
  3. L’addition de toutes les lignes

Prérequis

Dans le pipeline graphique classique, les textures sont dites LDR (Low Dynamic Range), c’est à dire que la plage de possibilitées pour décrire la couleur est plutôt limité. En effet chaque composante de couleur peut avoir 256 états possible, et il y a 3 composantes couleurs. Ce système est largement suffisant pour nos écrans d’ordinateur (qui peuvent pas faire mieux de toute façon), mais est légèrement étriqué pour décrire la réalité. Pour palier à ce phénomène, nous pouvons utiliser des textures dites HDR (High Dynamic Range). Ici chaque couleur peut avoir plus de 4 milliards de valeurs possible, ce qui permet de modeler plus finement la réalité. Une des premières application de cette technique est le soleil qui ébloui la caméra et qui sature les alentours (essayer de trouver des scène de 3D mark 2005 pour comprendre), chose qui était difficilement possible avant. Moi j’utilise le HDR tout simplement pour pouvoir avoir des données précises entre -1 et 1, ce qui est vachement pratique pour génerer du son.

Dans ma texture, chaque pixel a 4 composantes : le rouge, le vert, le bleu et l’alpha (la transparence), donc je peut stocker mes données dans chacune de ces composantes.

Précalcul

La phase de précalcul (HLSL Lookup generation sur le schéma) est une phase importante de l’algorithme, elle a lieu une seule fois dans la durée de vie du programme. Le précalcul va créer 512 oscillateurs dans une texture HDR. Un oscillateur ici est représenté par une simple sinusoïde sur laquelle on applique une envelope (volume variable en fonction du temps). Sur l’image vous pouvez voir des bandes vertes et des bandes rouges, ce sont en fait 2 instants superposés, l’instant précédent étant placé dans le canal vert de la texture et l’instant présent dans le canal rouge. La présence de ces 2 instants est important, l’instant présent a un volume qui va en montant, tandis que l’instant précédent a un volume descendant. Chaque pixel passe par les 2 états lors de la génération.

Mixage de données

Dans la partie précédente nous avons précalculé nos oscillateurs, maintenant nous allons mélanger l’image que nous dessinons avec cette même table. L’instant présent est représenté par une colone de la texture de dessin, que nous appellerons texture de coefficients. Sur chaque ligne de la table de précalcul nous multiplions le pixel situé à la même hauteur et à la colonne de l’instant présent de la texture de coefficients. En fait nous multiplions juste la composante rouge de la texture de précalcul, la composante verte est multiplié par la colone précédente (un pixel à gauche de la colone courante) de la texture de coefficients. Nous obtenons donc une texture où chaque oscillateur est pondéré par un coefficient, coefficient faisant partie du dessin dessiné à l’écran.

Addition des lignes

Nous avons mixés nos données, mais nous avons 512 oscillateurs pondérés et indépendants. Pour obtenir notre son final nous devons avoir qu’une seule ‘sortie’ (et non pas 512). Pour arranger ça, nous allons additionner toutes les colonnes de la dernière texture entre elles. Chaque pixel de la première ligne contiendra la somme de tous les pixels contenu dans sa colone. Dans notre cas ça revient à mixer ensemble tous les flux sonore. Au final nous appliquons aussi un volume à la première ligne. Cette phase ne se passe pas en une passe, elle est répété plusieurs fois, du fait de la spécificité de la programmation sur GPU (carte graphique), mais c’est un détail d’implémentation. A la fin de cette passe je peut directement lire ma texture pour récuperer le son quasi-pret à être envoyer sur la carte son. Process de génération fini.

Ou presque…

Ceci est une description légèrement simplifié de l’algorithme, il y a quelques astuces comme des réarangements de données ou des techniques pour éviter d’utiliser trop de pixels, mais ceci rentrant dans les détails d’implémentation je ne rentrerais pas dans les détails.

Conclusion

Voilà pour la description, si des éléments vous semblent obscurs ou si vous souhaitez plus d’information, n’hésitez pas à poster un commentaire pour eclaircissement, je modifierai sans problème. Je tiens à remercier EzecKiel pour son aide lors de la rédaction de ce billet.

Leave a Reply