S3) Types, actors et bindings

Comment BPscript sait ce qui occupe du temps, où l’envoyer, et à quelle fréquence

En eurorack, chaque câble porte un type de signal : gate, trigger ou CV. BPscript fait pareil avec ses symboles. Mais un câble va quelque part — et ce « quelque part » est défini par l’actor.

Où se situe cet article ?

On a vu en S2 que BPscript a trois mots-types : gate, trigger, cv. Ici on comprend pourquoi ces trois-là, et comment l’actor lie chaque symbole à son contexte complet : quel alphabet, quelle gamme, quelle sortie.


Trois types temporels

L’inspiration vient du monde modulaire (eurorack, synthèse analogique). Dans un synthétiseur modulaire, trois types de signaux circulent :

Signal Comportement Analogie musicale
Gate Tension haute tant que la touche est enfoncée Une note qui dure — début et fin
Trigger Impulsion brève, quasi-instantanée Un coup de caisse claire — on déclenche, ça ne « dure » pas
CV Tension qui varie continûment Un pitch bend, un crescendo — la valeur change

BPscript emprunte cette trichotomie parce qu’elle répond exactement à la question que l’ordonnanceur doit se poser : est-ce que ça occupe du temps ?

  • Un gate occupe du temps. Sa durée est calculée par BP3.
  • Un trigger n’occupe pas de temps. C’est un événement ponctuel — zéro durée.
  • Un cv occupe du temps ET sa valeur change pendant la durée.

Le problème : un alphabet ne suffit pas

Imaginons une scène avec deux musiciens. Ils jouent les mêmes notes (Sa, Re, Ga…) mais :

  • vont vers des sorties différentes (Web Audio vs MIDI canal 3)
  • utilisent des accordages différents (22 shruti vs 12-TET)
  • peuvent avoir des conventions d’octave différentes

Un simple binding alphabet → runtime (@alphabet.raga:sc) ne suffit pas pour distinguer deux instruments partageant le même vocabulaire. Il faut une unité qui regroupe toutes les couches de résolution d’un symbole. C’est l’actor.


L’actor : tout lier ensemble

L’actor est l’unité qui lie toutes les couches de résolution d’un symbole :

 

@actor sitar1  alphabet:sargam  scale:sargam_22shruti  transport:webaudio
@actor sitar2  alphabet:sargam  scale:sargam_12TET     transport:midi(ch:3)
@actor tabla   alphabet:tabla   sounds:tabla_perc      transport:midi(ch:10)
@actor lights  alphabet:dmx_cues                       transport:dmx

 

Un actor = alphabet + scale + sounds + transport (+ optionnellement eval pour les backticks).

Clé Obligatoire Rôle Exemple
alphabet oui Les noms de symboles disponibles alphabet:sargam
scale non Comment les degrés deviennent des fréquences (via le tempérament) scale:sargam_22shruti
sounds non Définitions par terminal : timbre, percussions, samples sounds:tabla_perc
transport oui Où envoyer les événements transport:webaudio
eval non Quel REPL évalue les backticks eval:sclang

Si scale est omis → pas de résolution de fréquence (percussions, DMX, lumières).
Si sounds est omis → le transport applique son rendu par défaut.
Si eval est omis → aucun REPL n’est associé : les backticks de cet acteur restent alors sans évaluateur (il faut déclarer eval pour les utiliser).


Résolution : implicite ou explicite

Résolution explicite — la notation pointée actor.terminal

Dans les règles, un terminal est qualifié par son actor via la notation pointée (dot notation) :

 

sitar1.Sa       // Sa résolu via sitar1 (sargam + 22 shruti + webaudio)
sitar2.Sa       // même note, autre actor (sargam + 12-TET + midi ch3)
tabla.tin       // tin résolu via tabla (tabla + midi ch10)
lights.spot     // spot résolu via lights (dmx)

 

Résolution implicite — quand c’est évident

