@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
@@ -0,0 +1,470 @@
1
+ import { P as ParseResult } from './index-B9MNZboQ.js';
2
+
3
+ /**
4
+ * Meter arithmetic shared by the meter module and the validation guards.
5
+ *
6
+ * These helpers never validate: they are the single definition of how a time
7
+ * signature is read, so the guard that rejects a malformed signature and the
8
+ * functions that use a validated one cannot drift apart. Everything here is
9
+ * integer arithmetic on the numerator, so a bar's pulse count is exact rather
10
+ * than the result of dividing two floats.
11
+ */
12
+
13
+ /**
14
+ * A meter in the plain data the library reads it as: one signature, or the map
15
+ * of a piece that changes meter.
16
+ *
17
+ * What {@link MeterLike} resolves to, and the type every function below the
18
+ * entry points works in — the text form is read once, at the boundary.
19
+ *
20
+ * @category Rhythm & Meter
21
+ */
22
+ type MeterData = TimeSignature | MeterMap;
23
+
24
+ /**
25
+ * Meter and time signatures: bar/beat arithmetic, simple vs. compound meters,
26
+ * metric-accent hierarchy, and tuplet subdivision.
27
+ *
28
+ * Positions and durations are measured in quarter-note beats, matching the rest
29
+ * of the library's beat convention (four quarter-note beats per bar in 4/4).
30
+ * Beat 0 is the first downbeat, so a pickup sounds at negative beats, and a
31
+ * piece that changes meter is described by a {@link MeterMap} rather than by
32
+ * one signature.
33
+ */
34
+
35
+ /**
36
+ * A time signature as a numerator over a note-value denominator.
37
+ *
38
+ * @category Rhythm & Meter
39
+ */
40
+ type TimeSignature = {
41
+ numerator: number;
42
+ denominator: number;
43
+ /**
44
+ * Optional grouping of the bar into felt beats, as positive integers. The
45
+ * entries are group lengths, written either in the meter's main pulses —
46
+ * `[2, 2, 3]` for a 2+2+3 reading of 7/8, `[3, 2]` for 5/8 — or, for a
47
+ * compound numerator, in denominator units. They must sum to
48
+ * {@link pulsesPerBar} in the first spelling and to the numerator in the
49
+ * second; a pulse is one unit outside compound meters, where the two
50
+ * spellings coincide.
51
+ *
52
+ * A compound numerator accepts both readings, and the shape of the grouping
53
+ * says which is meant. Groups of nothing but threes spell the compound
54
+ * division itself, so 9/8 as `[3, 3, 3]` (equivalently `[1, 1, 1]`) is the
55
+ * ordinary three dotted-quarter pulses; any other grouping summing to the
56
+ * numerator reads additively, so 9/8 as `[2, 2, 2, 3]` is nine quaver pulses
57
+ * grouped aksak-fashion. {@link pulsesPerBar}, {@link pulseBeats} and
58
+ * {@link isCompound} follow whichever reading the grouping selects.
59
+ *
60
+ * The head pulse of each group other than the downbeat is a secondary strong
61
+ * pulse to {@link metricWeight}/{@link isStrongBeat}. A grouping whose groups
62
+ * are all the same length states no accent the meter does not already have,
63
+ * so it weighs exactly as an ungrouped bar does.
64
+ */
65
+ grouping?: number[];
66
+ };
67
+ /**
68
+ * One time signature and the beat at which it takes effect.
69
+ *
70
+ * @category Rhythm & Meter
71
+ */
72
+ type MeterChange = {
73
+ /** Absolute quarter-note beat the signature takes effect at. */
74
+ startBeat: number;
75
+ /** The signature in force from that beat until the next change. */
76
+ ts: TimeSignature;
77
+ };
78
+ /**
79
+ * A piece's meter over time: the signatures in force, in beat order.
80
+ *
81
+ * A meter change starts a new bar, so a span that does not divide evenly into
82
+ * its own bars ends with a short bar rather than spilling across the change.
83
+ * The first entry also governs everything before it, which is what reads a
84
+ * pickup written at negative beats in the signature the piece opens in.
85
+ *
86
+ * @category Rhythm & Meter
87
+ */
88
+ type MeterMap = MeterChange[];
89
+
90
+ /**
91
+ * Anything that names a meter: a signature text such as `'6/8'`, a plain
92
+ * {@link TimeSignature}, a full {@link MeterMap}, or a value that serializes to
93
+ * one of those such as the `Meter` class.
94
+ *
95
+ * Every meter-aware function takes this, so a piece in one meter reads as
96
+ * `'4/4'` and a piece that changes meter reads as the map, without the caller
97
+ * choosing a different function for each. Only a signature has a text form — a
98
+ * meter map is a run of changes and is given as the data it is.
99
+ *
100
+ * @category Rhythm & Meter
101
+ */
102
+ type MeterLike = string | TimeSignature | MeterMap | {
103
+ /** The meter data this value stands for. */
104
+ toJSON(): TimeSignature | MeterMap;
105
+ };
106
+ /**
107
+ * Resolve any meter-shaped value to the plain meter data the library reads.
108
+ *
109
+ * The counterpart of {@link toNoteData} for meters: an entry point takes
110
+ * whatever form the caller has — the signature a meter field holds, the data
111
+ * the meter module returns, the map of a piece that changes meter, or a `Meter`
112
+ * instance — and gets one of two shapes back. An instance is accepted through
113
+ * its `toJSON` method rather than by its type, so the core layer can read a
114
+ * class it cannot import.
115
+ *
116
+ * Text is read by {@link parseTimeSignature} and nothing else, so every entry
117
+ * point that takes a meter accepts exactly the signatures that parser accepts,
118
+ * the additive `'2+2+3/8'` included and nothing besides. A meter map has no text
119
+ * form — it is a run of changes, each with the beat it starts at — so text
120
+ * always names a single signature.
121
+ *
122
+ * @param value A signature text, a plain time signature, a meter map, or a
123
+ * value whose `toJSON` returns one of those.
124
+ * @param name What the meter is called in an error message, so a caller that
125
+ * holds several of them hears which one was malformed.
126
+ * @returns The validated signature, or the validated map.
127
+ * @throws If the value names no meter, or the meter it names is malformed.
128
+ */
129
+ declare function toMeterData(value: MeterLike, name?: string): MeterData;
130
+ /**
131
+ * A position expressed as a bar index and a quarter-note offset within the bar.
132
+ *
133
+ * @category Rhythm & Meter
134
+ */
135
+ type BarPosition = {
136
+ /**
137
+ * 0-based bar index, counting the first full bar as 0.
138
+ * {@link formatBarPosition} renders it 1-based. A pickup sounds before that
139
+ * bar, so its notes report bar -1.
140
+ */
141
+ bar: number;
142
+ /**
143
+ * Quarter-note offset from the start of the bar — not the felt beat. In 6/8
144
+ * the second felt beat is at `beat: 1.5`; {@link barPositionToPulse} converts
145
+ * to felt-beat numbering.
146
+ */
147
+ beat: number;
148
+ };
149
+ /**
150
+ * Parse a time signature such as `"4/4"` or `"6/8"`, or the additive `"2+2+3/8"`.
151
+ *
152
+ * @param text The signature text.
153
+ * @returns The parsed time signature.
154
+ * @throws If the text is not `n/d` with positive integers, or names a signature
155
+ * the library rejects. Use {@link tryParseTimeSignature} where failure is
156
+ * ordinary, such as a meter field read on every keystroke.
157
+ * @example
158
+ * ```ts
159
+ * import { parseTimeSignature } from '@libraz/libcantus';
160
+ * parseTimeSignature('6/8'); // { numerator: 6, denominator: 8 }
161
+ * ```
162
+ * @category Rhythm & Meter
163
+ */
164
+ declare function parseTimeSignature(text: string): TimeSignature;
165
+ /**
166
+ * Parse a time signature, reporting failure instead of throwing it.
167
+ *
168
+ * The same reading as {@link parseTimeSignature} — that function is this one
169
+ * with its error thrown — for the callers where text that does not parse yet is
170
+ * the normal state of the input rather than a fault.
171
+ *
172
+ * @param text The signature text.
173
+ * @returns The signature, or the error explaining why the text is not one.
174
+ * @example
175
+ * ```ts
176
+ * import { tryParseTimeSignature } from '@libraz/libcantus';
177
+ * const result = tryParseTimeSignature('7/8');
178
+ * result.ok ? result.value.numerator : result.error.message;
179
+ * ```
180
+ * @category Rhythm & Meter
181
+ */
182
+ declare function tryParseTimeSignature(text: string): ParseResult<TimeSignature>;
183
+ /**
184
+ * Render a time signature as `"n/d"`, or as `"a+b+c/d"` when it carries an
185
+ * additive grouping and `grouping` is requested.
186
+ *
187
+ * The additive form is what {@link parseTimeSignature} reads back, and it adds
188
+ * its terms to get the numerator — so only a grouping written in denominator
189
+ * units can be rendered that way. A grouping counted in main pulses (9/8 as
190
+ * `[1, 1, 1]`, 12/8 as `[2, 2]`) would come back as a different bar, so it
191
+ * falls back to the plain form, which those groupings cost nothing: they select
192
+ * the same reading the bare signature does.
193
+ *
194
+ * The plain form drops the grouping, so a round trip through it reads 7/8 as
195
+ * flat rather than as 2+2+3; ask for the additive form to keep it.
196
+ *
197
+ * @param ts The time signature.
198
+ * @param opts Set `grouping: true` to render an additive grouping.
199
+ * @returns The formatted signature.
200
+ * @example
201
+ * ```ts
202
+ * import { formatTimeSignature } from '@libraz/libcantus';
203
+ * const aksak = { numerator: 7, denominator: 8, grouping: [2, 2, 3] };
204
+ * formatTimeSignature(aksak); // '7/8'
205
+ * formatTimeSignature(aksak, { grouping: true }); // '2+2+3/8'
206
+ * ```
207
+ * @category Rhythm & Meter
208
+ */
209
+ declare function formatTimeSignature(ts: TimeSignature, opts?: {
210
+ grouping?: boolean;
211
+ }): string;
212
+ /**
213
+ * Whether a meter is compound: its main pulses each divide into three, as in
214
+ * 6/8, 9/8, 12/8, or 6/4. Compound meters are those whose numerator is a
215
+ * multiple of three greater than three, independent of the denominator. Meters
216
+ * like 3/8 and 3/4 (simple triples, numerator 3) are not compound, and neither
217
+ * is a signature whose {@link TimeSignature.grouping} selects the additive
218
+ * reading (9/8 as 2+2+2+3).
219
+ *
220
+ * @param ts The time signature.
221
+ * @returns True for compound meters.
222
+ * @category Rhythm & Meter
223
+ */
224
+ declare function isCompound(ts: TimeSignature): boolean;
225
+ /**
226
+ * Length of a bar in quarter-note beats.
227
+ *
228
+ * @param ts The time signature.
229
+ * @returns The bar length in quarter notes.
230
+ * @category Rhythm & Meter
231
+ */
232
+ declare function beatsPerBar(ts: TimeSignature): number;
233
+ /**
234
+ * The time signature in force at a beat.
235
+ *
236
+ * @param beatInQuarters Absolute position in quarter-note beats.
237
+ * @param meter A single signature, or the piece's meter map.
238
+ * @returns The signature governing that beat.
239
+ * @example
240
+ * ```ts
241
+ * import { meterAt, parseTimeSignature } from '@libraz/libcantus';
242
+ * const meters = [
243
+ * { startBeat: 0, ts: parseTimeSignature('4/4') },
244
+ * { startBeat: 8, ts: parseTimeSignature('3/4') },
245
+ * ];
246
+ * meterAt(9, meters); // { numerator: 3, denominator: 4 }
247
+ * ```
248
+ * @category Rhythm & Meter
249
+ */
250
+ declare function meterAt(beatInQuarters: number, meter: MeterLike): TimeSignature;
251
+ /**
252
+ * Absolute beat at which the bar containing `beatInQuarters` begins.
253
+ *
254
+ * @param beatInQuarters Absolute position in quarter-note beats.
255
+ * @param meter A single signature, or the piece's meter map.
256
+ * @returns The bar's first beat, negative inside a pickup.
257
+ * @category Rhythm & Meter
258
+ */
259
+ declare function barStartBeat(beatInQuarters: number, meter: MeterLike): number;
260
+ /**
261
+ * Bar index of a beat: 0 for the first full bar, negative inside a pickup.
262
+ *
263
+ * Bars accumulate across meter changes, so the bar after a 4/4-to-3/4 change is
264
+ * the next bar and not the first bar of a new count.
265
+ *
266
+ * @param beatInQuarters Absolute position in quarter-note beats.
267
+ * @param meter A single signature, or the piece's meter map.
268
+ * @returns The 0-based bar index.
269
+ * @example
270
+ * ```ts
271
+ * import { barIndexAt, parseTimeSignature } from '@libraz/libcantus';
272
+ * const meters = [
273
+ * { startBeat: 0, ts: parseTimeSignature('4/4') },
274
+ * { startBeat: 8, ts: parseTimeSignature('3/4') },
275
+ * ];
276
+ * barIndexAt(11, meters); // 3
277
+ * ```
278
+ * @category Rhythm & Meter
279
+ */
280
+ declare function barIndexAt(beatInQuarters: number, meter: MeterLike): number;
281
+ /**
282
+ * Length in quarter-note beats of the bar containing a beat.
283
+ *
284
+ * The meter-map counterpart of {@link beatsPerBar}, which answers for one
285
+ * signature and so cannot be asked about a piece that changes meter.
286
+ *
287
+ * @param beatInQuarters Absolute position in quarter-note beats.
288
+ * @param meter A single signature, or the piece's meter map.
289
+ * @returns The bar length in quarter notes.
290
+ * @category Rhythm & Meter
291
+ */
292
+ declare function beatsPerBarAt(beatInQuarters: number, meter: MeterLike): number;
293
+ /**
294
+ * Read the meter out of a pair of options that accept either form.
295
+ *
296
+ * Entry points take `meters` for a piece that changes meter and keep `ts` as
297
+ * sugar for a piece that does not, so this is the one place that resolves the
298
+ * pair — including the rule that naming both is an input error rather than one
299
+ * of them silently winning.
300
+ *
301
+ * @param opts The options carrying `ts`, `meters`, or neither.
302
+ * @param name What the options belong to, for the error message.
303
+ * @returns The meter map to analyse against; 4/4 throughout when neither is given.
304
+ * @throws If both `ts` and `meters` are given, or the map is malformed.
305
+ * @example
306
+ * ```ts
307
+ * import { parseTimeSignature, resolveMeters } from '@libraz/libcantus';
308
+ * resolveMeters({ ts: parseTimeSignature('3/4') });
309
+ * // [{ startBeat: 0, ts: { numerator: 3, denominator: 4 } }]
310
+ * ```
311
+ * @category Rhythm & Meter
312
+ */
313
+ declare function resolveMeters(opts: {
314
+ ts?: TimeSignature;
315
+ meters?: MeterMap;
316
+ }, name?: string): MeterMap;
317
+ /**
318
+ * Number of main pulses (felt beats) per bar: the numerator for simple meters,
319
+ * a third of it for compound meters.
320
+ *
321
+ * For additive/irregular meters such as 7/8 or 5/8 this counts the raw pulses
322
+ * (7 and 5 respectively), which are otherwise felt as flat, evenly divided and
323
+ * equally accented pulses. To recover a 2+2+3 or 3+2 felt-beat grouping, set
324
+ * {@link TimeSignature.grouping}; {@link metricWeight} then accents each
325
+ * group's head pulse.
326
+ *
327
+ * @param ts The time signature.
328
+ * @returns The pulse count per bar.
329
+ * @category Rhythm & Meter
330
+ */
331
+ declare function pulsesPerBar(ts: TimeSignature): number;
332
+ /**
333
+ * Convert an absolute quarter-note position to a bar index and in-bar offset.
334
+ *
335
+ * @param beatInQuarters Absolute position in quarter-note beats.
336
+ * @param meter A single signature, or the piece's meter map.
337
+ * @returns The bar and in-bar quarter-note offset.
338
+ * @example
339
+ * ```ts
340
+ * import { parseTimeSignature, beatToBarPosition } from '@libraz/libcantus';
341
+ * const ts = parseTimeSignature('4/4');
342
+ * beatToBarPosition(5, ts); // { bar: 1, beat: 1 }
343
+ * ```
344
+ * @category Rhythm & Meter
345
+ */
346
+ declare function beatToBarPosition(beatInQuarters: number, meter: MeterLike): BarPosition;
347
+ /**
348
+ * Length of one felt beat (main pulse) in quarter-note beats.
349
+ *
350
+ * A quarter note in simple meters, a dotted quarter in compound ones, and one
351
+ * denominator unit in an additive metre. Position displays, click tracks, and
352
+ * score export are all written against this length.
353
+ *
354
+ * @param ts The time signature.
355
+ * @returns The pulse length in quarter-note beats.
356
+ * @example
357
+ * ```ts
358
+ * import { parseTimeSignature, pulseBeats } from '@libraz/libcantus';
359
+ * pulseBeats(parseTimeSignature('6/8')); // 1.5
360
+ * ```
361
+ * @category Rhythm & Meter
362
+ */
363
+ declare function pulseBeats(ts: TimeSignature): number;
364
+ /**
365
+ * The felt-beat number of a bar position, 1-based.
366
+ *
367
+ * {@link BarPosition.beat} is a quarter-note offset, so in 6/8 the second felt
368
+ * beat reads as 1.5. This is the number a musician says and a position display
369
+ * shows.
370
+ *
371
+ * @param pos The bar position.
372
+ * @param meter A single signature, or the piece's meter map.
373
+ * @returns The 1-based felt-beat number, fractional between pulses.
374
+ * @example
375
+ * ```ts
376
+ * import { barPositionToPulse, parseTimeSignature } from '@libraz/libcantus';
377
+ * barPositionToPulse({ bar: 0, beat: 1.5 }, parseTimeSignature('6/8')); // 2
378
+ * ```
379
+ * @category Rhythm & Meter
380
+ */
381
+ declare function barPositionToPulse(pos: BarPosition, meter: MeterLike): number;
382
+ /**
383
+ * Render an absolute position as the `bar.beat` a DAW or a score shows:
384
+ * 1-based bar, 1-based felt beat.
385
+ *
386
+ * The felt beats counted are the ones the bar actually has. A meter change
387
+ * starts a new bar, so the bar it interrupts is short, and a position that
388
+ * rounds past the end of a short bar reads as the downbeat of the next one
389
+ * rather than as a beat the bar never reached.
390
+ *
391
+ * @param beatInQuarters Absolute position in quarter-note beats.
392
+ * @param meter A single signature, or the piece's meter map.
393
+ * @param decimals Digits of the fractional beat to keep.
394
+ * @returns The formatted position, e.g. `'3.2'` for bar 3, felt beat 2.
395
+ * @example
396
+ * ```ts
397
+ * import { formatBarPosition, parseTimeSignature } from '@libraz/libcantus';
398
+ * formatBarPosition(7.5, parseTimeSignature('6/8')); // '3.2'
399
+ * ```
400
+ * @category Rhythm & Meter
401
+ */
402
+ declare function formatBarPosition(beatInQuarters: number, meter: MeterLike, decimals?: number): string;
403
+ /**
404
+ * Convert a bar index and in-bar offset back to an absolute quarter-note
405
+ * position.
406
+ *
407
+ * @param pos The bar position.
408
+ * @param meter A single signature, or the piece's meter map.
409
+ * @returns The absolute position in quarter-note beats.
410
+ * @category Rhythm & Meter
411
+ */
412
+ declare function barPositionToBeat(pos: BarPosition, meter: MeterLike): number;
413
+ /**
414
+ * Metric weight of a position within its bar, on a 0–3 scale:
415
+ * 3 the downbeat, 2 a secondary strong pulse, 1 any other main pulse, and 0 an
416
+ * off-pulse subdivision.
417
+ *
418
+ * The secondary strong pulse is the bar's midpoint in even simple/compound
419
+ * meters. For an additive/irregular meter with {@link TimeSignature.grouping}
420
+ * set (e.g. `[2, 2, 3]` for 7/8), each group's head pulse other than the
421
+ * downbeat is the secondary strong pulse instead; without a grouping every
422
+ * non-downbeat main pulse of such a meter weighs 1 (flat, evenly divided
423
+ * pulses). A grouping of equal-length groups (9/8 as `[1, 1, 1]`, 4/4 as
424
+ * `[1, 1, 1, 1]`) states the division the meter already has, so it weighs as
425
+ * an ungrouped bar rather than accenting every group head.
426
+ *
427
+ * Given a meter map, the weight follows the signature in force at that beat, so
428
+ * beat 5 of a piece is a mid-bar accent in 4/4 and a plain main pulse in 3/4.
429
+ * The downbeat is beat 0 however much pickup precedes it, so a note in the
430
+ * pickup weighs as the upbeat it is rather than as a downbeat.
431
+ *
432
+ * @param beatInQuarters Absolute quarter-note position, or an in-bar offset
433
+ * when the meter is a single signature.
434
+ * @param meter A single signature, or the piece's meter map.
435
+ * @returns The metric weight (0–3).
436
+ * @throws If the meter is malformed, including a grouping that is not a
437
+ * positive-integer list summing to the pulse count or the numerator.
438
+ * @example
439
+ * ```ts
440
+ * import { parseTimeSignature, metricWeight } from '@libraz/libcantus';
441
+ * const ts = parseTimeSignature('4/4');
442
+ * metricWeight(0, ts); // 3 (the downbeat)
443
+ * ```
444
+ * @category Rhythm & Meter
445
+ */
446
+ declare function metricWeight(beatInQuarters: number, meter: MeterLike): number;
447
+ /**
448
+ * Whether a position is metrically accented (weight 2 or more — a downbeat or a
449
+ * secondary strong pulse).
450
+ *
451
+ * @param beatInQuarters Absolute quarter-note position, or an in-bar offset
452
+ * when the meter is a single signature.
453
+ * @param meter A single signature, or the piece's meter map.
454
+ * @returns True on strong beats.
455
+ * @category Rhythm & Meter
456
+ */
457
+ declare function isStrongBeat(beatInQuarters: number, meter: MeterLike): boolean;
458
+ /**
459
+ * Subdivide a span into `count` equal tuplet durations (e.g. an eighth-note
460
+ * triplet is `tuplet(1, 3)`).
461
+ *
462
+ * @param totalBeats Total span in quarter-note beats.
463
+ * @param count Number of equal parts.
464
+ * @returns `count` equal durations summing to `totalBeats`.
465
+ * @throws If `count` is not a positive integer.
466
+ * @category Rhythm & Meter
467
+ */
468
+ declare function tuplet(totalBeats: number, count: number): number[];
469
+
470
+ export { type BarPosition as B, type MeterChange as M, type TimeSignature as T, type MeterData as a, type MeterLike as b, type MeterMap as c, barIndexAt as d, barPositionToBeat as e, barPositionToPulse as f, barStartBeat as g, beatToBarPosition as h, beatsPerBar as i, beatsPerBarAt as j, formatBarPosition as k, formatTimeSignature as l, isCompound as m, isStrongBeat as n, meterAt as o, metricWeight as p, parseTimeSignature as q, pulseBeats as r, pulsesPerBar as s, resolveMeters as t, toMeterData as u, tryParseTimeSignature as v, tuplet as w };
@@ -1,4 +1,4 @@
1
- import { d as ChordToneRole, C as Chord } from './index-C83mZI1P.js';
1
+ import { j as ChordToneRole, c as ChordLike } from './index-szBv3496.js';
2
2
 
