Pit Stop 5

Frequenza

Client side

s.boot;
s.scope(1);
s.meter(1,1);

//====================================================================

// Conversioni

60.midicps;   // da midinote a cicli per secondo
440.cpsmidi;  // da cicli per secondo a midinote
12.midiratio; // da intervallo midi a fattore di moltiplicazione in Hz
2.ratiomidi;  // da fattore di moltiplicazione in Hz a intervallo midi
4.octcps;     // da ottave decimali a cicli per secondo (4 = do centrale)
440.cpsoct;   // da cicli per secondo a ottave decimali

//====================================================================

// Strumento

(
var w,a,b,c,d,e,f,inizio=0;                    // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\ksig,
              {arg freq=400,amp=1,smt=0.02;
               var sig, port;
                   port = freq.lag(smt); // abbreviazione sintattica
                   sig  = SinOsc.ar(port,0,amp.lag(0.02));
               Out.ar(0,sig)
               }
          ).add;

{~synth = Synth(\ksig)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("GUI", 280@50); // Crea una finestra di 200x30 pixels
w.alwaysOnTop;                 // La posiziona sempre sopra tutte le altre finestre
w.front;                       // Visualizza la finestra
w.onClose_(                    // Esegue la funzione quando si chiude la finestra
           {~synth.free;~ksynth.free;w.free;a.free;
            b.free;c.free;d.free;e.free;f.free}
           ); 
                        
a = StaticText.new(w,                      // Crea un testo statico nella finestra
                     Rect(10, 7, 280, 15)) // Le coordinate del testo 
                                           // Il contenuto del testo  
 .string_(" freq        dur         def        curva    smooth");                     

b = NumberBox.new(w,                       // Crea un number box nella finestra
                    Rect(5, 25, 50, 20))   // Le coordinate del number box
 .value_(400);                             // Il primo valore visualizzato 

c = NumberBox.new(w,Rect(60, 25, 50, 20)).value_(0);     
d = NumberBox.new(w,Rect(115, 25, 50, 20)).value_(0.01); 
e = NumberBox.new(w,Rect(170, 25, 50, 20)).value_(1); 
f = NumberBox.new(w,Rect(225, 25, 50, 20)).value_(0.02); 

// ------------------------------ Operazioni di basso livello

~ksynth = {arg freq=100,dur=1,defId=0.01,curva=1,smt=0.02;          
           var range,nPassi,aPasso,dPasso;
               range  = abs(inizio-freq);
               nPassi = 1/defId;
               aPasso = Array.interpolation(nPassi,0,1)  // eventuale gliss
                             .pow(curva)                 // curva gliss
                             .normalize(inizio,freq);    // riscala   
               dPasso = dur/nPassi;                      // td singolo passo

Routine.new({                                            // Sequencing
             aPasso.do({arg item;
                        ~synth.set(\freq,item,\smt,smt); // al Synth
                        {b.value_(item);                 // alla GUI
                         c.value_(dur);
                         d.value_(defId);                 
                         e.value_(curva);
                         f.value_(smt)}.defer(0);        // {}.defer(0) = AppClock
                         inizio = item;                  // aggiorna l'inizio
                        dPasso.wait  
                        })
             }).play;
           };

b.action_({arg val; ~synth.set(\freq,val.value)});       // Interazione con GUI (solo freq)

MIDIIn.connectAll;                                       // Interazione MIDI
MIDIdef.noteOn(\noteOn,{arg vel,note;
                        ~synth.set(\freq,note.midicps,   // frequenze in Hz
                                   \amp,vel/127);        // ampiezza tra 0 e 1
                        {b.value_(note.midicps)}.defer(0)// alla GUI
               });
MIDIdef.noteOff(\noteOff,{~synth.set(\amp,0)});          // note off

OSCdef.new(\notam, {arg msg;                             // Interazione OSC
                    ~synth.set(\freq,msg[1].midicps,     // frequenze in Hz
                               \amp,msg[2]/127);         // ampiezza tra 0 e 1
                    {b.value_(msg[1].midicps)}.defer(0)},// alla GUI
                    '/nota', NetAddr.new("127.0.0.1",58027));
)

//====================================================================

// Controlli

// ------------------------------ Singolo valore

(
~ksynth.value(                        // alla funzione (.value() al posto di .set())
              freq:rrand(200,2000),   // frequenza in Hz
              dur:rand(2.0),          // durata eventuale interpolazione
              defId: rrand(0.01,0.3), // definizione scalini tra 0 e 1 (0.01=glissato)
              curva: rrand(0.01,4),   // 0/1 = logaritmico, 1 = lineare, >1 = esponenziale
              smt:0.02                // smoothing del segnale (indipendente dal gliss)
              );
)

// ------------------------------ Sequencing
// Deterministico
(
r = Routine.new({var note;
                     note = [[500, 0, 2, 0.01, 1],  // [freq,port,dur,def,curva] 
                             [730, 0, 1, 0.01, 1],  // oppure qualsiasi altra suddivisione in Array
                             [900, 2, 3, 0.01, 1],
                             [470, 1, 4, 0.1,  0.2],
                             [900, 3, 5, 0.2,  3]];
                     note.do({arg item, id;
                              ~ksynth.value(item[0],item[1],item[3],item[4]);
                     item[2].wait
                             })
                 }).reset.play;
)

r.stop;

// Non deterministico

(
r = Routine.new({var dur;
                     dur = rrand(0.05,2);
                  inf.do({
                           ~ksynth.value(rrand(200,2000),  // freq
                                         dur*rand(1.0),    // port
                                         rrand(0.01,0.3),  // defId
                                         rrand(0.01,4));   // curva
                           dur.wait
	                      })
                 }).reset.play;
)

r.stop;

// ------------------------------ Interazione MIDI

// Collegare una tastiera e schiacciare i tasti... (noteon e noteoff)

// ------------------------------ Interazione OSC

// • Monitorare i messaggi OSC:

OSCFunc.trace(true);  
OSCFunc.trace(false); 

// • Copiare il numero della porta in ingresso ('recvPort:57120') come output
//   del device che utilizziamo.
// • Inviare dei messaggi OSC dal device e copiare il numero di address 
//   ('address: a NetAddr("127.0.0.1", 58027)' e sostituirlo all'interno di
//   'OSCdef'
// • Eseguire il codice dello strumento e della GUI ed inviare messaggi dal device

Server side

Il controllo delle frequenze tramite segnali verrà affrontato nel Pit Stop n (METTI NUMERO E LINK), in questo ricordiamo solo la possibile interazione con mouse e tastiera del computer:

// ------------------------------ Interazione Mouse

(
SynthDef(\mouse,
                {var freq,amp,trig,sig;
                     freq = MouseX.kr(200,1000,0,0.2); // frequenza tra 200 e 1000Hz lineare
                     amp  = MouseY.kr(0.01,1.1,1,0.2); // ampiezza tra 0 e 1 esponenziale
                     trig = MouseButton.kr(0,1,0.2);   // noteon/off
                     sig  = SinOsc.ar(freq,0,amp);
		Out.ar(0,sig*trig)
}).add;

{a = Synth(\mouse)}.defer(0.1)
)

// ------------------------------ Interazione Tastiera

(
w = Window.new("key");                                 // Monitorare i diversi valori dei tasti
w.view.keyDownAction_({arg view,char,modifiers,unicode,keycode,key;
                      [char,keycode].postln
                      });
w.front;
)

(
SynthDef(\tasti,
                {var freq,amp,trig,sig;
                     freq = MouseX.kr(200,1000,0,0.2);
                     amp  = MouseY.kr(0.01,1.1,1,0.2);
                     trig = KeyState.kr(35,0,1,0.2);   // noteon/off se schiacciamo 'p'
                     sig  = SinOsc.ar(freq,0,amp);
		Out.ar(0,sig*trig)
}).add;

{a = Synth(\tasti)}.defer(0.1)
)

N.B. Tutti i parametri (argomenti) dei segnali di controllo possono a loro volta essere controllati attraverso le tecniche appena esposte sia Client (singoli valori o sequencing) che Server side (modulazioni).

Ampiezza

Client side

s.boot;
s.scope(1);
s.meter(1,1);

//====================================================================

// Conversioni

0.5.ampdb;   // da ampiezza lineare a db
-6.02.dbamp; // da db ad ampiezza lineare
0.5.cubed;   // ampiezza quartica

//====================================================================

// Strumento

(
var w,a,b,c,inizio=0;                   // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\ksig,
              {arg freq=400,amp=0,smooth=0.02;
               var sig, kamp;
                   kamp = amp.lag(smooth); 
                   sig  = SinOsc.ar(freq,0,kamp);
               Out.ar(0,sig)
               }
          ).add;

{~synth = Synth(\ksig)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("GUI", 60@228); 
w.alwaysOnTop;                 
w.front;                       
w.onClose_({~synth.free;~ksynth.free;w.free;a.free;b.free;c.free}); 
                        
a = StaticText.new(w, Rect(12, 205, 200, 15)).string_("amp");      
b = NumberBox.new(w,  Rect(5, 185, 50, 20)).value_(0.0);                        
c = Slider.new(w,     Rect(5, 5, 50, 180)).value_(0.0);    

// ------------------------------ Operazioni di basso livello

~ksynth = {arg amp=1,dur=1,curva=4,defId=0.01,smt=0.02;          
           var range,nPassi,aPasso,dPasso;
               range  = abs(inizio-amp);
               nPassi = 1/defId;
               aPasso = Array.interpolation(nPassi,0,1)
                             .pow(curva)                // cresc. e dim. quartici
                             .normalize(inizio,amp);       
               dPasso = dur/nPassi;

Routine.new({                                                
             aPasso.do({arg item;
                        ~synth.set(\amp,item,\smt,smt); // al Synth  
                        {b.value_(item);                // ala GUI 
                         c.value_(item)}.defer(0);           
                         inizio = item;                      
                        dPasso.wait  
                        })
             }).play;
};

c.action_({arg val;                       // Interazione con GUI
           ~synth.set(\amp, val.value);   // al Synth
           {b.value_(val.value)}.defer(0) // al NumberBox
	       });         

MIDIIn.connectAll;                               // Interazione MIDI                           
MIDIdef.cc(\amp,{arg vel;
                 ~synth.set(\amp,vel/127);       // al Synth 
                 {b.value_(vel/127);             // allo Slider
                  c.value_(vel/127)}.defer(0) }, // al NumberBox
                 0);                             // cc number


OSCdef.new(\notam, {arg msg;                             // Interazione OSC
                    ~synth.set(\amp,msg[1]/127);                           // al Synth 
                    {b.value_(msg[1]/127);c.value_(msg[1]/127)}.defer(0)}, // alla GUI
                    '/gain', NetAddr.new("127.0.0.1",58027));

)

//====================================================================

// Controlli

// ------------------------------ Singolo valore

(
~ksynth.value(                        // alla funzione (.value() al posto di .set())
              amp:rand(1.0),          // ampiezza lineare (0/1)
              dur:rand(2.0),          // durata eventuale interpolazione
              curva: rrand(0.01,4),   // 0/1 = logaritmico, 1 = lineare, >1 = esponenziale
              );
)

// ------------------------------ Sequencing
// Deterministico
(
r = Routine.new({var note;
                     note = [[0.0, 1,  1],  // [amp,dur,curva] 
                             [0.7, 0.5,1],  // oppure qualsiasi altra suddivisione in Array
                             [0.2, 2,  0.01],
                             [1.0, 0.7,0.2],
                             [0.2, 3,  3]];
                     note.do({arg item, id;
                              ~ksynth.value(item[0],item[1],item[2]);
                     item[1].wait
                             })
                 }).reset.play;
)

r.stop;

// Non deterministico

(
r = Routine.new({var dur;
                     dur = rrand(0.05,2);
                  inf.do({
                          ~ksynth.value(rand(1.0),      // amp
                                        dur,            // dur
                                        rrand(0.01,4)); // curva
                          dur.wait
	                      })
                 }).reset.play;
)

r.stop;

// ------------------------------ Interazione MIDI

// Collegare un controller MIDI e muovere uno Slider assegnato al ccn 0

// ------------------------------ Interazione OSC

// • Monitorare i messaggi OSC:

OSCFunc.trace(true);  
OSCFunc.trace(false); 

// • Copiare il numero della porta in ingresso ('recvPort:57120') come output
//   del device che utilizziamo.
// • Inviare dei messaggi OSC dal device e copiare il numero di address 
//   ('address: a NetAddr("127.0.0.1", 58027)' e sostituirlo all'interno di
//   'OSCdef'
// • Eseguire il codice dello strumento e della GUI ed inviare messaggi dal device

Server side

Rampe

//====================================================================

// Lineari

// ------------------------------ doneAction:0

