tonus 0.1.8 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/BIBLIOGRAPHY.md +138 -108
  2. package/CHANGELOG.md +664 -1
  3. package/LICENSE +133 -29
  4. package/README.md +107 -80
  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/data/zodiac.d.ts +47 -0
  83. package/dist/engines/harmonia/data/zodiac.js +163 -0
  84. package/dist/engines/harmonia/tabula.d.ts +3 -0
  85. package/dist/engines/harmonia/tabula.js +1 -0
  86. package/dist/engines/harmonia/voice.d.ts +4 -0
  87. package/dist/engines/harmonia/voice.js +8 -4
  88. package/dist/engines/imprint.js +14 -1
  89. package/dist/engines/planet/orbital.js +4 -4
  90. package/dist/engines/planet/planet.d.ts +10 -0
  91. package/dist/engines/planet/planet.js +30 -3
  92. package/dist/engines/planet/position.js +13 -10
  93. package/dist/engines/planet/types.d.ts +1 -0
  94. package/dist/engines/score/api.d.ts +2 -13
  95. package/dist/engines/score/api.js +21 -8
  96. package/dist/engines/score/articulation.js +2 -2
  97. package/dist/engines/score/cadence.d.ts +76 -0
  98. package/dist/engines/score/cadence.js +96 -0
  99. package/dist/engines/score/emitters/accidentals.d.ts +21 -0
  100. package/dist/engines/score/emitters/accidentals.js +88 -0
  101. package/dist/engines/score/emitters/atramentum.d.ts +107 -0
  102. package/dist/engines/score/emitters/atramentum.js +239 -0
  103. package/dist/engines/score/emitters/breaking.d.ts +62 -0
  104. package/dist/engines/score/emitters/breaking.js +80 -0
  105. package/dist/engines/score/emitters/moderna.d.ts +38 -0
  106. package/dist/engines/score/emitters/moderna.js +612 -0
  107. package/dist/engines/score/emitters/svg.d.ts +143 -0
  108. package/dist/engines/score/emitters/svg.js +1335 -0
  109. package/dist/engines/score/emitters/tracks.d.ts +104 -0
  110. package/dist/engines/score/emitters/tracks.js +728 -0
  111. package/dist/engines/score/infer.d.ts +3 -3
  112. package/dist/engines/score/infer.js +2 -2
  113. package/dist/engines/score/inscriptio.d.ts +69 -0
  114. package/dist/engines/score/inscriptio.js +138 -0
  115. package/dist/engines/score/ir.d.ts +2 -2
  116. package/dist/engines/score/ir.js +59 -12
  117. package/dist/engines/score/lyric.d.ts +23 -0
  118. package/dist/engines/score/lyric.js +234 -0
  119. package/dist/engines/score/meta.d.ts +2 -2
  120. package/dist/engines/score/modulation.d.ts +12 -0
  121. package/dist/engines/score/modulation.js +49 -0
  122. package/dist/engines/score/neume.js +35 -4
  123. package/dist/engines/score/parse.js +150 -9
  124. package/dist/engines/score/phrasing.js +4 -3
  125. package/dist/engines/score/prosody.d.ts +38 -0
  126. package/dist/engines/score/prosody.js +70 -6
  127. package/dist/engines/score/tabula.d.ts +37 -5
  128. package/dist/engines/score/tabula.js +18 -0
  129. package/dist/engines/score/types.d.ts +88 -1
  130. package/dist/engines/temper/api.d.ts +4 -1
  131. package/dist/engines/temper/api.js +28 -5
  132. package/dist/engines/temper/data/guido.js +6 -2
  133. package/dist/engines/temper/data/modes.d.ts +6 -0
  134. package/dist/engines/temper/data/modes.js +42 -0
  135. package/dist/engines/temper/data/tones.d.ts +1 -1
  136. package/dist/engines/temper/data/tones.js +20 -11
  137. package/dist/engines/temper/interval.js +4 -3
  138. package/dist/engines/temper/modality.d.ts +11 -2
  139. package/dist/engines/temper/modality.js +74 -2
  140. package/dist/engines/temper/modes.d.ts +1 -1
  141. package/dist/engines/temper/pitch.d.ts +1 -1
  142. package/dist/engines/temper/pitch.js +12 -2
  143. package/dist/engines/temper/scale.d.ts +53 -0
  144. package/dist/engines/temper/scale.js +107 -8
  145. package/dist/index.d.ts +26 -8
  146. package/dist/index.js +40 -4
  147. package/docs/api/calendar.md +279 -0
  148. package/docs/api/census.md +288 -0
  149. package/docs/api/chant.md +657 -0
  150. package/docs/api/heavens.md +396 -0
  151. package/docs/api/index.md +265 -0
  152. package/docs/api/score.md +906 -0
  153. package/docs/api/tuning.md +619 -0
  154. package/package.json +13 -5
  155. package/dist/data/office-matins-roman.d.ts +0 -19
  156. package/dist/data/office-matins-roman.js +0 -4383
  157. package/dist/data/office-psalms-roman.d.ts +0 -15
  158. package/dist/data/office-psalms-roman.js +0 -28
  159. package/dist/data/office-roman.d.ts +0 -19
  160. package/dist/data/office-roman.js +0 -13792
  161. package/dist/engines/chant/matutinum.d.ts +0 -33
  162. package/dist/engines/chant/matutinum.js +0 -81
  163. package/dist/engines/score/emitters/midi.d.ts +0 -65
  164. package/dist/engines/score/emitters/midi.js +0 -162
  165. package/dist/engines/score/emitters/musicxml.d.ts +0 -18
  166. package/dist/engines/score/emitters/musicxml.js +0 -166
