Funzioni

Quando cominci ad avere dei codici molto lunghi, potresti sentire il bisogno di organizzare e strutturare le cose per renderle più pulite e chiare da comprendere. Le funzioni sono un modo molto efficace per farlo. Ci consentono di dare un nome a un insieme di linee. Diamo un’occhiata a questa possibilità.

Definire le funzioni

define :foo do
  play 50
  sleep 1
  play 55
  sleep 2
end

Qui sopra, abbiamo definito una nuova funzione chiamandola ‘foo’. L’abbiamo fatto usando la nostra vecchia conoscenza, il blocco do/end, accoppiato alla parola magica ‘define’, seguita dal nome che abbiamo voluto dare alla funzione. Non dobbiamo per forza chiamarla ‘foo’ ma possiamo usare un nome qualsiasi, come ‘bar’, ‘baz’ o qualsiasi cosa che ci aiuti a ricordarne il ruolo, come ‘sezione_principale’ o ‘riff_principale’. Si può usare un termine in qualsiasi lingua.

Ricorda sempre di anteporre i due punti ‘:’ al nome della funzione quando vai a definirla.

Richiamare le funzioni

Una volta che abbiamo definito la nostra funzione, possiamo poi richiamarla semplicemente scrivendo il suo nome:

define :foo do
  play 50
  sleep 1
  play 55
  sleep 0.5
end
foo
sleep 1
2.times do
  foo
end

Possiamo utilizzare ‘foo’ anche dentro un blocco di iterazione o ovunque abbiamo scritto ‘play’ o ‘sample’. Questo ci permette di esprimere i nostri pensieri musicali e di creare delle parole con un senso preciso da utilizzare nelle nostre composizioni.

Le funzioni vengono ricordate anche in esecuzioni diverse

Fin qui, ogni volta che hai premuto Run, Sonic Pi ha iniziato da zero. Il sistema non conosceva niente più di quello che era scritto della finestra. Non puoi richiamare un codice tra una finestra e l’altra o tra un gruppo di codice e l’altro. Le funzioni sono diverse. Quando ne hai definita una, Sonic Pi si ricorda di lei. Prova. Cancella tutto il codice che hai scritto e sostituiscilo con questo:

foo

Premi Run e ascolta la fuzione in esecuzione. Dov’è finito il codice? Come fa Sonic Pi a sapere cosa eseguire? Sonic Pi, semplicemente, si ricorda della tua funzione, quindi anche se l’ha cancellata dalla finestra, si ricorda che cosa avevi digitato. Tutto ciò funziona soltanto se le funzioni sono state create utilizzando ‘define’ (e ‘defonce’).

Funzioni parametrizzate

Potresti essere interessato/a a sapere che, nello stesso modo in cui puoi passare da valori minimi a massimi o addittura casuali (‘rrand’), puoi insegnare alle tue funzioni ad accettare degli argomenti. Prova a dare un’occhiata a quanto segue:

define :my_player do |n|
  play n
end
my_player 80
sleep 0.5
my_player 90

Quanto presentato non è molto eccitante, ma illustra bene la questione. Abbiamo creato la nostra personale versione di ‘play’ chiamata ‘my_player’ che è stata poi sottoposta a dei parametri.

I parametri devono essere scritti successivmente al ‘do’ del blocco do/end ‘define’. Devono essere inclusi nelle barre verticali ‘ ’ ed essere separati dalle virgole ‘,’. Puoi usare una qualsiasi parola a tuo piacimento per dare il nome ai parametri.

La magia accade sempre all’interno del blocco do/end ‘define’. Puoi usare anche i nomi dei parametri come se fossero dei valori reali. Nell’esempio precedente noi stavamo suonando la nota ‘n’. Puoi considerare i parametri come una sorta di promessa che quando il codice è in esecuzione, essi verranno sostituiti con valori reali. Puoi fare ciò passando un parametro a una funzione quando lo richiami. Scrivendo il codice precedente, quanto detto è stato ottenuto digitando ‘my_player 80’ per suonare la nota corrispondente. All’interno della definizione della funzione, ‘n’ è sostituito con 80. Quindi se scrivi ‘play n’ la n verrà sostituita con 80. Se richiamassi di nuovo questa funzione scrivendo ‘my_player 90’, il valore n diventerebbe 90 e quindi scrivendo ‘play n’ otteniamo questa volta lo stesso suono di ‘play 90’.

Ma guardiamo un esempio più interessante:

define :chord_player do |root, repeats| 
  repeats.times do
    play chord(root, :minor), release: 0.3
    sleep 0.5
  end
end
chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3

Qui abbiamo digitato ‘repeats’ come se fosse un numero nella linea ‘repeats.times do’. Abbiamo inserito ‘roots’ come se fosse un nome di una nota all’interno dell’esecuzione di ‘play’.

Guarda come, grazie alle funzioni, riusciamo a scrivere qualcosa di molto espressivo, semplice da leggere e che compatta tutti i nostri ragionamenti!