tonus 0.9.0 → 0.10.0

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +3 -3
  3. package/dist/census.d.ts +4 -0
  4. package/dist/census.js +23 -0
  5. package/dist/corpus.d.ts +4 -0
  6. package/dist/corpus.js +17 -0
  7. package/dist/data/am.js +10220 -3006
  8. package/dist/data/attestation.js +38640 -4568
  9. package/dist/data/attestation.json +38639 -4567
  10. package/dist/data/census.d.ts +2 -2
  11. package/dist/data/census.js +4 -4
  12. package/dist/data/corpus-overlap.js +5 -118
  13. package/dist/data/gr.d.ts +29 -2
  14. package/dist/data/gr.js +2436 -6411
  15. package/dist/data/kyriale.d.ts +1 -1
  16. package/dist/data/kyriale.js +38 -38
  17. package/dist/data/la.js +12369 -1103
  18. package/dist/data/lh.js +3139 -158
  19. package/dist/data/lu.js +17332 -2379
  20. package/dist/data/nocturnale-romanum.js +10656 -1899
  21. package/dist/data/psm.js +463 -33
  22. package/dist/data/types.d.ts +1 -0
  23. package/dist/engines/chant/chant.js +60 -13
  24. package/dist/engines/chant/data/masses.js +18 -18
  25. package/dist/engines/chant/ordinary.js +12 -5
  26. package/dist/engines/chant/psalm.js +4 -0
  27. package/dist/engines/chant/types.d.ts +32 -4
  28. package/dist/engines/chant/types.js +47 -4
  29. package/dist/engines/score/emitters/moderna.js +150 -12
  30. package/dist/engines/score/infer.js +1 -1
  31. package/dist/engines/temper/gabc.d.ts +12 -0
  32. package/dist/engines/temper/gabc.js +51 -18
  33. package/dist/index.d.ts +5 -9
  34. package/dist/inscriptio.d.ts +5 -0
  35. package/dist/inscriptio.js +23 -0
  36. package/dist/score.d.ts +6 -0
  37. package/dist/score.js +20 -0
  38. package/docs/api/calendar.md +4 -4
  39. package/docs/api/census.md +31 -22
  40. package/docs/api/chant.md +102 -82
  41. package/docs/api/heavens.md +7 -7
  42. package/docs/api/index.md +40 -6
  43. package/docs/api/score.md +44 -44
  44. package/docs/api/tuning.md +14 -14
  45. package/package.json +22 -4
  46. package/dist/data/ams.d.ts +0 -5
  47. package/dist/data/ams.js +0 -122
  48. package/dist/data/cot.d.ts +0 -5
  49. package/dist/data/cot.js +0 -172
  50. package/dist/data/cse.d.ts +0 -5
  51. package/dist/data/cse.js +0 -122
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 — the bars of chant
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
  | ------- | ---------------------------- |
@@ -103,7 +103,7 @@ text: the `<sp>` shortcuts arrive as real characters (`<sp>V/</sp>` → ℣,
103
103
  `\greheightstar` verbatim → the raised *), centering braces and layout tags
104
104
  (`<clear>`, `<nlba>`) vanish, above-lines text (`<alt>`) is not lyric text,
105
105
  and page cross-references (`\pageref`) to the paper books are dropped. Style
106
- tags — `<i>`, `<b>`, `<sc>`, `<c>` (rubric color), `<e>` (elision) — survive
106
+ tags (`<i>`, `<b>`, `<sc>`, `<c>` for rubric color, `<e>` for elision) survive
107
107
  as `runs`, styled spans that concatenate to `lyric`; a style opened in one
108
108
  syllable and closed several later (the common `<i>ij.</i>` and euouae
109
109
  patterns) styles every syllable it crosses. Both notation species draw the
@@ -289,7 +289,7 @@ analysis, visualization, or emission.
289
289
 
290
290
  `Harmony` exposes the same surface for voiced bodies
