Ga naar inhoud

Mapping VSA ↔ vsa-template (experimenteel)

Status: hypotheses + architectuurkeuze VSA→template-instance; geen normatieve VSA 1.0-wijziging.

Implementatie: src/vsa/template_mapping.py (frase-toewijzing) en src/vsa/template_instance.py (event-niveau, S uit VSA + A/T/B uit template).

Doel

Beschrijven hoe een VSA-tekstblok (melodie S) op template-events van een vsa-template landt, zodat A, T en B uit de template meegenomen kunnen worden naar een afgeleide (bijv. MusicXML) — zonder lyrics in de template-syntax te stoppen.

Architectuur: VSA→template-instance (besloten)

Stem Toonhoogte / contour Ritme / optional / split-merge
S uit VSA + do-context uit VSA (scopes, ELMs, syllaben)
A/T/B uit template-laddergraden zelfde eventkeuzes als voor S

ELM vs EHM (bindend)

Modifier Rol in de instance
ELM (_, __, ~, -., ~., …) VSA bepaalt de werkelijke duur. Template-duration is alleen een formule-indicatie op het blad; in de uitgewerkte partituur wint de VSA-ELM. A/T/B krijgen dezelfde duur als S op dat event (H5).
EHM (/, \, ~, …) / resulterende laddergraad Moet precies matchen op template-pitches.S (zelfde klinkende toon t.o.v. do/mode). Geen “ongeveer”; mismatch → harde fout (H9), geen stil hold.

Kort: duur mag afwijken van de formule; toonhoogte niet.

Tekstregels → template-frasen

Elke VSA-regel (gescheiden door *) is één tekstfrase. De mapper wijst regels in volgorde toe aan template-frase-ids.

Legacy (nog ondersteund)

Vorm YAML Betekenis
cycle-form cycle + final cyclisch herhalen tot één regel resteert
sequence-form sequence vaste volgorde, geen herhaling

cycle: ["1", "2"] + final: laatste compileert naar:

text_mapping:
  - repeat: ["1", "2"]
    until: final
  - phrase: laatste

text_mapping (algemeen)

Lijst van stappen (in volgorde):

Stap YAML-vorm Effect
enkel phrase: "1" één tekstregel → frase 1
reeks sequence: ["1", "3", "2a"] vaste reeks, één regel per id
herhaling repeat: ["2", "3"] + until cyclisch toewijzen tot stopconditie

until: final

Herhaal het patroon cyclisch over zoveel regels als nodig, zodat de tail (alle stappen ná deze repeat) precies overblijft. Typisch eindigt de tail op phrase: laatste.

Geen eis dat het aantal regels vóór laatste een veelvoud van k is. Bij k = 2 en n = 7 regels: 1, 2, 1, 2, 1, 2, laatste.

until: { remaining: N }

Stop met herhalen wanneer nog N regels over zijn; die vallen op de tail (meestal sequence: [...]). Voorbeeld tropaar toon 1 (variant met slot 1, 1a, 1a, 2):

- repeat: ["1", "2"]
  until:
    remaining: 4
- sequence: ["1", "1a", "1a", "2"]

Voorbeelden (bladnotatie → text_mapping)

Blad / gewoonte text_mapping
\|\|: 1, 2 :\|\| laatste repeat [1,2] until final + phrase laatste
1 \|\|: 2, 3 :\|\| laatste phrase 1 + repeat [2,3] until final + phrase laatste
1, 3, 1, 2, 3, 1, 2a, 4 sequence: [1, 3, 1, 2, 3, 1, 2a, 4]
1, 2, 3, \|\|: 4, 5, 3a :\|\| laatste sequence [1,2,3] + repeat [4,5,3a] until final + phrase laatste

mapping_plans (meerdere plannen)

Als één template op het blad meerdere cycle-notaties heeft (bijv. tropaar toon 1), of de toewijzing afhangt van het aantal tekstregels:

mapping_plans:
  - id: standard
    label: "||: 1, 2 :|| laatste"
    when:
      default: true
    steps:
      - repeat: ["1", "2"]
        until: final
      - phrase: laatste
  - id: extended-close
    label: "||: 1, 2 :|| 1, 1a, 1a, 2"
    when:
      stanza_count: 5
    steps:
      - repeat: ["1", "2"]
        until:
          remaining: 4
      - sequence: ["1", "1a", "1a", "2"]

Selectie: select_mapping_plan(doc, stanza_count) — eerste plan waarvan when matcht; anders plan met when.default: true.

when-sleutel Match
default: true fallback
stanza_count exact aantal regels
stanza_count_mod { mod: 3, remainder: 0 } → n % 3 == 0
stanza_count_min minimaal n regels
stanza_count_max maximaal n regels

