tonus 0.1.8 → 0.5.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 (164) hide show
  1. package/BIBLIOGRAPHY.md +132 -108
  2. package/CHANGELOG.md +598 -1
  3. package/LICENSE +133 -29
  4. package/README.md +106 -83
  5. package/dist/data/am.js +2666 -11196
  6. package/dist/data/ams.d.ts +5 -0
  7. package/dist/data/ams.js +122 -0
  8. package/dist/data/attestation.d.ts +19 -0
  9. package/dist/data/attestation.js +15716 -0
  10. package/dist/data/attestation.json +15711 -0
  11. package/dist/data/cadentiae.d.ts +43 -0
  12. package/dist/data/cadentiae.js +174 -0
  13. package/dist/data/cal.js +48 -0
  14. package/dist/data/census.d.ts +12 -0
  15. package/dist/data/census.js +36 -0
  16. package/dist/data/commune-office.d.ts +4 -0
  17. package/dist/data/commune-office.js +2371 -0
  18. package/dist/data/commune-office.json +2365 -0
  19. package/dist/data/commune.js +181 -11
  20. package/dist/data/corpus-overlap.d.ts +17 -0
  21. package/dist/data/corpus-overlap.js +299 -5
  22. package/dist/data/cot.d.ts +5 -0
  23. package/dist/data/cot.js +172 -0
  24. package/dist/data/cse.d.ts +5 -0
  25. package/dist/data/cse.js +122 -0
  26. package/dist/data/gabc-glyphs.d.ts +45 -0
  27. package/dist/data/gabc-glyphs.js +122 -0
  28. package/dist/data/gr.js +754 -6394
  29. package/dist/data/kyriale.js +116 -116
  30. package/dist/data/la.js +799 -13419
  31. package/dist/data/lh.js +113 -3473
  32. package/dist/data/lu.js +931 -17631
  33. package/dist/data/nocturnale-romanum.js +1659 -10411
  34. package/dist/data/office-ferial.d.ts +4 -0
  35. package/dist/data/office-ferial.js +396 -0
  36. package/dist/data/office-ferial.json +391 -0
  37. package/dist/data/office-monastic.d.ts +17 -1
  38. package/dist/data/office-monastic.js +1403 -466
  39. package/dist/data/office-psalms-monastic.d.ts +13 -1
  40. package/dist/data/office-psalms-monastic.js +9 -0
  41. package/dist/data/propers.js +1 -1
  42. package/dist/data/psalms.js +22919 -5
  43. package/dist/data/psm.d.ts +5 -0
  44. package/dist/data/psm.js +122 -0
  45. package/dist/data/seasonal-respbreve.d.ts +5 -0
  46. package/dist/data/seasonal-respbreve.js +41 -0
  47. package/dist/data/seasonal-respbreve.json +35 -0
  48. package/dist/data/smufl-glyphs.d.ts +17 -0
  49. package/dist/data/smufl-glyphs.js +1546 -0
  50. package/dist/data/smufl-glyphs.json +1530 -0
  51. package/dist/engines/cal/calendar.d.ts +3 -2
  52. package/dist/engines/cal/calendar.js +105 -29
  53. package/dist/engines/cal/data/eras.d.ts +35 -0
  54. package/dist/engines/cal/data/eras.js +128 -0
  55. package/dist/engines/cal/date.js +44 -0
  56. package/dist/engines/cal/types.d.ts +15 -3
  57. package/dist/engines/cal/types.js +5 -5
  58. package/dist/engines/census/census.d.ts +7 -0
  59. package/dist/engines/census/census.js +179 -0
  60. package/dist/engines/census/types.d.ts +55 -0
  61. package/dist/engines/census/types.js +8 -0
  62. package/dist/engines/chant/attest.d.ts +39 -0
  63. package/dist/engines/chant/attest.js +90 -0
  64. package/dist/engines/chant/chant.d.ts +16 -4
  65. package/dist/engines/chant/chant.js +220 -30
  66. package/dist/engines/chant/data/compline.js +2 -1
  67. package/dist/engines/chant/data/masses.d.ts +56 -4
  68. package/dist/engines/chant/data/masses.js +305 -80
  69. package/dist/engines/chant/data/prime.js +1 -1
  70. package/dist/engines/chant/hour.js +279 -58
  71. package/dist/engines/chant/ordinary.d.ts +2 -0
  72. package/dist/engines/chant/ordinary.js +336 -56
  73. package/dist/engines/chant/propers.js +55 -5
  74. package/dist/engines/chant/psalm.d.ts +4 -4
  75. package/dist/engines/chant/psalm.js +25 -11
  76. package/dist/engines/chant/syllabify.d.ts +1 -0
  77. package/dist/engines/chant/syllabify.js +90 -17
  78. package/dist/engines/chant/types.d.ts +115 -12
  79. package/dist/engines/chant/types.js +38 -3
  80. package/dist/engines/harmonia/api.js +4 -0
  81. package/dist/engines/harmonia/data/doctrines.js +3 -1
  82. package/dist/engines/harmonia/tabula.d.ts +3 -0
  83. package/dist/engines/harmonia/tabula.js +1 -0
  84. package/dist/engines/harmonia/voice.d.ts +4 -0
  85. package/dist/engines/harmonia/voice.js +8 -4
  86. package/dist/engines/imprint.js +14 -1
  87. package/dist/engines/planet/orbital.js +4 -4
  88. package/dist/engines/planet/planet.d.ts +10 -0
  89. package/dist/engines/planet/planet.js +30 -3
  90. package/dist/engines/planet/position.js +13 -10
  91. package/dist/engines/planet/types.d.ts +1 -0
  92. package/dist/engines/score/api.d.ts +2 -13
  93. package/dist/engines/score/api.js +21 -8
  94. package/dist/engines/score/articulation.js +2 -2
  95. package/dist/engines/score/cadence.d.ts +76 -0
  96. package/dist/engines/score/cadence.js +96 -0
  97. package/dist/engines/score/emitters/accidentals.d.ts +21 -0
  98. package/dist/engines/score/emitters/accidentals.js +88 -0
  99. package/dist/engines/score/emitters/atramentum.d.ts +107 -0
  100. package/dist/engines/score/emitters/atramentum.js +239 -0
  101. package/dist/engines/score/emitters/breaking.d.ts +62 -0
  102. package/dist/engines/score/emitters/breaking.js +80 -0
  103. package/dist/engines/score/emitters/moderna.d.ts +38 -0
  104. package/dist/engines/score/emitters/moderna.js +612 -0
  105. package/dist/engines/score/emitters/svg.d.ts +143 -0
  106. package/dist/engines/score/emitters/svg.js +1328 -0
  107. package/dist/engines/score/emitters/tracks.d.ts +104 -0
  108. package/dist/engines/score/emitters/tracks.js +728 -0
  109. package/dist/engines/score/infer.d.ts +3 -3
  110. package/dist/engines/score/infer.js +2 -2
  111. package/dist/engines/score/inscriptio.d.ts +69 -0
  112. package/dist/engines/score/inscriptio.js +138 -0
  113. package/dist/engines/score/ir.d.ts +2 -2
  114. package/dist/engines/score/ir.js +59 -12
  115. package/dist/engines/score/lyric.d.ts +23 -0
  116. package/dist/engines/score/lyric.js +234 -0
  117. package/dist/engines/score/meta.d.ts +2 -2
  118. package/dist/engines/score/modulation.d.ts +12 -0
  119. package/dist/engines/score/modulation.js +49 -0
  120. package/dist/engines/score/neume.js +35 -4
  121. package/dist/engines/score/parse.js +150 -9
  122. package/dist/engines/score/phrasing.js +4 -3
  123. package/dist/engines/score/prosody.d.ts +38 -0
  124. package/dist/engines/score/prosody.js +70 -6
  125. package/dist/engines/score/tabula.d.ts +37 -5
  126. package/dist/engines/score/tabula.js +18 -0
  127. package/dist/engines/score/types.d.ts +88 -1
  128. package/dist/engines/temper/api.d.ts +4 -1
  129. package/dist/engines/temper/api.js +28 -5
  130. package/dist/engines/temper/data/guido.js +6 -2
  131. package/dist/engines/temper/data/modes.d.ts +6 -0
  132. package/dist/engines/temper/data/modes.js +42 -0
  133. package/dist/engines/temper/data/tones.d.ts +1 -1
  134. package/dist/engines/temper/data/tones.js +20 -11
  135. package/dist/engines/temper/interval.js +4 -3
  136. package/dist/engines/temper/modality.d.ts +11 -2
  137. package/dist/engines/temper/modality.js +74 -2
  138. package/dist/engines/temper/modes.d.ts +1 -1
  139. package/dist/engines/temper/pitch.d.ts +1 -1
  140. package/dist/engines/temper/pitch.js +12 -2
  141. package/dist/engines/temper/scale.d.ts +53 -0
  142. package/dist/engines/temper/scale.js +107 -8
  143. package/dist/index.d.ts +26 -8
  144. package/dist/index.js +37 -4
  145. package/docs/api/calendar.md +279 -0
  146. package/docs/api/census.md +288 -0
  147. package/docs/api/chant.md +657 -0
  148. package/docs/api/heavens.md +346 -0
  149. package/docs/api/index.md +263 -0
  150. package/docs/api/score.md +873 -0
  151. package/docs/api/tuning.md +619 -0
  152. package/package.json +11 -5
  153. package/dist/data/office-matins-roman.d.ts +0 -19
  154. package/dist/data/office-matins-roman.js +0 -4383
  155. package/dist/data/office-psalms-roman.d.ts +0 -15
  156. package/dist/data/office-psalms-roman.js +0 -28
  157. package/dist/data/office-roman.d.ts +0 -19
  158. package/dist/data/office-roman.js +0 -13792
  159. package/dist/engines/chant/matutinum.d.ts +0 -33
  160. package/dist/engines/chant/matutinum.js +0 -81
  161. package/dist/engines/score/emitters/midi.d.ts +0 -65
  162. package/dist/engines/score/emitters/midi.js +0 -162
  163. package/dist/engines/score/emitters/musicxml.d.ts +0 -18
  164. package/dist/engines/score/emitters/musicxml.js +0 -166
