tonus 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +275 -1
- package/README.md +3 -3
- package/dist/engines/chant/attest.js +8 -8
- package/dist/engines/chant/hour.js +3 -3
- package/dist/engines/chant/intone.js +7 -1
- package/dist/engines/score/cadence.d.ts +10 -4
- package/dist/engines/score/cadence.js +10 -4
- package/dist/engines/score/emitters/accidentals.d.ts +9 -0
- package/dist/engines/score/emitters/accidentals.js +76 -13
- package/dist/engines/score/emitters/atramentum.js +1 -1
- package/dist/engines/score/emitters/breaking.d.ts +2 -2
- package/dist/engines/score/emitters/breaking.js +2 -2
- package/dist/engines/score/emitters/moderna.js +165 -17
- package/dist/engines/score/emitters/svg.d.ts +16 -0
- package/dist/engines/score/emitters/svg.js +19 -12
- package/dist/engines/score/emitters/tracks.js +29 -10
- package/dist/engines/score/ir.js +24 -4
- package/dist/engines/score/neume.d.ts +19 -0
- package/dist/engines/score/neume.js +35 -0
- package/dist/engines/score/parse.js +4 -1
- package/dist/engines/score/types.d.ts +6 -0
- package/dist/engines/temper/data/guido.js +4 -2
- package/dist/engines/temper/gabc.d.ts +12 -0
- package/dist/engines/temper/gabc.js +51 -18
- package/dist/engines/temper/neume.d.ts +1 -1
- package/dist/engines/temper/neume.js +24 -3
- package/docs/api/calendar.md +4 -4
- package/docs/api/census.md +20 -20
- package/docs/api/chant.md +27 -27
- package/docs/api/heavens.md +7 -7
- package/docs/api/index.md +5 -5
- package/docs/api/score.md +191 -138
- package/docs/api/tuning.md +31 -23
- package/package.json +4 -3
package/docs/api/score.md
CHANGED
|
@@ -42,8 +42,8 @@ const score = tonus.notatio(introit, { temperamentum: t });
|
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
The structured view is `score.phrases`; the flat view, one row per note,
|
|
45
|
-
is `score.tabula`. Phrases split at every divisio
|
|
46
|
-
notation, signs of punctuation rather than measure:
|
|
45
|
+
is `score.tabula`. Phrases split at every divisio, the bars of chant
|
|
46
|
+
notation, which are signs of punctuation rather than measure:
|
|
47
47
|
|
|
48
48
|
| divisio | name |
|
|
49
49
|
| ------- | ---------------------------- |
|
|
@@ -83,18 +83,27 @@ interface Syllable {
|
|
|
83
83
|
lyric: string;
|
|
84
84
|
runs?: LyricRun[]; // styled spans, present only when GABC markup styled this syllable
|
|
85
85
|
notes: Note[];
|
|
86
|
-
neume: Neume;
|
|
86
|
+
neume: Neume; // the syllable read as ONE figure
|
|
87
|
+
neumes: Neume[]; // its figures, as GABC groups them, each classified
|
|
87
88
|
melisma: number; // notes on this syllable (1 = syllabic, >1 melismatic)
|
|
88
89
|
}
|
|
89
90
|
```
|
|
90
91
|
|
|
92
|
+
A syllable carries neumes rather than being one. GABC marks the figures with
|
|
93
|
+
`!`, `/` and `//`, and `neumes` names each; `neume` reads the whole syllable as
|
|
94
|
+
a single figure, which for a melisma of several is usually `compound`. A
|
|
95
|
+
syllable of one figure reports the same shape both ways. The salicus is the
|
|
96
|
+
exception and reports at syllable scope: its rule reads the oriscus on the
|
|
97
|
+
next-to-last note of an ascent, and the scribe may break the figure between
|
|
98
|
+
that oriscus and the summit.
|
|
99
|
+
|
|
91
100
|
GABC's lyric markup is decoded at parse, so `lyric` is always clean display
|
|
92
101
|
text: the `<sp>` shortcuts arrive as real characters (`<sp>V/</sp>` → ℣,
|
|
93
102
|
`<sp>R/</sp>` → ℟, `<sp>+</sp>` → the flex †, `<sp>'ae</sp>` → ǽ, the
|
|
94
103
|
`\greheightstar` verbatim → the raised *), centering braces and layout tags
|
|
95
104
|
(`<clear>`, `<nlba>`) vanish, above-lines text (`<alt>`) is not lyric text,
|
|
96
105
|
and page cross-references (`\pageref`) to the paper books are dropped. Style
|
|
97
|
-
tags
|
|
106
|
+
tags (`<i>`, `<b>`, `<sc>`, `<c>` for rubric color, `<e>` for elision) survive
|
|
98
107
|
as `runs`, styled spans that concatenate to `lyric`; a style opened in one
|
|
99
108
|
syllable and closed several later (the common `<i>ij.</i>` and euouae
|
|
100
109
|
patterns) styles every syllable it crosses. Both notation species draw the
|
|
@@ -280,7 +289,7 @@ analysis, visualization, or emission.
|
|
|
280
289
|
|
|
281
290
|
`Harmony` exposes the same surface for voiced bodies
|
|
282
291
|
([heavens.md](heavens.md#the-tabula)). The tabula is also the rendering
|
|
283
|
-
surface
|
|
292
|
+
surface. The SVG renderer ([below](#rendering)) consumes it directly, which is
|
|
284
293
|
why `hz`, `velocity`, `bend`, and the ornament flags live on each row.
|
|
285
294
|
|
|
286
295
|
```js
|
|
@@ -355,7 +364,7 @@ interface ChantTabulaRow {
|
|
|
355
364
|
|
|
356
365
|
## Rendering
|
|
357
366
|
|
|
358
|
-
The score is drawn as **SVG
|
|
367
|
+
The score is drawn as **SVG**: a self-contained, square-note chant staff with
|
|
359
368
|
SMuFL glyphs baked as inline paths (no external font). It consumes `score.tabula`,
|
|
360
369
|
so the interpretation applied through `pondus` and `accentus` is already in the
|
|
361
370
|
geometry. Microtuning lives on each tabula row's `bend`, `hz`, and `offset` for
|
|
@@ -364,7 +373,7 @@ a Web-Audio player to read directly.
|
|
|
364
373
|
### inscriptio — the standalone renderer
|
|
365
374
|
|
|
366
375
|
`tonus.inscriptio(score, opts?)` draws a `Score` and returns `{ svg, geometry }`.
|
|
367
|
-
Rendering is a standalone function that _takes_ a score, not a method on one
|
|
376
|
+
Rendering is a standalone function that _takes_ a score, not a method on one. The
|
|
368
377
|
score analyzes, `inscriptio` inks. It throws on a non-Score or an unknown
|
|
369
378
|
notation species (the builder-function contract).
|
|
370
379
|
|
|
@@ -382,14 +391,14 @@ Two notation species, each with its own spacing pass:
|
|
|
382
391
|
|
|
383
392
|
**Layout is deterministic, and lyric widths are computed rather than measured.**
|
|
384
393
|
The same score and options give byte-identical SVG on every machine, with no
|
|
385
|
-
DOM, no canvas, and no font file
|
|
394
|
+
DOM, no canvas, and no font file, so `inscriptio` runs anywhere Node does. Note
|
|
386
395
|
glyphs carry exact SMuFL advance widths; lyric text is computed from character
|
|
387
396
|
classes, since measuring it would require the font's own metrics. Line breaks,
|
|
388
397
|
system fill, and the width of the returned canvas all rest on that figure. It is
|
|
389
398
|
close, not exact: a lyric set in a face far from the assumed proportions will
|
|
390
399
|
break slightly early or late.
|
|
391
400
|
|
|
392
|
-
Two consequences worth planning around. `width` is a **request, not a promise
|
|
401
|
+
Two consequences worth planning around. `width` is a **request, not a promise**:
|
|
393
402
|
the canvas returned is `max(width, content)`, so a chant whose content cannot fit
|
|
394
403
|
comes back wider rather than clipped. And a caller who needs typographic
|
|
395
404
|
precision should render at a generous `width` and scale the result, rather than
|
|
@@ -397,22 +406,22 @@ relying on the estimate to land a tight column exactly.
|
|
|
397
406
|
|
|
398
407
|
Options, by group (all optional):
|
|
399
408
|
|
|
400
|
-
- **layout
|
|
409
|
+
- **layout**: `width` wraps systems to fit (absent = a single line); `scale`
|
|
401
410
|
sets how big the chant is drawn: `"small"`, `"normal"` (default), `"large"`,
|
|
402
411
|
or a staff height in px for fitting a known column. Everything scales from it
|
|
403
|
-
|
|
412
|
+
(notes, lyrics, the air between systems), and it reflows the music, so a
|
|
404
413
|
larger scale means fewer notes per line. The page margin does not scale: it
|
|
405
414
|
belongs to the page rather than the notation, and scaling it gave a large
|
|
406
415
|
chant *less* usable width than a small one.
|
|
407
|
-
- **front matter
|
|
416
|
+
- **front matter**: set as the Solesmes books open a piece: `title` centers
|
|
408
417
|
over the score; `rubric` (or `annotation: "auto"` to derive the genus/mode
|
|
409
418
|
mark, e.g. _Introitus. 8._) sits upright at the left margin; `dropcap` draws
|
|
410
419
|
the initial the printed books open with, taking the first letter out of the
|
|
411
420
|
lyric and indenting the first system to hold it. Both species take the
|
|
412
|
-
title; the margin mark and the initial are **quadrata's alone
|
|
421
|
+
title; the margin mark and the initial are **quadrata's alone**, because moderna is
|
|
413
422
|
a transcription read as an edition, and carries the analysis tracks a
|
|
414
423
|
reserved cap column would fight. It ignores them rather than refusing.
|
|
415
|
-
- **theme
|
|
424
|
+
- **theme**: the dress, `fonts` and `colors`.
|
|
416
425
|
|
|
417
426
|
### theme — faces and ink
|
|
418
427
|
|
|
@@ -432,14 +441,14 @@ tonus.inscriptio(score, {
|
|
|
432
441
|
```
|
|
433
442
|
|
|
434
443
|
**`fonts`** carries four roles. A book's dropcap is very often *not* its lyric
|
|
435
|
-
face
|
|
444
|
+
face, but a Lombardic or uncial initial against a text hand, which is the pairing
|
|
436
445
|
the printed books use. Each role takes a font-family string or
|
|
437
446
|
`{ family, weight?, scale? }` (`scale` adjusts that role's size, for a face
|
|
438
447
|
whose apparent size differs from the house serif).
|
|
439
448
|
|
|
440
449
|
The SVG carries font-family *references* by default, and the page hosting it
|
|
441
450
|
supplies the face (`@font-face`). A slot may instead carry
|
|
442
|
-
`embed: { base64, format? }`
|
|
451
|
+
`embed: { base64, format? }` (the caller's own bytes), and the face then rides
|
|
443
452
|
inside the SVG's `<style>`, making the file self-contained (at the cost of its
|
|
444
453
|
size; one `@font-face` per family + weight, deduped). tonus bundles no font
|
|
445
454
|
files: with `embed` it is a conduit for data the consumer supplies, so the
|
|
@@ -480,7 +489,7 @@ is 196 KB base64'd, which triples a typical chant and repeats in every file,
|
|
|
480
489
|
where a reference is cached once.
|
|
481
490
|
|
|
482
491
|
**`colors`** reach the SVG as CSS custom properties with the theme's own value
|
|
483
|
-
as the fallback
|
|
492
|
+
as the fallback, `fill="var(--tonus-note, #111)"`. A rendered chant therefore
|
|
484
493
|
carries the ink it was drawn with *and* stays themable: a host stylesheet that
|
|
485
494
|
sets the property rethemes the score without re-rendering it.
|
|
486
495
|
|
|
@@ -493,8 +502,8 @@ sets the property rethemes the score without re-rendering it.
|
|
|
493
502
|
}
|
|
494
503
|
```
|
|
495
504
|
|
|
496
|
-
The emitter's semantic classes
|
|
497
|
-
`episema`, `divisio`, `clef`, `mora`, `ictus`
|
|
505
|
+
The emitter's semantic classes (`note`, `lyric`, `dropcap`, `custos`,
|
|
506
|
+
`episema`, `divisio`, `clef`, `mora`, `ictus`) are stylable from the host page.
|
|
498
507
|
|
|
499
508
|
**`scale` is not part of the theme**: line breaking consumes it, so a scale
|
|
500
509
|
change re-renders while a colour change does not.
|
|
@@ -504,28 +513,35 @@ between systems, the notehead calibration against the staff, and the line-end
|
|
|
504
513
|
custos are constants. The custos appears whenever a system wraps, as it does in
|
|
505
514
|
a chant book.
|
|
506
515
|
|
|
507
|
-
**The geometry contract (public API).** `geometry` is one `NoteGeometry` per
|
|
508
|
-
in tabula order
|
|
509
|
-
|
|
510
|
-
|
|
516
|
+
**The geometry contract (public API).** `geometry` is one `NoteGeometry` per
|
|
517
|
+
note, in tabula order, so `geometry[i]` and `tabula[i]` are the same note two
|
|
518
|
+
ways. It says where each note landed on the drawn page, so a caller can put a
|
|
519
|
+
playhead, a selection, or an overlay against a note without scraping the SVG.
|
|
511
520
|
|
|
512
521
|
```ts
|
|
513
522
|
interface NoteGeometry {
|
|
514
|
-
phraseIndex: number; syllableIndex: number; neumeGroup: number;
|
|
523
|
+
phraseIndex: number; syllableIndex: number; neumeGroup: number;
|
|
524
|
+
noteIndex: number; // position within the SYLLABLE — the tabula's own index
|
|
525
|
+
neumeIndex: number; // position within the neume FIGURE
|
|
515
526
|
system: number; // which wrapped system the note landed in
|
|
516
527
|
x: number; y: number; // notehead anchor, svg user units
|
|
528
|
+
inkLeft: number; // the figure's measured ink extent. `x` is its LEFT
|
|
529
|
+
inkRight: number; // edge, so a mark that spans notes reaches for these
|
|
517
530
|
systemY: number; // the system's top offset within the svg
|
|
518
531
|
}
|
|
519
532
|
```
|
|
520
533
|
|
|
534
|
+
`y` is already absolute on the canvas; `systemY` reports which system a note
|
|
535
|
+
is in, not an offset to add.
|
|
536
|
+
|
|
521
537
|
### The analysis tracks
|
|
522
538
|
|
|
523
539
|
`tracks` draws an analysis band beneath every system. Any track rides either
|
|
524
|
-
species, and all may ride one score
|
|
540
|
+
species, and all may ride one score: the selection is independent of the
|
|
525
541
|
notation, as `notation` itself is. One governing ink system runs through them:
|
|
526
542
|
every mark draws in the score's black, strata graded by opacity alone (the
|
|
527
|
-
liturgical red belongs to the claims
|
|
528
|
-
prosodia's accent dots), and every pressure-bearing line shares one nib law
|
|
543
|
+
liturgical red belongs to the claims, the tonarium's mode line and the
|
|
544
|
+
prosodia's accent dots), and every pressure-bearing line shares one nib law:
|
|
529
545
|
velocity as stroke width.
|
|
530
546
|
|
|
531
547
|
```js
|
|
@@ -536,74 +552,70 @@ tonus.inscriptio(score, { width: 680, tracks: ["chironomia", "tonarium"] });
|
|
|
536
552
|
tonus.inscriptio(score, { width: 680, tracks: ["prosodia", "chironomia", "tonarium"] });
|
|
537
553
|
```
|
|
538
554
|
|
|
539
|
-
|
|
540
|
-
under
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
rather than frequency, beside `data-cadentia` — the family key, which is the
|
|
601
|
-
join back to [`CADENTIAE`](index.md#the-appendix) and the provenance a margin
|
|
602
|
-
gloss can print. Crowded labels dodge to a second row.
|
|
555
|
+
Several stack in a fixed order whatever order they are asked for: prosodia
|
|
556
|
+
first, directly under the lyric line it reads; chironomia next; tonarium
|
|
557
|
+
below. The page grows by the sum of the bands. The conventional pairing is the
|
|
558
|
+
chironomia under `quadrata` and the tonarium under `moderna`; the renderer
|
|
559
|
+
enforces none of it.
|
|
560
|
+
|
|
561
|
+
**`"prosodia"`** draws how the melody treats the word, in two lanes.
|
|
562
|
+
|
|
563
|
+
| mark | means |
|
|
564
|
+
| --- | --- |
|
|
565
|
+
| tent, one per word | apex over the accented syllable; accented words rise past the lane's rule, unaccented crest on it |
|
|
566
|
+
| filled dot at the peak | the accent lands **arsic** (struck) |
|
|
567
|
+
| open ring at the peak | the accent lands **thetic** (deferred) |
|
|
568
|
+
| stem on the rail | a spoken syllable; height is its note count |
|
|
569
|
+
| flat dash above the rail | the syllable is **recited on the tenor** |
|
|
570
|
+
| block | a **melisma of 4+ notes**, as wide as its extent, as tall as its count (8+ prints the count inside) |
|
|
571
|
+
| hairline through both lanes | a divisio |
|
|
572
|
+
|
|
573
|
+
Connected melismas join into one ridge, blocks sloping toward their
|
|
574
|
+
neighbours. Accents are the book's written accents (the GABC accented
|
|
575
|
+
vowels); the track derives none.
|
|
576
|
+
|
|
577
|
+
**`"chironomia"`** draws the conducting hand as one continuous line. Arsic
|
|
578
|
+
beats crest, thetic beats trough, single-note theses pass through shallow, and
|
|
579
|
+
the hand picks up between close arses in a small backward loop
|
|
580
|
+
[biblio: carroll-chironomy]. Each note's `velocity` (the `accentus` shaping)
|
|
581
|
+
becomes nib width, so the line presses where the voice does. Pierik letters
|
|
582
|
+
(A · T · PT) name the beats.
|
|
583
|
+
|
|
584
|
+
**`"tonarium"`** is the melodic-analysis lane, named for the book that
|
|
585
|
+
catalogued chants by mode. Four rails carry the maneriae finals ladder, D on
|
|
586
|
+
the bottom (categories, not pitches). Through them runs the melody itself,
|
|
587
|
+
compressed to the chant's ambitus at a lighter stratum: context, not message.
|
|
588
|
+
|
|
589
|
+
| mark | means |
|
|
590
|
+
| --- | --- |
|
|
591
|
+
| red line + numeral | the governing **mode** of each phrase (authentic vs plagal lives in the numeral) |
|
|
592
|
+
| line steps solid | a modulation of kind `"inflection"` |
|
|
593
|
+
| line dashed | a `"transposition"` (the affinal frame read as displacement) |
|
|
594
|
+
| melody re-inked black | a **cadence**: the same curve at the same width, turned pure black across the figure |
|
|
595
|
+
| filled terminal node | the family's measured `finality` **closes** |
|
|
596
|
+
| open terminal node | it **suspends** |
|
|
597
|
+
|
|
598
|
+
A wrapped cadence draws its node and label once, in the system holding the
|
|
599
|
+
figure's last note.
|
|
600
|
+
|
|
601
|
+
Every inked cadence carries a label beneath its node: the family's **in-mode
|
|
602
|
+
share** (`"3.9%"`), how often this close ends a chant in this chant's mode.
|
|
603
|
+
Where the chant has no mode, or the family has too few occurrences in it to
|
|
604
|
+
divide, it falls back to the plain corpus share. A close that joins
|
|
605
|
+
no [`CADENTIAE`](index.md#the-appendix) family reads **`rara`**. That is a
|
|
606
|
+
measurement rather than a gap: the catalogue holds the 110 families above
|
|
607
|
+
fifty corpus occurrences, so failing to join means rarer than anything it
|
|
608
|
+
records. About 43% of the corpus's cadences join no family, though of the
|
|
609
|
+
labels a page prints, about a third read `rara`. It is a word, not a number, so
|
|
610
|
+
it is not read on the percentage scale beside it.
|
|
611
|
+
|
|
612
|
+
Each cadence group carries `data-cadentia` (the family key, which joins back
|
|
613
|
+
to [`CADENTIAE`](index.md#the-appendix) and carries the provenance a margin
|
|
614
|
+
gloss can print) and `data-lift` (distinctiveness, for a caller who wants it
|
|
615
|
+
rather than frequency). Crowded labels dodge to a second row.
|
|
603
616
|
|
|
604
617
|
Everywhere, confidence is opacity, and a claim below confidence 0.45 draws
|
|
605
|
-
nothing
|
|
606
|
-
would falsify it.
|
|
618
|
+
nothing. Every mark sits under the notation that would falsify it.
|
|
607
619
|
|
|
608
620
|
## The imprint
|
|
609
621
|
|
|
@@ -667,11 +679,18 @@ interface ModalAffinity {
|
|
|
667
679
|
|
|
668
680
|
## Metrics
|
|
669
681
|
|
|
670
|
-
`score.metrics` measures the chant's shape
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
682
|
+
`score.metrics` measures the chant's shape: counts, range, melisma, melodic
|
|
683
|
+
motion, contour, tessitura, rhythm, cadence. It is chant-specific; `Harmony`
|
|
684
|
+
has no metrics.
|
|
685
|
+
|
|
686
|
+
```js
|
|
687
|
+
tonus.notatio(puerNatusEst).metrics;
|
|
688
|
+
// { noteCount: 159, syllableCount: 78, phraseCount: 10,
|
|
689
|
+
// ambitus: 10, melismaRatio: 2.04, tessitura: 5.2, … }
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
_Puer natus est_ spans ten semitones, sings a little over two notes to the
|
|
693
|
+
syllable, and sits about five semitones above its final.
|
|
675
694
|
|
|
676
695
|
```ts
|
|
677
696
|
interface Metrics {
|
|
@@ -691,12 +710,19 @@ interface Metrics {
|
|
|
691
710
|
cadenceWeight: number;
|
|
692
711
|
cadenceDistribution: CadenceDistribution;
|
|
693
712
|
}
|
|
713
|
+
```
|
|
694
714
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
715
|
+
The five composite fields each answer one question about the chant.
|
|
716
|
+
|
|
717
|
+
**Where the melody sits, and the shape it traces.** `noteRange` is the plain
|
|
718
|
+
compass; `arcus` reads the classic chant arch, a rise to a peak and a return to the
|
|
719
|
+
final.
|
|
720
|
+
|
|
721
|
+
```ts
|
|
722
|
+
interface NoteRange {
|
|
723
|
+
min: number; // lowest note MIDI
|
|
724
|
+
max: number; // highest note MIDI
|
|
725
|
+
span: number; // max − min, in semitones (this is `ambitus`)
|
|
700
726
|
}
|
|
701
727
|
|
|
702
728
|
interface Arcus {
|
|
@@ -705,32 +731,59 @@ interface Arcus {
|
|
|
705
731
|
final: number; // last note MIDI
|
|
706
732
|
archIndex: number; // signed: +1 rises and returns, 0 flat/monotonic
|
|
707
733
|
}
|
|
734
|
+
```
|
|
708
735
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
736
|
+
**How the melody moves.** Chant is overwhelmingly stepwise, so `motus` sorts
|
|
737
|
+
every adjacent within-phrase motion by size. The three names are the tradition's
|
|
738
|
+
own, and a chant whose skips and leaps outnumber its steps is unusual enough to
|
|
739
|
+
question.
|
|
740
|
+
|
|
741
|
+
```ts
|
|
742
|
+
interface IntervalStats {
|
|
743
|
+
histogram: Record<number, number>; // signed semitone interval → count
|
|
744
|
+
maxLeap: number; // largest absolute interval (semitones)
|
|
745
|
+
leapRate: number; // fraction of motions that are leaps
|
|
746
|
+
motus: { step: number; skip: number; leap: number };
|
|
713
747
|
}
|
|
748
|
+
```
|
|
714
749
|
|
|
750
|
+
| motion | semitones | interval |
|
|
751
|
+
| ------ | --------- | ----------------- |
|
|
752
|
+
| `step` | 1–2 | a second |
|
|
753
|
+
| `skip` | 3–4 | a third |
|
|
754
|
+
| `leap` | 5+ | a fourth or wider |
|
|
755
|
+
|
|
756
|
+
**How it is rhythmed.** Arsis and thesis across the score, and the size of the
|
|
757
|
+
compound beats they group into.
|
|
758
|
+
|
|
759
|
+
```ts
|
|
715
760
|
interface RhythmicProfile {
|
|
716
|
-
arsic: number;
|
|
717
|
-
thetic: number;
|
|
761
|
+
arsic: number; // arsic notes across the score
|
|
762
|
+
thetic: number; // thetic notes across the score
|
|
718
763
|
avgGroupSize: number; // mean notes per compound beat
|
|
719
764
|
maxGroupSize: number; // largest compound beat observed
|
|
720
765
|
}
|
|
721
|
-
|
|
722
|
-
interface CadenceDistribution {
|
|
723
|
-
comma: number; // divisio minima
|
|
724
|
-
tick: number; // virgula
|
|
725
|
-
semicolon: number; // divisio minor
|
|
726
|
-
colon: number; // divisio maior
|
|
727
|
-
doubleBar: number; // divisio finalis
|
|
728
|
-
}
|
|
729
766
|
```
|
|
730
767
|
|
|
768
|
+
**How it comes to rest.** `cadenceDistribution` counts the divisiones the chant
|
|
769
|
+
writes, one field per rung of the bar-line hierarchy. `cadenceWeight` sums the
|
|
770
|
+
same bars by that rank, so a chant closing on full bars weighs more than one
|
|
771
|
+
broken by breaths.
|
|
772
|
+
|
|
773
|
+
| field | GABC | divisio | weight |
|
|
774
|
+
| ----------- | ------- | --------------- | -----: |
|
|
775
|
+
| `tick` | `` ` `` | virgula | 0.25 |
|
|
776
|
+
| `comma` | `,` | divisio minima | 0.5 |
|
|
777
|
+
| `semicolon` | `;` | divisio minor | 0.75 |
|
|
778
|
+
| `colon` | `:` | divisio maior | 1.0 |
|
|
779
|
+
| `doubleBar` | `::` | divisio finalis | 1.5 |
|
|
780
|
+
|
|
781
|
+
This table is canonical: `metrics.ts` cites it rather than restating the
|
|
782
|
+
weights.
|
|
783
|
+
|
|
731
784
|
## Cadences
|
|
732
785
|
|
|
733
|
-
`score.cadences` names the melodic close of each phrase
|
|
786
|
+
`score.cadences` names the melodic close of each phrase. Where metrics
|
|
734
787
|
only counts the divisio bars, this identifies the figure. One `Cadence` per
|
|
735
788
|
phrase-ending divisio: its resolution `target`, the melodic `approach`, and the
|
|
736
789
|
`divisio` that tells medial from final (the double bar `::` is the final
|
|
@@ -742,23 +795,23 @@ the tabula.
|
|
|
742
795
|
Two catalogues describe a cadence, and they answer different questions. Read
|
|
743
796
|
this before deciding which field to use:
|
|
744
797
|
|
|
745
|
-
> Every cadence carries a **`signature
|
|
798
|
+
> Every cadence carries a **`signature`**, always. Some are **catalogued** by
|
|
746
799
|
> the corpus (`finality`, and everything in
|
|
747
800
|
> [`CADENTIAE`](index.md#the-appendix)). Some, on the final, are **named** by
|
|
748
801
|
> received theory (`formula`).
|
|
749
802
|
|
|
750
803
|
- **`formula`** is _tradita_: the mode's cadence figures as the treatises give
|
|
751
804
|
them ([tuning.md](tuning.md#cadence-figures)), matched in solmization
|
|
752
|
-
relative to the final
|
|
805
|
+
relative to the final (`"la-sol"`, `"mi-re"`). It fires **only on the
|
|
753
806
|
finalis**, because the received catalogue holds only final figures.
|
|
754
807
|
- **`signature`** is _inventa_: the tail's interval shape and where it lands,
|
|
755
808
|
keyed as `"2,0,-2 @0"` and mined from the corpus. It fires on **any** target,
|
|
756
809
|
so it is the one of the two that speaks about **medial** cadences.
|
|
757
810
|
|
|
758
|
-
Measured over the cadences `notatio` reports across the shipped corpus
|
|
759
|
-
|
|
760
|
-
both,
|
|
761
|
-
signature is mode-blind and the formula is mode-relative.
|
|
811
|
+
Measured over the cadences `notatio` reports across the shipped corpus (about
|
|
812
|
+
26,800 of them), roughly 43% carry a formula, 57% join the catalogue, and 31%
|
|
813
|
+
carry both, so about a third carry neither. Neither is derivable from the
|
|
814
|
+
other, because the signature is mode-blind and the formula is mode-relative.
|
|
762
815
|
|
|
763
816
|
### `finality` — how often this family closes
|
|
764
817
|
|
|
@@ -769,7 +822,7 @@ the final, 31 do not close, and finality across the catalogue runs the whole
|
|
|
769
822
|
range from 0 to 1. So
|
|
770
823
|
`arrival === 0` implies nothing about whether a close is final.
|
|
771
824
|
|
|
772
|
-
It is `null` when the signature falls below the catalogue's floor
|
|
825
|
+
It is `null` when the signature falls below the catalogue's floor: an
|
|
773
826
|
uncatalogued close, not a close that never closes.
|
|
774
827
|
|
|
775
828
|
```ts
|
|
@@ -790,7 +843,7 @@ interface Cadence {
|
|
|
790
843
|
}
|
|
791
844
|
```
|
|
792
845
|
|
|
793
|
-
A one-note phrase is a cadence
|
|
846
|
+
A one-note phrase is a cadence (a landing with no gesture) and keys with an
|
|
794
847
|
empty shape (`" @0"`), which is why `signature` is that key rather than null.
|
|
795
848
|
|
|
796
849
|
`arrival` is signed and not octave-reduced: `@-5`, a fourth below the final,
|
|
@@ -799,7 +852,7 @@ and `@+7`, a fifth above, are distinct families.
|
|
|
799
852
|
## Modulations
|
|
800
853
|
|
|
801
854
|
`score.modulations` marks where the tonal centre leans away from the home
|
|
802
|
-
mode
|
|
855
|
+
mode, the local counterpart to the imprint's global modal
|
|
803
856
|
affinity. Each phrase is scored against all eight modes (the imprint's
|
|
804
857
|
affinity math); a run of phrases that favours a foreign mode, by a margin,
|
|
805
858
|
becomes one `Modulation` span. The margin is calibrated against Suñol's
|
|
@@ -808,13 +861,13 @@ distribution-based: it finds where a passage leans, not a functional analysis.
|
|
|
808
861
|
|
|
809
862
|
`kind` says what the span is evidence OF, which matters because the three are
|
|
810
863
|
not the same phenomenon. **`inflection`** is a single phrase leaning away and
|
|
811
|
-
back
|
|
864
|
+
back: passing colour, not a shift. **`modulation`** is a sustained internal
|
|
812
865
|
excursion, two phrases or more, that returns. **`transposition`** is the whole
|
|
813
866
|
chant sitting in a foreign mode's frame: it does not close on its labelled
|
|
814
867
|
final and one foreign mode dominates most of its phrases, meaning the melody is
|
|
815
868
|
notated at a transposed position (the affinal) or the label disagrees with the
|
|
816
|
-
notation. A transposed chant is not modulating
|
|
817
|
-
so a caller displaying "modulations" should treat those spans as a re-reading of
|
|
869
|
+
notation. A transposed chant is not modulating, because the displacement is
|
|
870
|
+
global, so a caller displaying "modulations" should treat those spans as a re-reading of
|
|
818
871
|
the whole chant rather than an event inside it.
|
|
819
872
|
|
|
820
873
|
```ts
|
|
@@ -860,35 +913,35 @@ The classifier applies Carroll's three melodic rules in priority order
|
|
|
860
913
|
|
|
861
914
|
The first compound beat of an incise is always arsic. When every rule is inconclusive, the
|
|
862
915
|
shape alternates from the previous group. Two conventional overrides
|
|
863
|
-
precede the rules
|
|
864
|
-
summit is the arsic gesture
|
|
916
|
+
precede the rules. The **salicus** is always arsic, because the tension toward
|
|
917
|
+
its summit is the arsic gesture, and the **doubly-dotted clivis** is always
|
|
865
918
|
thetic, as a cadential figure.
|
|
866
919
|
|
|
867
920
|
A salicus here is Cardine's: an ascent of at least three notes whose
|
|
868
921
|
**next-to-last note is an oriscus** [biblio: cardine-semiology, ch. 16]. The
|
|
869
922
|
oriscus is what makes one. An ascending group carrying only the editorial
|
|
870
|
-
Solesmes ictus is a **scandicus** that was marked for rhythm
|
|
871
|
-
worth stating because conflating the two is, in Bevenot's word, a trap: over
|
|
923
|
+
Solesmes ictus is a **scandicus** that was marked for rhythm. The distinction
|
|
924
|
+
is worth stating because conflating the two is, in Bevenot's word, a trap: over
|
|
872
925
|
the sung corpus tonus finds about 260 salici against about 1,900 scandici, so
|
|
873
926
|
only about an eighth of that wider set carries an oriscus at all.
|
|
874
927
|
|
|
875
928
|
Cardine's correction also decides WHICH note is principal. The printed
|
|
876
929
|
editions lengthen the oriscus itself; the manuscripts show the principal note
|
|
877
|
-
is the one **immediately following** it
|
|
930
|
+
is the one **immediately following** it (the summit), so tonus prolongs that
|
|
878
931
|
note and takes the oriscus lightly. This is the one point where the rhythmic
|
|
879
932
|
layer departs from Mocquereau and Suñol, and it does so deliberately.
|
|
880
933
|
|
|
881
934
|
### Rhythmic types
|
|
882
935
|
|
|
883
|
-
Above the per-beat arsis/thesis, each phrase carries a `rhythmicType
|
|
936
|
+
Above the per-beat arsis/thesis, each phrase carries a `rhythmicType`, Le
|
|
884
937
|
Guennant's taxonomy (via Carroll) of how the incise's compound beats chain, and
|
|
885
938
|
the `beats` sequence it reads. The observable types are modeled: **IV** (a single
|
|
886
939
|
arsis to a single thesis), **V** (several arses to one thesis), **VI** (one arsis
|
|
887
940
|
to several theses), **VII** (regular A–T alternation), and **VIII** (a
|
|
888
|
-
contraction
|
|
941
|
+
contraction of two simple rhythms overlapping at a shared ictus, after Suñol).
|
|
889
942
|
Types I–III use sub-beat cells that never surface in isolation and are not
|
|
890
943
|
labeled; an incise that fits no type is `null`. The classification rules live at
|
|
891
|
-
the data
|
|
944
|
+
the data. See `classifyRhythmicType` in
|
|
892
945
|
[`score/ir.ts`](https://github.com/jeffreypierce/tonus/blob/main/src/engines/score/ir.ts).
|
|
893
946
|
|
|
894
947
|
### Modeled and not
|