Sintesi modulare in SuperCollider

Parte Prima
di Giorgio Zucco

 

 

 

 

 

 

 

 

 

 

 

 

Perchè un introduzione a SuperCollider? Ma sopratutto…perchè un linguaggio di programmazione per l’audio nel 2017? Nell’era dei mostruosi Vst con 50 giga di files di installazione, nell’era degli analogici di razza a basso costo (vedi Arturia, Korg, Novation), nell’era delle workstation con schermo touch dal peso inferiore ad un chilogrammo. Bene, perchè perdere ancora tempo con tecnologie esoteriche da nerd? Infatti, non ne vale affatto la pena….anzi, la lettura che seguirà, potrebbe allontanarvi in maniera inesorabile dal vostro sogno di raggiungere posizioni favorevoli nella chart di Beatport…siete avvisati!

Per quei pochi folli appassionati di programmazione (quella vera, quella testuale!), amanti del mondo open source, che non si accontentano solo di sfogliare un menu a tendina per scegliere un preset, ma vogliono davvero capire come stanno le cose, l’approccio verso un linguaggio di programmazione per l’audio potrebbe aprire nuovi e personali orizzonti.

In breve, esistono linguaggi classificati come “ad alto livello” (per distinguerli dai linguaggi a basso livello, dove il programmatore ha accesso ad una certa profondità di dettaglio, vicina al linguaggio macchina, come il linguaggio assembly ), nel nostro caso nati e pensati per il mondo audio, che permettono di affrontare problematiche musicali attraverso il collegamento (virtuale) di moduli, che chiameremo oggetti.

Immaginiamo per un attimo il concetto di sintesi modulare, quante volte ci siamo chiesti come funziona un enorme synth analogico a moduli? Ogni modulo (oggetto) ha un ingresso ed una uscita.
Cosa ci servirà per costruire un semplice sintetizzatore monofonico? Avremo bisogno di moduli elementari come un oscillatore per forma d’onda (dente di sega, triangolare, ecc) , un oscillatore a bassa frequenza (Lfo) ,un inviluppo d’ampiezza, un filtro passa basso risonante, collegati tra loro.

Nei linguaggi di programmazione per l’audio possiamo operare nello stesso modo in maniera virtuale, esistono diversi linguaggi adatti a questi scopi, citiamo i principali :

  • Csound: lo storico linguaggio sviluppato da Barry Vercoe (M.I.T), basato su una sintassi assembler style, richiede un approccio alla programmazione di tipo descrittivo, quindi più antico.
    Multipiattaforma, open source, forse il linguaggio meglio documentato (data l’età), dalle possibilità assolutamente illimitate, con i recenti sviluppi è anche ottimo per real time (perchè storicamente nasce per la modalità in differita, cioè scrivo…compilo..attendo…e ascolto…).
  • Max/Msp : software commerciale, particolarmente consigliato per il live electronics, considerato un vero e proprio linguaggio di programmazione nonostante utilizzi un approccio grafico, molto noto tra gli utenti di Ableton Live, in quanto è possibile lo sviluppo di plugin e l’interfacciamento con questa Daw (MaxForLive).
    La prima versione fu sviluppata da Miller Puckette, originariamente per controllare il processore 4x dell’Ircam.
  • Pure Data : molto simile a Max/Msp ma open source, significa un’interfaccia meno user friendly, meno documentato e aggiornato. Una validissima alternativa gratuita al costoso Max/Msp.
  • SuperCollider: sviluppato nel 1996 da James McCartney, particolarmente adatto per le applicazioni dal vivo, open source, multipiattaforma, con una sintassi moderna vicina al linguaggio Smalltalk.

 

Non ci addentreremo in inutili e risibili diatribe tra i pregi e difetti di ogni linguaggio, sono tutti importanti e validi, ognuno ha i suoi punti di forza e campi di applicazione più idonei.
Chi vi parla, ha dedicato buona parte della sua esistenza al linguaggio Csound, avvicinandosi negli ultimi anni ad un linguaggio alternativo come, appunto, SuperCollider.

Tra i software commerciali vicini a questo tipo di approccio, possiamo certamente citare il celebre Reaktor di Native Instruments. Secondo voi qual’è la differenza sostanziale tra Reaktor ed i linguaggi appena elencati?
Tralasciando le ovvie comodità di un software commerciale, il design accattivante, l’accesso a centinaia di esempi, preset di altissimo livello, già pronti per l’utilizzo nella propria daw, ecc.
Nonostante gli evidenti pregi di un sistema di questo tipo, ci scontreremo inesorabilmente con il limite che un mezzo commerciale offre, perchè è solo Native Instruments che deciderà i futuri sviluppi del proprio software, il numero di oggetti offerti e le tecniche di sintesi verso cui è indirizzato Reaktor.

