@libraz/libcantus 1.3.0 → 1.4.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 (130) hide show
  1. package/NOTICE +63 -0
  2. package/README.md +3 -1
  3. package/README_ja.md +13 -11
  4. package/dist/analyze/index.cjs +7 -7
  5. package/dist/analyze/index.cjs.map +1 -1
  6. package/dist/analyze/index.d.cts +14 -12
  7. package/dist/analyze/index.d.ts +14 -12
  8. package/dist/analyze/index.js +6 -6
  9. package/dist/{chunk-NB25P3EH.js → chunk-2G5MCGYU.js} +33 -11
  10. package/dist/chunk-2G5MCGYU.js.map +1 -0
  11. package/dist/{chunk-NM7UAMC3.cjs → chunk-3FDBMIPR.cjs} +64 -64
  12. package/dist/chunk-3FDBMIPR.cjs.map +1 -0
  13. package/dist/{chunk-YFA7X2F6.cjs → chunk-3MDOEFIQ.cjs} +411 -327
  14. package/dist/chunk-3MDOEFIQ.cjs.map +1 -0
  15. package/dist/{chunk-IPEF6NWB.js → chunk-5MWRBYAT.js} +278 -154
  16. package/dist/chunk-5MWRBYAT.js.map +1 -0
  17. package/dist/{chunk-B2PW6EHN.cjs → chunk-6TTBEON3.cjs} +1253 -889
  18. package/dist/chunk-6TTBEON3.cjs.map +1 -0
  19. package/dist/{chunk-UMWZ4ZET.js → chunk-7NQ6AL3H.js} +4 -4
  20. package/dist/chunk-7NQ6AL3H.js.map +1 -0
  21. package/dist/{chunk-PWC4CRWT.cjs → chunk-E3QO3UET.cjs} +31 -23
  22. package/dist/chunk-E3QO3UET.cjs.map +1 -0
  23. package/dist/{chunk-GNVN4PPJ.js → chunk-FJFULJZE.js} +531 -213
  24. package/dist/chunk-FJFULJZE.js.map +1 -0
  25. package/dist/{chunk-CPMB7P75.js → chunk-FK3DGAIZ.js} +608 -244
  26. package/dist/chunk-FK3DGAIZ.js.map +1 -0
  27. package/dist/chunk-GEDTJHAC.cjs.map +1 -1
  28. package/dist/{chunk-RFIBF2RR.js → chunk-H7FVMBUC.js} +138 -65
  29. package/dist/chunk-H7FVMBUC.js.map +1 -0
  30. package/dist/{chunk-4R2LWV7E.cjs → chunk-HYSVSFNI.cjs} +664 -540
  31. package/dist/chunk-HYSVSFNI.cjs.map +1 -0
  32. package/dist/{chunk-35NBV2FT.cjs → chunk-KMYGRFZ6.cjs} +47 -24
  33. package/dist/chunk-KMYGRFZ6.cjs.map +1 -0
  34. package/dist/{chunk-IFZDWIKM.cjs → chunk-LQZQDBCD.cjs} +1048 -730
  35. package/dist/chunk-LQZQDBCD.cjs.map +1 -0
  36. package/dist/{chunk-PM4XJE2Y.cjs → chunk-P3CPXAJ5.cjs} +76 -54
  37. package/dist/chunk-P3CPXAJ5.cjs.map +1 -0
  38. package/dist/{chunk-S5BKZZGM.cjs → chunk-S3QELJUE.cjs} +72 -56
  39. package/dist/chunk-S3QELJUE.cjs.map +1 -0
  40. package/dist/{chunk-PUKJP2Z5.js → chunk-TXFWSU5D.js} +31 -8
  41. package/dist/chunk-TXFWSU5D.js.map +1 -0
  42. package/dist/{chunk-76ZBTRG2.cjs → chunk-U4EQTDGN.cjs} +258 -218
  43. package/dist/chunk-U4EQTDGN.cjs.map +1 -0
  44. package/dist/chunk-UGLFDG7L.cjs.map +1 -1
  45. package/dist/{chunk-MLBPXA4Z.js → chunk-UTE5A36R.js} +198 -114
  46. package/dist/chunk-UTE5A36R.js.map +1 -0
  47. package/dist/{chunk-ZBUROTJQ.js → chunk-UZKQISRF.js} +17 -9
  48. package/dist/chunk-UZKQISRF.js.map +1 -0
  49. package/dist/{chunk-7KG3RTYS.js → chunk-VL5NXVCN.js} +281 -155
  50. package/dist/chunk-VL5NXVCN.js.map +1 -0
  51. package/dist/{chunk-CGBADIO5.cjs → chunk-WOMCXN2W.cjs} +328 -202
  52. package/dist/chunk-WOMCXN2W.cjs.map +1 -0
  53. package/dist/{chunk-3R3QVKY5.cjs → chunk-YDGMWH43.cjs} +397 -324
  54. package/dist/chunk-YDGMWH43.cjs.map +1 -0
  55. package/dist/{chunk-AGOVW7U6.js → chunk-YYVXRV3V.js} +72 -56
  56. package/dist/chunk-YYVXRV3V.js.map +1 -0
  57. package/dist/{chunk-M5RYMAFI.js → chunk-ZLNSH4UL.js} +71 -31
  58. package/dist/chunk-ZLNSH4UL.js.map +1 -0
  59. package/dist/{coerce-DRERzdve.d.cts → coerce-CUhHc3Tu.d.ts} +16 -8
  60. package/dist/{coerce-DP0vYu-x.d.ts → coerce-Ytt2Eiq9.d.cts} +16 -8
  61. package/dist/core/index.cjs +5 -5
  62. package/dist/core/index.cjs.map +1 -1
  63. package/dist/core/index.d.cts +9 -8
  64. package/dist/core/index.d.ts +9 -8
  65. package/dist/core/index.js +4 -4
  66. package/dist/generate/index.cjs +8 -8
  67. package/dist/generate/index.cjs.map +1 -1
  68. package/dist/generate/index.d.cts +28 -18
  69. package/dist/generate/index.d.ts +28 -18
  70. package/dist/generate/index.js +7 -7
  71. package/dist/{index-BMweUlm5.d.cts → index-5VJgKz_Q.d.cts} +6 -2
  72. package/dist/{index-BHIUyjhZ.d.ts → index-BLuDesVG.d.ts} +20 -13
  73. package/dist/{index-B9QLziDe.d.cts → index-BV6APVa6.d.cts} +20 -13
  74. package/dist/{index-CL4b4gUQ.d.ts → index-Bf0Sv8a9.d.ts} +6 -2
  75. package/dist/{index-Dw2DP7vm.d.ts → index-BkT21EMv.d.cts} +3 -2
  76. package/dist/{index-BL5N2Oyz.d.cts → index-C7KCaTRz.d.ts} +3 -2
  77. package/dist/{index-Cy15oTvh.d.ts → index-C9MYbuKS.d.cts} +7 -3
  78. package/dist/{index-Cy15oTvh.d.cts → index-C9MYbuKS.d.ts} +7 -3
  79. package/dist/{index-CY-3NVfy.d.cts → index-DVInzCDS.d.cts} +53 -29
  80. package/dist/{index-9eoQs2C1.d.ts → index-Dg-SAfhz.d.ts} +6 -4
  81. package/dist/{index-zaZdmnU4.d.ts → index-jgeug9EA.d.ts} +53 -29
  82. package/dist/{index-cHvbYgJI.d.cts → index-pQihL4z7.d.cts} +6 -4
  83. package/dist/index.cjs +13 -13
  84. package/dist/index.cjs.map +1 -1
  85. package/dist/index.d.cts +11 -11
  86. package/dist/index.d.ts +11 -11
  87. package/dist/index.js +12 -12
  88. package/dist/{masks-Cc7-MzzY.d.ts → masks-BnzXnBj0.d.cts} +3 -2
  89. package/dist/{masks-pADfTOiD.d.cts → masks-tycmkrgs.d.ts} +3 -2
  90. package/dist/model/index.cjs +12 -12
  91. package/dist/model/index.cjs.map +1 -1
  92. package/dist/model/index.d.cts +63 -48
  93. package/dist/model/index.d.ts +63 -48
  94. package/dist/model/index.js +11 -11
  95. package/dist/{positional-DJgs6ltD.d.ts → positional-CscpxtlE.d.cts} +3 -2
  96. package/dist/{positional-DMZer-FM.d.cts → positional-DLnfUgqG.d.ts} +3 -2
  97. package/dist/{profile-DLdlIpS9.d.ts → profile-B4WqcM4H.d.ts} +25 -17
  98. package/dist/{profile-CQMEqdH9.d.cts → profile-BJd1XkPB.d.cts} +25 -17
  99. package/dist/theory/index.cjs +5 -5
  100. package/dist/theory/index.cjs.map +1 -1
  101. package/dist/theory/index.d.cts +18 -14
  102. package/dist/theory/index.d.ts +18 -14
  103. package/dist/theory/index.js +4 -4
  104. package/dist/{types-D-XgxGvp.d.cts → types-7mGFwvMm.d.ts} +45 -22
  105. package/dist/{types-Dh7C064C.d.ts → types-_ofpb2be.d.cts} +45 -22
  106. package/package.json +13 -13
  107. package/dist/chunk-35NBV2FT.cjs.map +0 -1
  108. package/dist/chunk-3R3QVKY5.cjs.map +0 -1
  109. package/dist/chunk-4R2LWV7E.cjs.map +0 -1
  110. package/dist/chunk-76ZBTRG2.cjs.map +0 -1
  111. package/dist/chunk-7KG3RTYS.js.map +0 -1
  112. package/dist/chunk-AGOVW7U6.js.map +0 -1
  113. package/dist/chunk-B2PW6EHN.cjs.map +0 -1
  114. package/dist/chunk-CGBADIO5.cjs.map +0 -1
  115. package/dist/chunk-CPMB7P75.js.map +0 -1
  116. package/dist/chunk-GNVN4PPJ.js.map +0 -1
  117. package/dist/chunk-IFZDWIKM.cjs.map +0 -1
  118. package/dist/chunk-IPEF6NWB.js.map +0 -1
  119. package/dist/chunk-M5RYMAFI.js.map +0 -1
  120. package/dist/chunk-MLBPXA4Z.js.map +0 -1
  121. package/dist/chunk-NB25P3EH.js.map +0 -1
  122. package/dist/chunk-NM7UAMC3.cjs.map +0 -1
  123. package/dist/chunk-PM4XJE2Y.cjs.map +0 -1
  124. package/dist/chunk-PUKJP2Z5.js.map +0 -1
  125. package/dist/chunk-PWC4CRWT.cjs.map +0 -1
  126. package/dist/chunk-RFIBF2RR.js.map +0 -1
  127. package/dist/chunk-S5BKZZGM.cjs.map +0 -1
  128. package/dist/chunk-UMWZ4ZET.js.map +0 -1
  129. package/dist/chunk-YFA7X2F6.cjs.map +0 -1
  130. package/dist/chunk-ZBUROTJQ.js.map +0 -1
