S2) Trois mots et vingt-quatre symboles
Le vocabulaire complet de BPscript — dense, pas simple
Un langage qui ne réserve que trois mots, on l’imagine simple. Il ne l’est pas. BPscript est dense — et c’est un choix assumé.
Où se situe cet article ?
Après la vision de S1, on entre dans le langage lui-même. Cet article est une carte : il montre toutes les briques sans encore les assembler. Les articles suivants (S3 (à venir) à S8) plongeront dans chaque mécanisme.
Trois mots réservés
Avant même de savoir quel son produire, un ordonnanceur a besoin d’une information : comment l’événement occupe-t-il le temps ? Dure-t-il ? Est-il instantané ? Sa valeur change-t-elle pendant qu’il sonne ? C’est à cette question que répondent les trois — et seuls — mots réservés de BPscript. Tout le reste du vocabulaire (noms de notes, de runtimes, de librairies) est défini par l’utilisateur ou par les librairies.
| Mot | Rapport au temps | Sens |
|---|---|---|
| gate | occupe une durée | une valeur tenue, le temps que dure l’événement |
| trigger | instantané | une impulsion ponctuelle, sans durée |
| cv | occupe une durée | une valeur qui varie continûment pendant l’événement |
Ces trois catégories viennent de la synthèse modulaire (l’eurorack, format de synthétiseurs modulaires) : un signal y est soit une porte (gate — le son dure tant que la porte est ouverte), soit un déclencheur (trigger — une impulsion instantanée), soit une tension de contrôle (CV, control voltage — une valeur qui évolue dans le temps). BPscript reprend cette distinction parce qu’elle décrit exactement les trois façons dont un événement musical peut occuper le temps. Le détail des types fait l’objet de S3.
Vingt-quatre symboles structurels
Pourquoi des symboles plutôt que des mots-clés ? Parce qu’un symbole se lit d’un coup d’œil et n’alourdit pas le vocabulaire à mémoriser : -> montre une dérivation, ! montre une impulsion. Au-delà des trois mots, BPscript s’écrit donc avec 24 symboles, qui se regroupent en six familles selon ce qu’ils servent à exprimer.
Famille 1 — Environnement
@ directive (imports, configuration globale)
Le @ ouvre une directive : une instruction qui vaut pour toute la scène, pas pour un instant précis. Par exemple @actor sitar alphabet:sargam ..., @tempo:120, @mode:random. La plus importante est @actor, qui relie un alphabet, une gamme, des sons et une sortie (S3). Collé en suffixe à un élément (C4@kick), le @ applique aussi une macro ou un label.
Famille 2 — Dérivation
-> règle de production — utilisée quand le moteur génère (sens par défaut)
<- règle d'analyse — utilisée quand le moteur reconnaît une séquence (réduit la droite vers la gauche)
<> règle bidirectionnelle — valable dans les deux phases (génération et analyse)
Les flèches sont le cœur du langage. S -> A B C se lit « le non-terminal S (symbole intermédiaire, réécrit par une règle) se réécrit en A B C ». Le sens de la flèche indique dans quelle phase la règle est valable : -> est une règle de production, utilisée quand le moteur engendre une séquence (sens par défaut) ; <- une règle d’analyse, utilisée quand le moteur reconnaît une séquence donnée (il réduit la partie droite vers la gauche) ; <> une règle bidirectionnelle, valable dans les deux phases. Ces directions prolongent celles de BP3 (B3).
Famille 3 — Groupement temporel
{ } polymétrie (plusieurs voix) ou groupement
, séparateur de voix dans un groupe polymétrique
. séparateur de périodes (fragments de durée égale)
Les accolades {} regroupent des événements dans le temps. Avec une virgule, elles superposent des voix — c’est la polymétrie (superposition de flux temporels, voir B5) : {melodie, rythme}. Sans virgule, c’est un simple groupement : {A B C}. Le point . découpe une séquence en fragments de durée symbolique égale.
Famille 4 — Métadonnées et paramètres
[ ] instructions moteur (sur un symbole, un groupe ou une règle)
( ) déclaration, appel, paramètre runtime, ou contexte (selon la position)
: liaison (symbole:runtime, clé:valeur)
Deux notations, parce qu’il y a deux destinataires différents :
[]parle au moteur : ce sont les instructions que BP3 doit appliquer pour dériver —[speed:2],[weight:3],[scan:right].()parle au runtime : ce sont les paramètres transmis à la sortie qui produira le son —(vel:120),(pan:0.5).
Les crochets [] portent sur un symbole (A[/2]), un groupe ({A B}[speed:2]) ou une règle entière. Les parenthèses () ont quatre rôles selon leur position : paramètre runtime (Sa(vel:120)), déclaration (gate note(pitch, vel:80)), appel de macro (accent(Sa)) ou contexte de règle ((A B) C -> D E). Le : relie un nom à une valeur, ou un symbole à sa sortie.
Famille 5 — Temps et silence
- silence (occupe du temps, pas de son)
_ prolongation (étend l'événement précédent)
... repos indéterminé (durée calculée par le moteur)
~ liaison (legato entre deux notes)
Plusieurs façons d’exprimer l’absence ou la tenue, chacune avec une sémantique temporelle distincte :
| Symbole | Nom | Effet |
|---|---|---|
- |
silence | aucun événement, mais le temps s’écoule |
_ |
prolongation | l’événement précédent continue, sans nouvelle attaque |
... |
repos indéterminé | le moteur calcule la durée qui équilibre le mieux les voix |
La distinction compte pour la polymétrie : Sa _ Re fait durer Sa deux positions, tandis que Sa - Re insère un vrai silence entre les deux. Le repos indéterminé ... est propre à BP3 : il laisse l’algorithme de polymétrie choisir la durée qui donne la structure la plus régulière (B13).
Le tilde ~ lie deux notes : Sa~ Re ~Sa indique que Sa se prolonge à travers Re sans nouvelle attaque (une seule attaque au début, un seul relâchement à la fin).
Famille 6 — Événements et filtrage de motifs
! simultanéité (événements au même instant) / trigger sortant
<! trigger entrant (attente d'un signal externe)
? capture (filtrage de motif, avec numéro)
|x| homomorphisme (variable liée)
$ template maître (définition d'un motif)
& template esclave (référence à un motif)
# négation de contexte
= assignation (mutation de flag dans `[]`, définition de macro)
Ce sont les mécanismes avancés du langage. Chacun aura son article dédié :
!et<!→ S7?,|x|,$,&,#→ S8- les flags (gardes et mutations dans
[]) → S6
Les opérateurs de flags
Une composition n’est pas forcément une suite figée : elle peut prendre des décisions et évoluer au fil de la dérivation. Cet état est porté par les flags (variables conditionnelles de BP3 — voir B4). Les opérateurs des flags se répartissent en deux familles selon ce qu’ils font.
Comparaison — tester un flag, dans une garde ([…] avant le LHS) :
== test d'égalité
!= test d'inégalité
> test supérieur
< test inférieur
>= test supérieur ou égal
<= test inférieur ou égal
Calcul — modifier un flag, dans une mutation ([…] dans le RHS) :
+ incrément [flag+1]
- décrément [flag-1]
= assignation [flag=valeur]
Soit neuf opérateurs en tout : six de comparaison, trois de calcul. Deux d’entre eux réutilisent un glyphe rencontré ailleurs — - sert aussi de silence, = sert aussi à définir une macro — mais ce sont bien des opérateurs distincts : le - qui décrémente un flag n’a rien à voir avec le - qui marque un silence. L’inventaire des glyphes (les 24 symboles) et l’inventaire des opérateurs sont deux comptes indépendants.
Point commun à tous : gardes comme mutations vivent dans les crochets [] — c’est l’état du moteur, pas un événement temporel.
[count>3] A -> B C // garde : la règle existe si count > 3
S -> A B [count+1] C // mutation : incrémente count après B
[phase==1] S -> Sa Re Ga [phase=2] Pa // garde + mutation : joue, puis passe phase à 2
Une garde détermine si une règle s’applique : la règle « existe » tant que la condition est vraie. Ce n’est pas un test impératif exécuté ligne par ligne, mais une condition d’existence de la règle dans la grammaire. Hors du contexte des flags, ces opérateurs ne servent à rien : BPscript n’a pas d’arithmétique générale. Toute logique de calcul passe par les backticks (S4).
Les macros : factoriser un geste
En composant, on réécrit souvent les mêmes gestes : un accent, un ornement, une combinaison d’effets. Une macro évite de les recopier — on définit le motif une fois, on l’appelle par son nom. C’est une substitution textuelle : le compilateur remplace l’appel par le corps de la macro, avant toute autre analyse. La macro ne connaît donc ni les types ni les sorties ; la vérification vient ensuite.
@macro accent(x) = x(vel:120)
@macro scene_a(x) = x!visual_glow!spotlight
S -> accent(Sa) scene_a(Re) Ga
// Après expansion, le compilateur voit :
// Sa(vel:120) Re!visual_glow!spotlight Ga
La macro accent(x) ignore que x sera un gate. La macro scene_a(x) ignore ce que sont visual_glow ou spotlight. Elle recopie, point. Cette séparation donne trois étapes indépendantes, chacune avec sa préoccupation :
- Macros — réécriture du texte, sans connaître les types
- Types temporels — gate / trigger / cv, vérifiés à la compilation
- Sortie (runtime) — résolue dans la couche aval
Peu de mots, beaucoup de combinaisons
Le langage ne réserve que 3 mots, mais il ajoute 24 symboles, 7 opérateurs de flags, des macros, des backticks, des directives. Peu de mots ne veut donc pas dire peu de choses à apprendre : la richesse s’est déplacée du vocabulaire vers la combinatoire.
Pour situer cette intention parmi d’autres langages de live coding (programmation en direct sur scène) :
| Langage | Vocabulaire | Syntaxe |
|---|---|---|
| Sonic Pi | restreint, d’accès rapide | proche de Ruby |
| TidalCycles | algèbre de motifs expressive | proche de Haskell |
| BPscript | 3 mots + 24 symboles | héritée de BP3 |
L’idée n’est pas de promettre la simplicité, mais de réduire ce qu’il faut retenir : trois mots, et des symboles qui se lisent visuellement. -> est une flèche, ! une impulsion, ... une attente, {} un groupement. La difficulté n’est pas dans le vocabulaire ; elle est dans la manière de combiner ces briques — comme aux échecs, où six types de pièces suffisent à une complexité immense.
Un premier exemple complet
Voici une scène BPscript minimale qui mobilise la plupart des briques :
@alphabet.raga:supercollider // directive : importer le raga, lié à SC
@tempo:60 // directive : tempo global
[phase==1] S -> alap S // phase 1 : jouer l'ālāp, puis recommencer
[phase==2] S -> jor S // phase 2 : jouer le jor
[phase==3] S -> jhala // phase 3 : conclure avec le jhālā
alap -> Sa _ Re _ Ga _ [phase=2] // l'ālāp : lent, puis bascule en phase 2
jor -> {Sa Re Ga Pa}[speed:2] [phase=3] // le jor : plus rapide, puis phase 3
jhala -> {Sa Re Ga Pa Dha Ni Sa}[speed:4] // le jhālā : rapide, terminal
Ce qu’on y reconnaît :
@— directives globales (librairie, tempo)[flag==N]— gardes conditionnelles->— règles de dérivation_— prolongation (Sa dure deux positions)[phase=2]— mutation de flag (bascule de phase){}— groupement temporel[speed:2]— instruction moteur locale (vitesse doublée)
Treize lignes, trois phases, un raga complet. Ce n’est pas une suite figée : la structure se dérive, se conditionne et se ramifie.
Ce qu’il faut retenir
- 3 mots réservés —
gate,trigger,cv: ils déclarent comment un événement occupe le temps - 24 symboles structurels en 6 familles : environnement, dérivation, groupement, métadonnées, temps/silence, événements/motifs
- 9 opérateurs de flags — six de comparaison (gardes) et trois de calcul (
+,-,=, mutations) ;-et=réutilisent un glyphe vu ailleurs, mais restent des opérateurs distincts !est exclusivement temporel (événements simultanés) ; les gardes et mutations de flags s’écrivent dans[]- Les macros sont une substitution textuelle : elles ignorent les types et les sorties, vérifiés après expansion
- Dense, pas simple — peu de mots, des symboles visuels, une richesse qui vient de la combinatoire
- Pas de
for, pas dewhile— toute logique de calcul passe par les backticks
Pour aller plus loin
- Bel, B. & Kippen, J. (1992) : « Modelling Music with Grammars » — la syntaxe de BP3 dont BPscript hérite. Lien PDF
- ISO 14977 (1996) : standard EBNF — la notation utilisée pour spécifier formellement BPscript (S12)
Glossaire
- Mot réservé : mot que le langage se réserve — l’utilisateur ne peut ni le redéfinir ni l’employer comme nom
- Symbole structurel : caractère (ou groupe de caractères) à la signification syntaxique fixe
- Directive : instruction
@…qui configure la scène entière, hors du flux temporel - Non-terminal : symbole intermédiaire, réécrit par une règle (par opposition au terminal, symbole final)
- Dérivation : application successive des règles d’une grammaire pour engendrer une séquence
- Garde : condition qui détermine si une règle est active — la règle « existe » quand la garde est vraie
- Flag : variable conditionnelle de BP3 qui oriente l’application des règles et peut changer pendant la dérivation
- Macro : substitution textuelle — le compilateur remplace l’appel par le corps de la macro avant toute analyse
- Polymétrie : superposition de voix aux rapports de durée potentiellement irrationnels, notée
{voix1, voix2} - Runtime : environnement d’exécution, en aval, qui consomme la séquence horodatée et produit le son
- Live coding : pratique consistant à écrire ou modifier du code en direct sur scène
Liens dans la série
- S1 — BPscript : un langage moderne pour le Bol Processor — la vision
- S3 — Types, actors et bindings — les types en détail
- S4 — Les backticks — le pont vers les langages natifs
- S5 — Structurer le temps — polymétrie, silences, vitesse
- S6 — Composer avec des conditions — flags et parcours
- S7 — L’instant partagé — simultanéité
!et<! - S8 — Patterns, captures et templates — mécanismes avancés
- S12 — L’EBNF de BPscript — la spécification formelle complète
Prérequis : S1
Temps de lecture : 12 min
Tags : #BPscript #syntaxe #gate #trigger #cv
Prochain article : S3 — Types, actors et bindings