Un linguaggio di sintesi, perlomeno dal punto di vista teorico, è illimitato, non nasce con presupposti stilistici predefiniti, non segue mode “sonore” del momento, non cataloga e ridicolizza il materiale sonoro in elementari categorie come Lead, Bass, Pad, Fx.
Un linguaggio di programmazione per l’audio, nell’immediato, offre l’accesso ad un numero elevatissimo di oggetti sonori precostituiti (gli opcode in Csound, le Ugens in Supercollider), e se non dovessero bastare….offre al musicista/programmatore la possibilità di creare i propri moduli per le più disparate esigenze.
Quanto entusiasmo…in realtà, come facilmente potete immaginare, la curva di apprendimento è assai più lunga della lettura di un manuale del vostro Vst e synth hardware preferito.

Essendo questo un brevissimo articolo per avvicinare i moderni producer a SuperCollider, non ci soffermeremo su dettagli storici o tecnicismi che esulano dallo scopo.
Per prima cosa procuriamoci l’ambiente Supercollider per il nostro sistema operativo, nel mio caso utilizzo Sc sia in ambiente Mac che Windows, con le recenti release le differenze sono piuttosto minime :

http://supercollider.github.io/download

Cosa stiamo scaricando? Un’Ide, ossia un’ambiente integrato con editor di testo, compilatore, insomma uno strumento completo per creare suoni (e mille altre cose) con questo linguaggio.

Una volta installato ci troveremo davanti la seguente schermata :

 

Panico…Supercollider è quindi una pagina bianca per scrivere? si…dimenticate per il momento il design accattivante di Cubase o Ableton.

Ma come funziona questo linguaggio? A cosa è associato l’editor di testo che abbiamo appena aperto? la questione è assai complessa ma proviamo a semplificarla in questo modo. Sc è basato su un sistema client/server, nello specifico :

server = scsynth client = sclang

In pratica, scsynth fornisce un engine audio che viene interpretato da sclang (client, fondamentalmente il vero e proprio linguaggio che usiamo per comunicare con il server), abbiamo quindi due programmi distinti che comunicano tra di loro per mezzo di Osc (Open Sound Control).
Se abbiamo capito bene, essendo la comunicazione di client e server basata su Osc, è quindi possibile far comunicare client e server su due computer diversi, e perchè no, su luoghi diversi tra loro…..

Bene, basta chiacchiere, tiriamo fuori dalla custodia questo nuovo e curioso strumento per sentire qualche suono.

Per prima cosa avviamo il server con la seguente istruzione (attenzione, SC è sensibile alle maiuscole e minuscole) :

s.boot;

(è anche possibile avviare il server con la combinazione di tasti : cmd + B
oppure andando a cercare questa funzione nel menu dell’editor)

Selezioniamo l’istruzione appena scritta e premiamo la seguente combinazione di tasti :

Mac : cmd + enter Windows : ctrl + enter

Che succede? Apparirà sulla destra la descrizione della nostra periferica audio e il seguente messaggio :

SC_AudioDriver: sample rate = 44100.000000, driver’s block size = 512 SuperCollider 3 server ready.
Receiving notification messages from server localhost
Shared memory server interface initialized

Osserviamo la luce verde che indica l’engine audio in esecuzione.

Bene, ora il motore audio è pronto per ricevere istruzioni su cosa fare, scriviamo adesso la seguente riga di codice, sempre facendo attenzione a maiuscole e minuscole, parentesi graffe :

{Saw.ar(220)}.play;

Selezioniamo e lanciamo, da un solo canale del vostro computer dovreste riuscire a sentire una forma d’onda a dente di sega a 220 Hz.

Come facciamo a spegnere questo suono? Con la combinazione di tasti : cmd + .
Proviamo a riscrivere il breve codice nel seguente modo :
{

Saw.ar(220)

}.play;

Selezioniamo l’intero blocco e valutiamo con la solita combinazione di tasti, come vedete funziona lo stesso. Cosa indicano le parentesi graffe? Questo è uno dei punti chiave del linguaggio, pur essendo un argomento assai lungo possiamo iniziare a considerare il concetto di funzione.
Immaginiamo che le parentesi graffe delimitino una porzione di codice (di qualsiasi lunghezza o numero di righe) che svolga un determinato compito (un suono, una serie di suoni, un calcolo

matematico, una funzione di controllo, ecc). Questa funzione potrà essere associata ad un nome, e richiamata varie volte durante una performance in SC.

