ALGONOIZER
ALGONOIZER est un générateur de sons construit autour d'un Arduino, basé sur cet article de Vizmut, créateur d'IBNIZ. Il produit des sons allant du bruit à des séquences plus ou moins musicales.
Extraits sonores :
La génération sonore est basée sur la notion de dépassement d'entier. Le type entier int de l'Arduino est codé sur 16 bits, et peut représenter les valeurs comprises entre -32768 et 32767. Si l'on ajoute 1 à une variable int valant initialement 32767, le résultat n'est pas 32768 comme on pourrait s'y attendre, mais -32768. En effet, le codage du plus grand nombre est représenté par tous les bits à "1", et le fait de lui ajouter 1 réinitialise tous les bits à "0". Ce phénomène s'appelle dépassement d'entier.
Le fait d'ajouter 1 continuellement à un entier permet donc de faire varier cet entier de manière cyclique entre -32768 et 32767 de la manière suivante :
-32768, -32767, -32766, ..., 32765, 32766, 32767, -32768, -32767, etc...
Si on trace la valeur obtenue au fil des additions, on obtient une onde en dent de scie de période 65575 opérations. Si l'on contrôle la fréquence à laquelle les opérations sont effectuées, on peut donc contrôler la fréquence de l'onde. Par exemple si la fréquence de calcul est de 65.5kHz, les 65575 additions durent 1 seconde, et l'onde a pour fréquence 1Hz. Si au lieu d'ajouter 1 on ajoute 100, la fréquence de l'onde devient 100Hz, et cette onde est maintenant une onde audio.
On peut ajouter de la complexité et ne pas se contenter de simples additions : multiplications, divisions, opérations logiques, etc.. permettent de moduler l'onde et d'obtenir des sons (bruits ?) variés. Le code de l'ALGONOIZER intègre des fonctions trouvées sur le site cité plus haut, et des fonctions "maison", pour un total de 16 fonctions sélectionnables par un bouton rotatif. Deux autres boutons permettent de moduler la fonction sélectionnée. Un quatrième bouton permet de régler le volume de sortie.
L'ALGONOIZER dispose aussi d'un oscillateur LFO utilisé pour la modulation. La forme d'onde du LFO est réglable par un bouton : carré, sinus, triangle, rampe montante et rampe descendante. La fréquence est réglée par un bouton poussoir (du type tap tempo). Le bouton poussoir dispose d'une LED qui reproduit le cycle du LFO et permet de visualiser la fréquence définie.
La modulation est disponible sur chacun des paramètres audio : le volume de sortie, les deux paramètres agissant sur la fonction de génération sonore, mais également le choix de la fonction de génération. A partir d'une position de départ de chacun des potentiomètres de réglage, le mode de définition de la modulation par le LFO est enclenché en maintenant appuyé le bouton poussoir du LFO, et en modifiant les valeurs des potentiomètres que l'on veut contrôler par le LFO. Lorsque l'on relâche le bouton poussoir, le LFO module les paramètres audio correspondant entre leur valeur initiale qui a été sauvegardée, et la valeur instantanée définie par la position du potentiomètre. Attention toutefois, le code n'est pas parfait et le LFO et la modulation ne fonctionnent pas toujours très bien (comportement parfois erratique du LFO)...
Du point de vue technique, le code est basé sur l'utilisation des interruptions sur l'Arduino. Pour cela les registres TCCR1A, TCCR1B et TIMSK1 sont utilisés pour définir le mode "8-bit fast PWM" sans prescaler, et pour activer l'interruption sur le débordement de TIMER1. Dans ces conditions la routine d'interruption est exécutée à une fréquence de 62.5KHz. On utilise une interruption sur deux pour la génération audio, et l'autre pour le calcul du LFO. Soit une fréquence d'échantillonnage audio de 31.25KHz.
Le LFO est basé sur des tables d'ondes. Pour chaque forme d'onde, les valeurs sont stockées dans des tableaux, ce qui évite d'avoir à les recalculer en cours d'exécution.
Les calculs audio sont donc réalisés au sein de la routine d'interruption, et envoyés vers la sortie PWM. La boucle principale loop() est utilisée pour la lecture des potentiomètres et du bouton poussoir. Les potentiomètres sont connectés aux entrées analogiques, et la lecture est faite à l'aide de la fonction analogRead(). La vitesse d'acquisition est augmentée en modifiant la valeur du prescaler du convertisseur (voir cet article sur le convertisseur de l'Arduino et sur l'augmentation de la vitesse de conversion).
Le code peut être téléchargé ici (développé avec l'IDE Arduino v1.0). Attention, code non totalement fonctionnel, encore à améliorer en particulier au niveau du LFO.