(
{[SinOsc.ar,
  Line.ar(0,1,1,doneAction:0),
  SinOsc.ar*Line.ar(0,1,1,doneAction:0)
]}.plot(2);
)

{SinOsc.ar*Line.ar(0,1,1,doneAction:0).scope}.scope

// ------------------------------ doneAction:2

(
{[SinOsc.ar,
  Line.ar(0,1,1,doneAction:2),
  SinOsc.ar*Line.ar(0,1,1,doneAction:2)
]}.plot(2);
)

{SinOsc.ar*Line.ar(0,1,1,doneAction:2).scope}.scope

//====================================================================

// Esponenziali

(
{[SinOsc.ar,
  XLine.ar(0.001,1,1,doneAction:0),
  SinOsc.ar*XLine.ar(0.001,1,1,doneAction:0),
  XLine.ar(1,0.001,1,doneAction:0),
  SinOsc.ar*XLine.ar(1,0.001,1,doneAction:0)
]}.plot(2);
)

Segnali impulsivi

// ------------------------------ 1 sample

// Regolari

(
SynthDef(\pulse,
              {arg delta = 10, freq = 1200;
               var amp,sig;
                   amp   = Impulse.kr(delta);
                   sig   = SinOsc.ar(freq);
                Out.ar(0,sig*amp)
                }
          ).add;

{a = Synth(\pulse)}.defer(0.1)
)

a.set(\delta,rrand(1,10),\freq,rrand(200,2000));
a.free;

// Irregolari

(
SynthDef(\pulse,
              {arg delta = 10, freq = 1200;
               var amp,sig;
                   amp  = Dust.kr(delta);
                   sig  = SinOsc.ar(freq);
                Out.ar(0,sig*amp)
                }
          ).add;

{a = Synth(\pulse)}.defer(0.1)
)

a.free;

// ------------------------------ con decadimento

(
SynthDef(\pulse,
              {arg delta = 10, freq = 1200, decay = 0.2;
               var amp,sig;
                   amp  = Decay.kr(Impulse.kr(delta),decay);
                   sig  = SinOsc.ar(freq);
                Out.ar(0,sig*amp)
                }
          ).add;

{a = Synth(\pulse)}.defer(0.1)
)

a.set(\delta,rrand(1,10),\freq,rrand(200,2000),\decay,rrand(0.02,0.5));
a.free;

// ------------------------------ con attacco e decadimento

(
SynthDef(\pulse,
              {arg delta = 10, freq = 1200, attack=0.2, decay = 0.8;
               var amp,sig;
                   amp  = Decay2.kr(Impulse.kr(delta),
                                    delta.reciprocal*attack,
                                    delta.reciprocal*decay);
                   sig  = SinOsc.ar(freq);
                Out.ar(0,sig*amp)
                }
          ).add;

{a = Synth(\pulse)}.defer(0.1)
)

(
var atk,dec;
    atk = rrand(0.01,1).postln;
    dec = 1-atk;
    dec.postln;
a.set(\delta,rrand(1,10),\freq,rrand(200,2000),\attack,atk,\decay,dec)
)

a.free;

Segnali discreti

// ------------------------------ inviluppo trapezoidale senza smoothing

(
SynthDef(\envi,
              {arg tfreq=10, dur=1;
               var ksig,trig,bpf,env,sig;
                   ksig = LFNoise0.kr(tfreq);
                   trig = Trig.kr(ksig,1/tfreq*dur);
                   sig = SinOsc.ar(1970);
                Out.ar(0,sig*trig)
                }
          ).add;

{a = Synth(\envi)}.defer(0.1)
)

a.set(\amp,rand(1.0),\tfreq, rrand(2,10),\dur,rrand(0.01,1)); // esegui più volte
a.free;

// ------------------------------ inviluppo trapezoidale con smoothing

(
SynthDef(\envi,
              {arg tfreq=10, dur=1;
               var ksig,trig,bpf,env,sig;
                   ksig = LFNoise0.kr(tfreq);
                   trig = Trig.kr(ksig,1/tfreq*dur).lag(0.02);
                   sig = SinOsc.ar(1970);
                Out.ar(0,sig*trig)
                }
          ).add;

{a = Synth(\envi)}.defer(0.1)
)

a.set(\amp,rand(1.0),\tfreq, rrand(2,10),\dur,rrand(0.01,1)); // esegui più volte
a.free;

// N.B. La regolarità o irregolarità temporale dipende dall'andamento del segnale 'ksig'

Segnali continui

//====================================================================

// Conversione Bipolari (+/- 1) --> Unipolari (0/1)

//====================================================================

// Operazioni matematiche

(
{[SinOsc.ar,                   // bipolare +/- 1
  SinOsc.ar * 0.5,             // bipolare +/- 0.5
  SinOsc.ar * 0.5 + 0.5,       // unipolare tra 0 e 1	
  SinOsc.ar(mul: 0.5, add:0.5) // Utilizzando gli argomenti 'mul' e 'add' 
  ]
}.plot(minval:-1,maxval:1) 
)

// Metodo

(
{[SinOsc.ar.unipolar,   // sinusoide
  LFSaw.ar.unipolar,    // dente di sega
  LFTri.ar.unipolar,    // triangolare
  LFPulse.ar.unipolar,  // quadra
  LFNoise0.ar.unipolar  // random
  ]
}.plot(minval:-1,maxval:1) 
)

//====================================================================

// Visualizza

(
{var sig,rand;
     sig = SinOsc.ar(400);
 [sig,
  SinOsc.ar(5,-0.5*pi).unipolar,	       // Correzione di fase iniziale
  sig * SinOsc.ar(5,-0.5*pi).unipolar,
  LFSaw.ar(5,1) * 0.5 + 0.5,
  sig * (LFSaw.ar(5,1) * 0.5 + 0.5),
  LFPulse.ar(10).unipolar,
  sig * LFPulse.ar(10).unipolar,
  rand = LFNoise0.ar(5) * 0.5 + 0.5,
  sig * rand
  ]
}.plot(0.5,minval:-1,maxval:1)
)

// Audio

a = {SinOsc.ar(400, mul:SinOsc.kr(5,-0.5*pi).unipolar.scope).scope}.play; // eseguire una riga alla volta
a.free; 
a = {SinOsc.ar(420).scope * (LFSaw.kr(5,1) * 0.5 + 0.5).scope}.play;
a.free; 
a = {LFTri.ar(440, mul: LFPulse.kr(10).unipolar.scope).scope}.play;
a.free; 
a = {SinOsc.ar(1500).scope * (LFNoise0.kr(5) * 0.5 + 0.5).scope}.play;

// Smoothing per segnali discontinui
// Se il tempo di smoothing è troppo elevato si può modificare la forma d'onda:

(
{
 [LFSaw.kr(5).unipolar,
  LFSaw.ar(5).unipolar.lag(0.001),//  1 ms
  LFSaw.ar(5).unipolar.lag(0.01), // 10 ms 
  LFSaw.ar(5).unipolar.lag(0.1),  // 100 ms 
  LFSaw.ar(5).unipolar.lag(0.5),  // 500 ms
  LFSaw.ar(5).unipolar.lag(1)]    //   1 s
}.plot(1)
)

(
SynthDef(\ksig,
              {arg smt=0.1;
               var amp, sig;
                   amp = LFSaw.kr(3).unipolar.lag(smt); // smoothing
                   sig = SinOsc.ar(100);
               Out.ar(0,sig*amp)
               }
          ).add;

{a = Synth(\ksig)}.defer(0.1);
)

a.set(\smt,0.001);
a.set(\smt,0.01);
a.set(\smt,0.1);
a.set(\smt,0.5);
a.set(\smt,1);

// Segnali randomici e smoothing

(
{
 [LFNoise0.kr(15).unipolar, // senza interpolazione
  LFNoise1.kr(15).unipolar, // interpolazione lineare
  LFNoise2.kr(15).unipolar, // interpolazione cubica
  LFClipNoise.kr(15).unipolar]
}.plot(1)
)

N.B. Tutti i parametri (argomenti) dei segnali di controllo possono a loro volta essere controllati attraverso le tecniche appena esposte sia Client (singoli valori o sequencing) che Server side (modulazioni).

Inviluppi

BPF e segnali di controllo

s,boot;
s.scope(1);
s.meter(1,1);

//====================================================================

// ------------------------------ BPF

// Env.new()

(
Env.new([0.0,0.5,0.0], // livelli
        [   1,  1],    // tempi delta
        \lin,          // curva
).test.plot(minval: 0, maxval: 1)
)

// ------------------------------ Tipi di curva

(
[Env([0,0.5,0.1,0],          [0.1,0.2,1], \step), // Scalini
 Env([0,0.5,0.1,0],          [0.1,0.2,1], \lin),  // Curva lineare
 Env([0.0001,0.5,0.1,0.0001],[0.1,0.2,1], \exp),  // Curva esponenziale
 Env([0,0.5,0.1,0],          [0.1,0.2,1], \sin),  // Curva sinusoidale
 Env([0,0.5,0.1,0],          [0.1,0.2,1], \wel),  // Curva welch
 Env([0,0.5,0.1,0],          [0.1,0.2,1], \sqr),  // Curva radice 
 Env([0,0.5,0.1,0],          [0.1,0.2,1], \cub),  // Curva quartica 
 Env([0,0.5,0.1,0],          [0.1,0.2,1], -0.8),  // Curva logaritmica_n 0.0 = lineare
 Env([0,0.5,0.1,0],          [0.1,0.2,1],  0.8)   // Curva esponenziale_n
 ].plot  
);

Env([0,0.5,0.1,0], [0.1,0.2,1], \cub).test  // Suona l'inviluppo come test 

//====================================================================

// ------------------------------ Visualizza 

// .plot()

(
Env([0,1,0.1,0],[0.1,0.2,1], \wel).plot(
         50,      // size o numero di punti visualizzati (non necessariamente uguali a quelli del BPF)
         800@200, // bounds (dimensioni grafiche in pixels)
         0,1)     // minval e maxval.
)

// EnvelopeView.new()

(
w = Window.new("EnvelopeView", 500@400); // Crea una finestra di 500x400 pixels
w.alwaysOnTop;                           // La posiziona sempre sopra tutte le altre finestre
w.front;                                 // Visualizza la finestra
w.onClose_({e.free;w.free;r.stop;});     // Libera le variabili 'e, w, r' quando si chiude la finestra

e = EnvelopeView.new(w, Rect(10,10,480,380)) // Crea un EnvelopeWiev all'interno della finestra
 .resize_(5);                                // Permette il resize con il mouse della finestra

~myEnv = Env.new([0,1,0.8,0],[0.1,0.6,0.7]); // inviluppo
~myEnv.plot(minval:0,maxval:1);              // Plotter

// Riscala e visualizza: EnvelopeView accetta un Array di onset e uno di livelli:

e.valueAction_([[0] ++                       // aggiunge [0] all'Array
                       ~myEnv.times          // Array dei tempi delta
                             .normalizeSum   // riscala linearmente in valori compresi tra 0 e 1
                             .integrate,     // trasforma onsets in tempi delta
                       ~myEnv.levels]);      // Array dei livelli

// Riscala e ricrea l'inviluppo

e.action_({arg i;
           ~deltaT  = i.value[0]                 // recupera l'Array degli onsets tra 0 e 1
                       .differentiate            // da onset a tempi delta tra 0 e 1
                       .drop(1)                  // elimina lo 0 iniziale
                      * ~myEnv.duration;         // riscala i valori alla durata originale
           ~livelli = i.value[1];                // recupera l'Array dei livelli
           ~myEnv   = Env.new(~livelli,~deltaT); // Crea un nuovo inviluppo
	       [~livelli,~deltaT].postln
           });

// Suona in loop (modificare sull'interfaccia la posizione dei nodi).

r = Routine({
             inf.do({
                     {SinOsc.ar*EnvGen.ar(~myEnv,doneAction:2)}.play;
                     ~myEnv.duration.wait
	                 })
             }).reset.play
)

r.stop;

// Aspetto dell'interfaccia

(
e.drawLines_(true);            // Visualizza le linee tra i nodi
e.drawRects_(true);            // Visualizza i punti dei nodi
e.thumbSize_(20);              // Cambia il size dei nodi
e.strokeColor_(Color.blue);    // Colore delle connessioni
e.fillColor_(Color.green);     // Colore dei nodi
e.selectionColor_(Color.red);  // Colore della selezione
e.gridColor_(Color.black);     // Colore della cornice
e.resize_(5);                  // Permette il resize della finestra
e.step_(0.01);                 // Risoluzione in decimali
)

//====================================================================

// ------------------------------ EnvGen.kr()