Voorbeeld 3n regels met prefix + cycle + afwijkende slot:

- id: triple
  when:
    stanza_count_mod:
      mod: 3
      remainder: 0
  steps:
    - phrase: "1"
    - repeat: ["2", "3", "1"]
      until: final
    - phrase: "2a"
    - phrase: laatste

Frase-ankers (inclusief melisma)

Anchor (YAML) Bladlabel Bedoeling
e.st. e. st. eerste streek / inzet
l.st. l. st. laatste streek op cadensnoot
vl.st. vl. st. voorlaatste streek
l.lgr. l. lgr. start van het slotmelisma (laatste lettergreep)

l.lgr. wijst naar een noot waar nog noten achteraan komen. Vanaf dat event tot het einde van de template-frase horen alle noten bij de laatste lettergreep van de tekst — één syllabe over meerdere template-events (melisma). In VSA hoort dat te blijken als één zangelement met meerdere muzikale posities (& in de modifiers).

Hypotheses (event-niveau)

# Hypothese
H1 Ongemarkeerde VSA-syllaben vóór cadens-scopes vallen op recite. open (zelfde graad, eigen event op het formuleblad) wordt in de instance overgeslagen als de VSA meteen reciteert — geen dubbele noot. YAML blijft twee events.
H2 Cadens-scopes corresponderen met cadence-events, vaak bij l.st. of erna.
H3 {/…} aan het begin van een regel kan e.st. van frase 2 (of vergelijkbaar) zijn.
H4 optional: true events: mee als VSA-S dat slot gebruikt, anders weg — voor alle stemmen.
H5 ELM: VSA bepaalt de werkelijke nootlengte; template-duration is alleen formuleblad. Die VSA-duur geldt parallel voor A/T/B.
H6 Blijft VSA-S op dezelfde graad voor extra syllaben, dan houden A/T/B hetzelfde slot-akkoord.
H7 Verplichte template-slots moet VSA aandoen (eigen syllabe, hold H6, of melisma H8). Ongebruikt verplicht slot aan het eind → fout. Een andere toon in de cadens overslaan mag alleen via optional: true (H4). Rest van een ondergevulde zelfde-S-run mag stil weg.
H8 l.lgr.: start van een slotmelisma — geankerd event plus alle volgende events in de frase op de laatste VSA-syllabe.
H9 EHM/hoogte: VSA-S moet exact op een resterend template-S-slot landen (klinkende toon). Mismatch → TemplateInstanceError; geen stil hold, geen “ongeveer”.

H4 vs H7 (optional vs verplicht)

Soort template-slot VSA doet het slot niet aan Gedrag
optional: true (haakjes op het blad) — stil weglaten voor alle stemmen (H4)
verplicht (geen optional) — TemplateInstanceError — VSA moet het slot meenemen of de template/VSA corrigeren
verplicht, maar VSA “springt” naar andere toon tussenslot(s) met andere S-graad fout tenzij die tussenslots optional: true zijn
rest van een zelfde-S-run na de laatste gebruikte syllabe op die graad VSA gaat door naar een latere andere toon mag stil weg (ondergevulde run; “laatst gebruikt” telt ook de recite-graad)
optional tussenslots bij sprong naar latere toon VSA-pitch matcht een later slot optional tussenslots weglaten (H4); daarna koppelen

H6-aanscherping: blijven er VSA-syllaben op dezelfde graad én is het volgende template-slot ook die graad, dan vult de volgende syllabe dat slot (bijv. l.st.), in plaats van alles op het eerste slot te houden.

H5 (duur — ELM uit VSA)

De template geeft ongeveer aan hoe lang formuleslots zijn. In de instance bepalen de VSA-ELMs de lengte.

Situatie Gedrag
VSA-scope met _ / __ / ~ / … die MusicXML-duur op het mapped event (alle stemmen)
Template-event had andere duration (bijv. ~ vs VSA _) template genegeerd in de instance; wel zichtbaar op het formuleblad
Twee syllaben op dezelfde graad (split) twee events; elk met eigen VSA-duur; A/T/B-akkoord herhaald (H6)
Eén VSA-duur i.p.v. langere formule-indicatie (merge) één event met VSA-duur; geen aparte A/T/B-ritmes
Recite (ongemarkeerd) in instance vóór print-collapse kwart per syllabe; MSCZ-collapse naar \|\|O\|\| is een print-stap

Hoogte (EHM — exact)

