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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,130 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to tonus. Newest first.
|
|
4
4
|
|
|
5
|
+
## 0.10.0 — 2026-08-31
|
|
6
|
+
|
|
7
|
+
The corpus stores a melody once instead of once per book, the genus labels say
|
|
8
|
+
what GregoBase says, and the root index stops carrying the anatomy of its own
|
|
9
|
+
return values.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **BREAKING: the Kyrie's ordinary code is `ke`, not `ky`.** GregoBase files
|
|
14
|
+
every ordinary chant under office-part `ky` = Kyriale, which is the roll-up
|
|
15
|
+
genus, so the Kyrie itself needed a code of its own. `cantus({ ordinary })`
|
|
16
|
+
and `ordinarium({ ordinary })` both take `ke` now, and `ORDINARIA` is keyed
|
|
17
|
+
by it. **A stale `"ky"` throws** rather than returning `[]` — an unknown
|
|
18
|
+
ordinary code is a malformed query, and this is the one most likely to
|
|
19
|
+
arrive stale, so the error names the replacement.
|
|
20
|
+
- **BREAKING: three office genus labels were wrong and are corrected.** They
|
|
21
|
+
were read off the two-letter codes rather than off the source; GregoBase's
|
|
22
|
+
own vocabulary (`include/txt.php`, `$txt['usage']`) is now followed. `or` is
|
|
23
|
+
**Toni Communes** (it read "Ordinarium"), `tp` is **Tropa** (it read "Tonus
|
|
24
|
+
Peregrinus"), and `pa` is **Prosa**. `or` was the costly one: tonus stamped
|
|
25
|
+
an invented genus on a code the database already used for something else,
|
|
26
|
+
and 132 real Toni Communes chants were dropped at the extractor for want of
|
|
27
|
+
a mapping. Anything reading `chant.genus`, or filtering `office: "or"`
|
|
28
|
+
expecting the Mass ordinary, is affected — the ordinary is `ky` (genus) or
|
|
29
|
+
`ordinary` (part).
|
|
30
|
+
- **Two office codes are new: `ky` and `va`.** `ky` is the Mass ordinary's
|
|
31
|
+
roll-up genus; `va` ("Varia") is the catch-all a chant falls to when its
|
|
32
|
+
office-part is unrecognised. It used to fall to `or`, which was harmless
|
|
33
|
+
while `or` was an invented label and is not now that it means a recitation
|
|
34
|
+
formula the census excludes.
|
|
35
|
+
- **BREAKING: type-only names moved off the root entry.** Four subpath entries
|
|
36
|
+
now hold the grain the index was carrying — `tonus/corpus` (the shelf and its
|
|
37
|
+
vocabulary), `tonus/score` (what a `Score` is made of), `tonus/inscriptio`
|
|
38
|
+
(the drawing surface), `tonus/census` (one chant against the corpus). Verbs
|
|
39
|
+
stay on the root namespace, and the types a root signature names stay on the
|
|
40
|
+
root too. **Every value export the root carried is still exported from it**,
|
|
41
|
+
so nothing moved out of a JavaScript consumer's reach — though the code
|
|
42
|
+
renames above do reach one.
|
|
43
|
+
- **A melody printed in several books is stored once.** It was stored once per
|
|
44
|
+
book. `books` now lists every printing and `pages` is keyed by book code, so
|
|
45
|
+
`cantus({ source })` presents a shared chant as the book asked for: that
|
|
46
|
+
book's source record and page numbers, not those of the file the record
|
|
47
|
+
happens to live in. 7840 chants, 9758 listings.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- **Four subpath entries surface types that were reachable but unnameable.**
|
|
52
|
+
`ChantSource`, `OfficeCode`, `OrdinaryCode`, `CanonicalHour`, `Theme`,
|
|
53
|
+
`ThemeColors`, `TrackName`, `TrackData`, and `CENSUS_BLOCK_FLOATS` — each a
|
|
54
|
+
value callers had to spell by hand against a query or an option bag.
|
|
55
|
+
- **The two boundaries are gated instead of described.** `npm run gate` holds
|
|
56
|
+
the rendering boundary (only `inscriptio.ts` and the emitters may import from
|
|
57
|
+
`emitters/`) and the entry map (every `exports` subpath has a source module,
|
|
58
|
+
and every entry module is exported). Prose had already failed to hold the
|
|
59
|
+
rendering boundary once. It runs as part of `npm test`.
|
|
60
|
+
|
|
61
|
+
### Removed
|
|
62
|
+
|
|
63
|
+
- **`ams`, `cot`, and `cse` are no longer separate data files.** Their contents
|
|
64
|
+
were listings on records the other books already own, and are now reachable
|
|
65
|
+
through `books`/`pages` on those records.
|
|
66
|
+
|
|
67
|
+
## 0.9.1 — 2026-08-24
|
|
68
|
+
|
|
69
|
+
Moderna reads the pitch it was given: the whole page had been sitting a sixth
|
|
70
|
+
too high, and a transposed chant said nothing about its own accidentals.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- **Moderna drew every note a sixth above where it belonged.** `writtenY`
|
|
75
|
+
measured the note against a reference term that had not been normalised the
|
|
76
|
+
same way (`4 * 7` against a note term carrying `+2`), so sounding E4 computed
|
|
77
|
+
as 14 staff steps instead of 0. Every note of every moderna score sat above
|
|
78
|
+
the top line. The port was faithful — the same expression is in the locked
|
|
79
|
+
reference generator, which was fed pitches an octave below today's corpus, so
|
|
80
|
+
two errors cancelled; when the corpus moved to true octaves only one of them
|
|
81
|
+
moved. The clef's octave lift is now stated once, explicitly.
|
|
82
|
+
- **A transposed chromatic rendered as a silent wrong pitch.** `temperamentum`'s
|
|
83
|
+
`transpose` moves what a chant sounds, and moderna reads sounding pitch — but
|
|
84
|
+
the accidental was parsed and discarded, so `Ab3` and `A3` landed on one slot
|
|
85
|
+
with no sign drawn. The page read a semitone off with nothing to say so.
|
|
86
|
+
Spelling now follows `spn`: flats stay flats, sharps stay sharps. Signs
|
|
87
|
+
written in the GABC are unaffected — `computeAccidentals` remains
|
|
88
|
+
authoritative wherever it has an opinion, keyed on the degree a sign alters
|
|
89
|
+
rather than the row that carries it.
|
|
90
|
+
- **Moderna had no ledger lines at all.** A note outside the five rendered as a
|
|
91
|
+
head floating in blank space. One line per staff line the note has passed,
|
|
92
|
+
drawn behind the head: the spaces immediately outside (steps 9 and −1) get
|
|
93
|
+
none, and a line-note and the space above it share one.
|
|
94
|
+
- **`midiToGabc` threw on every B-flat** — the one accidental chant sings, and
|
|
95
|
+
the whole reason `parse.ts` carries a flat state machine. It now spells it
|
|
96
|
+
`ix`, and `gabcToMidi` reads that back, so the two stay inverses. Other
|
|
97
|
+
chromatic pitch classes still throw. Verified over 222 round-trips.
|
|
98
|
+
- **The GABC clef tables disagreed about which clefs exist.** `temper/gabc.ts`
|
|
99
|
+
knew six (`c1`–`c4`, `f3`, `f4`) while `parse.ts` accepted sixteen, so a
|
|
100
|
+
`cb2` the parser reads happily raised "Unknown clef". `CLEFS` is now derived
|
|
101
|
+
rather than hand-listed; all six original entries are reproduced exactly.
|
|
102
|
+
|
|
103
|
+
### Changed
|
|
104
|
+
|
|
105
|
+
- **A low moderna chant is written an octave up.** One clef throughout — what
|
|
106
|
+
floats is the written octave, the move the hand already makes when it lifts a
|
|
107
|
+
chant onto the gamut's fingers. Chant sounds below this staff (corpus median
|
|
108
|
+
50–62 against a window of 52–65), and transposing down pushes it further: at
|
|
109
|
+
−4 an unlifted score put 43.6% of all notes under the bottom line, now 9.8%.
|
|
110
|
+
Untransposed moderna output moves for most chants as a result, always toward
|
|
111
|
+
the staff (7.8% off-staff to 5.8%). Whole octaves only, and one lift for the
|
|
112
|
+
whole chant — a page that changed register partway would read as two pieces.
|
|
113
|
+
The limit is honest: an ambitus straddling the window cannot be aligned by
|
|
114
|
+
any multiple of 12, and 59 of 200 measured chants are wider than the staff.
|
|
115
|
+
`notatio`'s `spn` remains the authority on what actually sounds.
|
|
116
|
+
- **Quadrata is untouched by all of this**, by construction: it draws from
|
|
117
|
+
staff position, which transposition does not move. Verified byte-identical.
|
|
118
|
+
|
|
119
|
+
### Packaging
|
|
120
|
+
|
|
121
|
+
- `.npmignore` removed — it contradicted the `files` allowlist, and two
|
|
122
|
+
mechanisms deciding what ships is one more than can be reasoned about.
|
|
123
|
+
Measured before and after: the tarball is byte-identical at 216 files.
|
|
124
|
+
- `"sideEffects": false` declared, and verified true — nothing in `dist/` runs
|
|
125
|
+
at module scope and no data file is read at import time.
|
|
126
|
+
- The description no longer claims "and performance"; the voice lives in
|
|
127
|
+
tonus-sonus.
|
|
128
|
+
|
|
5
129
|
## 0.9.0 — 2026-08-19
|
|
6
130
|
|
|
7
131
|
The tracks stop promising a contract they never kept, and the geometry says
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ belong to which day and returns analysis and notation, and calculates the
|
|
|
8
8
|
_music of the spheres_ proposed by Pythagoras, Boethius, and more as real
|
|
9
9
|
intervals.
|
|
10
10
|
|
|
11
|
-
**[
|
|
11
|
+
**[Interactive demo](https://orreliquum.com/)**
|
|
12
12
|
|
|
13
13
|
Everything is computed locally and deterministically: the same question always
|
|
14
14
|
returns the same answer, from data that ships inside the package, with no network
|
|
@@ -72,8 +72,8 @@ its final, dominant, ambitus, and ethos, with its psalm tones.
|
|
|
72
72
|
**The calendar** is Tridentine, resolved against Easter by
|
|
73
73
|
the Julian or the Gregorian computus.
|
|
74
74
|
|
|
75
|
-
**The repertoire** is
|
|
76
|
-
the _Nocturnale Romanum_ night office
|
|
75
|
+
**The repertoire** is 7,840 chants across seven books, six Solesmes editions and
|
|
76
|
+
the _Nocturnale Romanum_ night office in
|
|
77
77
|
[GABC](https://gregorio-project.github.io/) notation: Mass propers, the Kyriale,
|
|
78
78
|
the Office hours, the psalter, and the Matins nocturns.
|
|
79
79
|
|
package/dist/census.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { getCensus as census } from "./engines/census/census.js";
|
|
2
|
+
export type { Census, CensusQuery, CensusBy, CensusGroup, CensusGroupProfile, CensusNeighbor, } from "./engines/census/types.js";
|
|
3
|
+
export { CENSUS_GROUPS, CENSUS_ORDER, CENSUS_BLOCK_FLOATS, } from "./data/census.js";
|
|
4
|
+
//# sourceMappingURL=census.d.ts.map
|
package/dist/census.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// tonus/census — one chant measured against the corpus that holds it
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// The analysis boundary, made addressable. The library never RUNS a census; it
|
|
5
|
+
// CITES one. Everything here reads a baked table — the blocks the corpus
|
|
6
|
+
// pipeline emits — and does arithmetic over it. No mining lives behind this
|
|
7
|
+
// entry and none may be added: a threshold calibrated across many chants is the
|
|
8
|
+
// corpus repo's business, and re-enters as generated data with provenance.
|
|
9
|
+
//
|
|
10
|
+
// Year-shaped questions ("this season," "this manuscript," a window of the
|
|
11
|
+
// calendar) are not here and do not belong here. `data/census.ts` states the
|
|
12
|
+
// same rule from the data side: this is the only census artifact in the
|
|
13
|
+
// package, and the corpus repo's other outputs stay there. Pooling blocks is
|
|
14
|
+
// the caller's to do, under the rule census.md fixes — cosine per field group,
|
|
15
|
+
// never over the flat 221.
|
|
16
|
+
//
|
|
17
|
+
// CENSUS_BLOCK_FLOATS joins the two constants the root already exported. A
|
|
18
|
+
// caller decoding a block had to know the stride and could get it only by
|
|
19
|
+
// counting CENSUS_GROUPS, which is the transcription the appendix rule exists
|
|
20
|
+
// to prevent.
|
|
21
|
+
export { getCensus as census } from "./engines/census/census.js";
|
|
22
|
+
export { CENSUS_GROUPS, CENSUS_ORDER, CENSUS_BLOCK_FLOATS, } from "./data/census.js";
|
|
23
|
+
//# sourceMappingURL=census.js.map
|
package/dist/corpus.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { getChants as cantus, getCorpus as corpus, SOURCES } from "./engines/chant/chant.js";
|
|
2
|
+
export { HORAE, OFFICIA, ORDINARIA, MODI } from "./engines/chant/types.js";
|
|
3
|
+
export type { Chant, OrdinaryChant, CantusQuery, CorpusQuery, Corpus, CorpusLedger, CorpusFullCount, GenusCount, ModeCount, SharedCount, ChantSource, OfficeCode, OrdinaryCode, CanonicalHour, } from "./engines/chant/types.js";
|
|
4
|
+
//# sourceMappingURL=corpus.d.ts.map
|
package/dist/corpus.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// tonus/corpus — the shelf: what tonus holds, and how to ask for it
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// The repertoire and its vocabulary, separated from the calendar that resolves
|
|
5
|
+
// a DAY. `cantus` and `corpus` ask what is on the shelf; `festum`, `proprium`
|
|
6
|
+
// and `officium` ask what a day calls for. The two questions have been one
|
|
7
|
+
// import since the beginning, which is part of why the shelf reads as though it
|
|
8
|
+
// were a property of the calendar.
|
|
9
|
+
//
|
|
10
|
+
// This entry surfaces four types the root index never exported, each of them a
|
|
11
|
+
// value a caller otherwise had to TYPE OUT against a query: ChantSource (the
|
|
12
|
+
// book codes `cantus({ source })` accepts), OfficeCode and OrdinaryCode (the
|
|
13
|
+
// genus and ordinary codes), and CanonicalHour (what HORAE holds). The appendix
|
|
14
|
+
// rule already admits the tables; the types they range over belong beside them.
|
|
15
|
+
export { getChants as cantus, getCorpus as corpus, SOURCES } from "./engines/chant/chant.js";
|
|
16
|
+
export { HORAE, OFFICIA, ORDINARIA, MODI } from "./engines/chant/types.js";
|
|
17
|
+
//# sourceMappingURL=corpus.js.map
|