REAPER – Créer des effets avec JSFX

Introduction

Reaper est un logiciel de production audio supportant plusieurs types de plugins: VST, DX, et JSFX (JS).
Contrairement aux premiers, les effets JSFX sont en réalité de simples scripts, qu’il est possible de modifier en temps réel via leur bouton « Edit ».
Screenshot bouton editer

Au premier abord, ce code peut paraître étrange, même quand on a l’expérience de langages comme Javascript ou C++. Les ressources officielles sur JSFX sont disponibles en anglais sur le site de Cockos: http://www.reaper.fm/sdk/js/js.php

Pour ceux qui connaissent ShaderToy ou Processing, JSFX est un équivalent audio, utilisable directement dans Reaper 🙂
Je m’y suis tout de même intéressé de plus près, et autant faire d’une pierre deux coups: j’ai décidé d’écrire
un article en français sur ce que j’apprend de cet outil 🙂

Note: je passe volontairement certaines parties présentées par la documentation officielle pour rester simple, j’aborderai ces détails peut-être plus tard.

Créer un effet

Pour créer un nouvel effet, ouvrez la fenêtre « Add FX », « File -> Create new JS FX… »
Screenshot create new JS effect

Choisissez le nom de votre effet:
Screenshot effect name

Reaper va créer votre effet avec quelques sliders de base, histoire de pas partir de rien.
Screenshot effect UI

Si vous le testez, évidemment, il ne fait rien de spécial. Pour ça, il va falloir mettre les mains dans le cambouis 😀
Cliquez sur Edit…
Screenshot default code

Décortiquons le code qui nous est fourni comme point de départ 🙂

Description

Chaque effet JS doit commencer par cette ligne:

desc:new effect

C’est une courte description qui sera utilisée comme nom dans la liste des effets.
Aussi, comme Reaper sauvegarde l’effet sans extension, c’est ce qui lui permet de savoir que le fichier est un effet JSFX.

Sliders

slider1:0<0,100,1>parameter1
slider2:0<0,100,1>parameter2
slider3:0<0,100,1>parameter3
slider4:0<0,100,1>parameter4
slider5:0<0,100,1>parameter5

S’ensuit une liste des sliders, qui définissent les paramètres que l’on peut changer en temps réel depuis l’interface ou automatiser.
En JS, ces paramètres portent forcément le nom « slider » suivi de leur numéro, même si leur valeur ne change qu’entre deux ou trois nombres.

La syntaxe d’un slider est la suivante:

slider[numéro]:[valeur par défaut]<[minimum], [maximum], [pas]>titre

Tous les sliders (et toutes les variables) sont des nombres flottants (à virgule).

Les sections de code

Une fois que l’on a défini une description et des paramètres, on peut implémenter des sections, ou des méthodes virtuelles pour ceux qui sont habitués à la programmation orienté objet 🙂

@init
bpos=0;
@slider
something=slider1*srate;

@block
blah+=samplesblock;

@sample
spl0=spl0;
spl1=spl1;

Ces sections sont appelées à des moments différents pour exécuter différentes tâches:

  • @init: appelé à chaque fois que l’on lance la lecture ou que l’on appuie sur CTRL+S dans l’éditeur de code
  • @slider: appelé après @init ou à chaque fois que l’utilisateur modifie un slider
  • @block: appelé pendant la lecture à chaque bloc de samples. Un bloc aura une taille différente en fonction de vos options, entre 128 et 2048.
  • @sample: appelé à chaque échantillon sonore (sample en anglais), le plus souvent 44100 fois par seconde. C’est le bloc le plus intéressant, car c’est ici que l’on peut modifier le son avec les variables spl0..spl63.

D’autres sections existent dans la doc, j’y reviendrai à l’occasion 🙂

Jouer avec le bloc @sample

