S Supercollider n’est pas seulement un séquenceur mais comme c’est un langage de programmation audio complet, il permet aussi de réaliser des synthétiseurs et des modules de traitement du signal. Je vous propose donc de découvrir comment réaliser 3 choses dans cet article. D’abord un petit synthétiseur FM, puis une reverb (sans trop d’explication car j’ai copié un exemple quelque part, et je ne comprends pas encore tout), puis un motif qui joue le tout, avec le code pour enregistrer tout cela dans un fichier ensuite. Je mets les explications dans le code suivant que vous pourrez copier :
// Lance le serveur audio : s.boot; // Si vous voulez voir la forme d'onde et les fréquences du son qui sort du serveur audio s.scope ; FreqScope.new ; // Créons un canal audio pour la reverb : ~vbus = Bus.audio(s, 2); // Créons un petit synthétiseur FM : ( SynthDef.new(\fm, { // On déclare des arguments en leur donnant en plus des valeurs par défaut. Il est important d'utiliser la variable freq pour la fréquence du porteur car cela permet dans les Pbind d'utiliser degree, note et midinote. arg freq=500, modHz=100, modAmp=0.2, gate=1.0, atk=0.01, rel=1.0, amp=0.2, pan=0.0, fxsend=(-25); //Puis on déclare des variables qui vont permettre de recevoir le signal audio, "car" pour l'oscillateur porteur, et "mod" pour l'oscillateur qui va moduler, "env" pour l'enveloppe qui permet d'arrêter le son à la fin : var car, mod, env, env2; // On définit les enveloppes, env pour l'amplitude du porteur et env2 pour l'amplitude du modulateur. Ici je choisis de fixer l'enveloppe du modulateur mais on pourrait très bien mettre un argument pour rendre cette enveloppe modulable par un Pbind : env = EnvGen.kr(Env.perc(atk, rel), gate: gate); env2 = EnvGen.kr(Env.perc(0.01, 0.5), gate: gate); /* On définit ensuite l'oscillateur qui va servir à moduler. Ici on choisit une onde sinusoïdale avec une fréquence et une amplitude. Rappelons que le ".ar" signifie Audio Rate : c'est-à-dire à la vitesse permettant le traitement audio. ".kr" utilisé dans l'enveloppe signifie Kontrol Rate : à la vitesse permettant un control, c'est ce qu'on utilise par exemple pour une enveloppe ou un lfo.*/ mod = SinOsc.ar(freq:modHz, mul:modAmp) * env2; /* On définit ensuite le porteur qui est lui aussi une onde sinusoïdale avec une certaine fréquence à laquelle on ajoute le modulateur pour obtenir de la synthèse FM, on fait cela pour un canal gauche et avec un petit detune pour le canal droit (on ajoute +5) en utilisant une collection (an Array) comprenant deux éléments [a,b]. On multiplie alors le résultat par amp pour garder une amplitude du signal pas trop forte (1 représente le maximum avant clipping, ici dans la déclaration des arguments, on a choisi 0.2). Il ne faut pas oublier de multiplier le signal par env (l'enveloppe que l'on a définie, sinon elle n'agit qu'avec le paramètre doneAction, comme si c'était une enveloppe carrée de durée atk+rel :*/ car = SinOsc.ar(freq:[freq + mod, freq + 8 + mod]) * env * amp; // Maintenant on utilise un générateur de sortie pour que le signal soit envoyé aux sorties audios de la carte son. En indiquant 0 comme canal de sortie, on indique le premier canal, celui de gauche, mais comme notre signal a été positionné sur 2 canaux, il va donc mettre automatiquement le premier signal sur la premier canal, donc à gauche, et le deuxième sur le second, c'est-à-dire à droite. Out.ar(0, car); // Envoyons le signal au canal audio de la reverb Out.ar(~vbus, car * fxsend.dbamp); // Une fois qu'on a fait tout cela, il faut ajouter cette définition de synthétiseur (the SynthDef) au serveur audio. }).add; ) // On ajoute maintenant la définition de la reverb : ( SynthDef(\reverb, { arg in=0, out=0, dec=4, lpf=1500; var sig; sig = In.ar(in, 2).sum; sig = DelayN.ar(sig, 0.03, 0.03); sig = CombN.ar(sig, 0.1, {Rand(0.01,0.099)}!32, dec); sig = SplayAz.ar(2, sig); sig = LPF.ar(sig, lpf); 5.do{sig = AllpassN.ar(sig, 0.1, {Rand(0.01,0.099)}!2, 3)}; sig = LPF.ar(sig, lpf); sig = LeakDC.ar(sig); Out.ar(out, sig); }).add; ) // Pour avoir un son de ce nouveau synthétiseur qui s'appelle \fm on tape la commande suivante, qui lance le synthétiseur avec les commandes par défaut inscrites dans la définition du synthé. Synth(\fm); // Pour avoir la reverb il faut d'abord la lancer ! Synth(\reverb, [\in, ~vbus]); // Et maintenant si on refait la commande qui lance notre petit synthé fm on a la reverb. L'ordre d'exécution des commandes est donc très important. Synth(\fm); // Mais ce qui fait vraiment la force de Supercollider c'est la richesse de ses commandes pour générer des séquences, des patterns en anglais, on peut alors séquencer chacun des arguments que nous avons définis dans la définition du synthé, avec des modules de séquençage très variés, ici des modules de sélection au hasard simulé. Remarquons que la durée de chacune des séquences n'est pas indiquée. Dans ce cas par défaut la durée est fixée à l'infini. ( // Remarquons qu'on déclare la séquence dans une variable p, ce qui permettra de la contrôler ensuite : p = Pbind( \instrument, \fm, \dur, Pseq([1/8,1/8,1/8,1/8,1/2,1/4,1/4,1/2,1/2,1],inf), \degree, Pseq([1,5,5,4,6]-1,inf), \modHz, Pexprand(0.2,7000,inf), \modAmp, Pwhite(0, 100.0), \amp, Pexprand(0.1, 0.5), \atk, Pexprand(0.001, 0.05), \rel, Pexprand(0.2, 2), \pan, Pwhite(-1.0, 1.0), \fxsend, Pexprand(-100.0, -10), ); ) // Commande qui permet de jouer ce petit motif. L'erreur facile à faire c'est de mettre simplement p.play, mais dans ce cas en faisant p.stop, le motif p ne s'arrête pas. Pour que le motif s'arrête il faut mettre la séquence qui se joue dans une variable, on le fait en faisant la commande suivante : ~pl = p.play; Et après on peut mettre ~pl.stop pour arrêter le séquence. C'est un peu subtile. Il faut comprendre que p représente une partition. Quand on dit p.play on demande à l'ordinateur de lancer un interpète qui joue cette partition. Quand on dit p.stop, on lui dit d'arrêter la partition, ce qui ne veut rien dire. En revanche, si on met p.play dans une variable alors la variable représente l'interpète qui lui va comprendre ce que veut dire d'arrêter de jouer. Cela vient d'une ambiguïté du vocabulaire de Supercollider. On peut ordonner aussi bien à une partition ou à un interprète de jouer, mais on ne peut stopper qu'un interprète et non une partition. ~pl = p.play; // Pour voir les événements choisis à chaque fois il suffit de faire : ~pl = p.trace.play; // Commande qui permet d'arrêter la séquence sans utiliser la coupure générale. // Attention si vous faites la commande stop avec le raccourci prévu dans Supercollider, il faudra relancer la reverb. ~pl.stop; // Jouer à nouveau la séquence en l'enregistrant dans un fichier : ( s.recHeaderFormat = "wav"; Routine({ s.record("/Users/lyann/Music/Dilecthus/Enregistrements/littleFm.wav"); wait(0.02); ~pl = p.play; wait(30); ~pl.stop; wait(5); s.stopRecording; }).play; )