@@ -169,29 +169,52 @@ function describesMap(index, map) {
169
169
  }
170
170
  return true;
171
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);
172
+ function meterSegments(map) {
173
+ const segments = new Array(map.length);
178
174
  let bars = 0;
175
+ let atZero = 0;
179
176
  for (let i = 0; i < map.length; i += 1) {
180
177
  const entry = map[i];
181
178
  const startBeat = entry?.startBeat ?? 0;
182
179
  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;
180
+ const barAnchor = i === 0 ? 0 : startBeat;
181
+ segments[i] = {
182
+ startBeat,
183
+ ts: entry === void 0 ? { numerator: 4, denominator: 4 } : copyTimeSignature(entry.ts),
184
+ barAnchor,
185
+ barBeats: barLen,
186
+ barsBefore: bars
187
+ };
188
+ if (i > 0 && startBeat <= BEAT_EPS) {
189
+ atZero = i;
190
+ }
189
191
  const next = map[i + 1];
190
192
  if (next !== void 0 && barLen > 0) {
191
- bars += Math.max(1, Math.ceil((next.startBeat - anchor) / barLen - BEAT_EPS));
193
+ const span = Math.ceil((next.startBeat - barAnchor) / barLen - BEAT_EPS);
194
+ bars += i === 0 ? span : Math.max(1, span);
192
195
  }
193
196
  }
194
- const index = { startBeats, signatures, barAnchors, barBeats, barsBefore, validated };
197
+ const zero = segments[atZero];
198
+ if (atZero > 0 && zero !== void 0 && zero.barBeats > 0) {
199
+ const shift = zero.barsBefore + Math.floor(-zero.barAnchor / zero.barBeats + BEAT_EPS);
200
+ if (shift !== 0) {
201
+ for (const segment of segments) {
202
+ segment.barsBefore -= shift;
203
+ }
204
+ }
205
+ }
206
+ return segments;
207
+ }
208
+ function buildMeterIndex(map, validated) {
209
+ const segments = meterSegments(map);
210
+ const index = {
211
+ startBeats: segments.map((segment) => segment.startBeat),
212
+ signatures: segments.map((segment) => segment.ts),
213
+ barAnchors: segments.map((segment) => segment.barAnchor),
214
+ barBeats: segments.map((segment) => segment.barBeats),
215
+ barsBefore: segments.map((segment) => segment.barsBefore),
216
+ validated
217
+ };
195
218
  INDEX_CACHE.set(map, index);
196
219
  return rememberRead(map, index);
197
220
  }
