tonus 0.1.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 (141) hide show
  1. package/BIBLIOGRAPHY.md +99 -0
  2. package/LICENSE +29 -0
  3. package/README.md +108 -0
  4. package/dist/data/cal.d.ts +10 -0
  5. package/dist/data/cal.js +3862 -0
  6. package/dist/data/commune.d.ts +17 -0
  7. package/dist/data/commune.js +1333 -0
  8. package/dist/data/gr.d.ts +5 -0
  9. package/dist/data/gr.js +13449 -0
  10. package/dist/data/kyriale.d.ts +11 -0
  11. package/dist/data/kyriale.js +971 -0
  12. package/dist/data/la.d.ts +5 -0
  13. package/dist/data/la.js +14229 -0
  14. package/dist/data/lh.d.ts +5 -0
  15. package/dist/data/lh.js +3619 -0
  16. package/dist/data/lu.d.ts +5 -0
  17. package/dist/data/lu.js +23779 -0
  18. package/dist/data/masses.d.ts +18 -0
  19. package/dist/data/masses.js +297 -0
  20. package/dist/data/office-roman.d.ts +19 -0
  21. package/dist/data/office-roman.js +13792 -0
  22. package/dist/data/office.d.ts +12 -0
  23. package/dist/data/office.js +13052 -0
  24. package/dist/data/propers.d.ts +13 -0
  25. package/dist/data/propers.js +7584 -0
  26. package/dist/data/psalms.d.ts +4 -0
  27. package/dist/data/psalms.js +10 -0
  28. package/dist/data/psalms.json +22918 -0
  29. package/dist/data/tones.d.ts +20 -0
  30. package/dist/data/tones.js +153 -0
  31. package/dist/data/types.d.ts +3 -0
  32. package/dist/data/types.js +2 -0
  33. package/dist/engines/cal/calendar.d.ts +21 -0
  34. package/dist/engines/cal/calendar.js +265 -0
  35. package/dist/engines/cal/date.d.ts +31 -0
  36. package/dist/engines/cal/date.js +141 -0
  37. package/dist/engines/cal/types.d.ts +66 -0
  38. package/dist/engines/cal/types.js +189 -0
  39. package/dist/engines/chant/chant.d.ts +10 -0
  40. package/dist/engines/chant/chant.js +135 -0
  41. package/dist/engines/chant/hour.d.ts +8 -0
  42. package/dist/engines/chant/hour.js +135 -0
  43. package/dist/engines/chant/intone.d.ts +8 -0
  44. package/dist/engines/chant/intone.js +84 -0
  45. package/dist/engines/chant/ordinary.d.ts +7 -0
  46. package/dist/engines/chant/ordinary.js +232 -0
  47. package/dist/engines/chant/propers.d.ts +8 -0
  48. package/dist/engines/chant/propers.js +107 -0
  49. package/dist/engines/chant/psalm.d.ts +7 -0
  50. package/dist/engines/chant/psalm.js +60 -0
  51. package/dist/engines/chant/syllabify.d.ts +20 -0
  52. package/dist/engines/chant/syllabify.js +192 -0
  53. package/dist/engines/chant/types.d.ts +76 -0
  54. package/dist/engines/chant/types.js +34 -0
  55. package/dist/engines/epoch.d.ts +2 -0
  56. package/dist/engines/epoch.js +14 -0
  57. package/dist/engines/harmonia/api.d.ts +35 -0
  58. package/dist/engines/harmonia/api.js +90 -0
  59. package/dist/engines/harmonia/aspects.d.ts +8 -0
  60. package/dist/engines/harmonia/aspects.js +15 -0
  61. package/dist/engines/harmonia/data/doctrines.d.ts +16 -0
  62. package/dist/engines/harmonia/data/doctrines.js +154 -0
  63. package/dist/engines/harmonia/data/vowels.d.ts +10 -0
  64. package/dist/engines/harmonia/data/vowels.js +21 -0
  65. package/dist/engines/harmonia/presence.d.ts +13 -0
  66. package/dist/engines/harmonia/presence.js +48 -0
  67. package/dist/engines/harmonia/tabula.d.ts +28 -0
  68. package/dist/engines/harmonia/tabula.js +32 -0
  69. package/dist/engines/harmonia/voice.d.ts +19 -0
  70. package/dist/engines/harmonia/voice.js +51 -0
  71. package/dist/engines/imprint.d.ts +30 -0
  72. package/dist/engines/imprint.js +152 -0
  73. package/dist/engines/planet/appearance.d.ts +40 -0
  74. package/dist/engines/planet/appearance.js +84 -0
  75. package/dist/engines/planet/aspects.d.ts +5 -0
  76. package/dist/engines/planet/aspects.js +41 -0
  77. package/dist/engines/planet/math.d.ts +13 -0
  78. package/dist/engines/planet/math.js +56 -0
  79. package/dist/engines/planet/orbital.d.ts +25 -0
  80. package/dist/engines/planet/orbital.js +223 -0
  81. package/dist/engines/planet/planet.d.ts +13 -0
  82. package/dist/engines/planet/planet.js +198 -0
  83. package/dist/engines/planet/position.d.ts +62 -0
  84. package/dist/engines/planet/position.js +156 -0
  85. package/dist/engines/planet/types.d.ts +61 -0
  86. package/dist/engines/planet/types.js +14 -0
  87. package/dist/engines/score/api.d.ts +54 -0
  88. package/dist/engines/score/api.js +87 -0
  89. package/dist/engines/score/articulation.d.ts +6 -0
  90. package/dist/engines/score/articulation.js +112 -0
  91. package/dist/engines/score/emitters/midi.d.ts +65 -0
  92. package/dist/engines/score/emitters/midi.js +158 -0
  93. package/dist/engines/score/emitters/musicxml.d.ts +18 -0
  94. package/dist/engines/score/emitters/musicxml.js +166 -0
  95. package/dist/engines/score/infer.d.ts +4 -0
  96. package/dist/engines/score/infer.js +77 -0
  97. package/dist/engines/score/ir.d.ts +4 -0
  98. package/dist/engines/score/ir.js +177 -0
  99. package/dist/engines/score/meta.d.ts +19 -0
  100. package/dist/engines/score/meta.js +34 -0
  101. package/dist/engines/score/neume.d.ts +3 -0
  102. package/dist/engines/score/neume.js +26 -0
  103. package/dist/engines/score/parse.d.ts +3 -0
  104. package/dist/engines/score/parse.js +359 -0
  105. package/dist/engines/score/phrasing.d.ts +24 -0
  106. package/dist/engines/score/phrasing.js +257 -0
  107. package/dist/engines/score/prosody.d.ts +35 -0
  108. package/dist/engines/score/prosody.js +109 -0
  109. package/dist/engines/score/tabula.d.ts +70 -0
  110. package/dist/engines/score/tabula.js +109 -0
  111. package/dist/engines/score/types.d.ts +159 -0
  112. package/dist/engines/score/types.js +2 -0
  113. package/dist/engines/temper/api.d.ts +60 -0
  114. package/dist/engines/temper/api.js +130 -0
  115. package/dist/engines/temper/data/constants.d.ts +27 -0
  116. package/dist/engines/temper/data/constants.js +150 -0
  117. package/dist/engines/temper/data/guido.d.ts +14 -0
  118. package/dist/engines/temper/data/guido.js +29 -0
  119. package/dist/engines/temper/data/modes.d.ts +38 -0
  120. package/dist/engines/temper/data/modes.js +158 -0
  121. package/dist/engines/temper/gabc.d.ts +5 -0
  122. package/dist/engines/temper/gabc.js +53 -0
  123. package/dist/engines/temper/gamut.d.ts +9 -0
  124. package/dist/engines/temper/gamut.js +24 -0
  125. package/dist/engines/temper/guido.d.ts +16 -0
  126. package/dist/engines/temper/guido.js +48 -0
  127. package/dist/engines/temper/interval.d.ts +15 -0
  128. package/dist/engines/temper/interval.js +31 -0
  129. package/dist/engines/temper/modes.d.ts +6 -0
  130. package/dist/engines/temper/modes.js +13 -0
  131. package/dist/engines/temper/neume.d.ts +14 -0
  132. package/dist/engines/temper/neume.js +59 -0
  133. package/dist/engines/temper/pitch.d.ts +40 -0
  134. package/dist/engines/temper/pitch.js +129 -0
  135. package/dist/engines/temper/scale.d.ts +37 -0
  136. package/dist/engines/temper/scale.js +217 -0
  137. package/dist/engines/temper/step.d.ts +23 -0
  138. package/dist/engines/temper/step.js +53 -0
  139. package/dist/index.d.ts +40 -0
  140. package/dist/index.js +27 -0
  141. package/package.json +60 -0