3
3
  /**
4
4
  * Harmonic role a pitch plays within a chord.
@@ -35,15 +35,19 @@ type VoicedRole = {
35
35
  * `'tension'` — including one that is simply foreign to the chord, which this
36
36
  * single-pitch query cannot tell from a colour tone. The root locks the chord
37
37
  * identity, the third locks its quality, and everything else is free voicing.
38
- * In a suspended chord (a chord whose intervals include a 4th (5) or 2nd (2)
39
- * but no third), the suspended tone takes the third's place as the
40
- * quality-defining tone and is locked to `quality`, since moving it changes the
41
- * chord. Detecting an octave doubling requires the surrounding voicing, which
42
- * this query does not carry, so `'doubling'` is part of the type — the shared
43
- * vocabulary of harmonic roles — but is never returned here.
38
+ * Where a chord has no third, the tone standing in its place — the fourth of a
39
+ * `sus4`, the second of a `sus2`, the eleventh of an eleventh chord — takes the
40
+ * third's slot and is locked to `quality`, since moving it changes the chord.
41
+ * At most one interval class of a chord is ever reported as its third, so a
42
+ * consumer reading `lock: 'quality'` as "this tone identifies the chord" gets
43
+ * one answer rather than two. Detecting an octave doubling requires the
44
+ * surrounding voicing, which this query does not carry, so `'doubling'` is part
45
+ * of the type — the shared vocabulary of harmonic roles — but is never returned
46
+ * here.
44
47
  *
45
48
  * @param pitch MIDI pitch or bare pitch class.
46
- * @param chord The chord providing the root reference.
49
+ * @param chord The chord providing the root reference, as a chord symbol, chord
50
+ * data, or a `Chord`.
47
51
  * @param chordId Identifier stored on the result (defaults to 0).
48
52
  * @returns The pitch's role, lock level, and owning chord id.
49
53
  * @example
@@ -54,6 +58,6 @@ type VoicedRole = {
54
58
  * ```
55
59
  * @category Functional Harmony
56
60
  */
57
- declare function roleOf(pitch: number, chord: Chord, chordId?: number): VoicedRole;
61
+ declare function roleOf(pitch: number, chord: ChordLike, chordId?: number): VoicedRole;
58
62
 
59
63
  export { type HarmonyRole as H, type LockLevel as L, type VoicedRole as V, roleOf as r };