Geluid




Audio-server

Het geluid wordt bij SuperCollider gegenereerd door de server. De server is een applicatie die los van de client draait. Hierdoor zorgt SuperCollider ervoor dat dit proces bij eventuele crash van de client of IDE door kan gaan, maar ook dat het op een andere computer kan werken.


opstarten en afsluiten

De server staat bij het opstarten van SC niet standaard aan. Dit is net als in Max, waar je ook eerst de audio aan moet zetten voor er geluid mogelijk is.

De server zet je aan door de volgende regel code uit te voeren:

s.boot;

Je zult nu zien dat de server-meters groen worden. De server kiest als output standaard de output van je computer.

Wil je de server uitzetten, gebruik dan de volgende code:

s.quit;

Samplerate

Het kan gebeuren dat er een samplerate mismatch is omdat SuperCollider bijvoorbeeld op 44100Hz draait en jouw geluidskaart op 48000Hz. Om de samplerate aan te passen kan je de volgende code uitvoeren voordat je de server opstart:
Server.default.options.sampleRate = 48000;


Output-device

Om het output-device te kiezen dat je wil gebruiken voer je de volgende code uit voor je de server opstart: Server.default.options.outDevice_("naam_van_device");

Als je wil weten welke output devices er allemaal beschikbaar zijn voer je de volgende code uit: ServerOptions.outDevices;

Wil je het input-apparaat aanpassen, gebruik in bovenstaande voorbeelden dan inDevice en inDevices


Geheugengebruik

Als je gebruik maakt van verschillende reverbs en delay's kan het voorkomen dat er niet genoeg RAM-geheugen beschikbaar is voor SuperCollider om mee te werken.

Om te kijken hoeveel geheugen er op dit moment beschikbaar is voer je de volgende code uit: Server.default.options.memSize
Waarschijnlijk komt daar 8192 uit, dat is dus 8 mb.

Als je dit wil uitbreiden naar meer geheugen kan je de volgende code uitvoeren:
Server.default.options.memSize = 512000

Daarmee maak je 500MB van je RAM-geheugen beschikbaar voor SuperCollider. Dat is in ieder geval genoeg om een grote hoeveelheid reverbs, delays en samples aan te kunnen.

Vergeet niet de server opnieuw op te starten als je aanpassingen hebt gemaakt aan audio device, samplerate of geheugengebruik


Volume

Supercollider voert de code uit zoals jij die ingeeft. Dus als er per ongeluk een komma verkeerd staat waardoor de amplitude 10 is in plaats van 1, zal het geluid 10 keer zo hard afgespeeld worden. Dit kan pijnlijk zijn aan je oren. Om te voorkomen dat dit mis gaat kan je met behulp van een extensie een limiter inbouwen op de output. Deze zal altijd aanstaan en ervoor zorgen dat je bij fouten nog steeds audio hoort binnen een redelijk volume. Je kunt de limiter, safety net geheten hier downloaden. Om te installeren voer je de volgende stappen uit:

Wil je de ingebouwde limiter uitzetten voer van de volgede code uit: Quarks.uninstall("SafetyNet")


Functies

Om geluid af te kunnen spelen kun je een functie maken die je uit kan voeren. In Supercollider maak je een functie door code tussen { } te plaatsen:

~sinus = {SinOsc.ar(440);}

De functie voer je vervolgens uit met:

~sinus.play;

Als het goed is hoor je nu een sinustoon van 440Hz. Je moet hierbij wel de server aan hebben staan, anders gebeurt er niets. Gebruik cmd/ctrl + . om het geluid weer te stoppen.

Als je de volgende code gebruikt hoor je niet alleen de sinustoon, maar zie je hem ook verschijnen op de oscilloscoop:

~sinus.scope;

Om het verloop van een golfvorm goed te zien kan je ook .plot gebruiken. Standaard laat SuperCollider het verloop van de golfvorm van 0.1 seconde zien. Als je dit aan wil passen kan je de tijd in seconden er tussen haakjes achter zetten:

~sinus.plot(1) //laat de sinus gedurende 1 seconde zien


UGens

