Une fois que vous commencez à écrire beaucoup de code, vous pouvez souhaiter trouver le moyen d’organiser et de structurer les choses pour les rendre plus ordonnées et faciles à comprendre. Les fonctions sont un moyen très puissant pour le faire. Elles vous donnent la capacité de donner un nom à un morceau de code. Jetons-y un œil.
define :foo do
play 50
sleep 1
play 55
sleep 2
end
Ici, nous avons défini une nouvelle fonction appelée foo
. Nous
faisons cela avec notre vieil ami, le bloc do/end et le mot magique
define
suivi par le nom que nous voulons donner à notre fonction.
Nous ne sommes pas tenus de l’appeler foo
, nous aurions pu l’appeler
avec n’importe quel nom que nous voulions, comme bar
, baz
ou
idéalement quelque chose de significatif pour vous comme
section_principale
ou lead_riff
.
Rappelez-vous d’ajouter un deux-points :
devant le nom de votre
fonction quand vous la définissez.
Une fois que nous avons défini notre fonction, nous pouvons l’appeler simplement en écrivant son nom :
define :foo do
play 50
sleep 1
play 55
sleep 0.5
end
foo
sleep 1
2.times do
foo
end
Nous pouvons même utiliser foo
à l’intérieur de blocs d’itération
ou n’importe où nous aurions pu écrire play
ou sample
. Ceci nous
donne un super moyen de nous exprimer et de créér de nouveaux mots
significatifs à utiliser dans nos compositions.
Pour le moment, chaque fois que nous avons pressé le bouton Run, Sonic Pi a démarré d’un état complètement vierge. Il ne savait rien à part ce qui était dans le buffer. Vous ne pouviez pas référencer du code d’un autre buffer ou d’un autre thread. Toutefois, les fonctions changent cela. Quand vous définissez une fonction, Sonic Pi s’en rappelle. Essayons-le. Effacez tout le code dans votre buffer et remplacez-le par :
foo
Pressez le bouton Run et écoutez votre fonction qui est jouée. Où le
code est-il allé ? Comment Sonic Pi sait-il quoi jouer ? Sonic Pi s’est
simplement souvenu de votre fonction - ainsi, même après l’avoir
effacée de votre buffer, il se rappelle de ce que vous avez
tapé. Ce comportement fonctionne uniquement avec les fonctions créées
en utilisant define
(et defonce
).
Vous pourriez être intéressé à savoir que juste comme vous pouvez
passer les valeurs min et max à rrand
, vous pouvez apprendre à vos
fonctions à accepter des arguments. Jetons-y un œil.
define :my_player do |n|
play n
end
my_player 80
sleep 0.5
my_player 90
Ce n’est pas très excitant, mais ça illustre le point. Nous avons
créé notre propre version de play
appelée my_player
et qui est
paramétrée.
Les paramètres doivent être placés après le do
du bloc do/end de
define
, entourés par des barres verticales |
et séparés par des
virgules ,
. Vous pouvez utiliser tout mot que vous souhaitez pour les
noms de paramètres.
La magie se passe à l’intérieur du bloc do/end de define
. Vous
pouvez utiliser les noms de paramètres comme si c’étaient des valeurs
réelles. Dans cet exemple, je joue la note n
. Vous pouvez considérer
les paramètres comme une sorte de promesse qui fait que, lorsque le code
s’exécute, ils sont remplacés par des valeurs réelles. Vous faites
ceci en passant un argument à la fonction quand vous l’appelez. Je le
fais avec my_player 80
pour jouer la note 80. À l’intérieur de la
définition de la fonction, n
est alors remplacé par 80, donc
play n
est changé en play 80
. Quand je l’appelle une nouvelle fois
avec my_player 90
, n
est alors remplacé par 90, donc play n
est
changé en play 90
.
Voyons un exemple plus intéressant :
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
Ici j’ai utilisé repeats
comme si c’était un nombre dans la ligne
repeats.times do
. J’ai aussi utilisé root
comme si c’était un nom de
note dans mon appel à play
.
Voyez comme nous sommes capables d’écrire quelque chose de très expressif et facile à lire en déplaçant beaucoup de notre logique à l’intérieur d’une fonction !