• Non ci sono risultati.

Synth e Group

Nel documento Introduzione a SuperCollider (pagine 152-158)

Introduzione a SuperCollider

1. direttamente In altre parole, sclang-interprete è un buon posto per l’utente da dove parlare al server al livello di quest’ultimo (da dove spedire messag-

5.6 Synth e Group

Una volta scritta la synthDef e speditala al server, quest’ultimo semplice- mente la archivia: essa è un progetto disponibile per costruire al volo un synth, uno strumento per produrre suono in tempo reale. Il synth può essere controlla- to a sua volta in tempo reale interattivamente dall’utente. Un tipico programma minimale in SC è il seguente:

1 // 1. avviare il server 2 s.boot ;

3 // tracciare i messaggi OSC

4 s.dumpOSC;

6 // 2. inviare la synthDef

7 (

8 SynthDef.new(\pulseSine , { arg out = 0, amp = 0.25, kfreq = 5 ; 9 Out.ar( 10 bus:out, 11 channelsArray: SinOsc.ar( 12 freq: kfreq*50, 13 mul: LFPulse.kr( 14 freq: kfreq, 15 width: 0.25 16 ) 17 ) 18 *amp); 19 }).add; 20 ) 22 // 3. creare un synth 23 x = Synth(\pulseSine ) ;

Il programma è costituito di tre blocchi. In primo luogo (8-19), si avvia il ser- ver. E si attende che questo abbia risposto. Quindi si valuta il blocco contenente la synthDef. E si attende che il server abbia risposto. Infine, si crea un synth (23). I tre blocchi rappresentano perciò tre momenti di interazione asincrona tra client e server. In altri termini, il client di principio non sa quanto tempo ci

metterà il server a rispondere alla sue richieste. Ovviamente, empiricamente il tempo sarà ridotto al massimo nell’ordine dei millisecondi, ma ciò non sposta il punto: si tratta di una interazione asincrona. Se si valutasse tutto il codice in colpo solo, l’interprete eseguirebbe tutte le espressioni una di fila all’altra il più velocemente possibile. Ma allora il server starebbe ancora facendo l’avvio quan- do arriverebbe la definizione della synthDef, che non sarebbe perciò ricevuta. A questo punto, alla richiesta di un synth si otterrebbe:

1 *** ERROR: SynthDef pulseSine not found 2 FAILURE IN SERVER /s_new SynthDef not found

Un messaggio di errore che appunto indica come la synthDef richiesta per costruire un synth non è disponibile sul server.

Tornando all’esempio di programma, come intuibile, c’è una classe Synth che incapsula tutti i comandi relativi a un oggetto synth sul server. Il meto- do costruttore new, omissibile al solito e qui omesso, prevede come argomento una stringa che indica la synthDef da cui il synth viene fabbricato ("pulseSi- ne"). Nel momento in cui viene creato attraverso new, il synth viene attivato (= suona). Questo comportamento è tipicamente utile, perché in realtà un synth può essere pensato come uno strumento (un sintetizzatore) ma anche come un evento sonoro (se si preferisce, una “nota”): a pensarlo così, diventa ovvio che la costruzione del synth equivale alla generazione di un evento sonoro. Nel mo- mento in cui si crea il synth, nella finestra dell’IDE dedicata al server il valore dei campi “u” (UGen attive) e “s” (synth attivi) varia di conseguenza.

Prima di entrare nel dettaglio del controllo del synth, molto generalmente, come si ferma il suono? La sequenza fondamentale (“salvavita”) che arresta ogni processo di generazione (anche iterativa) è nell’IDE “CTRL/APPLE + .” (il tasto di controllo dipende dalla piattaforma), che equivale a “Stop” nel menu Language.

Se si considera nuovamente il programma precedente e si include dumpOsc, si ottiene la seguente post window:

1 a SynthDef 2 [ "/d_recv", DATA[343], 0 ] 3 Synth(’pulseSine’ : 1000) 4 [ 9, "pulseSine", 1000, 0, 1, 0 ] 5 [ "/g_freeAll", 0 ] 6 [ "/clearSched", ] 7 [ "/g_new", 1, 0, 0 ]

Senza entrare troppo nei dettagli, le righe 1 e 2 indicano la ricezione della synthDef (in forma di risposta standard dell’interprete e di messaggio OSC), quindi (3-4) la creazione del synth, infine (5-7) la sequenza dei messaggi OSC inviata a seguito di “CTRL/APPLE + .”. Per quanto riguarda il synth, una os- servazione: il numero 1000 è un identificativo che il server assegna progressi- vamente ai synth, a partire da 1000 (i numeri precedenti sono riservati per po- tenziale uso interno). Se si crea un altro synth (senza chiamare Stop), si noterà come questo avrà identificativo 1001. In ogni caso, usualmente, si fa riferimento a un synth assegnando un oggetto SC di classe Synth a una variabile e non attra- verso l’ID. È un esempio di utilità delle classi sul lato linguaggio: permettono all’utente di non occuparsi di questi dettagli. Invece, 5-7 indicano che a seguito del comando di Stop al server è stato richiesto di eliminare tutti i synth. Qui g fa riferimento ad un group che è sempre presente (si veda dopo).

Il prossimo esempio, abbondantemente commentato, assume che la synth- Def pulseSine sia disponibile sul server. La riga 4 dimostra come si può istan- ziare un synth impostando subito i valori di alcuni argomenti della UGen-gra- ph function (che altrimenti riceverebbero il valore predefinito dalla synthDef): si utilizza un array che alterna nome dell’argomento e valore. Le righe 5-6 indi- cano come si può controllare l’esecuzione/pausa di un synth attraverso il me- todo run. Le righe 8-9 sono due esempi di controllo degli argomenti definiti nella UGen-graph function attraverso il metodo set che può ricevere liste ar- gomento/valore per impostare il parametro desiderato. La riga 11 indica come eliminare (tecnicamente, “deallocare”) un synth attraverso free. Infine, le ri- ghe 14-15 dimostrano che in alcuni casi è opportuno creare un synth senza che questo suoni con newPaused, in modo da mandarlo in esecuzione in un secondo momento (riga 15).

1 // Argomenti e controllo del synth

3 // controllo interattivo, valutare riga per riga (= performance) 4 x = Synth(\pulseSine , [\kfreq , 14, \amp , 0.7]) ;

5 x.run(false) ; // = premere il pulsante pausa sul synth 6 x.run(true) ; // = x.run, true e’ il valore default

8 x.set(\kfreq , 15, \amp , 0.125) ; // controllo degli argomenti 9 x.set(\kfreq , 20) ; // controllo degli argomenti, uno solo 11 x.free ; // deallocazione: eliminazione del synth

13 // da capo ma iniziando con un synth in pausa

14 x = Synth.newPaused(\pulseSine , [\kfreq , 5, \amp , 0.5]) ; 15 x.run ;

Il codice precedente è una sessione interattiva con l’interprete in cui si con- trolla in tempo reale il server. È un esempio di live coding, per quanto minimale: di programmazione live. Di fatto, con SC si fa in qualche modo sempre live co- ding.

I synth possono anche essere coordinati in un gruppo: un gruppo (group) è semplicemente una lista di synth a cui è possibili inviare lo stesso messaggio. Group e synth hanno sostanzialmente la stessa interfaccia, cioè i metodi di base dei synth (che abbiamo già discusso) valgono anche per i group. Si consideri l’esempio seguente:

1 SynthDef(\sine , {arg freq = 100; Out.ar(0, SinOsc.ar(freq))}).add ; 2 SynthDef(\pulse , {arg freq = 100; Out.ar(1, Pulse.ar(freq))}).add ;

4 s.scope ;

5 g = Group.new ;

6 x = Synth(\sine, [\freq , 200], target:g) ; 7 y = Synth(\pulse , [\freq, 1000], target:g) ; 9 g.set(\freq , 400) ;

10 x.set(\freq , 1000) ; 11 g.free ;

un oscillatore sinusoidale e uno a onda quadra. Entrambe espongono all’ester- no l’argomento freq che intuibilmente controlla la frequenza nei due oscillatori. I due oscillatori instradano il segnale rispettivamente verso il canale sinistro e quello destro attraverso l’argomento di Out, che specifica il bus (0 vs. 1). At- traverso s.scope è più chiaramente osservabile cosa succede (4). Viene quindi creato un gruppo attraverso la classe Group. Segue la creazione di due synth (righe 6-7), del tutto usuale se si eccettua la specificazione dell’argomento tar- get, che specifica l’eventuale assegnazione del synth a un gruppo, qui il gruppo g. A questo punto diventa possibile controllare l’intero gruppo. La riga 9 invia

(si noti la sintassi identica a quella per synth10) a tutti i synth del gruppo g il

messaggio che imposta freq= 400. Ad esso, rispondono tutti i synth che lo

prevedono (entrambi nel caso in questione). L’appartenenza a un gruppo non impedisce un controllo dei singoli synth (10). Si noti che è possibile deallocare in un unico messaggio l’intero gruppo, ovvero tutti i synth che ne fanno parte (11). I gruppi sono utili per avere forte modularità (i synth) ma allo stesso tempo coordinamento: si pensi a scalare il volume di molti synth insieme. Tra l’altro, un gruppo può a sua volta contenere altri gruppi. Quando si crea un synth sen- za specificare il gruppo, questo viene aggregato ad un gruppo di default.

5.7 Un theremin

Un theremin è uno strumento elettronico inventato dal russo Léon There- min in cui due antenne, senza essere toccate ma in funzione della prossimità delle mani dell’esecutore, controllano l’ampiezza e la frequenza di un oscilla- tore. Si consideri allora il seguente esempio (commentato per ribadire un’altra volta alcuni punti sulle synthDef):

10 Infatti, sia Synth che Group sono sottoclassi di Node, e tra l’altro l’help file di

1 SynthDef.new(\theremin , // nome simbolico 2 // segue il grafo delle ugen

3 {

4 // c’e’ sempre Out per uscire 5 Out.ar(

6 0, // indice del bus

7 // segue segnale generato dall’oscillatore digitale 8 SinOsc.ar( // la UGen oscillatore

9 freq: MouseX.kr(200, 5000, 1), // argomento frequenza 10 mul: MouseY.kr(0,1))) // moltiplicatore dell’ampiezza 11 }).add ;

La struttura è molto semplice: un generatore di sinusoidi è controllato in ampiezza e in frequenza da due UGen peculiari, MouseX e MouseY. Si tratta di due “pseudo-UGen”, infatti intercettano il mouse (che è a lato client, evidente- mente) per generare segnali di controllo. Sono molto utili per verificare rapida- mente cosa succede variando i valori di certi argomenti. Le due UGen, riferite alla posizione del mouse sui due assi, permettono di mappare l’escursione sui due assi tra minval e maxval, e definiscono anche la curva che connetterà i due

estremi (warp). Nella frequenza (MouseX) l’escursione è[200, 5000], poiché si fa

riferimento agli Hz, nell’ampiezza (MouseY) invece è[0, 1] (ampiezza normaliz-

zata). La curva è di tipo lineare (0) per l’ampiezza e esponenziale per le fre-

quenze (1), in modo da simulare la percezione delle altezze11. In questo modo,

attraverso il mouse, si simula il funzionamento di base di un theremin. Il grafo di UGen è in Figura 5.8. Il grafo permette di discutere un punto. Come si è detto, le UGen condividono gli argomenti mul e add. Internamente, in realtà esiste una UGen specializzata, MulAdd, che opera molto efficientemente. La UGen non è utilizzata esplicitamente dall’utente, ma c’è, e il grafo, essen- do generato ispezionando la struttura della synthDef, la rileva e la disegna (il blocco *).

11 L’argomento lag, di solito non impostato, è un ritardo che evita una eccessiva

MouseX minval: 200 maxval: 5000 warp: 1 lag: 0.2

SinOsc freq: phase: 0

* a: b:

MouseY : 0 : 1 : 0 : 0.2

Out bus: 0 channelsArray:

Fig. 5.8 UGen-graph di un theremin.

Se si vuole vedere cosa succede in termini di forma d’onda e spettro si usino s.scope e s.freqscope.

Nel documento Introduzione a SuperCollider (pagine 152-158)