Supercollider wordt geleverd met een groot aantal Unit Generators, kortweg UGens. Als je in de help browser op Browse klikt en dan onderin op UGens krijg je een overzicht met welke UGens er beschikbaar zijn.

Je kunt een UGen op twee verschillende manieren gebruiken: met .ar of met .kr als achtervoegsel. .ar staat voor AudioRate, dit is te vergelijken met de audio objecten in Max, dit zijn de objecten die audio genereren / bewerken en hoorbaar moeten zijn. .kr staat voor KontrolRate, dit is te vergelijken met de objecten zonder ~ in Max, deze kun je bijvoorbeeld gebruiken als LFO.

Als je de naam van een UGen met je muis selecteert en op cmd/ctrl+D drukt krijg je een overzicht (description) van hoe je deze kunt gebruiken. Bij bijvoorbeeld SinOsc.ar zie je dat je vier argumenten moet invullen: de frequentie, de fase, de mul en de add. Ook kan je zien dat er standaardwaarden zijn ingevuld. Als je niets invult worden die waardes gebruikt.


mul & add

Twee argumenten die je bij bijna elke UGen tegenkomt zijn mul en add. Net als in Max zijn de digitale audiosignalen in Supercollider uitgedrukt in getallen tussen -1 en 1.

Met mul kan je deze waarden vermenigvuldigen met een getal. Als je het signaal van een standaard oscillator wilt verzwakken tot de helft moet je bij mul dus 0.5 invullen, de range van de oscillator zal dan tussen -0.5 en 0.5 zijn.

Met add kan je een offset meegeven aan een signaal. Wil je bijvoorbeeld een sinus-oscillator gebruiken als LFO-signaal om de amplitude van een oscillator aan te passen dan zul je van het signaal van -1 tot 1 een signaal van 0 tot 1 moeten maken. Je hebt net gezien dat met een mul van 0.5 het signaal van -0.5 tot 0.5 loopt. Door er dan 0.5 bij op te tellen loopt het signaal van 0 tot 1.

    SinOsc.ar(100,0,0.5,0.5);

    /* Let op! Voer deze code niet zomaar uit!
        Het is geen bipolair audiosignaal meer,
        je kunt hier je speakers mee beschadigen!
     */

Wil je nu de frequentie van een oscillator moduleren dan kan je ook de mul en add gebruiken. Wil je dat de frequentie moduleren tussen 50 en 150Hz moet je een mul gebruiken van 50 en een add van 100.

SinOsc.ar(100,0,50,100);

//LET OP! VOER DIT NOOIT ZOMAAR UIT.
//EEN SIGNAAL DAT 50X VERSTERKT IS, IS ERG HARD!

Als je wil berekenen welke mul en welke add je moet invoeren dan kun je dat als volgt aanpakken: (bij een range tussen de 50 en 150)

Mul:
bovengrens โ€“ ondergrens / 2
150 โ€“ 50 = 100/2 = 50

Add:
ondergrens + mul
50 + 50 = 100

De oscillator zal nu bewegen met 100 als nulpunt en tot maximaal 50 daaronder en daarboven.


Nested UGens

De kracht van Supercollider ligt erin dat je gemakkelijk UGens kunt combineren tot complexere en daarmee vaak meer interessante synthese. In het bovenstaande voorbeeld kan je bijvoorbeeld nooit de modulerende sinus zomaar uitvoeren, je zult deze moeten gebruiken om de frequentie van een andere UGen te moduleren. Dit doe je met de volgende code:

{Saw.ar(SinOsc.kr(1,0,50,100),SinOsc.kr(0.5,0,0.5,0.5),0)}.play;

Zorg bij het uitvoeren van de code dat je het volume van je laptop altijd heel zacht zet. Als je code typt die er voor zorgt dat het hard wordt afgespeeld, zal Supercollider dit ook hard afspelen! Gebruik nooit een hoofdtelefoon of oortjes als je aan het experimenteren bent.



SynthDefs

Een eenvoudige SynthDef

Een SynthDef maakt het mogelijk om een aantal UGens te combineren en daarmee Synths te maken die terwijl ze draaien bestuurd kunnen worden. Je kunt er OSC-berichten naartoe sturen die ze 'live' gebruiken om bepaalde parameters aan te passen.