@@ -1,36 +1,63 @@
1
- // humana/data/masses — 18 kyriale mass profiles
2
- //
3
- // Describes which masses are appropriate for a given season, grade, and day.
4
- // Mass 0 has two ad-lib variants (index 0a/0b); all others are single entries.
5
- import { GRADE_ORDER, } from "../../cal/types.js";
6
- // Inclusive slice of GRADE_ORDER from `high` (more solemn) to `low`.
7
- // e.g. gradesFrom("duplex-i", "duplex-ii") lists every grade between them.
8
- function gradesFrom(high, low) {
9
- const hi = GRADE_ORDER.indexOf(high);
10
- const lo = GRADE_ORDER.indexOf(low);
11
- return GRADE_ORDER.slice(hi, lo + 1);
12
- }
13
- // Ad libitum entries are not part of the numbered kyriale; they serve as a
14
- // last-resort fallback when no numbered mass matches the feast context.
1
+ // "This Ordinary is NOT meant to be a matter of hard and fast rule: chants from
2
+ // one Mass may be used together with those from others, the Ferial Masses
3
+ // excepted." [liber-usualis, Kyriale] — so slots may mix freely EXCEPT
4
+ // under these two rubrics, whose masses are sung whole.
5
+ export const WHOLE_MASS_RUBRICS = new Set([
6
+ "feria",
7
+ "feria-penitential",
8
+ ]);
9
+ // The grades belonging to each rank category. The Grade ladder is
10
+ // classis-primary and already carries the class in its names — `-i` is
11
+ // "Duplex/Semiduplex I classis", `-ii` is II classis, unsuffixed is the
12
+ // III-class tier (see cal/types.ts and archive/plan-2-rank-redesign.md for
13
+ // the canonical 14-grade table).
14
+ export const CLASS_I_GRADES = [
15
+ "triduum",
16
+ "duplex-i",
17
+ "duplex-majus-i",
18
+ "semiduplex-i",
19
+ ];
20
+ export const CLASS_II_GRADES = ["duplex-ii", "semiduplex-ii"];
21
+ export const CLASS_III_GRADES = [
22
+ "duplex-majus",
23
+ "duplex",
24
+ "semiduplex",
25
+ ];
26
+ // `feria-privilegiata` is Ash Wednesday and Holy Week Mon–Wed — ranked high in
27
+ // precedence but a feria, and always penitential.
28
+ export const FERIA_GRADES = [
29
+ "feria-privilegiata",
30
+ "feria-major",
31
+ "vigilia",
32
+ "feria",
33
+ ];
34
+ // Ad libitum fallbacks for a day whose calendar entry names no mass at all.
35
+ // `mass` doubles as the lookup key into the Kyriale, so a fallback must name a
36
+ // mass the book actually carries. These two carried mass 0 — a number no Kyriale
37
+ // entry has — so the fallback silently resolved to nothing: the ordinary came
38
+ // back with a Credo and the sprinkling and no Kyrie, Gloria, Sanctus or Agnus at
39
+ // all, on roughly 50 days a year. The numbers below are the settings these
40
+ // entries are already named after: de Angelis IS mass VIII, Cum jubilo IS the
41
+ // BVM mass. An open editorial question on bvm: "Missa Salve" could instead
42
+ // point at the ad libitum Kyrie Salve (appendix); mass IX is the plain reading
43
+ // of "de Beata Maria".
15
44
  export const AD_LIB = {
16
45
  standard: {
17
46
  id: "adlib_standard",
18
- mass: 0,
47
+ mass: 8,
19
48
  title: "Missa de Angelis (short)",
20
- seasons: ["epi", "nat"],
21
- grades: gradesFrom("duplex-ii", "feria"),
22
- days: ["dominica"],
49
+ rubric: "class-ii",
50
+ heading: "For feasts of the II class. 5.",
23
51
  bvm: false,
24
52
  credos: ["I"],
25
53
  notes: "Ad libitum variant for ordinary Sundays.",
26
54
  },
27
55
  bvm: {
28
56
  id: "adlib_bvm",
29
- mass: 0,
57
+ mass: 9,
30
58
  title: "Missa de Beata Maria (Missa Salve)",
31
- seasons: ["epi", "pent"],
32
- grades: gradesFrom("semiduplex", "feria"),
33
- days: ["feria"],
59
+ rubric: "bvm",
60
+ heading: "For feasts of the Blessed Virgin. 1.",
34
61
  bvm: true,
35
62
  credos: [],
36
63
  notes: "BVM Saturdays outside privileged seasons.",
@@ -43,9 +70,8 @@ export const MASSES = new Map([
43
70
  id: "mass_1",
44
71
  mass: 1,
45
72
  title: "Lux et Origo",
46
- seasons: ["pasc"],
47
- grades: gradesFrom("triduum", "duplex-ii"),
48
- days: ["dominica"],
73
+ rubric: "paschal",
74
+ heading: "I. — In Paschal Time.",
49
75
  bvm: false,
50
76
  credos: ["I", "III"],
51
77
  notes: "Sundays of Paschaltide; also solemn feasts in Paschaltide.",
@@ -57,9 +83,8 @@ export const MASSES = new Map([
57
83
  id: "mass_2",
58
84
  mass: 2,
59
85
  title: "Kyrie fons bonitatis",
60
- seasons: ["pasc"],
61
- grades: gradesFrom("triduum", "duplex-ii"),
62
- days: ["dominica", "feria"],
86
+ rubric: "class-i",
87
+ heading: "II. — For feasts of the I class. 1.",
63
88
  bvm: false,
64
89
  credos: ["I", "III"],
65
90
  notes: "Solemn feasts of the Lord during Paschaltide.",
@@ -71,9 +96,8 @@ export const MASSES = new Map([
71
96
  id: "mass_3",
72
97
  mass: 3,
73
98
  title: "Kyrie Deus sempiterne",
74
- seasons: ["nat", "epi"],
75
- grades: gradesFrom("duplex-i", "duplex-ii"),
76
- days: ["dominica", "feria"],
99
+ rubric: "class-i",
100
+ heading: "III. — For feasts of the I class. 2.",
77
101
  bvm: false,
78
102
  credos: ["I", "III"],
79
103
  notes: "Solemn feasts of the Lord outside Paschaltide, especially at Christmas/Epiphany.",
@@ -85,9 +109,8 @@ export const MASSES = new Map([
85
109
  id: "mass_4",
86
110
  mass: 4,
87
111
  title: "Cunctipotens genitor Deus",
88
- seasons: ["nat", "epi", "pasc", "pent"],
89
- grades: gradesFrom("duplex-i", "duplex-ii"),
90
- days: ["dominica", "feria"],
112
+ rubric: "class-ii",
113
+ heading: "IV. — For feasts of the II class. 1.",
91
114
  bvm: false,
92
115
  credos: ["I", "III"],
93
116
  notes: "Feasts of the Apostles and major solemnities.",
@@ -99,9 +122,8 @@ export const MASSES = new Map([
99
122
  id: "mass_5",
100
123
  mass: 5,
101
124
  title: "Kyrie magnæ Deus potentiæ",
102
- seasons: ["nat", "epi", "pasc", "pent"],
103
- grades: gradesFrom("duplex-i", "duplex-ii"),
104
- days: ["dominica"],
125
+ rubric: "class-ii",
126
+ heading: "V. — For feasts of the II class. 2.",
105
127
  bvm: false,
106
128
  credos: [],
107
129
  notes: "For Apostles and certain solemnities.",
@@ -113,9 +135,8 @@ export const MASSES = new Map([
113
135
  id: "mass_6",
114
136
  mass: 6,
115
137
  title: "Kyrie Rex genitor",
116
- seasons: ["nat", "epi", "pasc", "pent"],
117
- grades: gradesFrom("duplex-ii", "semiduplex"),
118
- days: ["feria", "dominica"],
138
+ rubric: "class-ii",
139
+ heading: "VI. — For feasts of the II class. 3.",
119
140
  bvm: false,
120
141
  credos: [],
121
142
  notes: "For Confessors (non-bishops).",
@@ -127,9 +148,8 @@ export const MASSES = new Map([
127
148
  id: "mass_7",
128
149
  mass: 7,
129
150
  title: "Kyrie Rex splendens",
130
- seasons: ["epi", "pent"],
131
- grades: gradesFrom("duplex-ii", "duplex"),
132
- days: ["dominica"],
151
+ rubric: "class-ii",
152
+ heading: "VII. — For feasts of the II class. 4.",
133
153
  bvm: false,
134
154
  credos: [],
135
155
  notes: "For Sundays after Epiphany and after Pentecost (EF).",
@@ -141,9 +161,8 @@ export const MASSES = new Map([
141
161
  id: "mass_8",
142
162
  mass: 8,
143
163
  title: "De Angelis",
144
- seasons: ["epi", "nat", "pent"],
145
- grades: gradesFrom("duplex-i", "feria"),
146
- days: ["dominica"],
164
+ rubric: "class-ii",
165
+ heading: "VIII. — For feasts of the II class. 5.",
147
166
  bvm: false,
148
167
  credos: ["I", "III"],
149
168
  notes: "Commonly used for Sundays per annum.",
@@ -155,9 +174,8 @@ export const MASSES = new Map([
155
174
  id: "mass_9",
156
175
  mass: 9,
157
176
  title: "Cum jubilo",
158
- seasons: ["adv", "nat", "quad", "pasc", "epi", "pent"],
159
- grades: gradesFrom("triduum", "feria"),
160
- days: ["feria", "dominica"],
177
+ rubric: "bvm",
178
+ heading: "IX. — For feasts of the Blessed Virgin. 1.",
161
179
  bvm: true,
162
180
  credos: ["IV"],
163
181
  notes: "Mass of the Blessed Virgin Mary; often for BVM feasts and Saturdays.",
@@ -169,9 +187,8 @@ export const MASSES = new Map([
169
187
  id: "mass_10",
170
188
  mass: 10,
171
189
  title: "Alme Pater",
172
- seasons: ["adv", "nat", "quad", "pasc", "epi", "pent"],
173
- grades: gradesFrom("duplex-ii", "feria"),
174
- days: ["feria", "dominica"],
190
+ rubric: "bvm",
191
+ heading: "X. — For feasts of the Blessed Virgin. 2.",
175
192
  bvm: true,
176
193
  credos: [],
177
194
  notes: "Marian Kyriale",
@@ -183,9 +200,8 @@ export const MASSES = new Map([
183
200
  id: "mass_11",
184
201
  mass: 11,
185
202
  title: "Orbis factor",
186
- seasons: ["epi", "pent"],
187
- grades: gradesFrom("duplex-ii", "feria"),
188
- days: ["dominica"],
203
+ rubric: "sunday",
204
+ heading: "XI. — For Sundays throughout the Year.",
189
205
  bvm: false,
190
206
  credos: ["I", "III"],
191
207
  notes: "For Sundays per annum (after Epiphany and after Pentecost).",
@@ -197,9 +213,8 @@ export const MASSES = new Map([
197
213
  id: "mass_12",
198
214
  mass: 12,
199
215
  title: "Pater cuncta",
200
- seasons: ["epi", "pent"],
201
- grades: gradesFrom("duplex-ii", "duplex"),
202
- days: ["dominica"],
216
+ rubric: "class-iii",
217
+ heading: "XII. — For feasts of the III class. 1.",
203
218
  bvm: false,
204
219
  credos: [],
205
220
  notes: "For Sundays after Pentecost.",
@@ -211,9 +226,8 @@ export const MASSES = new Map([
211
226
  id: "mass_13",
212
227
  mass: 13,
213
228
  title: "Stelliferi conditor orbis",
214
- seasons: ["epi", "pent"],
215
- grades: gradesFrom("duplex-ii", "duplex"),
216
- days: ["dominica"],
229
+ rubric: "class-iii",
230
+ heading: "XIII. — For feasts of the III class. 2.",
217
231
  bvm: false,
218
232
  credos: [],
219
233
  notes: "For Sundays after Pentecost.",
@@ -225,9 +239,8 @@ export const MASSES = new Map([
225
239
  id: "mass_14",
226
240
  mass: 14,
227
241
  title: "Jesu Redemptor",
228
- seasons: ["epi", "nat"],
229
- grades: gradesFrom("duplex-ii", "duplex"),
230
- days: ["feria", "dominica"],
242
+ rubric: "class-iii",
243
+ heading: "XIV. — For feasts of the III class. 3.",
231
244
  bvm: false,
232
245
  credos: [],
233
246
  notes: "For Confessor Bishops.",
@@ -239,9 +252,8 @@ export const MASSES = new Map([
239
252
  id: "mass_15",
240
253
  mass: 15,
241
254
  title: "Dominator Deus",
242
- seasons: ["epi", "pent"],
243
- grades: gradesFrom("duplex-ii", "duplex"),
244
- days: ["dominica"],
255
+ rubric: "commemoration",
256
+ heading: "XV. — For commemorations.",
245
257
  bvm: false,
246
258
  credos: [],
247
259
  notes: "For Sundays after Pentecost of lower solemnity.",
@@ -253,9 +265,8 @@ export const MASSES = new Map([
253
265
  id: "mass_16",
254
266
  mass: 16,
255
267
  title: "Deus genitor alme",
256
- seasons: ["epi", "pent"],
257
- grades: gradesFrom("semiduplex", "simplex"),
258
- days: ["dominica"],
268
+ rubric: "feria",
269
+ heading: "XVI. — For ferias throughout the Year.",
259
270
  bvm: false,
260
271
  credos: [],
261
272
  notes: "For lower-rank Sundays after Pentecost.",
@@ -267,11 +278,8 @@ export const MASSES = new Map([
267
278
  id: "mass_17",
268
279
  mass: 17,
269
280
  title: "Salve",
270
- seasons: ["adv", "quadp", "quad"],
271
- // Advent/Lent Sundays are Semiduplex I classis — the highest dignity in
272
- // these seasons — so the penitential Sunday mass must reach that far up.
273
- grades: gradesFrom("semiduplex-i", "feria"),
274
- days: ["dominica"],
281
+ rubric: "sunday-penitential",
282
+ heading: "XVII. — For the Sundays of Advent and Lent.",
275
283
  bvm: false,
276
284
  credos: ["IV"],
277
285
  notes: "For Sundays of Advent, pre-Lent, and Lent.",
@@ -283,15 +291,232 @@ export const MASSES = new Map([
283
291
  id: "mass_18",
284
292
  mass: 18,
285
293
  title: "Deus Genitor alme",
286
- seasons: ["adv", "quadp", "quad"],
287
- // Penitential ferias: privileged ferias (Ash Wed, Holy Week Mon–Wed)
288
- // down through ordinary ferias.
289
- grades: gradesFrom("feria-privilegiata", "feria"),
290
- days: ["feria"],
294
+ rubric: "feria-penitential",
295
+ heading: "XVIII. — For the ferias of Advent and Lent.",
291
296
  bvm: false,
292
297
  credos: [],
293
298
  notes: "For weekdays of Advent, pre-Lent, and Lent; penitential ferias.",
294
299
  },
295
300
  ],
296
301
  ]);
302
+ /** The masses the book appoints under one rubric, in mass-number order. */
303
+ export function massesForRubric(rubric) {
304
+ return [...MASSES.values()]
305
+ .filter((m) => m.rubric === rubric)
306
+ .sort((a, b) => a.mass - b.mass);
307
+ }
308
+ /** mass number → ordinary code → what the Kyriale prints. */
309
+ export const MASS_CENTURY = {
310
+ // Mass I — Lux et Origo
311
+ 1: {
312
+ ky: { from: 10, to: 10, printed: "X. s." },
313
+ gl: { from: 10, to: 10, printed: "X. s." },
314
+ sa: { from: 10, to: 10, printed: "X. s." },
315
+ ag: { from: 10, to: 10, printed: "X. s." },
316
+ },
317
+ // Mass II — Kyrie fons bonitatis
318
+ 2: {
319
+ ky: { from: 10, to: 10, printed: "X. s." },
320
+ gl: { from: 13, to: 13, printed: "XIII. s." },
321
+ ag: { from: 10, to: 10, printed: "X. s." },
322
+ },
323
+ // Mass III — Kyrie Deus sempiterne
324
+ 3: {
325
+ ky: { from: 11, to: 11, inferred: true, printed: "XI. s." },
326
+ gl: { from: 11, to: 11, printed: "XI. s." },
327
+ sa: { from: 12, to: 12, alt: 11, printed: "(XI) XII. s." },
328
+ ag: { from: 11, to: 12, printed: "XI-XII. s." },
329
+ },
330
+ // Mass IV — Cunctipotens Genitor Deus
331
+ 4: {
332
+ ky: { from: 10, to: 10, printed: "X. s." },
333
+ gl: { from: 10, to: 10, printed: "X. s." },
334
+ sa: { from: 11, to: 11, printed: "XI. s." },
335
+ ag: { from: 13, to: 13, alt: 12, printed: "(XII) XIII. s." },
336
+ },
337
+ // Mass V — Kyrie magnæ Deus potentiæ
338
+ 5: {
339
+ ky: { from: 13, to: 13, printed: "XIII. s." },
340
+ gl: { from: 12, to: 12, printed: "XII. s." },
341
+ sa: { from: 12, to: 12, printed: "XII. s." },
342
+ ag: { from: 12, to: 12, printed: "XII. s." },
343
+ },
344
+ // Mass VI — Kyrie Rex Genitor
345
+ 6: {
346
+ ky: { from: 10, to: 10, printed: "X. s." },
347
+ gl: { from: 10, to: 10, printed: "X. s." },
348
+ sa: { from: 11, to: 11, printed: "XI. s." },
349
+ ag: { from: 11, to: 11, printed: "XI. s." },
350
+ },
351
+ // Mass VII — Kyrie Rex splendes
352
+ 7: {
353
+ ky: { from: 10, to: 10, printed: "X. s." },
354
+ gl: { from: 12, to: 12, printed: "XII. s." },
355
+ sa: { from: 11, to: 11, printed: "XI. s." },
356
+ ag: { from: 15, to: 15, printed: "XV. s." },
357
+ },
358
+ // Mass VIII — de Angelis
359
+ 8: {
360
+ ky: { from: 15, to: 16, printed: "XV-XVI. s." },
361
+ gl: { from: 16, to: 16, printed: "XVI. s." },
362
+ sa: { from: 12, to: 12, alt: 11, printed: "(XI) XII. s." },
363
+ ag: { from: 15, to: 15, printed: "XV. s." },
364
+ },
365
+ // Mass IX — Cum Jubilo
366
+ 9: {
367
+ ky: { from: 12, to: 12, printed: "XII. s." },
368
+ gl: { from: 11, to: 11, printed: "XI. s." },
369
+ sa: { from: 14, to: 14, printed: "XIV. s." },
370
+ ag: { from: 13, to: 13, alt: 10, printed: "(X) XIII. s." },
371
+ },
372
+ // Mass X — Alme Pater
373
+ 10: {
374
+ ky: { from: 11, to: 11, printed: "XI. s." },
375
+ gl: { from: 15, to: 15, printed: "XV. s." },
376
+ sa: { from: null, to: null, printed: "?. s." },
377
+ ag: { from: 12, to: 12, printed: "XII. s." },
378
+ },
379
+ // Mass XI — Orbis factor
380
+ 11: {
381
+ ky: { from: 14, to: 16, alt: 10, printed: "(X) XIV-XVI. s." },
382
+ gl: { from: 10, to: 10, printed: "X. s." },
383
+ sa: { from: 10, to: 10, printed: "X. s." },
384
+ ag: { from: 14, to: 14, printed: "XIV. s." },
385
+ },
386
+ // Mass XII — Pater cuncta
387
+ 12: {
388
+ ky: { from: 12, to: 12, printed: "XII. s." },
389
+ gl: { from: 12, to: 12, inferred: true, printed: "XII. s." },
390
+ sa: { from: 13, to: 13, printed: "XIII. s." },
391
+ ag: { from: 11, to: 11, printed: "XI. s." },
392
+ },
393
+ // Mass XIII — Stelliferi Conditor orbis
394
+ 13: {
395
+ ky: { from: 11, to: 11, printed: "XI. s." },
396
+ gl: { from: 12, to: 12, printed: "XII. s." },
397
+ sa: { from: 13, to: 13, printed: "XIII. s." },
398
+ ag: { from: null, to: null, printed: "? s." },
399
+ },
400
+ // Mass XIV — Jesu Redemptor
401
+ 14: {
402
+ ky: { from: 10, to: 10, inferred: true, printed: "X. s." },
403
+ gl: { from: 10, to: 10, printed: "X. s." },
404
+ sa: { from: 12, to: 12, inferred: true, printed: "XII. s." },
405
+ ag: { from: 13, to: 13, printed: "XIII. s." },
406
+ },
407
+ // Mass XV — Dominator Deus
408
+ 15: {
409
+ ky: { from: 11, to: 13, printed: "XI-XIII. s." },
410
+ gl: { from: 10, to: 10, printed: "X. s." },
411
+ sa: { from: 10, to: 10, printed: "X. s." },
412
+ ag: { from: 14, to: 14, alt: 12, printed: "(XII) XIV. s." },
413
+ },
414
+ // Mass XVI
415
+ 16: {
416
+ ky: { from: 11, to: 13, printed: "XI-XIII. s." },
417
+ sa: { from: 13, to: 13, printed: "XIII. s." },
418
+ ag: { from: 10, to: 11, printed: "X-XI. s." },
419
+ },
420
+ // Mass XVII
421
+ 17: {
422
+ ky: { from: 15, to: 17, alt: 10, printed: "(X) XV-XVII. s." },
423
+ sa: { from: 11, to: 11, printed: "XI. s." },
424
+ ag: { from: 13, to: 13, printed: "XIII. s." },
425
+ },
426
+ // Mass XVIII — Deus Genitor alme
427
+ 18: {
428
+ ky: { from: 11, to: 11, printed: "XI. s." },
429
+ sa: { from: 13, to: 13, printed: "XIII. s." },
430
+ ag: { from: 12, to: 12, printed: "XII. s." },
431
+ },
432
+ };
433
+ /** Credo number (roman, as the Kyriale names them) → its ascription. */
434
+ export const CREDO_CENTURY = {
435
+ I: { from: 11, to: 11, printed: "XI. s." },
436
+ II: { from: null, to: null, printed: "?. s." },
437
+ III: { from: 17, to: 17, printed: "XVII. s." },
438
+ IV: { from: 15, to: 15, printed: "XV. s." },
439
+ V: { from: 12, to: 12, printed: "XII. s." },
440
+ VI: { from: 11, to: 11, printed: "XI. s." },
441
+ };
442
+ // ── The Kyriale era rule ────────────────────────────────────────────────────
443
+ // A LATEST-CENTURY bound on ORDINARY settings, and nothing more. Scope matters
444
+ // here, so it is stated plainly rather than implied:
445
+ //
446
+ // This is NOT a corpus-wide era filter. tonus has per-chant EDITORIAL dates
447
+ // for the Kyriale and for nothing else — 71 of 2,860 shipped chants, 2.5%. A
448
+ // bound applied beyond that would be filtering 97.5% of the repertory on data
449
+ // that does not exist. The attestation filter learned this the hard way: at
450
+ // 69% coverage it answered "what was sung in 1098" by deleting the Night
451
+ // Office, because CANTUS had not yet dated the responsories, and it stayed
452
+ // retired until the coverage was closed (see chant/attest.ts). 2.5% is the
453
+ // stricter version of the same mistake.
454
+ //
455
+ // So the corpus's period is set by THE CUT — it ships what the liturgy places —
456
+ // and this rule only keeps the ordinary from reaching for a setting the
457
+ // Kyriale's own editors date to the Renaissance. Within its 2.5% the data is
458
+ // near-complete (66 of 72 mass parts printed) and per-part, which is what makes
459
+ // it safe to act on where CANTUS attestation was not.
460
+ //
461
+ // The cutoff: Docta Sanctorum Patrum, John XXII's bull at Avignon (1324),
462
+ // condemning the ars nova and insisting the plainchant melodies stay "intact
463
+ // and recognizable as such" — the liturgy's own line between the chant
464
+ // tradition and what followed. It lands on the seam already in the data:
465
+ // Kyriale parts by century run 10th 21 · 11th 17 · 12th 13 · 13th 8 · then
466
+ // 14th 2. A cliff, not a slope.
467
+ //
468
+ // There is deliberately NO lower bound. An earlier draft carried ERA_FROM=754
469
+ // (the Frankish adoption of the Roman rite), which read as doctrine but was
470
+ // unenforceable: nothing in the corpus is checked against it and no data could
471
+ // check it. A constant nothing enforces is a claim, not a rule.
472
+ export const ORDINARY_LATEST_YEAR = 1324;
473
+ /**
474
+ * The latest century a year admits WHOLE.
475
+ *
476
+ * The Kyriale dates a setting only to its century, so 1324 cannot admit "the
477
+ * 14th century" — a chant marked XIV. s. may have been written in 1390, well
478
+ * after the bull. A century is admitted only when it has CLOSED by the bound:
479
+ * 1324 → 13 (through the 1200s), 1300 → 13 (the century closes at its
480
+ * hundredth year). This is the same closed-century rule attest.ts applies to
481
+ * `before` — floor, not ceil, so an exact century year admits the century it
482
+ * ends. It is what keeps Mass IX's XIV-c Sanctus and Mass XI's XIV-c Agnus
483
+ * out, which is the whole point of choosing 1324.
484
+ */
485
+ function latestWholeCentury(year) {
486
+ return Math.floor(year / 100);
487
+ }
488
+ /**
489
+ * Whether a Kyriale setting is early enough to sing.
490
+ *
491
+ * PER PART, never per mass. The Kyriale is a 19th-c Solesmes GROUPING of chants
492
+ * from different centuries — which is why its ascriptions are per-part in the
493
+ * first place. Mass XI "Orbis factor" is a 10th-c Kyrie + 10th Gloria + 10th
494
+ * Sanctus with a 14th-c Agnus bolted on; a whole-mass test would lose the
495
+ * ordinary Sunday mass over one late part. The book licenses the per-part
496
+ * result outright — "chants from one Mass may be used together with those from
497
+ * others, the Ferial Masses excepted" — so a dropped part simply borrows, which
498
+ * is the machinery entriesForOffice() already runs.
499
+ *
500
+ * `alt` wins where the editors print one. Mass XI's Kyrie reads "(X) XIV-XVI.
501
+ * s." — the parenthetical is the melody, the late reading is whichever
502
+ * manuscript they transcribed. Modern scholarship agrees: Corpus Monodicum
503
+ * (Brill, 2024) dates Orbis factor to the 10th-12th c.
504
+ *
505
+ * An undated part (the editors' own "?. s.") is ADMITTED, not excluded —
506
+ * undated is not late, and excluding it would repeat the mistake that killed
507
+ * the attestation filter. Same for a part with no entry at all: this rule can
508
+ * only remove a setting the Kyriale itself dates late, never one it is silent
509
+ * about.
510
+ */
511
+ export function partWithinEra(mass, office, toYear = ORDINARY_LATEST_YEAR) {
512
+ if (mass == null || !office)
513
+ return true;
514
+ const entry = MASS_CENTURY[mass]?.[office];
515
+ if (!entry)
516
+ return true; // no printed century → admit
517
+ const century = entry.alt ?? entry.from;
518
+ if (century == null)
519
+ return true; // "?. s." → admit
520
+ return century <= latestWholeCentury(toYear);
521
+ }
297
522
  //# sourceMappingURL=masses.js.map
@@ -10,7 +10,7 @@
10
10
  //
11
11
  // Like compline.ts and masses.ts (its siblings here) this is a hand-authored table that
12
12
  // references chants already in the corpus by id; it carries no GABC of its own.
13
- // See docs/chant.md and BIBLIOGRAPHY.md.
13
+ // See ../../../../docs/api/chant.md and ../../../../BIBLIOGRAPHY.md.
14
14
  // Prime's psalmody (Ps 53 + a weekday-proper psalm + Ps 118 in two sections,
15
15
  // varying by weekday per DO's Tridentine scheme) is not hand-listed here — it
16
16
  // comes from the extracted scheme via `officePsalmPortions("Prima", weekday)`.