(
SynthDef(\envi,
              {arg freq, gate=0;
               var sig,bpf,env;
                   sig = SinOsc.ar(freq);
                   bpf = Env.new([0,0.5,0.1,0],[0.01,0.2,1],\cub); 
                   env = EnvGen.kr(bpf,            // un istanza di Env
                                   gate,           // trigger (vedi sotto)
                                   doneAction:2);  // 2 = terminato l'inviluppo distrugge l'istanza di Synth      
               Out.ar(0,sig*env)
               }
          ).add
)

Synth(\envi,[\freq,rrand(200,2000), \gate,1]);     // Eseguire più volte

// ------------------------------ Abbreviazione

(
SynthDef(\envi,
              {arg freq=890, gate=0;       
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,0.3],\cub) // solo Env
                            .kr(doneAction:0, gate:gate);         // parametri principali
               Out.ar(0,sig*env)
               }
          ).add
)

Synth(\envi,[\freq,rrand(200,2000), \gate,1]);     // Eseguire più volte

Trigger e inviluppi

// Due tipi di inviluppi:

// ------------------------------ Senza fase di sostegno

// • l'argomento 'gate' deve cominciare con 't_qualchecosa'. In questo modo passa
//   sia un messaggio di gate:1 che di gate:0
// • basta inviare un valore > 1 per far partire l'inviluppo fino alla fine

(
SynthDef(\envi,
              {arg freq, t_gate=0;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,3],\cub)
                            .kr(gate:t_gate,doneAction:2); // doneAction:2 = l'istanza di Synth
                                                           // si distrugge alla fine dell'inviluppo      
               Out.ar(0,sig*env)
                }
          ).add
)

Synth(\envi,[\freq,rrand(200,2000), \t_gate,1]); // Eseguire più volte

// ------------------------------ Con fase di sostegno

// • l'argomento 'gate' può essere chiamato come vogliamo.
// • un messaggio di 'gate:1' fa partire l'inviluppo fino al nodo di sostegno (note on)
// • deve seguire un messaggio di 'gate:0' che fa proseguire l'inviluppo fino alla fine
//   (note off o release)
// • per inviare i messaggi precedenti dobbiamo assegnare ogni istanza di Synth ad una
//   variabile, oppure includerli in un Array

(
SynthDef(\envi,
              {arg freq, gate=0;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,3],\cub, 2) // aggiunto un nuovo argomento (nodo di release)
                            .kr(gate:gate,doneAction:0);           // doneAction:0 = l'istanza di Synth
                                                                   // non si distrugge alla fine dell'inviluppo
               Out.ar(0,sig*env)
                }
          ).add;

{a = Synth(\envi)}.defer(0.01);        // creo una sola istanza
)

a.set(\freq,rrand(200,2000), \gate,1); // note on
a.set(\gate,0);                        // note off

Inviluppi senza sostegno

s.boot;
s.scope(1);
s.meter(1,1);

// • Anche gli Inviluppi senza sostegno hanno bisogno di un messaggio di
//   'gate:0' prima di essere triggerati nuovamente. Se utilizziamo la sintassi
//   't_qualchecosa' nello specificare il nome dell'argomento dedicato alla gate
//   il messaggio di 'gate:0' è generato automaticamente.
// • Se un trigger arriva prima della fine non si tronca ma riparte dal valore in
//   cui si trova.
// • Possiamo specificare i tempi come proporzioni e poi riscalarli in una durata
//   attraverso il terzo argomento di 'Env.kr()'

// ------------------------------ Env.new()

