Fonctions et abstraction

Abstraction des données

Sonic-Pi repose sur un véritable language de programmation : Ruby. Une large partie des fonctionnalités consacrées à la manipulation des données existe et Sonic-Pi est parfois utilisé pour enseigner les rudiments de la programmation et de l’informatique à des enfants. Je ne suis pas spécialiste dans le domaine et il est possible que ma manière de décrire et de nommer les choses soit en contradiction avec la nomenclature habituelle du monde de la programmation. J’exposerai pourtant dans cet article le peu que je sais de l’abstraction des données dans Sonic-Pi.

Pour mes lecteurs issus du monde de la programmation et de l’informatique, sachez que beaucoup des fonctionnalités de Sonic-Pi dans le domaine ne sont pas réellement issues du Ruby mais en sont en quelque sorte des dérivés. La librairie standard de Ruby devrait — théoriquement — plus ou moins fonctionner, sauf mentions contraires que je vais expliciter.

[ Cette partie du guide sera révisée pour inclure des informations techniques et de plus en plus fiables sur le fonctionnement de SP]

Utilisation de variables pour partager les données

Le degré zéro de l’abstraction dans Sonic-Pi consiste à nommer certaines données comme variables pour pouvoir ensuite les ré-employer et les invoquer à l’aide de leur nom dans différentes parties du code. Vous pouvez nommer et stocker dans une variable tout type de données (listes, nombres entiers, nombres décimaux, anneaux, etc…)


live_loop :mes_notes do notes = [:c4, :e4, :g4] play notes[0] ; sleep 0.25 play notes[1] ; sleep 0.25 play notes[2] ; sleep 0.25 end

Cet exemple brille par son ineptie conceptuelle, mais sa clarté pédagogique. Après avoir nommé une liste contenant une série de notes, je me suis servi du nom et de l’index pour appeler l’une des notes. Voici un exemple déjà plus intéressant :


ma_gamme_favorite = [:c, :d, :e, :fs, :g, :a, :bb] live_loop ma_gamme do play ma_gamme_favorite[[1, 3, 4, 8].choose], release: 0.125 sleep 0.25 end

Remarquez que la déclaration de ma gamme se situe en dehors du live_loop et que nous y avons tout de même accès. Vous pouvez ainsi partager certaines données situées dans le scope global, à savoir, le plus bas niveau possible de votre code.

Fonctions

Nommer des listes, des variables, ou tout autre élément est une chose. Mais pouvons-nous faire plus intéressant et plus utile ? Les fonctions sont sans doute les abstractions les plus utiles et les plus élégantes à utiliser pour vos improvisations. Définir hâtivement une fonction consisterait à dire qu’il s’agit d’un fragment de code réutilisable. Dans l’essentiel des cas, une fonction recevra une série d’arguments qui permettront d’informer le code qu’elle contient (données à utiliser pour interpréter le code).

Dans l’exemple suivant, je déclare deux fonctions, boum et bam. Le contenu importe peu et je vous encourage à vous concentrer sur la syntaxe. Une fonction est déclarée de la sorte : define :nom do |arguments| -> end.


define :boum do sample :perc_door sleep 1 end define :bam do sample :perc_swash sleep 1 end boum bam

define me permet de définir une série d’instructions. Je peux ensuite y référer en invoquant le nom de la fonction lorsque celle-ci est demandée. Pour toute une série de raisons techniques, define n’est pas le mot clef utilisé par Ruby pour déclarer une fonction mais un nouveau type de déclaration de fonction propre à Sonic-Pi.

L’exemple précédent est un premier pas vers la construction d’abstractions plus utiles. Avoir sous le coude une série de fonctions personnalisées permet de très facilement préparer au préalable certains éléments que vous pourrez charger dans un buffer et utiliser lors de vos improvisations. Cela permet d’éviter d’avoir à tout redéfinir à chaque session, ou de sauvegarder certaines fonctions utiles.

Reprenons l’exemple précédent et observons maintenant comment entrer nos propres arguments. Ils sont toujours notés entre | | et séparés par une virgule. Nous indiquerons ici un temps de sommeil propre à chaque fonction.


define :boum do |t| sample :perc_door sleep t end define :bam do |t| sample :perc_swash sleep t end boum 1 bam 1.25 bam 0.25 ; bam 0.10 ; bam 0.05

Nous n’avons pas toutefois franchi le cap de la construction d’une abstraction véritablement utile. Pourquoi ne construirions-nous pas un synthétiseur ? Nous pouvons stocker nos expériences de synthèse dans une fonction et les utiliser ensuite dans nos live_loops.