291
291
  ([heavens.md](heavens.md#the-tabula)). The tabula is also the rendering
292
- surface — the SVG renderer ([below](#rendering)) consumes it directly, which is
292
+ surface. The SVG renderer ([below](#rendering)) consumes it directly, which is
293
293
  why `hz`, `velocity`, `bend`, and the ornament flags live on each row.
294
294
 
295
295
  ```js
@@ -364,7 +364,7 @@ interface ChantTabulaRow {
364
364
 
365
365
  ## Rendering
366
366
 
367
- The score is drawn as **SVG** — a self-contained, square-note chant staff with
367
+ The score is drawn as **SVG**: a self-contained, square-note chant staff with
368
368
  SMuFL glyphs baked as inline paths (no external font). It consumes `score.tabula`,
369
369
  so the interpretation applied through `pondus` and `accentus` is already in the
370
370
  geometry. Microtuning lives on each tabula row's `bend`, `hz`, and `offset` for
@@ -373,7 +373,7 @@ a Web-Audio player to read directly.
373
373
  ### inscriptio — the standalone renderer
374
374
 
375
375
  `tonus.inscriptio(score, opts?)` draws a `Score` and returns `{ svg, geometry }`.
376
- Rendering is a standalone function that _takes_ a score, not a method on one — the
376
+ Rendering is a standalone function that _takes_ a score, not a method on one. The
377
377
  score analyzes, `inscriptio` inks. It throws on a non-Score or an unknown
378
378
  notation species (the builder-function contract).
379
379
 
@@ -391,14 +391,14 @@ Two notation species, each with its own spacing pass:
391
391
 
392
392
  **Layout is deterministic, and lyric widths are computed rather than measured.**
393
393
  The same score and options give byte-identical SVG on every machine, with no
394
- DOM, no canvas, and no font file — `inscriptio` runs anywhere Node does. Note
394
+ DOM, no canvas, and no font file, so `inscriptio` runs anywhere Node does. Note
395
395
  glyphs carry exact SMuFL advance widths; lyric text is computed from character
396
396
  classes, since measuring it would require the font's own metrics. Line breaks,
397
397
  system fill, and the width of the returned canvas all rest on that figure. It is
398
398
  close, not exact: a lyric set in a face far from the assumed proportions will
399
399
  break slightly early or late.
400
400
 
401
- 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**:
402
402
  the canvas returned is `max(width, content)`, so a chant whose content cannot fit
403
403
  comes back wider rather than clipped. And a caller who needs typographic
404
404
  precision should render at a generous `width` and scale the result, rather than
@@ -406,22 +406,22 @@ relying on the estimate to land a tight column exactly.
406
406
 
407
407
  Options, by group (all optional):
408
408
 
409
- - **layout** — `width` wraps systems to fit (absent = a single line); `scale`
409
+ - **layout**: `width` wraps systems to fit (absent = a single line); `scale`
410
410
  sets how big the chant is drawn: `"small"`, `"normal"` (default), `"large"`,
411
411
  or a staff height in px for fitting a known column. Everything scales from it
412
- — notes, lyrics, the air between systems — and it reflows the music, so a
412
+ (notes, lyrics, the air between systems), and it reflows the music, so a
413
413
  larger scale means fewer notes per line. The page margin does not scale: it
414
414
  belongs to the page rather than the notation, and scaling it gave a large
415
415
  chant *less* usable width than a small one.
416
- - **front matter** — set as the Solesmes books open a piece: `title` centers
416
+ - **front matter**: set as the Solesmes books open a piece: `title` centers
417
417
  over the score; `rubric` (or `annotation: "auto"` to derive the genus/mode
418
418
  mark, e.g. _Introitus. 8._) sits upright at the left margin; `dropcap` draws
419
419
  the initial the printed books open with, taking the first letter out of the
420
420
  lyric and indenting the first system to hold it. Both species take the
421
- title; the margin mark and the initial are **quadrata's alone** — moderna is
421
+ title; the margin mark and the initial are **quadrata's alone**, because moderna is
422
422
  a transcription read as an edition, and carries the analysis tracks a
423
423
  reserved cap column would fight. It ignores them rather than refusing.
424
- - **theme** — the dress: `fonts` and `colors`.
424
+ - **theme**: the dress, `fonts` and `colors`.
425
425
 
426
426
  ### theme — faces and ink
427
427
 
@@ -441,14 +441,14 @@ tonus.inscriptio(score, {
441
441
  ```
442
442
 
443
443
  **`fonts`** carries four roles. A book's dropcap is very often *not* its lyric
444
- face — a Lombardic or uncial initial against a text hand, which is the pairing
444
+ face, but a Lombardic or uncial initial against a text hand, which is the pairing
445
445
  the printed books use. Each role takes a font-family string or
446
446
  `{ family, weight?, scale? }` (`scale` adjusts that role's size, for a face
447
447
  whose apparent size differs from the house serif).
448
448
 
449
449
  The SVG carries font-family *references* by default, and the page hosting it
450
450
  supplies the face (`@font-face`). A slot may instead carry
451
- `embed: { base64, format? }` — the caller's own bytes — and the face then rides
451
+ `embed: { base64, format? }` (the caller's own bytes), and the face then rides
452
452
  inside the SVG's `<style>`, making the file self-contained (at the cost of its
453
453
  size; one `@font-face` per family + weight, deduped). tonus bundles no font
454
454
  files: with `embed` it is a conduit for data the consumer supplies, so the
@@ -489,7 +489,7 @@ is 196 KB base64'd, which triples a typical chant and repeats in every file,
489
489
  where a reference is cached once.
490
490
 
491
491
  **`colors`** reach the SVG as CSS custom properties with the theme's own value
492
- as the fallback — `fill="var(--tonus-note, #111)"`. A rendered chant therefore
492
+ as the fallback, `fill="var(--tonus-note, #111)"`. A rendered chant therefore
493
493
  carries the ink it was drawn with *and* stays themable: a host stylesheet that
494
494
  sets the property rethemes the score without re-rendering it.
495
495
 
@@ -502,8 +502,8 @@ sets the property rethemes the score without re-rendering it.
502
502
  }
503
503
  ```
504
504
 
505
- The emitter's semantic classes — `note`, `lyric`, `dropcap`, `custos`,
506
- `episema`, `divisio`, `clef`, `mora`, `ictus` — are stylable from the host page.
505
+ The emitter's semantic classes (`note`, `lyric`, `dropcap`, `custos`,
506
+ `episema`, `divisio`, `clef`, `mora`, `ictus`) are stylable from the host page.
507
507
 
508
508
  **`scale` is not part of the theme**: line breaking consumes it, so a scale
509
509
  change re-renders while a colour change does not.
@@ -537,11 +537,11 @@ is in, not an offset to add.
537
537
  ### The analysis tracks
538
538
 
539
539
  `tracks` draws an analysis band beneath every system. Any track rides either
540
- species, and all may ride one score — the selection is independent of the
540
+ species, and all may ride one score: the selection is independent of the
541
541
  notation, as `notation` itself is. One governing ink system runs through them:
542
542
  every mark draws in the score's black, strata graded by opacity alone (the
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 —
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:
545
545
  velocity as stroke width.
546
546
 
547
547
  ```js
@@ -679,7 +679,7 @@ interface ModalAffinity {
679
679
 
680
680
  ## Metrics
681
681
 
682
- `score.metrics` measures the chant's shape — counts, range, melisma, melodic
682
+ `score.metrics` measures the chant's shape: counts, range, melisma, melodic
683
683
  motion, contour, tessitura, rhythm, cadence. It is chant-specific; `Harmony`
684
684
  has no metrics.
685
685
 
@@ -715,7 +715,7 @@ interface Metrics {
715
715
  The five composite fields each answer one question about the chant.
716
716
 
717
717
  **Where the melody sits, and the shape it traces.** `noteRange` is the plain
718
- compass; `arcus` reads the classic chant arch — rise to a peak, return to the
718
+ compass; `arcus` reads the classic chant arch, a rise to a peak and a return to the
719
719
  final.
720
720
 
721
721
  ```ts
@@ -734,7 +734,7 @@ interface Arcus {
734
734
  ```
735
735
 
736
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
737
+ every adjacent within-phrase motion by size. The three names are the tradition's
738
738
  own, and a chant whose skips and leaps outnumber its steps is unusual enough to
739
739
  question.
740
740
 
@@ -778,12 +778,12 @@ broken by breaths.
778
778
  | `colon` | `:` | divisio maior | 1.0 |
779
779
  | `doubleBar` | `::` | divisio finalis | 1.5 |
780
780
 
781
- This table is canonical — `metrics.ts` cites it rather than restating the
781
+ This table is canonical: `metrics.ts` cites it rather than restating the
782
782
  weights.
783
783
 
784
784
  ## Cadences
785
785
 
786
- `score.cadences` names the melodic close of each phrase — where metrics
786
+ `score.cadences` names the melodic close of each phrase. Where metrics
787
787
  only counts the divisio bars, this identifies the figure. One `Cadence` per
788
788
  phrase-ending divisio: its resolution `target`, the melodic `approach`, and the
789
789
  `divisio` that tells medial from final (the double bar `::` is the final
@@ -795,21 +795,21 @@ the tabula.
795
795
  Two catalogues describe a cadence, and they answer different questions. Read
796
796
  this before deciding which field to use:
797
797
 
798
- > Every cadence carries a **`signature`** — always. Some are **catalogued** by
798
+ > Every cadence carries a **`signature`**, always. Some are **catalogued** by
799
799
  > the corpus (`finality`, and everything in
800
800
  > [`CADENTIAE`](index.md#the-appendix)). Some, on the final, are **named** by
801
801
  > received theory (`formula`).
802
802
 
803
803
  - **`formula`** is _tradita_: the mode's cadence figures as the treatises give
804
804
  them ([tuning.md](tuning.md#cadence-figures)), matched in solmization
805
- relative to the final — `"la-sol"`, `"mi-re"`. It fires **only on the
805
+ relative to the final (`"la-sol"`, `"mi-re"`). It fires **only on the
806
806
  finalis**, because the received catalogue holds only final figures.
807
807
  - **`signature`** is _inventa_: the tail's interval shape and where it lands,
808
808
  keyed as `"2,0,-2 @0"` and mined from the corpus. It fires on **any** target,
809
809
  so it is the one of the two that speaks about **medial** cadences.
810
810
 
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%
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
813
  carry both, so about a third carry neither. Neither is derivable from the
814
814
  other, because the signature is mode-blind and the formula is mode-relative.
815
815
 
@@ -822,7 +822,7 @@ the final, 31 do not close, and finality across the catalogue runs the whole
822
822
  range from 0 to 1. So
823
823
  `arrival === 0` implies nothing about whether a close is final.
824
824
 
825
- It is `null` when the signature falls below the catalogue's floor — an
825
+ It is `null` when the signature falls below the catalogue's floor: an
826
826
  uncatalogued close, not a close that never closes.
827
827
 
828
828
  ```ts
@@ -843,7 +843,7 @@ interface Cadence {
843
843
  }
844
844
  ```
845
845
 
846
- A one-note phrase is a cadence — a landing with no gesture — and keys with an
846
+ A one-note phrase is a cadence (a landing with no gesture) and keys with an
847
847
  empty shape (`" @0"`), which is why `signature` is that key rather than null.
848
848
 
849
849
  `arrival` is signed and not octave-reduced: `@-5`, a fourth below the final,
@@ -852,7 +852,7 @@ and `@+7`, a fifth above, are distinct families.
852
852
  ## Modulations
853
853
 
854
854
  `score.modulations` marks where the tonal centre leans away from the home
855
- mode — the local, temporal counterpart to the imprint's global modal
855
+ mode, the local counterpart to the imprint's global modal
856
856
  affinity. Each phrase is scored against all eight modes (the imprint's
857
857
  affinity math); a run of phrases that favours a foreign mode, by a margin,
858
858
  becomes one `Modulation` span. The margin is calibrated against Suñol's
@@ -861,13 +861,13 @@ distribution-based: it finds where a passage leans, not a functional analysis.
861
861
 
862
862
  `kind` says what the span is evidence OF, which matters because the three are
863
863
  not the same phenomenon. **`inflection`** is a single phrase leaning away and
864
- back — passing colour, not a shift. **`modulation`** is a sustained internal
864
+ back: passing colour, not a shift. **`modulation`** is a sustained internal
865
865
  excursion, two phrases or more, that returns. **`transposition`** is the whole
866
866
  chant sitting in a foreign mode's frame: it does not close on its labelled
867
867
  final and one foreign mode dominates most of its phrases, meaning the melody is
868
868
  notated at a transposed position (the affinal) or the label disagrees with the
869
- notation. A transposed chant is not modulating — the displacement is global —
870
- 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
871
871
  the whole chant rather than an event inside it.
872
872
 
873
873
  ```ts
@@ -913,35 +913,35 @@ The classifier applies Carroll's three melodic rules in priority order
913
913
 
914
914
  The first compound beat of an incise is always arsic. When every rule is inconclusive, the
915
915
  shape alternates from the previous group. Two conventional overrides
916
- precede the rules: the **salicus** is always arsic — the tension toward its
917
- summit is the arsic gesture — and the **doubly-dotted clivis** is always
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
918
918
  thetic, as a cadential figure.
919
919
 
920
920
  A salicus here is Cardine's: an ascent of at least three notes whose
921
921
  **next-to-last note is an oriscus** [biblio: cardine-semiology, ch. 16]. The
922
922
  oriscus is what makes one. An ascending group carrying only the editorial
923
- Solesmes ictus is a **scandicus** that was marked for rhythm — a distinction
924
- 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
925
925
  the sung corpus tonus finds about 260 salici against about 1,900 scandici, so
926
926
  only about an eighth of that wider set carries an oriscus at all.
927
927
 
928
928
  Cardine's correction also decides WHICH note is principal. The printed
929
929
  editions lengthen the oriscus itself; the manuscripts show the principal note
930
- is the one **immediately following** it — the summit — so tonus prolongs that
930
+ is the one **immediately following** it (the summit), so tonus prolongs that
931
931
  note and takes the oriscus lightly. This is the one point where the rhythmic
932
932
  layer departs from Mocquereau and Suñol, and it does so deliberately.
933
933
 
934
934
  ### Rhythmic types
935
935
 
936
- Above the per-beat arsis/thesis, each phrase carries a `rhythmicType` — Le
936
+ Above the per-beat arsis/thesis, each phrase carries a `rhythmicType`, Le
937
937
  Guennant's taxonomy (via Carroll) of how the incise's compound beats chain, and
938
938
  the `beats` sequence it reads. The observable types are modeled: **IV** (a single
939
939
  arsis to a single thesis), **V** (several arses to one thesis), **VI** (one arsis
940
940
  to several theses), **VII** (regular A–T alternation), and **VIII** (a
941
- contraction — two simple rhythms overlapping at a shared ictus, after Suñol).
941
+ contraction of two simple rhythms overlapping at a shared ictus, after Suñol).
942
942
  Types I–III use sub-beat cells that never surface in isolation and are not
943
943
  labeled; an incise that fits no type is `null`. The classification rules live at
944
- the data — see `classifyRhythmicType` in
944
+ the data. See `classifyRhythmicType` in
945
945
  [`score/ir.ts`](https://github.com/jeffreypierce/tonus/blob/main/src/engines/score/ir.ts).
946
946
 
947
947
  ### Modeled and not
@@ -343,11 +343,11 @@ interface GamutOptions {
343
343
  `modus` returns the full profile of one of the eight modes, as the
344
344
  medieval tonaries describe them:
345
345
 
346
- - its identity — Latin name, modern alias, _maneria_ (the family: Protus,
346
+ - its identity: Latin name, modern alias, _maneria_ (the family: Protus,
347
347
  Deuterus, Tritus, Tetrardus), and authentic or plagal type;
348
- - its structure — finalis, tenor, scale degrees, ambitus, and the species
348
+ - its structure: finalis, tenor, scale degrees, ambitus, and the species
349
349
  of fifth and fourth that build it;
350
- - its practice — hexachords in rank order, melodic profile, its cadence
350
+ - its practice: hexachords in rank order, melodic profile, its cadence
351
351
  figures, and permitted modulations.
352
352
 
353
353
  Each mode also carries its traditional **ethos** (the character medieval theory
@@ -365,7 +365,7 @@ data, in [`temper/data/modes.ts`](https://github.com/jeffreypierce/tonus/blob/ma
365
365
  temperamentum: the **finalis** and **reciting** tone as tuned notes (pitch +
366
366
  Guidonian step), and **ambitusNotes**, the mode's diatonic range walked out
367
367
  note by note. The raw `ModeData` fields (`final`, `tenor`, `cadences`, …)
368
- remain alongside — `Modus` extends `ModeData`.
368
+ remain alongside, because `Modus` extends `ModeData`.
369
369
 
370
370
  ```js
371
371
  t.modus(1);
@@ -436,7 +436,7 @@ interface Modus extends ModeData {
436
436
  ### Cadence figures
437
437
 
438
438
  Each mode carries the melodic figures its phrases characteristically close
439
- on, in `modus(n).cadences` — the shapes by which a chant comes to rest, stored
439
+ on, in `modus(n).cadences`, the shapes by which a chant comes to rest, stored
440
440
  as diatonic steps relative to the final. The score engine reads them to name a
441
441
  phrase's cadence ([score.md](score.md#cadences)).
442
442
 
@@ -449,10 +449,10 @@ phrase's cadence ([score.md](score.md#cadences)).
449
449
 
450
450
  The catalogue is an editorial synthesis covering the final cadences; its step
451
451
  encoding, sources, and known gaps (medial cadences are not yet included) are
452
- documented at the data — see `CadenceFigure` in
452
+ documented at the data. See `CadenceFigure` in
453
453
  [`temper/data/modes.ts`](https://github.com/jeffreypierce/tonus/blob/main/src/engines/temper/data/modes.ts).
454
454
 
455
- This is the **tradita** half — what the treatises say. Its counterpart is the
455
+ This is the **tradita** half, what the treatises say. Its counterpart is the
456
456
  corpus tally below, and they are not interchangeable: see [one spine, two
457
457
  annotations](score.md#one-spine-two-annotations).
458
458
 
@@ -460,8 +460,8 @@ annotations](score.md#one-spine-two-annotations).
460
460
 
461
461
  Where the figures above are received, [`CADENTIAE`](index.md#the-appendix) is
462
462
  **mined**: every phrase-end in the sung corpus, grouped into families by what
463
- the melody actually did. A family is a **shape** — the closing tail's
464
- successive semitone intervals — and an **arrival**, where it landed relative
463
+ the melody actually did. A family is a **shape** (the closing tail's
464
+ successive semitone intervals) and an **arrival**, where it landed relative
465
465
  to the chant's own closing note. Together they are the key, `"2,0,-2 @0"`, and
466
466
  the key is the family's whole name.
467
467
 
@@ -505,14 +505,14 @@ lift(fam, 6); // 2.15
505
505
  lift(fam, 4); // 0.07
506
506
  ```
507
507
 
508
- The commonest family in the corpus — about 1,100 occurrences, about 4% of all
509
- phrase-ends, closing a little under half the time — is not reached for evenly.
508
+ The commonest family in the corpus (about 1,100 occurrences, about 4% of all
509
+ phrase-ends, closing a little under half the time) is not reached for evenly.
510
510
  Mode 6 reaches for this close more than twice as often as the corpus does;
511
511
  mode 4 almost never. That is the figure the tonarium prints under a cadence
512
512
  ([score.md](score.md#the-analysis-tracks)).
513
513
 
514
- **The ratio is not baked.** The table exports the vocabulary — counts and
515
- their denominators — and leaves the arithmetic to the caller. Two cautions when
514
+ **The ratio is not baked.** The table exports the vocabulary (counts and
515
+ their denominators) and leaves the arithmetic to the caller. Two cautions when
516
516
  you take it: below roughly ten in-mode occurrences the ratio is one or two
517
517
  chants deciding a number that reads like a measurement, and a mode-less chant
518
518
  (`"?"`) has no denominator at all. In both cases fall back to `share`.
@@ -524,7 +524,7 @@ pitches: the **intonatio** (the opening rise), the **mediatio** (the
524
524
  cadence at the verse's colon), and the **terminatio** (the closing
525
525
  cadence). The termination varies by **differentia**, the cadential variant
526
526
  chosen to lead back into the antiphon; the mode's default differentia is
527
- used when none is given. The mode must be set explicitly — with mode
527
+ used when none is given. The mode must be set explicitly, because with mode
528
528
  `"auto"`, `tonus()` throws.
529
529
 
530
530
  ```js
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "tonus",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
- "description": "Medieval music analysis and performance: GABC plainchant exports, liturgical calendar, tuning systems, ephemeris, and the harmony of the spheres",
5
+ "description": "Medieval music analysis: GABC plainchant exports, liturgical calendar, tuning systems, ephemeris, and the harmony of the spheres",
6
6
  "author": "Jeffrey Pierce <jeffrey@jeffreypierce.net>",
7
7
  "license": "PolyForm-Noncommercial-1.0.0",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/jeffreypierce/tonus.git"
11
11
  },
12
- "homepage": "https://jeffreypierce.github.io/orreliquum/",
12
+ "homepage": "https://orreliquum.com/",
13
13
  "bugs": "https://github.com/jeffreypierce/tonus/issues",
14
14
  "keywords": [
15
15
  "gregorian-chant",
@@ -32,10 +32,27 @@
32
32
  ".": {
33
33
  "import": "./dist/index.js",
34
34
  "types": "./dist/index.d.ts"
35
+ },
36
+ "./inscriptio": {
37
+ "import": "./dist/inscriptio.js",
38
+ "types": "./dist/inscriptio.d.ts"
39
+ },
40
+ "./census": {
41
+ "import": "./dist/census.js",
42
+ "types": "./dist/census.d.ts"
43
+ },
44
+ "./corpus": {
45
+ "import": "./dist/corpus.js",
46
+ "types": "./dist/corpus.d.ts"
47
+ },
48
+ "./score": {
49
+ "import": "./dist/score.js",
50
+ "types": "./dist/score.d.ts"
35
51
  }
36
52
  },
37
53
  "main": "./dist/index.js",
38
54
  "types": "./dist/index.d.ts",
55
+ "sideEffects": false,
39
56
  "files": [
40
57
  "dist",
41
58
  "docs/api",
@@ -48,7 +65,8 @@
48
65
  "scripts": {
49
66
  "build": "tsc && cp src/data/psalms.json dist/data/psalms.json && cp src/data/smufl-glyphs.json dist/data/smufl-glyphs.json && cp src/data/office-ferial.json dist/data/office-ferial.json && cp src/data/commune-office.json dist/data/commune-office.json && cp src/data/seasonal-respbreve.json dist/data/seasonal-respbreve.json && cp src/data/attestation.json dist/data/attestation.json && node scripts/bake-data.mjs",
50
67
  "clean": "rm -rf dist",
51
- "test": "npm run build && node --test --test-reporter=spec tests/*.test.mjs",
68
+ "gate": "node scripts/gate-boundary.mjs",
69
+ "test": "npm run build && npm run gate && node --test --test-reporter=spec tests/*.test.mjs",
52
70
  "prepublishOnly": "npm run clean && npm run build",
53
71
  "lab": "npm run build && node scripts/render-lab.mjs",
54
72
  "stress": "npm run build && node scripts/render-stress.mjs",
@@ -1,5 +0,0 @@
1
- import type { Chant } from "./types.js";
2
- import type { ChantData } from "./gr.js";
3
- export declare const AMS_SOURCE: Chant["source"];
4
- export declare const AMS_DATA: ChantData[];
5
- //# sourceMappingURL=ams.d.ts.map
package/dist/data/ams.js DELETED
@@ -1,122 +0,0 @@
1
- export const AMS_SOURCE = {
2
- book: "Antiphonale Monasticum Solesmense",
3
- fullTitle: null,
4
- edition: "Proprium Sanctorum — offices proper to the Solesmes congregation",
5
- year: 1935,
6
- editor: "Solesmes",
7
- scanSource: "Scan courtesy of Dominique Crochu",
8
- code: "ams",
9
- };
10
- export const AMS_DATA = [
11
- {
12
- id: "gregobase:9299",
13
- incipit: "Gertrudis arca Numinis",
14
- gabc: "(c4)GEr(g)trú(hi)dis,(j) ar(ih)ca(g) Nú(h')mi(f)nis,(g'_) (,)\r\nSpon(i)só(k')que(j) junc(i)ta(k) Vír(ji)gi(h)num,(g.) (;)\r\nDa(g) nup(h')ti(f)á(g)lis(e) pán(fe)ge(d)re(c'_) (,)\r\nCas(g)tos(hi) a(j)mó(ih)res(g) fœ(h')́de(f)ris.(g.) (::)\r\n",
15
- office: "hy",
16
- mode: "8",
17
- pages: [
18
- { page: "1223", sequence: 1, extent: 1 }
19
- ],
20
- },
21
- {
22
- id: "gregobase:9301",
23
- incipit: "Annulis septem subarrhavit me",
24
- gabc: "(c3)AN(i)nu(i)lis(i) sep(i')tem(g) sub(i')ar(j>)rhá(i)vit(hi~) me(i.) *(,) Dó(ij)mi(i)nus(i) me(i')us(g) Je(hi)sus(g) Chris(e.)tus,(e.) (;) et(e) tam(g)quam(hf~) spon(h_)sam(g'_) (,) de(f)co(e')rá(f_)vit(f'_) me(h) co(g)ró(e.)na.(e.) (::)",
25
- office: "an",
26
- mode: "7",
27
- pages: [
28
- { page: "1225", sequence: 2, extent: 1 }
29
- ],
30
- },
31
- {
32
- id: "gregobase:9302",
33
- incipit: "Habuit Gertrudis potestatem",
34
- gabc: "(c4)HA(d)bu(e)it(c') Ger(d)trú(dh'!iv)dis(h.) *(,) pot(hg)es(gf)tá(ghg')tem(h_/iih.) (,) cláu(h>)de(j)re(jk) cæ(ji)lum(hg~) nú(h)bi(ij)bus,(h.) (;) et(h_ggo) a(e)pe(f')rí(g)re(g_e) por(gh)tas(fe) e(d!ewf_e)jus:(dc..) (;) qui(e)a(ed) lin(cd~)gua(d) e(e_f)jus(ghg/hiHGgo) (,) cla(e')vis(f) cæ(g)li(fe) fac(d)ta(cd) est.(d.) (::)",
35
- office: "an",
36
- mode: "1",
37
- pages: [
38
- { page: "1225", sequence: 3, extent: 2 }
39
- ],
40
- },
41
- {
42
- id: "gregobase:9304",
43
- incipit: "Ad sacros Virgo",
44
- gabc: "(f3)Ad(c) sa(f')cros(e) vir(f.)go(h.) (,) thá(g)la(f)mos(g') an(h)hé(g.)lans(f.) (;)\r\nNúp(ff)ti(f')as(g) cæ(h.)lo(e.) (,) ce(h)le(i)brá(j')re(kxk) ges(i.)tit,(j.) (:)\r\nEt(j) pi(i')is(h) vo(g.)tis(i.) (,) ní(f)mi(f)um(g') mo(e)rán(d.)tem(c.) (,)\r\nPró(h)vo(f')cat(g) ho(e.)ram.(f.) (::)\r\n",
45
- office: "hy",
46
- mode: "2",
47
- pages: [
48
- { page: "1226", sequence: 2, extent: 2 }
49
- ],
50
- },
51
- {
52
- id: "gregobase:9306",
53
- incipit: "Casta columba nidificans",
54
- gabc: "(c4)Cas(h)ta(f') co(g)lúm(gh)ba(g.) (,) ni(gh)dí(hg)fi(f)cans(g'_) in(f) ca(g')vér(h)na(g') ma(h)cé(hj)ri(h)æ(h.) (,) sa(i)cri(j) lá(k')te(j)ris(ji) Je(h)su(hi) Chris(h)ti,(g.) (;) mel(ghg') su(e)a(fg)vís(g)si(fe)mum(d.) (,) de(e_f) pe(gf)tra(gh) su(h)gé(g.)bat.(g.) (::)",
55
- office: "an",
56
- mode: "8",
57
- pages: [
58
- { page: "1229", sequence: 1, extent: 1 }
59
- ],
60
- },
61
- {
62
- id: "gregobase:9307",
63
- incipit: "Loquebatur Christus ad dilectam",
64
- gabc: "(c4)LO(d)que(e_f)bá(g)tur(g) Chris(gh)tus(g'_) *() ad(g) di(g')léc(g)tam(d') Ger(e)trú(fe)dem(e'_) (,) fá(f)ci(fe)e(f') ad(g) fá(gh)ci(g)em,(g.) (;) sic(i_j)ut(h) so(h)let(gf) lo(g)qui(d) ho(e_f)mo(g'_) (,) ad(g) a(gf)mí(g)cum(ghg) su(e.)um.(e.) (::)",
65
- office: "an",
66
- mode: "4",
67
- pages: [
68
- { page: "1229", sequence: 2, extent: 1 }
69
- ],
70
- },
71
- {
72
- id: "gregobase:9308",
73
- incipit: "Beatae Gertrudis verba",
74
- gabc: "(c3)BE(e)á(e)tæ(g') Ger(h)trú(i_h)dis(g_h) ver(i_j)ba(i'_) *(,) di(i)ví(j')ni(i) e(hi)rant(h') a(h)mó(hg)ris(fe) já(fe)cu(de)la:(e.) (;) lám(f')pa(e)des(d) e(e_f)jus,(f.) (,) lám(g')pa(h)des(i) i(hg)gnis(fe) at(d)que(f_h) flam(g)má(e.)rum.(e.) (::)",
75
- office: "an",
76
- mode: "7",
77
- pages: [
78
- { page: "1229", sequence: 3, extent: 1 }
79
- ],
80
- },
81
- {
82
- id: "gregobase:9309",
83
- incipit: "Dilectae animam e carcere corporis",
84
- gabc: "(c4)DI(f)léc(gh)tæ(f) á(g')ni(f)mam(f'_) *(,) e(f) cár(e')ce(f)re(d') cór(c)po(d)ris(fe) ex(gh)e(gh)ún(fv_2fv_2//ggf)tem(f.) (;) ac(f)cé(ixf!gwh!io)pit(h) Chris(hj)tus(h') in(h) ul(h')nas(g) su(hv_GF)as,(f.) (;) et(e) cor(fg~) su(gf)um(d_c) il(f)li(fg) a(g)mán(gf)ter(g) a(ghg)pé(f')ru(f)it.(f.) (::)",
85
- office: "an",
86
- mode: "6",
87
- pages: [
88
- { page: "1230", sequence: 1, extent: 1 }
89
- ],
90
- },
91
- {
92
- id: "gregobase:9321",
93
- incipit: "Damasci praepositus",
94
- gabc: "(c3)DA(e!fwh)má(f)sci,(fe) *() præ(d)pó(ef)si(f)tus(e.) (,) gen(g')tis(h) A(i')ré(h)tæ(f') re(h)gis(g.) (;) vó(h')lu(h)it(h') me(h) com(hg~)pre(f)hén(g_h)de(g)re :(e.) (:) a(e) frá(ef)tri(e)bus(ef) per(e) mu(e_fE'D)rum(d'_) (,) sub(d)mís(e')sus(d) sum(e') in(f) spor(h_i)ta:(htg/hih.) (;) et(h) sic(i) e(g')vá(h)si(f') ma(h)nus(e') e(f>)jus(e'_) (,) in(e>) nó(c_d)mi(ef)ne(f') Dó(e)mi(de)ni.(e.) (::)",
95
- office: "an",
96
- mode: "8",
97
- pages: [
98
- { page: "812", sequence: 3, extent: 2 }
99
- ],
100
- },
101
- {
102
- id: "gregobase:9322",
103
- incipit: "Ter virgis caesus sum",
104
- gabc: "(c3)TER(e!fwh) vir(f>)gis(ed) cæ(ef)sus(f) sum,(e.) *(,) se(g')mel(h) la(i)pi(hf)dá(h')tus(h) sum:(g.) (;) ter(i) nau(i)frá(h')gi(h)um(h) pér(ij)tu(i)li(hg/hih.) (,) pro(fe) Chris(f!gwh_f)ti(g') nó(e)mi(de)ne.(e.) (::) E(h) u(h) o(g) u(h) a(f) e.(e.) (::)",
105
- office: "an",
106
- mode: "8",
107
- pages: [
108
- { page: "813", sequence: 1, extent: 1 }
109
- ],
110
- },
111
- {
112
- id: "gregobase:10402",
113
- incipit: "Gratia Dei in me",
114
- gabc: "(c3)\r\nGRá(f)ti(e)a(f) De(h_i)i(ii) *(,)\r\nin(h) me(i) vá(j')cu(h)a(ij) non(j>) fu(i.)it:(i.) (;)\r\nsed(i) grá(f_i)ti(h')a(g) e(f_e~)jus(f_e) (,)\r\nsem(d')per(e) in(f') me(h) ma(f.)net.(f.) (::) E(i) u(h) o(i) u(j) a(h) e.(f.) (::)\r\n",
115
- office: "an",
116
- mode: "4",
117
- pages: [
118
- { page: "812", sequence: 2, extent: 1 }
119
- ],
120
- }
121
- ];
122
- //# sourceMappingURL=ams.js.map
@@ -1,5 +0,0 @@
1
- import type { Chant } from "./types.js";
2
- import type { ChantData } from "./gr.js";
3
- export declare const COT_SOURCE: Chant["source"];
4
- export declare const COT_DATA: ChantData[];
5
- //# sourceMappingURL=cot.d.ts.map