(
SynthDef(\envi,
              {arg freq=890, dur=1, t_gate=0;    // t_gate al posto di gate
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.3,0],    // livelli
                                 [0.01,0.2,0.3], // tempi delta
                                 \cub)           // curva
                            .kr(0,t_gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\t_gate,1,\dur,rrand(0.05,5));

// ------------------------------ Env.pairs()

(
SynthDef(\envi,
              {arg freq=890, dur=1, t_gate=0;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.pairs([[0,0],    // [onset, livelllo]
                                    [0.01,1],
                                    [0.1,0.1],
                                    [0.3,0]],
                                    \cub)     // curva
                           .kr(0,t_gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\t_gate,1,\dur,rrand(0.05,5));

// ------------------------------ Env.xyc()

(
SynthDef(\envi,
              {arg freq=890, dur=1, t_gate=0;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.xyc([[0,0,\lin],    // [onset, livelllo, curva]
                                  [0.1,0.7,\wel],
                                  [2,0.1,\sin],
                                  [3,0,\cub]])
                            .kr(0,t_gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\t_gate,1,\dur,rrand(0.05,5));

// ------------------------------ Env.triangle()

(
SynthDef(\envi,
              {arg freq=890, t_gate=0, dur=1, amp=1;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.triangle(dur,amp)
                            .kr(0,t_gate);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\t_gate,1);
a.set(\dur,rrand(0.01,1), \amp,rand(1.0), \t_gate,1)

// ------------------------------ Env.sine()

(
SynthDef(\envi,
              {arg freq=890, t_gate=0, dur=1, amp=1;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.sine(dur,amp)
                            .kr(0,t_gate);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\t_gate,1);
a.set(\dur,rrand(0.01,1), \amp,rand(1.0), \t_gate,1)

// ------------------------------ Env.perc()

(
SynthDef(\envi,
              {arg freq=890, t_gate=0, atk=0.01, dec=0.5, dur=1, amp=1;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.perc(atk,dec,amp)
                            .kr(0,t_gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\t_gate,1,\dur,rrand(0.05,5));

(
a.set(\atk,rrand(0.01,0.2),
      \dec,rrand(0.01,1),
      \dur,rrand(0.05,5),
      \amp,rand(1.0),
      \t_gate,1)
)

// ------------------------------ Env.linen()

(
SynthDef(\envi,
              {arg freq=890, t_gate=0, atk=0.01, sust=0.5, dec=0.2, dur=1, amp=1;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.linen(atk,sust,dec,amp,\welch)
                            .kr(0,t_gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\t_gate,1,\dur,rrand(0.05,5));

(
a.set(\atk,rrand(0.01,0.2),
      \dec,rrand(0.01,1),
      \dur,rrand(0.05,5),
      \amp,rand(1.0),
      \t_gate,1)
)

Controlli dinamici da Client

// ------------------------------ Modificare singoli valori nodi

(
SynthDef(\envi,
              {arg t_gate=0,
		           liv= #[0,0.65,0.43,0],  // literal Array...
		           tmp= #[0.02,0.3,0.2],
		           curva=\cub;
               var sig,env;
                   sig = SinOsc.ar(986);
                   env = Env.new(liv,tmp,curva).kr(0,t_gate);
                Out.ar(0,sig*env)
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);

w = Window.new("EnvelopeView", 500@400);
w.alwaysOnTop;
w.onClose_({~synth.free;e.free;w.free;r.stop;});
w.front;
e = EnvelopeView.new(w, Rect(10,10,480,380)).resize_(5);

r = Routine.new({
                 inf.do({var liv,tmp,curva;
                             liv = [0]++({rand(1.0)}!2)++[0];  // livelli random ad eccezione
                                                               // del primo e dell'ultimo
                             tmp = {rrand(0.07,0.3)}!3;        // tempi delta random
                             curva = #[\lin,\sin,\cub].choose; // curva random

                         ~synth.set(\liv,liv,\tmp,tmp,\t_gate,1);  // al Synth

                         {e.value_([                                // alla GUI
                                   [0]++tmp.normalizeSum.integrate, // onsets tra 0 e 1
                                   liv                              // livelli
                                   ])
                         }.defer(0);

                         (tmp.sum).wait                            // Durata totale
                         })
                 }).reset.play;
)

r.stop;

// ------------------------------ Modificare ampiezza e durata generale

// Durate e ampiezze proporzionali tra 0 e 1 (oppure tra 0 e 100)

(
SynthDef(\envi,
              {arg t_gate=0,
		           dur=1,              // durata generale
		           amp=1,              // ampiezza generale
		           liv= #[0,1,0.33,0], // valori relativi tra 0 e 1
		           tmp= #[2,38,50],    // valori relativi in percentuale (somma = 100)
		           curva=\cub;
               var sig,env;
                   sig = SinOsc.ar(986);
                   env = Env.new(liv,tmp,curva).kr(0,t_gate,dur);
		Out.ar(0,sig*env*amp)         // aggiunto * amp
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);

w = Window.new("EnvelopeView", 500@400);
w.alwaysOnTop;
w.onClose_({~synth.free;e.free;w.free;r.stop;});
w.front;
e = EnvelopeView.new(w, Rect(10,10,480,380)).resize_(5);

r = Routine.new({
                 inf.do({var dur,amp;
		                     dur= rrand(0.07,1);  // durata totale random
		                     amp= rand(1.0);      // ampiezza di picco random

                         ~synth.set(\dur,dur,\amp,amp,\t_gate,1);  // al Synth

                         {e.value_([                               // alla GUI
                                   [0]++[2,38,50].normalizeSum.integrate, // onsets tra 0 e 1
                                   [0,1,0.33,0]*amp                       // livelli
                                   ])
                         }.defer(0);

		                 dur.wait                       // Durata totale
                         })
                 }).reset.play;
)

r.stop;

// Inviluppi con tempi specificati come onsets:

(
SynthDef(\envi,
              {arg t_gate = 0,
                   n1=#[0,0.001], // SynthDef non accetta Array 2D...
                   n2=#[0.2,1],
                   n3=#[0.5,0.6],
                   n4=#[2,0.001]; 
               var sig,bpf,env;
                   sig = SinOsc.ar(986);
                   env = Env.pairs([n1,n2,n3,n4],\cub).kr(0,t_gate);
               Out.ar(0,sig*env)
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);

w = Window.new("EnvelopeView", 500@400);
w.alwaysOnTop;
w.onClose_({~synth.free;e.free;w.free;r.stop;});
w.front;
e = EnvelopeView.new(w, Rect(10,10,480,380)).resize_(5);

r = Routine.new({
                 inf.do({var amp,tempi,dur,xy,tempi_e;
                             amp   = [0,0.7,0.3,0];
                             tempi = {1.0.rand}!4;       // Array di tempi delta
                             tempi = tempi.putFirst(0);  // primo = 0
                             tempi_e = tempi.normalizeSum.integrate; // per visualizzazione
                             tempi = tempi.integrate;    // Tempi delta -->  onsets
                             dur   = tempi.last;         // Durata globale
                             xy   = [tempi,amp].flop;    // Crea Array 2D dei nodi
                             xy.postln;                  // Stampa

                         ~synth.set(                     // al Synth
                               \n1, xy[0],
                               \n2, xy[1],
                               \n3, xy[2],
                               \n4, xy[3],
                               \t_gate, 1
                               );

                        {e.value_([tempi_e, amp])}.defer(0); // alla GUI

                        dur.wait
                        })
                 }).reset.play
)

r.stop

// ------------------------------ Modificare parametri da GUI e controller MIDI (o OSC)

// Play = gate

(
SynthDef(\no_sust,
              {arg t_gate=0,amp=0,dur=1,curva=1;
               var sig,env;
                   sig = SinOsc.ar(1970);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,1],          // tempi, livelli
                                  K2A.ar(curva).lag(0.2)            // curva
                                 ).duration_(K2A.ar(dur).lag(0.02)) // durata globale
                                  .kr(0,t_gate)*                    // trigger
                                  K2A.ar(amp).lag(0.02);            // ampiezza
               Out.ar(0,sig*env)
               }
          ).add;

{~synth = Synth(\no_sust)}.defer(0.1);

w = Window.new("Controlli", 200@230);
w.onClose_({a.free;e.free}).front.alwaysOnTop;

MIDIIn.connectAll;

c = CheckBox.new(w,Rect(77, 10)).action_({arg i; ~synth.set(\t_gate,i.value.asInt)});
d = StaticText.new(w,Rect(95,10, 50, 15)).string = "Gate";
MIDIdef.cc(\mioK1, {arg val; {c.valueAction_(val/127)}.defer(0)},41);    // cc number 41 (Play)

e = Slider.new(w,Rect(10, 50, 50, 170)).action_({arg i; ~synth.set(\amp, i.value)});
f = StaticText.new(w,Rect(22, 30, 50, 15)).string = "Amp";
MIDIdef.cc(\mioK2, {arg val; {e.valueAction_(val/127)}.defer(0)},0);

g = Slider.new(w,Rect(75, 50, 50, 170)).action_({arg i; ~synth.set(\dur, i.value*0.9+0.1)});
h = StaticText.new(w,Rect(77, 30, 50, 15)).string = "Tempo";
MIDIdef.cc(\mioK3, {arg val; {g.valueAction_(val/127)}.defer(0)},1);

i = Slider.new(w,Rect(135, 50, 50, 170)).action_({arg i; ~synth.set(\curva, i.value*10+10)}); // da -5 a +5
l = StaticText.new(w,Rect(140, 30, 50, 15)).string = "Curva";
MIDIdef.cc(\mioK4, {arg val; {i.valueAction_(val/127)}.defer(0)},2);
)

Inviluppi con sostegno

// ------------------------------ Env.new()

(
SynthDef(\envi,
              {arg freq=890, dur=1, gate=0;    // gate al posto di t_gate
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.6,0],    // livelli
                                 [0.01,0.2,0.3], // tempi delta
                                 \cub,           // curva
                                 2)              // nodo di sostegno (id Array dei livelli)
                            .kr(0,gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\gate,1,\dur,rrand(0.05,5)); // Note on  (trigger inizio e si ferma al nodo di sostegno)
a.set(\gate,0);                    // Note off (trigger per proseguire)

// loop

(
SynthDef(\envi,
              {arg freq=890, dur=1, gate=0;    // gate al posto di t_gate
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.6,0],    // livelli
                                 [0.01,0.2,0.3], // tempi delta
                                 \cub,           // curva
                                 2,              // nodo di sostegno (id Array dei livelli)
                                 0)              // nodo di loop (id Array dei livelli)
                            .kr(0,gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\gate,1,\dur,rrand(0.05,5)); // Note on  (trigger inizio e si ferma al nodo di sostegno)
a.set(\gate,0);                    // Note off (trigger per proseguire)

// ------------------------------ Env.circle()

(
SynthDef(\envi,
              {arg freq=1025, dur=1, gate=0;
               var sig,env;
                   sig  = SinOsc.ar(freq);
                   env  = Env.circle([0.0, 0.3, 0.1, 0.5, 0.0], // livelli
                                     [0.02,0.2,0.01,0.3,0.2],   // tempi delta
                                     \cub)                      // curva
                             .kr(0,gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\gate,1,\dur,rrand(0.05,5)); // trigger del loop
a.set(\gate,0);                    // stop del loop

// ------------------------------ Env.asr() - Trapezoidale

(
SynthDef(\envi,
              {arg freq=1025, dur=1, gate=0;
               var sig,bpf,env;
                   sig  = SinOsc.ar(freq);
                   env  = Env.asr(0.08,  // attacco (tempo)
                                  0.4,   // sostegno (ampiezza)
                                  1,     // rilascio (tempo)
                                  \sin)  // curva
                             .kr(0,gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\gate,1,\dur,rrand(0.05,5)); // Note on
a.set(\gate,0);                    // Note off

// ------------------------------ Env.adsr()

(
SynthDef(\envi,
              {arg freq=1025, dur=1, gate=0;
               var sig,bpf,env;
                   sig  = SinOsc.ar(freq);
                   env  = Env.adsr(0.08,  // attacco (tempo)
                                   0.2,   // decadimento (tempo)
                                   0.4,   // sostegno (ampiezza)
                                   0.6,   // rilascio (tempo)
                                   1,     // ampiezza di picco
                                  \sin)   // curva
                              .kr(0,gate,dur);
               Out.ar(0,sig*env)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1);
)

a.set(\gate,1,\dur,rrand(0.05,5)); // Note on
a.set(\gate,0);                    // Note off

Controlli dinamici da Client

// ------------------------------ Modificare singoli valori nodi

// Come per inviluppi senza sostegno, bisogna solo utilizzare nested Routines per il controllo del gate

(
SynthDef(\envi,
              {arg adsr=#[0.08,0.2,0.4,0.6,1,\sin], gate=0;
               var sig,bpf,env;
                   sig  = SinOsc.ar(rrand(200,2000));
                   env  = Env.adsr(adsr[0],  // attacco (tempo)
                                   adsr[1],  // decadimento (tempo)
                                   adsr[2],  // sostegno (ampiezza)
                                   adsr[3],  // rilascio (tempo)
                                   adsr[4],  // ampiezza di picco
                                   adsr[5])  // curva
                              .kr(0,gate);
               Out.ar(0,sig*env)
               }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);
)

(
b = Routine.new({

                 inf.do({var delta  = rrand(1,3);

                         ~synth.set(\adsr,[rrand(0.02,1),     // modifica valori
                                           rrand(0.02,1),
                                           0.4,
                                           rrand(0.02,1),
                                           rand(1.0),
                                           \cub]); 

                          Routine.new({
                                       ~synth.set(\gate,1);         // note on
                                       (delta*rrand(0.1,0.8)).wait; // sustain
                                       ~synth.set(\gate,0)          // note off
                                       }).play;
                          delta.wait
                          })

	            }).play
)

b.stop;

// ------------------------------ Modificare ampiezza e durata generale

// Durate e ampiezze proporzionali tra 0 e 1 (oppure tra 0 e 100)

(
SynthDef(\envi,
              {arg amp=1,dur=1, gate=0;
               var sig,bpf,env;
                   sig  = SinOsc.ar(rrand(200,2000));
                   env  = Env.adsr(0.08,0.2,0.4,0.6,1,\sin)
                             .kr(0,gate,dur);  // aggiunto dur
               Out.ar(0,sig*env*amp)           // aggiunto * amp
               }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);
)

(
b = Routine.new({

                 inf.do({var delta  = rrand(1,3);
 
                         ~synth.set(\amp,rand(1.0),\dur,delta);     // dur = delta

                          Routine.new({
                                       ~synth.set(\gate,1);         // note on
                                       (delta*rrand(0.1,0.8)).wait; // sustain
                                       ~synth.set(\gate,0)          // note off
                                       }).play;
                          delta.wait
                          })

	            }).play
)

b.stop;

// ------------------------------ Modificare parametri da GUI e controller MIDI (o OSC)

// Play = gate
// N.B. le durate non possono essere riscalate
(
SynthDef(\sust,
              {arg gate=0,amp=0,dur=1,curva=1;     
               var sig,env;
                   sig = SinOsc.ar(1970);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,1],
                                 K2A.ar(curva).lag(0.2),2
                                 ).kr(0,gate)*
                                 K2A.ar(amp).lag(0.02);
               Out.ar(0,sig*env)
               }
          ).add;

{~synth = Synth(\sust)}.defer(0.1);

w = Window.new("Controlli", 135@230);
w.onClose_({a.free;e.free}).front.alwaysOnTop;

MIDIIn.connectAll;

c = CheckBox.new(w,Rect(50, 10)).action_({arg i; ~synth.set(\gate,i.value.asInt)});
d = StaticText.new(w,Rect(70,10, 50, 15)).string = "Note";
MIDIdef.cc(\mioK1, {arg val; {c.valueAction_(val/127)}.defer(0)},41);    // cc number 41 (Play)

e = Slider.new(w,Rect(10, 50, 50, 170)).action_({arg i; ~synth.set(\amp, i.value)});
f = StaticText.new(w,Rect(22, 30, 50, 15)).string = "Amp";
MIDIdef.cc(\mioK2, {arg val; {e.valueAction_(val/127)}.defer(0)},0); 

g = Slider.new(w,Rect(75, 50, 50, 170)).action_({arg i; ~synth.set(\curva, i.value*10+10)});
h = StaticText.new(w,Rect(77, 30, 50, 15)).string = "Curva";
MIDIdef.cc(\mioK3, {arg val; {g.valueAction_(val/127)}.defer(0)},1);
)

Fades

// ------------------------------ Env.cutoff()

(
SynthDef(\envi,
              {arg freq=876, gate=1;           // Necessita di un gate:1 di default
               var sig,fadein,fadeout;
                   sig  = SinOsc.ar(freq);
                   fadein = XLine.kr(0.0001,0.4,2);
                   fadeout  = Env.cutoff(1,    // tempo di rilascio
                                         0.4,  // picco (ampiezza)
                                         \sin) // curva
                                 .kr(0,gate);
               Out.ar(0,sig*fadein*fadeout)
               }
          ).add;

{a = Synth(\envi)}.defer(0.1)
)

a.set(\gate,0);   // trigger del rilascio

a = Synth(\envi);
a.release;        // come gate:0

a = Synth(\envi);
a.release(0.2);   // modifica il tempo di rilascio (di tutti gli Env)

Env.newClear()

// Inviare qualsiasi tipo di inviluppo dal Client ad un Synth

(
SynthDef(\envi,
              {arg t_trig=0, freq=600, dur=1;
               var env, bpf,senv,sig;
                   env = Env.newClear(4);        // Crea un inviluppo vuoto di 4 nodi
                   bpf = \env.kr(env.asArray);   // Crea un controllo dell'inviluppo
                   senv= EnvGen.kr(bpf, t_trig); // Genera l'inviluppo
                   sig = SinOsc.ar(freq);
               Out.ar(0,sig*senv)
	           }
        ).add;

{~synth = Synth(\envi)}.defer(0.1);

w = Window("EnvelopeView", 250@250); 
e = EnvelopeView(w, 250@250);  
e.drawLines_(true);            
e.drawRects_(true);            
e.thumbSize_(7);               
e.strokeColor_(Color.black);   
e.fillColor_(Color.black);     
e.selectionColor_(Color.blue); 
e.gridColor_(Color.gray(0.8)); 
e.resize_(5);                  
e.step_(0.01);                 
e.action_({arg b; [b.index, b.value].postln}); 
w.front;                       
w.onClose = {~synth.free;w.free;e.free};    
)

// Crea inviluppo e invia

(
x = Env.new([0,rand(1.0),rand(1.0),0], // Crea un Env
            {rrand(0.01, 0.5)}!3,      // durata totale: val+val+val
            \cub);
~synth.set(\env, x, \t_trig,1);        // al Synth            
e.setEnv(x)                            // lalla GUI
)

// Database inviluppi

(
var env;
    env = [Env.perc(0.1,1,0.3),
           Env.perc(1,0.1,0.7),
           Env.perc(0.3,0.5,0.4),
           Env.perc(0.9,0.01,0.7),
           Env.perc(0.01,0.2,0.9),
          ].choose;
~synth.set(\env,env,\t_trig,1);
e.setEnv(env)
)

Segnali e trigger

// ------------------------------ Segnali impulsivi

// Ampiezza fissa
(
SynthDef(\envi,
              {var sig,trig,env;
                   sig = SinOsc.ar;
                   trig = Impulse.kr(5);                               // trigger
                   env  = Env.new([0,1,0],[0.01,0.2],\cub).kr(0,trig); // inviluppo
                Out.ar(0,sig*env)
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);
)


// Ampiezza random
(
SynthDef(\envi,
              {var sig,trig,env;
                   sig = SinOsc.ar;
                   trig = Impulse.kr(5)*WhiteNoise.kr.unipolar;
                   env  = Env.new([0,1,0],[0.01,0.2],\cub).kr(0,trig,1,trig); // ampiezza
                Out.ar(0,sig*env)
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);
)

// Ampiezza e tempi delta random
(
SynthDef(\envi,
              {var sig,trig,env;
                   sig = SinOsc.ar;
                   trig = Dust.kr(5);
                   env  = Env.new([0,1,0],[0.01,0.2],\cub).kr(0,trig,1,trig); // ampiezza
                Out.ar(0,sig*env)
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);
)

// ------------------------------ Qualsiasi segnale cone Trig.kr()

// Trigger di EnvGen
(
SynthDef(\envi,
              {arg amp,tfreq=3, dur=1;
               var ksig,trig,env,sig;
                   sig = SinOsc.ar;
                   ksig = LFPulse.kr(tfreq);
                   trig = Trig.kr(ksig,1/tfreq*dur);
                   env = Env.new([0,1,0.6,0.2,0],[0.01,0.03,0.1,0.02],\cub,2).kr(0,trig,1,trig);
                Out.ar(0,sig*env)
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.1);
)

~synth.set(\amp,rand(1.0),\tfreq, rrand(1,5),\dur,rrand(0.01,1)); // esegui più volte

Voice allocation

s.boot;
s.scope(1);
s.meter(1,1);

//====================================================================

// L'argomento 'doneAction:n' di un inviluppo d'ampiezza può essere sfruttato
// per controllare un'allocazione di voci dinamica (Dynamic voice allocation):

s.plotTree; // visualizza i nodi

//====================================================================

Synth monofonici

//
// • Devono essere assegnati a una variabile o inclusi come items in un Array.
// • 'doneAction:0' = l'istanza di Synth non si distrugge alla fine dell'inviluppo

// ------------------------------ Senza sostegno

(
SynthDef(\envi,
              {arg freq=400, amp=0, t_gate=0;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.6,0],[0.01,0.2,1],\cub)
                            .kr(gate:t_gate,doneAction:0,mul:amp);
               Out.ar(0,sig*env)
               }
          ).add;

{~synth = Synth(\envi)}.defer(0.01);        // crea una sola istanza

MIDIIn.connectAll;                          // Interazione MIDI (solo noteon)
MIDIdef.noteOn(\on,{arg vel,note;
                    ~synth.set(\freq,note.midicps,\amp,(vel/127).pow(2),\t_gate,1)})
)

// Sequencing

b = SystemClock.sched(0,{~synth.set(\freq,rrand(200,2000),\amp,rand(1.0),\t_gate,1); rrand(0.2,2)});
b.clear;

// ------------------------------ Con sostegno

(
SynthDef(\envi,
              {arg freq=400, amp=0, gate=0;  // senza t_
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.6,0],[0.01,0.2,1],\cub, 2) // Nodo di sostegno
                            .kr(gate:gate,doneAction:0,mul:amp);
               Out.ar(0,sig*env)
                }
          ).add;

{~synth = Synth(\envi)}.defer(0.01);         // crea una sola istanza

MIDIIn.connectAll;                           // Interazione MIDI (noteOn)
MIDIdef.noteOn(\on,{arg vel,note;            // NoteOn
                    ~synth.set(\freq,note.midicps,\amp,(vel/127).pow(2),\gate,1)});
MIDIdef.noteOff(\off,{~synth.set(\gate,0)}); // NoteOff
)

// Sequencing

(
b = TempoClock.sched(0,
                       {var pitch,vel,delta;
                            pitch = rrand(60,90);
                            vel = rrand(60,127);
                            delta  = rrand(0.05,1);

                        Routine.new({
                                     ~synth.set(\freq,pitch.midicps,   // note on
                                                \amp,(vel/127).pow(2),
                                                \gate,1);
                                     (delta*rrand(0.1,0.8)).wait;      // sustain
                                     ~synth.set(\gate,0)               // note off
                                     }).play;
                        delta}
                    )
)

b.clear;

Synth polifonici

//
// • Non devono essere assegnati a una variabile o inclusi come items in un Array
//   in quanto si crea un'istanza di Synth ad ogni messaggio di 'gate:1' che si
//   autodistrugge alla fine dell'inviluppo grazie a 'doneAction:2'
// • Bisogna creare un Array con tanti items quanti i valori delle frequenze desiderati
//   e mapparli per gate:1 e gate:0 - noteOn e noteOff)

// ------------------------------ Senza sostegno

(
SynthDef(\envi,
              {arg freq=400, amp=0, t_gate=0;   // t_gate
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,1],\cub)
                            .kr(gate:t_gate,doneAction:2,mul:amp);
               Out.ar(0,sig*env)
                }
          ).add;

MIDIIn.connectAll;                              // Interazione MIDI (solo noteon)
MIDIdef.noteOn(\on,{arg vel,note;
                    Synth(\envi,[\freq,note.midicps,\amp,(vel/127).pow(2),\t_gate,1])})
)

// Sequencing

b = SystemClock.sched(0,{Synth(\envi,[\freq,rrand(200,2000),\amp,rand(1.0),\t_gate,1]); rrand(0.2,1)});
b.clear;

// ------------------------------ Con sostegno valori in MIDI Note

(
var notes = Array.newClear(128);   // Un Array vuoto di 128 items (tutte le note midi)

SynthDef(\envi,
              {arg freq=400, amp=0, gate=1;                       // gate e non t_
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,1],\cub,2) // Nodo di sostegno
                            .kr(gate:gate,doneAction:2,mul:amp);
               Out.ar(0,sig*env)
               }
          ).add;

~ksynth = {arg vel, pitch;             // valori da Client
           var item = notes.at(pitch); // Richiama l'item corrispondente alla midi note

           if(item.notNil,             // se non è 'nil'

              {item.release;           // parte il release (gate:0 o note Off)
               notes.put(pitch, nil)}, // e mette 'nil' nell'Array

              {item = Synth(\envi,[\freq,pitch.midicps,     // crea un Synth (noteOn)
                                   \amp,(vel/127).pow(2)]);
               notes.put(pitch, item)}                      // lo mette nell'Array
             )
           };

MIDIIn.connectAll;                          // Interazione MIDI
MIDIdef.noteOn(\on,                         // noteOn
                   {arg vel, pitch;
                    var item = notes.at(pitch);
 
                    if(item.notNil, {item.release; notes.put(pitch, nil)});  // noteOff di sicurezza
  
                    item = Synth(\envi,[\freq,pitch.midicps,    // crea un Synth (noteOn)
                                        \amp,(vel/127).pow(2)]);
                    notes.put(pitch, item)}                     // lo mette nell'Array
               );

MIDIdef.noteOff(\off,                        // noteOff
	            {arg vel, pitch;
	             var item = notes.at(pitch);

	             if(item.notNil,{item.release;notes.put(pitch, nil)})
	             })
)

// Sequencing

(
b = Routine.new({

                 inf.do({var pitch,vel,delta;
                             pitch = rrand(60,90);
                             vel = rrand(60,127);
                             delta  = rrand(0.05,1);

                          Routine.new({
                                       ~ksynth.value(vel,pitch);    // note on
                                       (delta*rrand(0.1,0.8)).wait; // sustain
                                       ~ksynth.value(0,pitch)       // note off
                                       }).play;
                          delta.wait
                          })

	            }).play
)

b.stop;

// ------------------------------ Con sostegno valori in Frequenze

// • Cambia il numero di items dell'Array e le conversioni dei valori
// • No interazione MIDI (solo controllo da Interprete)

(
var notes = Array.newClear(15000);   // Un Array vuoto di 15000 items (tutte le frequenze)

SynthDef(\envi,
              {arg freq=400, amp=0, gate=1;
               var sig,env;
                   sig = SinOsc.ar(freq);
                   env = Env.new([0,1,0.3,0],[0.01,0.2,1],\cub,2)
                            .kr(gate:gate,doneAction:2,mul:amp);
               Out.ar(0,sig*env)
                }
          ).add;

~ksynth = {arg vel, pitch;
           var item = notes.at(pitch);

           if(item.notNil,
                          {item.release; notes.put(pitch, nil)},
                          {item = Synth(\envi,[\freq,pitch,        // Hz
                                               \amp, vel.pow(2)]); // 0/1
           notes.put(pitch, item)})
           };
)

// Sequencing

(
b = Routine.new({

                 inf.do({var pitch,vel,delta;
                             pitch = rrand(200,7000);
                             vel = rrand(0.1,1);
                             delta  = rrand(0.05,1);

                          Routine.new({
                                       ~ksynth.value(vel,pitch);    // note on
                                       (delta*rrand(0.1,0.8)).wait; // sustain
                                       ~ksynth.value(0,pitch)       // note off
                                       }).play;
                          delta.wait
                          })

	            }).play
)

b.stop;

Panning

Multifonia

//====================================================================

// Espansione multicanale

//====================================================================

s.boot;
s.scope(8);
s.meter(8,8);

// Un Array di UGens oppure di argomenti di una UGen genera tante istanze di segnale quanto il numero di items.
// Ognuno è scritto su un bus audio differente in ordine crescente rispetto a quelllo specificato come primo.

// ------------------------------ Array di UGens:

(
SynthDef(\multi, {var sig;
                      sig = [SinOsc.ar(440),
                             SinOsc.ar(550),
                             SinOsc.ar(660),
                             SinOsc.ar(880)];
	               Out.ar(0,sig) // 4 segnali che escono su 4 canali differenti e contigui
	               }).add;

{~synth = Synth(\multi)}.defer(0.1)
)



// ------------------------------ Array di argomenti come valori:

(
SynthDef(\multi, {var sig;
                      sig = SinOsc.ar([440,550,660,880]);
	              Out.ar(0,sig)
	              }).add;

{~synth = Synth(\multi)}.defer(0.1)
)

// ------------------------------ Array di argomenti come segnali:

(
SynthDef(\multi, {var sig;
                      sig = SinOsc.ar([440,550,660,880],
                                       0,
                                       SinOsc.kr([1,0.5,0.2,0.4]).unipolar);
	              Out.ar(0,sig)
	              }).add;

{~synth = Synth(\multi)}.defer(0.1)
)

// ------------------------------ Visualizzazione

// Inviluppi

(
a = Env.perc([0.1,0.5,0.7],2,0.7).test;
a.plot(name:"plot 1", bounds:300@200, minval:0, maxval:1)
)

// Segnali

{SinOsc.ar([440,1200,3000], mul:0.1)}.plot

//====================================================================

// Implosione multicanale

//====================================================================

{SinOsc.ar([600,800,1000,1200,1500], mul:0.1)}.scope;          // multicanale
{Mix.new(SinOsc.ar([600,800,1000,1200,1500], mul:0.1))}.scope; // mono

(
SynthDef(\envi, {arg t_trig = 0;
                 var freq,env,sig;
                     freq = #[200,974,1500,1800];
                     env  = Env.perc([0.1,0.2,0.3,0.4],[0.4,0.3,0.2,0.1]).kr(gate:t_trig);
                     sig  = SinOsc.ar(freq, mul:env); // multicanale
                     sig  = Mix(sig);                 // mono
                Out.ar(0,sig*0.3)
                }
        ).add;

{~synth = Synth(\envi)}.defer(0.1);

)

~synth.set(\t_trig,1);

Monofonia

// ------------------------------ Mono

(
SynthDef(\mono,
    	      {arg bus=0;
               var sig;
                   sig = SinOsc.ar;
               Out.ar(bus, sig*0.2)}
         ).add;

{~synth = Synth(\mono)}.defer(0.1);
)

~synth.set(\bus,rand(8));

// ------------------------------ Dual Mono

(
SynthDef(\dual_mono,
    	      {arg bus=0;
               var sig;
		           sig = SinOsc.ar([456,678],0,0.5);
               Out.ar(bus, sig*0.2)}
         ).add;

{~synth = Synth(\dual_mono)}.defer(0.1);
)

~synth.set(\bus,rand(7));

Stereofonia

Client side

//====================================================================

// Strumento

(
var xO=0,yO=1;                  // operazioni di init

// ------------------------------ SynthDef e Synth

SynthDef(\stereo_gui,
              {arg amp=1,pos=0.0,lev=1,smt=0.2;
               var sig,pan;
                   sig = SinOsc.ar(Rand(400,2000));
                   pan = Pan2.ar(sig,
                                 pos.lag(smt), 
                                 lev.lag(smt));
               Out.ar(0,pan*amp)
               }
        ).add;
	
{~synth = Synth(\stereo_gui)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 200@220);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;e.free;c.free});

b = NumberBox.new(w, Rect(40,195,50,20)).value_(0.5);  // NumberBox X
c = NumberBox.new(w, Rect(120,195,50,20)).value_(0.5); // NumberBox Y
d = StaticText.new(w, Rect(25,198,180,15))             // Static text
 .string_("X:                  Y:");
e = Slider2D.new(w, Rect(10, 10, 180, 180))            // Slider2D
 .x_(0.5).y_(0.5);
	
// ------------------------------ Operazioni di basso livello

~ksynth = {arg x=0,y=1, dur=1,defId=0.01,smth=0.02;          
           var range,nPassi,xPasso,yPasso,dPasso;
               range  = abs(xO-x);
               nPassi = 1/defId;
               xPasso = Array.interpolation(nPassi,0,1) // Passaggi di x
                             .normalize(xO,x);
               yPasso = Array.interpolation(nPassi,0,1) // Passaggi di y
                             .normalize(yO,y);   
               dPasso = dur/nPassi;

Routine.new({                                                
             xPasso.do({arg item,id;
                        ~synth.set(\pos,item,\lev,(yPasso[id]).sqrt); // al Synth  
                        {b.value_(item);                              // al NumberBox X (+/-1)
                         c.value_((yPasso[id]).sqrt);                 // al NumberBox Y (1/0)
                         e.x_(item.linlin(-1,1,0,1))                  // allo Slider2D  (0/1)
                          .y_((1-yPasso[id]).sqrt)
                        }.defer(0);

                         xO = item;                                   // resetta all'ultimo valore
                         yO = yPasso[id];
                         dPasso.wait  
                        })
             }).play;
};
	
e.action_({arg i;
           ~synth.set(\pos,i.x.linlin(0,1,-1,1), //  al Synth
                      \lev, (1-i.y).sqrt); 
          {b.value_(i.x.linlin(0,1,-1,1));       // al Number Box X
           c.value_(1-i.y)}.defer(0);            // al Number Box Y
           });
	
MIDIIn.connectAll;                                
MIDIdef.cc(\knob, {arg val;                  
                   ~synth.set(\pos,val.linlin(0,127,-1,1)); // al Synth
                   {b.value_(val.linlin(0,127,-1,1));       // al NumberBox X (+/-1)
                    e.x_(val.linlin(0,127,0,1))             // allo Slider2D  (0/1)
                    }.defer(0)
                   }, 16);                                  // dal cc 16
MIDIdef.cc(\slid, {arg val;                  
                   ~synth.set(\lev,val.linlin(0,127,1,0));  // al Synth
                   {c.value_(1-(val/127));                  // al NumberBox Y (1/0)
                    e.y_(val.linlin(0,127,0,1))             // allo Slider2D  (0/1)
                    }.defer(0)
                   }, 0);                                   // dal cc 0

OSCdef.new(\notam, {arg msg;                                   // Interazione OSC
                    ~synth.set(\pos,msg[1].linlin(0,127,-1,1), // posizione
                               \lev,msg[2].linlin(0,127,1,0)); // distanza
                    {b.value_(msg[1].linlin(0,127,-1,1));      // alla GUI
                     e.x_(msg[1].linlin(0,127,-1,1));
                     c.value_(1-(msg[2]/127));
                     e.y_(msg[2].linlin(0,127,0,1))
                     }.defer(0)},      
                    '/pan', NetAddr.new("127.0.0.1",58027));
)

//====================================================================

// Controlli

// ------------------------------ Singolo valore

~ksynth.value(x:0.6,y:0.3,dur:0.4);    // tutti i parametri
~ksynth.value(rand2(1.0),rand(1.0),rand(2.0)); 
~ksynth.value(rand2(1.0),rand(1.0),0); // cambio immediato (in relazione al parametro di smoothing)

// ------------------------------ Sequencing

// Deterministico

(
var pos;
    pos = [[0,1,1],[-0.4,0.6,0.3],[0.6,0.3,2],[0,0.5,0.4],[1,0.7,3],[-1,1,5]]; // [x,y,dur]

h = Routine.new({
                 pos.do({arg i;
                         ~ksynth.value(i[0],i[1],i[2]);
                         i[2].wait
                         })
                 }).reset.play;
)

h.stop; ~ksynth.value(y:0,dur:0.2);

// Non deterministico

(
var x,y,dur;

h = Routine.new({
                 inf.do({x = rand2(1.0);  // valori tra 0.0 e 1.0 ampliano o restringono il fronte stereo
                         y = rand(1.0);
                         dur = rrand(0.01,3);
                         ~ksynth.value(x,y,dur); 
                         dur.wait                       
                         })
                  }).reset.play
)

h.stop;~ksynth.value(y:0);

// ------------------------------ Rota

(
var ciclo;
    ciclo = 3; // tempo di un'andata e ritorno in secondi

h = Routine.new({

                 inf.do({var dur = ciclo*0.5;  // pos
                         ~ksynth.value(1,1,dur);
                         dur.wait;
                         ~ksynth.value(-1,1,dur);
                         dur.wait;
                         })

                 }).reset.play
)

h.stop;~ksynth.value(y:0);

// ------------------------------ Spreading

(
var rng,dur,smt;
    rng = [-0.5,0.3];
    dur = 0.02;
    smt = 0.02;  // prova a cambiare

~ksynth.value(smt:smt);

h = Routine.new({
                 inf.do({var x,y;
                         x = rrand(rng[0],rng[1]);
                         y = 1;
                         ~ksynth.value(x,y,dur);
                         dur.wait
                         })
                 }).reset.play
)

h.stop;~ksynth.value(y:0);

// ------------------------------ Interazione MIDI

// Utilizza un Knob sul cc 16 per la psozione sul fronte stereo e un fader sul cc 0 per la distanza

// ------------------------------ Interazione OSC

// • Monitorare i messaggi OSC:

OSCFunc.trace(true);  
OSCFunc.trace(false); 

// • Copiare il numero della porta in ingresso ('recvPort:57120') come output
//   del device che utilizziamo.
// • Inviare dei messaggi OSC dal device e copiare il numero di address 
//   ('address: a NetAddr("127.0.0.1", 58027)' e sostituirlo all'interno di
//   'OSCdef'
// • Eseguire il codice dello strumento e della GUI ed inviare messaggi dal device

Server side

Segnali di controllo

// vel: Hz
// sprd: 0/1
// initpos: 0      = parte dal centro e va verso 1
//          pi     = parte dal centro e va verso -1
//          0.5pi  = parte da 1 e va verso -1
//          -0.5pi = parte da -1 e va verso 1

(
var w,a,b,c,d;                  // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\stereo_sig,
              {arg tipo=0,vel=1,sprd=1,initpos=0,dist=1,smt=0.2;
               var sig,ksigs,pos,pan;
                   sig = SinOsc.ar(Rand(400,2000));
                   pos = Select.kr(tipo,[LFTri.kr(vel,initpos,sprd),
                                         SinOsc.kr(vel,initpos,sprd),
                                         LFNoise0.kr(vel,sprd),
                                         LFNoise1.kr(vel,sprd),
                                         LFNoise2.kr(vel,sprd)]);
                   pos.scope;                                 // visualizza ksig
                   SendReply.kr(Impulse.kr(50), '/pos', pos); // Invia valori al Client
                   pan = Pan2.ar(sig,pos,dist.lag(smt));
               Out.ar(0,pan)
               }
        ).add;

{~synth = Synth(\stereo_sig)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 255@130);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;e.free;c.free});

a = PopUpMenu(w,Rect.new(10,10,100,20));
a.items = ["Triangolo","Sinusoide","Random 1","Random 2","Random 3"];
b = NumberBox.new(w,Rect.new(115,10,40,20))
 .value_(1);
c = NumberBox.new(w,Rect.new(180,10,40,20))
 .value_(1);
StaticText.new(w, Rect.new(158, 12, 20, 20))
          .string_("Vel");
StaticText.new(w, Rect.new(222, 12, 20, 20))
          .string_("Dist");
StaticText.new(w, Rect(10, 40, 255, 15))
          .string_("-1                          0                         1");
d = Slider.new(w, Rect(10, 55, 230, 50)); // Slider orizzontale

// ------------------------------ Operazioni di basso livello

a.action_({arg tipo;
	       ~synth.set(\tipo,tipo.value)
	       });
b.action_({arg vel;
	  	   ~synth.set(\vel, vel.value)
	       });
c.action_({arg dist;
	  	   ~synth.set(\dist, dist.value)
	       });

OSCFunc.new({arg msg; defer{d.value_(\pan.asSpec.unmap(msg[3]))}},'/pos', s.addr)
)

Inviluppi

(
s.waitForBoot{
var w,b,d;     // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\penvi,
              {arg t_gate=0;
               var sig,envpos,envdist,pan;
                   sig     = SinOsc.ar;
                   envpos  = Env.new([0,-1,0.7,0],[0.3,0.2,2],\lin).kr(0,t_gate);
                   envdist = Env.new([1,0.01,1],[3,3],\cub).kr(0,t_gate);
                   pan     = Pan2.ar(sig,envpos,envdist);
                   SendReply.kr(Impulse.kr(50), '/pos', envpos);
                   SendReply.kr(Impulse.kr(50), '/dis', envdist); 
               Out.ar(0,pan)
               }
          ).add;


{~synth = Synth(\penvi)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 255@130);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;e.free;c.free});
	
StaticText.new(w, Rect(86, 12, 255, 15))
          .string_("Dist");
b = NumberBox.new(w,Rect.new(115,10,40,20));

StaticText.new(w, Rect(10, 40, 255, 15))
          .string_("-1                         0                         1");
d = Slider.new(w, Rect(10, 55, 230, 50)); // Slider orizzontale

// ------------------------------ Operazioni di basso livello

OSCFunc.new({arg msg; defer{d.value_(\pan.asSpec.unmap(msg[3]))}},'/pos', s.addr);
OSCFunc.new({arg msg; defer{b.value_(\pan.asSpec.unmap(msg[3]))}},'/dis', s.addr);
}
)

// ------------------------------ Sequencing

~synth.set(\t_gate,1);

Mouse

(
SynthDef(\pmouse,
              {var sig,pos,dist,pan;
                   sig  = SinOsc.ar;
                   pos  = MouseX.kr(-1,1);
                   dist = MouseY.kr(1,0.001); // vicino in basso
                   pan  = Pan2.ar(sig,pos,dist);
               Out.ar(0,pan)
               }
          ).add;


{a = Synth(\pmouse)}.defer(0.1);
)

Quadrifonia

Client side

//====================================================================

// Strumento

(
var xO=0,yO=0;                  // operazioni di init

// ------------------------------ SynthDef e Synth

SynthDef(\stereo_gui,
              {arg amp=1,x=0,y=0,lev=1,smt=0.2;
               var sig,pan;
                   sig = SinOsc.ar(Rand(400,2000));
                   pan = Pan4.ar(sig,
                                 x.lag(smt), 
                                 y.lag(smt));
               Out.ar(0,pan*amp)
               }
        ).add;
	
{~synth = Synth(\stereo_gui)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 200@220);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;e.free;c.free});

b = NumberBox.new(w, Rect(40,195,50,20)).value_(0);  // NumberBox X
c = NumberBox.new(w, Rect(120,195,50,20)).value_(0); // NumberBox Y
d = StaticText.new(w,Rect(25,198,180,15))            // Static text
 .string_("X:                  Y:");
e = Slider2D.new(w,  Rect(10, 10, 180, 180))         // Slider2D
 .x_(0.5).y_(0.5);
	
// ------------------------------ Operazioni di basso livello

~ksynth = {arg x=0,y=1, dur=1,defId=0.01,smth=0.02;          
           var range,nPassi,xPasso,yPasso,dPasso;
               range  = abs(xO-x);
               nPassi = 1/defId;
               xPasso = Array.interpolation(nPassi,0,1) // Passaggi di x
                             .normalize(xO,x);
               yPasso = Array.interpolation(nPassi,0,1) // Passaggi di y
                             .normalize(yO,y);   
               dPasso = dur/nPassi;

Routine.new({                                                
             xPasso.do({arg item,id;
                        ~synth.set(\x,item,\y,yPasso[id]);  // al Synth (+/-1)  
                         {b.value_(item);                   // al NumberBox X (+/-1)
                          c.value_(yPasso[id]);             // al NumberBox Y (+/-1)
                          e.x_(item.linlin(-1,1,0,1))       // allo Slider2D  (0/1)
                           .y_(yPasso[id].linlin(-1,1,0,1))
                         }.defer(0);

                         xO = item;                         // resetta all'ultimo valore
                         yO = yPasso[id];
                         dPasso.wait  
                        })
             }).play;
};
	
e.action_({arg i;
           ~synth.set(\x,i.x.linlin(0,1,-1,1),            //  al Synth (+/-1)
                      \y,i.y.linlin(0,1,-1,1)); 
          {b.value_(i.x.linlin(0,1,-1,1));                // al Number Box X (+/-1)
           c.value_(i.y.linlin(0,1,-1,1))}.defer(0);      // al Number Box Y (+/-1)
           });
	
MIDIIn.connectAll;                                
MIDIdef.cc(\knob, {arg val;                  
                   ~synth.set(\x,val.linlin(0,127,-1,1)); // al Synth (+/-1)
                   {b.value_(val.linlin(0,127,-1,1));     // al NumberBox X (+/-1)
                    e.x_(val.linlin(0,127,0,1))           // allo Slider2D  (0/1)
                    }.defer(0)
                   }, 16);                                // dal cc 16
MIDIdef.cc(\slid, {arg val;                  
                   ~synth.set(\y,val.linlin(0,127,-1,1)); // al Synth
                   {c.value_(val.linlin(0,127,-1,1));     // al NumberBox Y (1/0)
                    e.y_(val.linlin(0,127,0,1))           // allo Slider2D  (0/1)
                    }.defer(0)
                   }, 0);                                 // dal cc 0

OSCFunc.new({arg msg;
             ~synth.set(\x, msg[1].linlin(0,127,-1,1),  // al Synth
                        \y, msg[2].linlin(0,127,-1,1));
             {e.x_(msg[1]/127);                         // all'interfaccia
              e.y_(msg[2]/127);
			  b.value_(msg[1].linlin(0,127,-1,1));                
              c.value_(msg[2].linlin(0,127,-1,1))
		}.defer(0);
	         },'/pos', NetAddr.new("127.0.0.1",57876))
)

//====================================================================

// Controlli

// ------------------------------ Singolo valore

~ksynth.value(0,0,0.5);// centro
~ksynth.value(x:-1,y:1,dur:2); // L1 - bus 0     
~ksynth.value(0,1,2);  // centro al fondo
~ksynth.value(1,1,2);  // L2 - bus 1
~ksynth.value(1,0,2);  // centro a destra
~ksynth.value(1,-1,2); // L4 - bus 3
~ksynth.value(0,-1,2); // centro di fronte
~ksynth.value(-1,-1,2);// L3 - bus 2
~ksynth.value(-1,0,2); // centro a sinistra

~ksynth.value(0,0,0.5);// centro
~ksynth.value(rand2(1.0),rand2(1.0),rrand(0.1,2))

// ------------------------------ Sequencing

// Deterministico

(
var pos;
    pos = [[0,1,1],[-0.4,0.4,0.3],[0.6,-0.3,2],[0,0.4,1],[1,0,3],[-1,1,5]]; // [x,y,time]

h = Routine.new({
                 pos.do({arg i;
                         ~ksynth.value(i[0],i[1],i[2]);
                         i[2].wait
                         })
                 }).reset.play;
)

h.stop;

// Non deterministico

(
var x,y,dur;

h = Routine.new({
                 inf.do({x = rand2(1.0);  
                         y = rand2(1.0);
                         dur = rrand(0.01,3);
                         ~ksynth.value(x,y,dur);
                         dur.wait                
                         })
                  }).reset.play
)

h.stop;

// ------------------------------ Rota

// Senso orario
(
var ciclo;
    ciclo = 4; // tempo di giro in secondi

h = Routine.new({

                 inf.do({var dur = ciclo*0.25;  // pos
                         ~ksynth.value(-1,1,dur);
                         dur.wait;
                         ~ksynth.value(1,1,dur);
                         dur.wait;
		                 ~ksynth.value(1,-1,dur);
		                 dur.wait;
				         ~ksynth.value(-1,-1,dur);
		                 dur.wait;
                         })

                 }).reset.play
)

h.stop;

// Senso antiorario
(
var ciclo;
    ciclo = 4; // tempo di giro in secondi

h = Routine.new({

                 inf.do({var dur = ciclo*0.25;  // pos
                         ~ksynth.value(-1,1,dur);
                         dur.wait;
                         ~ksynth.value(-1,-1,dur);
                         dur.wait;
		                 ~ksynth.value(1,-1,dur);
		                 dur.wait;
				         ~ksynth.value(1,1,dur);
		                 dur.wait;
                         })

                 }).reset.play
)

h.stop;

// ------------------------------ Spreading

(
var rx,ry,dur,smt;
    rx = [-1,0];
    ry = [1,0];
    dur = 0.1;
    smt = 0.1;  // prova a cambiare

~ksynth.value(smt:smt);

h = Routine.new({
                 inf.do({var x,y;
                         x = rrand(rx[0],rx[1]);
                         y = rrand(ry[0],ry[1]);
                         ~ksynth.value(x,y,dur);
                         dur.wait
                         })
                 }).reset.play
)

h.stop;

// ------------------------------ Interazione MIDI

// Utilizza un Knob sul cc 16 per la psozione sull'asse x e un fader sul cc 0 per l'a distanza'asse y

// ------------------------------ Interazione OSC

// • Monitorare i messaggi OSC:

OSCFunc.trace(true);  
OSCFunc.trace(false); 

// • Copiare il numero della porta in ingresso ('recvPort:57120') come output
//   del device che utilizziamo.
// • Inviare dei messaggi OSC dal device e copiare il numero di address 
//   ('address: a NetAddr("127.0.0.1", 58027)' e sostituirlo all'interno di
//   'OSCdef'
// • Eseguire il codice dello strumento e della GUI ed inviare messaggi dal device

Server side

Segnali di controllo

(
var w,d,a;                  // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\quad_sig,
              {arg tipoX=1,velX=0.5,sprdX=1,initposX= 0,
                   tipoY=1,velY=0.5,sprdY=1,initposY= 0.5pi,
                   smt=0.2;
               var sig,ksigs,x,y,pan;
                   sig = SinOsc.ar(Rand(400,2000));
                   x   = Select.kr(tipoX,[LFTri.kr(velX,initposX,sprdX),
                                          SinOsc.kr(velX,initposX,sprdX),
                                          LFNoise0.kr(velX,sprdX),
                                          LFNoise1.kr(velX,sprdX),
                                          LFNoise2.kr(velX,sprdX),
			                              ]);
                   y   = Select.kr(tipoY,[LFTri.kr(velY,initposY,sprdY),
                                          SinOsc.kr(velY,initposY,sprdY),
                                          LFNoise0.kr(velY,sprdY),
                                          LFNoise1.kr(velY,sprdY),
                                          LFNoise2.kr(velY,sprdY),
			                              ]);
                   SendReply.kr(Impulse.kr(50), '/pos', [x,y]); // Invia Slider2D
                   pan = Pan4.ar(sig,x,y);
               Out.ar(0,pan)
               }
        ).add;

{~synth = Synth(\quad_sig)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 210@210);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;d.free;a.free});

d = Slider2D.new(w, Rect(5, 5, 200, 200));          // Slider2D

OSCFunc.new({arg msg;
             {d.x_(msg[3].linlin(-1,1,0,1));     // solo all'interfaccia
              d.y_(msg[4].linlin(-1,1,0,1))}.defer(0);
              },'/pos', s.addr);
)

//====================================================================

// ------------------------------ Movimenti

~synth = Synth(\quad_sig,[\tipoX, 3, \tipoY, 3]).run;        // Random
~synth.run(false);
~synth = Synth(\quad_sig,[\initposX,0,\initposY,0.5pi]).run; // Senso orario
~synth.run(false);
~synth = Synth(\quad_sig,[\initposX,0.5pi,\initposY,0]).run; // Senso anti-orario
~synth.run(false);
~synth.set(\tipoX,rand(4),\tipoY,rand(4)).run;               // Combinazioni di segnali
~synth.run(false);
~synth.set(\tipoX,1,\tipoY,1,\velX,rrand(0.2,1),\velY,rrand(0.2,1)).run; // Combinazioni di velocità

//====================================================================

// ------------------------------ Controllo da GUI

(
var w,d,a;                  // variabili locali

// ------------------------------ SynthDef e Synth
	
SynthDef(\quad_sig,
              {arg tipoX=1,velX=0.5,sprdX=1,initposX= 0,
                   tipoY=1,velY=0.5,sprdY=1,initposY= 0.5pi,
                   smt=0.2;
               var sig,ksigs,x,y,pan;
                   sig = SinOsc.ar(Rand(400,2000));
                   x   = Select.kr(tipoX,[LFTri.kr(velX,initposX,sprdX),
                                          SinOsc.kr(velX,initposX,sprdX),
                                          LFNoise0.kr(velX,sprdX),
                                          LFNoise1.kr(velX,sprdX),
                                          LFNoise2.kr(velX,sprdX),
			                              ]);
                   y   = Select.kr(tipoY,[LFTri.kr(velY,initposY,sprdY),
                                          SinOsc.kr(velY,initposY,sprdY),
                                          LFNoise0.kr(velY,sprdY),
                                          LFNoise1.kr(velY,sprdY),
                                          LFNoise2.kr(velY,sprdY),
			                              ]);
                   SendReply.kr(Impulse.kr(50), '/pos', [x,y]); // Invia Slider2D
                   pan = Pan4.ar(sig,x,y);
               Out.ar(0,pan)
               }
        ).add;

{~synth = Synth(\quad_sig)}.defer(0.1);

// ------------------------------ GUI
		
w = Window.new("Pan", 270@210);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;b.free;c.free;d.free});

b = Knob.new(w,     Rect(210, 5, 50, 50));   // Knob
c = Slider.new(w,   Rect(210, 55, 50, 150)); // Slider
d = Slider2D.new(w, Rect(5, 5, 200, 200));   // Slider2D
	
// ------------------------------ Operazioni di basso livello

b.action_({arg i; ~synth.set(\velX,i.value.linlin(0,1,0.1,5),  // solo al Synth
                             \velY,i.value.linlin(0,1,0.1,5))});
c.action_({arg i; ~synth.set(\sprdX,i.value,\sprdY,i.value)});
	
OSCFunc.new({arg msg;
                    {d.x_(msg[3].linlin(-1,1,0,1));            // solo all'interfaccia
                     d.y_(msg[4].linlin(-1,1,0,1))}.defer(0);
                     },'/pos', s.addr);
	
MIDIIn.connectAll;                                
MIDIdef.cc(\knob, {arg val;                  
                   ~synth.set(\velX,val.linlin(0,127,0.1,5),  // al Synth
                              \velY,val.linlin(0,127,0.1,5)); 
                   {b.value_(val.linlin(0,127,0,1))}.defer(0) // al Knob                 
                   }, 16);                                    // dal cc 16
MIDIdef.cc(\slid, {arg val;                  
                   ~synth.set(\sprdX,val.linlin(0,127,0,1),   // al Synth
                              \sprdY,val.linlin(0,127,0,1));
                   {c.value_(val.linlin(0,127,0,1))}.defer(0) // allo Slider
                   }, 0);                                     // dal cc 0
)

Inviluppi

(
var w,b,d;     // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\penvi,
              {arg t_gate=0;
               var sig,x,xbpf,xsenv,y,ybpf,ysenv,pan;
                   sig = SinOsc.ar;

                   x   = Env.newClear(4);          // Crea un inviluppo vuoto di 4 nodi
                   xbpf= \x.kr(x.asArray);         // Crea un controllo dell'inviluppo
                   xsenv= EnvGen.kr(xbpf, t_gate); // Genera l'inviluppo

                   y   = Env.newClear(4);
                   ybpf= \y.kr(y.asArray);
                   ysenv= EnvGen.kr(ybpf, t_gate);

                   pan = Pan4.ar(sig,xsenv,ysenv);
			       SendReply.kr(Impulse.kr(50), '/pos', [xsenv,ysenv]);
               Out.ar(0,pan)
               }
          ).add;


{~synth = Synth(\penvi)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 210@210);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;d.free;a.free});

d = Slider2D.new(w, Rect(5, 5, 200, 200)); // Slider2D

OSCFunc.new({arg msg;
                    {d.x_(msg[3].linlin(-1,1,0,1));            
                     d.y_(msg[4].linlin(-1,1,0,1))}.defer(0);
                     },'/pos', s.addr);
)

// ------------------------------ Sequencing

(
h = 2;                                     // Definiamo una durata
u = {[{rand2(1.0)}!4, {rand(0.5)}!3]}!2;   // generiamo i valori di x e y
u.postln;                                  // stampa i valori
x = Env.new(u[0][0],u[0][1]).duration_(h); 
y = Env.new(u[1][0],u[1][1]).duration_(h); 
[x,y].plot;                               // Plotter
~synth.set(\x, x, \y, y, \t_gate,1);      // li inviamo al Synth
)

Mouse

(
SynthDef(\pmouse,
              {var sig,x,y,pan;
                   sig = SinOsc.ar;
                   x   = MouseX.kr(-1,1);
                   y   = MouseY.kr(-1,1); // vicino in basso
                   pan = Pan4.ar(sig,x,y);
               Out.ar(0,pan)
               }
          ).add;

{a = Synth(\pmouse)}.defer(0.1);
)

Sistemi circolari

Client side

//====================================================================

// Strumento

s.boot;
s.scope(6);
s.meter(6,6);

(
var w,b,c,d,e,f,g,thetaO=0,rhoO=1;             // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\esaf,
              {arg pos= 0,lev=1,dist=1,orient=0.5,smt=0.2;
               var nchans=6,sig,pan;
                   sig = SinOsc.ar(Rand(400,2000));
                   pan = PanAz.ar(nchans,
                                  sig,
                                  pos.lag(smt),
                                  lev.lag(smt),
                                  dist.linexp(0,1,nchans,2).lag(smt),
                                  orient);
               Out.ar(0,pan)
               }
        ).add;

{~synth = Synth(\esaf)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 250@220);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;b.free;c.free;d.free;e.free;f.free;g.free});

b = NumberBox.new(w, Rect(48, 195, 50, 20)).value_(0);   // NumberBox theta
c = NumberBox.new(w, Rect(140, 195, 50, 20)).value_(0);  // NumberBox rho
d = StaticText.new(w, Rect(10, 198, 180, 15))            // Static text
 .string_("theta:                  rho:");
e = Slider2D.new(w, Rect(10, 10, 180, 180))              // Slider2D
 .x_(0.5).y_(1);
f = Knob.new(w, Rect.new(195,10,50,50));
g = Slider.new(w, Rect.new(195,90,50,100));

// ------------------------------ Operazioni di basso livello

~ksynth = {arg theta=0, rho=1, dur=1,defId=0.01,smth=0.2;
           var range,nPassi,thetaPasso,rhoPasso,dPasso;
               range  = abs(thetaO-theta);
               nPassi = 1/defId;
               thetaPasso = Array.interpolation(nPassi,0,1) // Passaggi di theta
                                 .normalize(thetaO,theta);
               rhoPasso = Array.interpolation(nPassi,0,1)   // Passaggi di rho
                               .normalize(rhoO,rho);
               dPasso = dur/nPassi;

Routine.new({
             thetaPasso.do({arg item,id;
                            ~synth.set(\pos,item,\dist,rhoPasso[id]);  // al Synth (+/-1)
                             {b.value_(item);                          // alle diverse GUI
                              c.value_(rhoPasso[id]);                  

                              e.x_((rhoPasso[id] * cos(item -0.5* -pi)).linlin(-1,1,0,1)) 
                               .y_((rhoPasso[id] * sin(item -0.5* -pi)).linlin(-1,1,0,1));
                              f.value_(item);
                              g.value_(rhoPasso[id]);
                              }.defer(0);
				
                             thetaO = item;                         // resetta all'ultimo valore
                             rhoO   = rhoPasso[id];
                             dPasso.wait
                            })
             }).play
           };

f.action_({arg val;
           thetaO = val.value;
           ~synth.set(\pos,thetaO*2-1);                      // al Synth
           {b.value_(thetaO*2-1);                            // alle diverse GUI
            c.value_(rhoO);
            e.x_((rhoO * cos(thetaO*2-1 -0.5* -pi)).linlin(-1,1,0,1));
            e.y_((rhoO * sin(thetaO*2-1 -0.5* -pi)).linlin(-1,1,0,1))
            }.defer(0)
           });

g.action_({arg val;
          rhoO = 1-val.value;
          ~synth.set(\dist,rhoO);                           // al Synth
          {b.value_(thetaO*2-1);                            // alle diverse GUI
           c.value_(rhoO);
           e.x_((rhoO * cos(thetaO*2-1 -0.5* -pi)).linlin(-1,1,0,1));
           e.y_((rhoO * sin(thetaO*2-1 -0.5* -pi)).linlin(-1,1,0,1))
           }.defer(0)
          });

MIDIIn.connectAll;
MIDIdef.cc(\knob, {arg val;
                   thetaO = val;
                   ~synth.set(\pos,thetaO/127*2-1);         // al Synth
                   {b.value_(thetaO/127*2-1);               // alle diverse GUI
                    c.value_(rhoO/127);
                    e.x_((rhoO/127 * cos(thetaO/127*2-1 -0.5* -pi)).linlin(-1,1,0,1));
                    e.y_((rhoO/127 * sin(thetaO/127*2-1 -0.5* -pi)).linlin(-1,1,0,1));
                    f.value_(thetaO/127);
                    }.defer(0)
                   }, 16);                                  // dal cc 16

MIDIdef.cc(\slid, {arg val;
                   rhoO = val;
                   ~synth.set(\dist,rhoO/127);              // al Synth
                   {b.value_(thetaO/127*2-1);               // alle diverse GUI
                    c.value_(rhoO/127);
                    e.x_((rhoO/127 * cos(thetaO/127*2-1 -0.5* -pi)).linlin(-1,1,0,1));
                    e.y_((rhoO/127 * sin(thetaO/127*2-1 -0.5* -pi)).linlin(-1,1,0,1));
                    g.value_(rhoO/127);
                    }.defer(0)
                   }, 0);                                   // dal cc 0
)
//====================================================================