@@ -0,0 +1,150 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/data/constants — pitch-class vocabulary, solfège, intervals
3
+ // ---------------------------------------------------------------------------
4
+ /** 12 pitch-class names, index = pitch class 0–11. Sharp-biased except Eb/Ab/Bb. */
5
+ export const PITCH_CLASS = [
6
+ "C",
7
+ "C#",
8
+ "D",
9
+ "Eb",
10
+ "E",
11
+ "F",
12
+ "F#",
13
+ "G",
14
+ "Ab",
15
+ "A",
16
+ "Bb",
17
+ "B",
18
+ ];
19
+ /** Diatonic step letters in ascending order. */
20
+ export const DIATONIC_STEPS = ["C", "D", "E", "F", "G", "A", "B"];
21
+ /** Map any note name (including enharmonics) to its pitch class 0–11. */
22
+ export const NAME_TO_CHROMA = new Map([
23
+ ["C", 0],
24
+ ["B#", 0],
25
+ ["C#", 1],
26
+ ["Db", 1],
27
+ ["D", 2],
28
+ ["D#", 3],
29
+ ["Eb", 3],
30
+ ["E", 4],
31
+ ["Fb", 4],
32
+ ["E#", 5],
33
+ ["F", 5],
34
+ ["F#", 6],
35
+ ["Gb", 6],
36
+ ["G", 7],
37
+ ["G#", 8],
38
+ ["Ab", 8],
39
+ ["A", 9],
40
+ ["A#", 10],
41
+ ["Bb", 10],
42
+ ["B", 11],
43
+ ["Cb", 11],
44
+ ]);
45
+ // Modern fixed-do solfège → pitch class (input only; UT = C always)
46
+ export const SOLFEGE_TO_CHROMA = new Map([
47
+ ["UT", 0],
48
+ ["DO", 0],
49
+ ["RE", 2],
50
+ ["MI", 4],
51
+ ["FA", 5],
52
+ ["SOL", 7],
53
+ ["SO", 7],
54
+ ["LA", 9],
55
+ ["TE", 10],
56
+ ["TI", 11],
57
+ ["SI", 11],
58
+ ]);
59
+ // Diatonic pitch class → Guidonian solfège name (UT system, medieval 6-syllable)
60
+ // pc 10 (Bb) = FA in molle hexachord; pc 11 (B) = MI in durum hexachord
61
+ // Chromatic pcs have no canonical name — use lookupGuido() for context-aware solmization
62
+ export const CHROMA_TO_SOLFEGE = new Map([
63
+ [0, "UT"],
64
+ [2, "RE"],
65
+ [4, "MI"],
66
+ [5, "FA"],
67
+ [7, "SOL"],
68
+ [9, "LA"],
69
+ [10, "FA"], // Bb — b-molle
70
+ [11, "MI"], // B — b-durum
71
+ ]);
72
+ // Entries indexed by semitone count 0–11.
73
+ // semitone=0: use UNISONUS when abs=0, this entry when abs=12 (octave).
74
+ export const INTERVAL = [
75
+ {
76
+ latin: "Octava",
77
+ alias: "Diapason",
78
+ degree: 8,
79
+ quality: "perfect",
80
+ class: "P8",
81
+ },
82
+ { latin: "Semitonium", degree: 2, quality: "minor", class: "m2" },
83
+ { latin: "Tonus", degree: 2, quality: "major", class: "M2" },
84
+ { latin: "Tertia minor", degree: 3, quality: "minor", class: "m3" },
85
+ { latin: "Tertia maior", degree: 3, quality: "major", class: "M3" },
86
+ {
87
+ latin: "Quarta",
88
+ alias: "Diatessaron",
89
+ degree: 4,
90
+ quality: "perfect",
91
+ class: "P4",
92
+ },
93
+ { latin: "Tritonus", degree: 4, quality: "augmented", class: "TT" },
94
+ {
95
+ latin: "Quinta",
96
+ alias: "Diapente",
97
+ degree: 5,
98
+ quality: "perfect",
99
+ class: "P5",
100
+ },
101
+ { latin: "Sexta minor", degree: 6, quality: "minor", class: "m6" },
102
+ { latin: "Sexta maior", degree: 6, quality: "major", class: "M6" },
103
+ { latin: "Septima minor", degree: 7, quality: "minor", class: "m7" },
104
+ { latin: "Septima maior", degree: 7, quality: "major", class: "M7" },
105
+ ];
106
+ export const UNISONUS = {
107
+ latin: "Unisonus",
108
+ degree: 1,
109
+ quality: "perfect",
110
+ class: "P1",
111
+ };
112
+ // prettier-ignore
113
+ export const SHARP_SPELLING = [
114
+ { step: "C", acc: 0 }, // 0
115
+ { step: "C", acc: 1 }, // 1
116
+ { step: "D", acc: 0 }, // 2
117
+ { step: "D", acc: 1 }, // 3
118
+ { step: "E", acc: 0 }, // 4
119
+ { step: "F", acc: 0 }, // 5
120
+ { step: "F", acc: 1 }, // 6
121
+ { step: "G", acc: 0 }, // 7
122
+ { step: "G", acc: 1 }, // 8
123
+ { step: "A", acc: 0 }, // 9
124
+ { step: "A", acc: 1 }, // 10
125
+ { step: "B", acc: 0 }, // 11
126
+ ];
127
+ // prettier-ignore
128
+ export const FLAT_SPELLING = [
129
+ { step: "C", acc: 0 }, // 0
130
+ { step: "D", acc: -1 }, // 1
131
+ { step: "D", acc: 0 }, // 2
132
+ { step: "E", acc: -1 }, // 3
133
+ { step: "E", acc: 0 }, // 4
134
+ { step: "F", acc: 0 }, // 5
135
+ { step: "G", acc: -1 }, // 6
136
+ { step: "G", acc: 0 }, // 7
137
+ { step: "A", acc: -1 }, // 8
138
+ { step: "A", acc: 0 }, // 9
139
+ { step: "B", acc: -1 }, // 10
140
+ { step: "B", acc: 0 }, // 11
141
+ ];
142
+ // Prefer flat spelling for Bb, Eb, Ab
143
+ export const PREFER_FLAT_PCS = new Set([3, 8, 10]);
144
+ // Guidonian solmization syllable → pitch class, by hexachord
145
+ export const GUIDO_TO_PC = {
146
+ durum: { UT: 7, RE: 9, MI: 11, FA: 0, SOL: 2, LA: 4 },
147
+ naturale: { UT: 0, RE: 2, MI: 4, FA: 5, SOL: 7, LA: 9 },
148
+ molle: { UT: 5, RE: 7, MI: 9, FA: 10, SOL: 0, LA: 2 },
149
+ };
150
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,14 @@
1
+ export interface GuidonianVariant {
2
+ hexachord: "durum" | "naturale" | "molle";
3
+ solmization: "UT" | "RE" | "MI" | "FA" | "SOL" | "LA";
4
+ }
5
+ export interface GuidonianEntry {
6
+ hand: {
7
+ finger: string;
8
+ region: string;
9
+ };
10
+ name: [string, string];
11
+ variants: GuidonianVariant[];
12
+ }
13
+ export declare const GUIDONIAN_DATA: Map<number, GuidonianEntry>;
14
+ //# sourceMappingURL=guido.d.ts.map
@@ -0,0 +1,29 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/data/guido — Guidonian gamut and hexachord variants
3
+ // ---------------------------------------------------------------------------
4
+ // prettier-ignore
5
+ export const GUIDONIAN_DATA = new Map([
6
+ [43, { hand: { finger: "base", region: "palm" }, name: ["Γ", "Gammaut"], variants: [{ hexachord: "durum", solmization: "UT" }] }],
7
+ [45, { hand: { finger: "wrist", region: "center" }, name: ["A", "Are"], variants: [{ hexachord: "durum", solmization: "RE" }] }],
8
+ [47, { hand: { finger: "wrist", region: "inner" }, name: ["B", "Bemi"], variants: [{ hexachord: "durum", solmization: "MI" }] }],
9
+ [48, { hand: { finger: "palm", region: "base" }, name: ["C", "Cefaut"], variants: [{ hexachord: "durum", solmization: "FA" }, { hexachord: "naturale", solmization: "UT" }] }],
10
+ [50, { hand: { finger: "palm", region: "middle" }, name: ["D", "Desolre"], variants: [{ hexachord: "durum", solmization: "SOL" }, { hexachord: "naturale", solmization: "RE" }] }],
11
+ [52, { hand: { finger: "palm", region: "top" }, name: ["E", "Elami"], variants: [{ hexachord: "durum", solmization: "LA" }, { hexachord: "naturale", solmization: "MI" }] }],
12
+ [53, { hand: { finger: "thumb", region: "base" }, name: ["F", "Fefaut"], variants: [{ hexachord: "naturale", solmization: "FA" }, { hexachord: "molle", solmization: "UT" }] }],
13
+ [55, { hand: { finger: "thumb", region: "mid" }, name: ["G", "Gesolreut"], variants: [{ hexachord: "durum", solmization: "UT" }, { hexachord: "naturale", solmization: "SOL" }, { hexachord: "molle", solmization: "RE" }] }],
14
+ [57, { hand: { finger: "thumb", region: "tip" }, name: ["a", "Alamire"], variants: [{ hexachord: "durum", solmization: "RE" }, { hexachord: "naturale", solmization: "LA" }, { hexachord: "molle", solmization: "MI" }] }],
15
+ [58, { hand: { finger: "index", region: "base" }, name: ["b", "Befa"], variants: [{ hexachord: "molle", solmization: "FA" }] }],
16
+ [59, { hand: { finger: "index", region: "mid" }, name: ["♮", "Bemi"], variants: [{ hexachord: "durum", solmization: "MI" }] }],
17
+ [60, { hand: { finger: "index", region: "tip" }, name: ["c", "Cesolfaut"], variants: [{ hexachord: "durum", solmization: "FA" }, { hexachord: "naturale", solmization: "UT" }, { hexachord: "molle", solmization: "SOL" }] }],
18
+ [62, { hand: { finger: "middle", region: "base" }, name: ["d", "Delasolre"], variants: [{ hexachord: "durum", solmization: "SOL" }, { hexachord: "naturale", solmization: "RE" }, { hexachord: "molle", solmization: "LA" }] }],
19
+ [64, { hand: { finger: "middle", region: "mid" }, name: ["e", "Elami"], variants: [{ hexachord: "durum", solmization: "LA" }, { hexachord: "naturale", solmization: "MI" }] }],
20
+ [65, { hand: { finger: "middle", region: "tip" }, name: ["f", "Fefaut"], variants: [{ hexachord: "naturale", solmization: "FA" }, { hexachord: "molle", solmization: "UT" }] }],
21
+ [67, { hand: { finger: "ring", region: "base" }, name: ["g", "Gesolreut"], variants: [{ hexachord: "durum", solmization: "UT" }, { hexachord: "naturale", solmization: "SOL" }, { hexachord: "molle", solmization: "RE" }] }],
22
+ [69, { hand: { finger: "ring", region: "mid" }, name: ["aa", "Alamire"], variants: [{ hexachord: "durum", solmization: "RE" }, { hexachord: "naturale", solmization: "LA" }, { hexachord: "molle", solmization: "MI" }] }],
23
+ [70, { hand: { finger: "ring", region: "tip" }, name: ["bb", "Befa"], variants: [{ hexachord: "molle", solmization: "FA" }] }],
24
+ [71, { hand: { finger: "pinky", region: "base" }, name: ["♮♮", "Bemi"], variants: [{ hexachord: "durum", solmization: "MI" }] }],
25
+ [72, { hand: { finger: "pinky", region: "mid" }, name: ["cc", "Cesolfa"], variants: [{ hexachord: "durum", solmization: "FA" }, { hexachord: "naturale", solmization: "UT" }, { hexachord: "molle", solmization: "SOL" }] }],
26
+ [74, { hand: { finger: "pinky", region: "top" }, name: ["dd", "Delasol"], variants: [{ hexachord: "durum", solmization: "SOL" }, { hexachord: "naturale", solmization: "RE" }, { hexachord: "molle", solmization: "LA" }] }],
27
+ [76, { hand: { finger: "pinky", region: "tip" }, name: ["ee", "Ela"], variants: [{ hexachord: "durum", solmization: "LA" }, { hexachord: "naturale", solmization: "MI" }] }],
28
+ ]);
29
+ //# sourceMappingURL=guido.js.map
@@ -0,0 +1,38 @@
1
+ export interface ModeProfile {
2
+ mood: string;
3
+ phrasing: "recitative" | "lyrical" | "hymnic" | "solemn";
4
+ melodic: "rising" | "falling" | "arch" | "neutral";
5
+ tendency: "melismatic" | "neumatic" | "syllabic" | "neutral";
6
+ }
7
+ export interface ModeData {
8
+ mode: number;
9
+ nomen: string;
10
+ alias: string;
11
+ maneria: string;
12
+ type: "authentic" | "plagal";
13
+ final: number;
14
+ tenor: number;
15
+ scalePcs: number[];
16
+ hexachords: ("durum" | "naturale" | "molle")[];
17
+ profile: ModeProfile;
18
+ cadences: {
19
+ final: number[];
20
+ tenor: number[];
21
+ };
22
+ modulations: {
23
+ regular: number[];
24
+ conceded: number[];
25
+ initials: number[];
26
+ };
27
+ ambitus: {
28
+ lowest: number;
29
+ highest: number;
30
+ span: number;
31
+ };
32
+ species: {
33
+ fifth: [number, number];
34
+ fourth: [number, number];
35
+ };
36
+ }
37
+ export declare const MODES: Map<number, ModeData>;
38
+ //# sourceMappingURL=modes.d.ts.map
@@ -0,0 +1,158 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/data/modes — eight Gregorian modes (I–VIII)
3
+ // ---------------------------------------------------------------------------
4
+ export const MODES = new Map([
5
+ [
6
+ 1,
7
+ {
8
+ mode: 1,
9
+ nomen: "Protus Authenticus",
10
+ alias: "dorian",
11
+ maneria: "Protus",
12
+ type: "authentic",
13
+ final: 2,
14
+ tenor: 9,
15
+ scalePcs: [2, 4, 5, 7, 9, 11, 0],
16
+ hexachords: ["naturale"],
17
+ profile: { mood: "serious", phrasing: "lyrical", melodic: "falling", tendency: "melismatic" },
18
+ cadences: { final: [5, 4, 2], tenor: [9, 2] },
19
+ modulations: { regular: [2, 9, 5, 7], conceded: [12, 4], initials: [2, 5, 7, 9, 14] },
20
+ ambitus: { lowest: 2, highest: 21, span: 19 },
21
+ species: { fifth: [2, 9], fourth: [9, 2] },
22
+ },
23
+ ],
24
+ [
25
+ 2,
26
+ {
27
+ mode: 2,
28
+ nomen: "Protus Plagalis",
29
+ alias: "hypodorian",
30
+ maneria: "Protus",
31
+ type: "plagal",
32
+ final: 2,
33
+ tenor: 5,
34
+ scalePcs: [2, 4, 5, 7, 9, 11, 0],
35
+ hexachords: ["naturale"],
36
+ profile: { mood: "sad", phrasing: "lyrical", melodic: "arch", tendency: "neumatic" },
37
+ cadences: { final: [8, 7, 5], tenor: [0, 5] },
38
+ modulations: { regular: [2, 5, 7, 9], conceded: [0, 4], initials: [0, 2, 4, 5, 7, 9] },
39
+ ambitus: { lowest: 0, highest: 17, span: 17 },
40
+ species: { fifth: [2, 9], fourth: [9, 2] },
41
+ },
42
+ ],
43
+ [
44
+ 3,
45
+ {
46
+ mode: 3,
47
+ nomen: "Deuterus Authenticus",
48
+ alias: "phrygian",
49
+ maneria: "Deuterus",
50
+ type: "authentic",
51
+ final: 4,
52
+ tenor: 0,
53
+ scalePcs: [4, 5, 7, 9, 11, 0, 2],
54
+ hexachords: ["naturale"],
55
+ profile: { mood: "mystic", phrasing: "solemn", melodic: "falling", tendency: "melismatic" },
56
+ cadences: { final: [7, 6, 4], tenor: [0, 4] },
57
+ modulations: { regular: [4, 0, 7, 9], conceded: [5, 11], initials: [0, 2, 4, 7, 9] },
58
+ ambitus: { lowest: 4, highest: 16, span: 12 },
59
+ species: { fifth: [4, 11], fourth: [11, 4] },
60
+ },
61
+ ],
62
+ [
63
+ 4,
64
+ {
65
+ mode: 4,
66
+ nomen: "Deuterus Plagalis",
67
+ alias: "hypophrygian",
68
+ maneria: "Deuterus",
69
+ type: "plagal",
70
+ final: 4,
71
+ tenor: 9,
72
+ scalePcs: [4, 5, 7, 9, 11, 0, 2],
73
+ hexachords: ["naturale"],
74
+ profile: { mood: "harmonious", phrasing: "lyrical", melodic: "arch", tendency: "neumatic" },
75
+ cadences: { final: [7, 6, 4], tenor: [9, 4] },
76
+ modulations: { regular: [4, 9, 7, 0], conceded: [11], initials: [0, 4, 7, 9] },
77
+ ambitus: { lowest: 2, highest: 21, span: 19 },
78
+ species: { fifth: [4, 11], fourth: [11, 4] },
79
+ },
80
+ ],
81
+ [
82
+ 5,
83
+ {
84
+ mode: 5,
85
+ nomen: "Tritus Authenticus",
86
+ alias: "lydian",
87
+ maneria: "Tritus",
88
+ type: "authentic",
89
+ final: 5,
90
+ tenor: 0,
91
+ scalePcs: [5, 7, 9, 11, 0, 2, 4],
92
+ hexachords: ["molle"],
93
+ profile: { mood: "happy", phrasing: "solemn", melodic: "rising", tendency: "melismatic" },
94
+ cadences: { final: [8, 7, 5], tenor: [0, 5] },
95
+ modulations: { regular: [5, 0, 7, 12], conceded: [9, 2], initials: [5, 7, 9, 0, 12] },
96
+ ambitus: { lowest: 5, highest: 17, span: 12 },
97
+ species: { fifth: [5, 0], fourth: [0, 5] },
98
+ },
99
+ ],
100
+ [
101
+ 6,
102
+ {
103
+ mode: 6,
104
+ nomen: "Tritus Plagalis",
105
+ alias: "hypolydian",
106
+ maneria: "Tritus",
107
+ type: "plagal",
108
+ final: 5,
109
+ tenor: 9,
110
+ scalePcs: [5, 7, 9, 11, 0, 2, 4],
111
+ hexachords: ["molle"],
112
+ profile: { mood: "devout", phrasing: "lyrical", melodic: "arch", tendency: "neumatic" },
113
+ cadences: { final: [8, 7, 5], tenor: [9, 5] },
114
+ modulations: { regular: [5, 9, 0, 7], conceded: [2, 12], initials: [0, 2, 4, 5, 7, 9] },
115
+ ambitus: { lowest: 3, highest: 21, span: 18 },
116
+ species: { fifth: [5, 0], fourth: [0, 5] },
117
+ },
118
+ ],
119
+ [
120
+ 7,
121
+ {
122
+ mode: 7,
123
+ nomen: "Tetrardus Authenticus",
124
+ alias: "mixolydian",
125
+ maneria: "Tetrardus",
126
+ type: "authentic",
127
+ final: 7,
128
+ tenor: 2,
129
+ scalePcs: [7, 9, 11, 0, 2, 4, 5],
130
+ hexachords: ["durum"],
131
+ profile: { mood: "angelical", phrasing: "solemn", melodic: "rising", tendency: "melismatic" },
132
+ cadences: { final: [10, 9, 7], tenor: [2, 7] },
133
+ modulations: { regular: [7, 2, 9, 14], conceded: [5, 0], initials: [7, 9, 11, 2, 14] },
134
+ ambitus: { lowest: 7, highest: 19, span: 12 },
135
+ species: { fifth: [7, 2], fourth: [2, 7] },
136
+ },
137
+ ],
138
+ [
139
+ 8,
140
+ {
141
+ mode: 8,
142
+ nomen: "Tetrardus Plagalis",
143
+ alias: "hypomixolydian",
144
+ maneria: "Tetrardus",
145
+ type: "plagal",
146
+ final: 7,
147
+ tenor: 0,
148
+ scalePcs: [7, 9, 11, 0, 2, 4, 5],
149
+ hexachords: ["durum"],
150
+ profile: { mood: "perfect", phrasing: "lyrical", melodic: "arch", tendency: "neumatic" },
151
+ cadences: { final: [10, 9, 7], tenor: [0, 7] },
152
+ modulations: { regular: [7, 0, 9, 14], conceded: [2, 5], initials: [0, 2, 4, 7, 9, 12, 14] },
153
+ ambitus: { lowest: 5, highest: 19, span: 14 },
154
+ species: { fifth: [7, 2], fourth: [2, 7] },
155
+ },
156
+ ],
157
+ ]);
158
+ //# sourceMappingURL=modes.js.map
@@ -0,0 +1,5 @@
1
+ export declare function midiToGabc(midi: number, clef?: string): string;
2
+ export declare function gabcToMidi(letter: string, clef?: string): number;
3
+ export declare function pcToGabc(pc: number, clef?: string, oct?: number): string;
4
+ export declare function gabcToPc(letter: string, clef?: string): number;
5
+ //# sourceMappingURL=gabc.d.ts.map
@@ -0,0 +1,53 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/gabc — GABC pitch letter utilities
3
+ // ---------------------------------------------------------------------------
4
+ const DIATONIC = [0, 2, 4, 5, 7, 9, 11];
5
+ const LETTERS = "abcdefghijklm";
6
+ const CLEFS = {
7
+ c1: { doMidi: 60, doIdx: 3 },
8
+ c2: { doMidi: 60, doIdx: 5 },
9
+ c3: { doMidi: 60, doIdx: 7 },
10
+ c4: { doMidi: 60, doIdx: 9 },
11
+ f3: { doMidi: 53, doIdx: 5 },
12
+ f4: { doMidi: 53, doIdx: 3 },
13
+ };
14
+ export function midiToGabc(midi, clef = "c4") {
15
+ const def = CLEFS[clef];
16
+ if (!def)
17
+ throw new Error(`Unknown clef: ${clef}`);
18
+ const octave = Math.floor(midi / 12) - 1;
19
+ const pc = midi % 12;
20
+ const diatIdx = DIATONIC.indexOf(pc);
21
+ if (diatIdx === -1)
22
+ throw new Error(`MIDI note ${midi} (pc ${pc}) is not diatonic`);
23
+ const doOctave = Math.floor(def.doMidi / 12) - 1;
24
+ const staffPos = def.doIdx + diatIdx + (octave - doOctave) * 7;
25
+ const letter = LETTERS[staffPos];
26
+ if (!letter)
27
+ throw new Error(`MIDI ${midi} out of GABC range for clef ${clef}`);
28
+ return letter;
29
+ }
30
+ export function gabcToMidi(letter, clef = "c4") {
31
+ const def = CLEFS[clef];
32
+ if (!def)
33
+ throw new Error(`Unknown clef: ${clef}`);
34
+ const staffPos = LETTERS.indexOf(letter.toLowerCase());
35
+ if (staffPos === -1)
36
+ throw new Error(`Unknown GABC letter: ${letter}`);
37
+ const stepsFromDo = staffPos - def.doIdx;
38
+ const octOffset = Math.floor(stepsFromDo / 7);
39
+ const diatStep = ((stepsFromDo % 7) + 7) % 7;
40
+ const doOctave = Math.floor(def.doMidi / 12) - 1;
41
+ return (doOctave + octOffset + 1) * 12 + DIATONIC[diatStep];
42
+ }
43
+ export function pcToGabc(pc, clef = "c4", oct = 0) {
44
+ const def = CLEFS[clef];
45
+ if (!def)
46
+ throw new Error(`Unknown clef: ${clef}`);
47
+ const doOctave = Math.floor(def.doMidi / 12) - 1;
48
+ return midiToGabc((doOctave + oct + 1) * 12 + pc, clef);
49
+ }
50
+ export function gabcToPc(letter, clef = "c4") {
51
+ return gabcToMidi(letter, clef) % 12;
52
+ }
53
+ //# sourceMappingURL=gabc.js.map
@@ -0,0 +1,9 @@
1
+ import type { Pitch } from "./pitch.js";
2
+ import type { Scale } from "./scale.js";
3
+ export type { Pitch };
4
+ export interface GamutOptions {
5
+ span?: [number, number];
6
+ chromatic?: boolean;
7
+ }
8
+ export declare function buildGamut(scala: Scale, opts?: GamutOptions): Pitch[];
9
+ //# sourceMappingURL=gamut.d.ts.map
@@ -0,0 +1,24 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/gamut — modal pitch collection
3
+ // ---------------------------------------------------------------------------
4
+ import { MODES } from "./modes.js";
5
+ import { toPitch } from "./pitch.js";
6
+ export function buildGamut(scala, opts = {}) {
7
+ const modeData = MODES.get(scala.mode);
8
+ if (!modeData)
9
+ throw new RangeError(`Unknown mode: ${scala.mode}. Supported: 1–8.`);
10
+ const low = opts.span?.[0] ?? modeData.ambitus.lowest + 48;
11
+ const high = opts.span?.[1] ?? modeData.ambitus.highest + 48;
12
+ const pcs = opts.chromatic
13
+ ? new Set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
14
+ : new Set(modeData.scalePcs);
15
+ const pitches = [];
16
+ for (let midi = low; midi <= high; midi++) {
17
+ const pc = ((midi % 12) + 12) % 12;
18
+ if (!pcs.has(pc))
19
+ continue;
20
+ pitches.push(toPitch(midi, scala));
21
+ }
22
+ return pitches;
23
+ }
24
+ //# sourceMappingURL=gamut.js.map
@@ -0,0 +1,16 @@
1
+ export type { GuidonianVariant, GuidonianEntry } from "./data/guido.js";
2
+ export declare function lookupGuido(midi: number, mode?: number): {
3
+ name: string | null;
4
+ nomen: string | null;
5
+ hexachord: "durum" | "naturale" | "molle" | null;
6
+ solmization: string | null;
7
+ mutations: {
8
+ hexachord: string;
9
+ solmization: string;
10
+ }[];
11
+ hand: {
12
+ finger: string;
13
+ region: string;
14
+ } | null;
15
+ };
16
+ //# sourceMappingURL=guido.d.ts.map
@@ -0,0 +1,48 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/guido — Guidonian hexachord lookups
3
+ // ---------------------------------------------------------------------------
4
+ import { MODES } from "./modes.js";
5
+ import { GUIDONIAN_DATA } from "./data/guido.js";
6
+ // Look up the gamut entry for an exact MIDI number
7
+ function lookupExact(midi) {
8
+ return GUIDONIAN_DATA.get(midi);
9
+ }
10
+ // Look up by pitch class, picking the entry closest in pitch to the given MIDI
11
+ function lookupByPc(midi) {
12
+ const pc = ((midi % 12) + 12) % 12;
13
+ let best;
14
+ let bestDist = Infinity;
15
+ for (const [key, entry] of GUIDONIAN_DATA) {
16
+ if (key % 12 === pc) {
17
+ const dist = Math.abs(key - midi);
18
+ if (dist < bestDist) {
19
+ bestDist = dist;
20
+ best = entry;
21
+ }
22
+ }
23
+ }
24
+ return best;
25
+ }
26
+ // ── Public ──
27
+ // Build a Step's guidonian fields for a given MIDI note and optional mode.
28
+ // All fields are always present; nulled when out of gamut or context missing.
29
+ export function lookupGuido(midi, mode) {
30
+ const entry = lookupExact(midi) ?? lookupByPc(midi);
31
+ if (!entry) {
32
+ return { name: null, nomen: null, hexachord: null, solmization: null, mutations: [], hand: null };
33
+ }
34
+ // Determine primary hexachord — prefer mode's hexachord if available
35
+ const modeHex = mode != null ? MODES.get(mode)?.hexachords[0] : undefined;
36
+ const primary = (modeHex && entry.variants.find((v) => v.hexachord === modeHex)) ??
37
+ entry.variants.find((v) => v.hexachord === "naturale") ??
38
+ entry.variants[0];
39
+ return {
40
+ name: entry.name[0],
41
+ nomen: entry.name[1],
42
+ hexachord: primary?.hexachord ?? null,
43
+ solmization: primary?.solmization ?? null,
44
+ mutations: entry.variants.map((v) => ({ hexachord: v.hexachord, solmization: v.solmization })),
45
+ hand: entry.hand,
46
+ };
47
+ }
48
+ //# sourceMappingURL=guido.js.map
@@ -0,0 +1,15 @@
1
+ export type IntervalDirection = "up" | "down" | "unison";
2
+ export type IntervalQuality = "perfect" | "major" | "minor" | "augmented";
3
+ export type Consonance = "perfect" | "imperfect" | "dissonant";
4
+ export interface Interval {
5
+ nomen: string;
6
+ alias?: string;
7
+ quality: IntervalQuality;
8
+ class: string;
9
+ direction: IntervalDirection;
10
+ semitones: number;
11
+ cents: number;
12
+ consonance: Consonance;
13
+ }
14
+ export declare function classifyInterval(a: number, b?: number): Interval;
15
+ //# sourceMappingURL=interval.d.ts.map
@@ -0,0 +1,31 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/interval — interval classification between pitches
3
+ // ---------------------------------------------------------------------------
4
+ import { INTERVAL, UNISONUS } from "./data/constants.js";
5
+ const PERFECT_CLASSES = new Set(["P1", "P5", "P8"]);
6
+ const IMPERFECT_CLASSES = new Set(["m3", "M3", "m6", "M6"]);
7
+ function classifyConsonance(intervalClass) {
8
+ if (PERFECT_CLASSES.has(intervalClass))
9
+ return "perfect";
10
+ if (IMPERFECT_CLASSES.has(intervalClass))
11
+ return "imperfect";
12
+ return "dissonant";
13
+ }
14
+ export function classifyInterval(a, b) {
15
+ const semitones = b !== undefined ? b - a : a;
16
+ const abs = Math.abs(semitones);
17
+ const simple = abs % 12;
18
+ const direction = semitones > 0 ? "up" : semitones < 0 ? "down" : "unison";
19
+ const entry = abs === 0 ? UNISONUS : (simple === 0 ? INTERVAL[0] : INTERVAL[simple]);
20
+ return {
21
+ nomen: entry.latin,
22
+ alias: entry.alias,
23
+ quality: entry.quality,
24
+ class: entry.class,
25
+ direction,
26
+ semitones,
27
+ cents: semitones * 100,
28
+ consonance: classifyConsonance(entry.class),
29
+ };
30
+ }
31
+ //# sourceMappingURL=interval.js.map
@@ -0,0 +1,6 @@
1
+ import type { ModeData } from "./data/modes.js";
2
+ export type { ModeProfile, ModeData } from "./data/modes.js";
3
+ export { MODES } from "./data/modes.js";
4
+ /** Return ModeData for mode 1–8. Throws on unknown mode. */
5
+ export declare function getMode(mode: number): ModeData;
6
+ //# sourceMappingURL=modes.d.ts.map
@@ -0,0 +1,13 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/temper/modes — Gregorian modal system
3
+ // ---------------------------------------------------------------------------
4
+ import { MODES } from "./data/modes.js";
5
+ export { MODES } from "./data/modes.js";
6
+ /** Return ModeData for mode 1–8. Throws on unknown mode. */
7
+ export function getMode(mode) {
8
+ const found = MODES.get(mode);
9
+ if (!found)
10
+ throw new Error(`Unknown mode: ${mode}. Supported: 1–8.`);
11
+ return found;
12
+ }
13
+ //# sourceMappingURL=modes.js.map
@@ -0,0 +1,14 @@
1
+ import type { Interval } from "./interval.js";
2
+ import type { Pitch, PitchInput } from "./pitch.js";
3
+ import type { Scale } from "./scale.js";
4
+ export type { Interval };
5
+ export type NeumeShape = "punctum" | "pes" | "clivis" | "torculus" | "porrectus" | "scandicus" | "salicus" | "climacus" | "torculus resupinus" | "porrectus flexus" | "scandicus flexus" | "climacus resupinus" | "pes subpunctis" | "compound";
6
+ export interface Neume {
7
+ pitches: Pitch[];
8
+ intervals: Interval[];
9
+ shape: NeumeShape;
10
+ }
11
+ export type Direction = "up" | "down" | "unison";
12
+ export declare function classifyShape(dirs: Direction[]): NeumeShape;
13
+ export declare function buildNeume(inputs: PitchInput[], scala: Scale): Neume;
14
+ //# sourceMappingURL=neume.d.ts.map