Handel · Dixit Dominus

Rehearsal-aid technical reference

Stage-1 score parser

Literal extraction from the Legge score, score geometry and validation

Read first: current production settings

Some values within these source documents are historical. Movement 3 is now final at solo 0.7665 / piano 1.4741 (master 1.0000); Movement 10 piano is 1.7786. The modular-player and piano reference documents cover examples through Movement 8. See all current-status notes.

Download original MarkdownAll documents
Contents · 12 sections

Handel Dixit Dominus HWV 232 — Stage-1 direct-PDF parser

Canonical parser v4

Status: canonical parser infrastructure from Movement 9 onward
Adopted: 8 Oct 2026
Executable: dixit_stage1_parser_v4_CANONICAL.py
Regression suite: test_dixit_stage1_parser_v4_regression.py

This document is authoritative for the literal score-extraction / Stage-1 parser layer. It does not define vocal renderer phonemes, performing-edition overrides, piano reduction, or player balance.

The parser's job is to establish what the selected score source actually prints before any downstream interpretation is added.


1. Canonical ordering

The fundamental v4 rule is that movement/system ownership is resolved before clef, key, accidental, lyric or note state is interpreted.

PDF page
  -> identify score systems
  -> retain only systems belonging to selected movement
  -> bind named vocal staves within retained system
  -> bind clef/key glyphs to staff + retained-system geometry
  -> decode printed opening key signature
  -> require exact vocal-staff consensus
  -> parse pitches/rhythm/ties/lyrics

A page is not a musical-state boundary. Two movements can occupy different systems on the same PDF page.


2. Printed key signature: never inherit, never fall back

The movement profile deliberately contains no key signature.

For every named vocal staff independently:

  1. locate that staff's printed clef;
  2. identify the key-signature corridor between clef and time signature / first musical event;
  3. read accidental glyphs in that corridor;
  4. convert vertical staff position to a note letter using the active clef;
  5. compare the resulting semantic letter→accidental map across all named vocal staves.

The parse continues only if all named vocal staves agree exactly.

If the signature is absent, ambiguous, conflicting, or contaminated by another system, abort. There is no configured or inherited fallback.


3. Clef/key glyph ownership is two-dimensional

Nearest-staff assignment alone is insufficient on a page containing multiple score systems.

A candidate clef/key glyph belongs to a vocal staff only when:

nearest staff == candidate staff
AND
vertical distance from candidate staff <= canonical system-proximity limit

This rule must also be used conceptually by instrumental extraction: a clef on another score system cannot own notes merely because it is the closest clef on the page in one dimension.


4. Shared-page regression: PDF page 51

Philip Legge's score gives the project a particularly strong regression case: Movement 8 ends in the upper system of PDF page 51 and Movement 9 begins in the lower system of the same page.

Movement 8 — Conquassabit

profile pages:        48-51
p51 selection:        TOP system only
vocal topology:       Soprano I / Soprano II / Alto / Tenor / Bass
metre:                3/4
last bar:             50
printed key:          B-flat only
named-staff consensus: 5/5
systems:              7
vocal events:         821
lyric fragments:      362 / 362 assigned
continuation notes:   310
classified ties:      0
core issues:          0
unmapped glyphs:      0

Movement 9 — De torrente in via

profile pages:        51-54
p51 selection:        LOWER system only
vocal topology:       Soprano I / Soprano II / Tenor / Bass
metre:                4/4
last bar:             36
printed key:          B-flat + E-flat
named-staff consensus: 4/4
systems:              7
vocal events:         414
lyric fragments:      233 / 233 assigned
continuation notes:   66 (16 tied, 50 melismatic)
classified ties:      17
cross-system ties:    2
core issues:          0
unmapped glyphs:      0

The two cross-system Movement-9 ties are Soprano II bar 5→6 G4 and bar 26→27 C5.


5. Frozen byte-level regression hashes

The v4 regression suite requires exact SHA-256 identity for the principal extraction CSVs. These hashes establish that the infrastructure promotion does not alter already-validated musical extraction.

Movement 8

2c9674dae77674d0509c8da2ee0d2c584e199dca963b27081f8a7286b3f50b42  dixit-mvt8-vocals-v4.csv
f8d915b0266984d98e2716979115a669ae6ce509f924d73d2c09ee1ac4663504  dixit-mvt8-lyrics-v4.csv
092ffe3ade647cb685be7279771d235840a12e751aac55303b147c9de28a4e1e  dixit-mvt8-syllables-v4.csv
c5ba9a4c52cfe96fe601257064fd10a00584aa9567f38e0ddc62257afacc17cc  mvt8-key-signature-audit.csv

The first three files are byte-identical to the validated M8-v3 extraction counterparts after filename/schema promotion.

Movement 9

dd404fc078a6145288c91fcfd9a91e1c5caf4085010c47c03632956abeb2ad88  dixit-mvt9-vocals-v4.csv
a5cac5f09d700af9a8daf2e771ece56e92a2193dca251cd0dd7d5f03a4cacec7  dixit-mvt9-lyrics-v4.csv
7dda1cab37dec2d00253eb3c457cf959b55720777bec5c9cd01184c155a5b27c  dixit-mvt9-syllables-v4.csv
cb080446a54644f27838ea4c55104bdf1b7c3243acda96396bba76ceac6c2035  mvt9-key-signature-audit.csv

The first three files are byte-identical to the validated M9-v1 Stage-1 extraction counterparts.


6. Canonical profiles are explicit, but musical state is still read from score

A profile may contain structural facts required to delimit the parse:

movement number/title
PDF page span
shared-page system slice
named vocal topology
metre / expected final bar

A profile must not contain a guessed key signature used to rescue parsing. The key is score-derived state.

The current executable freezes M8 and M9 as profiles because they form the shared-page regression pair. Future movement profiles should be added only after movement boundaries/topology are established and then frozen by regression.


7. Rhythm closure is necessary, not sufficient

Zero bar-closure errors validate durations/topology only. They do not validate:

The canonical QC layers remain separate.


8. Running the parser

python3 dixit_stage1_parser_v4_CANONICAL.py \
  IMSLP13037-232dixit-philip-legge.pdf \
  --movement 9 \
  --no-render

For the frozen M8 regression:

python3 dixit_stage1_parser_v4_CANONICAL.py \
  IMSLP13037-232dixit-philip-legge.pdf \
  --movement 8 \
  --no-render

Preview tempo defaults to 100 BPM and can be overridden with --tempo. The literal score extraction is not changed by preview tempo.


9. Running the regression suite

python3 test_dixit_stage1_parser_v4_regression.py \
  dixit_stage1_parser_v4_CANONICAL.py \
  IMSLP13037-232dixit-philip-legge.pdf

A successful run must report both movement passes and the explicit shared-page boundary pass.


10. Promotion rule

dixit_stage1_parser_v4_CANONICAL.py supersedes the M8-specific v3 parser as the infrastructure starting point for subsequent movements.

The older movement-specific parsers remain historical/frozen reconstruction artifacts. Do not rewrite locked Movement-8 production data merely because the shared parser implementation has been promoted.