Een SynthDef maken

Een voorbeeld van een SynthDef die een sinus genereert

SynthDef("mySine", { |freq=400|
    Out.ar(0, SinOsc.ar(freq,0,0.2))
}).add;

Een SynthDef uitvoeren

Dit beschrijft een geluid maar maakt uit zichzelf nog geen geluid. Met deze SynthDef maken we een Synth:

~synth_a = Synth("mySine");

of zo:

~synth_a = Synth("mySine", [\freq, 440]);

Vervolgens kunnen we de frequentie aanpassen terwijl de Synth draait:

~synth_a.set(\freq, 800);
~synth_a.set(\freq, 400);


Een meer complete SynthDef, stap voor stap uitgelegd

Voor het aansturen van รฉรฉn sinustoon is een SynthDef misschien niet zo nuttig, maar voor complexere synthesizers is het heel handig om dat in een SynthDef te verpakken. Hieronder een voorbeeld van een complexere SynthDef, daarna zullen we daar een aantal onderdelen nader bekijken.

(
SynthDef("klank",{|freq=500,ffreq=500,rate=1,amp=0.5|
    var env,sig,mod;
    mod = SinOsc.ar(0.5,0,50,freq);
    env = EnvGen.ar(Env.linen(0.01,0.5,1.0,amp),Dust.ar(rate));
    sig = Ringz.ar(Dust.ar(rate*2,0.3),mod,0.6,env);
    sig = BLowPass.ar(sig,ffreq.lag(3),0.5);
    sig = FreeVerb.ar(sig);
    Out.ar([0,1],sig);
}).add;
)

~klank= Synth("klank",[\rate,10]);
~klank.set(\ffreq,500,\freq,1000,\rate,1000);

SynthDef("klank",{|freq=500,ffreq=500,rate=1,amp=0.5|

In de eerste regel wordt de SynthDef gedefinieerd. De naam van deze SynthDef staat tussen dubbele aanhalingstekens. "" Daarna volgt de functie waarin de synth wordt beschreven. Deze functie staat, net als een losse functie, tussen accolades {}. Het eerste onderdeel van deze functie is een lijst met argumenten die van buitenaf aangepast kunnen worden, met daarbij ook een defaultwaarde voor elke parameter. Deze lijst met argumenten begint en eindigt met een pipe: |.

var env,sig,mod;

In de tweede regel worden de lokale variabelen gedefinieerd. In tegenstelling tot globale variabelen die met een tilde beginnen worden lokale variabelen met het woordje var ervoor gedefinieerd. Deze variabelen zijn alleen binnen deze SynthDef bekend en kan je niet van buitenaf veranderen. In deze variabelen worden delen van de synthesizer opgeslagen. Na het aanmaken van de variabelen kan de definitie van de synthesizer opgebouwd worden.

mod = SinOsc.ar(0.5,0,50,freq);

In deze regel wordt de modulator voor de frequentie gemaakt. Het is een sinus die met een frequentie van 0.5 beweegt tussen -50 en +50 rond de frequentie die bovenin is gedefinieerd als freq.

env = EnvGen.ar(Env.linen(0.01,0.5,1.0,amp),Dust.ar(rate));

EnvGen is een envelope-generator. Om een envelope te genereren zijn er minimaal twee argumenten nodig. Het eerste argument is het type envelope. Dit kan een percussieve zijn (Env.perc) , een lineaire (Env.linen) of een adsr (Env.adsr). In de beschrijving van Env is de complete lijst met envelopes te vinden. Elke envelope heeft verschillende argumenten nodig. Meestal een attack- en decaytijd, amplitude en curve. Om het verloop van de envelope te kunnen zien is er de plotfunctie:

Env.perc(0.1,0.1,0.5,-4).plot

Het tweede argument van EnvGen geeft aan hoe de envelope getriggerd moet worden. In het geval hierboven gebeurt dat met een Dust-generator. Als in plaats van deze Dust-generator het woordje gate als argument wordt gebruikt kan de envelope handmatig worden gestart van buiten de SynthDef. Zie onderaan de pagina voor een voorbeeld. In datzelfde voorbeeld wordt ook een derde argument toegevoegd, een doneAction: Dit geeft aan wat er moet gebeuren als de envelope klaar is met afspelen (action when done). De meest gebruikte waarde bij een doneAction is 2, hiermee wordt de synth gestopt en verwijderd als de envelope klaar is.

sig = Ringz.ar(Dust.ar(rate*2,0.3),mod,0.6,env);
sig = BLowPass.ar(sig,ffreq.lag(3),0.5);
sig = FreeVerb.ar(sig);

In deze drie regels wordt de daadwerkelijke klank-generatie gedaan: een resonant filter met een Dust-generator als input, met als filterfrequentie de hierboven genoemde modulerende sinus. Een q van 0.6 en als mul de envelope. Daarna gaat het signaal door een lowpass filter en daarna door een reverb. Door bij elke UGen van deze code de help-file te openen krijg je te zien hoe ze precies werken.

De notatie waarbij je op elke volgende regel opnieuw sig gebruikt heeft als voordeel dat daarmee duidelijk is dat dit het signaal is dat je in een aantal stappen aan het bewerken bent. Je kunt natuurlijk voor elke stap een nieuwe variabele maken, maar dan zie je die flow niet zo mooi.

lag

Door .lag(tijd in seconden) toe te voegen achter een paramater zal de parameter bij aanpassing van buitenaf in de tijd die je aangeeft van de oude naar de nieuwe staat faden.

Out.ar([0,1],sig);

Het laatste onderdeel van de SynthDef is de output waarnaar het signaal moet worden gestuurd. Out.ar heeft twee argumenten: de bussen waar het signaal naar moet worden gestuurd. Dit kan ook een array zijn met meerdere bussen, om het signaal naar meerdere outputs te sturen. Het tweede argument is het signaal dat wordt verstuurd, in dit geval opgeslagen in de variabele sig.

}).add