Si un symbole n’apparaît que dans un seul actor, BPscript le résout automatiquement :

 

@actor sitar1  alphabet:sargam  scale:sargam_22shruti  transport:webaudio
@actor tabla   alphabet:tabla   sounds:tabla_perc       transport:midi(ch:10)

Sa Re Ga Pa    // → sitar1 (seul actor avec sa, re, ga, pa)
tin ta ke dha  // → tabla (seul actor avec tin, ta, ke, dha)

 

Pas besoin d’écrire sitar1. partout — le compilateur déduit.

Si un symbole apparaît dans plusieurs actors sans notation pointée explicite → erreur :

 

@actor sitar1  alphabet:sargam  ...
@actor sitar2  alphabet:sargam  ...

Sa Re Ga Pa    // Erreur : 'Sa' est dans sitar1 ET sitar2 — préciser l'actor

 


Import en bloc

Un @actor avec un alphabet importe tous les symboles de cet alphabet, liés à cet actor :

 

@actor sitar1  alphabet:sargam  scale:sargam_22shruti  transport:webaudio

// Sa, Re, Ga, Ma, Pa, Dha, Ni → automatiquement déclarés comme gate, liés à sitar1
// Pas besoin de "gate sitar1.Sa" pour chaque note

 

Surcharge individuelle possible via une déclaration explicite :

trigger dha:sitar1   // surcharge : dha est un trigger dans cet actor, pas un gate

 


Paramètres : () runtime vs [] moteur

Deux syntaxes pour deux destinations (S5) :

Syntaxe Destination Exemples
[] Moteur BP3 [speed:2], [weight:50], [tempo:2]
() Runtime (couche aval) (vel:80), (wave:sawtooth), (filter:300)

Les parenthèses () transportent les paramètres vers le runtime — BPscript ne les interprète pas, il les compile en contrôles opaques (_script(CT n)) que le runtime aval consomme :

 

Sa(vel:120)                      // symbole : vel=120 pour cette note
{A B C}(vel:80)                  // groupe : vel=80 pour tout le groupe
S -> A B (vel:120)               // règle : vel=120 en fin de RHS

 

Les crochets [] sont des instructions pour le moteur :

 

{A B C}[speed:2]                 // vitesse doublée (moteur)
S -> A B C [weight:3]            // poids de la règle (moteur)

 

La distinction est fondamentale : [] change le comportement du moteur (vitesse, poids, mode), () change le rendu par le runtime (vélocité, pan, instrument).


CV : valeurs continues

Certains gestes ne sont ni une note tenue ni une impulsion : un filtre qui s’ouvre, un crescendo, un vibrato. C’est ce que porte le cv — une valeur qui évolue pendant sa durée. Les objets CV sont déclarés en tête de scène et utilisés dans la grammaire comme des symboles ordinaires. La signature est nom(cible, transport) = lib.type(args) :

 

// Déclaration d'un CV — enveloppe ADSR ciblant le filtre, évaluée par SC
env1(filter, sc) = filter.adsr(10, 100, 0.7, 200)

// Utilisation dans une règle
S -> env1 Sa Re Ga Pa

 

Les CV couvrent plusieurs types : enveloppes ADSR, LFO (oscillateur basse fréquence), ramps (interpolation linéaire). Ils reçoivent leur durée de la grammaire et sont résolus dans la couche aval (S10).


La résolution de fréquence est en aval

Point important : Contrairement à l’écriture de grammaires BP3, ici on l’utilise uniquement en tant qu’ordonnanceur, donc BP3 ne traite pas les objets ordonnancés, les sons. Le compilateur lui transmet uniquement des noms opaques préfixés bol (bolSa, bolRe…). BP3 dérive la structure temporelle ; il ne sait ni quel actor, ni quel accordage, ni quelle sortie.

La traduction d’un symbole en hertz se fait dans la couche aval (le runtime), via un système de hauteurs en 6 couches :

 