// Controlli

// ------------------------------ Singolo valore

~ksynth.value(0.00,1,1);
~ksynth.value(0.25,1,1);
~ksynth.value(0.50,1,1);
~ksynth.value(0.75,1,1);
~ksynth.value(1.00,1,1);
~ksynth.value(1.25,1,1);
~ksynth.value(1.50,1,1);
~ksynth.value(1.75,1,1);
~ksynth.value(2.00,1,1);

~ksynth.value(0,0,1);
~ksynth.value(rand2(1.0),rand(1.0),rrand(0.1,2))

// ------------------------------ Sequencing

// Deterministico

(
var pos;
    pos = [[0,1,1],[-0.4,0.4,0.3],[-0.6,0.3,2],[0,0.4,1],[1,0,3],[-1,1,5]]; // [x,y,time]

h = Routine.new({
                 pos.do({arg i;
                         ~ksynth.value(i[0],i[1],i[2]);
                         i[2].wait
                         })
                 }).reset.play;
)

h.stop;

// Non deterministico

(
var theta,rho,dur;

h = Routine.new({
                 inf.do({theta = rand2(1.0);  
                         rho = rand(1.0);
                         dur = rrand(0.01,3);
                         ~ksynth.value(theta,rho,dur);
                         dur.wait                
                         })
                  }).reset.play
)

