@libraz/libcantus 0.9.4 → 1.0.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 (186) hide show
  1. package/README.md +61 -261
  2. package/README_ja.md +115 -0
  3. package/dist/analyze/index.cjs +54 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +213 -456
  6. package/dist/analyze/index.d.ts +213 -456
  7. package/dist/analyze/index.js +56 -9
  8. package/dist/chunk-3JXCW6DX.cjs +3220 -0
  9. package/dist/chunk-3JXCW6DX.cjs.map +1 -0
  10. package/dist/chunk-4A2RMUCC.js +7647 -0
  11. package/dist/chunk-4A2RMUCC.js.map +1 -0
  12. package/dist/chunk-6XPTBE7Y.cjs +49 -0
  13. package/dist/chunk-6XPTBE7Y.cjs.map +1 -0
  14. package/dist/chunk-AFM2ULJH.cjs +5121 -0
  15. package/dist/chunk-AFM2ULJH.cjs.map +1 -0
  16. package/dist/chunk-E3F4AHAH.cjs +690 -0
  17. package/dist/chunk-E3F4AHAH.cjs.map +1 -0
  18. package/dist/chunk-ELCTZUJJ.js +379 -0
  19. package/dist/chunk-ELCTZUJJ.js.map +1 -0
  20. package/dist/chunk-FVSI36UV.js +690 -0
  21. package/dist/chunk-FVSI36UV.js.map +1 -0
  22. package/dist/chunk-GEDTJHAC.cjs +1 -0
  23. package/dist/chunk-GEDTJHAC.cjs.map +1 -0
  24. package/dist/chunk-GOZG57ER.js +3220 -0
  25. package/dist/chunk-GOZG57ER.js.map +1 -0
  26. package/dist/chunk-H3VORETI.js +2243 -0
  27. package/dist/chunk-H3VORETI.js.map +1 -0
  28. package/dist/chunk-H42UHPYW.js +1577 -0
  29. package/dist/chunk-H42UHPYW.js.map +1 -0
  30. package/dist/chunk-HFPS7JFD.js +1 -0
  31. package/dist/chunk-INHVXP6Z.js +3053 -0
  32. package/dist/chunk-INHVXP6Z.js.map +1 -0
  33. package/dist/chunk-K4ZJUGF4.cjs +379 -0
  34. package/dist/chunk-K4ZJUGF4.cjs.map +1 -0
  35. package/dist/chunk-KNJEKLKV.js +49 -0
  36. package/dist/chunk-KNJEKLKV.js.map +1 -0
  37. package/dist/chunk-M4CWTJWJ.cjs +7647 -0
  38. package/dist/chunk-M4CWTJWJ.cjs.map +1 -0
  39. package/dist/chunk-MXO72PLY.cjs +211 -0
  40. package/dist/chunk-MXO72PLY.cjs.map +1 -0
  41. package/dist/chunk-NLEU4QSE.cjs +360 -0
  42. package/dist/chunk-NLEU4QSE.cjs.map +1 -0
  43. package/dist/chunk-OE6WK2Y2.cjs +1577 -0
  44. package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
  45. package/dist/chunk-Q2WGKJNN.cjs +1064 -0
  46. package/dist/chunk-Q2WGKJNN.cjs.map +1 -0
  47. package/dist/chunk-QYQQ5J6E.js +1 -0
  48. package/dist/chunk-QYQQ5J6E.js.map +1 -0
  49. package/dist/chunk-RHIJ3S4I.cjs +1 -0
  50. package/dist/chunk-RHIJ3S4I.cjs.map +1 -0
  51. package/dist/chunk-TTCLJX6D.js +211 -0
  52. package/dist/chunk-TTCLJX6D.js.map +1 -0
  53. package/dist/chunk-UADYAYAT.cjs +3053 -0
  54. package/dist/chunk-UADYAYAT.cjs.map +1 -0
  55. package/dist/chunk-VOHZB45S.js +5121 -0
  56. package/dist/chunk-VOHZB45S.js.map +1 -0
  57. package/dist/chunk-VTI6FOLB.js +1064 -0
  58. package/dist/chunk-VTI6FOLB.js.map +1 -0
  59. package/dist/chunk-WWURE4XT.cjs +2243 -0
  60. package/dist/chunk-WWURE4XT.cjs.map +1 -0
  61. package/dist/chunk-YH3BIKHH.js +360 -0
  62. package/dist/chunk-YH3BIKHH.js.map +1 -0
  63. package/dist/core/index.cjs +103 -6
  64. package/dist/core/index.cjs.map +1 -1
  65. package/dist/core/index.d.cts +96 -345
  66. package/dist/core/index.d.ts +96 -345
  67. package/dist/core/index.js +104 -7
  68. package/dist/generate/index.cjs +89 -10
  69. package/dist/generate/index.cjs.map +1 -1
  70. package/dist/generate/index.d.cts +437 -1095
  71. package/dist/generate/index.d.ts +437 -1095
  72. package/dist/generate/index.js +94 -15
  73. package/dist/index-9wcMhG73.d.ts +1095 -0
  74. package/dist/{index-D6b6na69.d.cts → index-B4o55NDr.d.cts} +13 -9
  75. package/dist/index-B9MNZboQ.d.cts +770 -0
  76. package/dist/index-B9MNZboQ.d.ts +770 -0
  77. package/dist/index-BGFW-8P2.d.cts +2307 -0
  78. package/dist/index-BO6xE9YU.d.cts +1804 -0
  79. package/dist/index-BkGmlyI3.d.cts +470 -0
  80. package/dist/index-CCNJRG-P.d.cts +1095 -0
  81. package/dist/index-CGpRv5sl.d.cts +643 -0
  82. package/dist/index-C_8o--VE.d.cts +1242 -0
  83. package/dist/index-CgHqxdps.d.ts +2307 -0
  84. package/dist/index-Chbst3Jx.d.ts +1343 -0
  85. package/dist/index-Cj49F892.d.ts +470 -0
  86. package/dist/{index-tSQh-xwY.d.ts → index-CunYKLiu.d.ts} +13 -9
  87. package/dist/index-D57QRbVn.d.ts +1804 -0
  88. package/dist/index-DInQqT8Q.d.cts +66 -0
  89. package/dist/index-DInQqT8Q.d.ts +66 -0
  90. package/dist/index-Dzr13q3d.d.cts +1343 -0
  91. package/dist/index-G1uwGGWQ.d.ts +643 -0
  92. package/dist/index-szBv3496.d.ts +1242 -0
  93. package/dist/index.cjs +358 -15
  94. package/dist/index.cjs.map +1 -1
  95. package/dist/index.d.cts +17 -15
  96. package/dist/index.d.ts +17 -15
  97. package/dist/index.js +407 -64
  98. package/dist/masks-DYbE485J.d.cts +445 -0
  99. package/dist/masks-DYbE485J.d.ts +445 -0
  100. package/dist/model/index.cjs +39 -7
  101. package/dist/model/index.cjs.map +1 -1
  102. package/dist/model/index.d.cts +4685 -243
  103. package/dist/model/index.d.ts +4685 -243
  104. package/dist/model/index.js +40 -8
  105. package/dist/positional-Cptlj-xs.d.ts +287 -0
  106. package/dist/positional-DvH_sd8u.d.cts +287 -0
  107. package/dist/theory/index.cjs +101 -7
  108. package/dist/theory/index.cjs.map +1 -1
  109. package/dist/theory/index.d.cts +513 -173
  110. package/dist/theory/index.d.ts +513 -173
  111. package/dist/theory/index.js +118 -24
  112. package/package.json +16 -11
  113. package/dist/chunk-36N73KZ3.cjs +0 -246
  114. package/dist/chunk-36N73KZ3.cjs.map +0 -1
  115. package/dist/chunk-4HLLZPXT.cjs +0 -3077
  116. package/dist/chunk-4HLLZPXT.cjs.map +0 -1
  117. package/dist/chunk-7MGZ7D62.cjs +0 -498
  118. package/dist/chunk-7MGZ7D62.cjs.map +0 -1
  119. package/dist/chunk-7NKDPF74.js +0 -3077
  120. package/dist/chunk-7NKDPF74.js.map +0 -1
  121. package/dist/chunk-CAN76NCU.cjs +0 -679
  122. package/dist/chunk-CAN76NCU.cjs.map +0 -1
  123. package/dist/chunk-D2FAJBYL.js +0 -479
  124. package/dist/chunk-D2FAJBYL.js.map +0 -1
  125. package/dist/chunk-EHVEBWM5.js +0 -1449
  126. package/dist/chunk-EHVEBWM5.js.map +0 -1
  127. package/dist/chunk-FCANXBAT.cjs +0 -30
  128. package/dist/chunk-FCANXBAT.cjs.map +0 -1
  129. package/dist/chunk-FNDWXRRI.cjs +0 -479
  130. package/dist/chunk-FNDWXRRI.cjs.map +0 -1
  131. package/dist/chunk-GQSGS2N4.js +0 -173
  132. package/dist/chunk-GQSGS2N4.js.map +0 -1
  133. package/dist/chunk-HKGYCQ34.js +0 -53
  134. package/dist/chunk-HKGYCQ34.js.map +0 -1
  135. package/dist/chunk-I24MV65U.js +0 -106
  136. package/dist/chunk-I24MV65U.js.map +0 -1
  137. package/dist/chunk-KMHOICIY.js +0 -679
  138. package/dist/chunk-KMHOICIY.js.map +0 -1
  139. package/dist/chunk-LW53AHQU.cjs +0 -1117
  140. package/dist/chunk-LW53AHQU.cjs.map +0 -1
  141. package/dist/chunk-N6IHQUOX.js +0 -1
  142. package/dist/chunk-NKIBQ6PT.js +0 -30
  143. package/dist/chunk-NKIBQ6PT.js.map +0 -1
  144. package/dist/chunk-NP4NA2FB.cjs +0 -106
  145. package/dist/chunk-NP4NA2FB.cjs.map +0 -1
  146. package/dist/chunk-NVE34YGZ.cjs +0 -1449
  147. package/dist/chunk-NVE34YGZ.cjs.map +0 -1
  148. package/dist/chunk-NYYWMV2C.js +0 -327
  149. package/dist/chunk-NYYWMV2C.js.map +0 -1
  150. package/dist/chunk-Q2XUP227.js +0 -845
  151. package/dist/chunk-Q2XUP227.js.map +0 -1
  152. package/dist/chunk-Q6OP4U43.cjs +0 -327
  153. package/dist/chunk-Q6OP4U43.cjs.map +0 -1
  154. package/dist/chunk-RC6GBMCD.cjs +0 -845
  155. package/dist/chunk-RC6GBMCD.cjs.map +0 -1
  156. package/dist/chunk-RK35RIN7.js +0 -1117
  157. package/dist/chunk-RK35RIN7.js.map +0 -1
  158. package/dist/chunk-RUMU3UA6.cjs +0 -53
  159. package/dist/chunk-RUMU3UA6.cjs.map +0 -1
  160. package/dist/chunk-T64C7ZD7.cjs +0 -1
  161. package/dist/chunk-T64C7ZD7.cjs.map +0 -1
  162. package/dist/chunk-XEBG3G53.js +0 -498
  163. package/dist/chunk-XEBG3G53.js.map +0 -1
  164. package/dist/chunk-YLEMGEFH.js +0 -246
  165. package/dist/chunk-YLEMGEFH.js.map +0 -1
  166. package/dist/chunk-ZEJR4TKL.cjs +0 -173
  167. package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
  168. package/dist/function-BtiZb9i9.d.ts +0 -208
  169. package/dist/function-DNugAOrt.d.cts +0 -208
  170. package/dist/index-6VR8-kit.d.ts +0 -143
  171. package/dist/index-70p168VM.d.ts +0 -192
  172. package/dist/index-Be74mcon.d.cts +0 -152
  173. package/dist/index-BtXT6UQ0.d.cts +0 -192
  174. package/dist/index-C5UBbQ4G.d.ts +0 -152
  175. package/dist/index-C83mZI1P.d.ts +0 -242
  176. package/dist/index-DXd9JikN.d.cts +0 -246
  177. package/dist/index-DXd9JikN.d.ts +0 -246
  178. package/dist/index-OG65ocOr.d.cts +0 -272
  179. package/dist/index-OG65ocOr.d.ts +0 -272
  180. package/dist/index-tJhkmQgE.d.cts +0 -143
  181. package/dist/index-y_ak9_Hi.d.cts +0 -242
  182. package/dist/styled-DIRkk9Uz.d.ts +0 -506
  183. package/dist/styled-DJbkJQfj.d.cts +0 -506
  184. package/dist/types-BN6_Q9Kl.d.cts +0 -39
  185. package/dist/types-BN6_Q9Kl.d.ts +0 -39
  186. /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
