M12) From Structure to Sound
BP3 and Abstraction Layers
How a Single Language Encodes Form, Harmony, Groove, and Gesture — Illustrated by a Flamenco Rumba
In M3, we saw that digital music tools each operate at a different level of abstraction: MIDI describes events (level 3), MusicXML captures notation (level 4), BP3 generates from rules (level 5). Most tools are confined to only one of these levels — a MIDI file doesn’t know “sonata form,” and a MusicXML score knows nothing about groove.
BP3 does things differently. Thanks to its mechanisms — grammars, scripts, polymetry — it naturally crosses several levels of abstraction within a single program. A composer can encode formal structure, harmony, groove, instrumental gesture, and sound in two files of a few dozen lines, without changing paradigms.
The idea in one sentence: BP3 is a generative language that simultaneously encodes structure, harmony, accents, rhythm, gesture, and sound — without leaving level 5.
Demonstration by example: a flamenco rumba compas.
The Six Layers in a BP3 Grammar
From top (most abstract) to bottom (most concrete), a BP3 grammar can encode six layers of musical information:
| # | Layer | Question | BP3 Mechanism | M3 Level |
|---|---|---|---|---|
| 6 | Structure | What form? | Grammar rules | Generative (5) |
| 5 | Harmony | What possible notes? | _script() (shared variables) |
Notational (4) |
| 4 | Accents | What dynamic profile? | _script($ACCENT) |
Event-based (3) |
| 3 | Rhythm | Which beats are played? | _script($PLAY) |
Event-based (3) |
| 2 | Gesture | How to play physically? | Poly_ratio {1, ...} (strum) |
Event-based (3) |
| 1 | Sound | What MIDI events? | _note(), _vel() |
Event-based (3) |
The key point: BP3 generates at level 5 of the M3 taxonomy, but it encodes information from levels 3 and 4 within its terminal objects and variables. It’s like an architect drawing a blueprint (structure) that contains electrical specifications (technical) and material choices (material) — the blueprint is the most abstract level, but it carries the concrete levels within it.
The Example: A Flamenco Rumba Compas
Musical Context
Flamenco rumba is one of the most popular flamenco styles. Its rhythmic energy relies on a characteristic motif: the 3-3-2 pattern.
Deciphering — The 3-3-2 pattern: Take 8 beats. Instead of grouping them regularly (4+4 or 2+2+2+2), group them as 3+3+2: ! . . ! . . o . — a strong accent every 3 eighth notes, then a weak accent after 2. This asymmetrical grouping creates a characteristic “bounce” found in rumba, son cubano, bossa nova, and many popular music styles. It’s the rhythmic DNA of rumba.
The right-hand technique is rasgueado: a rapid alternation of downward (D — down-strum) and upward (U — up-strum) sweeps across the strings. Each finger sweeps all 6 guitar strings in an instant.
Deciphering — Rasgueado: A flamenco guitar technique where the right hand rapidly sweeps across all strings. A down-strum goes from low to high (string 6 → string 1), an up-strum does the reverse. The result is a “strummed” chord in a few milliseconds.
Many rasgueado techniques exist; for the “simplicity” of the example, we will consider a simple gesture where the downstroke is done with a single finger (which is quite simple and would produce a somewhat thin sound, let’s say the middle finger) and the upstroke with the thumb (which, however, is quite classic).
Our example uses a typical harmonic progression: i – V7 – V7 – i (Em – B7 – B7 – Em) — the minor color and dominant tension characteristic of flamenco.
The Grammar File — -gr.Rumba
The grammar file defines the structure and organization of the layers:
-gr.Rumba
// ═══ LAYER 6: STRUCTURE (the form of the piece) ═══
S --> SETUP_GUITARE SEQUENCE
SEQUENCE --> MESURE_1 MESURE_2 MESURE_3 MESURE_4
// ═══ LAYER 5: HARMONY (the i–V7–V7–i progression) ═══
MESURE_1 --> POS_Em COMPAS
MESURE_2 --> POS_B7 COMPAS
MESURE_3 --> POS_B7 COMPAS
MESURE_4 --> POS_Em COMPAS
// ═══ LAYER 4: ACCENTS (the 3-3-2 dynamic profile) ═══
COMPAS --> { ACCENT_MAP, RHYTHM_MAP, MECHANICS }
ACCENT_MAP --> O . . O . . o .
// ═══ LAYER 3: RHYTHM (which beats are played) ═══
RHYTHM_MAP --> x - x x - x x x
// ═══ LAYER 2: GESTURE (right-hand alternation) ═══
MECHANICS --> D U D U D U D U
Five blocks, one per layer (the Sound layer is implemented in the data file). Each block answers a single question:
- Structure:
SEQUENCE → MESURE_1 ... MESURE_4— how many measures, in what order. - Harmony:
MESURE_N → POS_X COMPAS— which chord for each measure (then delegates to rhythm). - Accents:
ACCENT_MAP → O . . O . . o .— what dynamic profile (the 3-3-2 pattern). - Rhythm:
RHYTHM_MAP → x - x x - x x x— which beats are played or muted. - Gesture:
MECHANICS → D U D U D U D U— what right-hand movement.
The polymetry { ACCENT_MAP, RHYTHM_MAP, MECHANICS } (B5) superimposes three layers in parallel — the 8 accents, the 8 beats, and the 8 strums align one by one.
The Data File — -da.Rumba
The data file gives substance to each terminal and non-terminal of the grammar:
-da.Rumba
// ═══ LAYER 4: INSTRUMENT (tuning) ═══
SETUP_GUITARE _script(
$S6 = 40;
$S5 = 45;
$S4 = 50;
$S3 = 55;
$S2 = 59;
$S1 = 64;
)
// ═══ LAYER 4: CHORD POSITIONS (F = fret, V = voiced / string played) ═══
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;
)
// ═══ LAYER 4: ACCENTS (dynamic profile) ═══
O _script($ACCENT = 127) // strong accent
o _script($ACCENT = 60) // weak accent
. _script($ACCENT = 40) // normal note
// ��══ LAYER 3: RHYTHM (which beats are played) ═══
x _script($PLAY = 1) // played beat
- _script($PLAY = 0) // muted beat
// ═══ LAYER 2: RIGHT-HAND GESTURES ═══
// Down-strum: velocity = accent × rhythm, then 6 notes low→high
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: velocity = accent × rhythm, then 6 notes high→low
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))}
Cross-Reading: Each Layer Dissected
Structure Layer — Grammar as Musical Form
At the top of abstraction, the structural rules outline the form of the piece — without mentioning any chords:
S --> SETUP_GUITARE SEQUENCE
SEQUENCE --> MESURE_1 MESURE_2 MESURE_3 MESURE_4
The structure doesn’t know if it’s Em or B7. It only says: “there are 4 measures, in this order.” To change to 8 measures or an AABA form, you only modify this section.
Derivation (B3, ORD mode) hierarchically decomposes the piece:
S
└─ SETUP_GUITARE SEQUENCE
└─ MESURE_1 MESURE_2 MESURE_3 MESURE_4
└─ POS_Em COMPAS POS_B7 COMPAS POS_B7 COMPAS POS_Em COMPAS
This is the same mechanism as a syntax tree (L4), but the nodes carry musical names, not computational ones. The Structure layer delegates to the Harmony layer, which delegates to the Rhythm layer — each within its own block.
Harmony Layer — _script() as Instrumental Memory
The harmonic layer uses _script() to configure the guitar’s state via shared variables (B4).
SETUP_GUITARE tunes the 6 strings. Each $Sn variable contains the MIDI number of the open string:
| Variable | Note | MIDI |
|---|---|---|
$S6 |
E2 | 40 |
$S5 |
A2 | 45 |
$S4 |
D3 | 50 |
$S3 |
G3 | 55 |
$S2 |
B3 | 59 |
$S1 |
E4 | 64 |
Chord positions (POS_Em, POS_B7) place fingers on the fretboard. Each string receives a fret ($Fn) and a voicing indicator ($Vn: 1 = played, 0 = muted):
Em (E minor): all open strings except frets 2 on A and D.
- Result: E2 (40+0) – B2 (45+2) – E3 (50+2) – G3 (55+0) – B3 (59+0) – E4 (64+0) ✓
B7 (B seventh): string 6 muted ($V6=0), fingerings at frets 1 and 2.
- Result: × – B2 (45+2) – D#3 (50+1) – A3 (55+2) – B3 (59+0) – F#4 (64+2) ✓
The key mechanism is decoupling: chord variables persist after POS_Em executes and remain active until the next POS_B7. To change the harmonic progression (e.g., Am–G–F–E instead of Em–B7–B7–Em), only the Harmony block of the grammar is modified — neither the structure, nor the accents, nor the rhythm, nor the gesture are affected.
An important detail: _script() is a zero-duration operation in BP3. When writing MESURE_1 → POS_Em COMPAS, the position change executes instantaneously before the first beat of the compas — not on the beat. This is exactly what happens in reality: a guitarist places their left-hand fingers before the right hand strikes. The code’s sequentiality faithfully models this causal dependency between the two hands.
Accents Layer — the 3-3-2 Dynamic Profile
The Accents layer defines the dynamic profile — how much energy on each beat, regardless of whether it’s played or not:
ACCENT_MAP --> O . . O . . o .
| Symbol | Meaning | $ACCENT |
|---|---|---|
O |
Strong accent | 127 |
o |
Weak accent | 60 |
. |
Normal note | 40 |
The 3-3-2 pattern appears in the distribution of strong accents: positions 1, 4, 7 (groups of 3+3+2):
Position: 1 2 3 4 5 6 7 8
Accent: O . . O . . o .
Groupe: | ── 3 ── | ── 3 ── | ─ 2 ─ |
The dynamic profile is pure: it says “here it’s strong, here it’s soft” without stating what is played or not. It’s the rhythmic DNA of rumba — the 3-3-2 feeling — separated from any playing decision.
Rhythm Layer — Which Beats Are Played
The Rhythm layer decides which beats sound — independently of their dynamics:
RHYTHM_MAP --> x - x x - x x x
| Symbol | Meaning | $PLAY |
|---|---|---|
x |
Played beat | 1 |
- |
Muted beat | 0 |
This is where decoupling becomes powerful. With the same 3-3-2 accent profile, different rhythms can be played — each variation only affects this line:
x - x x - x x x ← classic rumba (our example)
x - x x x x x x ← fuller variation
x x x x - x x x ← displacement of silence
x x x x x x x x ← all beats played
The dynamic profile remains identical (! . . ! . . o .) — the 3-3-2 feeling is preserved, only the rhythm changes. This is a separation impossible in traditional encoding where accent and rhythm are merged into a single symbol.
Each symbol in both layers is a terminal that acts as a state command: it does not produce sound itself, but modifies a variable ($ACCENT or $PLAY) that will be read by the Gesture layer when producing MIDI notes.
Gesture Layer — Polymetry and Micro-timing
The gesture layer models the physical movement of the right hand:
MECHANICS --> D U D U D U D U
D and U are defined in two steps — like the real gesture:
D _vel($ACCENT*$PLAY) {1, _note(...) _note(...) _note(...) ... }
U _vel($ACCENT*$PLAY) {1, _note(...) _note(...) _note(...) ... }
First, _vel($ACCENT * $PLAY) sets the force of the gesture — only once, because a rasgueado is a single gesture. Velocity combines two layers: dynamics ($ACCENT, layer 4) and rhythm ($PLAY, layer 3). If the beat is muted ($PLAY = 0), the velocity is zero regardless of the accent — the strum is silent. Then {1, 6 notes} is a poly_ratio (B5) that compresses the 6 notes into 1 unit of time — the micro-timing that transforms 6 discrete events into a “strummed” chord of a few milliseconds.
Deciphering — Poly_ratio: The expression
{1, seq}compresses the sequenceseqinto exactly 1 unit of time. For a guitar strum, this means the 6 notes are played sequentially but very quickly — like a real sweep across the strings.
The strum direction is encoded in the order of notes:
- D (down-strum): low → high, so string 6 → string 1 (
$S6+$F6first). - U (up-strum): high → low, so string 1 → string 6 (
$S1+$F1first).
Voicing (which strings sound) is managed by the left-hand’s $Vn variables: _note($Vn * ($Sn+$Fn)). If $Vn = 0 (muted string), the MIDI note is 0 — silence. This is a pragmatic shortcut: strictly speaking, MIDI note 0 is not a silence but a C-1, and a production grammar would separate voicing and pitch. But for our demonstration, this shortcut has the advantage of clearly showing how the left hand (voicing) and the right hand (dynamics) each contribute to the final result without mixing.
The superposition of the three layers is achieved by 3-voice polymetry:
COMPAS --> { ACCENT_MAP, RHYTHM_MAP, MECHANICS }
This means: playing the 8 accents, the 8 played/muted choices, and the 8 strums in parallel, temporally aligned. At beat 1, the accent (!), the rhythm (x), and the gesture (D) coincide — and the resulting velocity is $ACCENT × $PLAY = 127 × 1 = 127. At beat 2, the accent (.), the rhythm (-), and the gesture (U) coincide — and the velocity is 60 × 0 = 0 (silence). The three sequences have the same length (8 elements), so the ratio is 1:1:1.
Sound Layer — MIDI Terminals
At the bottom of the stack, the _note() and _vel() terminals produce MIDI events (B2). Each strum decomposes into:
_vel($ACCENT * $PLAY)— placed before the poly_ratio, zero duration: the force of the gesture, combining dynamics (Accents layer) and the played/muted choice (Rhythm layer)._note($Vn * ($Sn + $Fn))— inside the poly_ratio: the MIDI note = voicing × (string + fret).
The code faithfully models the physical reality of the gesture:
| Real gesture | BP3 Code | Why |
|---|---|---|
| Left hand sets the chord before the beat | POS_X (duration 0) then COMPAS |
_script() is instantaneous |
| Right hand sweeps with uniform force | _vel(...) only once before the strum |
one gesture = one velocity |
| Accent depends on the 3-3-2 pattern | $ACCENT (layer 4) in velocity |
the dynamic profile |
| Some beats are muted | $PLAY (layer 3) in velocity |
the played/muted rhythm |
| Some strings muted by the left hand | $Vn in _note($Vn * ...) |
it’s the left hand, not the right |
| Strings swept in rapid sequence | {1, _note(...) _note(...) ...} |
poly_ratio = micro-timing |
This is the destination point: all the abstraction of the upper layers resolves into MIDI events. The variables $V, $S, $F, $ACCENT, and $PLAY — originating from five different layers — converge here. The code’s sequentiality (POS → _vel → _note) reflects the gesture’s sequentiality (placing fingers → preparing the strike → sweeping the strings).
BP3 Mechanisms Mobilized — Summary Table
| BP3 Mechanism | Layer served | Role | Article |
|---|---|---|---|
| Grammar rules | Structure | Hierarchical decomposition of form | B3 |
_script() |
Harmony, Accents, Rhythm | Shared state between layers (persistent variables) | B7 |
Polymetry {A, B, C} |
Accents + Rhythm + Gesture | Superposition of three temporal flows | B5 |
Poly_ratio {n, seq} |
Gesture | Micro-timing (6-note strum in 1 beat) | B5 |
Variables $ |
All | Indirection and decoupling between layers | B4 |
_note(), _vel() |
Sound | Production of terminal MIDI events | B2 |
Six mechanisms. Six layers. Two files. One language.
What This Shows
Layer Traversal
BP3 operates at level 5 (generative) of the M3 taxonomy, but it encodes information from levels 3 and 4 within its objects. The grammar generates the structure (level 5), the _script() carry the harmony (level 4), and the _note(), _vel() terminals produce the events (level 3). A single program traverses three levels of abstraction — where normally a tool per level would be required.
Decoupling
Each layer is independently modifiable — each modification affects only one block of the grammar:
- Change the structure (8 measures instead of 4) → modify only the Structure block.
- Change the progression (Am–G–F–E instead of Em–B7–B7–Em) → modify only the Harmony block.
- Change the accents (
! . . ! . . o .→! . ! . ! . ! .) → modify only the Accents block. - Change the rhythm (
x - x x - x x x→x x x x x x x x) → modify only the Rhythm block. - Change the gesture (rasgueado → arpeggio) → modify only the Gesture block.
This is the consequence of two mechanisms: block separation in the grammar, and the variable system (B4) that allows layers to communicate via names ($ACCENT, $PLAY, $Sn, $Fn, $Vn), not hardcoded values.
Composability
Decoupling implies recombination: layers can be freely assembled. Same groove + different instrument (replace SETUP_GUITARE with an oud setup). Same structure + different harmony (Am–G–F–E progression instead of Em–B7–B7–Em). Same gesture + different groove (reggaeton pattern on the same strumming mechanics).
A Single Language
Where a classic workflow would require a DAW for structure, a score editor for harmony, a sequencer for groove, and a VST plugin for sound, BP3 unifies everything into two text files — a grammar and its data. No conversion between formats, no loss of information between levels.
This is the promise of the generative level (M3) fully realized: a language that describes how to build music, not how it appears at a given level.
Outlook: BP3 could go further. Via _script() controlling SuperCollider SynthDefs, it could also encode timbre — descending to level 1 (signal) of the M3 taxonomy. This is the direction outlined by time-objects (B9): when the grammar no longer merely generates notes, but directly controls sound synthesis.
Glossary
- Compas: The rhythmic cycle of flamenco, structured by accents that define the identity of each palo (style). In rumba, the compas is a 4-beat cycle (or 8 eighth notes) with a 3-3-2 accent pattern.
- 3-3-2 Pattern: A rhythmic grouping of 3+3+2 = 8 beats, typical of rumba, son cubano, and many popular music styles. The asymmetry creates a characteristic rhythmic tension between the groups of 3 and the final group of 2.
- Poly_ratio: A single-voice polymetric expression
{n, seq}compressing or stretching a sequence into n time units. Here,{1, 6 notes}makes 6 notes play in 1 beat — a micro-timing. - Rasgueado: A flamenco guitar technique consisting of rapid sweeps across the strings, typically alternating downward (down-strum) and upward (up-strum) movements.
- Strum: A rapid sweep across guitar strings. A down-strum (D) goes from low to high; an up-strum (U) goes from high to low.