h.stop;

// ------------------------------ Rota

// Senso orario
(
var dur, valO;
    dur  = 1;    // tempo di giro in secondi
    valO = 0;   // posizione iniziale   
h = Routine.new({
                 inf.do({
		                 valO = valO+2;
		                 ~ksynth.value(valO,1,dur);
		                 dur.wait;
                         })

                 }).reset.play;
)

h.stop;
h.reset.play;

// Senso antiorario
(
var dur, valO;
    dur  = 1;    // tempo di giro in secondi
    valO = 0;   // posizione iniziale   
h = Routine.new({
                 inf.do({
		                 valO = valO-2;
		                 ~ksynth.value(valO,1,dur);
		                 dur.wait;
                         })

                 }).reset.play;
)

h.stop;
h.reset.play;

// ------------------------------ Spreading

(
var rth,rrh,dur,smt;
    rth = [0,0.5];
    rrh = [1,0.5];
    dur = 0.1;
    smt = 0.1;  // prova a cambiare

~ksynth.value(smt:smt);

h = Routine.new({
                 inf.do({var theta,rho;
                         theta = rrand(rth[0],rth[1]);
                         rho = rrand(rrh[0],rrh[1]);
                         ~ksynth.value(theta,rho,dur);
                         dur.wait
                         })
                 }).reset.play
)