Un moyen simple de commencer à modifier le son consiste à jouer un peu avec le bloc @sample.
Comme dit plus haut, dans ce bloc nous avons accès aux variables spl0 et spl1 (autant que de canaux, ici on s’intéressera seulement à la stéréo).
Ces variables contiennent la valeur des échantillons sonores que reçoit notre effet.

L’implémentation de base est la suivante:

spl0 = spl0;
spl1 = spl1;

Qui, vous l’aurez deviné, ne fait qu’envoyer en sortie ce qu’on reçoit en entrée.
Il est possible de faire des opérations sur ces variables comme dans tout langage de programmation:

// On inverse la stéréo, amplifie le canal gauche et atténue le droit
spl0 = spl1*2.0;
spl1 = spl0/0.5;

Note: on peut évidemment ajouter des commentaires avec // ou /* */ comme en Javascript.

On peut aussi créer des variables.
En JSFX, les variables sont déclarées comme en Python: elles existent à partir du moment où on leur donne une valeur.

volume = 0.5;
spl0 = spl0 * volume;
spl1 = spl1 * volume;

Pour rendre ça plus interactif, on peut aussi utiliser nos sliders. Par exemple, un effet qui contrôle juste le volume peut s’écrire ainsi:

slider1:100<0,100,1>Volume

@sample
k = slider1 / 100.0;
// On pourrait directement utiliser un slider entre 0 et 1, mais ce serait moins évident pour la plupart des utilisateurs.
spl0 = spl0 * k;
spl1 = spl1 * k;

Jusqu’à maintenant, on n’a défini de variables que dans @sample. Mais on peut aussi utiliser @init pour créer un compteur par exemple:

@init
compteur = 0;

@sample
compteur += 1; // On incrémente le compteur à chaque sample
// Et ici on se sert du compteur pour faire varier le volume par va-et-vient
k = 1 + 0.5 * sin(compteur / srate) // Coefficient entre 0 et 1
spl0 = spl0 * k;
spl1 = spl1 * k;

Vous remarquerez la présence d’une variable spéciale, srate. Elle est surlignée et visible dans le panneau latéral de l’éditeur (si, si, en scrollant en bas).
Screenshot srate

srate contient la fréquence d’échantillonage (sample rate en anglais). Si l’on revient au code d’exemple précédent, cela veut donc dire que compteur / srate sera équivalent au temps écoulé depuis le dernier appel à @init, en secondes 🙂

Vous pouvez aussi voir la valeur de compteur, plus haut:
Screenshot compteur

J’ai aussi utilisé la fonction sin, qui fait partie d’une longue liste de fonctions mathématiques de base que vous pouvez également utiliser ici.
Vous pouvez les retrouver dans la doc: http://www.reaper.fm/sdk/js/basiccode.php#js_basicfunc

Conditions

Nous avons vu comment modifier le son avec des formules simples, or il est aussi possible de réaliser des conditions, des if comme on fait dans pratiquement tous les langages.
Or, en JSFX, c’est un peu différent:

valeur > 50 ? truc = 5 : truc = 0;

Déroutant?
En JSFX, les conditions sont exprimées comme des ternaires.
On écrit une expression suivie d’un ?. Si l’expression ne retourne pas 0, l’instruction suivant le ? sera exécutée. Sinon, l’instruction suivant le : sera exécutée. Si on a rien à faire dans le second cas, on peut se passer du :, c’est optionnel.

Il est possible de grouper des instructions avec les parenthèses, ce qui donne une syntaxe peut-être plus familière:

valeur > 50 ? (
  // Si vrai
  truc = 5;
  k += 1;
) : (
  // Sinon
  truc = 0;
)

Tableaux

Tout langage de programmation permet d’utiliser des listes, arrays, vectors (appelez-ça comme vous voulez :p).
En JSFX, une nouvelle fois, la syntaxe est différente.

La doc nous dit ceci à propos des arrays:

A virtual local address space of about 8 million words, which can be accessed via brackets « [ » and « ] ».

