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

## Les fonctions sont mémorisées à travers des runs

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`).

## 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 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 !