h.stop;

// ------------------------------ Interazione MIDI

// Utilizza un Knob sul cc 16 per la psozione sull'asse x e un fader sul cc 0 per l'a distanza'asse y

Server side

Segnali di controllo

(
var w,d,a;                  // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\circ_sig,
              {arg tipoS=0,velS=1,sprdS=1,initpoS= 0,
                   lev = 1,
                   tipoD=0,velD=1,sprdD=1,initpoD=1,
                   orient=0.5,
                   smt=0.2;
               var nchans=6,sig,pos,dist,pan;
                   sig = SinOsc.ar(Rand(400,2000));
                   pos   = Select.kr(tipoS,[LFSaw.kr(velS,initpoS,sprdS),    // orario
                                            LFSaw.kr(velS,initpoS,sprdS)* -1,// antiorario
                                            SinOsc.kr(velS,initpoS,sprdS),
                                            LFNoise1.kr(velS,sprdS),
                                            LFNoise2.kr(velS,sprdS)
                                           ]);
                   dist = Select.kr(tipoD,[initpoD.lag(smt),              // fissa
                                           LFTri.kr(velD,initpoD,sprdD),
                                           SinOsc.kr(velD,initpoD,sprdD),
                                           LFNoise1.kr(velD,sprdD),
                                           LFNoise2.kr(velD,sprdD),
			                              ]);
                   SendReply.kr(Impulse.kr(50), '/pos', [pos,dist]);
                   pan = PanAz.ar(nchans, sig, pos, lev.lag(smt),
                                  dist.linexp(0,1,nchans,2),             // riscalato
                                  orient);
               Out.ar(0,pan)
               }
        ).add;

