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.
- package/CHANGELOG.md +124 -0
- package/README.md +3 -3
- package/dist/census.d.ts +4 -0
- package/dist/census.js +23 -0
- package/dist/corpus.d.ts +4 -0
- package/dist/corpus.js +17 -0
- package/dist/data/am.js +10220 -3006
- package/dist/data/attestation.js +38640 -4568
- package/dist/data/attestation.json +38639 -4567
- package/dist/data/census.d.ts +2 -2
- package/dist/data/census.js +4 -4
- package/dist/data/corpus-overlap.js +5 -118
- package/dist/data/gr.d.ts +29 -2
- package/dist/data/gr.js +2436 -6411
- package/dist/data/kyriale.d.ts +1 -1
- package/dist/data/kyriale.js +38 -38
- package/dist/data/la.js +12369 -1103
- package/dist/data/lh.js +3139 -158
- package/dist/data/lu.js +17332 -2379
- package/dist/data/nocturnale-romanum.js +10656 -1899
- package/dist/data/psm.js +463 -33
- package/dist/data/types.d.ts +1 -0
- package/dist/engines/chant/chant.js +60 -13
- package/dist/engines/chant/data/masses.js +18 -18
- package/dist/engines/chant/ordinary.js +12 -5
- package/dist/engines/chant/psalm.js +4 -0
- package/dist/engines/chant/types.d.ts +32 -4
- package/dist/engines/chant/types.js +47 -4
- package/dist/engines/score/emitters/moderna.js +150 -12
- package/dist/engines/score/infer.js +1 -1
- package/dist/engines/temper/gabc.d.ts +12 -0
- package/dist/engines/temper/gabc.js +51 -18
- package/dist/index.d.ts +5 -9
- package/dist/inscriptio.d.ts +5 -0
- package/dist/inscriptio.js +23 -0
- package/dist/score.d.ts +6 -0
- package/dist/score.js +20 -0
- package/docs/api/calendar.md +4 -4
- package/docs/api/census.md +31 -22
- package/docs/api/chant.md +102 -82
- package/docs/api/heavens.md +7 -7
- package/docs/api/index.md +40 -6
- package/docs/api/score.md +44 -44
- package/docs/api/tuning.md +14 -14
- package/package.json +22 -4
- package/dist/data/ams.d.ts +0 -5
- package/dist/data/ams.js +0 -122
- package/dist/data/cot.d.ts +0 -5
- package/dist/data/cot.js +0 -172
- package/dist/data/cse.d.ts +0 -5
- package/dist/data/cse.js +0 -122
package/docs/api/chant.md
CHANGED
|
@@ -9,9 +9,9 @@ carries page-level provenance back to its book.
|
|
|
9
9
|
|
|
10
10
|
- [Chant](#chant)
|
|
11
11
|
- [The corpora](#the-corpora)
|
|
12
|
-
- [The
|
|
12
|
+
- [The shelf is the books](#the-shelf-is-the-books)
|
|
13
13
|
- [The books — `corpus`](#the-books--corpus)
|
|
14
|
-
- [
|
|
14
|
+
- [What the book holds — `full`](#what-the-book-holds--full)
|
|
15
15
|
- [Retrieval — `cantus`](#retrieval--cantus)
|
|
16
16
|
- [Reaching the ordinary — `ordinary`](#reaching-the-ordinary--ordinary)
|
|
17
17
|
- [On chant ids](#on-chant-ids)
|
|
@@ -30,33 +30,29 @@ carries page-level provenance back to its book.
|
|
|
30
30
|
|
|
31
31
|
## The corpora
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Six Solesmes books, extracted from
|
|
34
34
|
[GregoBase](https://gregobase.selapa.net/), joined by the Divinum Officium
|
|
35
35
|
propers, office, and psalter, plus the Nocturnale Romanum for the night office:
|
|
36
36
|
|
|
37
|
-
| Source | Book
|
|
38
|
-
| ------ |
|
|
39
|
-
| `gr` | Graduale Romanum
|
|
40
|
-
| `lu` | The Liber Usualis
|
|
41
|
-
| `la` | Liber antiphonarius
|
|
42
|
-
| `lh` | Liber Hymnarius
|
|
43
|
-
| `am` | Antiphonale Monasticum
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
The ten books list 2,767 rows for those 2,187 chants: a melody printed in two
|
|
57
|
-
books is stored once and listed under both.
|
|
58
|
-
|
|
59
|
-
`am`, `ams`, and `psm` are the monastic (Benedictine) books; the rest are
|
|
37
|
+
| Source | Book | Edition | Chants |
|
|
38
|
+
| ------ | ----------------------- | -------------- | ------ |
|
|
39
|
+
| `gr` | Graduale Romanum | Solesmes, 1961 | 1,373 |
|
|
40
|
+
| `lu` | The Liber Usualis | Solesmes, 1961 | 2,446 |
|
|
41
|
+
| `la` | Liber antiphonarius | Solesmes, 1960 | 2,506 |
|
|
42
|
+
| `lh` | Liber Hymnarius | Solesmes, 1983 | 361 |
|
|
43
|
+
| `am` | Antiphonale Monasticum | Solesmes, 1934 | 1,448 |
|
|
44
|
+
| `psm` | Psalterium Monasticum | Solesmes, 1981 | 60 |
|
|
45
|
+
| `nr` | Nocturnale Romanum | Sandhofe, 2002 | 1,564 |
|
|
46
|
+
|
|
47
|
+
**7,840 chants in all**, the Mass ordinary among them (120 settings, reached by
|
|
48
|
+
[`ordinary`](#reaching-the-ordinary--ordinary) rather than by book). That is the
|
|
49
|
+
books themselves: tonus carries what they print, whether or not the calendar
|
|
50
|
+
reaches it.
|
|
51
|
+
|
|
52
|
+
The seven books list 9,758 rows for those 7,840 chants: a melody printed in two
|
|
53
|
+
books is stored once and listed under each, with each book's own page citation.
|
|
54
|
+
|
|
55
|
+
`am` and `psm` are the monastic (Benedictine) books; the rest are
|
|
60
56
|
Roman. Every book here bears the rhythmic markings the score engine reads; that
|
|
61
57
|
is the admission rule. `nr` is the night-office repertoire (responsories,
|
|
62
58
|
antiphons) from the
|
|
@@ -64,37 +60,48 @@ antiphons) from the
|
|
|
64
60
|
community restitution, the one non-Solesmes source, admitted because it carries
|
|
65
61
|
those marks too.
|
|
66
62
|
|
|
67
|
-
### The
|
|
63
|
+
### The shelf is the books
|
|
68
64
|
|
|
69
|
-
The corpus
|
|
70
|
-
liturgical year
|
|
71
|
-
|
|
72
|
-
not shipped — 10,156 book chants become 2,187.
|
|
65
|
+
The corpus was **assignment-driven** until 2026-08-31: a chant shipped only when
|
|
66
|
+
some day of the liturgical year called for it, and 10,156 book chants became
|
|
67
|
+
2,187. That gate is gone. The shelf now carries the books whole.
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
The reason is that the gate answered four questions with one silence. A chant
|
|
70
|
+
absent from the shelf might be genuinely superseded repertoire, or printed in an
|
|
71
|
+
edition the calendar does not address, or proper to a sanctorale the calendar
|
|
72
|
+
does not enumerate, or simply missed by the matcher that places texts on days —
|
|
73
|
+
and nothing downstream could tell those apart, because the chant was not there
|
|
74
|
+
to ask about. Worse, the population every `census` measurement was taken against
|
|
75
|
+
was itself the product of that gate, so "how typical is this chant" quietly meant
|
|
76
|
+
"how typical among the chants one rite happened to call for".
|
|
77
|
+
|
|
78
|
+
Whether a day calls for a chant is now a question for the day verbs — `festum`,
|
|
79
|
+
`proprium`, `officium` — which answer it directly and say what their tables
|
|
80
|
+
hold. It is not a filter on the shelf. `cantus` and `corpus` ask what the books
|
|
81
|
+
print; that a chant has no day to be sung on is a fact about the calendar, not a
|
|
82
|
+
reason it should be unfindable.
|
|
76
83
|
|
|
77
84
|
## The books — `corpus`
|
|
78
85
|
|
|
79
86
|
`corpus(code)` returns one book's bibliographic identity and a breakdown of what
|
|
80
|
-
it holds
|
|
87
|
+
it holds: how many chants, in what genres, in what modes. `corpus({ book })` is
|
|
81
88
|
the same question in the query form every other verb uses; both spellings return
|
|
82
89
|
one answer.
|
|
83
90
|
|
|
84
|
-
`corpus()` with no argument returns **the whole shelf
|
|
91
|
+
`corpus()` with no argument returns **the whole shelf**, the rollup plus every
|
|
85
92
|
book's ledger:
|
|
86
93
|
|
|
87
94
|
```js
|
|
88
95
|
tonus.corpus();
|
|
89
|
-
// { count:
|
|
90
|
-
// listings:
|
|
91
|
-
// total:
|
|
92
|
-
// genera: [ { office: "an", genus: "Antiphona", count:
|
|
93
|
-
// modes: [ { mode: "1", modus: "Modus I", count:
|
|
94
|
-
// books: [ …
|
|
96
|
+
// { count: 7840, // chants tonus holds, each counted once
|
|
97
|
+
// listings: 9758, // rows on the shelf — a chant in two books appears twice
|
|
98
|
+
// total: 9811, // what the books hold, before dedup
|
|
99
|
+
// genera: [ { office: "an", genus: "Antiphona", count: 3959 }, … ],
|
|
100
|
+
// modes: [ { mode: "1", modus: "Modus I", count: 1520 }, … ],
|
|
101
|
+
// books: [ …7 Corpus entries, in registry order ] }
|
|
95
102
|
```
|
|
96
103
|
|
|
97
|
-
**`count` is the number of chants
|
|
104
|
+
**`count` is the number of chants**, the one to quote. `listings` is how long
|
|
98
105
|
the shelf is: a melody printed in several books is stored once and listed under
|
|
99
106
|
each, so the shelf runs longer than the repertory. The breakdowns describe the
|
|
100
107
|
same population `count` does, so `genera` and `modes` sum to it.
|
|
@@ -128,42 +135,44 @@ interface Corpus {
|
|
|
128
135
|
}
|
|
129
136
|
```
|
|
130
137
|
|
|
131
|
-
###
|
|
138
|
+
### What the book holds — `full`
|
|
132
139
|
|
|
133
|
-
Every `Corpus` carries `full`: what the book
|
|
140
|
+
Every `Corpus` carries `full`: what the book holds in GregoBase's catalogue, in
|
|
134
141
|
the same genera/modes shape as the shipped counts.
|
|
135
142
|
|
|
136
143
|
```js
|
|
137
144
|
const am = tonus.corpus("am");
|
|
138
|
-
am.count; //
|
|
139
|
-
am.full.total; // 1456 — what
|
|
140
|
-
am.genera[0]; // { office: "an", genus: "Antiphona", count:
|
|
145
|
+
am.count; // 1448 — chants tonus lists under the Antiphonale
|
|
146
|
+
am.full.total; // 1456 — what GregoBase catalogues for the book
|
|
147
|
+
am.genera[0]; // { office: "an", genus: "Antiphona", count: 1045 }
|
|
141
148
|
am.full.genera[0]; // { office: "an", genus: "Antiphona", count: 1049 }
|
|
142
149
|
```
|
|
143
150
|
|
|
144
|
-
|
|
145
|
-
|
|
151
|
+
The two now sit close, because the shelf carries the book rather than a
|
|
152
|
+
selection from it. What remains between them is what the extractor drops for
|
|
153
|
+
reasons of its own — a chant GregoBase marks as a duplicate of another, or one
|
|
154
|
+
whose GABC will not parse — not a liturgical judgement.
|
|
146
155
|
|
|
147
|
-
Only the extractor can measure
|
|
148
|
-
|
|
149
|
-
Every shelved book reports one, including the Nocturnale, whose tally
|
|
150
|
-
from its own extract rather than from GregoBase.
|
|
156
|
+
Only the extractor can measure `full`. By the time tonus loads, its record is
|
|
157
|
+
one per chant, so the catalogue tally is read from an artifact rather than
|
|
158
|
+
derived. Every shelved book reports one, including the Nocturnale, whose tally
|
|
159
|
+
comes from its own extract rather than from GregoBase.
|
|
151
160
|
|
|
152
161
|
The metadata is drawn from GregoBase's own catalogue. The `genera` list is the
|
|
153
162
|
office distribution (descending by count); `modes` counts modes I–VIII, with a
|
|
154
163
|
final `mode: null` bucket for chants outside the eight modes (psalm tones and the
|
|
155
164
|
like) so the counts reconcile with `count`.
|
|
156
165
|
|
|
157
|
-
**Overlap.** tonus
|
|
158
|
-
|
|
159
|
-
|
|
166
|
+
**Overlap.** tonus stores one copy of each chant — the Liber Usualis owns the
|
|
167
|
+
record where several books print it — but LISTS it under every book that does,
|
|
168
|
+
so `count` is what a book prints rather than what it happens to store. `total` is the full pre-dedup count, `unique` the
|
|
160
169
|
chants a book alone has, and `shared` how many it holds in common with each other
|
|
161
170
|
book (by GregoBase chant id). These reveal, for instance, that the Liber Usualis
|
|
162
171
|
is largely the Graduale and the Antiphonarius bound together (it shares hundreds
|
|
163
172
|
of chants with each), while the Antiphonale Monasticum is almost entirely its own.
|
|
164
173
|
|
|
165
174
|
The Nocturnale (`nr`) is compared differently, because it has no GregoBase
|
|
166
|
-
catalogue: its counts come from its own extract, and it shares **nothing
|
|
175
|
+
catalogue: its counts come from its own extract, and it shares **nothing**, so
|
|
167
176
|
`unique` is all 1,564 chants it holds. That is a measurement, not a gap. The
|
|
168
177
|
nocturnale–GregoBase crosswalk is a route to metadata, not a claim that the two
|
|
169
178
|
books print the same chant, so it does not count as sharing.
|
|
@@ -234,11 +243,20 @@ name:
|
|
|
234
243
|
|
|
235
244
|
| `office` | `genus` | `office` | `genus` | `office` | `genus` |
|
|
236
245
|
| -------- | --------- | -------- | ------------ | -------- | ------------------ |
|
|
237
|
-
| `an` | Antiphona | `hy` | Hymnus | `
|
|
238
|
-
| `al` | Alleluia | `in` | Introitus | `
|
|
239
|
-
| `ca` | Canticum | `of` | Offertorium | `
|
|
240
|
-
| `co` | Communio | `ps` | Psalmus | `
|
|
241
|
-
| `gr` | Graduale | `re` | Responsorium | `
|
|
246
|
+
| `an` | Antiphona | `hy` | Hymnus | `se` | Sequentia |
|
|
247
|
+
| `al` | Alleluia | `in` | Introitus | `tr` | Tractus |
|
|
248
|
+
| `ca` | Canticum | `of` | Offertorium | `tp` | Tropa |
|
|
249
|
+
| `co` | Communio | `ps` | Psalmus | `or` | Toni Communes |
|
|
250
|
+
| `gr` | Graduale | `re` | Responsorium | `ky` | Kyriale |
|
|
251
|
+
| `im` | Improperia| `rb` | Resp. Breve | `va` | Varia |
|
|
252
|
+
| `pa` | Prosa | `su` | Supplicatio | | |
|
|
253
|
+
|
|
254
|
+
The labels are GregoBase's own vocabulary (`$txt['usage']`), not tonus's
|
|
255
|
+
gloss. Three were corrected in 0.10.0: `tp` reads **Tropa** (it had said
|
|
256
|
+
"Tonus Peregrinus"), `or` reads **Toni Communes** (it had said "Ordinarium"),
|
|
257
|
+
and `pa` reads **Prosa**. `ky` is the Mass ordinary's roll-up genus — the
|
|
258
|
+
part itself rides `ordinary` (`ke`, `gl`, `cr`, …), and `va` is the
|
|
259
|
+
catch-all for a chant whose office-part tonus does not recognise.
|
|
242
260
|
|
|
243
261
|
```ts
|
|
244
262
|
interface Chant {
|
|
@@ -249,7 +267,9 @@ interface Chant {
|
|
|
249
267
|
genus: string; // Latin genre name, "Antiphona", "Introitus" …
|
|
250
268
|
mode: string | null; // raw from source: "1"–"8", differentia forms ("2d", "8g"), "p"/"d"/"e" …
|
|
251
269
|
modus: string | null; // Latin mode name, "Modus I"–"Modus VIII"
|
|
252
|
-
|
|
270
|
+
books: (ChantSource | "user" | "ky")[]; // every book that prints it
|
|
271
|
+
pages: { page: string; sequence: number; extent: number }[]; // the presented book's
|
|
272
|
+
|
|
253
273
|
source: {
|
|
254
274
|
book: string;
|
|
255
275
|
year: number | null;
|
|
@@ -282,7 +302,7 @@ interface CantusQuery {
|
|
|
282
302
|
The Mass ordinary is addressable but not shelved. `ordinary` is the door:
|
|
283
303
|
|
|
284
304
|
```js
|
|
285
|
-
tonus.cantus({ ordinary: "
|
|
305
|
+
tonus.cantus({ ordinary: "ke" }); // all 31 Kyries
|
|
286
306
|
tonus.cantus({ ordinary: "gl", mode: 4 }); // mode-4 Glorias
|
|
287
307
|
tonus.cantus({ ordinary: ["as", "va"] }); // the sprinkle antiphons
|
|
288
308
|
```
|
|
@@ -295,18 +315,18 @@ A plain search does not sweep it in: `{ mode: 5 }` returns the shelf. Ask for a
|
|
|
295
315
|
Kyrie and you get Kyries.
|
|
296
316
|
|
|
297
317
|
For the setting a given DAY calls for, [`ordinarium`](#the-ordinary--ordinarium)
|
|
298
|
-
is the verb
|
|
318
|
+
is the verb, and it applies the Kyriale's own rubrics. This is flat retrieval.
|
|
299
319
|
|
|
300
320
|
### On chant ids
|
|
301
321
|
|
|
302
|
-
An id's prefix names **the catalogue the identifier came from
|
|
322
|
+
An id's prefix names **the catalogue the identifier came from**, not the book
|
|
303
323
|
the chant is printed in, and not a claim about who the melody belongs to. A
|
|
304
324
|
chant carrying `gregobase:1210` is a Solesmes book chant that GregoBase happens
|
|
305
|
-
to have catalogued; the corpus is assembled from
|
|
325
|
+
to have catalogued; the corpus is assembled from seven books, and GregoBase is
|
|
306
326
|
one source among several.
|
|
307
327
|
|
|
308
328
|
The prefix is therefore **not a namespace you can query against**. GregoBase
|
|
309
|
-
holds 18,148 chants; tonus ships 1,717 of them
|
|
329
|
+
holds 18,148 chants; tonus ships 1,717 of them (9.5%), because the corpus is
|
|
310
330
|
assignment-driven, so an id copied from the GregoBase site will usually return
|
|
311
331
|
`[]` here. That is not a lookup failure; it means no day of the calendar calls
|
|
312
332
|
for that chant. The two prefixes in the shipped corpus are `gregobase:` (1,717)
|
|
@@ -322,7 +342,7 @@ to a chant rather than to a printing.
|
|
|
322
342
|
`before: 1098` keeps only chants a manuscript of the 10th century or earlier
|
|
323
343
|
already holds. This is **evidence, not existence**: the dates come from
|
|
324
344
|
CANTUS's manuscript index, a terminus ante quem, so the filter answers "what
|
|
325
|
-
is attested by then," never "what existed then"
|
|
345
|
+
is attested by then," never "what existed then." A chant with no dated
|
|
326
346
|
witness is excluded rather than assumed old. CANTUS dates only to the century,
|
|
327
347
|
so a year admits the centuries that have CLOSED before it (`before: 1098` →
|
|
328
348
|
through the 900s).
|
|
@@ -339,7 +359,7 @@ tonus.ordinarium({ feast: easter }); // the ordinary the view attests
|
|
|
339
359
|
```
|
|
340
360
|
|
|
341
361
|
What happens to a slot the view excludes differs by verb, on the rubric's
|
|
342
|
-
own logic: `ordinarium` **re-picks
|
|
362
|
+
own logic: `ordinarium` **re-picks**, because the Kyriale offers ranked
|
|
343
363
|
alternatives by design, so the rotation runs over the admissible pool and
|
|
344
364
|
the day still sings. `proprium` and `officium` have no pool
|
|
345
365
|
of alternatives, so an excluded chant **falls silent**. A `before` given to a
|
|
@@ -371,15 +391,15 @@ interface PropriumQuery extends CantusQuery {
|
|
|
371
391
|
## The ordinary — `ordinarium`
|
|
372
392
|
|
|
373
393
|
`ordinarium(query?)` retrieves the fixed chants of the Mass from the
|
|
374
|
-
Kyriale. A feast drives mass selection through its `masses` list
|
|
394
|
+
Kyriale. A feast drives mass selection through its `masses` list, the
|
|
375
395
|
masses the day's Kyriale RUBRIC appoints, derived as described in
|
|
376
396
|
[calendar.md](calendar.md#the-days-feasts--festum); `mass` pins a kyriale
|
|
377
397
|
number directly. Where the rubric names several masses, the year rotates
|
|
378
398
|
through them (same feast, same year → same answer, every time), and sibling
|
|
379
399
|
printings under one number (Mass I prints two dismissals; Mass XVII prints
|
|
380
400
|
Kyrie A/B/C) rotate with it. Slots resolve independently, which the book
|
|
381
|
-
licenses outright
|
|
382
|
-
from others"
|
|
401
|
+
licenses outright ("chants from one Mass may be used together with those
|
|
402
|
+
from others") with one exception, the book's own: **"the Ferial Masses
|
|
383
403
|
excepted."** Under a ferial rubric the sung ordinary is not gathered from
|
|
384
404
|
several masses; only the dismissal travels.
|
|
385
405
|
|
|
@@ -397,10 +417,10 @@ tonus.ordinarium({ feast: easter });
|
|
|
397
417
|
|
|
398
418
|
The **Gloria follows the day's rank rubric, not its season**: the ferial
|
|
399
419
|
masses print none (XVI, XVIII) and the penitential-Sunday mass none (XVII),
|
|
400
|
-
while a I-class feast inside Advent or Lent
|
|
420
|
+
while a I-class feast inside Advent or Lent (the Immaculate Conception)
|
|
401
421
|
keeps its Gloria. At a Gloria-less Mass the dismissal is the Benedicamus
|
|
402
422
|
Domino, and a mass with no dismissal of its own borrows one exactly as the
|
|
403
|
-
book directs: "Benedicamus Domino **as in Mass II
|
|
423
|
+
book directs: "Benedicamus Domino **as in Mass II**," so a green feria
|
|
404
424
|
sings Mass XVI whole with the Mass II Benedicamus. The ad libitum appendix
|
|
405
425
|
is a **solemnity boost**, reachable only under the festal rubrics (it takes
|
|
406
426
|
its turn in the rotation once every _n + 1_ years); it never reaches a
|
|
@@ -418,13 +438,13 @@ and selected by season: **Vidi aquam** (`va`) in Paschaltide, **Asperges
|
|
|
418
438
|
me** (`as`) otherwise.
|
|
419
439
|
|
|
420
440
|
```js
|
|
421
|
-
tonus.ordinarium({ ordinary: "
|
|
441
|
+
tonus.ordinarium({ ordinary: "ke" }); // every Kyrie
|
|
422
442
|
tonus.ordinarium({ mass: 9, ordinary: "gl" }); // Gloria of Cum jubilo
|
|
423
443
|
```
|
|
424
444
|
|
|
425
445
|
| `ordinary` | `ordinarium` |
|
|
426
446
|
| ---------- | --------------------------------------------- |
|
|
427
|
-
| `
|
|
447
|
+
| `ke` | Kyrie eleison |
|
|
428
448
|
| `gl` | Gloria |
|
|
429
449
|
| `cr` | Credo |
|
|
430
450
|
| `sa` | Sanctus |
|
|
@@ -475,7 +495,7 @@ seasonal ordo and returned in liturgical order. With no feast, each resolves
|
|
|
475
495
|
for the [default epoch](index.md#dates).
|
|
476
496
|
|
|
477
497
|
**Matins is returned flat.** The night office answers like any other hour,
|
|
478
|
-
its responsories drawn from the Nocturnale Romanum (`nr`)
|
|
498
|
+
its responsories drawn from the Nocturnale Romanum (`nr`). But the
|
|
479
499
|
three-nocturn, twelve-psalm division is not modelled: the chants are right,
|
|
480
500
|
their grouping into nocturns is not expressed.
|
|
481
501
|
|
|
@@ -492,7 +512,7 @@ interface OfficiumQuery extends CantusQuery {
|
|
|
492
512
|
}
|
|
493
513
|
```
|
|
494
514
|
|
|
495
|
-
The eight hours ship as [`HORAE`](index.md#the-appendix), Matins first
|
|
515
|
+
The eight hours ship as [`HORAE`](index.md#the-appendix), Matins first. Read
|
|
496
516
|
them from there rather than transcribing them, and an unrecognised `hora`
|
|
497
517
|
throws rather than matching nothing, so a misspelling cannot read as an empty
|
|
498
518
|
hour.
|
|
@@ -507,9 +527,9 @@ tonus.officium({ hora: "vespers" }); // throws: unknown hora "vespers"
|
|
|
507
527
|
|
|
508
528
|
### One cursus, the Benedictine
|
|
509
529
|
|
|
510
|
-
tonus assembles a single office
|
|
530
|
+
tonus assembles a single office (the monastic cursus) with no option to
|
|
511
531
|
choose another. The chants come from the Antiphonale Monasticum (`am`) and its
|
|
512
|
-
companions; the psalmody follows the Benedictine distribution
|
|
532
|
+
companions; the psalmody follows the Benedictine distribution, the little
|
|
513
533
|
hours take the gradual psalms (Terce 119–121, Sext 122–124, None 125–127),
|
|
514
534
|
with Sunday and Monday walking their portions of Ps 118 instead; Prime walks
|
|
515
535
|
Pss 1–19 across the week (Sunday opens Ps 118); and Compline is the fixed
|
|
@@ -530,7 +550,7 @@ the opening formula is included, as it is for a psalm's first verse.
|
|
|
530
550
|
mediant, as a psalm sung without an antiphon; `solemn` uses a tone's
|
|
531
551
|
ornamented mediant where it has one. Canticles are addressed by name:
|
|
532
552
|
`benedictus`, `magnificat`, `nunc dimittis`, `benedicite`. (The Te Deum
|
|
533
|
-
is not psalmody
|
|
553
|
+
is not psalmody: it carries its own melody and is not addressable here.)
|
|
534
554
|
|
|
535
555
|
```js
|
|
536
556
|
tonus.psalmus({ psalm: 109, verse: "1a", mode: 1 });
|
package/docs/api/heavens.md
CHANGED
|
@@ -168,12 +168,12 @@ and moves with precession; a table carrying "March 21" would be wrong for most
|
|
|
168
168
|
of the period this library models, and wrong differently every century.
|
|
169
169
|
|
|
170
170
|
**What is omitted, and why.** The exaltation degrees Ptolemy gives (the Sun at
|
|
171
|
-
19° Arietis and the rest) are not carried
|
|
172
|
-
here reads. Nor are the lunar nodes' exaltations, because the nodes are not
|
|
171
|
+
19° Arietis and the rest) are not carried, because the sign is the resolution
|
|
172
|
+
anything here reads. Nor are the lunar nodes' exaltations, because the nodes are not
|
|
173
173
|
tonus bodies. Five signs exalt nobody: that silence is the tradition's, not a
|
|
174
174
|
gap in the table.
|
|
175
175
|
|
|
176
|
-
The `melothesia` is the *homo signorum* of medieval calendars
|
|
176
|
+
The `melothesia` is the *homo signorum* of medieval calendars, Aries at the
|
|
177
177
|
head down to Pisces at the feet. It was practice, not decoration: phlebotomy
|
|
178
178
|
was timed against it, and while the Moon stood in a sign its member was not to
|
|
179
179
|
be touched. Sourced from Ptolemy's *Tetrabiblos* I.17 and I.19
|
|
@@ -216,7 +216,7 @@ The doctrinae:
|
|
|
216
216
|
Sphere pitches are computed directly from the doctrina's pure ratios,
|
|
217
217
|
anchored at the temperamentum's A4, so historical coherence holds:
|
|
218
218
|
`temperamentum("ptolemy-intense")` with `harmonia({ doctrina: "ptolemy" })`
|
|
219
|
-
gives pure Ptolemaic intervals throughout
|
|
219
|
+
gives pure Ptolemaic intervals throughout: Sun→Jupiter a pure 3/2,
|
|
220
220
|
Sun→Saturn a pure 2/1. The temperamentum's scale governs pitch naming and
|
|
221
221
|
the imprint.
|
|
222
222
|
|
|
@@ -322,7 +322,7 @@ h.tabula.find((r) => r.name === "Jupiter");
|
|
|
322
322
|
```
|
|
323
323
|
|
|
324
324
|
`ratio` is the doctrina's own fraction against the mese, the primary datum of
|
|
325
|
-
the whole scheme
|
|
325
|
+
the whole scheme. `spn` and `hz` are that ratio sounded against A4, not
|
|
326
326
|
independent claims. Comparing doctrinae means comparing these: the table
|
|
327
327
|
under [Theory & Context](#theory--context) is what the field returns.
|
|
328
328
|
|
|
@@ -364,7 +364,7 @@ The doctrina ratios are reconstructed from the primary texts through
|
|
|
364
364
|
Joscelyn Godwin's syntheses, mapping each body to a Greek tone-name and
|
|
365
365
|
deriving its ratio by Pythagorean interval arithmetic normalized to the
|
|
366
366
|
mese (Sun = 1/1). The full method, the taxonomy, and the decisions taken
|
|
367
|
-
along the way are documented at the data
|
|
367
|
+
along the way are documented at the data. See `DOCTRINAE` in
|
|
368
368
|
[`harmonia/data/doctrines.ts`](https://github.com/jeffreypierce/tonus/blob/main/src/engines/harmonia/data/doctrines.ts).
|
|
369
369
|
The same arithmetic is laid out from the tuning side in
|
|
370
370
|
[tuning.md](tuning.md#theory--context).
|
|
@@ -385,7 +385,7 @@ The resulting ratios, by sphere from the outermost:
|
|
|
385
385
|
|
|
386
386
|
The single pitch separating Pythagoras from Boethius is Venus: a whole
|
|
387
387
|
tone above the Sun in the disjunct system (9/8, B durum), a semitone in
|
|
388
|
-
the conjunct (256/243, B molle)
|
|
388
|
+
the conjunct (256/243, B molle). This is the origin of the durum/molle
|
|
389
389
|
distinction that runs through all of medieval music theory.
|
|
390
390
|
|
|
391
391
|
## Sources
|
package/docs/api/index.md
CHANGED
|
@@ -4,7 +4,7 @@ The technical center of tonus: the full public API, the conventions every method
|
|
|
4
4
|
obeys, and the error contract. The API is **fourteen methods on the `tonus`
|
|
5
5
|
namespace**, no sub-namespaces.
|
|
6
6
|
|
|
7
|
-
**[
|
|
7
|
+
**[Interactive demo](https://orreliquum.com/)**
|
|
8
8
|
|
|
9
9
|
```js
|
|
10
10
|
import tonus from "tonus";
|
|
@@ -12,6 +12,7 @@ import tonus from "tonus";
|
|
|
12
12
|
|
|
13
13
|
- [The methods](#the-methods) — by engine
|
|
14
14
|
- [The appendix](#the-appendix) — the canonical constant tables
|
|
15
|
+
- [The entries](#the-entries) — the four subpaths, and what each holds
|
|
15
16
|
- [Full contents](#full-contents) — every method and section
|
|
16
17
|
- [Conventions](#conventions) — Latin/English, dates, determinism, error contracts, bibliography
|
|
17
18
|
|
|
@@ -88,7 +89,7 @@ table of codes or English keeps English.
|
|
|
88
89
|
| ----------- | -------------------------------------------------------------------------- |
|
|
89
90
|
| `HORAE` | the eight canonical hours, Matins first — the order is the content |
|
|
90
91
|
| `OFFICIA` | office code → the Latin genus (`an` → "Antiphona") |
|
|
91
|
-
| `ORDINARIA` | ordinary code → the Latin name (`
|
|
92
|
+
| `ORDINARIA` | ordinary code → the Latin name (`ke` → "Kyrie eleison") |
|
|
92
93
|
| `MODI` | mode number → the Latin name (`"1"` → "Modus I") |
|
|
93
94
|
| `SOURCES` | book code → its bibliographic record; the codes `cantus({ source })` takes |
|
|
94
95
|
|
|
@@ -123,9 +124,42 @@ is for.
|
|
|
123
124
|
| `CENSUS_GROUPS` | the field groups → `{ offset, count }`; the keys are the valid `by:` values **and** the `profile` keys |
|
|
124
125
|
| `CENSUS_ORDER` | every censused chant id, in block order — so membership is a lookup, not a `try/catch` |
|
|
125
126
|
|
|
126
|
-
Use these to pool blocks without reproducing the distance rule
|
|
127
|
+
Use these to pool blocks without reproducing the distance rule. See [the census
|
|
127
128
|
contract](census.md#distance-is-cosine-per-field-group).
|
|
128
129
|
|
|
130
|
+
## The entries
|
|
131
|
+
|
|
132
|
+
The fourteen methods and every table above are on the root, and stay there. Four
|
|
133
|
+
subpath entries hold what the root index was carrying without being asked to:
|
|
134
|
+
the **anatomy** of a return value, and the types whose values a caller had to
|
|
135
|
+
spell by hand against a query or an option bag.
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
import { cantus, corpus } from "tonus/corpus";
|
|
139
|
+
import { inscriptio } from "tonus/inscriptio";
|
|
140
|
+
import type { Note, Phrase } from "tonus/score";
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Entry | Holds |
|
|
144
|
+
| ------------------ | ------------------------------------------------------------------------- |
|
|
145
|
+
| `tonus/corpus` | the shelf and its vocabulary — `cantus`, `corpus`, `SOURCES`, `HORAE` … |
|
|
146
|
+
| `tonus/score` | what a `Score` is made of — `Note`, `Phrase`, `Syllable`, `Metrics` … |
|
|
147
|
+
| `tonus/inscriptio` | the drawing surface — `inscriptio`, `Theme`, `TrackName`, `NoteGeometry` |
|
|
148
|
+
| `tonus/census` | one chant against the corpus — `census`, `CENSUS_BLOCK_FLOATS` |
|
|
149
|
+
|
|
150
|
+
Nothing is hidden by the split. The verbs stay on the namespace — the export law
|
|
151
|
+
puts them there — and the types a root signature names (`Score`, `Chant`,
|
|
152
|
+
`Cadence`, `Metrics`, `Imprint`) stay on the root as well, because the root's own
|
|
153
|
+
signatures name them. What moved off is what only a caller already **holding** a
|
|
154
|
+
`Score` could reach.
|
|
155
|
+
|
|
156
|
+
Each entry also surfaces types that were reachable through a signature but
|
|
157
|
+
nameable nowhere: `ChantSource` and `OfficeCode` (the codes `cantus({ source })`
|
|
158
|
+
and `office` take), `Theme` and `TrackName` (what an `opts` bag accepts), and
|
|
159
|
+
`CENSUS_BLOCK_FLOATS` (the stride a caller decoding a block had to get by
|
|
160
|
+
counting `CENSUS_GROUPS`). That drift — a value you must pass but cannot name —
|
|
161
|
+
is what the entries exist to stop.
|
|
162
|
+
|
|
129
163
|
## Full contents
|
|
130
164
|
|
|
131
165
|
Every method and every section, page by page, in dependency order. Pages later in
|
|
@@ -218,7 +252,7 @@ Other fields carry only one register. Latin-only, _e.g._ `genus`, `ordinarium`,
|
|
|
218
252
|
`incipit`, `differentia`, `accentus`. English-only, _e.g._ `date`, `velocity`, `hz`.
|
|
219
253
|
|
|
220
254
|
Display strings live in exported maps (_e.g._ `SEASON_LABEL`),
|
|
221
|
-
never as label fields on objects
|
|
255
|
+
never as label fields on objects. The maps are [the appendix](#the-appendix).
|
|
222
256
|
|
|
223
257
|
### Dates
|
|
224
258
|
|
|
@@ -238,14 +272,14 @@ an ensemble) it is seeded, so the same seed yields byte-identical output.
|
|
|
238
272
|
|
|
239
273
|
### Error contract
|
|
240
274
|
|
|
241
|
-
- Query functions return `[]` on no match, never throw
|
|
275
|
+
- Query functions return `[]` on no match, never throw. But an **empty or
|
|
242
276
|
unknown-key query** throws (a mistyped filter is a bug, not an empty result):
|
|
243
277
|
`festum({ month: 12 })` and `cantus({})` throw rather than silently resolving a
|
|
244
278
|
plausible-looking answer.
|
|
245
279
|
- Builder functions throw `Error` with a descriptive message on invalid input.
|
|
246
280
|
- `notatio` throws on invalid `Chant` input.
|
|
247
281
|
- `inscriptio` throws on a non-`Score` argument or an unknown notation species.
|
|
248
|
-
- `temperamentum.tonus()` throws if `mode` is `"auto"
|
|
282
|
+
- `temperamentum.tonus()` throws if `mode` is `"auto"`. Mode must be set
|
|
249
283
|
explicitly.
|
|
250
284
|
- Malformed `comma`, ratio, or Scala input throws `RangeError`; custom scales
|
|
251
285
|
must supply 7 or 12 steps, beginning at `1/1` (a degree list) or ending at
|