Concrètement, cela signifie que l’on peut utiliser n’importe quelle variable comme une addresse dans un ensemble de valeurs que JSFX a créé pour nous (ça devrait parler aux adeptes du C/C++!).

compteur = 0;
// Si j'écris compteur[0], j'accèderai à la case 0.
compteur += 1
// Si j'écris compteur[0], j'accèderai à la case 1. compteur[-1] sera la valeur précédente, et compteur[1] celle d'après.

Voyons un exemple pratique sur ce système. Si on a besoin de mémoriser les derniers échantillons lus par l’effet et les restituer avec un retard, pour faire un écho par exemple, ça donnerait quelque chose comme ça:

@init
compteur = 0; // Compteur de samples
taille = srate ; // Taille de notre tableau, correspondant à 1 seconde d'audio (44100 échantillons)

@sample
compteur += 1; // On incrémente le compteur à chaque sample

// Si on arrive au bout du tableau, on recommence à zéro (notre tableau est cyclique).
compteur == taille ? compteur = 0;

// tableau contient en fait l'addresse à laquelle on se place, comme en C/C++.
// x2 car on est en stéréo (ce qui signifie qu'en fait on a 44100 couples de valeurs, donc un tableau de 88200 nombres)

tableau = compteur * 2;

// On ajoute le son mémorisé (l'écho), qui vaudra 0 au début tant que le tableau n'aura pas complété son premier cycle.
// Pour rester simple, on fait juste la moyenne des deux.

spl0 = (spl0 + tableau[0])/2 ;
spl1 = (spl1 + tableau[1])/2;

// on mémorise l'échantillon courant, qui sera restitué en tant qu'écho 44100 échantillons plus tard.
// Note: JSFX ajuste automatiquement la taille du tableau en fonction des accès.

tableau[0] = spl0;
tableau[1] = spl1;

To be continued

Ça commençait tout juste à devenir marrant, mais c’est maintenant que je vous laisse 🙂
J’ai encore à apprendre moi-même sur JSFX, j’espère que cet article vous a plu / aidé à rentrer dans le délire de cette fonctionnalité méconnue de Reaper.
J’écrirai une suite à l’occasion, je suis certain qu’il y a beaucoup d’autres sujets à aborder.
Bon bidouillage!

4 réflexions sur “REAPER – Créer des effets avec JSFX

  • 1 septembre 2016 à 16 h 51 min
    Permalien

    Sympa le tuto 🙂
    T’as déjà fait des JSFX spécial sagas audio ?

    Répondre
      • 2 septembre 2016 à 21 h 06 min
        Permalien

        haha oui je comprends, j’ai pas eu besoin d’en créer non plus pour de la saga audio,
        j’en utilise cependant quelques uns en saga audio, mais ils existaient déjà 😛
        Faut dire qu’au delà des effets audio, ça peut aussi gérer du routing, du MIDI, faire de l’analyse de signal… Il y a de quoi faire 🙂

        C’est surtout faire des ReaScripts qui m’a beaucoup aidé pour Alien2347 !

        (ps : je vois que ton site est sous WordPress, ce serait bien si tu pouvais installer un petit plugin pour pouvoir permettre à ceux qui commentent de s’abonner aux réponses. Tu peux garder le système de commentaires natif et utiliser un module type wpDiscuz – qui est très bien – pour gérer les abonnements, où les gérer ailleurs comme avec Disqus). 😛

        Répondre
  • 5 avril 2017 à 19 h 53 min
    Permalien

    merci pour ton tuto.
    j’ai fait quelque scripts en Python pour Reaper..plutot facile mais jsfx est plus difficile pour moi.
    j’essaie d’envoyer une note midi quand un slider est bouger.
    c’est pour utiliser dans Mux Modular (environnement vst modulaire).
    L’avantage du JSFX c’est qu’on peut l’utiliser dans n’importe quel host vst

    Répondre

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.