Vergelijking: absolute toonhoogte van de VSA-noot (uit EHM + do-context) ↔ laddergraad pitches.S van template-events (zelfde do/mode). Geen tolerantie: verkeerde graad is fout, ook als de ELM “ongeveer” past. | Situatie | Gedrag | | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | VSA-pitch = huidig slot | koppelen | | VSA-pitch = later slot; overgeslagen tussenslots alleen optional of rest van dezelfde S-run | tussenslots weg; daarna koppelen | | VSA-pitch = later slot; ≥1 overgeslagen tussenslot is verplicht én andere S-graad | TemplateInstanceError (verplicht slot overgeslagen) | | VSA-pitch = zelfde slot opnieuw | hold (H6); bij volgend zelfde-S-slot: dat slot vullen | | VSA-pitch past nergens meer in de resterende tail | TemplateInstanceError (hoogte-mismatch) | | Extra noot ná de tail, andere hoogte | TemplateInstanceError | | Extra noot ná de tail,zelfde hoogte als slot | hold (H6) | | Einde VSA terwijl er nog verplichte template-slots resten | TemplateInstanceError (verplicht slot niet aangedaan) | | Einde VSA; resten alleen optional: true | optional resten weglaten (H4) |

Zo wordt bijv. {-&/Schep_&_}{\per_} (mi–fa–mi) op template-laatste (mi–re–mi) afgewezen i.p.v. A/T/B stil op mi te laten hangen.

Foutmeldingen (instance-mapping)

Mappingfouten (H7/H9 e.d.) moeten bruikbaar zijn, in dezelfde geest als vsa validate:

Laag Inhoud
Compact korte regel: bestand, regel/kolom (of frase-id + syllabe), foutcode
Uitgebreid wat er mis is (VSA-pitch vs verwachte template-S-slots); hint hoe te herstellen (VSA aanpassen, optional zetten, of ander cadenspad)

Minimaal in elke melding: bronpad, regel/kolom in de VSA-bron (via VsaNote.line/column), frase-id, betrokken lyric/syllabe, verwachte vs gevonden laddergraden. Compact: bestand:regel:kolom: CODE.

Parallelle cadenspaden (of)

Eén template-frase mag 2+ slot-/cadensreeksen hebben, in YAML als of: met minstens twee events:-lijsten. De VSA kiest impliciet welk pad klinkt: de mapper probeert de paden in volgorde en neemt het eerste waarvan de hoogten (EHM) kloppen. Geen pad → TemplateInstanceError (VSA-TEMPLATE-CADENCE-PATH / hoogte-mismatch).

Dit zijn formule-alternatieven in één template, geen aparte uitvoeringsvorm-en (die horen bij zangstuk → variant → uitvoeringsvorm). Tropaar-toon-4 laatste is nu alleen mi–re–mi; een fa-pad kan later als tweede of-tak zonder extra YAML-bestand.

Formuleblad (template.mscz): toont pad 0 (eerste tak).

mode / do (template vs VSA)

Template-mode is major of minor — dezelfde waarden als de VSA-parser. Bij map_vsa_to_template moeten VSA-frontmatter mode en do (indien aanwezig) exact gelijk zijn aan de template; anders VSA-TEMPLATE-MODE-MISMATCH / VSA-TEMPLATE-DO-MISMATCH. Geen stille afwijking.

Sequence-form / text_mapping-lengte

sequence: ["1", "2", "3"] eist precies drie VSA-regels. Cycle+final is variabel (herhaling tot de slotfrase past). Past het aantal regels niet bij het plan → VSA-TEMPLATE-TEXT-MAPPING (zelfde geest als vsa validate).

Tenor-octaaf (tropaar toon 4)

Openingsakkoord tenor sol-1 t.o.v. do: F4 = C4 (niet C3). Bass do-1 = F3. Dat is de gekozen spelling in template.yaml; pitches_status blijft provisional tot een volledige PDF-audit van andere tonen.

Inline VSA in proza

Toon-aanduiding (T.4, T.N) hoort niet in de zingbare VSA-regel (geen lyric-syllabe). Klein fragment in markdown/proza (alleen hoogtemarkering, eventueel Amen) is een aparte presentatielaag — niet de instance-lyric-pipeline. Corpus-.vsa heeft geen T.N vóór EHM’s.

Corpus en detail

Library-werkmappen: library/.

Corpus Toon 4: library/tropaar-toon-4/notes/corpus.md.

Elia regel 1 (instance + MusicXML): library/tropaar-toon-4/notes/elia-mapping.md.

Wat deze laag niet doet

  • Geen nieuwe VSA-syntax voor SATB (SATB blijft in de template).
  • Geen automatische keuze tussen plannen op inhoud van de tekst (alleen stanza_count / expliciet plan_id); inhoudelijke keuze blijft redactie.