Layer 0 — Acteur     : quel contexte de résolution (sitar1 vs sitar2) ?
1 — Alphabet         : quel degré (Sa = degré 1, Ga = degré 3) ?
2 — Octaves          : quel registre (saptak) ?
3 — Tempérament      : quel rapport pour ce degré (5/4, 2^(4/12)) ?
4 — Tuning           : quelle fondamentale, quel diapason ?
5 — Resolver         : le calcul final en Hz

 

C’est pourquoi le même Ga peut produire deux fréquences différentes selon l’actor :

 

sitar1 : Ga (registre médian) → 327.03 Hz (22 shruti, ratio 5/4)
sitar2 : Ga (registre médian) → 329.63 Hz (12-TET, ratio 2^(4/12))

 

Même symbole, même registre, fréquences différentes — parce que l’accordage (couches 3-4) diffère. Les détails du système de hauteurs en 6 couches sont dans S9.


Un exemple complet

 

// Actors
@actor sitar   alphabet:sargam   scale:sargam_22shruti  transport:webaudio
@actor tabla   alphabet:tabla    sounds:tabla_perc       transport:midi(ch:10)
@actor lights  alphabet:dmx_cues                         transport:dmx

// Inits
`js: // Web Audio setup`

// Composition — les actors résolvent automatiquement
S -> { melodie, rythme, eclairage }

melodie   -> Sa Re Ga(vel:120) Pa      // → sitar (seul à avoir ces notes)
rythme    -> tin ta ke dha             // → tabla (seul à avoir ces bols)
eclairage -> -!spot _ _ -!fade         // → lights (seul à avoir spot, fade)

 

Trois instruments, trois actors, trois destinations — une seule grammaire. La résolution est implicite parce que chaque symbole n’appartient qu’à un seul actor.


Ce qu’il faut retenir

  1. Trois types temporels : gate (durée), trigger (instant), cv (continu)
  2. L’actor lie tout : alphabet + scale + sounds + transport + eval
  3. @actor déclare un actor avec ses propriétés
  4. Résolution implicite : si un symbole n’est que dans un actor, pas besoin de le qualifier
  5. Résolution explicite : notation pointée sitar1.Sa quand plusieurs actors partagent le même alphabet
  6. () = runtime, [] = moteur — deux syntaxes, deux destinations
  7. La fréquence se résout en aval — BP3 ne voit que des noms opaques bol… ; les 6 couches pitch tournent dans le runtime

Glossaire

  • Actor : Unité de binding qui lie un alphabet, une gamme (scale), des sons (sounds), un transport et un évaluateur — le contexte complet de résolution d’un symbole
  • Gate : Signal qui reste actif pendant une durée — en BPscript, un symbole qui occupe du temps
  • Trigger : Impulsion instantanée de durée zéro
  • CV (Control Voltage) : Valeur qui varie continûment sur une durée (ADSR, LFO, ramp)
  • Resolver : Dernière des 6 couches pitch (en aval) qui traduit un symbole en fréquence
  • Binding : Liaison entre un symbole et son actor — implicite (déduite) ou explicite (notation pointée)
  • Transport : Protocole de sortie (Web Audio, MIDI, OSC, DMX) déclaré dans l’actor
  • Résolution implicite : Le compilateur déduit l’actor d’un symbole quand il n’y a pas d’ambiguïté

Liens dans la série

  • S2 — Les 3 mots et 24 symboles
  • S4 (à venir) — Les backticks — le champ eval de l’actor détermine quel REPL évalue
  • S5 — [] moteur vs () runtime en détail
  • S9 — Le système de hauteurs en 6 couches — ce que le resolver fait
  • S10 — Le pipeline — comment les actors traversent la compilation

Prérequis : S2
Temps de lecture : 14 min
Tags : #BPscript #actors #gate #trigger #cv #tuning


Prochain article : S4 — Les backticks : JS inline et REPLs


Retour à l’index