Anche qui cercheremo di non entrare troppo nello specifico (si rimanda il lettore alla sterminata letteratura su supercollider che si trova online), cosa notiamo di particolare? il nostro editor testuale ha colorato di blu la parola Saw, significa che questa parola viene in un certo senso riconosciuta dall’ambiente.

Ricordate quando parlavamo di moduli, di oggetti? di sintesi modulare? Saw è un oggetto sonoro in grado di realizzare una forma d’onda a dente di sega, riceve dati in ingresso (in questo caso abbiamo espresso un valore di 220 hz per la sua frequenza), la sua uscita audio viene attivata dall’istruzione play.

Saw è uno dei tanti mattoncini, moduli, oggetti (non solo sonori) contenuti in Supercollider, vengono chiamati Ugens ossia unità generatrici, si tratta in pratica di blocchi di codice in grado di svolgere un determinato compito e con la possibilità di essere richiamato e utilizzato anche all’infinito, con la versione recente 3.8, le Ugens sono esattamente 1074!

Che dite? Esempio troppo povero, vediamo cosa succede se inseriamo altri valori di frequenza :

{Saw.ar(220,440)}.play;

Cosa succede se lanciamo l’istruzione? sentiremo un suono decisamente distorto sul canale sinistro del vostro impianto audio, di che problema si tratta? in pratica per indicare due valori diversi per il parametro frequenza, abbiamo bisogno della seguente modifica :

{Saw.ar( [ 220,880 ] )}.play;

I valori numerici, indicati tra parentesi quadre, definiscono un array, ossia una sorta di contenitore di dati dello stessa tipologia, in questo caso la frequenza.

Se lanciamo il codice noteremo qualcosa di nuovo, se il vostro sistema di ascolto è stereo (o qualche matto sta provando questo tutorial con una sola Avantone mono accesa? ) potrete notare le due frequenze diverse divise tra left e right del panorama stereo.

Procediamo con l’aggiunta di un nuovo valore numerico :

{Saw.ar( [ 220,880,1760 ] )}.play;

Cosa succede ora? Nonostante il codice indichi tre valori di frequenza, stiamo ascoltando sempre e solo i primi due, eppure SC non indica messaggi di errore o altro, di che si tratta?
Stiamo per conoscere una delle cose piu interessanti e potenti di questo linguaggio, il valore numerico di 1760 che non riusciamo ad ascoltare, in realtà sta suonando esattamente su un terzo canale. SC invia ogni frequenza generata da Saw, ad un canale audio diverso, questa modalità viene chiamata Multichannel expansion, quindi se siete sul vostro laptop in cuffia non sarete in grado di sentire il terzo suono.

Volete una prova? SC dispone di numerosi tool per visualizzare dati sonori, lanciate nuovamente il codice precedente, a cui seguirà l’istruzione :

s.scope;

 

Stethoscope visualizza la tre forme d’onda associate all’ugen Saw, è possibile modificare in alto il numero di canali da visualizzare.

E se volessimo ascoltare nel semplice panorama stereo queste tre frequenze? o definire un array di un vastissimo numero da ascoltare tranquillamente nelle nostre cuffie? abbiamo bisogno di una Ugen in grado di mixare e reindirizzare a due soli canali i dati richiesti.

{
     Mix(Saw.ar( [ 110, 220, 440, 880 ] ))

}.play;

Non è ancora efficace vero? In questo modo SC sta mixando quattro istanze di Saw, indirizzandole verso un unico canale.

Per ascoltare questa polifonia di quattro frequenze, abbiamo bisogno di utilizzare una nuova ugen che si occupa proprio di gestire l’audio in uscita. Proviamo a lanciare il seguente esempio :

{
     Out.ar([0,1] ,Mix(Saw.ar( [ 110, 220, 440, 880 ] )))

}.play;

Come funziona Out? questo modulo per prima cosa attiva i canali in uscita che ci servono, in SC vengono chiamati Bus.

array [0 , 1] (che corrisponde ad una coppia di casse oppure le nostre cuffie collegate ad un laptop, i valori 0 e 1 fanno riferimento alle prime due uscite audio del vostro dispositivo mobile o scheda audio, significa che con una scheda audio multicanale è possibile indicare il canale esatto di uscita, esempio [3, 4])

e poi prende come input il segnale (o array di segnali, come nel nostro caso) da mandare ai canali audio definiti, il suo meccanismo si potrebbe quindi semplificare nel seguente modo :

Out (canali audio, array di segnali audio da distribuire) ora è più chiara la sintassi dell’esempio precedente?

Fine Prima Parte