{~synth = Synth(\circ_sig)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 270@210);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;b.free;c.free;d.free});

b = Knob.new(w,     Rect(210, 5, 50, 50));   // Knob
c = Slider.new(w,   Rect(210, 55, 50, 150)); // Slider
d = Slider2D.new(w, Rect(5, 5, 200, 200));   // Slider2D

// ------------------------------ Operazioni di basso livello

b.action_({arg i; ~synth.set(\velS,i.value.linlin(0,1,0.1,5),  // solo al Synth
                             \velD,i.value.linlin(0,1,0.1,5))});
c.action_({arg i; ~synth.set(\tipoD,0,\initpoS,i.value,\initpoD,i.value)});

OSCFunc.new({arg msg;

           {b.value_(msg[3]);                                 // alle diverse GUI
            c.value_(msg[4]);
            d.x_((msg[4] * cos(msg[3] -0.5* -pi)).linlin(-1,1,0,1));
            d.y_((msg[4] * sin(msg[3] -0.5* -pi)).linlin(-1,1,0,1))
            }.defer(0)

            },'/pos', s.addr);

MIDIIn.connectAll;
MIDIdef.cc(\knob, {arg val;
                   ~synth.set(\velS,val.linlin(0,127,0.1,5),
                              \velD,val.linlin(0,127,0.1,5));
                   {b.value_(val.linlin(0,127,0,1))}.defer(0) // al Knob
                   }, 16);                                    // dal cc 16
MIDIdef.cc(\slid, {arg val;
                   ~synth.set(\tipoD,0,                       // al Synth
                              \initpoS,val.linlin(0,127,0,1),
                              \initpoD,val.linlin(0,127,0,1));
                   {c.value_(val.linlin(0,127,0,1))}.defer(0) // allo Slider
                   }, 0);                                     // dal cc 0
)

Inviluppi

(
var w,d;                  // variabili locali

// ------------------------------ SynthDef e Synth

SynthDef(\circ_sig,
              {arg t_gate,
                   lev = 1,
                   orient=0.5,
                   smt=0.2;
               var nchans=6,sig,
                   pos,posbpf,posEnv,
                   dist,distbpf,distEnv,
                   pan;

                   sig = SinOsc.ar(Rand(400,2000));

                   pos   = Env.newClear(4);           // Crea un inviluppo vuoto di 4 nodi
                   posbpf= \pos.kr(pos.asArray);      // Crea un controllo dell'inviluppo
                   posEnv= EnvGen.kr(posbpf, t_gate); // Genera l'inviluppo
  
                   dist = Env.newClear(4);
                   distbpf= \dist.kr(dist.asArray);
                   distEnv= EnvGen.kr(distbpf, t_gate);

                   SendReply.kr(Impulse.kr(50), '/pos', [posEnv,distEnv]);
                   pan = PanAz.ar(nchans,
                                  sig,
                                  posEnv,
                                  lev.lag(smt),
                                  distEnv.linexp(0,1,nchans,2),
                                  orient);
               Out.ar(0,pan)
               }
        ).add;

{~synth = Synth(\circ_sig)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 210@210);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;b.free;c.free;d.free});

d = Slider2D.new(w, Rect(5, 5, 200, 200));   // Slider2D

// ------------------------------ Operazioni di basso livello

OSCFunc.new({arg msg;
             {d.x_((msg[4] * cos(msg[3] -0.5* -pi)).linlin(-1,1,0,1));
              d.y_((msg[4] * sin(msg[3] -0.5* -pi)).linlin(-1,1,0,1))}.defer(0)
             },'/pos', s.addr)
)

// ------------------------------ Sequencing

(
var pos,dist;
h = 2;                                         // Definiamo una durata
p = [{rand2(1.0)}!4, {rand(0.5)}!3];           // generiamo i valori di pos
d = [{rand2(1.0)}!4, {rand(0.5)}!3];           // generiamo i valori di dist
pos  = Env.new(p[0],p[1]).duration_(h);
dist = Env.new(d[0],d[1]).duration_(h);
[pos,dist].plot;                               // Plotter
~synth.set(\pos, pos, \dist, dist, \t_gate,1); // li inviamo al Synth
)

Mouse

(
var w,d;                  // variabili locali

// ------------------------------ SynthDef e Synth
SynthDef(\pmouse,
              {var nchans=6,sig,pos,dist,pan;
                   sig = SinOsc.ar;
                   pos  = MouseX.kr(-5,5);    // numero di giri sull'asse x
                   dist = MouseY.kr(0,1);
                   SendReply.kr(Impulse.kr(50), '/pos', [pos,dist]);
                   pan = PanAz.ar(nchans,sig,pos,1,dist.linexp(0,1,nchans,2));
               Out.ar(0,pan)
               }
          ).add;

{a = Synth(\pmouse)}.defer(0.1);

// ------------------------------ GUI

w = Window.new("Pan", 210@210);
w.alwaysOnTop;
w.front;
w.onClose_({~synth.free;w.free;b.free;c.free;d.free});

d = Slider2D.new(w, Rect(5, 5, 200, 200));   // Slider2D

// ------------------------------ Operazioni di basso livello

OSCFunc.new({arg msg;
             {d.x_((msg[4] * cos(msg[3] -0.5* -pi)).linlin(-1,1,0,1));
              d.y_((msg[4] * sin(msg[3] -0.5* -pi)).linlin(-1,1,0,1))}.defer(0)
             },'/pos', s.addr)
)

SplayAz

(
SynthDef(\stereo,
              {arg sprd,ctr=0;
               var nchans=6,sig,width,lev=1,orient=0.5,pan;
		           sig = [SinOsc.ar(800),Saw.ar(1000),WhiteNoise.ar];
		           width = MouseX.kr(2,6);
		           sprd = MouseX.kr(0,1);
                   pan = SplayAz.ar(nchans, // numero di canali del sistema
                                    sig,    // Array di canali mono
                                    sprd,   // spread 0 = tutti al centro
                                    lev,    // ampiezza globale (0. / 1.)
                                    width,  // su quanti canali i segnali sono distribuiti
                                    ctr,    // shift dal centro
                                    orient, // orientazione
                                    true);  // limiter...
               Out.ar(0,pan)
               }
        ).add;

{~synth = Synth(\stereo)}.defer(0.1);
)