Aller au contenu
roomi fields

BPscript · S9 · Conception

Le système de hauteurs en six couches

De l'acteur au Hz — comment BPscript résout les notes pour toutes les traditions musicales

Publié le 21 mai 2026 · Read in English

De l’acteur au Hz

« Sa » n’est pas une fréquence. C’est un nom. Le chemin entre ce nom et les 261.63 Hz qui sortent du haut-parleur traverse six couches — chacune indépendante, chacune remplaçable.

Où se situe cet article ?

On a vu en S3 que chaque acteur a son propre resolver. Ici on ouvre le système de hauteurs pour comprendre ses six couches — et pourquoi elles sont séparées.


Pourquoi six couches ?

La plupart des systèmes musicaux informatiques traitent les hauteurs en un bloc : un nom de note → un numéro MIDI → une fréquence. Ça marche pour le piano occidental en tempérament égal (12-TET : douze demi-tons identiques). Ça atteint vite ses limites dès qu’on sort de ce cadre :

  • Un sitar en 22 shruti (les micro-intervalles de la musique indienne classique) n’utilise pas les mêmes intervalles qu’un piano
  • Un maqam arabe (mode mélodique arabe) a des quarts de ton que le MIDI standard ne peut pas représenter
  • Un raga indien peut avoir des gammes différentes à la montée et à la descente
  • Deux musiciens jouant les mêmes notes peuvent être accordés différemment

BPscript organise ces distinctions en six couches :

