M12) De la structure au son
BP3 et les couches d’abstraction
Comment un seul langage encode la forme, l’harmonie, le groove et le geste — illustré par une Rumba Flamenca
Dans M3, nous avons vu que les outils musicaux numériques opèrent chacun à un niveau d’abstraction différent : MIDI décrit des événements (niveau 3), MusicXML capture une notation (niveau 4), BP3 génère à partir de règles (niveau 5). La plupart des outils sont cantonnés à un seul de ces niveaux — un fichier MIDI ne connaît pas la « forme sonate », et une partition MusicXML ne sait rien du groove.
BP3 fait les choses différemment. Grâce à ses mécanismes — grammaires, scripts, polymétrie — il traverse naturellement plusieurs niveaux d’abstraction dans un seul programme. Un compositeur peut encoder la structure formelle, l’harmonie, le groove, le geste instrumental et le son dans deux fichiers de quelques dizaines de lignes, sans changer de paradigme.
L’idée en une phrase : BP3 est un langage génératif qui encode simultanément la structure, l’harmonie, les accents, le rythme, le geste et le son — sans quitter le niveau 5.
Démonstration par l’exemple : un compas de rumba flamenca.
Trois niveaux, six couches
Du haut (le plus abstrait) vers le bas (le plus concret), une grammaire BP3 peut encoder six couches d’information musicale, réparties sur trois niveaux de la taxonomie de M3 :
| Niveau M3 | Couche | Question | Mécanisme BP3 |
|---|---|---|---|
| Génératif (5) | Structure | Quelle forme ? | Règles de grammaire |
| Notationnel (4) | Harmonie | Quelles notes possibles ? | _script() (variables partagées) |
| Événementiel (3) | Accents | Quel profil dynamique ? | _script($ACCENT) |
| (idem) | Rythme | Quels temps sont joués ? | _script($PLAY) |
| (idem) | Geste | Comment jouer physiquement ? | Poly_ratio {1, ...} (strum) |
| (idem) | Son | Quels événements MIDI ? | _note(), _vel() |
Le point clé : BP3 génère au niveau 5 de la taxonomie de M3, mais il encode des informations des niveaux 3 et 4 dans ses objets terminaux et ses variables. C’est comme un architecte qui dessine un plan (structure) contenant les spécifications électriques (technique) et les choix de matériaux (matière) — le plan est le niveau le plus abstrait, mais il porte les niveaux concrets en lui.
L’exemple : un compas de Rumba Flamenca
Contexte musical
La rumba flamenca est l’un des styles les plus populaires du flamenco. Son énergie rythmique repose sur un motif caractéristique : le pattern 3-3-2.
Décryptage — Le pattern 3-3-2 : Prenez 8 temps. Au lieu de les grouper régulièrement (4+4 ou 2+2+2+2), groupez-les en 3+3+2 : ! . . ! . . o . — un accent fort toutes les 3 croches, puis un accent faible après 2. Ce groupement asymétrique crée un « rebond » caractéristique que l’on retrouve dans la rumba, le son cubain, la bossa nova et de nombreuses musiques populaires. C’est l’ADN rythmique de la rumba.
La technique de main droite est le rasgueado : une alternance rapide de balayages des cordes vers le bas (D — down-strum) et vers le haut (U — up-strum). Chaque doigt balaie les 6 cordes de la guitare en un instant.
Décryptage — Rasgueado : Technique de guitare flamenca où la main droite balaie rapidement toutes les cordes. Un down-strum va des graves vers les aigus (corde 6 → corde 1), un up-strum fait l’inverse. Le résultat est un accord « égrené » en quelques millisecondes.
Il exite de nombreuses techniques de rasgeado, pour la « simplicité » de l’exemple, on va considérer un geste simple où la descente se fait a un seul doigt (ce qui est assez simple et donnerait un son un peu pauvre, admettons le majeur) et la remontée au pouce (ce qui, par contre, est assez classique)
Notre exemple utilise une progression harmonique typique : i – V7 – V7 – i (Em – B7 – B7 – Em) — la couleur mineure et la tension dominante caractéristiques du flamenco.
Le fichier grammaire — -gr.Rumba
Le fichier grammaire définit la structure et l’organisation des couches :
-gr.Rumba
// ═══ STRUCTURE — la forme du morceau [Génératif] ═══
S --> SETUP_GUITARE SEQUENCE
SEQUENCE --> MESURE_1 MESURE_2 MESURE_3 MESURE_4
// ═══ HARMONIE — la progression i–V7–V7–i [Notationnel] ═══
MESURE_1 --> POS_Em COMPAS
MESURE_2 --> POS_B7 COMPAS
MESURE_3 --> POS_B7 COMPAS
MESURE_4 --> POS_Em COMPAS
// ═══ ACCENTS — le profil dynamique 3-3-2 [Événementiel] ═══
COMPAS --> { ACCENT_MAP, RHYTHM_MAP, MECHANICS }
ACCENT_MAP --> O . . O . . o .
// ═══ RYTHME — quels temps sont joués [Événementiel] ═══
RHYTHM_MAP --> x - x x - x x x
// ═══ GESTE — l'alternance main droite [Événementiel] ═══
MECHANICS --> D U D U D U D U
Cinq blocs, un par couche (la couche Son est réalisée dans le fichier data). Chaque bloc répond à une seule question :
- Structure :
SEQUENCE → MESURE_1 ... MESURE_4— combien de mesures, dans quel ordre. - Harmonie :
MESURE_N → POS_X COMPAS— quel accord pour chaque mesure (puis délègue au rythme). - Accents :
ACCENT_MAP → O . . O . . o .— quel profil dynamique (le pattern 3-3-2). - Rythme :
RHYTHM_MAP → x - x x - x x x— quels temps sont joués ou muets. - Geste :
MECHANICS → D U D U D U D U— quel mouvement de main droite.
La polymétrie { ACCENT_MAP, RHYTHM_MAP, MECHANICS } (B5) superpose trois couches en parallèle — les 8 accents, les 8 temps et les 8 strums s’alignent un à un.
Le fichier data — -da.Rumba
Le fichier data donne un corps à chaque terminal et non-terminal de la grammaire :
-da.Rumba
// ═══ HARMONIE — instrument (accordage) [Notationnel] ═══
SETUP_GUITARE _script(
$S6 = 40;
$S5 = 45;
$S4 = 50;
$S3 = 55;
$S2 = 59;
$S1 = 64;
)
// ═══ HARMONIE — positions d'accords (F = frette, V = voiced) [Notationnel] ═══
POS_Em _script(
$F6=0; $V6=1;
$F5=2; $V5=1;
$F4=2; $V4=1;
$F3=0; $V3=1;
$F2=0; $V2=1;
$F1=0; $V1=1;
)
POS_B7 _script(
$F6=0; $V6=0;
$F5=2; $V5=1;
$F4=1; $V4=1;
$F3=2; $V3=1;
$F2=0; $V2=1;
$F1=2; $V1=1;
)
// ═══ ACCENTS — profil dynamique [Événementiel] ═══
O _script($ACCENT = 127) // accent fort
o _script($ACCENT = 80) // accent faible
. _script($ACCENT = 60) // note normale
// ═══ RYTHME — quels temps sont joués [Événementiel] ═══
x _script($PLAY = 1) // temps joué
- _script($PLAY = 0) // temps muet
// ═══ GESTE — main droite [Événementiel] ═══
// Down-strum : vélocité = accent × rythme, puis 6 notes grave→aigu
D _vel($ACCENT*$PLAY) {1, _note($V6*($S6+$F6)) _note($V5*($S5+$F5)) _note($V4*($S4+$F4)) _note($V3*($S3+$F3)) _note($V2*($S2+$F2)) _note($V1*($S1+$F1))}
// Up-strum : vélocité = accent × rythme, puis 6 notes aigu→grave
U _vel($ACCENT*$PLAY) {1, _note($V1*($S1+$F1)) _note($V2*($S2+$F2)) _note($V3*($S3+$F3)) _note($V4*($S4+$F4)) _note($V5*($S5+$F5)) _note($V6*($S6+$F6))}
Lecture croisée : chaque couche décortiquée
Couche Structure — la grammaire comme forme musicale
Au sommet de l’abstraction, les règles de structure dessinent la forme de la pièce — sans mentionner aucun accord :
S --> SETUP_GUITARE SEQUENCE
SEQUENCE --> MESURE_1 MESURE_2 MESURE_3 MESURE_4
La structure ne sait pas si c’est du Em ou du B7. Elle dit seulement : « il y a 4 mesures, dans cet ordre. » Pour passer à 8 mesures ou à une forme AABA, on ne touche qu’ici.
La dérivation (B3, mode ORD) décompose hiérarchiquement la pièce :
S
└─ SETUP_GUITARE SEQUENCE
└─ MESURE_1 MESURE_2 MESURE_3 MESURE_4
└─ POS_Em COMPAS POS_B7 COMPAS POS_B7 COMPAS POS_Em COMPAS
C’est le même mécanisme qu’un arbre syntaxique (L4), mais les nœuds portent des noms musicaux, pas informatiques. La couche Structure délègue à la couche Harmonie, qui délègue au Rythme — chacune dans son bloc.
Couche Harmonie — _script() comme mémoire instrumentale
La couche harmonique utilise _script() pour configurer l’état de la guitare via des variables partagées (B4).
SETUP_GUITARE accorde les 6 cordes. Chaque variable $Sn contient le numéro MIDI de la corde à vide :
| Variable | Note | MIDI |
|---|---|---|
$S6 |
E2 | 40 |
$S5 |
A2 | 45 |
$S4 |
D3 | 50 |
$S3 |
G3 | 55 |
$S2 |
B3 | 59 |
$S1 |
E4 | 64 |
Les positions d’accords (POS_Em, POS_B7) posent les doigts sur le manche. Chaque corde reçoit une frette ($Fn) et un indicateur de voicing ($Vn : 1 = jouée, 0 = étouffée) :
Em (Mi mineur) : toutes les cordes ouvertes sauf les frettes 2 sur A et D.
Em B7
┌───┬───┬───┐ ┌───┬───┬───┐
e ───┤ │ │ │ e ───┤ │ ● │ │
├───┼───┼───┤ ├───┼───┼───┤
B ───┤ │ │ │ B ───┤ │ │ │
├───┼───┼───┤ ├───┼───┼───┤
G ───┤ │ │ │ G ───┤ │ ● │ │
├───┼───┼───┤ ├───┼───┼───┤
D ───┤ │ ● │ │ D ───┤ ● │ │ │
├───┼───┼───┤ ├───┼───┼───┤
A ───┤ │ ● │ │ A ───┤ │ ● │ │
├───┼───┼───┤ ├───┼───┼───┤
E ───┤ │ │ │ E ───x │ │ │
└───┴───┴───┘ └───┴───┴───┘
fr1 fr2 fr3 fr1 fr2 fr3
Décryptage — Lire une tablature : Chaque ligne horizontale est une corde (de E grave en bas à e aigu en haut). Les chiffres ou les
●indiquent à quelle frette poser les doigts.○= corde jouée à vide (frette 0).✕= corde étouffée (non jouée).
En tablature chiffrée, avec la correspondance MIDI :
Em (Mi mineur) B7 (Si septième)
e ──0── E4 (64+0 = 64) e ──2── F#4 (64+2 = 66)
B ──0── B3 (59+0 = 59) B ──0── B3 (59+0 = 59)
G ──0── G3 (55+0 = 55) G ──2── A3 (55+2 = 57)
D ──2── E3 (50+2 = 52) D ──1── D#3 (50+1 = 51)
A ──2── B2 (45+2 = 47) A ──2── B2 (45+2 = 47)
E ──0── E2 (40+0 = 40) E ──✕── (étouffée, $V6=0)
Le mécanisme clé est le découplage : les variables d’accord persistent après l’exécution de POS_Em et restent actives jusqu’au prochain POS_B7. Pour changer la progression harmonique (par exemple Am–G–F–E au lieu de Em–B7–B7–Em), on ne modifie que le bloc Harmonie de la grammaire — ni la structure, ni les accents, ni le rythme, ni le geste ne sont touchés.
Un détail important : _script() est une opération à durée zéro dans BP3. Quand on écrit MESURE_1 → POS_Em COMPAS, le changement de position s’exécute instantanément avant le premier temps du compas — pas sur le temps. C’est exactement ce qui se passe en vrai : un guitariste pose les doigts de la main gauche avant que la main droite ne frappe. La séquentialité du code modélise fidèlement cette dépendance causale entre les deux mains.
Couche Accents — le profil dynamique 3-3-2
La couche Accents définit le profil dynamique — quelle énergie sur chaque temps, indépendamment du fait qu’il soit joué ou non :
ACCENT_MAP --> O . . O . . o .
| Symbole | Signification | $ACCENT |
|---|---|---|
O |
Accent fort | 127 |
o |
Accent faible | 80 |
. |
note normale | 60 |
Le pattern 3-3-2 apparaît dans la répartition des accents forts et faibles : positions 1, 4, 7 (groupes de 3+3+2) :
Position: 1 2 3 4 5 6 7 8
Accent: O . . O . . o .
Groupe: | ── 3 ── | ── 3 ── | ─ 2 ─ |
Le profil dynamique est pur : il dit « ici c’est fort, ici c’est doux » sans se prononcer sur ce qui est joué ou non. C’est l’ADN rythmique de la rumba — le feeling 3-3-2 — séparé de toute décision de jeu.
Couche Rythme — quels temps sont joués
La couche Rythme décide quels temps sonnent — indépendamment de leur dynamique :
RHYTHM_MAP --> x - x x - x x x
| Symbole | Signification | $PLAY |
|---|---|---|
x |
Temps joué | 1 |
- |
Temps muet | 0 |
C’est ici que le découplage devient puissant. Avec le même profil d’accents 3-3-2, on peut jouer des rythmes différents — chaque variante ne touche que cette ligne :
x - x x - x x x ← rumba classique (notre exemple)
x - x x x x x x ← variante plus remplie
x x x x - x x x ← déplacement du silence
x x x x x x x x ← tous les temps joués
Le profil dynamique reste identique (O . . O . . o .) — le feeling 3-3-2 est préservé, seul le rythme change. C’est une séparation impossible dans un encodage traditionnel où accent et rythme sont fusionnés en un seul symbole.
Chaque symbole des deux couches est un terminal qui agit comme une commande d’état : il ne produit pas de son lui-même, mais modifie une variable ($ACCENT ou $PLAY) qui sera lue par la couche Geste au moment de produire les notes MIDI.
Couche Geste — polymétrie et micro-timing
La couche geste modélise le mouvement physique de la main droite :
MECHANICS --> D U D U D U D U
D et U sont définis en deux temps — comme le geste réel :
D _vel($ACCENT*$PLAY) {1, _note(...) _note(...) _note(...) ... }
U _vel($ACCENT*$PLAY) {1, _note(...) _note(...) _note(...) ... }
D’abord _vel($ACCENT * $PLAY) fixe la force du geste — une seule fois, parce qu’un rasgueado est un geste unique. La vélocité combine deux couches : la dynamique ($ACCENT, couche Accents) et le rythme ($PLAY, couche Rythme). Si le temps est muet ($PLAY = 0), la vélocité est nulle quel que soit l’accent — le strum est silencieux. Puis {1, 6 notes} est un poly_ratio (B5) qui compresse les 6 notes dans 1 unité de temps — le micro-timing qui transforme 6 événements discrets en un accord « égrené » de quelques millisecondes.
Décryptage — Poly_ratio : L’expression
{1, seq}compresse la séquenceseqdans exactement 1 unité de temps. Pour un strum de guitare, cela signifie que les 6 notes sont jouées séquentiellement mais très rapidement — comme un vrai balayage des cordes.
La direction du strum est encodée dans l’ordre des notes :
- D (down-strum) : grave → aigu, donc corde 6 → corde 1 (
$S6+$F6en premier). - U (up-strum) : aigu → grave, donc corde 1 → corde 6 (
$S1+$F1en premier).
Le voicing (quelles cordes sonnent) est géré par les variables $Vn de la main gauche : _note($Vn * ($Sn+$Fn)). Si $Vn = 0 (corde étouffée), la note MIDI est 0 — silence. C’est un raccourci pragmatique : en toute rigueur, MIDI note 0 n’est pas un silence mais un C-1, et une grammaire de production séparerait voicing et pitch. Mais pour notre démonstration, ce raccourci a l’avantage de montrer clairement comment la main gauche (voicing) et la main droite (dynamique) contribuent chacune au résultat final sans se mélanger.
La superposition des trois couches est réalisée par la polymétrie à 3 voix :
COMPAS --> { ACCENT_MAP, RHYTHM_MAP, MECHANICS }
Cela signifie : jouer les 8 accents, les 8 choix joué/muet et les 8 strums en parallèle, alignés temporellement. Au temps 1, l’accent (!), le rythme (x) et le geste (D) coïncident — et la vélocité résultante est $ACCENT × $PLAY = 127 × 1 = 127. Au temps 2, l’accent (.), le rythme (-) et le geste (U) coïncident — et la vélocité est 60 × 0 = 0 (silence). Les trois séquences ont la même longueur (8 éléments), donc le ratio est 1:1:1.
Couche Son — les terminaux MIDI
Tout en bas de la pile, les terminaux _note() et _vel() produisent les événements MIDI (B2). Chaque strum se décompose en :
_vel($ACCENT * $PLAY)— posé avant le poly_ratio, durée zéro : la force du geste, combinant la dynamique (couche Accents) et le choix joué/muet (couche Rythme)._note($Vn * ($Sn + $Fn))— à l’intérieur du poly_ratio : la note MIDI = voicing × (corde + frette).
Le code modélise fidèlement la réalité physique du geste :
| Geste réel | Code BP3 | Pourquoi |
|---|---|---|
| Main gauche pose l’accord avant le temps | POS_X (durée 0) puis COMPAS |
_script() est instantané |
| Main droite balaie avec une force uniforme | _vel(...) une seule fois avant le strum |
un geste = une vélocité |
| L’accent dépend du pattern 3-3-2 | $ACCENT (couche Accents) dans la vélocité |
le profil dynamique |
| Certains temps sont muets | $PLAY (couche Rythme) dans la vélocité |
le rythme joué/muet |
| Certaines cordes étouffées par la main gauche | $Vn dans _note($Vn * ...) |
c’est la main gauche, pas la droite |
| Cordes balayées en séquence rapide | {1, _note(...) _note(...) ...} |
poly_ratio = micro-timing |
C’est le point d’arrivée : toute l’abstraction des couches supérieures se résout en événements MIDI. Les variables $V, $S, $F, $ACCENT et $PLAY — provenant de cinq couches différentes — convergent ici. La séquentialité du code (POS → _vel → _note) reflète la séquentialité du geste (poser les doigts → armer la frappe → balayer les cordes).
Les mécanismes BP3 mobilisés — tableau de synthèse
| Mécanisme BP3 | Couche servie | Rôle | Article |
|---|---|---|---|
| Règles de grammaire | Structure | Décomposition hiérarchique de la forme | B3 |
_script() |
Harmonie, Accents, Rythme | État partagé entre couches (variables persistantes) | B7 |
Polymétrie {A, B, C} |
Accents + Rythme + Geste | Superposition de trois flux temporels | B5 |
Poly_ratio {n, seq} |
Geste | Micro-timing (strum de 6 notes en 1 temps) | B5 |
Variables $ |
Toutes | Indirection et découplage entre couches | B4 |
_note(), _vel() |
Son | Production des événements MIDI terminaux | B2 |
Six mécanismes. Six couches sur trois niveaux. Deux fichiers. Un seul langage.
Ce que ça montre
Traversée de couches
BP3 opère au niveau 5 (génératif) de la taxonomie de M3, mais il encode des informations des niveaux 3 et 4 dans ses objets. La grammaire génère la structure (niveau 5), les _script() portent l’harmonie (niveau 4), et les terminaux _note(), _vel() produisent les événements (niveau 3). Un seul programme traverse trois niveaux d’abstraction — là où il faudrait normalement un outil par niveau.
Découplage
Chaque couche est modifiable indépendamment — chaque modification ne touche qu’un seul bloc de la grammaire :
- Changer la structure (8 mesures au lieu de 4) → modifier le bloc Structure uniquement.
- Changer la progression (Am–G–F–E au lieu de Em–B7–B7–Em) → modifier le bloc Harmonie uniquement.
- Changer les accents et passer d’une Rumba a un Tango (
O . . O . . o .→O . O . O . . .) → modifier le bloc Accents uniquement. - Changer le rythme (
x - x x - x x x→x x x x x x x x) → modifier le bloc Rythme uniquement. - Changer le geste (rasgueado → arpège) → modifier le bloc Geste uniquement.
C’est la conséquence de deux mécanismes : la séparation en blocs dans la grammaire, et le système de variables (B4) qui fait communiquer les couches par des noms ($ACCENT, $PLAY, $Sn, $Fn, $Vn), pas par des valeurs câblées.
Composabilité
Le découplage implique la recombinaison : on peut assembler librement les couches. Même groove + autre instrument (remplacer SETUP_GUITARE par un setup de oud). Même structure + autre harmonie (progression Am–G–F–E au lieu de Em–B7–B7–Em). Même geste + autre groove (pattern reggaeton sur la même mécanique de strum).
Un seul langage
Là où un workflow classique nécessiterait un DAW pour la structure, un éditeur de partition pour l’harmonie, un séquenceur pour le groove et un plugin VST pour le son, BP3 unifie tout en deux fichiers texte — une grammaire et ses données. Pas de conversion entre formats, pas de perte d’information entre niveaux.
C’est la promesse du niveau génératif (M3) pleinement réalisée : un langage qui décrit comment construire la musique, pas comment elle apparaît à un niveau donné.
Ouverture : BP3 pourrait aller plus loin. Via _script() contrôlant des SynthDefs SuperCollider, il pourrait aussi encoder le timbre — descendant jusqu’au niveau 1 (signal) de la taxonomie de M3. C’est la direction esquissée par les time-objects (B9) : quand la grammaire ne se contente plus de générer des notes, mais pilote directement la synthèse sonore.
Glossaire
- Compas : Cycle rythmique du flamenco, structuré par des accents qui définissent l’identité de chaque palo (style). En rumba, le compas est un cycle de 4 temps (ou 8 croches) avec un pattern d’accents 3-3-2.
- Pattern 3-3-2 : Groupement rythmique en 3+3+2 = 8 temps, typique de la rumba, du son cubain et de nombreuses musiques populaires. L’asymétrie crée une tension rythmique caractéristique entre les groupes de 3 et le groupe final de 2.
- Poly_ratio : Expression polymétrique mono-voix
{n, seq}compressant ou étirant une séquence dans n unités de temps. Ici,{1, 6 notes}fait jouer 6 notes en 1 temps — un micro-timing. - Rasgueado : Technique de guitare flamenca consistant en balayages rapides des cordes, alternant typiquement des mouvements vers le bas (down-strum) et vers le haut (up-strum).
- Strum : Balayage rapide des cordes de guitare. Un down-strum (D) va des graves vers les aigus ; un up-strum (U) va des aigus vers les graves.