De functie en de SynthDef worden afgesloten. met .add wordt de functie naar de server gestuurd en daar toegevoegd aan het lijstje met beschikbare SynthDefs om aan te roepen.



Envelopes

EnvGen & Env

Envelopes in Supercollider maak je met behulp van de EnvGen UGen. EnvGen.ar verwacht een aantal parameters waarvan er een aantal nodig zijn om in te voeren en een aantal optioneel zijn. Hieronder een uitleg voor alle parameters van EnvGen:

Voorbeeld van een van buitenaf getriggerde envelope:

(
SynthDef("envelope",{|freq=300,att=0.1,dec=0.4,gate|
    var env, sig;
    env = EnvGen.ar(Env.perc(att,dec,0.5),gate,doneAction:2);
    sig = Saw.ar(freq,env);
    sig = BLowPass.ar(sig,freq*2);
    Out.ar([0,1],sig);
}).add;
)

    ~env = Synth("envelope",[\gate,1]);


Audio opnemen en afspelen

In SuperCollider is het natuurlijk ook mogelijk om samples op te nemen, in te laden en vervolgens af te spelen.


buffers

Om audio op te slaan heb je een buffer nodig. Een buffer maak je aan door in een variabele een hoeveelheid geheugen te reserveren waar je de audio in kan opslaan.


lege buffer

Een lege buffer maak je aan met Buffer.alloc():

~buffer = Buffer.alloc(s, 5 * s.sampleRate, 2);

sample inladen

Als je een sample in een buffer wil inladen kan je dat doen met Buffer.read De buffer zal daarmee meteen de grootte van de sample krijgen.

~sample = Buffer.read(s,'/Users/gebruiker/samples/kick.wav');

audio opnemen

Als je eenmaal een lege buffer hebt gemaakt kan je daar audio in opnemen. Dit kan audio zijn vanuit een SynthDef waar je later weer bewerkingen op wil uitvoeren, of audio van de microfooningang. Hieronder een voorbeeld van hoe je geluid van je microfoon opneemt. Je kan vervolgens de UGen die gebruikt wordt om de audio op te nemen natuurlijk ook op een andere plek inzetten.

~buffer = Buffer.alloc(s, 5 * s.sampleRate, 2);