acteur      →  contexte (qui joue quoi, où)
alphabet    →  noms + altérations (comment on l'écrit)
octaves     →  convention de registre (héritée de l'alphabet)
temperament →  grille d'intervalles (où se placent les notes)
tuning      →  gamme concrète (quels degrés on utilise dans la gamme)
resolver    →  jeton → fréquence (ce qui produit le son)

La première couche — l’acteur — est le contexte qui lie toutes les autres. Les quatre suivantes (alphabet, octaves, tempérament, tuning) sont des données culturelles et mathématiques. La dernière produit le tout.


Couche 0 — Acteur : l’unité de rattachement

Une scène BPscript peut contenir plusieurs instruments qui partagent le même alphabet. Deux sitaristes jouent les mêmes notes (sargam — le solfège indien : sa re ga ma pa dha ni) mais peuvent aller vers des sorties différentes, utiliser des accords différents, ou des conventions d’octave différentes. L’alphabet seul ne suffit pas : il manque le contexte.

L’acteur est l’unité qui lie toutes les couches de résolution ensemble :

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

Les propriétés disponibles de la directive @actor :

PropriétéObligatoireRôle
alphabetouivocabulaire (noms des symboles)
scalesi l’acteur a des hauteurssélection des degrés → hauteur via tempérament
soundssi percussif (sans hauteur) ou timbre spécifiquedéfinitions par terminal (timbre, perc, échantillon)
transportouidestination de rendu
evalnonclé d’évaluation pour les backticks (défaut : aucun REPL — null)

Si scale est omis → pas de résolution de fréquence (percussions, DMX). Si sounds est omis → timbre par défaut du transport.

Le . (notation pointée) préfixe un terminal par son acteur, comme un espace de noms :

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

Si un seul acteur contient un symbole, le préfixe est facultatif (résolution implicite). Si plusieurs acteurs partagent le symbole sans préfixe → erreur. Chaque acteur a son propre resolver : le resolver n’est pas un singleton global, c’est une instance par acteur. C’est ce qui permet à sitar1.Sa et sitar2.Sa — même nom, même octave — de produire des fréquences différentes parce que leur scale (et donc leur tempérament) diffère.


Couche 1 — Alphabet : noms et altérations

L’alphabet définit une séquence ordonnée de noms et les altérations disponibles. Les noms et altérations sont purement nominaux — pas de fréquence, pas de MIDI, pas de ratio. La convention de registre (octaves), elle, fait l’objet de la couche suivante : elle dit seulement comment s’écrivent les notes et chaque alphabet choisit la sienne (western → registres western, sargam → registres saptak).

{
  "western": {
    "notes": ["C", "D", "E", "F", "G", "A", "B"],
    "alterations": ["bb", "b", "", "#", "##"]
  },
  "sargam": {
    "notes": ["sa", "re", "ga", "ma", "pa", "dha", "ni"],
    "alterations": ["", "komal", "tivra"]
  }
}

La position dans la liste est l’index (degré) : C = degré 0, D = degré 1, etc.

Chaque tradition a ses propres conventions d’altérations :

TraditionAltérations
Occidentalebb, b, #, ##
Sargam (Inde)komal (bémol), tivra (dièse)
Arabebb, b, half_b, half_#, #, ##
Turquebakiye, kucuk_mucenneb, buyuk_mucenneb

Couche 2 — Octaves : la convention de registre

Comment nommer les registres (octaves) ? C’est une couche à part entière, rattachée à l’alphabet dont elle hérite par défaut (surchargeable par acteur) — chaque tradition a la sienne :

{
  "western": {
    "position": "suffix",
    "separator": "",
    "registers": ["0","1","2","3","4","5","6","7","8","9"],
    "default": 4
  },
  "saptak": {
    "position": "suffix",
    "separator": "_",
    "registers": ["v", "", "^"],
    "default": 1
  }
}
  • position : "prefix" ou "suffix" — le registre vient avant ou après la note
  • separator : caractère entre note et registre ("" = collé, "_" = underscore)
  • registers : liste ordonnée grave→aigu, "" = pas de marqueur (registre par défaut)
  • default : index du registre central (celui qui sert de référence)

Exemples de résolution :

  • Western : C4 → note C, registre index 4
  • Saptak : Sa_^ → note Sa, registre index 2 (taar saptak)
  • Saptak : Sa → note Sa, registre index 1 (madhya, par défaut — "" dans la liste)

Couche 3 — Tempérament : la grille mathématique

Le tempérament définit la grille d’intervalles — une division de l’espace des fréquences. Il est indépendant de tout alphabet ou gamme.

Type “table” — ratios fixes

{
  "12TET": {
    "period_ratio": 2,
    "divisions": 12,
    "ratios": ["0c", "100c", "200c", "300c", "400c", "500c",
               "600c", "700c", "800c", "900c", "1000c", "1100c"]
  },
  "22shruti": {
    "period_ratio": 2,
    "divisions": 22,
    "ratios": [1, "256/243", "16/15", "10/9", "9/8", "32/27", "6/5", "5/4",
               "81/64", "4/3", "27/20", "45/32", "729/512", "3/2", "128/81",
               "8/5", "5/3", "27/16", "16/9", "9/5", "15/8", "243/128"]
  }
}
  • period_ratio : l’intervalle qui se répète (2 = octave, 3 = tritave pour Bohlen-Pierce)
  • divisions : nombre de pas dans la période
  • ratios : le ratio de chaque pas — 3 formats acceptés :
FormatUsageExemplePrécision
FractionIntonation juste, shruti, pythagoricien"9/8"Exacte (rationnels)
DécimalGamelan, systèmes mesurés1.05946Approximation
CentsTempéraments égaux (12-TET, 24-TET)"100c"Convertie en irrationnel

Le resolver normalise tout en float au chargement. Un seul chemin de calcul ensuite.

Type “parametric” — Dynamic Tonality

Inspiré de la Dynamic Tonality (Milne, Sethares, Plamondon). Au lieu de ratios fixes, le tempérament est défini par un period et un generator dont la taille peut varier continûment :

{
  "meantone": {
    "type": "parametric",
    "period": 1200,
    "generator": 697,
    "generator_range": [685, 720],
    "mapping": [[1,0], [1,1], [0,4]],
    "primes": [2, 3, 5],
    "commas": ["81/80"]
  }
}

En faisant varier le generator de 685 à 720 cents, on traverse un continuum de tempéraments :

GeneratorTempéramentCaractère
694.7¢2/7-comma meantoneTrès doux
697¢1/4-comma meantoneClassique
700¢12-TETÉgal
702¢PythagoricienBrillant

Tous partagent le même mapping (tierce = 4g-2P, quinte = g). Seule la couleur change.

Le generator est un CV — il peut varier dans le temps via la polymétrie (S5) :

// Morphe du pythagoricien au mésotonique en temps réel
S -> { Sa Re Ga Pa , sitar.tuning.generator(ramp(702, 697)) }

Toutes les fréquences changent simultanément — la structure de la gamme reste, seul le tempérament bouge.


Couche 4 — Tuning : la gamme concrète

Le tuning fait le pont entre les noms (alphabet) et les positions (tempérament) :

{
  "Cmaj_just": {
    "temperament": "just_5limit",
    "degrees": [0, 2, 4, 5, 7, 9, 11],
    "alterations": { "#": "25/24", "b": "24/25" },
    "baseHz": 440,
    "baseNote": "A",
    "baseRegister": 4
  }
}
  • degrees : quels pas du tempérament sont utilisés, dans l’ordre de l’alphabet
  • alterations : les altérations, chiffrées de trois façons (voir ci-dessous)
  • baseHz/baseNote/baseRegister : le point de référence

Trois façons de chiffrer une altération

Une altération (#, komal, half_b…) est un décalage appliqué à un degré. Selon le système, on la chiffre de trois manières — toutes ramenées à un rapport de fréquence au chargement :

FaçonExempleQuand
ratio"#": "25/24"intonation juste : le ½-ton n’est pas un degré, il faut un rapport exact
cents"half_b": "-50c"microtonal mesuré : le quart de ton arabe = −50 cents
degrés"#": "+1"grille égale : le ½-ton est un degré, on décale d’un pas (ton = 2 degrés)

C’est exactement la différence diatonique / chromatique :

// Diatonique juste — 7 degrés ; le # n'est PAS un degré → ratio
"Cmaj_just":       { "degrees": [0,2,4,5,7,9,11],            "alterations": { "#": "25/24" } }

// Chromatique égal — 12 degrés ; le # EST déjà un degré → décalage de pas
"chromatic_12tet": { "degrees": [0,1,2,3,4,5,6,7,8,9,10,11], "alterations": { "#": "+1" } }

En diatonique, C# se calcule (C × 25/24) car la gamme ne contient pas ce ½-ton. En chromatique, C# est simplement le degré suivant. Le ratio reste indispensable dès qu’on quitte la grille égale : 25/24 n’est ni un pas entier ni une fraction propre d’octave dans un système inégal.

Gammes composées — tétracordes et jins

Dans les traditions arabe, turque et grecque, les gammes sont construites par empilement de fragments (tétracordes = 4 notes couvrant une quarte) :

{
  "maqam_rast": {
    "compose": ["jins_rast", "jins_rast"],
    "junction": "3/2",
    "description": "Maqam Rast = Rast + Rast sur la quinte"
  }
}

Le resolver empile les fragments au chargement → produit un tableau de degrés comme un tuning normal.

Gammes directionnelles — aroha et avaroha

Dans la musique indienne, certains ragas ont des gammes différentes à la montée et à la descente :

{
  "bhairav": {
    "temperament": "22shruti",
    "ascending":  [0, 2, 7, 9, 13, 15, 20],
    "descending": [0, 4, 7, 9, 13, 17, 20],
    "baseHz": 240,
    "baseNote": "sa",
    "description": "Raga Bhairav — aroha et avaroha différents"
  }
}

Quand ascending et descending sont présents (au lieu de degrees), le resolver choisit selon la direction mélodique — déterminée par le contexte (note précédente vs courante).


Couche 5 — Resolver : jeton → fréquence

Le resolver est le composant runtime qui assemble les couches précédentes. Il y a un resolver par acteur (S3) — pas un singleton global. C’est l’acteur (couche 0) qui lui fournit son alphabet (registres compris), son tuning et son tempérament.

Le chemin de résolution :

"Sa_^" (jeton brut)
  → analyse : note="sa", registre="^" (index 2)
  → recherche alphabet : sa = degré 0
  → tuning : degré 0 → pas 0 du tempérament
  → tempérament : pas 0 → ratio 1/1
  → octave : register 2 - default 1 = +1 octave → ratio × 2
  → baseHz : 240 × 1 × 2 = 480 Hz

Même jeton, deux acteurs, deux résultats :

  • Sa_^ via sitar1 (22 shruti, base 240) → 480 Hz
  • Sa_^ via sitar2 (12-TET, base 261.63) → 523.25 Hz

La transposition : pourquoi c’est compliqué

Un point musicologique fondamental qui justifie cette architecture : la transposition ne fonctionne pas de la même façon dans tous les systèmes.

En tempérament égal (12-TET), transposer = décaler d’un nombre de demi-tons. Simple. Mais :

  • En intonation juste, les pas ne sont pas tous égaux : décaler la mélodie sur la grille déforme les intervalles. Transposer Do majeur en Ré en ajoutant un ton à chaque note fait passer la tierce majeure de 5/4 (juste, 386 c) à 81/64 (pythagoricienne, 408 c) — le comma syntonique apparaît. (C’est la même inégalité des pas qui fait que C# et Db n’y ont pas la même fréquence.)
  • En 22 shruti : même problème, en pire. « Monter d’un pas » change l’intervalle selon la position.
  • Solution : plutôt que de compter des pas, on change la tonique (la note de référence) en préservant les intervalles.

BPscript gère ça en séparant tonique (tuning, baseNote/baseHz) et grille (tempérament, ratios). Changer la tonique = changer le tuning, pas le tempérament. Les détails sont dans l’annexe transposition de PITCH.md, développée dans S15.


Ce qu’il faut retenir

  1. Six couches : acteur → alphabet → octaves → tempérament → tuning → resolver
  2. Acteur = contexte de rattachement (alphabet + tuning + octaves + sound + transport) — un resolver par acteur
  3. Alphabet = la notation — noms + altérations, zéro fréquence
  4. Octaves = convention de registre, héritée de l’alphabet (surchargeable par acteur)
  5. Tempérament = grille mathématique — ratios en fractions, décimal ou cents
  6. Tuning = gamme concrète — degrés + altérations + référence Hz
  7. Gammes composées (tétracordes/jins) et directionnelles (aroha/avaroha)
  8. Dynamic Tonality : le generator du tempérament peut varier comme un CV — morph de tempérament en temps réel

Pour aller plus loin

  • Milne, A., Sethares, W. & Plamondon, J. (2007) : “Isomorphic controllers and dynamic tuning” — les fondements de la Dynamic Tonality
  • Asselin, P.-Y. (1985) : Musique et tempérament — référence francophone sur les systèmes d’accord historiques
  • Sethares, W. (2005) : Tuning, Timbre, Spectrum, Scale — le couplage timbre-tuning (spectral matching)

Glossaire

  • Acteur : Unité de rattachement qui lie alphabet + scale + sounds + transport — porte un resolver dédié
  • Alphabet : Séquence ordonnée de noms de notes + altérations disponibles — purement nominal
  • Octaves : Convention de nommage des registres (position, séparateur, liste grave→aigu)
  • Tempérament : Grille mathématique d’intervalles — division de l’espace fréquentiel en pas
  • Tuning : Gamme concrète = quels pas du tempérament utiliser + fréquence de référence
  • Resolver : Instance (1 par acteur) qui traduit un jeton en fréquence en traversant les six couches
  • Dynamic Tonality : Tempérament paramétrique dont le generator peut varier continûment
  • Tétracorde/Jins : Fragment de 4 notes couvrant une quarte — brique de base des gammes arabes et turques
  • Aroha/Avaroha : Gamme ascendante/descendante d’un raga indien — peuvent être différentes
  • Cents : Unité logarithmique d’intervalle — 1200 cents = 1 octave, 100 cents = 1 demi-ton en 12-TET
  • MOS (Moment of Symmetry) : Gamme générée par un seul intervalle (generator) réduit dans une période

Liens dans la série

  • S3 — Types, acteurs et rattachements — chaque acteur a son propre resolver
  • S5 — Structurer le temps — le generator comme CV dans la polymétrie
  • S10 — Le pipeline — comment les cinq couches sont chargées et résolues
  • S15 — La transposition au-delà du tempérament égal

Prérequis : S3 Temps de lecture : 16 min Tags : #BPscript #pitch #tempérament #tuning #alphabet #intonation


Prochain article : S10 — Sous le capot : compilateur, moteur et dispatcher


← Retour à l’index