@@ -285,9 +308,16 @@ function describeRejected(value) {
285
308
  }
286
309
  return value.length <= MAX_ECHOED_LENGTH ? JSON.stringify(value) : `${JSON.stringify(value.slice(0, MAX_ECHOED_LENGTH))} (truncated from ${value.length} characters)`;
287
310
  }
311
+ function receivedText(value) {
312
+ try {
313
+ return `${value}`;
314
+ } catch {
315
+ return describeRejected(value);
316
+ }
317
+ }
288
318
  function assertFiniteNumber(value, name) {
289
319
  if (!Number.isFinite(value)) {
290
- throw new InvalidInputError(`${name} must be finite; received ${value}`);
320
+ throw new InvalidInputError(`${name} must be finite; received ${receivedText(value)}`);
291
321
  }
292
322
  return value;
293
323
  }
@@ -433,7 +463,7 @@ function assertTimeSignature(ts, name = "time signature") {
433
463
  }
434
464
  function assertMeterMap(meters, name = "meters") {
435
465
  if (!Array.isArray(meters)) {
436
- throw new InvalidInputError(`${name} must be an array; received ${typeof meters}`);
466
+ throw new InvalidInputError(`${name} must be an array; received ${describeRejected(meters)}`);
437
467
  }
438
468
  if (meters.length === 0) {
439
469
  throw new InvalidInputError(`${name} must not be empty`);
@@ -496,7 +526,7 @@ function assertNoteEvent(event, name = "note event", options = {}) {
496
526
  function assertNoteEvents(events, name = "note events", options = {}) {
497
527
  const asked = assertOptions(options, `${name} options`);
498
528
  if (!Array.isArray(events)) {
499
- throw new InvalidInputError(`${name} must be an array; received ${typeof events}`);
529
+ throw new InvalidInputError(`${name} must be an array; received ${describeRejected(events)}`);
500
530
  }
501
531
  assertGenerationBudget(events.length, `${name} count`, asked.budget);
502
532
  for (let index = 0; index < events.length; index += 1) {
@@ -592,7 +622,7 @@ function parseEnglish(text) {
592
622
  }
593
623
  const note = { letter, alter };
594
624
  if (match[3] !== void 0) {
595
- note.octave = Number.parseInt(match[3], 10);
625
+ note.octave = octaveOf(match[3]);
596
626
  }
597
627
  return note;
598
628
  }
@@ -733,7 +763,11 @@ function splitOctave(text) {
733
763
  return { name: text, octave: void 0 };
734
764
  }
735
765
  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) };
766
+ return { name: text.slice(0, signed), octave: octaveOf(text.slice(signed)) };
767
+ }
768
+ function octaveOf(digits) {
769
+ const octave = Number.parseInt(digits, 10);
770
+ return octave === 0 ? 0 : octave;
737
771
  }
738
772
  function parseIn(text, system) {
739
773
  const table = tableOf(system);
@@ -999,12 +1033,16 @@ function transposeNote(note, semitones, opts) {
999
1033
  const octaves = Math.floor(magnitude / 12);
1000
1034
  const withinOctave = magnitude % 12;
1001
1035
  const letterSteps = direction * ((LETTER_STEPS_BY_SEMITONE[withinOctave] ?? 0) + 7 * octaves);
1002
- const absoluteLetter = mod7(note.letter) + letterSteps;
1036
+ return landOnLetter(note, mod7(note.letter) + letterSteps, steps);
1037
+ }
1038
+ function landOnLetter(note, absoluteLetter, steps) {
1003
1039
  const letter = mod7(absoluteLetter);
1004
1040
  const natural = LETTER_SEMITONES[letter] ?? 0;
1005
1041
  if (note.octave === void 0) {
1042
+ const source = LETTER_SEMITONES[mod7(note.letter)] ?? 0;
1043
+ const wrapped = 12 * Math.floor(absoluteLetter / 7);
1006
1044
  return assertNote(
1007
- { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) },
1045
+ { letter, alter: note.alter + source + steps - wrapped - natural },
1008
1046
  "transposed note"
1009
1047
  );
1010
1048
  }
@@ -1017,10 +1055,6 @@ function transposeNote(note, semitones, opts) {
1017
1055
  function bareOf(note) {
1018
1056
  return { letter: note.letter, alter: note.alter };
1019
1057
  }
1020
- function alterFor(natural, pc) {
1021
- const d = mod12(pc - natural);
1022
- return d > 6 ? d - 12 : d;
1023
- }
1024
1058
  var SIMPLE_REFERENCE = [0, 0, 2, 4, 5, 7, 9, 11];
1025
1059
  function isPerfectNumber(simpleNumber) {
1026
1060
  return simpleNumber === 1 || simpleNumber === 4 || simpleNumber === 5;
@@ -1030,7 +1064,7 @@ function qualityFromSpan(numberValue, semitones) {
1030
1064
  const simple = numberValue - 7 * octaves;
1031
1065
  const reference = (SIMPLE_REFERENCE[simple] ?? 0) + 12 * octaves;
1032
1066
  const delta = semitones - reference;
1033
- const repeat = (glyph, count) => `${glyph}${glyph.repeat(Math.min(count, MAX_ALTER * 2) - 1)}`;
1067
+ const repeat = (glyph, count) => `${glyph}${glyph.repeat(Math.min(count, MAX_ALTER * 2 + 1) - 1)}`;
1034
1068
  if (isPerfectNumber(simple)) {
1035
1069
  if (delta === 0) {
1036
1070
  return "P";
@@ -1170,21 +1204,7 @@ function transposeByInterval(given, named) {
1170
1204
  assertInteger(interval.number, "interval.number", 1, MAX_INTERVAL_NUMBER);
1171
1205
  assertFiniteNumber(interval.semitones, "interval.semitones");
1172
1206
  const letterSteps = (interval.number - 1) * (isDescendingInterval(interval) ? -1 : 1);
1173
- const absoluteLetter = mod7(note.letter) + letterSteps;
1174
- const letter = mod7(absoluteLetter);
1175
- const natural = LETTER_SEMITONES[letter] ?? 0;
1176
- const steps = Math.round(interval.semitones);
1177
- if (note.octave === void 0) {
1178
- return assertNote(
1179
- { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) },
1180
- "transposed note"
1181
- );
1182
- }
1183
- const octave = note.octave + Math.floor(absoluteLetter / 7);
1184
- return assertNote(
1185
- { letter, alter: noteToMidi(note) + steps - ((octave + 1) * 12 + natural), octave },
1186
- "transposed note"
1187
- );
1207
+ return landOnLetter(note, mod7(note.letter) + letterSteps, Math.round(interval.semitones));
1188
1208
  }
1189
1209
  function diatonicIndex(note) {
1190
1210
  return mod7(note.letter) + 7 * (note.octave ?? 0);
@@ -1204,15 +1224,11 @@ function spelledInterval(a, b) {
1204
1224
  letterSteps = diatonicIndex(b) - diatonicIndex(a);
1205
1225
  semitones = noteToMidi(b) - noteToMidi(a);
1206
1226
  } else {
1207
- letterSteps = mod7(b.letter - a.letter);
1208
- let rawSemis = mod12(noteToPitchClass(b) - noteToPitchClass(a));
1209
- const reference = SIMPLE_REFERENCE[letterSteps + 1] ?? 0;
1210
- if (reference - rawSemis > 6) {
1211
- rawSemis += 12;
1212
- } else if (rawSemis - reference > 6) {
1213
- rawSemis -= 12;
1214
- }
1215
- semitones = rawSemis;
1227
+ const fromLetter = mod7(a.letter);
1228
+ const toLetter = mod7(b.letter);
1229
+ letterSteps = mod7(toLetter - fromLetter);
1230
+ const wrapped = toLetter < fromLetter ? 12 : 0;
1231
+ semitones = (LETTER_SEMITONES[toLetter] ?? 0) + wrapped - (LETTER_SEMITONES[fromLetter] ?? 0) + b.alter - a.alter;
1216
1232
  }
1217
1233
  const absSteps = Math.abs(letterSteps);
1218
1234
  const number = absSteps + 1;
@@ -1519,17 +1535,17 @@ function metricGridUnit(meter) {
1519
1535
  if (!isMeterMap(resolved)) {
1520
1536
  return pulseBeatsOf(resolved);
1521
1537
  }
1538
+ const segments = meterSegments(resolved);
1522
1539
  let unit = 0;
1523
- for (const change of resolved) {
1524
- unit = commonStep(unit, pulseBeatsOf(change.ts));
1540
+ for (const segment of segments) {
1541
+ unit = commonStep(unit, pulseBeatsOf(segment.ts));
1525
1542
  }
1526
1543
  if (unit <= 0) {
1527
1544
  return pulseBeatsOf(DEFAULT_TS);
1528
1545
  }
1529
- const origin = resolved[0]?.startBeat ?? 0;
1530
1546
  let onChanges = unit;
1531
- for (const change of resolved) {
1532
- onChanges = commonStep(onChanges, Math.abs(change.startBeat - origin));
1547
+ for (const segment of segments) {
1548
+ onChanges = commonStep(onChanges, Math.abs(segment.barAnchor));
1533
1549
  }
1534
1550
  return onChanges * MAX_CHANGE_DIVISIONS >= unit - BEAT_EPS ? onChanges : unit;
1535
1551
  }
@@ -1637,4 +1653,4 @@ export {
1637
1653
  isStrongBeat,
1638
1654
  tuplet
1639
1655
  };
1640
- //# sourceMappingURL=chunk-AGOVW7U6.js.map
1656
+ //# sourceMappingURL=chunk-YYVXRV3V.js.map