@libraz/libcantus 1.0.1 → 1.2.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 (142) hide show
  1. package/README.md +27 -65
  2. package/README_ja.md +28 -66
  3. package/dist/analyze/index.cjs +11 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +79 -144
  6. package/dist/analyze/index.d.ts +79 -144
  7. package/dist/analyze/index.js +20 -16
  8. package/dist/chunk-35NBV2FT.cjs +145 -0
  9. package/dist/chunk-35NBV2FT.cjs.map +1 -0
  10. package/dist/{chunk-UADYAYAT.cjs → chunk-3R3QVKY5.cjs} +1353 -580
  11. package/dist/chunk-3R3QVKY5.cjs.map +1 -0
  12. package/dist/{chunk-WWURE4XT.cjs → chunk-76ZBTRG2.cjs} +624 -729
  13. package/dist/chunk-76ZBTRG2.cjs.map +1 -0
  14. package/dist/{chunk-FVSI36UV.js → chunk-7KG3RTYS.js} +197 -110
  15. package/dist/chunk-7KG3RTYS.js.map +1 -0
  16. package/dist/{chunk-VTI6FOLB.js → chunk-AGOVW7U6.js} +709 -133
  17. package/dist/chunk-AGOVW7U6.js.map +1 -0
  18. package/dist/{chunk-E3F4AHAH.cjs → chunk-CGBADIO5.cjs} +221 -134
  19. package/dist/chunk-CGBADIO5.cjs.map +1 -0
  20. package/dist/{chunk-6XH6QZYQ.cjs → chunk-DSMJRXCZ.cjs} +1455 -849
  21. package/dist/chunk-DSMJRXCZ.cjs.map +1 -0
  22. package/dist/{chunk-PKFNUHDY.js → chunk-FBH75DAY.js} +1218 -612
  23. package/dist/chunk-FBH75DAY.js.map +1 -0
  24. package/dist/chunk-H2KJHBW4.js +3329 -0
  25. package/dist/chunk-H2KJHBW4.js.map +1 -0
  26. package/dist/chunk-HPVSH7SF.cjs +2294 -0
  27. package/dist/chunk-HPVSH7SF.cjs.map +1 -0
  28. package/dist/{chunk-MXO72PLY.cjs → chunk-HWHGOVO6.cjs} +21 -19
  29. package/dist/chunk-HWHGOVO6.cjs.map +1 -0
  30. package/dist/chunk-HYJJ2V2I.js +2294 -0
  31. package/dist/chunk-HYJJ2V2I.js.map +1 -0
  32. package/dist/{chunk-AFM2ULJH.cjs → chunk-J7FHVZII.cjs} +1567 -1067
  33. package/dist/chunk-J7FHVZII.cjs.map +1 -0
  34. package/dist/chunk-K6OZXIR6.js +1 -0
  35. package/dist/{chunk-H3VORETI.js → chunk-M5RYMAFI.js} +487 -592
  36. package/dist/chunk-M5RYMAFI.js.map +1 -0
  37. package/dist/chunk-NB25P3EH.js +363 -0
  38. package/dist/chunk-NB25P3EH.js.map +1 -0
  39. package/dist/{chunk-TTCLJX6D.js → chunk-NFJ4P6ZZ.js} +10 -8
  40. package/dist/chunk-NFJ4P6ZZ.js.map +1 -0
  41. package/dist/chunk-NM7UAMC3.cjs +457 -0
  42. package/dist/chunk-NM7UAMC3.cjs.map +1 -0
  43. package/dist/chunk-PM4XJE2Y.cjs +363 -0
  44. package/dist/chunk-PM4XJE2Y.cjs.map +1 -0
  45. package/dist/chunk-PUKJP2Z5.js +145 -0
  46. package/dist/chunk-PUKJP2Z5.js.map +1 -0
  47. package/dist/{chunk-VOHZB45S.js → chunk-Q6LFSAKV.js} +1321 -821
  48. package/dist/chunk-Q6LFSAKV.js.map +1 -0
  49. package/dist/{chunk-INHVXP6Z.js → chunk-RFIBF2RR.js} +1203 -430
  50. package/dist/chunk-RFIBF2RR.js.map +1 -0
  51. package/dist/{chunk-Q2WGKJNN.cjs → chunk-S5BKZZGM.cjs} +699 -123
  52. package/dist/chunk-S5BKZZGM.cjs.map +1 -0
  53. package/dist/chunk-SGLEQVJH.cjs +3329 -0
  54. package/dist/chunk-SGLEQVJH.cjs.map +1 -0
  55. package/dist/chunk-UGLFDG7L.cjs +1 -0
  56. package/dist/chunk-UGLFDG7L.cjs.map +1 -0
  57. package/dist/{chunk-YH3BIKHH.js → chunk-UMWZ4ZET.js} +146 -49
  58. package/dist/chunk-UMWZ4ZET.js.map +1 -0
  59. package/dist/{index-szBv3496.d.ts → coerce-DP0vYu-x.d.ts} +286 -199
  60. package/dist/{index-C_8o--VE.d.cts → coerce-DRERzdve.d.cts} +286 -199
  61. package/dist/core/index.cjs +9 -5
  62. package/dist/core/index.cjs.map +1 -1
  63. package/dist/core/index.d.cts +122 -108
  64. package/dist/core/index.d.ts +122 -108
  65. package/dist/core/index.js +32 -28
  66. package/dist/generate/index.cjs +8 -8
  67. package/dist/generate/index.d.cts +168 -84
  68. package/dist/generate/index.d.ts +168 -84
  69. package/dist/generate/index.js +7 -7
  70. package/dist/{index-CGpRv5sl.d.cts → index-9eoQs2C1.d.ts} +34 -19
  71. package/dist/{index-CCNJRG-P.d.cts → index-B9QLziDe.d.cts} +293 -56
  72. package/dist/{index-Dzr13q3d.d.cts → index-BBWNZS0f.d.cts} +135 -58
  73. package/dist/{index-9wcMhG73.d.ts → index-BHIUyjhZ.d.ts} +293 -56
  74. package/dist/{index-BGFW-8P2.d.cts → index-BJgP97N1.d.ts} +196 -114
  75. package/dist/{index-CunYKLiu.d.ts → index-BL5N2Oyz.d.cts} +1 -1
  76. package/dist/{index-Cj49F892.d.ts → index-BMweUlm5.d.cts} +63 -23
  77. package/dist/{index-CgHqxdps.d.ts → index-BNSM-DSk.d.cts} +196 -114
  78. package/dist/{index-D57QRbVn.d.ts → index-BRMbPkHE.d.ts} +480 -254
  79. package/dist/{index-Chbst3Jx.d.ts → index-CJBBiAmU.d.ts} +135 -58
  80. package/dist/{index-BkGmlyI3.d.cts → index-CL4b4gUQ.d.ts} +63 -23
  81. package/dist/{index-B9MNZboQ.d.ts → index-Cy15oTvh.d.cts} +52 -22
  82. package/dist/{index-B9MNZboQ.d.cts → index-Cy15oTvh.d.ts} +52 -22
  83. package/dist/{index-BO6xE9YU.d.cts → index-DGCNKAUr.d.cts} +480 -254
  84. package/dist/{index-B4o55NDr.d.cts → index-Dw2DP7vm.d.ts} +1 -1
  85. package/dist/{index-G1uwGGWQ.d.ts → index-cHvbYgJI.d.cts} +34 -19
  86. package/dist/index.cjs +42 -14
  87. package/dist/index.cjs.map +1 -1
  88. package/dist/index.d.cts +14 -14
  89. package/dist/index.d.ts +14 -14
  90. package/dist/index.js +82 -54
  91. package/dist/{masks-DYbE485J.d.cts → masks-Cc7-MzzY.d.ts} +49 -2
  92. package/dist/{masks-DYbE485J.d.ts → masks-pADfTOiD.d.cts} +49 -2
  93. package/dist/model/index.cjs +19 -12
  94. package/dist/model/index.cjs.map +1 -1
  95. package/dist/model/index.d.cts +504 -182
  96. package/dist/model/index.d.ts +504 -182
  97. package/dist/model/index.js +18 -11
  98. package/dist/{positional-Cptlj-xs.d.ts → positional-DJgs6ltD.d.ts} +85 -8
  99. package/dist/{positional-DvH_sd8u.d.cts → positional-DMZer-FM.d.cts} +85 -8
  100. package/dist/theory/index.cjs +35 -6
  101. package/dist/theory/index.cjs.map +1 -1
  102. package/dist/theory/index.d.cts +257 -62
  103. package/dist/theory/index.d.ts +257 -62
  104. package/dist/theory/index.js +41 -12
  105. package/package.json +7 -5
  106. package/dist/chunk-2LCPM3EG.js +0 -3224
  107. package/dist/chunk-2LCPM3EG.js.map +0 -1
  108. package/dist/chunk-6XH6QZYQ.cjs.map +0 -1
  109. package/dist/chunk-6XPTBE7Y.cjs +0 -49
  110. package/dist/chunk-6XPTBE7Y.cjs.map +0 -1
  111. package/dist/chunk-AFM2ULJH.cjs.map +0 -1
  112. package/dist/chunk-B6XNKWZV.cjs +0 -3224
  113. package/dist/chunk-B6XNKWZV.cjs.map +0 -1
  114. package/dist/chunk-E3F4AHAH.cjs.map +0 -1
  115. package/dist/chunk-ELCTZUJJ.js +0 -379
  116. package/dist/chunk-ELCTZUJJ.js.map +0 -1
  117. package/dist/chunk-FVSI36UV.js.map +0 -1
  118. package/dist/chunk-H3VORETI.js.map +0 -1
  119. package/dist/chunk-H42UHPYW.js +0 -1577
  120. package/dist/chunk-H42UHPYW.js.map +0 -1
  121. package/dist/chunk-HFPS7JFD.js +0 -1
  122. package/dist/chunk-INHVXP6Z.js.map +0 -1
  123. package/dist/chunk-K4ZJUGF4.cjs +0 -379
  124. package/dist/chunk-K4ZJUGF4.cjs.map +0 -1
  125. package/dist/chunk-KNJEKLKV.js +0 -49
  126. package/dist/chunk-KNJEKLKV.js.map +0 -1
  127. package/dist/chunk-MXO72PLY.cjs.map +0 -1
  128. package/dist/chunk-NLEU4QSE.cjs +0 -360
  129. package/dist/chunk-NLEU4QSE.cjs.map +0 -1
  130. package/dist/chunk-OE6WK2Y2.cjs +0 -1577
  131. package/dist/chunk-OE6WK2Y2.cjs.map +0 -1
  132. package/dist/chunk-PKFNUHDY.js.map +0 -1
  133. package/dist/chunk-Q2WGKJNN.cjs.map +0 -1
  134. package/dist/chunk-RHIJ3S4I.cjs +0 -1
  135. package/dist/chunk-RHIJ3S4I.cjs.map +0 -1
  136. package/dist/chunk-TTCLJX6D.js.map +0 -1
  137. package/dist/chunk-UADYAYAT.cjs.map +0 -1
  138. package/dist/chunk-VOHZB45S.js.map +0 -1
  139. package/dist/chunk-VTI6FOLB.js.map +0 -1
  140. package/dist/chunk-WWURE4XT.cjs.map +0 -1
  141. package/dist/chunk-YH3BIKHH.js.map +0 -1
  142. /package/dist/{chunk-HFPS7JFD.js.map → chunk-K6OZXIR6.js.map} +0 -0
