Fonctions

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.

Definition des fonctions

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.

Appel des fonctions

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éer de nouveaux mots significatifs à utiliser dans nos compositions.

Les fonctions sont mémorisées d’une exécution à l’autre

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 connait rien à part ce qui est dans le buffer. Vous ne pouvez 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).

Fonctions paramétrées

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 le mot de votre choix 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 !