@@ -0,0 +1,80 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/score/emitters/breaking — where a system ends, for both species
3
+ // ---------------------------------------------------------------------------
4
+ //
5
+ // The two emitters break lines at different granularities — quadrata at a
6
+ // divisio (and, since 2026-08-05, at a word), moderna between syllables — and
7
+ // they draw different line-end marks (quadrata a custos, moderna none). Those
8
+ // are real differences between the duae species, not accidents to unify.
9
+ //
10
+ // But the RULES governing a break are the same in both, and were written twice:
11
+ //
12
+ // - `z` forces a break, outranking any width test (the engraver's own)
13
+ // - `<nlba>` seals a seam and forbids one (the editor's own)
14
+ // - a seal yields when the sealed run cannot fit a line (the page wins)
15
+ // - the usable width reserves the line-end mark (never overrun it)
16
+ //
17
+ // Writing them twice is what shipped `<nlba>` working in quadrata and broken in
18
+ // moderna on 2026-08-05: the fix went into the emitter I happened to patch
19
+ // first, and only a sweep across both species caught it. This module is the
20
+ // mechanism; each emitter keeps its own policy and its own drawing.
21
+ //
22
+ // Nothing here measures or draws. The caller supplies measurements — which is
23
+ // what keeps tonus headless: the estimate lives in the emitter, the decision
24
+ // lives here, and neither needs a DOM.
25
+ const NO_BREAK = { break: false, reason: "none" };
26
+ /**
27
+ * Decide whether a system ends before `next`.
28
+ *
29
+ * The order is the precedence order, and it is the whole contract:
30
+ *
31
+ * 1. `z` — an instruction, not a preference. Nothing overrides it, including
32
+ * a seal: an editor who wrote both meant both, and the break is the more
33
+ * specific statement.
34
+ * 2. `<nlba>` — forbids a break, unless honouring it would push the sealed run
35
+ * off the page. A seal is a preference about where a line ends; staying
36
+ * inside the canvas is the stronger claim.
37
+ * 3. Width — the ordinary case.
38
+ */
39
+ export function decideBreak(q) {
40
+ if (q.next.lineBreak && !q.forcedHandled)
41
+ return { break: true, reason: "forced" };
42
+ if (q.next.keepWithPrev) {
43
+ const run = q.sealedRun ?? q.need;
44
+ // A run that cannot fit a line of its own has nowhere better to go, so the
45
+ // seal yields rather than running off the canvas. Otherwise the seal holds:
46
+ // the break belongs before the group, and the caller finds it there.
47
+ const fitsAnyLine = q.lineStart + run <= q.boundary;
48
+ if (fitsAnyLine)
49
+ return NO_BREAK;
50
+ }
51
+ // Past the boundary already — break regardless of what comes next. This must
52
+ // be tested on its own: a single figure wider than a whole line (a 36-note
53
+ // melisma at 420px) can never be rescued by breaking, but the line before it
54
+ // should still end rather than run on. Folding this into the `need` test
55
+ // below let such a syllable extend a line that was already full — measured,
56
+ // one Graduale render overran by 56px.
57
+ if (q.x > q.boundary)
58
+ return { break: true, reason: "width" };
59
+ return q.x + q.need > q.boundary
60
+ ? { break: true, reason: "width" }
61
+ : NO_BREAK;
62
+ }
63
+ /**
64
+ * Width of the sealed run beginning at `from`, by the caller's own measure.
65
+ *
66
+ * The head of a sealed group must be tested against the WHOLE group: admit the
67
+ * head alone and every seam after it is sealed, so the line can no longer break
68
+ * and the overflow is unrecoverable. Measured across the 35 Graduale chants that
69
+ * carry `<nlba>`, measuring one syllable instead of the run broke 37 seams.
70
+ */
71
+ export function sealedRunWidth(rows, from, widthOf) {
72
+ let total = widthOf(from);
73
+ for (let i = from + 1; i < rows.length; i++) {
74
+ if (!rows[i].keepWithPrev)
75
+ break;
76
+ total += widthOf(i);
77
+ }
78
+ return total;
79
+ }
80
+ //# sourceMappingURL=breaking.js.map
@@ -0,0 +1,38 @@
1
+ import type { SvgResult, SvgOpts } from "./svg.js";
2
+ import type { ChantTabulaRow } from "../tabula.js";
3
+ import type { Chant } from "../../chant/types.js";
4
+ /** Every geometric constant, derived from the requested staff height. */
5
+ export interface ModernaMetrics {
6
+ /** Staff space — the distance between two lines. */
7
+ MSP: number;
8
+ /** SMuFL glyph scale: 1 em = 4 staff spaces. */
9
+ SCALE: number;
10
+ /** Top staff line, system-local. */
11
+ MTOP: number;
12
+ /** noteheadBlack advance. */
13
+ NH_W: number;
14
+ /** Per-note advance inside a melisma. */
15
+ ADV: number;
16
+ /** Gap after each syllable. */
17
+ SYL_GAP: number;
18
+ /** Lyric baseline, system-local. */
19
+ LYRIC_Y: number;
20
+ /** The factor against the engraved metrics — 1 at the default. */
21
+ k: number;
22
+ }
23
+ /**
24
+ * Moderna's metrics for a requested staff height.
25
+ *
26
+ * Everything scales together, so the engraving's internal relationships —
27
+ * notehead to staff, slur to notehead, lyric to baseline — hold at any size;
28
+ * they were drawn as a set and stay one.
29
+ */
30
+ export declare function metrics(staffHeight?: number): ModernaMetrics;
31
+ type Row = ChantTabulaRow;
32
+ /**
33
+ * Render the tabula as moderna. Multi-system when `width` is set; single system
34
+ * otherwise. Returns the shared { svg, geometry } contract.
35
+ */
36
+ export declare function toModerna(rows: Row[], chant: Chant, options?: SvgOpts): SvgResult;
37
+ export {};
38
+ //# sourceMappingURL=moderna.d.ts.map