@@ -1,242 +0,0 @@
1
- import { K as KeyScale } from './types-BN6_Q9Kl.js';
2
-
3
- /**
4
- * Chord quality identifiers understood by the chord builder.
5
- *
6
- * @category Chords
7
- */
8
- type ChordQuality = 'maj' | 'min' | 'dim' | 'aug' | 'maj7' | 'min7' | 'dom7' | 'dim7' | 'm7b5' | 'minMaj7' | 'aug7' | 'augMaj7' | 'majb5' | '6' | 'min6' | '6/9' | 'sus2' | 'sus4' | 'add9' | 'add11' | 'maj9' | 'min9' | 'dom9' | '7b9' | '7#9' | '7#11' | '7b13' | '11' | '13' | '5' | '7sus4' | '7b5' | '7alt' | '13b9' | 'maj13' | 'maj7#11' | 'min11' | 'min13' | 'minAdd9' | 'min6/9';
9
- /**
10
- * The basic role a chord tone plays: the degrees a chord's own template names.
11
- *
12
- * The shared vocabulary behind {@link chordToneRole}, the harmony layer's
13
- * `HarmonyRole`, and the voice analyser's labels, so the three cannot drift.
14
- *
15
- * @category Chords
16
- */
17
- type ChordToneRole = 'root' | 'third' | 'fifth' | 'sixth' | 'seventh';
18
- /**
19
- * A bare spelled pitch used as an enharmonic hint: a diatonic letter
20
- * (0..6 = C..B) plus a chromatic alteration (-2 double-flat .. +2 double-sharp).
21
- * Mirrors the letter/alter half of the pitch module's `Note` without an octave.
22
- *
23
- * @category Chords
24
- */
25
- type PitchSpelling = {
26
- letter: number;
27
- alter: number;
28
- };
29
- /**
30
- * A chord expressed as a root pitch class plus semitone offsets.
31
- *
32
- * `rootSpelling`/`bassSpelling` are optional enharmonic hints recorded by
33
- * parsers (e.g. `parseChordSymbol('Bb7')`) so formatters can reproduce the
34
- * original spelling instead of defaulting to sharps. Consumers may ignore
35
- * them; a hint is only trusted when its pitch class still matches the
36
- * corresponding `rootPc`/`bassPc`.
37
- *
38
- * @category Chords
39
- */
40
- type Chord = {
41
- rootPc: number;
42
- quality: ChordQuality;
43
- intervals: number[];
44
- bassPc?: number;
45
- rootSpelling?: PitchSpelling;
46
- bassSpelling?: PitchSpelling;
47
- };
48
- /**
49
- * A chord positioned in time: a root pitch class and quality placed at a beat,
50
- * with optional harmonic-analysis hints. Serves as the neutral exchange record
51
- * between progression generators and timeline analysers.
52
- *
53
- * @category Composition
54
- */
55
- type ChordSpan = {
56
- rootPc: number;
57
- quality: ChordQuality;
58
- startBeat: number;
59
- bassPc?: number;
60
- /** 0-based scale degree of the chord root, when known. */
61
- degree?: number;
62
- /** True when the chord is a secondary dominant tonicizing another degree. */
63
- secondaryDominant?: boolean;
64
- };
65
- /**
66
- * A chord occupying a half-open beat span `[startBeat, endBeat)`.
67
- *
68
- * The exchange record between anything that lays chords out in time — a
69
- * timeline analysis, a bass-line plan, an accompaniment generator — so those
70
- * surfaces share one definition instead of agreeing by coincidence.
71
- *
72
- * @category Composition
73
- */
74
- type ChordSegment = {
75
- startBeat: number;
76
- endBeat: number;
77
- chord: Chord;
78
- };
79
- /**
80
- * All chord qualities the builder understands, in declaration order.
81
- *
82
- * The order is stable but carries no meaning: it is neither alphabetical nor
83
- * sorted by template size. {@link detectChord} uses it as its final tie-break,
84
- * so it is part of the observable behaviour and does not get reshuffled
85
- * casually — but do not read it as a ranking.
86
- *
87
- * @category Chords
88
- */
89
- declare function chordQualities(): ChordQuality[];
90
- /**
91
- * Build a chord rooted on a diatonic scale degree.
92
- *
93
- * The root pitch class is the degree's diatonic pitch class in `key`; the
94
- * quality's interval template is attached unchanged. Degrees beyond the scale
95
- * length wrap around.
96
- *
97
- * @param degree 0-based scale degree of the chord root.
98
- * @param ext Chord quality to apply.
99
- * @param key Key context supplying the diatonic root.
100
- * @returns The constructed chord.
101
- *
102
- * @category Chords
103
- */
104
- declare function chordFromDegree(degree: number, ext: ChordQuality, key: KeyScale): Chord;
105
- /**
106
- * Build a chord from an explicit root pitch class and quality.
107
- *
108
- * @param rootPc Root pitch class (0..11).
109
- * @param quality Chord quality supplying the interval template.
110
- * @param bassPc Optional slash-chord bass pitch class.
111
- * @returns The constructed chord.
112
- *
113
- * @example
114
- * ```ts
115
- * import { makeChord } from '@libraz/libcantus';
116
- * const cmaj7 = makeChord(0, 'maj7');
117
- * // { rootPc: 0, quality: 'maj7', intervals: [0, 4, 7, 11] }
118
- * ```
119
- *
120
- * @category Chords
121
- */
122
- declare function makeChord(rootPc: number, quality: ChordQuality, bassPc?: number): Chord;
123
- /**
124
- * Transpose a chord by a number of semitones.
125
- *
126
- * The interval template is carried over untouched, so a chord whose intervals
127
- * were customised keeps them, and a slash bass moves with the root. Enharmonic
128
- * spelling hints are dropped rather than shifted: the letter a transposed root
129
- * should take depends on the destination key, which a semitone count does not
130
- * carry. Pass the result through {@link spellChord} to respell it.
131
- *
132
- * @param chord The chord to transpose.
133
- * @param semitones The signed semitone offset.
134
- * @returns The transposed chord.
135
- * @throws If `semitones` is not finite.
136
- *
137
- * @example
138
- * ```ts
139
- * import { formatChordSymbol, parseChordSymbol, transposeChord } from '@libraz/libcantus';
140
- * formatChordSymbol(transposeChord(parseChordSymbol('C/G'), 2)); // 'D/A'
141
- * ```
142
- *
143
- * @category Chords
144
- */
145
- declare function transposeChord(chord: Chord, semitones: number): Chord;
146
- /**
147
- * Get the sorted, deduplicated pitch classes of a chord.
148
- *
149
- * A slash bass is one of them: `F/G` sounds a G, the voicers put it in the
150
- * bass, and a set that omitted it would not re-detect as the chord it came
151
- * from. Pass `includeBass: false` to enumerate the interval template alone.
152
- *
153
- * @param chord The chord to enumerate.
154
- * @param opts Set `includeBass: false` to omit a slash bass.
155
- * @returns The chord's pitch classes, sorted ascending in [0, 11].
156
- *
157
- * @example
158
- * ```ts
159
- * import { makeChord, chordPitchClasses } from '@libraz/libcantus';
160
- * chordPitchClasses(makeChord(0, 'maj7')); // [0, 4, 7, 11]
161
- * chordPitchClasses(makeChord(5, 'maj', 7)); // [0, 5, 7, 9] — F/G, G included
162
- * ```
163
- *
164
- * @category Chords
165
- */
166
- declare function chordPitchClasses(chord: Chord, opts?: {
167
- includeBass?: boolean;
168
- }): number[];
169
- /**
170
- * A pitch's interval class above the chord root, in [0, 11].
171
- *
172
- * The shared reading of "where does this pitch sit in the chord", used by the
173
- * safety evaluator and the voice analyser alike so they cannot disagree.
174
- *
175
- * @param pitch MIDI pitch or bare pitch class.
176
- * @param chord The chord providing the root reference.
177
- * @returns The interval class above the root.
178
- * @category Chords
179
- */
180
- declare function intervalAboveRoot(pitch: number, chord: Chord): number;
181
- /**
182
- * Whether a pitch is one of a chord's tones, ignoring octave.
183
- *
184
- * @param pitch MIDI pitch or bare pitch class.
185
- * @param chord The chord, or null for no sounding harmony.
186
- * @returns True when the pitch class belongs to the chord.
187
- * @category Chords
188
- */
189
- declare function isChordMember(pitch: number, chord: Chord | null): boolean;
190
- /**
191
- * Determine a pitch's harmonic role within a chord.
192
- *
193
- * The role is derived from the pitch's interval above the chord root, reduced
194
- * modulo 12. A major sixth (9) reads as a `sixth` for sixth chords but as a
195
- * `seventh` for a diminished-seventh chord; ninths and other tensions have no
196
- * basic role and return null.
197
- *
198
- * @param pitch MIDI pitch or bare pitch class.
199
- * @param chord The chord providing the root reference.
200
- * @returns The chord-tone role, or null if the pitch has no basic role.
201
- *
202
- * @category Chords
203
- */
204
- declare function chordToneRole(pitch: number, chord: Chord): ChordToneRole | null;
205
- /**
206
- * Build the diatonic triad rooted on a scale degree by stacking scale thirds.
207
- *
208
- * Unlike {@link chordFromDegree}, the chord quality is derived from the scale
209
- * rather than supplied, so degrees yield their scale-correct triads (e.g. a
210
- * diminished triad on the leading tone of a major key).
211
- *
212
- * @param degree 0-based scale degree of the chord root.
213
- * @param key Key/scale context.
214
- * @returns The diatonic triad.
215
- * @throws If the scale is not heptatonic. Stacking thirds means skipping every
216
- * other degree, which only lands on a triad when there are seven of them, so
217
- * the pentatonic, blues, whole-tone, octatonic and chromatic scales have no
218
- * diatonic triad; use {@link chordFromDegree} with an explicit quality there.
219
- *
220
- * @example
221
- * ```ts
222
- * import { majorKey, diatonicTriad } from '@libraz/libcantus';
223
- * const tonic = diatonicTriad(0, majorKey(0)); // C major triad (degree 0 of C major)
224
- * ```
225
- *
226
- * @category Chords
227
- */
228
- declare function diatonicTriad(degree: number, key: KeyScale): Chord;
229
- /**
230
- * Build the diatonic seventh chord rooted on a scale degree.
231
- *
232
- * @param degree 0-based scale degree of the chord root.
233
- * @param key Key/scale context.
234
- * @returns The diatonic seventh chord.
235
- * @throws If the scale is not heptatonic, for the reason given on
236
- * {@link diatonicTriad}.
237
- *
238
- * @category Chords
239
- */
240
- declare function diatonicSeventh(degree: number, key: KeyScale): Chord;
241
-
242
- export { type Chord as C, type PitchSpelling as P, type ChordQuality as a, type ChordSegment as b, type ChordSpan as c, type ChordToneRole as d, chordFromDegree as e, chordPitchClasses as f, chordQualities as g, chordToneRole as h, diatonicSeventh as i, diatonicTriad as j, intervalAboveRoot as k, isChordMember as l, makeChord as m, transposeChord as t };
@@ -1,246 +0,0 @@
1
- /**
2
- * Meter and time signatures: bar/beat arithmetic, simple vs. compound meters,
3
- * metric-accent hierarchy, and tuplet subdivision.
4
- *
5
- * Positions and durations are measured in quarter-note beats, matching the rest
6
- * of the library's beat convention (four quarter-note beats per bar in 4/4).
7
- */
8
- /**
9
- * A time signature as a numerator over a note-value denominator.
10
- *
11
- * @category Rhythm & Meter
12
- */
13
- type TimeSignature = {
14
- numerator: number;
15
- denominator: number;
16
- /**
17
- * Optional additive grouping of the bar's main pulses, as the felt-beat
18
- * lengths in pulses — e.g. `[2, 2, 3]` for a 2+2+3 reading of 7/8, or
19
- * `[3, 2]` for 5/8. The entries must be positive integers summing to the
20
- * numerator.
21
- *
22
- * A compound numerator accepts both readings. 9/8 groups its three dotted
23
- * pulses as `[1, 1, 1]`, or reads additively as `[2, 2, 2, 3]` quavers; a
24
- * grouping that sums to the numerator selects the additive reading, so
25
- * aksak and other additive metres are expressible. {@link pulsesPerBar}
26
- * and {@link isCompound} follow whichever reading the grouping selects.
27
- *
28
- * When present, the head pulse of each group (other than the downbeat) is
29
- * treated as a secondary strong pulse by
30
- * {@link metricWeight}/{@link isStrongBeat}; when absent, all main pulses
31
- * are weighted equally as flat, evenly divided pulses.
32
- */
33
- grouping?: number[];
34
- };
35
- /**
36
- * A position expressed as a bar index and a quarter-note offset within the bar.
37
- *
38
- * @category Rhythm & Meter
39
- */
40
- type BarPosition = {
41
- /** 0-based bar index. {@link formatBarPosition} renders it 1-based. */
42
- bar: number;
43
- /**
44
- * Quarter-note offset from the start of the bar — not the felt beat. In 6/8
45
- * the second felt beat is at `beat: 1.5`; {@link barPositionToPulse} converts
46
- * to felt-beat numbering.
47
- */
48
- beat: number;
49
- };
50
- /**
51
- * Parse a time signature such as `"4/4"` or `"6/8"`.
52
- *
53
- * @param text The signature text.
54
- * @returns The parsed time signature.
55
- * @throws If the text is not `n/d` with positive integers.
56
- * @example
57
- * ```ts
58
- * import { parseTimeSignature } from '@libraz/libcantus';
59
- * parseTimeSignature('6/8'); // { numerator: 6, denominator: 8 }
60
- * ```
61
- * @category Rhythm & Meter
62
- */
63
- declare function parseTimeSignature(text: string): TimeSignature;
64
- /**
65
- * Render a time signature as `"n/d"`, or as `"a+b+c/d"` when it carries an
66
- * additive grouping and `grouping` is requested.
67
- *
68
- * The plain form drops the grouping, so a round trip through it reads 7/8 as
69
- * flat rather than as 2+2+3; ask for the additive form to keep it.
70
- *
71
- * @param ts The time signature.
72
- * @param opts Set `grouping: true` to render an additive grouping.
73
- * @returns The formatted signature.
74
- * @example
75
- * ```ts
76
- * import { formatTimeSignature } from '@libraz/libcantus';
77
- * const aksak = { numerator: 7, denominator: 8, grouping: [2, 2, 3] };
78
- * formatTimeSignature(aksak); // '7/8'
79
- * formatTimeSignature(aksak, { grouping: true }); // '2+2+3/8'
80
- * ```
81
- * @category Rhythm & Meter
82
- */
83
- declare function formatTimeSignature(ts: TimeSignature, opts?: {
84
- grouping?: boolean;
85
- }): string;
86
- /**
87
- * Whether a meter is compound: its main pulses each divide into three, as in
88
- * 6/8, 9/8, 12/8, or 6/4. Compound meters are those whose numerator is a
89
- * multiple of three greater than three, independent of the denominator. Meters
90
- * like 3/8 and 3/4 (simple triples, numerator 3) are not compound, and neither
91
- * is a signature whose {@link TimeSignature.grouping} selects the additive
92
- * reading (9/8 as 2+2+2+3).
93
- *
94
- * @param ts The time signature.
95
- * @returns True for compound meters.
96
- * @category Rhythm & Meter
97
- */
98
- declare function isCompound(ts: TimeSignature): boolean;
99
- /**
100
- * Length of a bar in quarter-note beats.
101
- *
102
- * @param ts The time signature.
103
- * @returns The bar length in quarter notes.
104
- * @category Rhythm & Meter
105
- */
106
- declare function beatsPerBar(ts: TimeSignature): number;
107
- /**
108
- * Number of main pulses (felt beats) per bar: the numerator for simple meters,
109
- * a third of it for compound meters.
110
- *
111
- * For additive/irregular meters such as 7/8 or 5/8 this counts the raw pulses
112
- * (7 and 5 respectively), which are otherwise felt as flat, evenly divided and
113
- * equally accented pulses. To recover a 2+2+3 or 3+2 felt-beat grouping, set
114
- * {@link TimeSignature.grouping}; {@link metricWeight} then accents each
115
- * group's head pulse.
116
- *
117
- * @param ts The time signature.
118
- * @returns The pulse count per bar.
119
- * @category Rhythm & Meter
120
- */
121
- declare function pulsesPerBar(ts: TimeSignature): number;
122
- /**
123
- * Convert an absolute quarter-note position to a bar index and in-bar offset.
124
- *
125
- * @param beatInQuarters Absolute position in quarter-note beats.
126
- * @param ts The time signature.
127
- * @returns The bar and in-bar quarter-note offset.
128
- * @example
129
- * ```ts
130
- * import { parseTimeSignature, beatToBarPosition } from '@libraz/libcantus';
131
- * const ts = parseTimeSignature('4/4');
132
- * beatToBarPosition(5, ts); // { bar: 1, beat: 1 }
133
- * ```
134
- * @category Rhythm & Meter
135
- */
136
- declare function beatToBarPosition(beatInQuarters: number, ts: TimeSignature): BarPosition;
137
- /**
138
- * Length of one felt beat (main pulse) in quarter-note beats.
139
- *
140
- * A quarter note in simple meters, a dotted quarter in compound ones, and one
141
- * denominator unit in an additive metre. Position displays, click tracks, and
142
- * score export are all written against this length.
143
- *
144
- * @param ts The time signature.
145
- * @returns The pulse length in quarter-note beats.
146
- * @example
147
- * ```ts
148
- * import { parseTimeSignature, pulseBeats } from '@libraz/libcantus';
149
- * pulseBeats(parseTimeSignature('6/8')); // 1.5
150
- * ```
151
- * @category Rhythm & Meter
152
- */
153
- declare function pulseBeats(ts: TimeSignature): number;
154
- /**
155
- * The felt-beat number of a bar position, 1-based.
156
- *
157
- * {@link BarPosition.beat} is a quarter-note offset, so in 6/8 the second felt
158
- * beat reads as 1.5. This is the number a musician says and a position display
159
- * shows.
160
- *
161
- * @param pos The bar position.
162
- * @param ts The time signature.
163
- * @returns The 1-based felt-beat number, fractional between pulses.
164
- * @example
165
- * ```ts
166
- * import { barPositionToPulse, parseTimeSignature } from '@libraz/libcantus';
167
- * barPositionToPulse({ bar: 0, beat: 1.5 }, parseTimeSignature('6/8')); // 2
168
- * ```
169
- * @category Rhythm & Meter
170
- */
171
- declare function barPositionToPulse(pos: BarPosition, ts: TimeSignature): number;
172
- /**
173
- * Render an absolute position as the `bar.beat` a DAW or a score shows:
174
- * 1-based bar, 1-based felt beat.
175
- *
176
- * @param beatInQuarters Absolute position in quarter-note beats.
177
- * @param ts The time signature.
178
- * @param decimals Digits of the fractional beat to keep.
179
- * @returns The formatted position, e.g. `'3.2'` for bar 3, felt beat 2.
180
- * @example
181
- * ```ts
182
- * import { formatBarPosition, parseTimeSignature } from '@libraz/libcantus';
183
- * formatBarPosition(7.5, parseTimeSignature('6/8')); // '3.2'
184
- * ```
185
- * @category Rhythm & Meter
186
- */
187
- declare function formatBarPosition(beatInQuarters: number, ts: TimeSignature, decimals?: number): string;
188
- /**
189
- * Convert a bar index and in-bar offset back to an absolute quarter-note
190
- * position.
191
- *
192
- * @param pos The bar position.
193
- * @param ts The time signature.
194
- * @returns The absolute position in quarter-note beats.
195
- * @category Rhythm & Meter
196
- */
197
- declare function barPositionToBeat(pos: BarPosition, ts: TimeSignature): number;
198
- /**
199
- * Metric weight of a position within its bar, on a 0–3 scale:
200
- * 3 the downbeat, 2 a secondary strong pulse, 1 any other main pulse, and 0 an
201
- * off-pulse subdivision.
202
- *
203
- * The secondary strong pulse is the bar's midpoint in even simple/compound
204
- * meters. For an additive/irregular meter with {@link TimeSignature.grouping}
205
- * set (e.g. `[2, 2, 3]` for 7/8), each group's head pulse other than the
206
- * downbeat is the secondary strong pulse instead; without a grouping every
207
- * non-downbeat main pulse of such a meter weighs 1 (flat, evenly divided
208
- * pulses).
209
- *
210
- * @param beatInQuarters Absolute or in-bar quarter-note position.
211
- * @param ts The time signature.
212
- * @returns The metric weight (0–3).
213
- * @throws If the time signature is malformed, including a grouping that is not
214
- * a positive-integer list summing to the pulse count or the numerator.
215
- * @example
216
- * ```ts
217
- * import { parseTimeSignature, metricWeight } from '@libraz/libcantus';
218
- * const ts = parseTimeSignature('4/4');
219
- * metricWeight(0, ts); // 3 (the downbeat)
220
- * ```
221
- * @category Rhythm & Meter
222
- */
223
- declare function metricWeight(beatInQuarters: number, ts: TimeSignature): number;
224
- /**
225
- * Whether a position is metrically accented (weight 2 or more — a downbeat or a
226
- * secondary strong pulse).
227
- *
228
- * @param beatInQuarters Absolute or in-bar quarter-note position.
229
- * @param ts The time signature.
230
- * @returns True on strong beats.
231
- * @category Rhythm & Meter
232
- */
233
- declare function isStrongBeat(beatInQuarters: number, ts: TimeSignature): boolean;
234
- /**
235
- * Subdivide a span into `count` equal tuplet durations (e.g. an eighth-note
236
- * triplet is `tuplet(1, 3)`).
237
- *
238
- * @param totalBeats Total span in quarter-note beats.
239
- * @param count Number of equal parts.
240
- * @returns `count` equal durations summing to `totalBeats`.
241
- * @throws If `count` is not a positive integer.
242
- * @category Rhythm & Meter
243
- */
244
- declare function tuplet(totalBeats: number, count: number): number[];
245
-
246
- export { type BarPosition as B, type TimeSignature as T, barPositionToPulse as a, barPositionToBeat as b, beatToBarPosition as c, beatsPerBar as d, formatTimeSignature as e, formatBarPosition as f, isStrongBeat as g, pulseBeats as h, isCompound as i, pulsesPerBar as j, metricWeight as m, parseTimeSignature as p, tuplet as t };