S4) Les backticks
Quand BPscript ouvre une fenêtre
Du code natif dans le flux temporel
BPscript fait une chose : ordonner des symboles dans le temps. Quand il faut du vrai code — définir un son, calculer une valeur — il ouvre une fenêtre vers un autre langage, puis la referme. Cette fenêtre, c’est le backtick.
Où se situe cet article ?
On a vu en S3 que chaque symbole appartient à un acteur, lequel désigne un runtime (environnement d’exécution en aval). Ici, on comprend comment BPscript transmet du code à ce runtime : les backticks.
Le principe : confier du code sans l’interpréter
Les backticks (` « ) délimitent du code que BPscript ne parse pas, ne comprend pas, ne valide pas. Il le transmet au runtime concerné, qui l’évalue.
Sa(vel:`rrand(40,127)`)
BPscript voit : « le symbole Sa a un paramètre vel dont la valeur est un fragment entre backticks ». Il confie rrand(40,127) au runtime de Sa, qui l’évalue et retourne un nombre. BPscript ne sait pas ce que rrand signifie — et n’a pas besoin de le savoir. Cette frontière nette est ce qui permet au langage de rester petit : il décrit le quand, le runtime décide du comment.
État actuel : aujourd’hui, l’évaluateur opérationnel est JavaScript, avec une sortie Web Audio. Les tags
sc:(SuperCollider),py:(Python) outidal:(TidalCycles) qu’on verra dans les exemples illustrent l’architecture cible — un même mécanisme de backticks, plusieurs runtimes possibles en aval — mais ces évaluateurs ne sont pas encore branchés.
Trois types de backticks
BPscript distingue trois types selon la position du backtick et la façon dont le runtime cible est désigné.
Inline — le runtime est implicite
À l’intérieur d’un appel de symbole, le runtime est celui du symbole : pas besoin de le préciser.
Sa(vel:`rrand(40,127)`) // le runtime de Sa évalue le fragment
Le compilateur sait quel runtime appeler — celui de l’acteur du symbole porteur.
Orphelin — en tête de scène, le tag est obligatoire
Quand un backtick n’est attaché à aucun symbole et se trouve en tête de scène (hors des règles), il faut indiquer explicitement à quel runtime il est destiné :
`sc: SynthDef(\sitar, { |freq, vel=80| ... }).add` // → SuperCollider
`py: import dmx; d = dmx.open()` // → Python
Standalone — dans le flux, le tag est obligatoire
Quand un backtick non attaché apparaît à l’intérieur d’une règle, il s’exécute au temps de la dérivation où il se trouve. Le tag reste obligatoire :
melodie -> Sa(vel:`sc: i*20`) `sc: i=i+1` Re(vel:`sc: i*20`)
Le tag (sc:, py:, tidal:, js:…) précède le code, séparé par un :. Sans tag, le compilateur ne sait pas où envoyer le code — c’est une erreur. Seul le type inline en dispense, parce que le symbole porteur fournit déjà le runtime.
Trois usages
Les trois types correspondent à trois moments dans la vie d’une scène.
1. Init — préparer le runtime, avant la dérivation
Les backticks orphelins, en tête de scène, sont exécutés une fois au chargement, avant toute règle :
`js: synth = makeGrainSynth()`
C’est là qu’on prépare le terrain : définir un synthétiseur, importer une bibliothèque, initialiser une variable.
2. Flux — au moment de la dérivation
Un backtick standalone, au milieu d’une séquence, s’exécute au temps où la dérivation l’atteint :
melodie -> Sa(vel:`js: i*20`) `js: i=i+1` Re(vel:`js: i*20`)
Ici, ` js: i=i+1 ` est un événement de durée nulle dans le flux : il s’exécute entre deux notes, au moment précis calculé par BP3, et modifie l’état du runtime.
3. Résolution — évaluer et retourner une valeur
Un backtick inline, dans un appel, calcule la valeur d’un paramètre :
Sa(vel:`rrand(40,127)`) // le runtime évalue et retourne un entier
Sa(vel:120) // pas de backtick → littéral, aucune évaluation
La résolution est un aller-retour : BPscript envoie l’expression, le runtime l’évalue et retourne la valeur, BPscript l’injecte dans le paramètre. C’est le seul cas où une réponse est attendue ; l’init et le flux sont des envois sans retour (fire-and-forget).
Variables, portées et isolation
Le modèle prévoit que chaque runtime maintienne sa propre session persistante — comme un REPL (Read-Eval-Print Loop, une console interactive) qui reste ouverte pendant toute la scène. Une variable y vit dans la portée de son runtime :
`js: var i = 0` // portée du runtime : i = 0
Sa(vel:`js: i`) `js: i = i + 1` Re(vel:`js: i`)
// i persiste d'un backtick à l'autre, dans la même session
Dans l’architecture cible, plusieurs runtimes coexistent sans état partagé : une variable définie dans l’un n’est pas visible dans l’autre. La coordination entre eux ne passe pas par des variables, mais par les mécanismes propres à BPscript :
- les flags (gérés par BP3 — voir S6) ;
- les triggers
!et<!(voir S7).
C’est une isolation voulue : chaque runtime est un bac à sable, sans couplage caché ni effet de bord d’un langage sur l’autre.
Un fichier sans backticks reste portable
Un fichier .bps sans aucun backtick ne dépend d’aucun langage externe : sa structure est pure.
@tempo:120
S -> { melodie, rythme }
melodie -> Sa Re Ga Pa
rythme -> -!dha - -!ti -!dha
Un tel fichier fonctionne avec n’importe quel adaptateur (programme qui traduit les événements BPscript en commandes pour un runtime) capable de recevoir des gates et des triggers — Web Audio aujourd’hui, d’autres demain. Dès qu’on ajoute un backtick, on lie une partie du fichier à un runtime précis : c’est un compromis assumé entre puissance et portabilité.
Ce qu’il faut retenir
- Les backticks délimitent du code que BPscript n’interprète pas — il le transmet au runtime
- État actuel — l’évaluateur opérationnel est JS / Web Audio ; les tags
sc:/py:/tidal:illustrent l’architecture cible, pas encore branchée - Trois types — inline (dans un appel, runtime implicite), orphelin (en tête de scène, tag obligatoire), standalone (dans le flux, tag obligatoire)
- Trois usages — initialisation, exécution au moment de la dérivation, calcul d’un paramètre
- Sessions persistantes — chaque runtime garde son état ; les variables y vivent dans leur propre portée
- Pas d’état partagé entre runtimes — la coordination passe par les flags et les triggers
- Sans backtick = portable — la structure ne dépend d’aucun langage externe
Glossaire
- Backtick : caractère `
« délimitant du code natif destiné à un runtime — BPscript le transmet sans l’interpréter - Backtick inline : backtick dans un appel de symbole — le runtime est déduit du symbole, pas de tag
- Backtick orphelin : backtick en tête de scène, non attaché à un symbole, exécuté à l’init — nécessite un tag de runtime
- Backtick standalone : backtick dans le flux d’une règle, exécuté au moment de la dérivation — nécessite un tag de runtime
- Runtime : environnement d’exécution, en aval, qui évalue le code et produit le son
- REPL : Read-Eval-Print Loop — console interactive qui conserve un état entre les commandes
- Portée : zone de visibilité d’une variable — chaque runtime a la sienne, isolée des autres
- Adaptateur : programme qui traduit les événements horodatés de BPscript en commandes pour un runtime
Liens dans la série
- S3 — Types, actors et bindings — comment les types et runtimes sont déclarés
- S6 — Flags et parcours — la coordination par les flags
- S7 — L’instant partagé — la coordination par les triggers
!/<! - S9 — Le système de hauteurs en six couches — le routage vers les adaptateurs
- S10 — Sous le capot — comment le runtime aval reçoit les backticks
Prérequis : S3
Temps de lecture : 10 min
Tags : #BPscript #backticks #runtime #live-coding
Prochain article : S5 (à venir) — Structurer le temps : polymétrie, silences, vitesse