@@ -40,8 +40,24 @@ function isLibcantusError(value) {
40
40
  return code === "INVALID_INPUT" || code === "NO_SOLUTION" || code === "BUDGET_EXCEEDED";
41
41
  }
42
42
 
43
+ // src/core/instrument/articulation.ts
44
+ var ARTICULATIONS = Object.freeze([
45
+ "accent",
46
+ "ghost",
47
+ "staccato",
48
+ "legato",
49
+ "slide",
50
+ "hammer",
51
+ "mute",
52
+ "flam",
53
+ "drag",
54
+ "roll",
55
+ "choke",
56
+ "open"
57
+ ]);
58
+
43
59
  // src/core/meter/internal.ts
44
- var EPS = 1e-9;
60
+ var BEAT_EPS = 1e-9;
45
61
  function unitBeatsOf(ts) {
46
62
  return 4 / ts.denominator;
47
63
  }
@@ -96,86 +112,195 @@ function barBeatsOf(ts) {
96
112
  function isMeterMap(meter) {
97
113
  return Array.isArray(meter);
98
114
  }
99
- function entryIndexOf(map, beat) {
100
- let index = 0;
101
- for (let i = 1; i < map.length; i += 1) {
102
- if ((_nullishCoalesce(_optionalChain([map, 'access', _ => _[i], 'optionalAccess', _2 => _2.startBeat]), () => ( Number.POSITIVE_INFINITY))) > beat + EPS) {
103
- break;
104
- }
105
- index = i;
115
+ function copyTimeSignature(ts) {
116
+ return ts.grouping === void 0 ? { numerator: ts.numerator, denominator: ts.denominator } : { numerator: ts.numerator, denominator: ts.denominator, grouping: [...ts.grouping] };
117
+ }
118
+ function copyMeterMap(map) {
119
+ const copy = new Array(map.length);
120
+ for (let i = 0; i < map.length; i += 1) {
121
+ const entry = map[i];
122
+ copy[i] = entry === void 0 ? { startBeat: 0, ts: { numerator: 4, denominator: 4 } } : { startBeat: entry.startBeat, ts: copyTimeSignature(entry.ts) };
106
123
  }
124
+ return copy;
125
+ }
126
+ function copyMeterData(data) {
127
+ return isMeterMap(data) ? copyMeterMap(data) : copyTimeSignature(data);
128
+ }
129
+ var INDEX_CACHE = /* @__PURE__ */ new WeakMap();
130
+ var readMap;
131
+ var readIndex;
132
+ function rememberRead(map, index) {
133
+ readMap = map;
134
+ readIndex = index;
107
135
  return index;
108
136
  }
109
- function barsBeforeEntry(map, index) {
137
+ function sameSignature(ts, snapshot) {
138
+ if (typeof ts !== "object" || ts === null) {
139
+ return false;
140
+ }
141
+ if (ts.numerator !== snapshot.numerator || ts.denominator !== snapshot.denominator) {
142
+ return false;
143
+ }
144
+ const grouping = ts.grouping;
145
+ const was = snapshot.grouping;
146
+ if (grouping === void 0 || was === void 0) {
147
+ return grouping === was;
148
+ }
149
+ if (grouping.length !== was.length) {
150
+ return false;
151
+ }
152
+ for (let i = 0; i < was.length; i += 1) {
153
+ if (grouping[i] !== was[i]) {
154
+ return false;
155
+ }
156
+ }
157
+ return true;
158
+ }
159
+ function describesMap(index, map) {
160
+ if (index.startBeats.length !== map.length) {
161
+ return false;
162
+ }
163
+ for (let i = 0; i < map.length; i += 1) {
164
+ const entry = map[i];
165
+ const signature = index.signatures[i];
166
+ if (entry === void 0 || entry === null || signature === void 0 || entry.startBeat !== index.startBeats[i] || !sameSignature(entry.ts, signature)) {
167
+ return false;
168
+ }
169
+ }
170
+ return true;
171
+ }
172
+ function buildMeterIndex(map, validated) {
173
+ const startBeats = new Array(map.length);
174
+ const signatures = new Array(map.length);
175
+ const barAnchors = new Array(map.length);
176
+ const barBeats = new Array(map.length);
177
+ const barsBefore = new Array(map.length);
110
178
  let bars = 0;
111
- for (let i = 0; i < index; i += 1) {
179
+ for (let i = 0; i < map.length; i += 1) {
112
180
  const entry = map[i];
181
+ const startBeat = _nullishCoalesce(_optionalChain([entry, 'optionalAccess', _ => _.startBeat]), () => ( 0));
182
+ const barLen = entry === void 0 ? 0 : barBeatsOf(entry.ts);
183
+ const anchor = i === 0 ? 0 : startBeat;
184
+ startBeats[i] = startBeat;
185
+ signatures[i] = entry === void 0 ? { numerator: 4, denominator: 4 } : copyTimeSignature(entry.ts);
186
+ barAnchors[i] = anchor;
187
+ barBeats[i] = barLen;
188
+ barsBefore[i] = bars;
113
189
  const next = map[i + 1];
114
- if (entry === void 0 || next === void 0) {
115
- break;
190
+ if (next !== void 0 && barLen > 0) {
191
+ bars += Math.max(1, Math.ceil((next.startBeat - anchor) / barLen - BEAT_EPS));
192
+ }
193
+ }
194
+ const index = { startBeats, signatures, barAnchors, barBeats, barsBefore, validated };
195
+ INDEX_CACHE.set(map, index);
196
+ return rememberRead(map, index);
197
+ }
198
+ function meterIndexOf(map) {
199
+ if (readMap === map && readIndex !== void 0) {
200
+ return readIndex;
201
+ }
202
+ const cached = INDEX_CACHE.get(map);
203
+ return cached !== void 0 && describesMap(cached, map) ? rememberRead(map, cached) : buildMeterIndex(map, false);
204
+ }
205
+ function isValidatedMeterMap(map) {
206
+ const cached = INDEX_CACHE.get(map);
207
+ if (_optionalChain([cached, 'optionalAccess', _2 => _2.validated]) !== true || !describesMap(cached, map)) {
208
+ return false;
209
+ }
210
+ rememberRead(map, cached);
211
+ return true;
212
+ }
213
+ function rememberValidatedMeterMap(map) {
214
+ buildMeterIndex(map, true);
215
+ }
216
+ function lastAtOrBefore(keys, value) {
217
+ let low = 1;
218
+ let high = keys.length - 1;
219
+ let index = 0;
220
+ while (low <= high) {
221
+ const mid = low + high >>> 1;
222
+ if ((_nullishCoalesce(keys[mid], () => ( Number.POSITIVE_INFINITY))) <= value) {
223
+ index = mid;
224
+ low = mid + 1;
225
+ } else {
226
+ high = mid - 1;
116
227
  }
117
- bars += Math.max(1, Math.ceil((next.startBeat - entry.startBeat) / barBeatsOf(entry.ts) - EPS));
118
228
  }
119
- return bars;
229
+ return index;
230
+ }
231
+ function entryIndexOf(map, beat) {
232
+ return lastAtOrBefore(meterIndexOf(map).startBeats, beat + BEAT_EPS);
120
233
  }
121
234
  function barStartOf(map, beat) {
122
- const entry = map[entryIndexOf(map, beat)];
123
- if (entry === void 0) {
235
+ const index = meterIndexOf(map);
236
+ const at = lastAtOrBefore(index.startBeats, beat + BEAT_EPS);
237
+ const anchor = index.barAnchors[at];
238
+ const barLen = index.barBeats[at];
239
+ if (anchor === void 0 || barLen === void 0 || barLen === 0) {
124
240
  return 0;
125
241
  }
126
- const barLen = barBeatsOf(entry.ts);
127
- return entry.startBeat + Math.floor((beat - entry.startBeat) / barLen + EPS) * barLen;
242
+ return anchor + Math.floor((beat - anchor) / barLen + BEAT_EPS) * barLen;
128
243
  }
129
244
  function barLengthOf(map, beat) {
130
- const index = entryIndexOf(map, beat);
131
- const entry = map[index];
132
- if (entry === void 0) {
245
+ const index = meterIndexOf(map);
246
+ const at = lastAtOrBefore(index.startBeats, beat + BEAT_EPS);
247
+ const full = index.barBeats[at];
248
+ if (full === void 0) {
133
249
  return 0;
134
250
  }
135
- const full = barBeatsOf(entry.ts);
136
- const next = _optionalChain([map, 'access', _3 => _3[index + 1], 'optionalAccess', _4 => _4.startBeat]);
251
+ const next = index.startBeats[at + 1];
137
252
  return next === void 0 ? full : Math.min(full, next - barStartOf(map, beat));
138
253
  }
139
254
  function barIndexOf(map, beat) {
140
- const index = entryIndexOf(map, beat);
141
- const entry = map[index];
142
- if (entry === void 0) {
255
+ const index = meterIndexOf(map);
256
+ const at = lastAtOrBefore(index.startBeats, beat + BEAT_EPS);
257
+ const anchor = index.barAnchors[at];
258
+ const barLen = index.barBeats[at];
259
+ if (anchor === void 0 || barLen === void 0 || barLen === 0) {
143
260
  return 0;
144
261
  }
145
- const barLen = barBeatsOf(entry.ts);
146
- return barsBeforeEntry(map, index) + Math.floor((beat - entry.startBeat) / barLen + EPS);
262
+ return (_nullishCoalesce(index.barsBefore[at], () => ( 0))) + Math.floor((beat - anchor) / barLen + BEAT_EPS);
147
263
  }
148
264
  function beatOfBarIndex(map, barIndex) {
149
- let base = 0;
150
- for (let i = 0; i < map.length; i += 1) {
151
- const entry = map[i];
152
- if (entry === void 0) {
153
- continue;
154
- }
155
- const barLen = barBeatsOf(entry.ts);
156
- const next = map[i + 1];
157
- if (next === void 0) {
158
- return entry.startBeat + (barIndex - base) * barLen;
159
- }
160
- const bars = Math.max(1, Math.ceil((next.startBeat - entry.startBeat) / barLen - EPS));
161
- if (barIndex < base + bars) {
162
- return entry.startBeat + (barIndex - base) * barLen;
163
- }
164
- base += bars;
265
+ const index = meterIndexOf(map);
266
+ const at = lastAtOrBefore(index.barsBefore, barIndex);
267
+ const anchor = index.barAnchors[at];
268
+ const barLen = index.barBeats[at];
269
+ if (anchor === void 0 || barLen === void 0) {
270
+ return 0;
165
271
  }
166
- return 0;
272
+ return anchor + (barIndex - (_nullishCoalesce(index.barsBefore[at], () => ( 0)))) * barLen;
167
273
  }
168
274
 
169
275
  // src/core/validation/index.ts
170
276
  var DEFAULT_GENERATION_BUDGET = 1e6;
277
+ var MAX_METER_CHANGES = 1e5;
278
+ var MAX_ECHOED_LENGTH = 64;
279
+ function describeRejected(value) {
280
+ if (value === null) {
281
+ return "null";
282
+ }
283
+ if (typeof value !== "string") {
284
+ return typeof value;
285
+ }
286
+ return value.length <= MAX_ECHOED_LENGTH ? JSON.stringify(value) : `${JSON.stringify(value.slice(0, MAX_ECHOED_LENGTH))} (truncated from ${value.length} characters)`;
287
+ }
171
288
  function assertFiniteNumber(value, name) {
172
289
  if (!Number.isFinite(value)) {
173
290
  throw new InvalidInputError(`${name} must be finite; received ${value}`);
174
291
  }
175
292
  return value;
176
293
  }
294
+ function assertBounds(min, max, name) {
295
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
296
+ throw new InvalidInputError(
297
+ `${name} must be bounded by finite numbers; received [${describeRejected(min)}, ${describeRejected(max)}]`
298
+ );
299
+ }
300
+ }
177
301
  function assertInteger(value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
178
302
  assertFiniteNumber(value, name);
303
+ assertBounds(min, max, name);
179
304
  if (!Number.isSafeInteger(value) || value < min || value > max) {
180
305
  throw new InvalidInputError(
181
306
  `${name} must be an integer in [${min}, ${max}]; received ${value}`
@@ -186,6 +311,9 @@ function assertInteger(value, name, min = Number.MIN_SAFE_INTEGER, max = Number.
186
311
  function assertMidiPitch(value, name = "MIDI pitch") {
187
312
  return assertInteger(value, name, 0, 127);
188
313
  }
314
+ function assertPitchClass(value, name = "pitch class") {
315
+ return assertInteger(value, name, 0, 11);
316
+ }
189
317
  function clampToMidi(value, name = "MIDI pitch") {
190
318
  assertInteger(value, name);
191
319
  return Math.min(127, Math.max(0, value));
@@ -197,13 +325,43 @@ function assertFiniteSemitones(value, name = "semitones") {
197
325
  return assertFiniteNumber(value, name);
198
326
  }
199
327
  function dropSilentNotes(events) {
200
- return events.filter((event) => event !== void 0 && event.durationBeat > 0);
328
+ return assertArray(events, "events").filter(
329
+ (event) => event !== void 0 && event !== null && event.durationBeat > 0
330
+ );
201
331
  }
202
332
  var soundingNotesOnly = dropSilentNotes;
333
+ function assertArray(value, name) {
334
+ if (!Array.isArray(value)) {
335
+ throw new InvalidInputError(`${name} must be an array; received ${describeRejected(value)}`);
336
+ }
337
+ return value;
338
+ }
339
+ function assertRecord(value, name) {
340
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
341
+ throw new InvalidInputError(`${name} must be an object; received ${describeRejected(value)}`);
342
+ }
343
+ return value;
344
+ }
345
+ function assertOptions(value, name = "options") {
346
+ return value === void 0 ? {} : assertRecord(value, name);
347
+ }
348
+ function assertFlag(value, name) {
349
+ if (typeof value !== "boolean") {
350
+ throw new InvalidInputError(`${name} must be a boolean; received ${describeRejected(value)}`);
351
+ }
352
+ return value;
353
+ }
354
+ function assertFunction(value, name) {
355
+ if (typeof value !== "function") {
356
+ throw new InvalidInputError(`${name} must be a function; received ${describeRejected(value)}`);
357
+ }
358
+ return value;
359
+ }
203
360
  function assertOneOf(value, allowed, name) {
204
- if (typeof value !== "string" || !allowed.includes(value)) {
361
+ const names = assertArray(allowed, `${name} allowed values`);
362
+ if (typeof value !== "string" || !names.includes(value)) {
205
363
  throw new InvalidInputError(
206
- `${name} must be one of ${allowed.join(", ")}; received ${JSON.stringify(value)}`
364
+ `${name} must be one of ${names.join(", ")}; received ${describeRejected(value)}`
207
365
  );
208
366
  }
209
367
  return value;
@@ -213,13 +371,14 @@ function assertPositiveInt(value, name, max = DEFAULT_GENERATION_BUDGET) {
213
371
  }
214
372
  function assertRange(value, min, max, name) {
215
373
  assertFiniteNumber(value, name);
374
+ assertBounds(min, max, name);
216
375
  if (value < min || value > max) {
217
376
  throw new InvalidInputError(`${name} must be in [${min}, ${max}]; received ${value}`);
218
377
  }
219
378
  return value;
220
379
  }
221
380
  function assertGenerationBudget(estimated, name, limit = DEFAULT_GENERATION_BUDGET) {
222
- const cap = _nullishCoalesce(limit, () => ( DEFAULT_GENERATION_BUDGET));
381
+ const cap = limit === void 0 ? DEFAULT_GENERATION_BUDGET : limit;
223
382
  assertFiniteNumber(estimated, name);
224
383
  assertPositiveInt(cap, `${name} limit`, Number.MAX_SAFE_INTEGER);
225
384
  if (estimated < 0) {
@@ -232,10 +391,31 @@ function assertGenerationBudget(estimated, name, limit = DEFAULT_GENERATION_BUDG
232
391
  }
233
392
  return estimated;
234
393
  }
394
+ function assertTableSize(rows, columns, name, budget) {
395
+ assertFiniteNumber(rows, `${name} rows`);
396
+ assertFiniteNumber(columns, `${name} columns`);
397
+ return assertGenerationBudget(rows * columns, name, budget);
398
+ }
399
+ function allocateCandidateTable(rows, columns, name, budget) {
400
+ return new Float64Array(assertTableSize(rows, columns, name, budget));
401
+ }
402
+ function allocateChoiceTable(rows, columns, name, budget) {
403
+ return new Int32Array(assertTableSize(rows, columns, name, budget));
404
+ }
235
405
  function assertTimeSignature(ts, name = "time signature") {
406
+ if (typeof ts !== "object" || ts === null) {
407
+ throw new InvalidInputError(
408
+ `${name} must be a time signature; received ${describeRejected(ts)}`
409
+ );
410
+ }
236
411
  assertPositiveInt(ts.numerator, `${name}.numerator`);
237
412
  assertPositiveInt(ts.denominator, `${name}.denominator`);
238
413
  if (ts.grouping !== void 0) {
414
+ if (!Array.isArray(ts.grouping)) {
415
+ throw new InvalidInputError(
416
+ `${name}.grouping must be an array of group lengths; received ${describeRejected(ts.grouping)}`
417
+ );
418
+ }
239
419
  if (ts.grouping.length === 0) {
240
420
  throw new InvalidInputError(`${name}.grouping must not be empty`);
241
421
  }
@@ -258,11 +438,17 @@ function assertMeterMap(meters, name = "meters") {
258
438
  if (meters.length === 0) {
259
439
  throw new InvalidInputError(`${name} must not be empty`);
260
440
  }
441
+ assertGenerationBudget(meters.length, `${name} count`, MAX_METER_CHANGES);
442
+ if (isValidatedMeterMap(meters)) {
443
+ return meters;
444
+ }
261
445
  let previous = Number.NEGATIVE_INFINITY;
262
446
  for (let index = 0; index < meters.length; index += 1) {
263
447
  const entry = meters[index];
264
- if (entry === void 0) {
265
- throw new InvalidInputError(`${name}[${index}] must be a meter change; received undefined`);
448
+ if (typeof entry !== "object" || entry === null) {
449
+ throw new InvalidInputError(
450
+ `${name}[${index}] must be a meter change; received ${describeRejected(entry)}`
451
+ );
266
452
  }
267
453
  assertFiniteNumber(entry.startBeat, `${name}[${index}].startBeat`);
268
454
  if (index > 0 && entry.startBeat <= previous) {
@@ -273,15 +459,22 @@ function assertMeterMap(meters, name = "meters") {
273
459
  previous = entry.startBeat;
274
460
  assertTimeSignature(entry.ts, `${name}[${index}].ts`);
275
461
  }
462
+ rememberValidatedMeterMap(meters);
276
463
  return meters;
277
464
  }
278
465
  function assertNoteEvent(event, name = "note event", options = {}) {
466
+ const asked = assertOptions(options, `${name} options`);
467
+ if (typeof event !== "object" || event === null) {
468
+ throw new InvalidInputError(
469
+ `${name} must be a note event; received ${describeRejected(event)}`
470
+ );
471
+ }
279
472
  assertMidiPitch(event.pitch, `${name}.pitch`);
280
- const minStartBeat = _nullishCoalesce(options.minStartBeat, () => ( -Number.MAX_SAFE_INTEGER));
473
+ const minStartBeat = _nullishCoalesce(asked.minStartBeat, () => ( -Number.MAX_SAFE_INTEGER));
281
474
  assertFiniteNumber(minStartBeat, "minStartBeat");
282
475
  assertRange(event.startBeat, minStartBeat, Number.MAX_SAFE_INTEGER, `${name}.startBeat`);
283
476
  assertFiniteNumber(event.durationBeat, `${name}.durationBeat`);
284
- if (!options.allowNonPositiveDuration && event.durationBeat <= 0) {
477
+ if (!asked.allowNonPositiveDuration && event.durationBeat <= 0) {
285
478
  throw new InvalidInputError(
286
479
  `${name}.durationBeat must be positive; received ${event.durationBeat}`
287
480
  );
@@ -293,21 +486,27 @@ function assertNoteEvent(event, name = "note event", options = {}) {
293
486
  `${name}.durationBeat`
294
487
  );
295
488
  if (event.velocity !== void 0) {
296
- assertRange(event.velocity, 0, 127, `${name}.velocity`);
489
+ assertInteger(event.velocity, `${name}.velocity`, 0, 127);
490
+ }
491
+ if (event.articulation !== void 0) {
492
+ assertOneOf(event.articulation, ARTICULATIONS, `${name}.articulation`);
297
493
  }
298
494
  return event;
299
495
  }
300
496
  function assertNoteEvents(events, name = "note events", options = {}) {
497
+ const asked = assertOptions(options, `${name} options`);
301
498
  if (!Array.isArray(events)) {
302
499
  throw new InvalidInputError(`${name} must be an array; received ${typeof events}`);
303
500
  }
304
- assertGenerationBudget(events.length, `${name} count`, options.budget);
501
+ assertGenerationBudget(events.length, `${name} count`, asked.budget);
305
502
  for (let index = 0; index < events.length; index += 1) {
306
503
  const event = events[index];
307
- if (event === void 0) {
308
- throw new InvalidInputError(`${name}[${index}] must be a note event; received undefined`);
504
+ if (typeof event !== "object" || event === null) {
505
+ throw new InvalidInputError(
506
+ `${name}[${index}] must be a note event; received ${describeRejected(event)}`
507
+ );
309
508
  }
310
- assertNoteEvent(event, `${name}[${index}]`, options);
509
+ assertNoteEvent(event, `${name}[${index}]`, asked);
311
510
  }
312
511
  return events;
313
512
  }
@@ -343,6 +542,30 @@ var JAPANESE_DOUBLE = "\u91CD";
343
542
  var ITALIAN_SHARP = "diesis";
344
543
  var ITALIAN_FLAT = "bemolle";
345
544
  var ITALIAN_DOUBLE = "doppio";
545
+ var MAX_NAME_ACCIDENTALS = 2;
546
+ function longestGlyph(glyphs) {
547
+ return Math.max(...glyphs.map((glyph) => glyph.length));
548
+ }
549
+ var MAX_LETTER_LENGTH = {
550
+ english: longestGlyph(ENGLISH_LETTERS),
551
+ german: longestGlyph(GERMAN_LETTERS),
552
+ japanese: longestGlyph(JAPANESE_LETTERS),
553
+ italian: longestGlyph(ITALIAN_LETTERS)
554
+ };
555
+ var MAX_ACCIDENTAL_LENGTH = {
556
+ /** `#`, `x` and `b`. */
557
+ english: 1,
558
+ /** The `-is` and `-es` affixes, whose first mark may elide to a bare `s`. */
559
+ german: 2,
560
+ /** 嬰 and 変; 重 stands in for the second mark of a double, not beside it. */
561
+ japanese: 1,
562
+ /** A space and the accidental word; `doppio` covers two marks in one word. */
563
+ italian: 1 + Math.max(ITALIAN_SHARP.length, ITALIAN_FLAT.length)
564
+ };
565
+ function maxNoteNameLength(system) {
566
+ const table = tableOf(assertSystem(system));
567
+ return MAX_LETTER_LENGTH[table] + MAX_NAME_ACCIDENTALS * MAX_ACCIDENTAL_LENGTH[table];
568
+ }
346
569
  function normalize(text) {
347
570
  return text.trim().replace(/\s+/g, " ");
348
571
  }
@@ -498,12 +721,19 @@ function formatItalian(note) {
498
721
  const accidental = marks === 2 ? `${ITALIAN_DOUBLE} ${word}` : Array.from({ length: marks }, () => word).join(" ");
499
722
  return `${glyph} ${accidental}`;
500
723
  }
724
+ function isDigit(ch) {
725
+ return ch >= "0" && ch <= "9";
726
+ }
501
727
  function splitOctave(text) {
502
- const match = text.match(/^(.*?)(-?\d+)$/);
503
- if (match === null) {
728
+ let start = text.length;
729
+ while (start > 0 && isDigit(text.charAt(start - 1))) {
730
+ start -= 1;
731
+ }
732
+ if (start === text.length) {
504
733
  return { name: text, octave: void 0 };
505
734
  }
506
- return { name: _nullishCoalesce(match[1], () => ( "")), octave: Number.parseInt(_nullishCoalesce(match[2], () => ( "0")), 10) };
735
+ const signed = start > 0 && text.charAt(start - 1) === "-" ? start - 1 : start;
736
+ return { name: text.slice(0, signed), octave: Number.parseInt(text.slice(signed), 10) };
507
737
  }
508
738
  function parseIn(text, system) {
509
739
  const table = tableOf(system);
@@ -518,6 +748,13 @@ function parseIn(text, system) {
518
748
  }
519
749
  return octave === void 0 ? note : { ...note, octave };
520
750
  }
751
+ function trimSeparators(text) {
752
+ let end = text.length;
753
+ while (end > 0 && /[\s-]/.test(text.charAt(end - 1))) {
754
+ end -= 1;
755
+ }
756
+ return text.slice(0, end);
757
+ }
521
758
  function splitModeWord(text) {
522
759
  const lower = text.toLowerCase();
523
760
  let best;
@@ -533,27 +770,31 @@ function splitModeWord(text) {
533
770
  return { tonic: text, mode: void 0, system: void 0 };
534
771
  }
535
772
  return {
536
- tonic: text.slice(0, text.length - best.word.length).replace(/[\s-]+$/, ""),
773
+ tonic: trimSeparators(text.slice(0, text.length - best.word.length)),
537
774
  mode: best.mode,
538
775
  system: best.system
539
776
  };
540
777
  }
541
778
  function resolveSystem(text) {
542
779
  const { tonic, system: wordSystem } = splitModeWord(text);
543
- const accepted = DETECTION_ORDER.filter((system) => parseIn(tonic, system) !== null);
544
- const first = accepted[0];
545
- if (first === void 0) {
780
+ if (wordSystem === void 0) {
781
+ for (const system of DETECTION_ORDER) {
782
+ if (parseIn(tonic, system) !== null) {
783
+ return system;
784
+ }
785
+ }
546
786
  return null;
547
787
  }
548
- if (wordSystem === void 0) {
549
- return first;
788
+ if (parseIn(tonic, wordSystem) !== null) {
789
+ return wordSystem;
550
790
  }
551
- if (!accepted.includes(wordSystem)) {
552
- throw new InvalidInputError(
553
- `${JSON.stringify(text)} mixes note-name systems: ${JSON.stringify(tonic)} is ${accepted.join(" or ")} but its mode word is ${wordSystem}`
554
- );
791
+ const accepted = DETECTION_ORDER.filter((system) => parseIn(tonic, system) !== null);
792
+ if (accepted.length === 0) {
793
+ return null;
555
794
  }
556
- return wordSystem;
795
+ throw new InvalidInputError(
796
+ `${describeRejected(text)} mixes note-name systems: ${describeRejected(tonic)} is ${accepted.join(" or ")} but its mode word is ${wordSystem}`
797
+ );
557
798
  }
558
799
  function detectNoteNameSystem(text) {
559
800
  if (typeof text !== "string") {
@@ -561,21 +802,23 @@ function detectNoteNameSystem(text) {
561
802
  }
562
803
  const system = resolveSystem(normalize(text));
563
804
  if (system === null) {
564
- throw new InvalidInputError(`no note-name system reads ${JSON.stringify(text)}`);
805
+ throw new InvalidInputError(`no note-name system reads ${describeRejected(text)}`);
565
806
  }
566
807
  return system;
567
808
  }
568
809
  function readNoteName(text, opts) {
810
+ const asked = assertOptions(opts, "opts");
569
811
  const name = normalize(text);
570
- const system = _optionalChain([opts, 'optionalAccess', _5 => _5.system]) === void 0 ? resolveSystem(name) : assertSystem(opts.system);
812
+ const system = asked.system === void 0 ? resolveSystem(name) : assertSystem(asked.system);
571
813
  const note = system === null ? null : parseIn(name, system);
572
814
  if (note === null) {
573
- throw new InvalidInputError(`Invalid note: ${text}`);
815
+ throw new InvalidInputError(`Invalid note: ${describeRejected(text)}`);
574
816
  }
575
817
  return note;
576
818
  }
577
819
  function writeNoteName(note, opts) {
578
- const system = _optionalChain([opts, 'optionalAccess', _6 => _6.system]) === void 0 ? "english" : assertSystem(opts.system);
820
+ const asked = assertOptions(opts, "opts");
821
+ const system = asked.system === void 0 ? "english" : assertSystem(asked.system);
579
822
  const table = tableOf(system);
580
823
  const name = table === "german" ? formatGerman(note) : table === "japanese" ? formatJapanese(note) : table === "italian" ? formatItalian(note) : formatEnglish(note);
581
824
  return note.octave === void 0 ? name : `${name}${note.octave}`;
@@ -585,24 +828,26 @@ function impliedMode(system, tonic) {
585
828
  }
586
829
  function readKeyName(text, opts) {
587
830
  const name = normalize(text);
831
+ const asked = assertOptions(opts, "opts");
588
832
  const split = splitModeWord(name);
589
- const system = _optionalChain([opts, 'optionalAccess', _7 => _7.system]) === void 0 ? resolveSystem(name) : assertSystem(opts.system);
833
+ const system = asked.system === void 0 ? resolveSystem(name) : assertSystem(asked.system);
590
834
  if (system !== null && split.system !== void 0 && split.system !== tableOf(system)) {
591
835
  throw new InvalidInputError(
592
- `${JSON.stringify(text)} is not a ${system} key name: its mode word is ${split.system}`
836
+ `${describeRejected(text)} is not a ${system} key name: its mode word is ${split.system}`
593
837
  );
594
838
  }
595
839
  const tonic = system === null ? null : parseIn(split.tonic, system);
596
840
  if (tonic === null || system === null) {
597
- throw new InvalidInputError(`Invalid key name: ${text}`);
841
+ throw new InvalidInputError(`Invalid key name: ${describeRejected(text)}`);
598
842
  }
599
843
  if (tonic.octave !== void 0) {
600
- throw new InvalidInputError(`a key name carries no octave; received ${JSON.stringify(text)}`);
844
+ throw new InvalidInputError(`a key name carries no octave; received ${describeRejected(text)}`);
601
845
  }
602
846
  return { tonic, mode: _nullishCoalesce(split.mode, () => ( impliedMode(system, split.tonic))) };
603
847
  }
604
848
  function writeKeyName(key, opts) {
605
- const system = _optionalChain([opts, 'optionalAccess', _8 => _8.system]) === void 0 ? "english" : assertSystem(opts.system);
849
+ const asked = assertOptions(opts, "opts");
850
+ const system = asked.system === void 0 ? "english" : assertSystem(asked.system);
606
851
  const table = tableOf(system);
607
852
  const word = MODE_WORDS[table][key.mode];
608
853
  const tonic = writeNoteName(key.tonic, { system });
@@ -619,11 +864,13 @@ function writeKeyName(key, opts) {
619
864
  // src/core/pitch/index.ts
620
865
  var LETTER_SEMITONES = [0, 2, 4, 5, 7, 9, 11];
621
866
  var MAX_ALTER = 6;
867
+ var MAX_OCTAVE = 100;
622
868
  function assertNote(note, name) {
869
+ assertRecord(note, name);
623
870
  assertInteger(note.letter, `${name}.letter`, 0, 6);
624
871
  assertInteger(note.alter, `${name}.alter`, -MAX_ALTER, MAX_ALTER);
625
872
  if (note.octave !== void 0) {
626
- assertInteger(note.octave, `${name}.octave`, -100, 100);
873
+ assertInteger(note.octave, `${name}.octave`, -MAX_OCTAVE, MAX_OCTAVE);
627
874
  }
628
875
  return note;
629
876
  }
@@ -644,11 +891,12 @@ function parseNote(text, opts) {
644
891
  return unwrapParse(tryParseNote(text, opts));
645
892
  }
646
893
  function tryParseNote(text, opts) {
894
+ const asked = assertOptions(opts, "opts");
647
895
  try {
648
896
  if (typeof text !== "string") {
649
897
  throw new InvalidInputError(`note must be a string; received ${typeof text}`);
650
898
  }
651
- return { ok: true, value: assertNote(readNoteName(text, opts), `note ${text}`) };
899
+ return { ok: true, value: assertNote(readNoteName(text, asked), `note ${text}`) };
652
900
  } catch (error) {
653
901
  return parseFailure(error);
654
902
  }
@@ -661,11 +909,12 @@ function parseKeyName(text, opts) {
661
909
  return unwrapParse(tryParseKeyName(text, opts));
662
910
  }
663
911
  function tryParseKeyName(text, opts) {
912
+ const asked = assertOptions(opts, "opts");
664
913
  try {
665
914
  if (typeof text !== "string") {
666
915
  throw new InvalidInputError(`key name must be a string; received ${typeof text}`);
667
916
  }
668
- const key = readKeyName(text, opts);
917
+ const key = readKeyName(text, asked);
669
918
  assertNote(key.tonic, `key ${text}`);
670
919
  return { ok: true, value: key };
671
920
  } catch (error) {
@@ -673,10 +922,11 @@ function tryParseKeyName(text, opts) {
673
922
  }
674
923
  }
675
924
  function formatKeyName(key, opts) {
676
- assertNote(key.tonic, "key.tonic");
677
- const mode = assertOneOf(key.mode, ["major", "minor"], "key.mode");
925
+ const named = assertRecord(key, "key");
926
+ assertNote(named.tonic, "key.tonic");
927
+ const mode = assertOneOf(named.mode, ["major", "minor"], "key.mode");
678
928
  return writeKeyName(
679
- { tonic: { letter: mod7(key.tonic.letter), alter: key.tonic.alter }, mode },
929
+ { tonic: { letter: mod7(named.tonic.letter), alter: named.tonic.alter }, mode },
680
930
  opts
681
931
  );
682
932
  }
@@ -735,12 +985,14 @@ function midiToNote(midi, spelling = "sharp") {
735
985
  }
736
986
  var LETTER_STEPS_BY_SEMITONE = [0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6];
737
987
  function transposeNote(note, semitones, opts) {
988
+ assertNote(note, "note");
989
+ const asked = assertOptions(opts, "opts");
738
990
  if (!Number.isFinite(semitones)) {
739
991
  throw new InvalidInputError(`semitones must be a finite number; received ${semitones}`);
740
992
  }
741
993
  const steps = Math.round(semitones);
742
- if (_optionalChain([opts, 'optionalAccess', _9 => _9.spelling]) !== void 0) {
743
- return note.octave === void 0 ? bareOf(midiToNote(60 + mod12(noteToPitchClass(note) + steps), opts.spelling)) : midiToNote(noteToMidi(note) + steps, opts.spelling);
994
+ if (asked.spelling !== void 0) {
995
+ return note.octave === void 0 ? bareOf(midiToNote(60 + mod12(noteToPitchClass(note) + steps), asked.spelling)) : midiToNote(noteToMidi(note) + steps, asked.spelling);
744
996
  }
745
997
  const direction = steps < 0 ? -1 : 1;
746
998
  const magnitude = Math.abs(steps);
@@ -751,10 +1003,16 @@ function transposeNote(note, semitones, opts) {
751
1003
  const letter = mod7(absoluteLetter);
752
1004
  const natural = _nullishCoalesce(LETTER_SEMITONES[letter], () => ( 0));
753
1005
  if (note.octave === void 0) {
754
- return { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) };
1006
+ return assertNote(
1007
+ { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) },
1008
+ "transposed note"
1009
+ );
755
1010
  }
756
1011
  const octave = note.octave + Math.floor(absoluteLetter / 7);
757
- return { letter, alter: noteToMidi(note) + steps - ((octave + 1) * 12 + natural), octave };
1012
+ return assertNote(
1013
+ { letter, alter: noteToMidi(note) + steps - ((octave + 1) * 12 + natural), octave },
1014
+ "transposed note"
1015
+ );
758
1016
  }
759
1017
  function bareOf(note) {
760
1018
  return { letter: note.letter, alter: note.alter };
@@ -787,7 +1045,7 @@ function qualityFromSpan(numberValue, semitones) {
787
1045
  }
788
1046
  return delta > 0 ? repeat("A", delta) : repeat("d", -delta - 1);
789
1047
  }
790
- var MAX_INTERVAL_NUMBER = 75;
1048
+ var MAX_INTERVAL_NUMBER = 7 * (2 * MAX_OCTAVE) + 6 + 1;
791
1049
  function intervalSemitones(numberValue, quality) {
792
1050
  assertInteger(numberValue, "interval number", 1, MAX_INTERVAL_NUMBER);
793
1051
  const octaves = Math.floor((numberValue - 1) / 7);
@@ -819,9 +1077,9 @@ function intervalSemitones(numberValue, quality) {
819
1077
  `a unison cannot be diminished; a unison narrowed by a semitone descends, so name it '-${"A".repeat(quality.length)}1'`
820
1078
  );
821
1079
  }
822
- return Math.abs(reference - quality.length - (perfect ? 0 : 1));
1080
+ return reference - quality.length - (perfect ? 0 : 1);
823
1081
  }
824
- throw new InvalidInputError(`unknown interval quality ${JSON.stringify(quality)}`);
1082
+ throw new InvalidInputError(`unknown interval quality ${describeRejected(quality)}`);
825
1083
  }
826
1084
  var INTERVAL_NAME_PATTERN = /^(-?)(P|M|m|A+|d+)(\d+)$/;
827
1085
  function parseInterval(name) {
@@ -830,16 +1088,19 @@ function parseInterval(name) {
830
1088
  function tryParseInterval(name) {
831
1089
  try {
832
1090
  const match = typeof name === "string" ? name.trim().match(INTERVAL_NAME_PATTERN) : null;
833
- const quality = _optionalChain([match, 'optionalAccess', _10 => _10[2]]);
834
- const numberValue = Number(_optionalChain([match, 'optionalAccess', _11 => _11[3]]));
1091
+ const quality = _optionalChain([match, 'optionalAccess', _3 => _3[2]]);
1092
+ const numberValue = Number(_optionalChain([match, 'optionalAccess', _4 => _4[3]]));
835
1093
  if (quality === void 0 || !Number.isFinite(numberValue)) {
836
1094
  throw new InvalidInputError(
837
- `interval must be a quality followed by a number, such as 'P5'; received ${JSON.stringify(name)}`
1095
+ `interval must be a quality followed by a number, such as 'P5'; received ${describeRejected(name)}`
838
1096
  );
839
1097
  }
840
1098
  const span = intervalSemitones(numberValue, quality);
841
- if (_optionalChain([match, 'optionalAccess', _12 => _12[1]]) !== "-") {
842
- return { ok: true, value: { number: numberValue, quality, semitones: span } };
1099
+ if (_optionalChain([match, 'optionalAccess', _5 => _5[1]]) !== "-") {
1100
+ return {
1101
+ ok: true,
1102
+ value: { number: numberValue, quality, semitones: span, descending: false }
1103
+ };
843
1104
  }
844
1105
  return {
845
1106
  ok: true,
@@ -854,29 +1115,26 @@ function isDescendingInterval(interval) {
854
1115
  return interval.descending;
855
1116
  }
856
1117
  const span = Math.round(interval.semitones);
857
- if (span < 0 && qualityFromSpan(interval.number, span) === interval.quality) {
858
- return false;
1118
+ if (qualityFromSpan(interval.number, span) === interval.quality) {
1119
+ return interval.number === 1 && span < 0;
859
1120
  }
860
- return span < 0;
1121
+ return span !== 0;
861
1122
  }
862
1123
  function normalizedInterval(data) {
863
1124
  assertInteger(data.number, "interval.number", 1);
864
1125
  assertFiniteNumber(data.semitones, "interval.semitones");
865
1126
  const expected = intervalSemitones(data.number, data.quality);
866
- if (Math.abs(data.semitones) !== expected) {
1127
+ if (Math.abs(data.semitones) !== Math.abs(expected)) {
867
1128
  throw new InvalidInputError(
868
1129
  `${data.quality}${data.number} spans ${expected} semitones; received ${data.semitones}`
869
1130
  );
870
1131
  }
871
- const normalized = {
1132
+ return {
872
1133
  number: data.number,
873
1134
  quality: data.quality,
874
- semitones: data.semitones
1135
+ semitones: data.semitones,
1136
+ descending: isDescendingInterval(data)
875
1137
  };
876
- if (isDescendingInterval(data)) {
877
- normalized.descending = true;
878
- }
879
- return normalized;
880
1138
  }
881
1139
  function toSpelledInterval(value) {
882
1140
  if (typeof value === "string") {
@@ -895,7 +1153,7 @@ function toNoteData(value) {
895
1153
  return parseNote(value);
896
1154
  }
897
1155
  if (typeof value === "number") {
898
- return midiToNote(value);
1156
+ return midiToNote(assertMidiPitch(value, "note"));
899
1157
  }
900
1158
  if (typeof value === "object" && value !== null) {
901
1159
  const data = "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON() : value;
@@ -906,9 +1164,10 @@ function toNoteData(value) {
906
1164
  `note must be a name, a MIDI number, or spelled note data; received ${typeof value}`
907
1165
  );
908
1166
  }
909
- function transposeByInterval(note, interval) {
910
- assertNote(note, "note");
911
- assertInteger(interval.number, "interval.number", 1);
1167
+ function transposeByInterval(given, named) {
1168
+ const note = toNoteData(given);
1169
+ const interval = toSpelledInterval(named);
1170
+ assertInteger(interval.number, "interval.number", 1, MAX_INTERVAL_NUMBER);
912
1171
  assertFiniteNumber(interval.semitones, "interval.semitones");
913
1172
  const letterSteps = (interval.number - 1) * (isDescendingInterval(interval) ? -1 : 1);
914
1173
  const absoluteLetter = mod7(note.letter) + letterSteps;
@@ -916,10 +1175,16 @@ function transposeByInterval(note, interval) {
916
1175
  const natural = _nullishCoalesce(LETTER_SEMITONES[letter], () => ( 0));
917
1176
  const steps = Math.round(interval.semitones);
918
1177
  if (note.octave === void 0) {
919
- return { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) };
1178
+ return assertNote(
1179
+ { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) },
1180
+ "transposed note"
1181
+ );
920
1182
  }
921
1183
  const octave = note.octave + Math.floor(absoluteLetter / 7);
922
- return { letter, alter: noteToMidi(note) + steps - ((octave + 1) * 12 + natural), octave };
1184
+ return assertNote(
1185
+ { letter, alter: noteToMidi(note) + steps - ((octave + 1) * 12 + natural), octave },
1186
+ "transposed note"
1187
+ );
923
1188
  }
924
1189
  function diatonicIndex(note) {
925
1190
  return mod7(note.letter) + 7 * (_nullishCoalesce(note.octave, () => ( 0)));
@@ -952,15 +1217,12 @@ function spelledInterval(a, b) {
952
1217
  const absSteps = Math.abs(letterSteps);
953
1218
  const number = absSteps + 1;
954
1219
  const directedSpan = letterSteps === 0 ? Math.abs(semitones) : letterSteps > 0 ? semitones : -semitones;
955
- const interval = {
1220
+ return {
956
1221
  number,
957
1222
  quality: qualityFromSpan(number, directedSpan),
958
- semitones
1223
+ semitones,
1224
+ descending: letterSteps < 0 || letterSteps === 0 && semitones < 0
959
1225
  };
960
- if (letterSteps < 0 || letterSteps === 0 && semitones < 0) {
961
- interval.descending = true;
962
- }
963
- return interval;
964
1226
  }
965
1227
 
966
1228
  // src/core/interval/index.ts
@@ -970,10 +1232,13 @@ var ConsonanceClass = /* @__PURE__ */ ((ConsonanceClass2) => {
970
1232
  ConsonanceClass2[ConsonanceClass2["Dissonance"] = 2] = "Dissonance";
971
1233
  return ConsonanceClass2;
972
1234
  })(ConsonanceClass || {});
1235
+ Object.freeze(ConsonanceClass);
973
1236
  function simpleInterval(semitones) {
1237
+ assertFiniteSemitones(semitones);
974
1238
  return pitchClassOf(Math.abs(semitones));
975
1239
  }
976
1240
  function classifyInterval(semitones, twoVoice = true) {
1241
+ assertFlag(twoVoice, "twoVoice");
977
1242
  const pc = simpleInterval(semitones);
978
1243
  if (pc === 0 || pc === 7) {
979
1244
  return 0 /* PerfectConsonance */;
@@ -991,6 +1256,7 @@ function isPerfectInterval(semitones) {
991
1256
  return pc === 0 || pc === 7;
992
1257
  }
993
1258
  function isConsonantInterval(semitones, twoVoice = true) {
1259
+ assertFlag(twoVoice, "twoVoice");
994
1260
  const pc = simpleInterval(semitones);
995
1261
  if (pc === 5) {
996
1262
  return !twoVoice;
@@ -998,6 +1264,316 @@ function isConsonantInterval(semitones, twoVoice = true) {
998
1264
  return pc === 0 || pc === 3 || pc === 4 || pc === 7 || pc === 8 || pc === 9;
999
1265
  }
1000
1266
 
1267
+ // src/core/meter/index.ts
1268
+ function toMeterData(value, name = "meter") {
1269
+ return copyMeterData(readMeterData(value, name));
1270
+ }
1271
+ function readMeterData(value, name = "meter") {
1272
+ if (typeof value === "string") {
1273
+ const parsed = tryParseTimeSignature(value);
1274
+ if (parsed.ok) {
1275
+ return parsed.value;
1276
+ }
1277
+ throw new InvalidInputError(`${name} must name a time signature; ${parsed.error.message}`);
1278
+ }
1279
+ if (typeof value === "object" && value !== null) {
1280
+ const data = !Array.isArray(value) && "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON() : value;
1281
+ if (isMeterMap(data)) {
1282
+ return assertMeterMap(data, name);
1283
+ }
1284
+ if (typeof data === "object" && data !== null && "numerator" in data) {
1285
+ return assertTimeSignature(data, name);
1286
+ }
1287
+ }
1288
+ throw new InvalidInputError(
1289
+ `${name} must be a time signature, a meter map, or a signature name; received ${describeRejected(value)}`
1290
+ );
1291
+ }
1292
+ function readSignature(value, name) {
1293
+ const resolved = readMeterData(value, name);
1294
+ return isMeterMap(resolved) ? meterAtChecked(0, resolved) : resolved;
1295
+ }
1296
+ var DEFAULT_TS = Object.freeze({ numerator: 4, denominator: 4 });
1297
+ var MAX_CHANGE_DIVISIONS = 16;
1298
+ function isMultiple(value, unit) {
1299
+ if (unit === 0) {
1300
+ return false;
1301
+ }
1302
+ const ratio = value / unit;
1303
+ return Math.abs(ratio - Math.round(ratio)) < BEAT_EPS;
1304
+ }
1305
+ function parseTimeSignature(text) {
1306
+ return unwrapParse(tryParseTimeSignature(text));
1307
+ }
1308
+ function tryParseTimeSignature(text) {
1309
+ try {
1310
+ if (typeof text !== "string") {
1311
+ throw new InvalidInputError(`time signature must be a string; received ${typeof text}`);
1312
+ }
1313
+ return { ok: true, value: readTimeSignature(text) };
1314
+ } catch (error) {
1315
+ return parseFailure(error);
1316
+ }
1317
+ }
1318
+ function readTimeSignature(text) {
1319
+ const match = /^\s*((?:\d+\s*\+\s*)*\d+)\s*\/\s*(\d+)\s*$/.exec(text);
1320
+ if (!match) {
1321
+ throw new InvalidInputError(`Invalid time signature: ${text}`);
1322
+ }
1323
+ const groupTokens = (_nullishCoalesce(match[1], () => ( ""))).split("+").map((token) => Number.parseInt(token.trim(), 10));
1324
+ const numerator = groupTokens.reduce((sum, value) => sum + value, 0);
1325
+ const denominator = Number.parseInt(_nullishCoalesce(match[2], () => ( "")), 10);
1326
+ if (!Number.isSafeInteger(numerator) || !Number.isSafeInteger(denominator) || numerator <= 0 || denominator <= 0) {
1327
+ throw new InvalidInputError(`Invalid time signature: ${text}`);
1328
+ }
1329
+ const ts = groupTokens.length > 1 ? { numerator, denominator, grouping: groupTokens } : { numerator, denominator };
1330
+ return assertTimeSignature(ts, `time signature ${text}`);
1331
+ }
1332
+ function formatTimeSignature(ts, opts = {}) {
1333
+ const asked = assertOptions(opts, "opts");
1334
+ const signature = readSignature(ts, "ts");
1335
+ const grouping = signature.grouping;
1336
+ if (asked.grouping === true && grouping !== void 0) {
1337
+ if (groupingSumOf(signature) === signature.numerator) {
1338
+ return `${grouping.join("+")}/${signature.denominator}`;
1339
+ }
1340
+ const pulseGrouping = pulseGroupingOf(signature);
1341
+ if (pulseGrouping !== void 0 && !isUniformGrouping(pulseGrouping)) {
1342
+ throw new InvalidInputError(
1343
+ `ts carries a grouping no signature text can spell: ${grouping.join("+")} counted in the pulses of ${signature.numerator}/${signature.denominator}. Format it without the grouping to name the bar it is written in.`
1344
+ );
1345
+ }
1346
+ }
1347
+ return `${signature.numerator}/${signature.denominator}`;
1348
+ }
1349
+ function isCompound(ts) {
1350
+ const signature = readSignature(ts, "ts");
1351
+ return isCompoundNumerator(signature.numerator) && !isAdditiveReading(signature);
1352
+ }
1353
+ function beatsPerBar(ts) {
1354
+ return barBeatsOf(readSignature(ts, "ts"));
1355
+ }
1356
+ function meterAt(beatInQuarters, meter) {
1357
+ assertFiniteNumber(beatInQuarters, "beat");
1358
+ return copyTimeSignature(meterAtChecked(beatInQuarters, readMeterData(meter)));
1359
+ }
1360
+ function meterAtChecked(beatInQuarters, meter) {
1361
+ if (!isMeterMap(meter)) {
1362
+ return meter;
1363
+ }
1364
+ const ts = _optionalChain([meter, 'access', _6 => _6[entryIndexOf(meter, beatInQuarters)], 'optionalAccess', _7 => _7.ts]);
1365
+ if (ts === void 0) {
1366
+ throw new InvalidInputError(
1367
+ `meters names no time signature in force at beat ${beatInQuarters}; a meter map must stay a non-empty run of changes while it is being read`
1368
+ );
1369
+ }
1370
+ return ts;
1371
+ }
1372
+ function barStartBeat(beatInQuarters, meter) {
1373
+ assertFiniteNumber(beatInQuarters, "beat");
1374
+ return barStartChecked(beatInQuarters, readMeterData(meter));
1375
+ }
1376
+ function barStartChecked(beatInQuarters, meter) {
1377
+ if (isMeterMap(meter)) {
1378
+ return barStartOf(meter, beatInQuarters);
1379
+ }
1380
+ const barLen = barBeatsOf(meter);
1381
+ return Math.floor(beatInQuarters / barLen + BEAT_EPS) * barLen;
1382
+ }
1383
+ function barIndexAt(beatInQuarters, meter) {
1384
+ assertFiniteNumber(beatInQuarters, "beat");
1385
+ return barIndexChecked(beatInQuarters, readMeterData(meter));
1386
+ }
1387
+ function barIndexChecked(beatInQuarters, meter) {
1388
+ if (isMeterMap(meter)) {
1389
+ return barIndexOf(meter, beatInQuarters);
1390
+ }
1391
+ return Math.floor(beatInQuarters / barBeatsOf(meter) + BEAT_EPS);
1392
+ }
1393
+ function beatsPerBarAt(beatInQuarters, meter) {
1394
+ assertFiniteNumber(beatInQuarters, "beat");
1395
+ const data = readMeterData(meter);
1396
+ return isMeterMap(data) ? barLengthOf(data, beatInQuarters) : barBeatsOf(meterAt(beatInQuarters, meter));
1397
+ }
1398
+ function resolveMeters(opts, name = "meters") {
1399
+ assertRecord(opts, `${name} options`);
1400
+ if (opts.ts !== void 0 && opts.meters !== void 0) {
1401
+ throw new InvalidInputError(
1402
+ `${name} and ts name the same thing; give one or the other, not both`
1403
+ );
1404
+ }
1405
+ for (const [field, value] of [
1406
+ ["meters", opts.meters],
1407
+ ["ts", opts.ts]
1408
+ ]) {
1409
+ if (value === null) {
1410
+ throw new InvalidInputError(
1411
+ `${field === "meters" ? name : "ts"} must name a meter, not null`
1412
+ );
1413
+ }
1414
+ }
1415
+ const given = _nullishCoalesce(opts.meters, () => ( opts.ts));
1416
+ if (given === void 0) {
1417
+ return [{ startBeat: 0, ts: copyTimeSignature(DEFAULT_TS) }];
1418
+ }
1419
+ const resolved = toMeterData(given, opts.meters !== void 0 ? name : "ts");
1420
+ return isMeterMap(resolved) ? resolved : [{ startBeat: 0, ts: resolved }];
1421
+ }
1422
+ function pulsesPerBar(ts) {
1423
+ return pulseCountOf(readSignature(ts, "ts"));
1424
+ }
1425
+ function isGroupHead(grouping, pulseIndex) {
1426
+ let acc = 0;
1427
+ for (const g of grouping) {
1428
+ if (acc === pulseIndex) {
1429
+ return true;
1430
+ }
1431
+ acc += g;
1432
+ }
1433
+ return false;
1434
+ }
1435
+ function isUniformGrouping(grouping) {
1436
+ return grouping.every((entry) => entry === grouping[0]);
1437
+ }
1438
+ function beatToBarPosition(beatInQuarters, meter) {
1439
+ assertFiniteNumber(beatInQuarters, "beat");
1440
+ return barPositionChecked(beatInQuarters, readMeterData(meter));
1441
+ }
1442
+ function barPositionChecked(beatInQuarters, meter) {
1443
+ return {
1444
+ bar: barIndexChecked(beatInQuarters, meter),
1445
+ beat: beatInQuarters - barStartChecked(beatInQuarters, meter)
1446
+ };
1447
+ }
1448
+ function pulseBeats(ts) {
1449
+ return pulseBeatsOf(readSignature(ts, "ts"));
1450
+ }
1451
+ function barPositionToPulse(pos, meter) {
1452
+ const position = assertRecord(pos, "position");
1453
+ assertInteger(position.bar, "position.bar");
1454
+ assertFiniteNumber(position.beat, "position.beat");
1455
+ return pulseChecked(position, readMeterData(meter));
1456
+ }
1457
+ function pulseChecked(pos, meter) {
1458
+ return pos.beat / pulseBeatsOf(meterAtBarChecked(pos.bar, meter)) + 1;
1459
+ }
1460
+ function meterAtBarChecked(bar, meter) {
1461
+ if (!isMeterMap(meter)) {
1462
+ return meter;
1463
+ }
1464
+ assertFiniteNumber(bar, "position.bar");
1465
+ return meterAtChecked(beatOfBarIndex(meter, bar), meter);
1466
+ }
1467
+ function formatBarPosition(beatInQuarters, meter, decimals = 2) {
1468
+ assertInteger(decimals, "decimals", 0, 100);
1469
+ assertFiniteNumber(beatInQuarters, "beat");
1470
+ const resolved = readMeterData(meter);
1471
+ const position = barPositionChecked(beatInQuarters, resolved);
1472
+ const ts = meterAtChecked(beatInQuarters, resolved);
1473
+ const pulse = pulseChecked(position, ts);
1474
+ const rounded = Number(pulse.toFixed(decimals));
1475
+ const barLength = isMeterMap(resolved) ? barLengthOf(resolved, beatInQuarters) : barBeatsOf(resolved);
1476
+ const pulsesInBar = Math.ceil(barLength / pulseBeatsOf(ts) - BEAT_EPS);
1477
+ if (rounded >= pulsesInBar + 1) {
1478
+ return `${barIndexChecked(barStartChecked(beatInQuarters, resolved) + barLength, resolved) + 1}.1`;
1479
+ }
1480
+ const wholePulse = Math.floor(rounded);
1481
+ const fraction = Number((rounded - wholePulse).toFixed(decimals));
1482
+ return fraction === 0 ? `${position.bar + 1}.${wholePulse}` : `${position.bar + 1}.${wholePulse}+${fraction}`;
1483
+ }
1484
+ function barPositionToBeat(pos, meter) {
1485
+ const position = assertRecord(pos, "bar position");
1486
+ assertInteger(position.bar, "bar position bar");
1487
+ assertFiniteNumber(position.beat, "bar position beat");
1488
+ const resolved = readMeterData(meter);
1489
+ if (isMeterMap(resolved)) {
1490
+ return beatOfBarIndex(resolved, position.bar) + position.beat;
1491
+ }
1492
+ return position.bar * barBeatsOf(resolved) + position.beat;
1493
+ }
1494
+ function metricWeight(beatInQuarters, meter) {
1495
+ assertFiniteNumber(beatInQuarters, "beat");
1496
+ const resolved = readMeterData(meter);
1497
+ const ts = meterAtChecked(beatInQuarters, resolved);
1498
+ const beat = beatInQuarters - barStartChecked(beatInQuarters, resolved);
1499
+ const pulse = pulseBeatsOf(ts);
1500
+ if (!isMultiple(beat, pulse)) {
1501
+ return 0;
1502
+ }
1503
+ const pulses = pulseCountOf(ts);
1504
+ const pulseIndex = Math.round(beat / pulse) % pulses;
1505
+ if (pulseIndex === 0) {
1506
+ return 3;
1507
+ }
1508
+ const grouping = pulseGroupingOf(ts);
1509
+ if (grouping !== void 0 && (isAdditiveReading(ts) || !isUniformGrouping(grouping))) {
1510
+ return isGroupHead(grouping, pulseIndex) ? 2 : 1;
1511
+ }
1512
+ if (pulses % 2 === 0 && pulseIndex === pulses / 2) {
1513
+ return 2;
1514
+ }
1515
+ return 1;
1516
+ }
1517
+ function metricGridUnit(meter) {
1518
+ const resolved = readMeterData(meter);
1519
+ if (!isMeterMap(resolved)) {
1520
+ return pulseBeatsOf(resolved);
1521
+ }
1522
+ let unit = 0;
1523
+ for (const change of resolved) {
1524
+ unit = commonStep(unit, pulseBeatsOf(change.ts));
1525
+ }
1526
+ if (unit <= 0) {
1527
+ return pulseBeatsOf(DEFAULT_TS);
1528
+ }
1529
+ const origin = _nullishCoalesce(_optionalChain([resolved, 'access', _8 => _8[0], 'optionalAccess', _9 => _9.startBeat]), () => ( 0));
1530
+ let onChanges = unit;
1531
+ for (const change of resolved) {
1532
+ onChanges = commonStep(onChanges, Math.abs(change.startBeat - origin));
1533
+ }
1534
+ return onChanges * MAX_CHANGE_DIVISIONS >= unit - BEAT_EPS ? onChanges : unit;
1535
+ }
1536
+ function commonStep(a, b) {
1537
+ let longer = Math.max(a, b);
1538
+ let shorter = Math.min(a, b);
1539
+ for (let i = 0; i < 8 && shorter > BEAT_EPS; i += 1) {
1540
+ const remainder = longer - Math.floor(longer / shorter + BEAT_EPS) * shorter;
1541
+ longer = shorter;
1542
+ shorter = remainder > BEAT_EPS ? remainder : 0;
1543
+ }
1544
+ const smallest = a > 0 && b > 0 ? Math.min(a, b) : Math.max(a, b);
1545
+ return longer > BEAT_EPS && longer <= smallest + BEAT_EPS ? longer : smallest;
1546
+ }
1547
+ function isStrongBeat(beatInQuarters, meter) {
1548
+ return metricWeight(beatInQuarters, meter) >= 2;
1549
+ }
1550
+ function tuplet(totalBeats, count) {
1551
+ assertRange(totalBeats, 0, Number.MAX_SAFE_INTEGER, "tuplet total beats");
1552
+ assertPositiveInt(count, "tuplet count");
1553
+ return new Array(count).fill(totalBeats / count);
1554
+ }
1555
+
1556
+
1557
+
1558
+
1559
+
1560
+
1561
+
1562
+
1563
+
1564
+
1565
+
1566
+
1567
+
1568
+
1569
+
1570
+
1571
+
1572
+
1573
+
1574
+
1575
+
1576
+
1001
1577
 
1002
1578
 
1003
1579
 
@@ -1060,5 +1636,5 @@ function isConsonantInterval(semitones, twoVoice = true) {
1060
1636
 
1061
1637
 
1062
1638
 
1063
- exports.parseFailure = parseFailure; exports.unwrapParse = unwrapParse; exports.InvalidInputError = InvalidInputError; exports.NoSolutionError = NoSolutionError; exports.BudgetExceededError = BudgetExceededError; exports.isLibcantusError = isLibcantusError; exports.isCompoundNumerator = isCompoundNumerator; exports.groupingSumOf = groupingSumOf; exports.isAdditiveReading = isAdditiveReading; exports.pulseCountOf = pulseCountOf; exports.pulseBeatsOf = pulseBeatsOf; exports.pulseGroupingOf = pulseGroupingOf; exports.barBeatsOf = barBeatsOf; exports.isMeterMap = isMeterMap; exports.entryIndexOf = entryIndexOf; exports.barStartOf = barStartOf; exports.barLengthOf = barLengthOf; exports.barIndexOf = barIndexOf; exports.beatOfBarIndex = beatOfBarIndex; exports.DEFAULT_GENERATION_BUDGET = DEFAULT_GENERATION_BUDGET; exports.assertFiniteNumber = assertFiniteNumber; exports.assertInteger = assertInteger; exports.assertMidiPitch = assertMidiPitch; exports.clampToMidi = clampToMidi; exports.assertDegree = assertDegree; exports.assertFiniteSemitones = assertFiniteSemitones; exports.dropSilentNotes = dropSilentNotes; exports.soundingNotesOnly = soundingNotesOnly; exports.assertOneOf = assertOneOf; exports.assertPositiveInt = assertPositiveInt; exports.assertRange = assertRange; exports.assertGenerationBudget = assertGenerationBudget; exports.assertTimeSignature = assertTimeSignature; exports.assertMeterMap = assertMeterMap; exports.assertNoteEvent = assertNoteEvent; exports.assertNoteEvents = assertNoteEvents; exports.detectNoteNameSystem = detectNoteNameSystem; exports.pitchClassOf = pitchClassOf; exports.diatonicLetterOf = diatonicLetterOf; exports.naturalPitchClassOf = naturalPitchClassOf; exports.parseNote = parseNote; exports.tryParseNote = tryParseNote; exports.formatNote = formatNote; exports.parseKeyName = parseKeyName; exports.tryParseKeyName = tryParseKeyName; exports.formatKeyName = formatKeyName; exports.noteToPitchClass = noteToPitchClass; exports.noteToMidi = noteToMidi; exports.midiToNote = midiToNote; exports.transposeNote = transposeNote; exports.intervalSemitones = intervalSemitones; exports.parseInterval = parseInterval; exports.tryParseInterval = tryParseInterval; exports.toSpelledInterval = toSpelledInterval; exports.toNoteData = toNoteData; exports.transposeByInterval = transposeByInterval; exports.spelledInterval = spelledInterval; exports.ConsonanceClass = ConsonanceClass; exports.classifyInterval = classifyInterval; exports.isPerfectInterval = isPerfectInterval; exports.isConsonantInterval = isConsonantInterval;
1064
- //# sourceMappingURL=chunk-Q2WGKJNN.cjs.map
1639
+ exports.parseFailure = parseFailure; exports.unwrapParse = unwrapParse; exports.InvalidInputError = InvalidInputError; exports.NoSolutionError = NoSolutionError; exports.BudgetExceededError = BudgetExceededError; exports.isLibcantusError = isLibcantusError; exports.ARTICULATIONS = ARTICULATIONS; exports.BEAT_EPS = BEAT_EPS; exports.DEFAULT_GENERATION_BUDGET = DEFAULT_GENERATION_BUDGET; exports.describeRejected = describeRejected; exports.assertFiniteNumber = assertFiniteNumber; exports.assertInteger = assertInteger; exports.assertMidiPitch = assertMidiPitch; exports.assertPitchClass = assertPitchClass; exports.clampToMidi = clampToMidi; exports.assertDegree = assertDegree; exports.assertFiniteSemitones = assertFiniteSemitones; exports.dropSilentNotes = dropSilentNotes; exports.soundingNotesOnly = soundingNotesOnly; exports.assertArray = assertArray; exports.assertRecord = assertRecord; exports.assertOptions = assertOptions; exports.assertFlag = assertFlag; exports.assertFunction = assertFunction; exports.assertOneOf = assertOneOf; exports.assertPositiveInt = assertPositiveInt; exports.assertRange = assertRange; exports.assertGenerationBudget = assertGenerationBudget; exports.allocateCandidateTable = allocateCandidateTable; exports.allocateChoiceTable = allocateChoiceTable; exports.assertTimeSignature = assertTimeSignature; exports.assertMeterMap = assertMeterMap; exports.assertNoteEvent = assertNoteEvent; exports.assertNoteEvents = assertNoteEvents; exports.MAX_NAME_ACCIDENTALS = MAX_NAME_ACCIDENTALS; exports.maxNoteNameLength = maxNoteNameLength; exports.detectNoteNameSystem = detectNoteNameSystem; exports.pitchClassOf = pitchClassOf; exports.diatonicLetterOf = diatonicLetterOf; exports.naturalPitchClassOf = naturalPitchClassOf; exports.parseNote = parseNote; exports.tryParseNote = tryParseNote; exports.formatNote = formatNote; exports.parseKeyName = parseKeyName; exports.tryParseKeyName = tryParseKeyName; exports.formatKeyName = formatKeyName; exports.noteToPitchClass = noteToPitchClass; exports.noteToMidi = noteToMidi; exports.midiToNote = midiToNote; exports.transposeNote = transposeNote; exports.intervalSemitones = intervalSemitones; exports.parseInterval = parseInterval; exports.tryParseInterval = tryParseInterval; exports.toSpelledInterval = toSpelledInterval; exports.toNoteData = toNoteData; exports.transposeByInterval = transposeByInterval; exports.spelledInterval = spelledInterval; exports.ConsonanceClass = ConsonanceClass; exports.classifyInterval = classifyInterval; exports.isPerfectInterval = isPerfectInterval; exports.isConsonantInterval = isConsonantInterval; exports.toMeterData = toMeterData; exports.parseTimeSignature = parseTimeSignature; exports.tryParseTimeSignature = tryParseTimeSignature; exports.formatTimeSignature = formatTimeSignature; exports.isCompound = isCompound; exports.beatsPerBar = beatsPerBar; exports.meterAt = meterAt; exports.barStartBeat = barStartBeat; exports.barIndexAt = barIndexAt; exports.beatsPerBarAt = beatsPerBarAt; exports.resolveMeters = resolveMeters; exports.pulsesPerBar = pulsesPerBar; exports.beatToBarPosition = beatToBarPosition; exports.pulseBeats = pulseBeats; exports.barPositionToPulse = barPositionToPulse; exports.formatBarPosition = formatBarPosition; exports.barPositionToBeat = barPositionToBeat; exports.metricWeight = metricWeight; exports.metricGridUnit = metricGridUnit; exports.isStrongBeat = isStrongBeat; exports.tuplet = tuplet;
1640
+ //# sourceMappingURL=chunk-S5BKZZGM.cjs.map