define :mon_synthe do |note, a, d, s, r, cutoff| use_synth :saw use_synth_defaults cutoff: cutoff, release: 0.1 play note, attack: a, decay: d, sustain: s, release: r end live_loop :test do ; tick play mon_synthe :c4, 0, (line 0, 0.2, steps: 5).look, 0, 0, [50, 90, 100].choose sleep 0.125 end

N’hésitez pas à passer plusieurs heures à trouver des combinaisons agréables, à construire des fonctions utiles, des machines, ou toute autre idée. Une fois que celle-ci sera prête à l’emploi, vous n’aurez plus qu’à la stocker et vous l’aurez sous la main pour toujours. En personnalisant votre utilisation de Sonic-Pi, vous pouvez créer une petite librairie personnelle qui vous permettra d’être plus rapide, plus efficace, et d’obtenir des résultats musicaux plus intéressants.

Il est possible d’appeller une fonction dans une fonction, sous condition que la fonction appellée se situe en amont de la fonction que vous êtes en train de définir :


define :mon_synthe do |note, a, d, s, r, cutoff| use_synth :saw use_synth_defaults cutoff: cutoff, release: 0.1 play note, attack: a, decay: d, sustain: s, release: r end define :supra_synthe do |note, a, d, s, r, cutoff| play mon_synthe note, a, d, s, r, cutoff play mon_synthe note + 5, a, d, s, r, cutoff end live_loop :test do ; tick play supra_synthe :c4, 0, (line 0, 0.2, steps: 5).look, 0, 0, [50, 90, 100].choose sleep 0.125 end

More Songs about Functions and Arguments

Vous pouvez attribuer à vos arguments une valeur par défaut. Cela empêchera parfois de tomber sur une erreur en plein jeu :


define :boy do |note = :c3, a = 1, d = 1, s = 0.5, r = 0.5| play :c4, attack: a, decay: d, sustain: s, release: r end live_loop :wooh do; tick boy ; sleep 0.5 end

Vous pouvez également utiliser la véritable syntaxe propre aux fonctions en Ruby. Beaucoup d’exemples avancés fournis par des utilisateurs du forum in_thread en témoignent.

 

Ajout permanent d’une abstraction

Vous allez parfois écrire des fonctions si pratiques que vous souhaiterez les avoir toujours sous la main à votre disposition. Il existe un mécanisme prévu à cet effet, le fichier init.rb. L’extension .rb signifie qu’il s’agit d’un fichier texte Ruby, le langage de Sonic-Pi. Ce fichier se situe généralement dans le dossier d’installation de Sonic-Pi ou au même niveau. Pour l’utilisateur d’un système Unix, ce sera typiquement votre /home/. Pour un utilisateur Windows, il s’agira de là où vous l’avez installé.

Maintenant que vous connaissez son existence, vous pouvez en profiter pour stocker tout ce dont vous avez besoin mais que vous ne souhaitez pas voir apparaître dans votre buffer de texte :

  • la déclaration de vos dossiers d’échantillons.
  • vos synthétiseurs personnels
  • quelques machines spéciales dont vous vous servez souvent.
  • la déclaration d’un module externe (vous verrez cela plus tard)

Quelques notes supplémentaires

Ces mécanismes d’abstraction sont dans une très large mesure hérités de Ruby. Si certains d’entre vous sont habitués aux langages de programmation, vous aurez très certainement eu l’envie de commencer à utiliser de la programmation orientée objet dans Sonic-Pi (OOP). Au risque de vous déçevoir, il n’est pas véritablement possible d’utiliser les classes dans Sonic-Pi. S’il hérite d’une partie des fonctionnalités du Ruby, il ne les reproduit pas toutes.

Je ne peux vous conseiller que d’essayer d’employer certaines des fonctionnalités que vous souhaitez utiliser et de voir si oui ou non il est possible de les employer. Certains utilisateurs, sur le forum officiel, ont déjà fait montre de leur ingéniosité pour contourner les limitations imposées par Sonic-Pi. L’un d’entre eux se débrouille même pour utiliser les classes.

Cela ne signifie pas que Sonic-Pi est figé dans un état fixe. Voyez la section consacrée aux modules pour découvrir certains packages prévus pour étendre les possibilités de Sonic-Pi.

Comme toujours, nous sommes ici en survol rapide d’une partie spécifique du logiciel. Nous y reviendrons, consultez les sections ultérieures.