SynthDef(\record,{ | buffer|
    var sig;
    sig = SoundIn.ar([0,1],1);
    RecordBuf(sig,buf);
}).add;

~recorder = Synth(\record,[\buffer,~buffer]);

Met SoundIn.ar() kan je het geluid van de input van je geluidskaart binnenhalen in SuperCollider. Het eerste argument is welke input(s) je wil gebruiken. Als je alleen het linkerkanaal wilt gebruiken kan je daar 0 invoeren. Als je twee kanalen wil gebruiken dan gebruik je blokhaken: [0,1]. Let op: als je een stereo-buffer hebt aangemaakt zal je ook een stereo-signaal moeten gebruiken om op te nemen

Met RecordBuf.ar() kan je geluid opnemen. Het eerste argument is het signaal dat je wilt opnemen, het tweede is de buffer waarin je dit wil opnemen. Het is handig om dit in een argument van de SynthDef mee te geven, zodat je deze SynthDef ook voor andere buffers makkelijk kan gebruiken. Er zijn nog een aantal overige, optionele, opties voor RecordBuf.ar(): Een aantal interessante zijn:


Audio afspelen

Als er audio in een buffer is opgeslagen kan je deze vervolgens afpslen. De volgende SynthDef laat kort zien hoe je audio afspeelt:

SynthDef(\play,{ |buffer,speed=0.5,trig=1|
    var sig;
    sig = PlayBuf.ar(2,buffer,speed,trig,loop:1);
    Out.ar(0,sig);
}).add;

~player = Synth(\play,[\buffer,~buffer]);

De argumenten van PlayBuf.ar() zijn alsvolgt:

Natuurlijk zijn er ook andere manieren van afspelen mogelijk. Zie hiervoor onder andere de UGens: GrainBuf.ar() en TGrains.ar().



Busses

Binnen SuperCollider is het mogelijk om via busses audio van de ene plek naar de andere plek te sturen. Dus bijvoorbeeld van meerdere oscillators naar een reverb, of vanuit meerdere effect-SynthDefs naar een sample-recorder.


busnummers

Elk van de 128 audio-busses in SuperCollider heeft een nummer. Ook de in- en output van de aangesloten geluidskaart vallen onder deze 128 busses. De eerste x busses zijn voor de output van je geluidskaart, de volgende x busses zijn voor de input van je geluidskaart, de overige busses zijn vrij te gebruiken.
Stel dat je een geluidskaart hebt aangesloten met 8 in- en outputs dan ziet de bus-verdeling er als volgt uit:

Er zijn twee manieren om dit op te lossen:


Bus.audio();

Met Bus.audio() zorgt SuperCollider dat je een bus reserveert die beschikbaar is, ongeacht het aantal in- en outputs. je gebruikt dit op de volgende manier:

~reverbBus = Bus.audio(s,2);

Deze bus sla je op in een variabele zodat je er later mee aan de slag kan.

Bus als input

Je kunt met In.ar() een bus inzetten als input van een SynthDef. Zie onderstaand voorbeeld:

~reverbBus = Bus.audio(s,2);
SynthDef(\reverb,{|inBus,roomSize|
    var sig;
    sig = In.ar(inBus,2);
    sig = FreeVerb.ar(sig,1,roomSize);
    Out.ar(0,sig);
}).add;

~reverb = Synth(\reverb,[\inBus,~reverbBus]);

Bus als output

Net zoals je met Out.ar() iets naar de output van je geluidskaart kan sturen, kan je ook een signaal naar een bus sturen, zie onderstaand voorbeeld:

~reverbBus = Bus.audio(s,2);
(
SynthDef(\reverb,{|inBus,roomSize|
    var sig;
    sig = In.ar(inBus,2);
    sig = FreeVerb.ar(sig,1,roomSize);
    Out.ar(0,sig);
}).add;

SynthDef(\synth,{|outBus,freq=440,mix|
    var sig;
    sig = SinOsc.ar(freq,0,0.5);
    Out.ar(outBus,sig*mix);
    Out.ar(0,sig*(1-mix));
}).add;
)
~reverb = Synth(\reverb,[\inBus,~reverbBus]);
~synth = Synth(\synth,[\outBus,~reverbBus,\mix,0.5]);