@libraz/libcantus 1.1.0 → 1.3.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 (103) hide show
  1. package/README.md +4 -0
  2. package/README_ja.md +4 -0
  3. package/dist/analyze/index.cjs +31 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +155 -9
  6. package/dist/analyze/index.d.ts +155 -9
  7. package/dist/analyze/index.js +37 -13
  8. package/dist/{chunk-TT6PKMPR.cjs → chunk-35NBV2FT.cjs} +16 -16
  9. package/dist/{chunk-TT6PKMPR.cjs.map → chunk-35NBV2FT.cjs.map} +1 -1
  10. package/dist/{chunk-YPB3A3EY.cjs → chunk-3R3QVKY5.cjs} +314 -285
  11. package/dist/chunk-3R3QVKY5.cjs.map +1 -0
  12. package/dist/{chunk-GDKE6RQW.cjs → chunk-4R2LWV7E.cjs} +691 -413
  13. package/dist/chunk-4R2LWV7E.cjs.map +1 -0
  14. package/dist/{chunk-RVS4G4MR.cjs → chunk-76ZBTRG2.cjs} +198 -198
  15. package/dist/{chunk-RVS4G4MR.cjs.map → chunk-76ZBTRG2.cjs.map} +1 -1
  16. package/dist/{chunk-X6RJAHII.js → chunk-7KG3RTYS.js} +2 -2
  17. package/dist/{chunk-PQL7E5F6.js → chunk-AGOVW7U6.js} +1 -1
  18. package/dist/{chunk-PQL7E5F6.js.map → chunk-AGOVW7U6.js.map} +1 -1
  19. package/dist/{chunk-5KW7DNCJ.cjs → chunk-B2PW6EHN.cjs} +2423 -453
  20. package/dist/chunk-B2PW6EHN.cjs.map +1 -0
  21. package/dist/{chunk-J772DL3B.cjs → chunk-CGBADIO5.cjs} +53 -53
  22. package/dist/{chunk-J772DL3B.cjs.map → chunk-CGBADIO5.cjs.map} +1 -1
  23. package/dist/{chunk-R5VUXQMP.js → chunk-CPMB7P75.js} +1978 -8
  24. package/dist/chunk-CPMB7P75.js.map +1 -0
  25. package/dist/{chunk-VLE5R7PF.js → chunk-GNVN4PPJ.js} +1874 -8
  26. package/dist/chunk-GNVN4PPJ.js.map +1 -0
  27. package/dist/{chunk-Q6R3QAZD.cjs → chunk-IFZDWIKM.cjs} +2199 -333
  28. package/dist/chunk-IFZDWIKM.cjs.map +1 -0
  29. package/dist/{chunk-DKICR7AN.js → chunk-IPEF6NWB.js} +296 -18
  30. package/dist/chunk-IPEF6NWB.js.map +1 -0
  31. package/dist/{chunk-AWEMD747.js → chunk-M5RYMAFI.js} +3 -3
  32. package/dist/{chunk-HSY2VQXZ.js → chunk-MLBPXA4Z.js} +330 -728
  33. package/dist/chunk-MLBPXA4Z.js.map +1 -0
  34. package/dist/{chunk-H66ARFU5.js → chunk-NB25P3EH.js} +3 -3
  35. package/dist/{chunk-5JJ6EHEZ.cjs → chunk-NM7UAMC3.cjs} +62 -62
  36. package/dist/{chunk-5JJ6EHEZ.cjs.map → chunk-NM7UAMC3.cjs.map} +1 -1
  37. package/dist/{chunk-R7B5N2JK.cjs → chunk-PM4XJE2Y.cjs} +47 -47
  38. package/dist/{chunk-R7B5N2JK.cjs.map → chunk-PM4XJE2Y.cjs.map} +1 -1
  39. package/dist/{chunk-7GOKQJTQ.js → chunk-PUKJP2Z5.js} +2 -2
  40. package/dist/{chunk-QCXYKSZS.cjs → chunk-PWC4CRWT.cjs} +19 -19
  41. package/dist/{chunk-QCXYKSZS.cjs.map → chunk-PWC4CRWT.cjs.map} +1 -1
  42. package/dist/{chunk-FPBZFNCD.js → chunk-RFIBF2RR.js} +47 -18
  43. package/dist/{chunk-FPBZFNCD.js.map → chunk-RFIBF2RR.js.map} +1 -1
  44. package/dist/{chunk-XKSO2V5I.cjs → chunk-S5BKZZGM.cjs} +1 -1
  45. package/dist/{chunk-XKSO2V5I.cjs.map → chunk-S5BKZZGM.cjs.map} +1 -1
  46. package/dist/{chunk-HOHFYGKW.js → chunk-UMWZ4ZET.js} +2 -2
  47. package/dist/{chunk-XVMJO3QF.cjs → chunk-YFA7X2F6.cjs} +489 -887
  48. package/dist/chunk-YFA7X2F6.cjs.map +1 -0
  49. package/dist/{chunk-57WB2EDF.js → chunk-ZBUROTJQ.js} +3 -3
  50. package/dist/{coerce-wwdELNYS.d.ts → coerce-DP0vYu-x.d.ts} +77 -1
  51. package/dist/{coerce-CJlgULrQ.d.cts → coerce-DRERzdve.d.cts} +77 -1
  52. package/dist/core/index.cjs +5 -5
  53. package/dist/core/index.d.cts +2 -2
  54. package/dist/core/index.d.ts +2 -2
  55. package/dist/core/index.js +4 -4
  56. package/dist/generate/index.cjs +20 -8
  57. package/dist/generate/index.cjs.map +1 -1
  58. package/dist/generate/index.d.cts +87 -9
  59. package/dist/generate/index.d.ts +87 -9
  60. package/dist/generate/index.js +19 -7
  61. package/dist/{index-BaoKVVhE.d.cts → index-B9QLziDe.d.cts} +2 -2
  62. package/dist/{index-CnHQgqNh.d.ts → index-BHIUyjhZ.d.ts} +2 -2
  63. package/dist/{index-CBCP84rv.d.cts → index-BL5N2Oyz.d.cts} +1 -1
  64. package/dist/{index-D_hzxD8w.d.cts → index-BMweUlm5.d.cts} +3 -0
  65. package/dist/{index-Ci3xyows.d.ts → index-CL4b4gUQ.d.ts} +3 -0
  66. package/dist/{index-BzLNkmA7.d.cts → index-CY-3NVfy.d.cts} +486 -5
  67. package/dist/{index-CnIdP4EZ.d.ts → index-Dw2DP7vm.d.ts} +1 -1
  68. package/dist/{index-DpC-mDlV.d.ts → index-zaZdmnU4.d.ts} +486 -5
  69. package/dist/index.cjs +49 -13
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/index.d.cts +10 -10
  72. package/dist/index.d.ts +10 -10
  73. package/dist/index.js +55 -19
  74. package/dist/{masks-O73Rhj5d.d.ts → masks-Cc7-MzzY.d.ts} +1 -1
  75. package/dist/{masks-C8TWLFIi.d.cts → masks-pADfTOiD.d.cts} +1 -1
  76. package/dist/model/index.cjs +12 -12
  77. package/dist/model/index.d.cts +213 -16
  78. package/dist/model/index.d.ts +213 -16
  79. package/dist/model/index.js +11 -11
  80. package/dist/{index-DTsKaPaC.d.cts → profile-CQMEqdH9.d.cts} +88 -601
  81. package/dist/{index-BUtIf2go.d.ts → profile-DLdlIpS9.d.ts} +88 -601
  82. package/dist/theory/index.cjs +5 -5
  83. package/dist/theory/index.d.cts +7 -7
  84. package/dist/theory/index.d.ts +7 -7
  85. package/dist/theory/index.js +4 -4
  86. package/dist/{index-BpWOhkkE.d.ts → types-D-XgxGvp.d.cts} +1170 -14
  87. package/dist/{index-B3WCj_Hm.d.cts → types-Dh7C064C.d.ts} +1170 -14
  88. package/package.json +6 -5
  89. package/dist/chunk-5KW7DNCJ.cjs.map +0 -1
  90. package/dist/chunk-DKICR7AN.js.map +0 -1
  91. package/dist/chunk-GDKE6RQW.cjs.map +0 -1
  92. package/dist/chunk-HSY2VQXZ.js.map +0 -1
  93. package/dist/chunk-Q6R3QAZD.cjs.map +0 -1
  94. package/dist/chunk-R5VUXQMP.js.map +0 -1
  95. package/dist/chunk-VLE5R7PF.js.map +0 -1
  96. package/dist/chunk-XVMJO3QF.cjs.map +0 -1
  97. package/dist/chunk-YPB3A3EY.cjs.map +0 -1
  98. /package/dist/{chunk-X6RJAHII.js.map → chunk-7KG3RTYS.js.map} +0 -0
  99. /package/dist/{chunk-AWEMD747.js.map → chunk-M5RYMAFI.js.map} +0 -0
  100. /package/dist/{chunk-H66ARFU5.js.map → chunk-NB25P3EH.js.map} +0 -0
  101. /package/dist/{chunk-7GOKQJTQ.js.map → chunk-PUKJP2Z5.js.map} +0 -0
  102. /package/dist/{chunk-HOHFYGKW.js.map → chunk-UMWZ4ZET.js.map} +0 -0
  103. /package/dist/{chunk-57WB2EDF.js.map → chunk-ZBUROTJQ.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkTT6PKMPRcjs = require('./chunk-TT6PKMPR.cjs');
3
+ var _chunk35NBV2FTcjs = require('./chunk-35NBV2FT.cjs');
4
4
 
5
5
 
6
6
 
@@ -47,8 +47,8 @@ var _chunkTT6PKMPRcjs = require('./chunk-TT6PKMPR.cjs');
47
47
 
48
48
 
49
49
 
50
- var _chunkYPB3A3EYcjs = require('./chunk-YPB3A3EY.cjs');
51
50
 
51
+ var _chunk3R3QVKY5cjs = require('./chunk-3R3QVKY5.cjs');
52
52
 
53
53
 
54
54
 
@@ -77,18 +77,31 @@ var _chunkYPB3A3EYcjs = require('./chunk-YPB3A3EY.cjs');
77
77
 
78
78
 
79
79
 
80
- var _chunkXKSO2V5Icjs = require('./chunk-XKSO2V5I.cjs');
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+ var _chunkS5BKZZGMcjs = require('./chunk-S5BKZZGM.cjs');
81
94
 
82
95
  // src/analyze/detect/modes.ts
83
96
  var MODAL_CANDIDATES = Object.freeze([
84
- { scaleName: "dorian", mode: "minor", mask: _chunkYPB3A3EYcjs.DORIAN_MASK, substitutions: [[8, 9]] },
85
- { scaleName: "phrygian", mode: "minor", mask: _chunkYPB3A3EYcjs.PHRYGIAN_MASK, substitutions: [[2, 1]] },
86
- { scaleName: "lydian", mode: "major", mask: _chunkYPB3A3EYcjs.LYDIAN_MASK, substitutions: [[5, 6]] },
87
- { scaleName: "mixolydian", mode: "major", mask: _chunkYPB3A3EYcjs.MIXOLYDIAN_MASK, substitutions: [[11, 10]] },
97
+ { scaleName: "dorian", mode: "minor", mask: _chunk3R3QVKY5cjs.DORIAN_MASK, substitutions: [[8, 9]] },
98
+ { scaleName: "phrygian", mode: "minor", mask: _chunk3R3QVKY5cjs.PHRYGIAN_MASK, substitutions: [[2, 1]] },
99
+ { scaleName: "lydian", mode: "major", mask: _chunk3R3QVKY5cjs.LYDIAN_MASK, substitutions: [[5, 6]] },
100
+ { scaleName: "mixolydian", mode: "major", mask: _chunk3R3QVKY5cjs.MIXOLYDIAN_MASK, substitutions: [[11, 10]] },
88
101
  {
89
102
  scaleName: "locrian",
90
103
  mode: "minor",
91
- mask: _chunkYPB3A3EYcjs.LOCRIAN_MASK,
104
+ mask: _chunk3R3QVKY5cjs.LOCRIAN_MASK,
92
105
  substitutions: [
93
106
  [2, 1],
94
107
  [7, 6]
@@ -115,12 +128,12 @@ function resolveModalCandidates(modes) {
115
128
  return MODAL_CANDIDATES;
116
129
  }
117
130
  if (!Array.isArray(modes)) {
118
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)("modes must be a boolean or an array of mode names");
131
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("modes must be a boolean or an array of mode names");
119
132
  }
120
133
  const requested = new Set(modes);
121
134
  for (const name of requested) {
122
135
  if (!MODAL_SCALE_NAMES.some((known) => known === name)) {
123
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(
136
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
124
137
  `unknown mode '${String(name)}'; expected one of ${MODAL_SCALE_NAMES.join(", ")}`
125
138
  );
126
139
  }
@@ -131,7 +144,7 @@ function resolveModalCandidates(modes) {
131
144
  // src/analyze/adjacency.ts
132
145
  var HUMANIZE_ADJACENCY = 0.05;
133
146
  function sameInstant(beat, other) {
134
- return Math.abs(beat - other) <= _chunkXKSO2V5Icjs.BEAT_EPS;
147
+ return Math.abs(beat - other) <= _chunkS5BKZZGMcjs.BEAT_EPS;
135
148
  }
136
149
  function adjacent(prevEnd, nextStart) {
137
150
  return Math.abs(nextStart - prevEnd) <= HUMANIZE_ADJACENCY;
@@ -145,7 +158,7 @@ var MAX_VELOCITY = 127;
145
158
  var ACCENT_DIVISOR = 3;
146
159
  function noteWeight(note, beats, meter) {
147
160
  const velocityFactor = note.velocity !== void 0 ? note.velocity / MAX_VELOCITY : 1;
148
- const accent = meter === void 0 ? 1 : 1 + _chunkXKSO2V5Icjs.metricWeight.call(void 0, note.startBeat, meter) / ACCENT_DIVISOR;
161
+ const accent = meter === void 0 ? 1 : 1 + _chunkS5BKZZGMcjs.metricWeight.call(void 0, note.startBeat, meter) / ACCENT_DIVISOR;
149
162
  return beats * velocityFactor * accent;
150
163
  }
151
164
  function bucketNotesBySlot(notes, grid, slotCount, opts) {
@@ -158,7 +171,7 @@ function bucketNotesBySlot(notes, grid, slotCount, opts) {
158
171
  Math.ceil((note.startBeat + note.durationBeat - grid.origin) / grid.slotBeats)
159
172
  );
160
173
  memberships += Math.max(0, lastExclusive - first);
161
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0, memberships, opts.name, opts.budget);
174
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, memberships, opts.name, opts.budget);
162
175
  for (let slot = first; slot < lastExclusive; slot += 1) {
163
176
  _optionalChain([buckets, 'access', _2 => _2[slot], 'optionalAccess', _3 => _3.push, 'call', _4 => _4(note)]);
164
177
  }
@@ -171,14 +184,14 @@ function windowWeights(notes, windowStart, windowEnd, meter) {
171
184
  for (const note of notes) {
172
185
  const noteEnd = note.startBeat + note.durationBeat;
173
186
  const overlap = Math.min(noteEnd, windowEnd) - Math.max(note.startBeat, windowStart);
174
- if (overlap <= _chunkXKSO2V5Icjs.BEAT_EPS) {
187
+ if (overlap <= _chunkS5BKZZGMcjs.BEAT_EPS) {
175
188
  continue;
176
189
  }
177
- const onsetInWindow = note.startBeat >= windowStart - _chunkXKSO2V5Icjs.BEAT_EPS && note.startBeat < windowEnd - _chunkXKSO2V5Icjs.BEAT_EPS;
178
- const pc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, note.pitch);
190
+ const onsetInWindow = note.startBeat >= windowStart - _chunkS5BKZZGMcjs.BEAT_EPS && note.startBeat < windowEnd - _chunkS5BKZZGMcjs.BEAT_EPS;
191
+ const pc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, note.pitch);
179
192
  const weight = noteWeight(note, overlap, onsetInWindow ? meter : void 0);
180
193
  weights[pc] = (_nullishCoalesce(weights[pc], () => ( 0))) + weight;
181
- if (weight > _chunkXKSO2V5Icjs.BEAT_EPS && note.pitch < lowestPitch) {
194
+ if (weight > _chunkS5BKZZGMcjs.BEAT_EPS && note.pitch < lowestPitch) {
182
195
  lowestPitch = note.pitch;
183
196
  }
184
197
  }
@@ -213,12 +226,12 @@ var NAMED_PROFILES = {
213
226
  };
214
227
  function assertProfileVector(vector, name) {
215
228
  if (vector.length !== PROFILE_LENGTH) {
216
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(`${name} must have ${PROFILE_LENGTH} entries`);
229
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must have ${PROFILE_LENGTH} entries`);
217
230
  }
218
231
  for (let index = 0; index < vector.length; index += 1) {
219
232
  const value = vector[index];
220
233
  if (typeof value !== "number" || !Number.isFinite(value)) {
221
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(`${name}[${index}] must be a finite number`);
234
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}[${index}] must be a finite number`);
222
235
  }
223
236
  }
224
237
  }
@@ -229,18 +242,18 @@ function resolveKeyProfile(profile) {
229
242
  if (typeof profile === "string") {
230
243
  const named = NAMED_PROFILES[profile];
231
244
  if (named === void 0) {
232
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(
245
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
233
246
  `unknown key profile '${profile}'; expected one of ${Object.keys(NAMED_PROFILES).join(", ")}`
234
247
  );
235
248
  }
236
249
  return named;
237
250
  }
238
251
  if (typeof profile !== "object" || profile === null) {
239
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)("profile must be a profile name or a { major, minor } pair");
252
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("profile must be a profile name or a { major, minor } pair");
240
253
  }
241
254
  const { major, minor } = profile;
242
255
  if (!Array.isArray(major) || !Array.isArray(minor)) {
243
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)("profile must carry a major and a minor vector");
256
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("profile must carry a major and a minor vector");
244
257
  }
245
258
  assertProfileVector(major, "profile.major");
246
259
  assertProfileVector(minor, "profile.minor");
@@ -290,44 +303,44 @@ function profileScore(dist, vector, tonic) {
290
303
 
291
304
  // src/analyze/detect/index.ts
292
305
  function uniquePitchClasses(pitches) {
293
- return [...new Set(pitches.map(_chunkXKSO2V5Icjs.pitchClassOf))].sort((a, b) => a - b);
306
+ return [...new Set(pitches.map(_chunkS5BKZZGMcjs.pitchClassOf))].sort((a, b) => a - b);
294
307
  }
295
308
  function assertPitches(pitches, name, budget = void 0) {
296
- _chunkXKSO2V5Icjs.assertArray.call(void 0, pitches, name);
297
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0, pitches.length, name, budget);
309
+ _chunkS5BKZZGMcjs.assertArray.call(void 0, pitches, name);
310
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, pitches.length, name, budget);
298
311
  for (let index = 0; index < pitches.length; index += 1) {
299
- _chunkXKSO2V5Icjs.assertMidiPitch.call(void 0, _nullishCoalesce(pitches[index], () => ( Number.NaN)), `pitches[${index}]`);
312
+ _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, _nullishCoalesce(pitches[index], () => ( Number.NaN)), `pitches[${index}]`);
300
313
  }
301
314
  }
302
315
  function detectChord(pitches, opts = {}) {
303
- const asked = _chunkXKSO2V5Icjs.assertOptions.call(void 0, opts, "opts");
316
+ const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
304
317
  assertPitches(pitches, "chord detection pitches");
305
- if (asked.bassPc !== void 0) _chunkXKSO2V5Icjs.assertFiniteNumber.call(void 0, asked.bassPc, "bassPc");
318
+ if (asked.bassPc !== void 0) _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, asked.bassPc, "bassPc");
306
319
  const input = uniquePitchClasses(pitches);
307
320
  if (input.length === 0) {
308
321
  return [];
309
322
  }
310
323
  const inputKind = asked.input === void 0 || asked.input === "auto" ? pitches.every((pitch) => Number.isInteger(pitch) && pitch >= 0 && pitch <= 11) ? "pitchClass" : "midi" : asked.input;
311
- const bassPc = asked.bassPc !== void 0 ? _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, asked.bassPc) : inputKind === "midi" ? _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, pitches.reduce((lowest, pitch) => Math.min(lowest, pitch), Infinity)) : void 0;
324
+ const bassPc = asked.bassPc !== void 0 ? _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, asked.bassPc) : inputKind === "midi" ? _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitches.reduce((lowest, pitch) => Math.min(lowest, pitch), Infinity)) : void 0;
312
325
  const inputSet = new Set(input);
313
326
  const matches = [];
314
- const qualities = _chunkYPB3A3EYcjs.chordQualities.call(void 0, );
327
+ const qualities = _chunk3R3QVKY5cjs.chordQualities.call(void 0, );
315
328
  const toneCounts = new Map(
316
- qualities.map((quality) => [quality, _chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, _chunkYPB3A3EYcjs.makeChord.call(void 0, 0, quality)).length])
329
+ qualities.map((quality) => [quality, _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, 0, quality)).length])
317
330
  );
318
331
  const qualityRank = new Map(qualities.map((quality, index) => [quality, index]));
319
332
  for (const rootPc of input) {
320
333
  for (const quality of qualities) {
321
- const chord = _chunkYPB3A3EYcjs.makeChord.call(void 0, rootPc, quality);
322
- const tones = _chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, chord);
334
+ const chord = _chunk3R3QVKY5cjs.makeChord.call(void 0, rootPc, quality);
335
+ const tones = _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord);
323
336
  const toneSet = new Set(tones);
324
337
  const missingPcs = tones.filter((pc) => !inputSet.has(pc));
325
- const fifthPc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc + 7);
338
+ const fifthPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc + 7);
326
339
  if (missingPcs.length > 1 || missingPcs.length === 1 && missingPcs[0] !== fifthPc) {
327
340
  continue;
328
341
  }
329
342
  const extraPcs = input.filter((pc) => !toneSet.has(pc));
330
- const bassIndex = bassPc === void 0 ? -1 : chord.intervals.findIndex((iv) => _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc + iv) === bassPc);
343
+ const bassIndex = bassPc === void 0 ? -1 : chord.intervals.findIndex((iv) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc + iv) === bassPc);
331
344
  const inversion = bassPc === void 0 || bassIndex < 0 ? null : bassIndex;
332
345
  const match = {
333
346
  rootPc,
@@ -372,15 +385,15 @@ function detectChordBest(pitches, opts = {}) {
372
385
  if (!best) {
373
386
  return null;
374
387
  }
375
- return _chunkYPB3A3EYcjs.makeChord.call(void 0, best.rootPc, best.quality, best.bassPc);
388
+ return _chunk3R3QVKY5cjs.makeChord.call(void 0, best.rootPc, best.quality, best.bassPc);
376
389
  }
377
390
  var MINOR_VARIANTS = [
378
- { variant: "natural", mask: _chunkYPB3A3EYcjs.NATURAL_MINOR_MASK, scaleName: "naturalMinor" },
379
- { variant: "harmonic", mask: _chunkYPB3A3EYcjs.HARMONIC_MINOR_MASK, scaleName: "harmonicMinor" },
380
- { variant: "melodic", mask: _chunkYPB3A3EYcjs.MELODIC_MINOR_MASK, scaleName: "melodicMinor" }
391
+ { variant: "natural", mask: _chunk3R3QVKY5cjs.NATURAL_MINOR_MASK, scaleName: "naturalMinor" },
392
+ { variant: "harmonic", mask: _chunk3R3QVKY5cjs.HARMONIC_MINOR_MASK, scaleName: "harmonicMinor" },
393
+ { variant: "melodic", mask: _chunk3R3QVKY5cjs.MELODIC_MINOR_MASK, scaleName: "melodicMinor" }
381
394
  ];
382
395
  var MAJOR_VARIANTS = [
383
- { variant: "major", mask: _chunkYPB3A3EYcjs.MAJOR_MASK, scaleName: "major" }
396
+ { variant: "major", mask: _chunk3R3QVKY5cjs.MAJOR_MASK, scaleName: "major" }
384
397
  ];
385
398
  var SCALE_NAME_ORDER = [
386
399
  "major",
@@ -407,7 +420,7 @@ function quoteScores(rival, winner) {
407
420
  return `${rival.toFixed(digits)} against ${winner.toFixed(digits)}`;
408
421
  }
409
422
  function keyLabel(match) {
410
- const tonic = _chunkXKSO2V5Icjs.formatNote.call(void 0, _chunkYPB3A3EYcjs.spelledKeyOf.call(void 0, match.key).tonic);
423
+ const tonic = _chunkS5BKZZGMcjs.formatNote.call(void 0, _chunk3R3QVKY5cjs.spelledKeyOf.call(void 0, match.key).tonic);
411
424
  const scale = match.scaleName.replace(/([A-Z])/g, " $1").toLowerCase();
412
425
  return `${tonic} ${scale}`;
413
426
  }
@@ -438,11 +451,11 @@ function explainMatches(results, inputSize) {
438
451
  winner.alternatives = results.slice(1, EXPLAINED_RIVALS + 1).map((rival) => ({ label: keyLabel(rival), reason: keyRivalReason(winner, rival) }));
439
452
  }
440
453
  function detectKey(pitches, opts = {}) {
441
- const asked = _chunkXKSO2V5Icjs.assertRecord.call(void 0, opts, "opts");
454
+ const asked = _chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "opts");
442
455
  assertPitches(pitches, "key detection pitches", asked.budget);
443
456
  const weights = asked.weights;
444
457
  if (weights !== void 0 && weights.length !== pitches.length) {
445
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)("weights must have one entry per pitch");
458
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("weights must have one entry per pitch");
446
459
  }
447
460
  const profile = resolveKeyProfile(opts.profile);
448
461
  const modalCandidates = resolveModalCandidates(opts.modes).map((candidate) => ({
@@ -453,11 +466,11 @@ function detectKey(pitches, opts = {}) {
453
466
  let total = 0;
454
467
  for (let index = 0; index < pitches.length; index += 1) {
455
468
  const weight = weights === void 0 ? 1 : _nullishCoalesce(weights[index], () => ( 0));
456
- _chunkXKSO2V5Icjs.assertFiniteNumber.call(void 0, weight, `weights[${index}]`);
469
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, weight, `weights[${index}]`);
457
470
  if (weight <= 0) {
458
471
  continue;
459
472
  }
460
- const pc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, _nullishCoalesce(pitches[index], () => ( 0)));
473
+ const pc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _nullishCoalesce(pitches[index], () => ( 0)));
461
474
  counts.set(pc, (_nullishCoalesce(counts.get(pc), () => ( 0))) + weight);
462
475
  total += weight;
463
476
  }
@@ -538,8 +551,8 @@ function detectKey(pitches, opts = {}) {
538
551
  return results;
539
552
  }
540
553
  function detectKeyFromNotes(notes, opts = {}) {
541
- const asked = _chunkXKSO2V5Icjs.assertOptions.call(void 0, opts, "opts");
542
- _chunkXKSO2V5Icjs.assertNoteEvents.call(void 0, notes, "key detection notes", {
554
+ const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
555
+ _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "key detection notes", {
543
556
  allowNonPositiveDuration: true,
544
557
  budget: asked.budget
545
558
  });
@@ -561,40 +574,40 @@ function detectKeyBest(pitches, opts = {}) {
561
574
 
562
575
  // src/analyze/functional/internal.ts
563
576
  function isMinorScale(key) {
564
- return _chunkYPB3A3EYcjs.isMinorMask.call(void 0, key.modeMask12);
577
+ return _chunk3R3QVKY5cjs.isMinorMask.call(void 0, key.modeMask12);
565
578
  }
566
579
  function parallelScale(key) {
567
580
  return {
568
- rootPc: _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc),
569
- modeMask12: isMinorScale(key) ? _chunkYPB3A3EYcjs.MAJOR_MASK : _chunkYPB3A3EYcjs.NATURAL_MINOR_MASK
581
+ rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc),
582
+ modeMask12: isMinorScale(key) ? _chunk3R3QVKY5cjs.MAJOR_MASK : _chunk3R3QVKY5cjs.NATURAL_MINOR_MASK
570
583
  };
571
584
  }
572
585
  function degreeRootPc(degreeNumber, key) {
573
- const tones = _chunkYPB3A3EYcjs.scaleTonesInDegreeOrder.call(void 0, key);
586
+ const tones = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, key);
574
587
  if (tones.length === 0) {
575
- return _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc);
588
+ return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
576
589
  }
577
590
  const index = ((degreeNumber - 1) % tones.length + tones.length) % tones.length;
578
- return _nullishCoalesce(tones[index], () => ( _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc)));
591
+ return _nullishCoalesce(tones[index], () => ( _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc)));
579
592
  }
580
593
  function loweredDegrees(key) {
581
- const tones = _chunkYPB3A3EYcjs.scaleTonesInDegreeOrder.call(void 0, key);
594
+ const tones = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, key);
582
595
  const out = /* @__PURE__ */ new Set();
583
596
  if (tones.length !== 7) {
584
597
  return out;
585
598
  }
586
- const major = _chunkYPB3A3EYcjs.scaleTonesInDegreeOrder.call(void 0, { rootPc: _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunkYPB3A3EYcjs.MAJOR_MASK });
599
+ const major = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, { rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunk3R3QVKY5cjs.MAJOR_MASK });
587
600
  for (let index = 0; index < 7; index += 1) {
588
601
  const tone = tones[index];
589
602
  const majorTone = major[index];
590
- if (tone !== void 0 && majorTone !== void 0 && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, majorTone - tone) === 1) {
603
+ if (tone !== void 0 && majorTone !== void 0 && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, majorTone - tone) === 1) {
591
604
  out.add(index + 1);
592
605
  }
593
606
  }
594
607
  return out;
595
608
  }
596
609
  function romanReference(key) {
597
- return _chunkYPB3A3EYcjs.heptatonicFrameOf.call(void 0, key);
610
+ return _chunk3R3QVKY5cjs.heptatonicFrameOf.call(void 0, key);
598
611
  }
599
612
 
600
613
  // src/analyze/functional/augmented-sixth.ts
@@ -606,11 +619,11 @@ var TONES_ABOVE_BASS = {
606
619
  german: [0, 4, 7, 10]
607
620
  };
608
621
  var SPELLED_ABOVE_BASS = {
609
- italian: ["P1", "M3", "A6"].map((name) => _chunkXKSO2V5Icjs.parseInterval.call(void 0, name)),
610
- french: ["P1", "M3", "A4", "A6"].map((name) => _chunkXKSO2V5Icjs.parseInterval.call(void 0, name)),
611
- german: ["P1", "M3", "P5", "A6"].map((name) => _chunkXKSO2V5Icjs.parseInterval.call(void 0, name))
622
+ italian: ["P1", "M3", "A6"].map((name) => _chunkS5BKZZGMcjs.parseInterval.call(void 0, name)),
623
+ french: ["P1", "M3", "A4", "A6"].map((name) => _chunkS5BKZZGMcjs.parseInterval.call(void 0, name)),
624
+ german: ["P1", "M3", "P5", "A6"].map((name) => _chunkS5BKZZGMcjs.parseInterval.call(void 0, name))
612
625
  };
613
- var BASS_INTERVAL = _chunkXKSO2V5Icjs.parseInterval.call(void 0, "m6");
626
+ var BASS_INTERVAL = _chunkS5BKZZGMcjs.parseInterval.call(void 0, "m6");
614
627
  var CHORD_SHAPE = {
615
628
  italian: { rootAboveBass: 0, quality: "dom7", intervals: [0, 4, 10] },
616
629
  french: { rootAboveBass: 6, quality: "7b5", intervals: [0, 4, 6, 10] },
@@ -629,7 +642,7 @@ var SYMBOL_BY_KIND = {
629
642
  german: "Ger6"
630
643
  };
631
644
  function bassPcOf(key) {
632
- return _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc + BASS_ABOVE_TONIC);
645
+ return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc + BASS_ABOVE_TONIC);
633
646
  }
634
647
  function bareSpelling(note) {
635
648
  return { letter: note.letter, alter: note.alter };
@@ -643,13 +656,13 @@ function augmentedSixthChord(kind, key) {
643
656
  return augmentedSixthOn(kind, key);
644
657
  }
645
658
  function augmentedSixthOn(kind, keyLike) {
646
- const checked = _chunkXKSO2V5Icjs.assertOneOf.call(void 0, kind, KINDS, "augmented sixth kind");
659
+ const checked = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, kind, KINDS, "augmented sixth kind");
647
660
  const shape = CHORD_SHAPE[checked];
648
- const { scale: key, tonic } = _chunkYPB3A3EYcjs.resolveKey.call(void 0, keyLike);
661
+ const { scale: key, tonic } = _chunk3R3QVKY5cjs.resolveKey.call(void 0, keyLike);
649
662
  const bassPc = bassPcOf(key);
650
- const chord = _chunkYPB3A3EYcjs.makeChord.call(void 0, _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, bassPc + shape.rootAboveBass), shape.quality, bassPc);
663
+ const chord = _chunk3R3QVKY5cjs.makeChord.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, bassPc + shape.rootAboveBass), shape.quality, bassPc);
651
664
  chord.intervals = [...shape.intervals];
652
- const bass = _chunkXKSO2V5Icjs.transposeByInterval.call(void 0, tonic, BASS_INTERVAL);
665
+ const bass = _chunkS5BKZZGMcjs.transposeByInterval.call(void 0, tonic, BASS_INTERVAL);
653
666
  const tones = spelledInChordOrder(checked, tonic);
654
667
  const [root = bass] = tones;
655
668
  chord.rootSpelling = bareSpelling(root);
@@ -660,55 +673,55 @@ function augmentedSixthOn(kind, keyLike) {
660
673
  function kindOfPitchClasses(pcs, bass) {
661
674
  for (const kind of KINDS) {
662
675
  const tones = TONES_ABOVE_BASS[kind];
663
- if (pcs.size === tones.length && tones.every((tone) => pcs.has(_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, bass + tone)))) {
676
+ if (pcs.size === tones.length && tones.every((tone) => pcs.has(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, bass + tone)))) {
664
677
  return kind;
665
678
  }
666
679
  }
667
680
  return null;
668
681
  }
669
682
  function spellingId(note) {
670
- return `${_chunkXKSO2V5Icjs.diatonicLetterOf.call(void 0, note.letter)}:${note.alter}`;
683
+ return `${_chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, note.letter)}:${note.alter}`;
671
684
  }
672
685
  function spellsAugmentedSixth(chord, kind, key) {
673
686
  const tonic = key.tonic;
674
- const written = new Set(_chunkYPB3A3EYcjs.spellChord.call(void 0, chord, tonic, key.scale).map(spellingId));
687
+ const written = new Set(_chunk3R3QVKY5cjs.spellChord.call(void 0, chord, tonic, key.scale).map(spellingId));
675
688
  const tones = spelledFromTonic(kind, tonic).map(spellingId);
676
689
  return written.size === tones.length && tones.every((tone) => written.has(tone));
677
690
  }
678
691
  function augmentedSixthKind(chord, key) {
679
- return augmentedSixthKindOf(_chunkYPB3A3EYcjs.toChordData.call(void 0, chord), key);
692
+ return augmentedSixthKindOf(_chunk3R3QVKY5cjs.toChordData.call(void 0, chord), key);
680
693
  }
681
694
  function augmentedSixthKindOf(chord, keyLike) {
682
- const resolved = _chunkYPB3A3EYcjs.resolveKey.call(void 0, keyLike);
695
+ const resolved = _chunk3R3QVKY5cjs.resolveKey.call(void 0, keyLike);
683
696
  const bass = bassPcOf(resolved.scale);
684
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc))) !== bass) {
697
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc))) !== bass) {
685
698
  return null;
686
699
  }
687
- const kind = kindOfPitchClasses(new Set(_chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, chord)), bass);
700
+ const kind = kindOfPitchClasses(new Set(_chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord)), bass);
688
701
  if (kind === null || !spellsAugmentedSixth(chord, kind, resolved)) {
689
702
  return null;
690
703
  }
691
704
  return kind;
692
705
  }
693
706
  function augmentedSixthFromPitchClasses(pcs, bassPc, key) {
694
- return augmentedSixthOverBass(_chunkXKSO2V5Icjs.assertArray.call(void 0, pcs, "pcs"), bassPc, key);
707
+ return augmentedSixthOverBass(_chunkS5BKZZGMcjs.assertArray.call(void 0, pcs, "pcs"), bassPc, key);
695
708
  }
696
709
  function augmentedSixthOverBass(pcs, bassPc, keyLike) {
697
- const resolved = _chunkYPB3A3EYcjs.resolveKey.call(void 0, keyLike);
710
+ const resolved = _chunk3R3QVKY5cjs.resolveKey.call(void 0, keyLike);
698
711
  const bass = bassPcOf(resolved.scale);
699
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, bassPc) !== bass) {
712
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, bassPc) !== bass) {
700
713
  return null;
701
714
  }
702
- const kind = kindOfPitchClasses(new Set(pcs.map(_chunkXKSO2V5Icjs.pitchClassOf)), bass);
715
+ const kind = kindOfPitchClasses(new Set(pcs.map(_chunkS5BKZZGMcjs.pitchClassOf)), bass);
703
716
  return kind === null ? null : augmentedSixthOn(kind, resolved);
704
717
  }
705
718
  function spellAugmentedSixth(kind, tonic) {
706
- return spelledFromTonic(kind, _chunkXKSO2V5Icjs.toNoteData.call(void 0, tonic));
719
+ return spelledFromTonic(kind, _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic));
707
720
  }
708
721
  function spelledFromTonic(kind, tonic) {
709
- const checked = _chunkXKSO2V5Icjs.assertOneOf.call(void 0, kind, KINDS, "augmented sixth kind");
710
- const bass = _chunkXKSO2V5Icjs.transposeByInterval.call(void 0, tonic, BASS_INTERVAL);
711
- return SPELLED_ABOVE_BASS[checked].map((interval) => _chunkXKSO2V5Icjs.transposeByInterval.call(void 0, bass, interval));
722
+ const checked = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, kind, KINDS, "augmented sixth kind");
723
+ const bass = _chunkS5BKZZGMcjs.transposeByInterval.call(void 0, tonic, BASS_INTERVAL);
724
+ return SPELLED_ABOVE_BASS[checked].map((interval) => _chunkS5BKZZGMcjs.transposeByInterval.call(void 0, bass, interval));
712
725
  }
713
726
  function augmentedSixthFromSymbol(symbol, key) {
714
727
  const kind = KIND_BY_SYMBOL.get(symbol);
@@ -724,11 +737,11 @@ var SUBDOMINANT_DEGREE = 4;
724
737
  var DOMINANT_DEGREE = 5;
725
738
  var SUBMEDIANT_DEGREE = 6;
726
739
  function degreeOffset(degreeNumber, key) {
727
- return _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, degreeRootPc(degreeNumber, romanReference(key)) - key.rootPc);
740
+ return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, degreeRootPc(degreeNumber, romanReference(key)) - key.rootPc);
728
741
  }
729
742
  function thirdBelongsToKey(chord, key) {
730
743
  return chord.intervals.some(
731
- (interval) => (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, interval) === 3 || _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, interval) === 4) && _chunkYPB3A3EYcjs.isScaleTone.call(void 0, _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc + interval), key)
744
+ (interval) => (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval) === 3 || _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval) === 4) && _chunk3R3QVKY5cjs.isScaleTone.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval), key)
732
745
  );
733
746
  }
734
747
  function deceptiveTargets(key) {
@@ -740,25 +753,25 @@ function deceptiveTargets(key) {
740
753
  return borrowed === submediant ? [submediant] : [submediant, borrowed];
741
754
  }
742
755
  function restsOnDominant(to, key) {
743
- if (_chunkYPB3A3EYcjs.hasMajorThird.call(void 0, to) || _chunkYPB3A3EYcjs.isDominantChordOf.call(void 0, to, key)) {
756
+ if (_chunk3R3QVKY5cjs.hasMajorThird.call(void 0, to) || _chunk3R3QVKY5cjs.isDominantChordOf.call(void 0, to, key)) {
744
757
  return true;
745
758
  }
746
- if (_chunkYPB3A3EYcjs.scaleSystemOf.call(void 0, key) !== "modal") {
759
+ if (_chunk3R3QVKY5cjs.scaleSystemOf.call(void 0, key) !== "modal") {
747
760
  return false;
748
761
  }
749
- const dominantPc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc + degreeOffset(DOMINANT_DEGREE, key));
750
- const leadingToneDominant = _chunkYPB3A3EYcjs.isScaleTone.call(void 0, _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, dominantPc + 4), key);
762
+ const dominantPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc + degreeOffset(DOMINANT_DEGREE, key));
763
+ const leadingToneDominant = _chunk3R3QVKY5cjs.isScaleTone.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, dominantPc + 4), key);
751
764
  return !leadingToneDominant && thirdBelongsToKey(to, key);
752
765
  }
753
766
  function isTonicSixFour(chord, key) {
754
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) !== 0 || chord.bassPc === void 0) {
767
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) !== 0 || chord.bassPc === void 0) {
755
768
  return false;
756
769
  }
757
- const isTriad = chord.intervals.length === 3 && chord.intervals.some((interval) => _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, interval) === 7);
758
- return isTriad && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.bassPc - chord.rootPc) === 7;
770
+ const isTriad = chord.intervals.length === 3 && chord.intervals.some((interval) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval) === 7);
771
+ return isTriad && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.bassPc - chord.rootPc) === 7;
759
772
  }
760
773
  function isCadentialSixFour(chord, next, key) {
761
- return isTonicSixFour(chord, key) && _chunkYPB3A3EYcjs.isDominantChordOf.call(void 0, next, key) && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc))) === _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, _nullishCoalesce(next.bassPc, () => ( next.rootPc)));
774
+ return isTonicSixFour(chord, key) && _chunk3R3QVKY5cjs.isDominantChordOf.call(void 0, next, key) && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc))) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _nullishCoalesce(next.bassPc, () => ( next.rootPc)));
762
775
  }
763
776
  function outerPitches(voicing) {
764
777
  let bass;
@@ -777,20 +790,28 @@ function outerPitches(voicing) {
777
790
  return { bass, soprano };
778
791
  }
779
792
  function bassPcOf2(chord, voicedBass) {
780
- return _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, _nullishCoalesce(_nullishCoalesce(voicedBass, () => ( chord.bassPc)), () => ( chord.rootPc)));
793
+ return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _nullishCoalesce(_nullishCoalesce(voicedBass, () => ( chord.bassPc)), () => ( chord.rootPc)));
781
794
  }
795
+ var CADENCE_TYPES = Object.freeze([
796
+ "authentic",
797
+ "plagal",
798
+ "half",
799
+ "deceptive",
800
+ "phrygian",
801
+ "modal"
802
+ ]);
782
803
  function cadenceType(from, to, key, fromBassPc, toBassPc) {
783
- const tonic = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc);
784
- const fromOffset = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, from.rootPc - tonic);
785
- const toOffset = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, to.rootPc - tonic);
786
- const dominant = _chunkYPB3A3EYcjs.isDominantChordOf.call(void 0, from, key);
787
- if ((dominant || _chunkYPB3A3EYcjs.isLeadingToneChordOf.call(void 0, from, key)) && toOffset === 0) {
804
+ const tonic = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
805
+ const fromOffset = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, from.rootPc - tonic);
806
+ const toOffset = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, to.rootPc - tonic);
807
+ const dominant = _chunk3R3QVKY5cjs.isDominantChordOf.call(void 0, from, key);
808
+ if ((dominant || _chunk3R3QVKY5cjs.isLeadingToneChordOf.call(void 0, from, key)) && toOffset === 0) {
788
809
  return "authentic";
789
810
  }
790
811
  if (fromOffset === degreeOffset(SUBDOMINANT_DEGREE, key) && toOffset === 0) {
791
812
  return "plagal";
792
813
  }
793
- if (fromOffset === 10 && toOffset === 0 && _chunkYPB3A3EYcjs.hasMajorThird.call(void 0, from)) {
814
+ if (fromOffset === 10 && toOffset === 0 && _chunk3R3QVKY5cjs.hasMajorThird.call(void 0, from)) {
794
815
  return "modal";
795
816
  }
796
817
  if (dominant && deceptiveTargets(key).includes(toOffset)) {
@@ -798,7 +819,7 @@ function cadenceType(from, to, key, fromBassPc, toBassPc) {
798
819
  }
799
820
  const dominantOffset = degreeOffset(DOMINANT_DEGREE, key);
800
821
  const half = toOffset === dominantOffset && restsOnDominant(to, key) && fromOffset !== dominantOffset;
801
- if (half && isMinorScale(key) && fromOffset === 5 && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, fromBassPc - tonic) === 8 && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, toBassPc - tonic) === 7) {
822
+ if (half && isMinorScale(key) && fromOffset === 5 && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, fromBassPc - tonic) === 8 && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, toBassPc - tonic) === 7) {
802
823
  return "phrygian";
803
824
  }
804
825
  return half ? "half" : null;
@@ -900,12 +921,12 @@ function cadenceAlternatives(facts) {
900
921
  return out;
901
922
  }
902
923
  function detectCadence(from, to, key, opts = {}) {
903
- const { approach, ...rest } = _chunkXKSO2V5Icjs.assertOptions.call(void 0, opts, "opts");
924
+ const { approach, ...rest } = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
904
925
  return cadenceBetween(
905
- _chunkYPB3A3EYcjs.toChordData.call(void 0, from),
906
- _chunkYPB3A3EYcjs.toChordData.call(void 0, to),
907
- _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key),
908
- approach === void 0 ? rest : { ...rest, approach: _chunkYPB3A3EYcjs.toChordData.call(void 0, approach) }
926
+ _chunk3R3QVKY5cjs.toChordData.call(void 0, from),
927
+ _chunk3R3QVKY5cjs.toChordData.call(void 0, to),
928
+ _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key),
929
+ approach === void 0 ? rest : { ...rest, approach: _chunk3R3QVKY5cjs.toChordData.call(void 0, approach) }
909
930
  );
910
931
  }
911
932
  function cadenceBetween(from, to, key, opts = {}) {
@@ -914,11 +935,11 @@ function cadenceBetween(from, to, key, opts = {}) {
914
935
  const toOuter = outerPitches(_nullishCoalesce(toVoicing, () => ( [])));
915
936
  const fromBassPc = bassPcOf2(from, fromOuter.bass);
916
937
  const toBassPc = bassPcOf2(to, toOuter.bass);
917
- const toRootPosition = toBassPc === _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, to.rootPc);
918
- const rootPosition = fromBassPc === _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, from.rootPc) && toRootPosition;
919
- const soprano = toOuter.soprano === void 0 ? null : _chunkYPB3A3EYcjs.chordToneRole.call(void 0, toOuter.soprano, to);
938
+ const toRootPosition = toBassPc === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, to.rootPc);
939
+ const rootPosition = fromBassPc === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, from.rootPc) && toRootPosition;
940
+ const soprano = toOuter.soprano === void 0 ? null : _chunk3R3QVKY5cjs.chordToneRole.call(void 0, toOuter.soprano, to);
920
941
  const type = cadenceType(from, to, key, fromBassPc, toBassPc);
921
- const leadingTone = _chunkYPB3A3EYcjs.isLeadingToneChordOf.call(void 0, from, key);
942
+ const leadingTone = _chunk3R3QVKY5cjs.isLeadingToneChordOf.call(void 0, from, key);
922
943
  const facts = {
923
944
  type,
924
945
  strength: type === "authentic" ? authenticStrength(leadingTone, rootPosition, toOuter.soprano !== void 0, soprano) : null,
@@ -927,10 +948,10 @@ function cadenceBetween(from, to, key, opts = {}) {
927
948
  // promised is the one it does not get.
928
949
  evaded: type === "authentic" && !toRootPosition,
929
950
  leadingTone,
930
- fromOffset: _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, from.rootPc - key.rootPc),
931
- toOffset: _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, to.rootPc - key.rootPc),
951
+ fromOffset: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, from.rootPc - key.rootPc),
952
+ toOffset: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, to.rootPc - key.rootPc),
932
953
  minor: isMinorScale(key),
933
- onFifthDegree: _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, to.rootPc - key.rootPc) === degreeOffset(DOMINANT_DEGREE, key),
954
+ onFifthDegree: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, to.rootPc - key.rootPc) === degreeOffset(DOMINANT_DEGREE, key),
934
955
  sixFour: opts.approach !== void 0 && isCadentialSixFour(opts.approach, from, key),
935
956
  withinSixFour: isCadentialSixFour(from, to, key)
936
957
  };
@@ -951,53 +972,53 @@ function cadenceBetween(from, to, key, opts = {}) {
951
972
  // src/analyze/functional/borrowed.ts
952
973
  function isMinorScaleAlteration(chord, key) {
953
974
  if (!isMinorScale(key)) return false;
954
- const alteredKey = { rootPc: _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunkYPB3A3EYcjs.HARMONIC_MINOR_MASK };
955
- if (_chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, alteredKey)) return true;
956
- return _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) === 11 && _chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, { rootPc: _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunkYPB3A3EYcjs.MELODIC_MINOR_MASK });
975
+ const alteredKey = { rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunk3R3QVKY5cjs.HARMONIC_MINOR_MASK };
976
+ if (_chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, alteredKey)) return true;
977
+ return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) === 11 && _chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, { rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunk3R3QVKY5cjs.MELODIC_MINOR_MASK });
957
978
  }
958
979
  function isBorrowed(chord, key) {
959
- if (_chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, key)) {
980
+ if (_chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, key)) {
960
981
  return false;
961
982
  }
962
- if (_chunkYPB3A3EYcjs.isNeapolitanChordOf.call(void 0, chord, key)) {
983
+ if (_chunk3R3QVKY5cjs.isNeapolitanChordOf.call(void 0, chord, key)) {
963
984
  return true;
964
985
  }
965
986
  if (isMinorScaleAlteration(chord, key)) {
966
987
  return false;
967
988
  }
968
- return _chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, parallelScale(key));
989
+ return _chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, parallelScale(key));
969
990
  }
970
991
  function borrowedSourceOf(chord, key) {
971
- if (_chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, key)) {
992
+ if (_chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, key)) {
972
993
  return null;
973
994
  }
974
- if (_chunkYPB3A3EYcjs.isNeapolitanChordOf.call(void 0, chord, key)) return "neapolitan";
995
+ if (_chunk3R3QVKY5cjs.isNeapolitanChordOf.call(void 0, chord, key)) return "neapolitan";
975
996
  if (isBorrowed(chord, key)) {
976
997
  return isMinorScale(key) ? "parallelMajor" : "parallelMinor";
977
998
  }
978
999
  return null;
979
1000
  }
980
1001
  function isBorrowedChord(chord, key) {
981
- return isBorrowed(_chunkYPB3A3EYcjs.toChordData.call(void 0, chord), _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key));
1002
+ return isBorrowed(_chunk3R3QVKY5cjs.toChordData.call(void 0, chord), _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key));
982
1003
  }
983
1004
  function borrowedSource(chord, key) {
984
- return borrowedSourceOf(_chunkYPB3A3EYcjs.toChordData.call(void 0, chord), _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key));
1005
+ return borrowedSourceOf(_chunk3R3QVKY5cjs.toChordData.call(void 0, chord), _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key));
985
1006
  }
986
1007
 
987
1008
  // src/analyze/functional/tonicization.ts
988
1009
  function isTonicizableRoot(rootPc, key) {
989
- return _chunkYPB3A3EYcjs.tonicizableDegrees.call(void 0, key).some((degree) => degree.rootPc === _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc));
1010
+ return _chunk3R3QVKY5cjs.tonicizableDegrees.call(void 0, key).some((degree) => degree.rootPc === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc));
990
1011
  }
991
1012
  function appliedTarget(chord, key) {
992
- const dominant = _chunkYPB3A3EYcjs.hasDominantSonority.call(void 0, chord);
993
- const leadingTone = _chunkYPB3A3EYcjs.LEADING_TONE_QUALITIES.has(chord.quality);
1013
+ const dominant = _chunk3R3QVKY5cjs.hasDominantSonority.call(void 0, chord);
1014
+ const leadingTone = _chunk3R3QVKY5cjs.LEADING_TONE_QUALITIES.has(chord.quality);
994
1015
  if (!dominant && !leadingTone) {
995
1016
  return null;
996
1017
  }
997
- return _chunkYPB3A3EYcjs.appliedDominantTarget.call(void 0, chord.rootPc + (dominant ? 5 : 1), key);
1018
+ return _chunk3R3QVKY5cjs.appliedDominantTarget.call(void 0, chord.rootPc + (dominant ? 5 : 1), key);
998
1019
  }
999
1020
  function isAppliedDominant(chord, key) {
1000
- if (_chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, key)) {
1021
+ if (_chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, key)) {
1001
1022
  return false;
1002
1023
  }
1003
1024
  const source = borrowedSourceOf(chord, key);
@@ -1010,7 +1031,7 @@ function pointsAtTonicizableDegree(chord, key) {
1010
1031
  if (appliedTarget(chord, key) !== null) {
1011
1032
  return true;
1012
1033
  }
1013
- return _chunkYPB3A3EYcjs.soundsDominantSeventh.call(void 0, chord) && isTonicizableRoot(_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc - 1), key);
1034
+ return _chunk3R3QVKY5cjs.soundsDominantSeventh.call(void 0, chord) && isTonicizableRoot(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - 1), key);
1014
1035
  }
1015
1036
 
1016
1037
  // src/analyze/functional/roman.ts
@@ -1125,33 +1146,33 @@ function parseInversion(figures) {
1125
1146
  function parseSimpleRoman(text, key) {
1126
1147
  const match = /^([b#]?)([iIvV]+)(.*)$/.exec(text.trim());
1127
1148
  if (!match) {
1128
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(`Invalid Roman numeral: ${text}`);
1149
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Invalid Roman numeral: ${text}`);
1129
1150
  }
1130
1151
  const glyphText = _nullishCoalesce(match[2], () => ( ""));
1131
1152
  if (glyphText !== glyphText.toUpperCase() && glyphText !== glyphText.toLowerCase()) {
1132
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(`Roman numeral must use one case: ${text}`);
1153
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Roman numeral must use one case: ${text}`);
1133
1154
  }
1134
1155
  const accidental = match[1] === "b" ? -1 : match[1] === "#" ? 1 : 0;
1135
1156
  const glyph = glyphText.toUpperCase();
1136
1157
  const degreeNumber = ROMAN_TO_DEGREE[glyph];
1137
1158
  if (degreeNumber === void 0) {
1138
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(`Invalid Roman numeral: ${text}`);
1159
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Invalid Roman numeral: ${text}`);
1139
1160
  }
1140
1161
  const isUpper = glyphText[0] === _optionalChain([glyphText, 'access', _5 => _5[0], 'optionalAccess', _6 => _6.toUpperCase, 'call', _7 => _7()]);
1141
1162
  const suffix = _nullishCoalesce(match[3], () => ( ""));
1142
1163
  const frame = romanReference(key);
1143
1164
  const redundantFlat = accidental === -1 && loweredDegrees(frame).has(degreeNumber);
1144
- const diatonicRootPc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0,
1165
+ const diatonicRootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0,
1145
1166
  degreeRootPc(degreeNumber, frame) + (redundantFlat ? 0 : accidental)
1146
1167
  );
1147
- const rootForQuality = (quality2) => accidental === 0 && degreeNumber === 7 && loweredDegrees(frame).has(7) && _chunkYPB3A3EYcjs.LEADING_TONE_QUALITIES.has(quality2) ? _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, diatonicRootPc + 1) : diatonicRootPc;
1168
+ const rootForQuality = (quality2) => accidental === 0 && degreeNumber === 7 && loweredDegrees(frame).has(7) && _chunk3R3QVKY5cjs.LEADING_TONE_QUALITIES.has(quality2) ? _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, diatonicRootPc + 1) : diatonicRootPc;
1148
1169
  const canonical = SUFFIX_QUALITY.get(`${isUpper ? "u" : "l"}:${suffix}`);
1149
1170
  if (canonical !== void 0) {
1150
1171
  return { rootPc: rootForQuality(canonical), quality: canonical, inversion: 0 };
1151
1172
  }
1152
1173
  const parsedSuffix = /^(o|°|dim|ø|\+|aug)?(maj7|M7)?(65|64|43|42|7|6|2)?$/.exec(suffix);
1153
1174
  if (!parsedSuffix) {
1154
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(`Unsupported suffix "${suffix}" in Roman numeral: ${text}`);
1175
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unsupported suffix "${suffix}" in Roman numeral: ${text}`);
1155
1176
  }
1156
1177
  const qualityMarker = _nullishCoalesce(parsedSuffix[1], () => ( ""));
1157
1178
  const isDim = qualityMarker === "o" || qualityMarker === "\xB0" || qualityMarker === "dim";
@@ -1160,7 +1181,7 @@ function parseSimpleRoman(text, key) {
1160
1181
  const explicitMaj7 = parsedSuffix[2] !== void 0;
1161
1182
  const figures = _nullishCoalesce(parsedSuffix[3], () => ( ""));
1162
1183
  if (figures !== "" && !INVERSION_FIGURES.has(figures)) {
1163
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(
1184
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
1164
1185
  `Unsupported figured-bass or extension "${figures}" in Roman numeral: ${text}`
1165
1186
  );
1166
1187
  }
@@ -1191,22 +1212,22 @@ function parseSimpleRoman(text, key) {
1191
1212
  var NEAPOLITAN_SIXTH = "N6";
1192
1213
  function chromaticSymbolChord(text, key) {
1193
1214
  if (text === NEAPOLITAN_SIXTH) {
1194
- const rootPc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.scale.rootPc + 1);
1195
- return _chunkYPB3A3EYcjs.makeChord.call(void 0, rootPc, "maj", _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc + 4));
1215
+ const rootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.scale.rootPc + 1);
1216
+ return _chunk3R3QVKY5cjs.makeChord.call(void 0, rootPc, "maj", _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc + 4));
1196
1217
  }
1197
1218
  return augmentedSixthFromSymbol(text, key);
1198
1219
  }
1199
1220
  function tonicizedKey(targetRoot, key) {
1200
- return _chunkYPB3A3EYcjs.resolveKey.call(void 0, {
1201
- scale: _chunkYPB3A3EYcjs.majorKey.call(void 0, targetRoot),
1202
- tonic: _chunkYPB3A3EYcjs.spellPitchClass.call(void 0, targetRoot, key.tonic, key.scale)
1221
+ return _chunk3R3QVKY5cjs.resolveKey.call(void 0, {
1222
+ scale: _chunk3R3QVKY5cjs.majorKey.call(void 0, targetRoot),
1223
+ tonic: _chunk3R3QVKY5cjs.spellPitchClass.call(void 0, targetRoot, key.tonic, key.scale)
1203
1224
  });
1204
1225
  }
1205
1226
  function augmentedSixthTarget(chord, key) {
1206
- if (_chunkYPB3A3EYcjs.chordToneSpellings.call(void 0, chord) === void 0) {
1227
+ if (_chunk3R3QVKY5cjs.chordToneSpellings.call(void 0, chord) === void 0) {
1207
1228
  return null;
1208
1229
  }
1209
- for (const degree of _chunkYPB3A3EYcjs.tonicizableDegrees.call(void 0, key.scale)) {
1230
+ for (const degree of _chunk3R3QVKY5cjs.tonicizableDegrees.call(void 0, key.scale)) {
1210
1231
  if (degree.degreeNumber === 1) {
1211
1232
  continue;
1212
1233
  }
@@ -1217,14 +1238,14 @@ function augmentedSixthTarget(chord, key) {
1217
1238
  return null;
1218
1239
  }
1219
1240
  function chordFromParsed(parsed) {
1220
- const chord = _chunkYPB3A3EYcjs.makeChord.call(void 0, parsed.rootPc, parsed.quality);
1241
+ const chord = _chunk3R3QVKY5cjs.makeChord.call(void 0, parsed.rootPc, parsed.quality);
1221
1242
  if (parsed.inversion > 0 && parsed.inversion < chord.intervals.length) {
1222
- chord.bassPc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, parsed.rootPc + (_nullishCoalesce(chord.intervals[parsed.inversion], () => ( 0))));
1243
+ chord.bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, parsed.rootPc + (_nullishCoalesce(chord.intervals[parsed.inversion], () => ( 0))));
1223
1244
  }
1224
1245
  return chord;
1225
1246
  }
1226
1247
  function romanToChord(text, key) {
1227
- const resolved = _chunkYPB3A3EYcjs.resolveKey.call(void 0, key);
1248
+ const resolved = _chunk3R3QVKY5cjs.resolveKey.call(void 0, key);
1228
1249
  const scale = resolved.scale;
1229
1250
  const trimmed = text.trim().replace(/(\d)\/(?=\d)/g, "$1");
1230
1251
  const slash = trimmed.indexOf("/");
@@ -1241,14 +1262,14 @@ function romanStyle(quality) {
1241
1262
  return ROMAN_STYLE[quality];
1242
1263
  }
1243
1264
  function romanSpelling(rootPc, key) {
1244
- const tones = _chunkYPB3A3EYcjs.scaleTonesInDegreeOrder.call(void 0, romanReference(key));
1245
- const diatonic = tones.indexOf(_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc));
1265
+ const tones = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, romanReference(key));
1266
+ const diatonic = tones.indexOf(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc));
1246
1267
  if (diatonic >= 0) {
1247
1268
  return { degreeNumber: diatonic + 1, accidental: "" };
1248
1269
  }
1249
1270
  const lowered = loweredDegrees(romanReference(key));
1250
1271
  for (let i = 0; i < tones.length; i += 1) {
1251
- if (lowered.has(i + 1) && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) + 1) === _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc)) {
1272
+ if (lowered.has(i + 1) && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) + 1) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc)) {
1252
1273
  return { degreeNumber: i + 1, accidental: "#" };
1253
1274
  }
1254
1275
  }
@@ -1257,20 +1278,20 @@ function romanSpelling(rootPc, key) {
1257
1278
  if (degreeNumber2 === 1 || degreeNumber2 === 5) {
1258
1279
  continue;
1259
1280
  }
1260
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) - 1) === _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc)) {
1281
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) - 1) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc)) {
1261
1282
  return { degreeNumber: degreeNumber2, accidental: "b" };
1262
1283
  }
1263
1284
  }
1264
1285
  for (let i = 0; i < tones.length; i += 1) {
1265
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) + 1) === _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc)) {
1286
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) + 1) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc)) {
1266
1287
  return { degreeNumber: i + 1, accidental: "#" };
1267
1288
  }
1268
1289
  }
1269
- const [degreeNumber, accidental] = _nullishCoalesce(OFFSET_SPELLING[_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, rootPc - key.rootPc)], () => ( [1, ""]));
1290
+ const [degreeNumber, accidental] = _nullishCoalesce(OFFSET_SPELLING[_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc - key.rootPc)], () => ( [1, ""]));
1270
1291
  return { degreeNumber, accidental };
1271
1292
  }
1272
1293
  function seventhDegreeAccidental(accidental, degreeNumber, quality, key) {
1273
- if (degreeNumber !== 7 || !_chunkYPB3A3EYcjs.LEADING_TONE_QUALITIES.has(quality) || !loweredDegrees(romanReference(key)).has(7)) {
1294
+ if (degreeNumber !== 7 || !_chunk3R3QVKY5cjs.LEADING_TONE_QUALITIES.has(quality) || !loweredDegrees(romanReference(key)).has(7)) {
1274
1295
  return accidental;
1275
1296
  }
1276
1297
  if (accidental === "#") {
@@ -1312,22 +1333,22 @@ var SEVENTH_FIGURE_QUALITIES = /* @__PURE__ */ new Set([
1312
1333
  function numeralFor(degreeNumber, lower) {
1313
1334
  const glyph = ROMAN[degreeNumber - 1];
1314
1335
  if (glyph === void 0) {
1315
- throw new (0, _chunkXKSO2V5Icjs.InvalidInputError)(`no Roman numeral for scale degree ${degreeNumber}`);
1336
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`no Roman numeral for scale degree ${degreeNumber}`);
1316
1337
  }
1317
1338
  return lower ? glyph.toLowerCase() : glyph;
1318
1339
  }
1319
1340
  function chordToRoman(chord, key, opts = {}) {
1320
- return renderRoman(_chunkYPB3A3EYcjs.toChordData.call(void 0, chord), key, _chunkXKSO2V5Icjs.assertOptions.call(void 0, opts, "opts")).roman;
1341
+ return renderRoman(_chunk3R3QVKY5cjs.toChordData.call(void 0, chord), key, _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts")).roman;
1321
1342
  }
1322
1343
  function renderRoman(chord, keyLike, opts) {
1323
- const resolved = _chunkYPB3A3EYcjs.resolveKey.call(void 0, keyLike);
1344
+ const resolved = _chunk3R3QVKY5cjs.resolveKey.call(void 0, keyLike);
1324
1345
  const key = resolved.scale;
1325
1346
  const augmented = augmentedSixthSymbol(chord, resolved);
1326
1347
  if (augmented !== null) {
1327
1348
  return { roman: augmented, derivation: { kind: "augmentedSixth" } };
1328
1349
  }
1329
1350
  if (opts.applied === true) {
1330
- const target = _nullishCoalesce(augmentedSixthTarget(chord, resolved), () => ( (_chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, key) ? null : appliedTarget(chord, key))));
1351
+ const target = _nullishCoalesce(augmentedSixthTarget(chord, resolved), () => ( (_chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, key) ? null : appliedTarget(chord, key))));
1331
1352
  if (target !== null) {
1332
1353
  const local = renderRoman(chord, tonicizedKey(target.rootPc, resolved), {}).roman;
1333
1354
  const numeral = numeralFor(target.degreeNumber, target.lower);
@@ -1344,14 +1365,14 @@ function renderRoman(chord, keyLike, opts) {
1344
1365
  let inversion = 0;
1345
1366
  let bass = "root";
1346
1367
  if (chord.bassPc !== void 0) {
1347
- const idx = chord.intervals.findIndex((iv) => _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc + iv) === chord.bassPc);
1368
+ const idx = chord.intervals.findIndex((iv) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + iv) === chord.bassPc);
1348
1369
  if (idx > 0) {
1349
1370
  inversion = idx;
1350
1371
  } else if (idx < 0) {
1351
1372
  bass = "foreign";
1352
1373
  }
1353
1374
  }
1354
- if (opts.neapolitan === true && inversion === 1 && _chunkYPB3A3EYcjs.isNeapolitanChordOf.call(void 0, chord, key)) {
1375
+ if (opts.neapolitan === true && inversion === 1 && _chunk3R3QVKY5cjs.isNeapolitanChordOf.call(void 0, chord, key)) {
1355
1376
  return { roman: NEAPOLITAN_SIXTH, derivation: { kind: "neapolitan" } };
1356
1377
  }
1357
1378
  if (inversion > 0) {
@@ -1450,8 +1471,8 @@ function romanAlternatives(chord, key, opts) {
1450
1471
  return out;
1451
1472
  }
1452
1473
  function explainRoman(chord, key, opts = {}) {
1453
- const asked = _chunkXKSO2V5Icjs.assertOptions.call(void 0, opts, "opts");
1454
- const data = _chunkYPB3A3EYcjs.toChordData.call(void 0, chord);
1474
+ const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
1475
+ const data = _chunk3R3QVKY5cjs.toChordData.call(void 0, chord);
1455
1476
  const { roman, derivation } = renderRoman(data, key, asked);
1456
1477
  return {
1457
1478
  roman,
@@ -1466,6 +1487,7 @@ function capitalize(text) {
1466
1487
  }
1467
1488
 
1468
1489
  // src/analyze/functional/function.ts
1490
+ var HARMONIC_FUNCTIONS = Object.freeze(["tonic", "subdominant", "dominant"]);
1469
1491
  var FUNCTION_BY_OFFSET = [
1470
1492
  "tonic",
1471
1493
  // 0 I
@@ -1519,18 +1541,18 @@ var MINOR_FUNCTION_BY_OFFSET = [
1519
1541
  // 11 viio
1520
1542
  ];
1521
1543
  function isMinorKey(key) {
1522
- return isMinorScale(_chunkYPB3A3EYcjs.toKeyScale.call(void 0, key));
1544
+ return isMinorScale(_chunk3R3QVKY5cjs.toKeyScale.call(void 0, key));
1523
1545
  }
1524
1546
  function functionOf(chord, key) {
1525
- return functionWithReason(_chunkYPB3A3EYcjs.toChordData.call(void 0, chord), _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key)).function;
1547
+ return functionWithReason(_chunk3R3QVKY5cjs.toChordData.call(void 0, chord), _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key)).function;
1526
1548
  }
1527
1549
  function degreeFunction(chord, key) {
1528
1550
  const functions = isMinorScale(key) ? MINOR_FUNCTION_BY_OFFSET : FUNCTION_BY_OFFSET;
1529
- return _nullishCoalesce(functions[_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc)], () => ( "tonic"));
1551
+ return _nullishCoalesce(functions[_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc)], () => ( "tonic"));
1530
1552
  }
1531
1553
  function functionWithReason(chord, key) {
1532
- const offset = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc);
1533
- if (_chunkYPB3A3EYcjs.isNeapolitanChordOf.call(void 0, chord, key)) {
1554
+ const offset = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc);
1555
+ if (_chunk3R3QVKY5cjs.isNeapolitanChordOf.call(void 0, chord, key)) {
1534
1556
  return { function: "subdominant", reason: "neapolitan" };
1535
1557
  }
1536
1558
  if (augmentedSixthKindOf(chord, key) !== null) {
@@ -1539,7 +1561,7 @@ function functionWithReason(chord, key) {
1539
1561
  if (isAppliedDominant(chord, key)) {
1540
1562
  return { function: "dominant", reason: "applied" };
1541
1563
  }
1542
- if (!isMinorScale(key) && !_chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, key) && _chunkYPB3A3EYcjs.hasMajorThird.call(void 0, chord) && (offset === 8 || offset === 10)) {
1564
+ if (!isMinorScale(key) && !_chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, key) && _chunk3R3QVKY5cjs.hasMajorThird.call(void 0, chord) && (offset === 8 || offset === 10)) {
1543
1565
  return { function: "subdominant", reason: "flatSideMajor" };
1544
1566
  }
1545
1567
  return { function: degreeFunction(chord, key), reason: "degree" };
@@ -1562,7 +1584,7 @@ function describeChord(fn, reason, roman, source) {
1562
1584
  function functionAlternatives(chord, key, reason, accepted) {
1563
1585
  const out = [];
1564
1586
  if (reason === "degree") {
1565
- if (pointsAtTonicizableDegree(chord, key) && _chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, key)) {
1587
+ if (pointsAtTonicizableDegree(chord, key) && _chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, key)) {
1566
1588
  out.push({
1567
1589
  label: "applied dominant",
1568
1590
  reason: "The chord is diatonic to the key, so it keeps the function of its degree rather than tonicizing another"
@@ -1586,15 +1608,15 @@ function functionAlternatives(chord, key, reason, accepted) {
1586
1608
  return out;
1587
1609
  }
1588
1610
  function isDiatonic(chord, key) {
1589
- return _chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, _chunkYPB3A3EYcjs.toChordData.call(void 0, chord), _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key));
1611
+ return _chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, _chunk3R3QVKY5cjs.toChordData.call(void 0, chord), _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key));
1590
1612
  }
1591
1613
  function parallelKey(key) {
1592
- return parallelScale(_chunkYPB3A3EYcjs.toKeyScale.call(void 0, key));
1614
+ return parallelScale(_chunk3R3QVKY5cjs.toKeyScale.call(void 0, key));
1593
1615
  }
1594
1616
  function analyzeChord(chord, key, opts = {}) {
1595
- const asked = _chunkXKSO2V5Icjs.assertOptions.call(void 0, opts, "opts");
1596
- const data = _chunkYPB3A3EYcjs.toChordData.call(void 0, chord);
1597
- const scale = _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key);
1617
+ const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
1618
+ const data = _chunk3R3QVKY5cjs.toChordData.call(void 0, chord);
1619
+ const scale = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key);
1598
1620
  const source = borrowedSourceOf(data, scale);
1599
1621
  const { function: fn, reason } = functionWithReason(data, scale);
1600
1622
  const roman = renderRoman(data, scale, asked).roman;
@@ -1611,18 +1633,18 @@ function analyzeChord(chord, key, opts = {}) {
1611
1633
  };
1612
1634
  }
1613
1635
  function secondaryDominant(targetDegree, key) {
1614
- const scale = _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key);
1615
- const degreeCount = _chunkYPB3A3EYcjs.scaleTonesInDegreeOrder.call(void 0, scale).length;
1616
- _chunkXKSO2V5Icjs.assertInteger.call(void 0, targetDegree, "targetDegree", 1, degreeCount);
1636
+ const scale = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key);
1637
+ const degreeCount = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, scale).length;
1638
+ _chunkS5BKZZGMcjs.assertInteger.call(void 0, targetDegree, "targetDegree", 1, degreeCount);
1617
1639
  const targetRoot = degreeRootPc(targetDegree, scale);
1618
- return _chunkYPB3A3EYcjs.makeChord.call(void 0, _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, targetRoot + 7), "dom7");
1640
+ return _chunk3R3QVKY5cjs.makeChord.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, targetRoot + 7), "dom7");
1619
1641
  }
1620
1642
  function secondaryDominantOf(target) {
1621
- const data = _chunkYPB3A3EYcjs.toChordData.call(void 0, target);
1622
- _chunkXKSO2V5Icjs.assertFiniteNumber.call(void 0, data.rootPc, "target chord rootPc");
1623
- const dominant = _chunkYPB3A3EYcjs.makeChord.call(void 0, _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, data.rootPc + 7), "dom7");
1643
+ const data = _chunk3R3QVKY5cjs.toChordData.call(void 0, target);
1644
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, data.rootPc, "target chord rootPc");
1645
+ const dominant = _chunk3R3QVKY5cjs.makeChord.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, data.rootPc + 7), "dom7");
1624
1646
  if (data.rootSpelling !== void 0) {
1625
- const moved = _chunkXKSO2V5Icjs.transposeNote.call(void 0, data.rootSpelling, 7);
1647
+ const moved = _chunkS5BKZZGMcjs.transposeNote.call(void 0, data.rootSpelling, 7);
1626
1648
  dominant.rootSpelling = { letter: moved.letter, alter: moved.alter };
1627
1649
  }
1628
1650
  return dominant;
@@ -1631,17 +1653,17 @@ function secondaryDominantOf(target) {
1631
1653
  // src/analyze/functional/pivot.ts
1632
1654
  var HEPTATONIC_DEGREES = 7;
1633
1655
  function pivotChords(from, to) {
1634
- return pivotsBetween(_chunkYPB3A3EYcjs.toKeyScale.call(void 0, from), _chunkYPB3A3EYcjs.toKeyScale.call(void 0, to));
1656
+ return pivotsBetween(_chunk3R3QVKY5cjs.toKeyScale.call(void 0, from), _chunk3R3QVKY5cjs.toKeyScale.call(void 0, to));
1635
1657
  }
1636
1658
  function pivotsBetween(from, to) {
1637
- if (_chunkYPB3A3EYcjs.scaleTonesInDegreeOrder.call(void 0, from).length !== HEPTATONIC_DEGREES) {
1659
+ if (_chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, from).length !== HEPTATONIC_DEGREES) {
1638
1660
  return [];
1639
1661
  }
1640
1662
  const pivots = [];
1641
1663
  const seen = /* @__PURE__ */ new Set();
1642
1664
  for (let degree = 1; degree <= HEPTATONIC_DEGREES; degree += 1) {
1643
1665
  const chord = stackedTriad(degree, from);
1644
- if (chord === null || !_chunkYPB3A3EYcjs.isDiatonicChord.call(void 0, chord, to)) {
1666
+ if (chord === null || !_chunk3R3QVKY5cjs.isDiatonicChord.call(void 0, chord, to)) {
1645
1667
  continue;
1646
1668
  }
1647
1669
  const identity = `${chord.rootPc}:${chord.quality}`;
@@ -1659,9 +1681,9 @@ function pivotsBetween(from, to) {
1659
1681
  }
1660
1682
  function stackedTriad(degree, key) {
1661
1683
  try {
1662
- return _chunkYPB3A3EYcjs.diatonicTriad.call(void 0, degree, key);
1684
+ return _chunk3R3QVKY5cjs.diatonicTriad.call(void 0, degree, key);
1663
1685
  } catch (error) {
1664
- if (error instanceof _chunkXKSO2V5Icjs.InvalidInputError) {
1686
+ if (error instanceof _chunkS5BKZZGMcjs.InvalidInputError) {
1665
1687
  return null;
1666
1688
  }
1667
1689
  throw error;
@@ -1669,6 +1691,16 @@ function stackedTriad(degree, key) {
1669
1691
  }
1670
1692
 
1671
1693
  // src/analyze/form/internal.ts
1694
+ function barSpanOf(startBeat, endBeat, meter) {
1695
+ const firstBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, startBeat, meter);
1696
+ const lastBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, endBeat, meter);
1697
+ const partOf = (beat, bar) => {
1698
+ const barStart = _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar, beat: 0 }, meter);
1699
+ const barLength = _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, barStart, meter);
1700
+ return barLength > 0 ? (beat - barStart) / barLength : 0;
1701
+ };
1702
+ return lastBar - firstBar + partOf(endBeat, lastBar) - partOf(startBeat, firstBar);
1703
+ }
1672
1704
  function clamp01(value) {
1673
1705
  return Math.min(1, Math.max(0, value));
1674
1706
  }
@@ -1683,34 +1715,34 @@ function firstSoundingBeat(notes, fallback = 0) {
1683
1715
  return Number.isFinite(first) ? first : fallback;
1684
1716
  }
1685
1717
  function lastBarOf(meter, spanStart, spanEnd) {
1686
- const firstBar = _chunkXKSO2V5Icjs.barIndexAt.call(void 0, spanStart, meter);
1687
- const bar = _chunkXKSO2V5Icjs.barIndexAt.call(void 0, Math.max(spanStart, spanEnd), meter);
1688
- if (bar > firstBar && _chunkXKSO2V5Icjs.barPositionToBeat.call(void 0, { bar, beat: 0 }, meter) >= spanEnd - _chunkXKSO2V5Icjs.BEAT_EPS) {
1718
+ const firstBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, spanStart, meter);
1719
+ const bar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, Math.max(spanStart, spanEnd), meter);
1720
+ if (bar > firstBar && _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar, beat: 0 }, meter) >= spanEnd - _chunkS5BKZZGMcjs.BEAT_EPS) {
1689
1721
  return bar - 1;
1690
1722
  }
1691
1723
  return bar;
1692
1724
  }
1693
1725
  function sliceBars(notes, meter, spanStart, spanEnd, budget) {
1694
- const firstBar = _chunkXKSO2V5Icjs.barIndexAt.call(void 0, spanStart, meter);
1726
+ const firstBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, spanStart, meter);
1695
1727
  const lastBar = lastBarOf(meter, spanStart, spanEnd);
1696
1728
  const barCount = lastBar - firstBar + 1;
1697
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0, barCount, "form bars", budget);
1729
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, barCount, "form bars", budget);
1698
1730
  const buckets = Array.from({ length: barCount }, () => []);
1699
1731
  let memberships = 0;
1700
1732
  for (const note of notes) {
1701
1733
  const noteEnd = note.startBeat + note.durationBeat;
1702
- const from = Math.max(firstBar, _chunkXKSO2V5Icjs.barIndexAt.call(void 0, note.startBeat, meter));
1703
- const to = Math.min(lastBar, _chunkXKSO2V5Icjs.barIndexAt.call(void 0, Math.max(note.startBeat, noteEnd - _chunkXKSO2V5Icjs.BEAT_EPS), meter));
1734
+ const from = Math.max(firstBar, _chunkS5BKZZGMcjs.barIndexAt.call(void 0, note.startBeat, meter));
1735
+ const to = Math.min(lastBar, _chunkS5BKZZGMcjs.barIndexAt.call(void 0, Math.max(note.startBeat, noteEnd - _chunkS5BKZZGMcjs.BEAT_EPS), meter));
1704
1736
  memberships += Math.max(0, to - from + 1);
1705
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0, memberships, "form note-to-bar memberships", budget);
1737
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, memberships, "form note-to-bar memberships", budget);
1706
1738
  for (let bar = from; bar <= to; bar += 1) {
1707
1739
  _optionalChain([buckets, 'access', _8 => _8[bar - firstBar], 'optionalAccess', _9 => _9.push, 'call', _10 => _10(note)]);
1708
1740
  }
1709
1741
  }
1710
1742
  const slices = [];
1711
1743
  for (let bar = firstBar; bar <= lastBar; bar += 1) {
1712
- const startBeat = _chunkXKSO2V5Icjs.barPositionToBeat.call(void 0, { bar, beat: 0 }, meter);
1713
- const endBeat = _chunkXKSO2V5Icjs.barPositionToBeat.call(void 0, { bar: bar + 1, beat: 0 }, meter);
1744
+ const startBeat = _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar, beat: 0 }, meter);
1745
+ const endBeat = _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar: bar + 1, beat: 0 }, meter);
1714
1746
  const barNotes = _nullishCoalesce(buckets[bar - firstBar], () => ( []));
1715
1747
  const { weights, totalWeight } = windowWeights(barNotes, startBeat, endBeat, meter);
1716
1748
  slices.push({ index: bar, startBeat, endBeat, notes: barNotes, weights, totalWeight });
@@ -1728,10 +1760,10 @@ function weightSimilarity(a, b) {
1728
1760
  normA += x * x;
1729
1761
  normB += y * y;
1730
1762
  }
1731
- if (normA <= _chunkXKSO2V5Icjs.BEAT_EPS && normB <= _chunkXKSO2V5Icjs.BEAT_EPS) {
1763
+ if (normA <= _chunkS5BKZZGMcjs.BEAT_EPS && normB <= _chunkS5BKZZGMcjs.BEAT_EPS) {
1732
1764
  return 1;
1733
1765
  }
1734
- if (normA <= _chunkXKSO2V5Icjs.BEAT_EPS || normB <= _chunkXKSO2V5Icjs.BEAT_EPS) {
1766
+ if (normA <= _chunkS5BKZZGMcjs.BEAT_EPS || normB <= _chunkS5BKZZGMcjs.BEAT_EPS) {
1735
1767
  return 0;
1736
1768
  }
1737
1769
  return clamp01(dot / Math.sqrt(normA * normB));
@@ -1758,13 +1790,13 @@ function combineEvidence(strengths) {
1758
1790
  // src/analyze/grid.ts
1759
1791
  function gridOriginOf(firstOnset, slotBeats) {
1760
1792
  const startBeat = firstOnset < 0 && firstOnset > -HUMANIZE_ADJACENCY ? 0 : firstOnset;
1761
- return { origin: Math.floor(startBeat / slotBeats + _chunkXKSO2V5Icjs.BEAT_EPS) * slotBeats, startBeat };
1793
+ return { origin: Math.floor(startBeat / slotBeats + _chunkS5BKZZGMcjs.BEAT_EPS) * slotBeats, startBeat };
1762
1794
  }
1763
1795
  function gridForNotes(notes, slotBeats) {
1764
1796
  return gridOriginOf(firstSoundingBeat(notes), slotBeats);
1765
1797
  }
1766
1798
  function barGridStart(firstOnset, meter) {
1767
- return gridOriginOf(firstOnset, _chunkXKSO2V5Icjs.beatsPerBarAt.call(void 0, firstOnset, meter)).startBeat;
1799
+ return gridOriginOf(firstOnset, _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, firstOnset, meter)).startBeat;
1768
1800
  }
1769
1801
 
1770
1802
  // src/analyze/keys/index.ts
@@ -1784,13 +1816,13 @@ var FIFTHS_DISTANCE_COST = 0.18;
1784
1816
  var KEY_CANDIDATES = (() => {
1785
1817
  const candidates = [];
1786
1818
  for (let rootPc = 0; rootPc < 12; rootPc += 1) {
1787
- candidates.push({ key: _chunkYPB3A3EYcjs.majorKey.call(void 0, rootPc), rootPc, minor: false });
1788
- candidates.push({ key: _chunkYPB3A3EYcjs.minorKey.call(void 0, rootPc), rootPc, minor: true });
1819
+ candidates.push({ key: _chunk3R3QVKY5cjs.majorKey.call(void 0, rootPc), rootPc, minor: false });
1820
+ candidates.push({ key: _chunk3R3QVKY5cjs.minorKey.call(void 0, rootPc), rootPc, minor: true });
1789
1821
  }
1790
1822
  return candidates;
1791
1823
  })();
1792
1824
  function fifthsOf(rootPc, minor) {
1793
- const majorRoot = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, minor ? rootPc + 3 : rootPc);
1825
+ const majorRoot = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, minor ? rootPc + 3 : rootPc);
1794
1826
  const raw = majorRoot * 7 % 12;
1795
1827
  return raw > 6 ? raw - 12 : raw;
1796
1828
  }
@@ -1808,9 +1840,9 @@ function chooseKeys(slots, changeCost, meter, budget) {
1808
1840
  if (slots.length === 0) {
1809
1841
  return [];
1810
1842
  }
1811
- const back = _chunkXKSO2V5Icjs.allocateChoiceTable.call(void 0, slots.length, count, "key search choices", budget);
1812
- let costs = _chunkXKSO2V5Icjs.allocateCandidateTable.call(void 0, 1, count, "key search costs", budget);
1813
- let spare = _chunkXKSO2V5Icjs.allocateCandidateTable.call(void 0, 1, count, "key search costs", budget);
1843
+ const back = _chunkS5BKZZGMcjs.allocateChoiceTable.call(void 0, slots.length, count, "key search choices", budget);
1844
+ let costs = _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0, 1, count, "key search costs", budget);
1845
+ let spare = _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0, 1, count, "key search costs", budget);
1814
1846
  const opening = _nullishCoalesce(_optionalChain([slots, 'access', _11 => _11[0], 'optionalAccess', _12 => _12.scores]), () => ( []));
1815
1847
  for (let c = 0; c < count; c += 1) {
1816
1848
  costs[c] = -(_nullishCoalesce(opening[c], () => ( 0)));
@@ -1819,7 +1851,7 @@ function chooseKeys(slots, changeCost, meter, budget) {
1819
1851
  const slot = slots[i];
1820
1852
  const previous = costs;
1821
1853
  const next = spare;
1822
- const accent = _chunkXKSO2V5Icjs.metricWeight.call(void 0, _nullishCoalesce(_optionalChain([slot, 'optionalAccess', _13 => _13.startBeat]), () => ( 0)), meter);
1854
+ const accent = _chunkS5BKZZGMcjs.metricWeight.call(void 0, _nullishCoalesce(_optionalChain([slot, 'optionalAccess', _13 => _13.startBeat]), () => ( 0)), meter);
1823
1855
  const metricFactor = 1 - STRONG_BEAT_DISCOUNT * accent / MAX_METRIC_WEIGHT;
1824
1856
  const rowBase = i * count;
1825
1857
  for (let to = 0; to < count; to += 1) {
@@ -1889,7 +1921,7 @@ function enforceMinimumRegion(slots, path, minBeats, budget) {
1889
1921
  return chosen;
1890
1922
  }
1891
1923
  const candidates = KEY_CANDIDATES.length;
1892
- const totals = _chunkXKSO2V5Icjs.allocateCandidateTable.call(void 0, slots.length, candidates, "key region scores", budget);
1924
+ const totals = _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0, slots.length, candidates, "key region scores", budget);
1893
1925
  for (let i = 0; i < slots.length; i += 1) {
1894
1926
  const scores = _nullishCoalesce(_optionalChain([slots, 'access', _18 => _18[i], 'optionalAccess', _19 => _19.scores]), () => ( []));
1895
1927
  const base = i * candidates;
@@ -1920,13 +1952,13 @@ function enforceMinimumRegion(slots, path, minBeats, budget) {
1920
1952
  return chosen;
1921
1953
  }
1922
1954
  const length = region.endBeat - region.startBeat;
1923
- if (region.merged || length >= minBeats - _chunkXKSO2V5Icjs.BEAT_EPS) {
1955
+ if (region.merged || length >= minBeats - _chunkS5BKZZGMcjs.BEAT_EPS) {
1924
1956
  continue;
1925
1957
  }
1926
1958
  const previous = region.previous;
1927
1959
  const next = region.next;
1928
- const before = previous !== void 0 && Math.abs(previous.endBeat - region.startBeat) < _chunkXKSO2V5Icjs.BEAT_EPS ? previous : void 0;
1929
- const after = next !== void 0 && Math.abs(next.startBeat - region.endBeat) < _chunkXKSO2V5Icjs.BEAT_EPS ? next : void 0;
1960
+ const before = previous !== void 0 && Math.abs(previous.endBeat - region.startBeat) < _chunkS5BKZZGMcjs.BEAT_EPS ? previous : void 0;
1961
+ const after = next !== void 0 && Math.abs(next.startBeat - region.endBeat) < _chunkS5BKZZGMcjs.BEAT_EPS ? next : void 0;
1930
1962
  if (before === void 0 && after === void 0) {
1931
1963
  continue;
1932
1964
  }
@@ -2036,7 +2068,7 @@ function withRelations(regions) {
2036
2068
  if (previous === void 0 || current === void 0) {
2037
2069
  continue;
2038
2070
  }
2039
- const relation = _chunkYPB3A3EYcjs.keyRelationBetween.call(void 0, previous.key, current.key);
2071
+ const relation = _chunk3R3QVKY5cjs.keyRelationBetween.call(void 0, previous.key, current.key);
2040
2072
  if (relation !== null && relation !== "same") {
2041
2073
  current.modulation = relation;
2042
2074
  }
@@ -2044,22 +2076,22 @@ function withRelations(regions) {
2044
2076
  return regions;
2045
2077
  }
2046
2078
  function keyTimelineFromNotes(notes, opts = {}) {
2047
- const meters = _chunkXKSO2V5Icjs.resolveMeters.call(void 0, opts, "key timeline meters");
2048
- const bar = _chunkXKSO2V5Icjs.beatsPerBarAt.call(void 0, 0, meters);
2079
+ const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "key timeline meters");
2080
+ const bar = _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, 0, meters);
2049
2081
  const expectedKeyBeats = _nullishCoalesce(opts.expectedKeyBeats, () => ( bar * 4));
2050
- _chunkXKSO2V5Icjs.assertRange.call(void 0, expectedKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "expectedKeyBeats");
2082
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, expectedKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "expectedKeyBeats");
2051
2083
  const minKeyBeats = _nullishCoalesce(opts.minKeyBeats, () => ( bar));
2052
- _chunkXKSO2V5Icjs.assertRange.call(void 0, minKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "minKeyBeats");
2084
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, minKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "minKeyBeats");
2053
2085
  const budget = opts.budget;
2054
- _chunkXKSO2V5Icjs.assertNoteEvents.call(void 0, notes, "key timeline notes", { allowNonPositiveDuration: true, budget });
2086
+ _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "key timeline notes", { allowNonPositiveDuration: true, budget });
2055
2087
  const sounding = notes.filter((note) => note.durationBeat > 0);
2056
2088
  const lastEnd = sounding.reduce((end, n) => Math.max(end, n.startBeat + n.durationBeat), 0);
2057
2089
  const totalBeats = _nullishCoalesce(opts.totalBeats, () => ( lastEnd));
2058
- _chunkXKSO2V5Icjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "key timeline totalBeats");
2090
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "key timeline totalBeats");
2059
2091
  const slotBeats = Math.min(minKeyBeats, expectedKeyBeats);
2060
2092
  const { origin, startBeat: musicStart } = gridForNotes(sounding, slotBeats);
2061
- const slotCount = Math.max(0, Math.ceil((totalBeats - origin) / slotBeats - _chunkXKSO2V5Icjs.BEAT_EPS));
2062
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0, slotCount * KEY_CANDIDATES.length, "key timeline slots", budget);
2093
+ const slotCount = Math.max(0, Math.ceil((totalBeats - origin) / slotBeats - _chunkS5BKZZGMcjs.BEAT_EPS));
2094
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, slotCount * KEY_CANDIDATES.length, "key timeline slots", budget);
2063
2095
  if (slotCount === 0 || sounding.length === 0) {
2064
2096
  return [];
2065
2097
  }
@@ -2097,7 +2129,7 @@ function keyTimelineFromNotes(notes, opts = {}) {
2097
2129
  (candidate) => profileScore(weights, candidate.minor ? profile.minor : profile.major, candidate.rootPc) * totalWeight
2098
2130
  );
2099
2131
  slots.push({ startBeat, endBeat, scores, weight: totalWeight });
2100
- if (totalWeight > _chunkXKSO2V5Icjs.BEAT_EPS) {
2132
+ if (totalWeight > _chunkS5BKZZGMcjs.BEAT_EPS) {
2101
2133
  weightSum += totalWeight;
2102
2134
  soundingSlots += 1;
2103
2135
  }
@@ -2111,14 +2143,14 @@ function keyTimelineFromNotes(notes, opts = {}) {
2111
2143
  const grouped = regionsFromPath(slots, path);
2112
2144
  const head = grouped[0];
2113
2145
  const next = grouped[1];
2114
- if (head !== void 0 && next !== void 0 && head.endBeat - Math.max(head.startBeat, musicStart) < slotBeats - _chunkXKSO2V5Icjs.BEAT_EPS) {
2146
+ if (head !== void 0 && next !== void 0 && head.endBeat - Math.max(head.startBeat, musicStart) < slotBeats - _chunkS5BKZZGMcjs.BEAT_EPS) {
2115
2147
  next.startBeat = head.startBeat;
2116
2148
  next.from = head.from;
2117
2149
  grouped.shift();
2118
2150
  }
2119
2151
  const regions = grouped.map((region) => {
2120
2152
  const candidate = KEY_CANDIDATES[region.candidate];
2121
- const key = _chunkYPB3A3EYcjs.resolveKey.call(void 0, _nullishCoalesce(_optionalChain([candidate, 'optionalAccess', _24 => _24.key]), () => ( _chunkYPB3A3EYcjs.majorKey.call(void 0, 0))));
2153
+ const key = _chunk3R3QVKY5cjs.resolveKey.call(void 0, _nullishCoalesce(_optionalChain([candidate, 'optionalAccess', _24 => _24.key]), () => ( _chunk3R3QVKY5cjs.majorKey.call(void 0, 0))));
2122
2154
  const startBeat = Math.max(region.startBeat, musicStart);
2123
2155
  const weights = new Array(PITCH_CLASSES).fill(0);
2124
2156
  for (let i = region.from; i < region.toExclusive; i += 1) {
@@ -2138,7 +2170,7 @@ function keyTimelineFromNotes(notes, opts = {}) {
2138
2170
  return {
2139
2171
  startBeat,
2140
2172
  endBeat: region.endBeat,
2141
- key: _chunkYPB3A3EYcjs.resolveKey.call(void 0, key),
2173
+ key: _chunk3R3QVKY5cjs.resolveKey.call(void 0, key),
2142
2174
  confidence: Math.max(0, correlation)
2143
2175
  };
2144
2176
  });
@@ -2150,20 +2182,20 @@ var TONIC_CREDIT = 0.4;
2150
2182
  var CADENCE_CREDIT = 0.6;
2151
2183
  var CHORD_MODULATION_COST = 0.6;
2152
2184
  function chordFitsKey(chord, candidate) {
2153
- const tones = _chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, chord);
2185
+ const tones = _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord);
2154
2186
  if (tones.length === 0) {
2155
2187
  return 0;
2156
2188
  }
2157
2189
  let inKey = 0;
2158
2190
  for (const pc of tones) {
2159
- if (_chunkYPB3A3EYcjs.isScaleTone.call(void 0, pc, candidate.key)) {
2191
+ if (_chunk3R3QVKY5cjs.isScaleTone.call(void 0, pc, candidate.key)) {
2160
2192
  inKey += 1;
2161
2193
  }
2162
2194
  }
2163
2195
  let score = CHORD_TONE_CREDIT * ((inKey - (tones.length - inKey)) / tones.length);
2164
- const rootDegree = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc - candidate.rootPc);
2196
+ const rootDegree = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - candidate.rootPc);
2165
2197
  if (rootDegree === 7) {
2166
- if (_chunkYPB3A3EYcjs.soundsDominantSeventh.call(void 0, chord)) {
2198
+ if (_chunk3R3QVKY5cjs.soundsDominantSeventh.call(void 0, chord)) {
2167
2199
  score += DOMINANT_CREDIT;
2168
2200
  } else if (chord.quality === "maj") {
2169
2201
  score += DOMINANT_CREDIT * 0.5;
@@ -2175,17 +2207,17 @@ function chordFitsKey(chord, candidate) {
2175
2207
  return score;
2176
2208
  }
2177
2209
  function detectModulations(chords, opts = {}) {
2178
- _chunkXKSO2V5Icjs.assertArray.call(void 0, chords, "modulation chord segments");
2210
+ _chunkS5BKZZGMcjs.assertArray.call(void 0, chords, "modulation chord segments");
2179
2211
  chords.forEach((segment, index) => {
2180
- _chunkXKSO2V5Icjs.assertRecord.call(void 0, segment, `modulation chord segments[${index}]`);
2212
+ _chunkS5BKZZGMcjs.assertRecord.call(void 0, segment, `modulation chord segments[${index}]`);
2181
2213
  });
2182
- const meters = _chunkXKSO2V5Icjs.resolveMeters.call(void 0, opts, "modulation meters");
2183
- const bar = _chunkXKSO2V5Icjs.beatsPerBarAt.call(void 0, 0, meters);
2214
+ const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "modulation meters");
2215
+ const bar = _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, 0, meters);
2184
2216
  const expectedKeyBeats = _nullishCoalesce(opts.expectedKeyBeats, () => ( bar * 4));
2185
- _chunkXKSO2V5Icjs.assertRange.call(void 0, expectedKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "expectedKeyBeats");
2217
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, expectedKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "expectedKeyBeats");
2186
2218
  const minKeyBeats = _nullishCoalesce(opts.minKeyBeats, () => ( bar));
2187
- _chunkXKSO2V5Icjs.assertRange.call(void 0, minKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "minKeyBeats");
2188
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0,
2219
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, minKeyBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "minKeyBeats");
2220
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0,
2189
2221
  chords.length * KEY_CANDIDATES.length,
2190
2222
  "modulation chord segments",
2191
2223
  opts.budget
@@ -2193,7 +2225,7 @@ function detectModulations(chords, opts = {}) {
2193
2225
  const sorted = [...chords].filter((segment) => segment.endBeat > segment.startBeat).sort((a, b) => a.startBeat - b.startBeat);
2194
2226
  const lastChordEnd = sorted.reduce((end, segment) => Math.max(end, segment.endBeat), 0);
2195
2227
  const totalBeats = _nullishCoalesce(opts.totalBeats, () => ( lastChordEnd));
2196
- _chunkXKSO2V5Icjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "modulation totalBeats");
2228
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "modulation totalBeats");
2197
2229
  const ordered = sorted.map((segment) => ({ ...segment, endBeat: Math.min(segment.endBeat, totalBeats) })).filter((segment) => segment.endBeat > segment.startBeat);
2198
2230
  if (ordered.length === 0) {
2199
2231
  return [];
@@ -2216,14 +2248,14 @@ function detectModulations(chords, opts = {}) {
2216
2248
  if (arriving === void 0 || approaching === void 0 || slot === void 0) {
2217
2249
  continue;
2218
2250
  }
2219
- const isDominantMotion = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, approaching.rootPc - arriving.rootPc) === 7 && _chunkYPB3A3EYcjs.soundsDominantSeventh.call(void 0, approaching);
2251
+ const isDominantMotion = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, approaching.rootPc - arriving.rootPc) === 7 && _chunk3R3QVKY5cjs.soundsDominantSeventh.call(void 0, approaching);
2220
2252
  if (!isDominantMotion) {
2221
2253
  continue;
2222
2254
  }
2223
2255
  const length = slot.endBeat - slot.startBeat;
2224
2256
  for (let c = 0; c < KEY_CANDIDATES.length; c += 1) {
2225
2257
  const candidate = KEY_CANDIDATES[c];
2226
- if (candidate !== void 0 && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, arriving.rootPc - candidate.rootPc) === 0) {
2258
+ if (candidate !== void 0 && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, arriving.rootPc - candidate.rootPc) === 0) {
2227
2259
  slot.scores[c] = (_nullishCoalesce(slot.scores[c], () => ( 0))) + CADENCE_CREDIT * length;
2228
2260
  }
2229
2261
  }
@@ -2237,7 +2269,7 @@ function detectModulations(chords, opts = {}) {
2237
2269
  const profile = resolveKeyProfile(opts.profile);
2238
2270
  const regions = grouped.map((region) => {
2239
2271
  const candidate = KEY_CANDIDATES[region.candidate];
2240
- const key = _chunkYPB3A3EYcjs.resolveKey.call(void 0, _nullishCoalesce(_optionalChain([candidate, 'optionalAccess', _31 => _31.key]), () => ( _chunkYPB3A3EYcjs.majorKey.call(void 0, 0))));
2272
+ const key = _chunk3R3QVKY5cjs.resolveKey.call(void 0, _nullishCoalesce(_optionalChain([candidate, 'optionalAccess', _31 => _31.key]), () => ( _chunk3R3QVKY5cjs.majorKey.call(void 0, 0))));
2241
2273
  const weights = new Array(PITCH_CLASSES).fill(0);
2242
2274
  for (let i = region.from; i < region.toExclusive; i += 1) {
2243
2275
  const segment = ordered[i];
@@ -2245,10 +2277,10 @@ function detectModulations(chords, opts = {}) {
2245
2277
  continue;
2246
2278
  }
2247
2279
  const overlap = segment.endBeat - segment.startBeat;
2248
- if (overlap <= _chunkXKSO2V5Icjs.BEAT_EPS) {
2280
+ if (overlap <= _chunkS5BKZZGMcjs.BEAT_EPS) {
2249
2281
  continue;
2250
2282
  }
2251
- for (const pc of _chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, segment.chord)) {
2283
+ for (const pc of _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, segment.chord)) {
2252
2284
  weights[pc] = (_nullishCoalesce(weights[pc], () => ( 0))) + overlap;
2253
2285
  }
2254
2286
  }
@@ -2273,7 +2305,7 @@ function detectModulations(chords, opts = {}) {
2273
2305
  var THIRD_SEMITONES = [3, 4];
2274
2306
  var FIFTH_SEMITONES = [6, 7, 8];
2275
2307
  function triadCore(chord) {
2276
- const root = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc);
2308
+ const root = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc);
2277
2309
  let third;
2278
2310
  let fifth;
2279
2311
  for (const interval of chord.intervals) {
@@ -2289,7 +2321,7 @@ function triadCore(chord) {
2289
2321
  if (third === void 0 || fifth === void 0) {
2290
2322
  return null;
2291
2323
  }
2292
- return [root, _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, root + third), _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, root + fifth)].sort((a, b) => a - b);
2324
+ return [root, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, root + third), _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, root + fifth)].sort((a, b) => a - b);
2293
2325
  }
2294
2326
  function lastChordFinishedBy(chords) {
2295
2327
  const byEnd = chords.map((_, index) => index).sort((a, b) => (_nullishCoalesce(_optionalChain([chords, 'access', _34 => _34[a], 'optionalAccess', _35 => _35.endBeat]), () => ( 0))) - (_nullishCoalesce(_optionalChain([chords, 'access', _36 => _36[b], 'optionalAccess', _37 => _37.endBeat]), () => ( 0))));
@@ -2327,7 +2359,7 @@ function attachPivots(regions, chords) {
2327
2359
  if (previous === void 0 || current === void 0) {
2328
2360
  continue;
2329
2361
  }
2330
- const last = finished(current.startBeat + _chunkXKSO2V5Icjs.BEAT_EPS);
2362
+ const last = finished(current.startBeat + _chunkS5BKZZGMcjs.BEAT_EPS);
2331
2363
  if (last === void 0) {
2332
2364
  continue;
2333
2365
  }
@@ -2335,9 +2367,9 @@ function attachPivots(regions, chords) {
2335
2367
  if (core === null) {
2336
2368
  continue;
2337
2369
  }
2338
- const root = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, last.chord.rootPc);
2370
+ const root = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, last.chord.rootPc);
2339
2371
  const pivot = pivotChords(previous.key, current.key).find(
2340
- (entry) => entry.chord.rootPc === root && sameTones(_chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, entry.chord), core)
2372
+ (entry) => entry.chord.rootPc === root && sameTones(_chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, entry.chord), core)
2341
2373
  );
2342
2374
  if (pivot !== void 0) {
2343
2375
  current.pivot = pivot;
@@ -2362,12 +2394,12 @@ function keyLookup(regions, fallback) {
2362
2394
  };
2363
2395
  }
2364
2396
  function prevailingKeyOf(regions) {
2365
- _chunkXKSO2V5Icjs.assertArray.call(void 0, regions, "key regions");
2397
+ _chunkS5BKZZGMcjs.assertArray.call(void 0, regions, "key regions");
2366
2398
  const totals = /* @__PURE__ */ new Map();
2367
2399
  for (const [index, given] of regions.entries()) {
2368
- const region = _chunkXKSO2V5Icjs.assertRecord.call(void 0, given, `key regions[${index}]`);
2369
- _chunkXKSO2V5Icjs.assertRecord.call(void 0, region.key, `key regions[${index}].key`);
2370
- const id = `${_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, region.key.scale.rootPc)}:${region.key.scale.modeMask12}`;
2400
+ const region = _chunkS5BKZZGMcjs.assertRecord.call(void 0, given, `key regions[${index}]`);
2401
+ _chunkS5BKZZGMcjs.assertRecord.call(void 0, region.key, `key regions[${index}].key`);
2402
+ const id = `${_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, region.key.scale.rootPc)}:${region.key.scale.modeMask12}`;
2371
2403
  const entry = totals.get(id);
2372
2404
  const length = Math.max(0, region.endBeat - region.startBeat);
2373
2405
  if (entry === void 0) {
@@ -2392,11 +2424,11 @@ function keyScaleAt(key) {
2392
2424
  if (typeof key === "function") {
2393
2425
  return key;
2394
2426
  }
2395
- const scale = _chunkYPB3A3EYcjs.toKeyScale.call(void 0, key);
2427
+ const scale = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key);
2396
2428
  return () => scale;
2397
2429
  }
2398
2430
  function toVoiceNotes(events) {
2399
- _chunkXKSO2V5Icjs.assertNoteEvents.call(void 0, events, "voice notes", { allowNonPositiveDuration: true });
2431
+ _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, events, "voice notes", { allowNonPositiveDuration: true });
2400
2432
  return events.map((event, index) => ({ ...event, id: index, originalIndex: index }));
2401
2433
  }
2402
2434
  function intervalAboveBass(pitch, others, chord) {
@@ -2408,7 +2440,7 @@ function intervalAboveBass(pitch, others, chord) {
2408
2440
  return ((pitch - bass) % 12 + 12) % 12;
2409
2441
  }
2410
2442
  const ref = _nullishCoalesce(chord.bassPc, () => ( chord.rootPc));
2411
- return ((_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, pitch) - _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, ref)) % 12 + 12) % 12;
2443
+ return ((_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch) - _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, ref)) % 12 + 12) % 12;
2412
2444
  }
2413
2445
  var TENSION_DEGREE_BY_INTERVAL = {
2414
2446
  1: 9,
@@ -2427,7 +2459,7 @@ function asSounded(chord) {
2427
2459
  if (chord.bassPc === void 0) {
2428
2460
  return chord;
2429
2461
  }
2430
- return { ...chord, intervals: [...chord.intervals, _chunkYPB3A3EYcjs.intervalAboveRoot.call(void 0, chord.bassPc, chord)] };
2462
+ return { ...chord, intervals: [...chord.intervals, _chunk3R3QVKY5cjs.intervalAboveRoot.call(void 0, chord.bassPc, chord)] };
2431
2463
  }
2432
2464
  function isStep(a, b) {
2433
2465
  const d = Math.abs(a - b);
@@ -2456,19 +2488,19 @@ var STEP_RESOLUTION = 2;
2456
2488
  var NEAREST_CHORD_TONE_REACH = 12;
2457
2489
  function nearestChordTone(pitch, chord, maxDistance) {
2458
2490
  for (let delta = 1; delta <= maxDistance; delta += 1) {
2459
- if (_chunkYPB3A3EYcjs.isChordMember.call(void 0, pitch - delta, chord)) {
2491
+ if (_chunk3R3QVKY5cjs.isChordMember.call(void 0, pitch - delta, chord)) {
2460
2492
  return pitch - delta;
2461
2493
  }
2462
- if (_chunkYPB3A3EYcjs.isChordMember.call(void 0, pitch + delta, chord)) {
2494
+ if (_chunk3R3QVKY5cjs.isChordMember.call(void 0, pitch + delta, chord)) {
2463
2495
  return pitch + delta;
2464
2496
  }
2465
2497
  }
2466
2498
  return void 0;
2467
2499
  }
2468
2500
  function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2469
- _chunkXKSO2V5Icjs.assertNoteEvents.call(void 0, voice, "voice notes", { allowNonPositiveDuration: true });
2470
- _chunkXKSO2V5Icjs.assertFunction.call(void 0, chordAtBeat2, "chordAtBeat");
2471
- _chunkXKSO2V5Icjs.assertFunction.call(void 0, otherVoicesAtBeat, "otherVoicesAtBeat");
2501
+ _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, voice, "voice notes", { allowNonPositiveDuration: true });
2502
+ _chunkS5BKZZGMcjs.assertFunction.call(void 0, chordAtBeat2, "chordAtBeat");
2503
+ _chunkS5BKZZGMcjs.assertFunction.call(void 0, otherVoicesAtBeat, "otherVoicesAtBeat");
2472
2504
  const keyAt = keyScaleAt(key);
2473
2505
  const result = [];
2474
2506
  for (let i = 0; i < voice.length; i += 1) {
@@ -2484,11 +2516,11 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2484
2516
  const next = nextNote !== void 0 && adjacent(noteEnd, nextNote.startBeat) ? nextNote : void 0;
2485
2517
  const chord = chordAtBeat2(note.startBeat);
2486
2518
  const labels = [];
2487
- const member = _chunkYPB3A3EYcjs.isChordMember.call(void 0, note.pitch, chord);
2519
+ const member = _chunk3R3QVKY5cjs.isChordMember.call(void 0, note.pitch, chord);
2488
2520
  let handled = false;
2489
2521
  if (chord && member) {
2490
- const role = _chunkYPB3A3EYcjs.chordToneRole.call(void 0, note.pitch, chord);
2491
- const degree = role === null ? tensionDegree(_chunkYPB3A3EYcjs.intervalAboveRoot.call(void 0, note.pitch, chord)) : void 0;
2522
+ const role = _chunk3R3QVKY5cjs.chordToneRole.call(void 0, note.pitch, chord);
2523
+ const degree = role === null ? tensionDegree(_chunk3R3QVKY5cjs.intervalAboveRoot.call(void 0, note.pitch, chord)) : void 0;
2492
2524
  if (role) {
2493
2525
  labels.push({ kind: "chordTone", role });
2494
2526
  handled = true;
@@ -2496,7 +2528,7 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2496
2528
  labels.push({ kind: "tension", degree });
2497
2529
  handled = true;
2498
2530
  } else {
2499
- const bassRole = _chunkYPB3A3EYcjs.chordToneRole.call(void 0, note.pitch, asSounded(chord));
2531
+ const bassRole = _chunk3R3QVKY5cjs.chordToneRole.call(void 0, note.pitch, asSounded(chord));
2500
2532
  if (bassRole !== null) {
2501
2533
  labels.push({ kind: "chordTone", role: bassRole });
2502
2534
  handled = true;
@@ -2505,11 +2537,11 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2505
2537
  }
2506
2538
  if (!handled && chord && prev && next) {
2507
2539
  const prevChord = chordAtBeat2(prev.startBeat);
2508
- const prepared = prev.pitch === note.pitch && _chunkYPB3A3EYcjs.isChordMember.call(void 0, prev.pitch, prevChord);
2540
+ const prepared = prev.pitch === note.pitch && _chunk3R3QVKY5cjs.isChordMember.call(void 0, prev.pitch, prevChord);
2509
2541
  const resolves = isStep(next.pitch, note.pitch);
2510
2542
  const others = otherVoicesAtBeat(note.startBeat);
2511
2543
  const verticallyDissonant = others.some(
2512
- (ov) => _chunkYPB3A3EYcjs.createsVerticalDissonance.call(void 0, note.pitch, ov.pitch, true)
2544
+ (ov) => _chunk3R3QVKY5cjs.createsVerticalDissonance.call(void 0, note.pitch, ov.pitch, true)
2513
2545
  );
2514
2546
  if (prepared && verticallyDissonant && resolves) {
2515
2547
  const ic = intervalAboveBass(note.pitch, others, chord);
@@ -2521,8 +2553,8 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2521
2553
  }
2522
2554
  }
2523
2555
  if (!handled && chord && prev && next) {
2524
- const prevMember = _chunkYPB3A3EYcjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat));
2525
- const nextMember = _chunkYPB3A3EYcjs.isChordMember.call(void 0, next.pitch, chordAtBeat2(next.startBeat));
2556
+ const prevMember = _chunk3R3QVKY5cjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat));
2557
+ const nextMember = _chunk3R3QVKY5cjs.isChordMember.call(void 0, next.pitch, chordAtBeat2(next.startBeat));
2526
2558
  const up = note.pitch - prev.pitch > 0;
2527
2559
  const contInto = next.pitch - note.pitch > 0;
2528
2560
  const sameDir = note.pitch !== prev.pitch && next.pitch !== note.pitch && up === contInto;
@@ -2531,20 +2563,20 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2531
2563
  handled = true;
2532
2564
  }
2533
2565
  }
2534
- if (!handled && chord && prev && next && !member && prev.pitch === next.pitch && _chunkYPB3A3EYcjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat)) && isStep(note.pitch, prev.pitch)) {
2566
+ if (!handled && chord && prev && next && !member && prev.pitch === next.pitch && _chunk3R3QVKY5cjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat)) && isStep(note.pitch, prev.pitch)) {
2535
2567
  labels.push({ kind: "neighbor" });
2536
2568
  handled = true;
2537
2569
  }
2538
2570
  if (!handled && chord && next && !member && note.pitch === next.pitch) {
2539
2571
  const nextChord = chordAtBeat2(next.startBeat);
2540
- if (_chunkYPB3A3EYcjs.isChordMember.call(void 0, next.pitch, nextChord)) {
2572
+ if (_chunk3R3QVKY5cjs.isChordMember.call(void 0, next.pitch, nextChord)) {
2541
2573
  labels.push({ kind: "anticipation" });
2542
2574
  handled = true;
2543
2575
  }
2544
2576
  }
2545
2577
  if (!handled && chord && prev && next && !member) {
2546
- const prevMember = _chunkYPB3A3EYcjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat));
2547
- const nextMember = _chunkYPB3A3EYcjs.isChordMember.call(void 0, next.pitch, chordAtBeat2(next.startBeat));
2578
+ const prevMember = _chunk3R3QVKY5cjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat));
2579
+ const nextMember = _chunk3R3QVKY5cjs.isChordMember.call(void 0, next.pitch, chordAtBeat2(next.startBeat));
2548
2580
  const leapFromPrev = Math.abs(note.pitch - prev.pitch) >= LEAP_SEMITONES;
2549
2581
  const stepToNext = isStep(next.pitch, note.pitch);
2550
2582
  const opposite = note.pitch - prev.pitch > 0 !== next.pitch - note.pitch > 0;
@@ -2554,8 +2586,8 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2554
2586
  }
2555
2587
  }
2556
2588
  if (!handled && chord && prev && next && !member) {
2557
- const prevMember = _chunkYPB3A3EYcjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat));
2558
- const nextMember = _chunkYPB3A3EYcjs.isChordMember.call(void 0, next.pitch, chordAtBeat2(next.startBeat));
2589
+ const prevMember = _chunk3R3QVKY5cjs.isChordMember.call(void 0, prev.pitch, chordAtBeat2(prev.startBeat));
2590
+ const nextMember = _chunk3R3QVKY5cjs.isChordMember.call(void 0, next.pitch, chordAtBeat2(next.startBeat));
2559
2591
  const stepFromPrev = isStep(note.pitch, prev.pitch);
2560
2592
  const leapToNext = Math.abs(next.pitch - note.pitch) >= LEAP_SEMITONES;
2561
2593
  const opposite = note.pitch - prev.pitch > 0 !== next.pitch - note.pitch > 0;
@@ -2565,7 +2597,7 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2565
2597
  }
2566
2598
  }
2567
2599
  if (!handled && chord && !member) {
2568
- const ic = _chunkYPB3A3EYcjs.intervalAboveRoot.call(void 0, note.pitch, chord);
2600
+ const ic = _chunk3R3QVKY5cjs.intervalAboveRoot.call(void 0, note.pitch, chord);
2569
2601
  const degree = tensionDegree(ic);
2570
2602
  const colours = NATURAL_TENSION_INTERVALS.has(ic) || chord.intervals.some((i2) => i2 === 10 || i2 === 11);
2571
2603
  const avoid = ic === 5 && chord.intervals.includes(4) && !chord.intervals.includes(5) || ic === 11 && chord.intervals.includes(4) && chord.intervals.includes(10);
@@ -2584,7 +2616,7 @@ function analyzeVoice(voice, chordAtBeat2, key, otherVoicesAtBeat = () => []) {
2584
2616
  );
2585
2617
  }
2586
2618
  }
2587
- if (next && _chunkYPB3A3EYcjs.isLeadingToneResolution.call(void 0, note.pitch, next.pitch, keyAt(next.startBeat))) {
2619
+ if (next && _chunk3R3QVKY5cjs.isLeadingToneResolution.call(void 0, note.pitch, next.pitch, keyAt(next.startBeat))) {
2588
2620
  labels.push({ kind: "leadingTone", resolveTo: next.pitch });
2589
2621
  }
2590
2622
  const analyzed = {
@@ -2635,22 +2667,22 @@ function describe(labels) {
2635
2667
 
2636
2668
  // src/analyze/timeline/index.ts
2637
2669
  function assertChordTimeline(timeline, name = "timeline") {
2638
- const read = _chunkXKSO2V5Icjs.assertRecord.call(void 0, timeline, name);
2639
- _chunkXKSO2V5Icjs.assertFunction.call(void 0, read.at, `${name}.at`);
2640
- const segments = _chunkXKSO2V5Icjs.assertArray.call(void 0, read.segments, `${name}.segments`);
2670
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, timeline, name);
2671
+ _chunkS5BKZZGMcjs.assertFunction.call(void 0, read.at, `${name}.at`);
2672
+ const segments = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.segments, `${name}.segments`);
2641
2673
  for (let index = 0; index < segments.length; index += 1) {
2642
- const segment = _chunkXKSO2V5Icjs.assertRecord.call(void 0, segments[index], `${name}.segments[${index}]`);
2643
- _chunkXKSO2V5Icjs.assertFiniteNumber.call(void 0, segment.startBeat, `${name}.segments[${index}].startBeat`);
2644
- _chunkXKSO2V5Icjs.assertFiniteNumber.call(void 0, segment.endBeat, `${name}.segments[${index}].endBeat`);
2674
+ const segment = _chunkS5BKZZGMcjs.assertRecord.call(void 0, segments[index], `${name}.segments[${index}]`);
2675
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, segment.startBeat, `${name}.segments[${index}].startBeat`);
2676
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, segment.endBeat, `${name}.segments[${index}].endBeat`);
2645
2677
  }
2646
2678
  return read;
2647
2679
  }
2648
2680
  function chordTimelineFromChords(chords, totalBeats) {
2649
- _chunkXKSO2V5Icjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "timeline totalBeats");
2650
- _chunkXKSO2V5Icjs.assertArray.call(void 0, chords, "chords");
2651
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0, chords.length, "timeline chords");
2681
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "timeline totalBeats");
2682
+ _chunkS5BKZZGMcjs.assertArray.call(void 0, chords, "chords");
2683
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, chords.length, "timeline chords");
2652
2684
  for (let index = 0; index < chords.length; index += 1) {
2653
- _chunkXKSO2V5Icjs.assertRange.call(void 0,
2685
+ _chunkS5BKZZGMcjs.assertRange.call(void 0,
2654
2686
  _nullishCoalesce(_optionalChain([chords, 'access', _42 => _42[index], 'optionalAccess', _43 => _43.startBeat]), () => ( Number.NaN)),
2655
2687
  -Number.MAX_SAFE_INTEGER,
2656
2688
  Number.MAX_SAFE_INTEGER,
@@ -2665,13 +2697,13 @@ function chordTimelineFromChords(chords, totalBeats) {
2665
2697
  return {
2666
2698
  startBeat: gc.startBeat,
2667
2699
  endBeat,
2668
- chord: _chunkYPB3A3EYcjs.chordFromSpan.call(void 0, gc)
2700
+ chord: _chunk3R3QVKY5cjs.chordFromSpan.call(void 0, gc)
2669
2701
  };
2670
2702
  }).filter((seg) => seg.endBeat > seg.startBeat);
2671
2703
  return { at: segmentLookup(segments), segments };
2672
2704
  }
2673
2705
  function chordAtBeat(segments, beat) {
2674
- _chunkXKSO2V5Icjs.assertFiniteNumber.call(void 0, beat, "timeline query beat");
2706
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, beat, "timeline query beat");
2675
2707
  const candidate = segments[firstAfter(segments, beat) - 1];
2676
2708
  return candidate !== void 0 && beat >= candidate.startBeat && beat < candidate.endBeat ? candidate.chord : null;
2677
2709
  }
@@ -2691,7 +2723,7 @@ function firstAfter(segments, beat) {
2691
2723
  function segmentStartingAt(segments, beat) {
2692
2724
  const index = firstAfter(segments, beat);
2693
2725
  for (const candidate of [segments[index - 1], segments[index]]) {
2694
- if (candidate !== void 0 && Math.abs(candidate.startBeat - beat) < _chunkXKSO2V5Icjs.BEAT_EPS) {
2726
+ if (candidate !== void 0 && Math.abs(candidate.startBeat - beat) < _chunkS5BKZZGMcjs.BEAT_EPS) {
2695
2727
  return candidate;
2696
2728
  }
2697
2729
  }
@@ -2712,10 +2744,10 @@ var OCTAVE = 12;
2712
2744
  function scoreMatch(match, weights, maxWeight, key, pedalPc) {
2713
2745
  const rootWeight = maxWeight > 0 ? (_nullishCoalesce(weights[match.rootPc], () => ( 0))) / maxWeight : 0;
2714
2746
  const rootStanding = match.inversion === 0 ? Math.max(rootWeight, BASS_ROOT_STANDING) : rootWeight;
2715
- const chord = _chunkYPB3A3EYcjs.makeChord.call(void 0, match.rootPc, match.quality);
2747
+ const chord = _chunk3R3QVKY5cjs.makeChord.call(void 0, match.rootPc, match.quality);
2716
2748
  const account = matchAccount(match, chord, pedalPc);
2717
2749
  let score = rootStanding;
2718
- if (_chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, chord).every((pc) => _chunkYPB3A3EYcjs.isScaleTone.call(void 0, pc, key))) {
2750
+ if (_chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord).every((pc) => _chunk3R3QVKY5cjs.isScaleTone.call(void 0, pc, key))) {
2719
2751
  score += DIATONIC_BONUS;
2720
2752
  }
2721
2753
  if (account.exact) {
@@ -2730,7 +2762,7 @@ function isSlashReading(match, pedalPc) {
2730
2762
  return pedalPc !== null && match.inversion === null && match.missingPcs.length === 0 && match.extraPcs.length === 1 && match.extraPcs[0] === pedalPc && SLASH_UPPER_QUALITIES.has(match.quality);
2731
2763
  }
2732
2764
  function namesAsExtension(chord, pc) {
2733
- return chord.intervals.some((iv) => iv >= OCTAVE && _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc + iv) === pc);
2765
+ return chord.intervals.some((iv) => iv >= OCTAVE && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + iv) === pc);
2734
2766
  }
2735
2767
  function matchAccount(match, chord, pedalPc) {
2736
2768
  const unvoiced = pedalPc !== null && namesAsExtension(chord, pedalPc) ? 1 : 0;
@@ -2746,10 +2778,10 @@ function bassSoundsOnlyBelow(notes, windowStart, windowEnd, bassPc) {
2746
2778
  let highestBass = Number.NEGATIVE_INFINITY;
2747
2779
  for (const note of notes) {
2748
2780
  const overlap = Math.min(note.startBeat + note.durationBeat, windowEnd) - Math.max(note.startBeat, windowStart);
2749
- if (overlap <= _chunkXKSO2V5Icjs.BEAT_EPS) {
2781
+ if (overlap <= _chunkS5BKZZGMcjs.BEAT_EPS) {
2750
2782
  continue;
2751
2783
  }
2752
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, note.pitch) === bassPc) {
2784
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, note.pitch) === bassPc) {
2753
2785
  highestBass = Math.max(highestBass, note.pitch);
2754
2786
  } else {
2755
2787
  upperFloor = Math.min(upperFloor, note.pitch);
@@ -2758,7 +2790,7 @@ function bassSoundsOnlyBelow(notes, windowStart, windowEnd, bassPc) {
2758
2790
  return highestBass <= upperFloor;
2759
2791
  }
2760
2792
  function chordConfidence(chord, weights, totalWeight, exact) {
2761
- const tones = new Set(_chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, chord));
2793
+ const tones = new Set(_chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord));
2762
2794
  let chordWeight = 0;
2763
2795
  for (let pc = 0; pc < 12; pc += 1) {
2764
2796
  if (tones.has(pc)) {
@@ -2776,12 +2808,12 @@ function analyzeWindow(notes, windowStart, windowEnd, meters, key) {
2776
2808
  windowEnd,
2777
2809
  meters
2778
2810
  );
2779
- if (totalWeight <= _chunkXKSO2V5Icjs.BEAT_EPS) {
2811
+ if (totalWeight <= _chunkS5BKZZGMcjs.BEAT_EPS) {
2780
2812
  return null;
2781
2813
  }
2782
2814
  const ranked = weights.map((weight, pc) => ({ pc, weight })).filter(({ weight }) => weight > 0).sort((a, b) => b.weight - a.weight || a.pc - b.pc);
2783
2815
  const selected = ranked.filter(({ weight }) => weight >= maxWeight * NOISE_THRESHOLD_RATIO).slice(0, MAX_DETECTION_PCS).map(({ pc }) => pc);
2784
- const bassPc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, lowestPitch);
2816
+ const bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, lowestPitch);
2785
2817
  const hasBass = selected.includes(bassPc);
2786
2818
  const detectionPitches = hasBass ? selected.map((pc) => pc === bassPc ? pc : pc + 12) : selected;
2787
2819
  const pedalPc = hasBass && bassSoundsOnlyBelow(notes, windowStart, windowEnd, bassPc) ? bassPc : null;
@@ -2789,17 +2821,17 @@ function analyzeWindow(notes, windowStart, windowEnd, meters, key) {
2789
2821
  let bestMatch = null;
2790
2822
  let bestScore = Number.NEGATIVE_INFINITY;
2791
2823
  for (const match of matches) {
2792
- const score = scoreMatch(match, weights, maxWeight, _chunkYPB3A3EYcjs.scaleOf.call(void 0, key), pedalPc);
2824
+ const score = scoreMatch(match, weights, maxWeight, _chunk3R3QVKY5cjs.scaleOf.call(void 0, key), pedalPc);
2793
2825
  if (score > bestScore) {
2794
2826
  bestScore = score;
2795
2827
  bestMatch = match;
2796
2828
  }
2797
2829
  }
2798
2830
  if (bestMatch) {
2799
- const chord = _chunkYPB3A3EYcjs.makeChord.call(void 0, bestMatch.rootPc, bestMatch.quality, bestMatch.bassPc);
2831
+ const chord = _chunk3R3QVKY5cjs.makeChord.call(void 0, bestMatch.rootPc, bestMatch.quality, bestMatch.bassPc);
2800
2832
  const account = matchAccount(
2801
2833
  bestMatch,
2802
- _chunkYPB3A3EYcjs.makeChord.call(void 0, bestMatch.rootPc, bestMatch.quality),
2834
+ _chunk3R3QVKY5cjs.makeChord.call(void 0, bestMatch.rootPc, bestMatch.quality),
2803
2835
  pedalPc
2804
2836
  );
2805
2837
  const reading = {
@@ -2823,7 +2855,7 @@ function shared(chord) {
2823
2855
  }
2824
2856
  var DOMINANT_ABOVE_TONIC = 7;
2825
2857
  function resolvesOntoDominant(readings, index, key) {
2826
- const dominantPc = _chunkXKSO2V5Icjs.pitchClassOf.call(void 0, key.rootPc + DOMINANT_ABOVE_TONIC);
2858
+ const dominantPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc + DOMINANT_ABOVE_TONIC);
2827
2859
  const candidate = _optionalChain([readings, 'access', _46 => _46[index], 'optionalAccess', _47 => _47.chord]);
2828
2860
  for (let i = index + 1; i < readings.length; i += 1) {
2829
2861
  const next = readings[i];
@@ -2834,10 +2866,10 @@ function resolvesOntoDominant(readings, index, key) {
2834
2866
  if (candidate !== void 0 && sameChord(chord, candidate)) {
2835
2867
  continue;
2836
2868
  }
2837
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc))) !== dominantPc) {
2869
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc))) !== dominantPc) {
2838
2870
  return false;
2839
2871
  }
2840
- if (_chunkXKSO2V5Icjs.pitchClassOf.call(void 0, chord.rootPc) === dominantPc) {
2872
+ if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc) === dominantPc) {
2841
2873
  return true;
2842
2874
  }
2843
2875
  }
@@ -2870,7 +2902,7 @@ var LEXICON_TONES = (() => {
2870
2902
  for (const quality of SEGMENTATION_QUALITIES) {
2871
2903
  LEXICON_ROOTS[candidate] = rootPc;
2872
2904
  LEXICON_TONE_START[candidate] = tones.length;
2873
- tones.push(..._chunkYPB3A3EYcjs.chordPitchClasses.call(void 0, _chunkYPB3A3EYcjs.makeChord.call(void 0, rootPc, quality)));
2905
+ tones.push(..._chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, rootPc, quality)));
2874
2906
  candidate += 1;
2875
2907
  }
2876
2908
  }
@@ -2891,7 +2923,7 @@ function candidateScore(candidate, weights, totalWeight) {
2891
2923
  for (let index = first; index < last; index += 1) {
2892
2924
  const weight = _nullishCoalesce(weights[_nullishCoalesce(LEXICON_TONES[index], () => ( 0))], () => ( 0));
2893
2925
  covered += weight;
2894
- if (weight <= _chunkXKSO2V5Icjs.BEAT_EPS) {
2926
+ if (weight <= _chunkS5BKZZGMcjs.BEAT_EPS) {
2895
2927
  missing += 1;
2896
2928
  }
2897
2929
  }
@@ -2907,16 +2939,16 @@ function slotOfBeat(grid, beat) {
2907
2939
  }
2908
2940
  function createBoundaryTables(slotCount, budget) {
2909
2941
  return {
2910
- scores: _chunkXKSO2V5Icjs.allocateCandidateTable.call(void 0, slotCount, LEXICON_SIZE, "timeline window scores", budget),
2911
- back: _chunkXKSO2V5Icjs.allocateChoiceTable.call(void 0, slotCount, LEXICON_SIZE, "timeline window choices", budget),
2912
- costs: _chunkXKSO2V5Icjs.allocateCandidateTable.call(void 0, 1, LEXICON_SIZE, "timeline window costs", budget),
2913
- spare: _chunkXKSO2V5Icjs.allocateCandidateTable.call(void 0, 1, LEXICON_SIZE, "timeline window costs", budget),
2914
- path: _chunkXKSO2V5Icjs.allocateChoiceTable.call(void 0, slotCount, 1, "timeline window path", budget)
2942
+ scores: _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0, slotCount, LEXICON_SIZE, "timeline window scores", budget),
2943
+ back: _chunkS5BKZZGMcjs.allocateChoiceTable.call(void 0, slotCount, LEXICON_SIZE, "timeline window choices", budget),
2944
+ costs: _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0, 1, LEXICON_SIZE, "timeline window costs", budget),
2945
+ spare: _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0, 1, LEXICON_SIZE, "timeline window costs", budget),
2946
+ path: _chunkS5BKZZGMcjs.allocateChoiceTable.call(void 0, slotCount, 1, "timeline window path", budget)
2915
2947
  };
2916
2948
  }
2917
2949
  function scoreSlot(tables, slot, index) {
2918
2950
  const base = index * LEXICON_SIZE;
2919
- if (slot.totalWeight <= _chunkXKSO2V5Icjs.BEAT_EPS) {
2951
+ if (slot.totalWeight <= _chunkS5BKZZGMcjs.BEAT_EPS) {
2920
2952
  tables.scores.fill(0, base, base + LEXICON_SIZE);
2921
2953
  return;
2922
2954
  }
@@ -2946,7 +2978,7 @@ function chooseBoundaries(tables, from, to, grid, meters, changeCost) {
2946
2978
  }
2947
2979
  }
2948
2980
  const slotStart = beatOfSlot(grid, from + i);
2949
- const accent = _chunkXKSO2V5Icjs.metricWeight.call(void 0, slotStart, meters);
2981
+ const accent = _chunkS5BKZZGMcjs.metricWeight.call(void 0, slotStart, meters);
2950
2982
  const penalty = changeCost * (1 - STRONG_BEAT_DISCOUNT2 * accent / MAX_METRIC_WEIGHT2);
2951
2983
  const rowBase = (from + i) * LEXICON_SIZE;
2952
2984
  const change = cheapest + penalty;
@@ -2988,7 +3020,7 @@ function chooseBoundaries(tables, from, to, grid, meters, changeCost) {
2988
3020
  }
2989
3021
  function slotBeatsWithin(gridUnit, minChordBeats, harmonicRhythm) {
2990
3022
  const resolution = Math.min(minChordBeats, harmonicRhythm);
2991
- const divisions = Math.max(1, Math.ceil(gridUnit / resolution - _chunkXKSO2V5Icjs.BEAT_EPS));
3023
+ const divisions = Math.max(1, Math.ceil(gridUnit / resolution - _chunkS5BKZZGMcjs.BEAT_EPS));
2992
3024
  return gridUnit / divisions;
2993
3025
  }
2994
3026
  function gridSpans(slotCount, grid) {
@@ -3004,7 +3036,7 @@ function dynamicSpans(slotWeights, tables, grid, harmonicRhythm, meters) {
3004
3036
  let weightSum = 0;
3005
3037
  for (let i = 0; i < slotCount; i += 1) {
3006
3038
  const weight = _nullishCoalesce(_optionalChain([slotWeights, 'access', _48 => _48[i], 'optionalAccess', _49 => _49.totalWeight]), () => ( 0));
3007
- if (weight > _chunkXKSO2V5Icjs.BEAT_EPS) {
3039
+ if (weight > _chunkS5BKZZGMcjs.BEAT_EPS) {
3008
3040
  soundingSlots += 1;
3009
3041
  weightSum += weight;
3010
3042
  }
@@ -3014,7 +3046,7 @@ function dynamicSpans(slotWeights, tables, grid, harmonicRhythm, meters) {
3014
3046
  }
3015
3047
  const meanSlotWeight = weightSum / soundingSlots;
3016
3048
  const changeCost = CHANGE_COST * meanSlotWeight * (harmonicRhythm / slotBeats);
3017
- const silent = slotWeights.map((slot) => slot.totalWeight <= _chunkXKSO2V5Icjs.BEAT_EPS);
3049
+ const silent = slotWeights.map((slot) => slot.totalWeight <= _chunkS5BKZZGMcjs.BEAT_EPS);
3018
3050
  const breaks = new Array(slotCount).fill(false);
3019
3051
  for (let i = 0; i < slotCount; ) {
3020
3052
  if (!silent[i]) {
@@ -3025,7 +3057,7 @@ function dynamicSpans(slotWeights, tables, grid, harmonicRhythm, meters) {
3025
3057
  while (end < slotCount && silent[end]) {
3026
3058
  end += 1;
3027
3059
  }
3028
- if ((end - i) * slotBeats >= harmonicRhythm - _chunkXKSO2V5Icjs.BEAT_EPS) {
3060
+ if ((end - i) * slotBeats >= harmonicRhythm - _chunkS5BKZZGMcjs.BEAT_EPS) {
3029
3061
  for (let k = i; k < end; k += 1) {
3030
3062
  breaks[k] = true;
3031
3063
  }
@@ -3088,30 +3120,30 @@ function evidenceFits(previous, grid, slotCount, totalBeats, segmentation, harmo
3088
3120
  return previous.grid.origin === grid.origin && previous.grid.slotBeats === grid.slotBeats && previous.slotCount === slotCount && previous.totalBeats === totalBeats && previous.segmentation === segmentation && previous.harmonicRhythm === harmonicRhythm && previous.keyGiven === keyGiven;
3089
3121
  }
3090
3122
  function analyzeTimeline(notes, opts = {}, previous, dirty) {
3091
- const meters = _chunkXKSO2V5Icjs.resolveMeters.call(void 0, opts, "timeline meters");
3092
- const harmonicRhythm = _nullishCoalesce(opts.harmonicRhythm, () => ( _chunkXKSO2V5Icjs.beatsPerBarAt.call(void 0, 0, meters)));
3093
- _chunkXKSO2V5Icjs.assertRange.call(void 0, harmonicRhythm, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "harmonic rhythm");
3123
+ const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "timeline meters");
3124
+ const harmonicRhythm = _nullishCoalesce(opts.harmonicRhythm, () => ( _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, 0, meters)));
3125
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, harmonicRhythm, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "harmonic rhythm");
3094
3126
  const segmentation = _nullishCoalesce(opts.segmentation, () => ( "dynamic"));
3095
- const gridUnit = _chunkXKSO2V5Icjs.metricGridUnit.call(void 0, meters);
3127
+ const gridUnit = _chunkS5BKZZGMcjs.metricGridUnit.call(void 0, meters);
3096
3128
  const minChordBeats = _nullishCoalesce(opts.minChordBeats, () => ( gridUnit));
3097
- _chunkXKSO2V5Icjs.assertRange.call(void 0, minChordBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "minChordBeats");
3129
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, minChordBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "minChordBeats");
3098
3130
  const budget = opts.budget;
3099
3131
  const noteOptions = { allowNonPositiveDuration: true, budget };
3100
3132
  if (opts.pickupBeats !== void 0) {
3101
- _chunkXKSO2V5Icjs.assertRange.call(void 0, opts.pickupBeats, 0, Number.MAX_SAFE_INTEGER, "timeline pickupBeats");
3133
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, opts.pickupBeats, 0, Number.MAX_SAFE_INTEGER, "timeline pickupBeats");
3102
3134
  noteOptions.minStartBeat = -opts.pickupBeats;
3103
3135
  }
3104
- _chunkXKSO2V5Icjs.assertNoteEvents.call(void 0, notes, "timeline notes", noteOptions);
3105
- const sounding = _chunkTT6PKMPRcjs.sortedNoteEvents.call(void 0, notes.filter((note) => note.durationBeat > 0));
3136
+ _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "timeline notes", noteOptions);
3137
+ const sounding = _chunk35NBV2FTcjs.sortedNoteEvents.call(void 0, notes.filter((note) => note.durationBeat > 0));
3106
3138
  const lastNoteEnd = sounding.reduce((end, n) => Math.max(end, n.startBeat + n.durationBeat), 0);
3107
3139
  const totalBeats = _nullishCoalesce(opts.totalBeats, () => ( lastNoteEnd));
3108
- _chunkXKSO2V5Icjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "timeline totalBeats");
3140
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "timeline totalBeats");
3109
3141
  const slotBeats = segmentation === "grid" ? harmonicRhythm : slotBeatsWithin(gridUnit, minChordBeats, harmonicRhythm);
3110
3142
  const { origin, startBeat: musicStart } = gridForNotes(sounding, slotBeats);
3111
3143
  const grid = { origin, slotBeats };
3112
- const slotCount = Math.max(0, Math.ceil((totalBeats - grid.origin) / slotBeats - _chunkXKSO2V5Icjs.BEAT_EPS));
3144
+ const slotCount = Math.max(0, Math.ceil((totalBeats - grid.origin) / slotBeats - _chunkS5BKZZGMcjs.BEAT_EPS));
3113
3145
  const dynamic = segmentation === "dynamic";
3114
- _chunkXKSO2V5Icjs.assertGenerationBudget.call(void 0,
3146
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0,
3115
3147
  dynamic ? slotCount * LEXICON_SIZE : slotCount,
3116
3148
  "timeline windows",
3117
3149
  budget
@@ -3120,13 +3152,13 @@ function analyzeTimeline(notes, opts = {}, previous, dirty) {
3120
3152
  {
3121
3153
  startBeat: musicStart,
3122
3154
  endBeat: totalBeats,
3123
- key: _chunkYPB3A3EYcjs.resolveKey.call(void 0, opts.key),
3155
+ key: _chunk3R3QVKY5cjs.resolveKey.call(void 0, opts.key),
3124
3156
  confidence: 1
3125
3157
  }
3126
3158
  ] : keyTimelineFromNotes(sounding, { meters, totalBeats, budget });
3127
- const prevailingKey = _nullishCoalesce(prevailingKeyOf(keys), () => ( _chunkYPB3A3EYcjs.resolveKey.call(void 0, _chunkYPB3A3EYcjs.majorKey.call(void 0, 0))));
3159
+ const prevailingKey = _nullishCoalesce(prevailingKeyOf(keys), () => ( _chunk3R3QVKY5cjs.resolveKey.call(void 0, _chunk3R3QVKY5cjs.majorKey.call(void 0, 0))));
3128
3160
  const keyAt = keyLookup(keys, prevailingKey);
3129
- const scaleAt = (beat) => _chunkYPB3A3EYcjs.scaleOf.call(void 0, keyAt(beat));
3161
+ const scaleAt = (beat) => _chunk3R3QVKY5cjs.scaleOf.call(void 0, keyAt(beat));
3130
3162
  const segments = [];
3131
3163
  const segmentConfidence = [];
3132
3164
  const slotNotes = bucketNotesBySlot(sounding, grid, slotCount, {
@@ -3200,7 +3232,7 @@ function analyzeTimeline(notes, opts = {}, previous, dirty) {
3200
3232
  }
3201
3233
  const { start, end } = bounds;
3202
3234
  const last = segments[segments.length - 1];
3203
- if (last && sameChord(last.chord, inferred.chord) && Math.abs(last.endBeat - start) < _chunkXKSO2V5Icjs.BEAT_EPS) {
3235
+ if (last && sameChord(last.chord, inferred.chord) && Math.abs(last.endBeat - start) < _chunkS5BKZZGMcjs.BEAT_EPS) {
3204
3236
  const lastLength = last.endBeat - last.startBeat;
3205
3237
  const length = end - start;
3206
3238
  const lastConfidence = _nullishCoalesce(segmentConfidence[segmentConfidence.length - 1], () => ( 0));
@@ -3241,11 +3273,11 @@ function detectCadences(timeline, key) {
3241
3273
  if (!prev || !cur) {
3242
3274
  continue;
3243
3275
  }
3244
- if (Math.abs(cur.startBeat - prev.endBeat) > _chunkXKSO2V5Icjs.BEAT_EPS) {
3276
+ if (Math.abs(cur.startBeat - prev.endBeat) > _chunkS5BKZZGMcjs.BEAT_EPS) {
3245
3277
  continue;
3246
3278
  }
3247
3279
  const before = timeline.segments[i - 2];
3248
- const approach = before !== void 0 && Math.abs(prev.startBeat - before.endBeat) <= _chunkXKSO2V5Icjs.BEAT_EPS ? before.chord : void 0;
3280
+ const approach = before !== void 0 && Math.abs(prev.startBeat - before.endBeat) <= _chunkS5BKZZGMcjs.BEAT_EPS ? before.chord : void 0;
3249
3281
  const key2 = keyAt(cur.startBeat);
3250
3282
  const cadence = detectCadence(prev.chord, cur.chord, key2, {
3251
3283
  ...approach === void 0 ? {} : { approach }
@@ -3255,7 +3287,7 @@ function detectCadences(timeline, key) {
3255
3287
  }
3256
3288
  if (cadence.type === "half" && isCadentialSixFour(prev.chord, cur.chord, key2)) {
3257
3289
  const next = timeline.segments[i + 1];
3258
- if (next !== void 0 && Math.abs(next.startBeat - cur.endBeat) <= _chunkXKSO2V5Icjs.BEAT_EPS) {
3290
+ if (next !== void 0 && Math.abs(next.startBeat - cur.endBeat) <= _chunkS5BKZZGMcjs.BEAT_EPS) {
3259
3291
  const onward = detectCadence(cur.chord, next.chord, keyAt(next.startBeat)).type;
3260
3292
  if (onward === "authentic" || onward === "deceptive") {
3261
3293
  continue;
@@ -3267,6 +3299,1840 @@ function detectCadences(timeline, key) {
3267
3299
  return hits;
3268
3300
  }
3269
3301
 
3302
+ // src/analyze/melody/internal.ts
3303
+ var RHYTHM_GRID = 64;
3304
+ function phraseNotes(phrase) {
3305
+ if (Array.isArray(phrase)) {
3306
+ return phrase;
3307
+ }
3308
+ return _chunkS5BKZZGMcjs.assertRecord.call(void 0, phrase, "melodic phrase").notes;
3309
+ }
3310
+ function orderedNotes(notes, name, budget) {
3311
+ _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, name, { allowNonPositiveDuration: true, budget });
3312
+ const sounding = notes.filter((note) => note.durationBeat > 0).sort((a, b) => a.startBeat - b.startBeat || a.pitch - b.pitch);
3313
+ const line = [];
3314
+ for (const note of sounding) {
3315
+ const previous = line[line.length - 1];
3316
+ if (previous !== void 0 && Math.abs(note.startBeat - previous.startBeat) <= _chunkS5BKZZGMcjs.BEAT_EPS) {
3317
+ line[line.length - 1] = note;
3318
+ continue;
3319
+ }
3320
+ line.push(note);
3321
+ }
3322
+ return line;
3323
+ }
3324
+ function intervalsOf(notes) {
3325
+ const out = [];
3326
+ for (let i = 1; i < notes.length; i += 1) {
3327
+ out.push((_nullishCoalesce(_optionalChain([notes, 'access', _57 => _57[i], 'optionalAccess', _58 => _58.pitch]), () => ( 0))) - (_nullishCoalesce(_optionalChain([notes, 'access', _59 => _59[i - 1], 'optionalAccess', _60 => _60.pitch]), () => ( 0))));
3328
+ }
3329
+ return out;
3330
+ }
3331
+ function onsetGaps(notes) {
3332
+ const out = [];
3333
+ for (let i = 1; i < notes.length; i += 1) {
3334
+ out.push((_nullishCoalesce(_optionalChain([notes, 'access', _61 => _61[i], 'optionalAccess', _62 => _62.startBeat]), () => ( 0))) - (_nullishCoalesce(_optionalChain([notes, 'access', _63 => _63[i - 1], 'optionalAccess', _64 => _64.startBeat]), () => ( 0))));
3335
+ }
3336
+ return out;
3337
+ }
3338
+ function retrogradeGaps(notes) {
3339
+ const out = [];
3340
+ for (let i = notes.length - 1; i >= 1; i -= 1) {
3341
+ const later = notes[i];
3342
+ const earlier = notes[i - 1];
3343
+ out.push(
3344
+ (_nullishCoalesce(_optionalChain([later, 'optionalAccess', _65 => _65.startBeat]), () => ( 0))) + (_nullishCoalesce(_optionalChain([later, 'optionalAccess', _66 => _66.durationBeat]), () => ( 0))) - ((_nullishCoalesce(_optionalChain([earlier, 'optionalAccess', _67 => _67.startBeat]), () => ( 0))) + (_nullishCoalesce(_optionalChain([earlier, 'optionalAccess', _68 => _68.durationBeat]), () => ( 0))))
3345
+ );
3346
+ }
3347
+ return out;
3348
+ }
3349
+ function rhythmProfile(gaps) {
3350
+ const unit = _nullishCoalesce(gaps[0], () => ( 0));
3351
+ if (!(unit > _chunkS5BKZZGMcjs.BEAT_EPS)) {
3352
+ return gaps.length === 0 ? [] : null;
3353
+ }
3354
+ return gaps.map((gap) => Math.round(gap / unit * RHYTHM_GRID) / RHYTHM_GRID);
3355
+ }
3356
+ function sameNumbers(a, b) {
3357
+ if (a.length !== b.length) {
3358
+ return false;
3359
+ }
3360
+ for (let i = 0; i < a.length; i += 1) {
3361
+ if (Math.abs((_nullishCoalesce(a[i], () => ( 0))) - (_nullishCoalesce(b[i], () => ( 0)))) > _chunkS5BKZZGMcjs.BEAT_EPS) {
3362
+ return false;
3363
+ }
3364
+ }
3365
+ return true;
3366
+ }
3367
+ function roundTo(value, digits) {
3368
+ const scale = 10 ** digits;
3369
+ return Math.round(value * scale) / scale;
3370
+ }
3371
+ function endBeatOf(notes) {
3372
+ let end = 0;
3373
+ for (const note of notes) {
3374
+ end = Math.max(end, note.startBeat + note.durationBeat);
3375
+ }
3376
+ return end;
3377
+ }
3378
+ function onsetSpan(notes) {
3379
+ if (notes.length < 2) {
3380
+ return 0;
3381
+ }
3382
+ return (_nullishCoalesce(_optionalChain([notes, 'access', _69 => _69[notes.length - 1], 'optionalAccess', _70 => _70.startBeat]), () => ( 0))) - (_nullishCoalesce(_optionalChain([notes, 'access', _71 => _71[0], 'optionalAccess', _72 => _72.startBeat]), () => ( 0)));
3383
+ }
3384
+
3385
+ // src/analyze/melody/contour.ts
3386
+ var DIRECTIONAL_SHARE = 0.75;
3387
+ var MELODIC_CONTOUR_SHAPES = Object.freeze([
3388
+ "arch",
3389
+ "ascending",
3390
+ "descending",
3391
+ "wave",
3392
+ "static"
3393
+ ]);
3394
+ function extremes(notes) {
3395
+ if (notes.length === 0) {
3396
+ return { peak: -1, trough: -1 };
3397
+ }
3398
+ let peak = 0;
3399
+ let trough = 0;
3400
+ for (let i = 1; i < notes.length; i += 1) {
3401
+ if ((_nullishCoalesce(_optionalChain([notes, 'access', _73 => _73[i], 'optionalAccess', _74 => _74.pitch]), () => ( 0))) > (_nullishCoalesce(_optionalChain([notes, 'access', _75 => _75[peak], 'optionalAccess', _76 => _76.pitch]), () => ( 0)))) {
3402
+ peak = i;
3403
+ }
3404
+ if ((_nullishCoalesce(_optionalChain([notes, 'access', _77 => _77[i], 'optionalAccess', _78 => _78.pitch]), () => ( 0))) < (_nullishCoalesce(_optionalChain([notes, 'access', _79 => _79[trough], 'optionalAccess', _80 => _80.pitch]), () => ( 0)))) {
3405
+ trough = i;
3406
+ }
3407
+ }
3408
+ return { peak, trough };
3409
+ }
3410
+ function melodicContour(notes) {
3411
+ const line = orderedNotes(phraseNotes(notes), "contour notes");
3412
+ const intervals = intervalsOf(line);
3413
+ const directions = intervals.map(
3414
+ (step) => step > 0 ? "up" : step < 0 ? "down" : "same"
3415
+ );
3416
+ const { peak, trough } = extremes(line);
3417
+ const range = (_nullishCoalesce(_optionalChain([line, 'access', _81 => _81[peak], 'optionalAccess', _82 => _82.pitch]), () => ( 0))) - (_nullishCoalesce(_optionalChain([line, 'access', _83 => _83[trough], 'optionalAccess', _84 => _84.pitch]), () => ( 0)));
3418
+ const motion = intervals.reduce((sum, step) => sum + Math.abs(step), 0);
3419
+ if (motion === 0) {
3420
+ return {
3421
+ directions,
3422
+ shape: "static",
3423
+ peakIndex: peak,
3424
+ troughIndex: trough,
3425
+ range: 0,
3426
+ rationale: line.length < 2 ? "Too short to have a direction, so the line is static" : "Every note at the same pitch, so the line is static"
3427
+ };
3428
+ }
3429
+ const first = _nullishCoalesce(_optionalChain([line, 'access', _85 => _85[0], 'optionalAccess', _86 => _86.pitch]), () => ( 0));
3430
+ const last = _nullishCoalesce(_optionalChain([line, 'access', _87 => _87[line.length - 1], 'optionalAccess', _88 => _88.pitch]), () => ( 0));
3431
+ const net = last - first;
3432
+ const directness = Math.abs(net) / motion;
3433
+ const share = Math.round(directness * 100);
3434
+ if (directness >= DIRECTIONAL_SHARE) {
3435
+ const shape = net > 0 ? "ascending" : "descending";
3436
+ return {
3437
+ directions,
3438
+ shape,
3439
+ peakIndex: peak,
3440
+ troughIndex: trough,
3441
+ range,
3442
+ rationale: `${share}% of the motion runs ${net > 0 ? "up" : "down"}, so the line is ${shape}`
3443
+ };
3444
+ }
3445
+ const peakPitch = _nullishCoalesce(_optionalChain([line, 'access', _89 => _89[peak], 'optionalAccess', _90 => _90.pitch]), () => ( 0));
3446
+ const archMotion = peakPitch - first + (peakPitch - last);
3447
+ if (peak > 0 && peak < line.length - 1 && archMotion >= DIRECTIONAL_SHARE * motion) {
3448
+ return {
3449
+ directions,
3450
+ shape: "arch",
3451
+ peakIndex: peak,
3452
+ troughIndex: trough,
3453
+ range,
3454
+ rationale: `Rises to its peak at note ${peak + 1} of ${line.length} and falls back, so the line is an arch`
3455
+ };
3456
+ }
3457
+ return {
3458
+ directions,
3459
+ shape: "wave",
3460
+ peakIndex: peak,
3461
+ troughIndex: trough,
3462
+ range,
3463
+ rationale: `Changes direction without settling either way (${share}% of the motion nets out), so the line is a wave`
3464
+ };
3465
+ }
3466
+
3467
+ // src/analyze/melody/motifs.ts
3468
+ var MIN_CELL_NOTES = 3;
3469
+ var MAX_CELL_NOTES = 8;
3470
+ var MIN_OCCURRENCES = 2;
3471
+ function windowSignature(notes) {
3472
+ const profile = rhythmProfile(onsetGaps(notes));
3473
+ if (profile === null) {
3474
+ return null;
3475
+ }
3476
+ return `${notes.length}|${intervalsOf(notes).join(",")}|${profile.join(",")}`;
3477
+ }
3478
+ function nonOverlapping(starts, length) {
3479
+ const picked = [];
3480
+ let lastEnd = Number.NEGATIVE_INFINITY;
3481
+ for (const start of starts) {
3482
+ if (start > lastEnd) {
3483
+ picked.push(start);
3484
+ lastEnd = start + length - 1;
3485
+ }
3486
+ }
3487
+ return picked;
3488
+ }
3489
+ function subsumes(outer, inner) {
3490
+ let at = 0;
3491
+ for (const start of inner.starts) {
3492
+ while (at + 1 < outer.starts.length && (_nullishCoalesce(outer.starts[at + 1], () => ( 0))) <= start) {
3493
+ at += 1;
3494
+ }
3495
+ const from = outer.starts[at];
3496
+ if (from === void 0 || start < from || start + inner.length > from + outer.length) {
3497
+ return false;
3498
+ }
3499
+ }
3500
+ return true;
3501
+ }
3502
+ function listBeats(occurrences) {
3503
+ const shown = occurrences.slice(0, 5).map((occurrence) => roundTo(occurrence.startBeat, 3));
3504
+ return occurrences.length > shown.length ? `${shown.join(", ")}, and ${occurrences.length - shown.length} more` : shown.join(", ");
3505
+ }
3506
+ function motifFromGroup(group, notes) {
3507
+ const first = _nullishCoalesce(group.starts[0], () => ( 0));
3508
+ const prime = notes.slice(first, first + group.length).map((note) => ({ ...note }));
3509
+ const primePitch = _nullishCoalesce(_optionalChain([prime, 'access', _91 => _91[0], 'optionalAccess', _92 => _92.pitch]), () => ( 0));
3510
+ const primeSpan = onsetSpan(prime);
3511
+ const occurrences = group.starts.map((start) => {
3512
+ const statement = notes.slice(start, start + group.length);
3513
+ const span = onsetSpan(statement);
3514
+ return {
3515
+ noteIndex: start,
3516
+ startBeat: _nullishCoalesce(_optionalChain([statement, 'access', _93 => _93[0], 'optionalAccess', _94 => _94.startBeat]), () => ( 0)),
3517
+ endBeat: endBeatOf(statement),
3518
+ transpose: (_nullishCoalesce(_optionalChain([statement, 'access', _95 => _95[0], 'optionalAccess', _96 => _96.pitch]), () => ( 0))) - primePitch,
3519
+ timeRatio: primeSpan > _chunkS5BKZZGMcjs.BEAT_EPS ? span / primeSpan : 1
3520
+ };
3521
+ });
3522
+ const shape = melodicContour(prime).shape;
3523
+ const transposed = occurrences.some((occurrence) => occurrence.transpose !== 0);
3524
+ const stretched = occurrences.some((occurrence) => Math.abs(occurrence.timeRatio - 1) > _chunkS5BKZZGMcjs.BEAT_EPS);
3525
+ const detail = [
3526
+ transposed ? "at more than one pitch level" : "at the same pitch level",
3527
+ stretched ? "and in more than one set of note values" : ""
3528
+ ].filter((part) => part !== "").join(" ");
3529
+ return {
3530
+ notes: prime,
3531
+ intervals: intervalsOf(prime),
3532
+ rhythm: _nullishCoalesce(rhythmProfile(onsetGaps(prime)), () => ( [])),
3533
+ occurrences,
3534
+ rationale: `${group.length}-note ${shape} cell stated ${occurrences.length} ${occurrences.length === 1 ? "time" : "times"} (beats ${listBeats(occurrences)}), ${detail}`
3535
+ };
3536
+ }
3537
+ function extractMotifs(notes, opts = {}) {
3538
+ const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
3539
+ const minNotes = _chunkS5BKZZGMcjs.assertInteger.call(void 0, _nullishCoalesce(asked.minNotes, () => ( MIN_CELL_NOTES)), "motif minNotes", 2, 64);
3540
+ const maxNotes = _chunkS5BKZZGMcjs.assertInteger.call(void 0, _nullishCoalesce(asked.maxNotes, () => ( MAX_CELL_NOTES)), "motif maxNotes", 2, 64);
3541
+ if (maxNotes < minNotes) {
3542
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
3543
+ `motif maxNotes must be at least minNotes ${minNotes}; received ${maxNotes}`
3544
+ );
3545
+ }
3546
+ const minOccurrences = _chunkS5BKZZGMcjs.assertInteger.call(void 0,
3547
+ _nullishCoalesce(asked.minOccurrences, () => ( MIN_OCCURRENCES)),
3548
+ "motif minOccurrences",
3549
+ 2
3550
+ );
3551
+ const sounding = orderedNotes(notes, "melody notes", asked.budget);
3552
+ if (sounding.length < minNotes) {
3553
+ return [];
3554
+ }
3555
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0,
3556
+ sounding.length * (maxNotes - minNotes + 1),
3557
+ "motif windows",
3558
+ asked.budget
3559
+ );
3560
+ const groups = /* @__PURE__ */ new Map();
3561
+ for (let length = minNotes; length <= maxNotes; length += 1) {
3562
+ for (let start = 0; start + length <= sounding.length; start += 1) {
3563
+ const signature = windowSignature(sounding.slice(start, start + length));
3564
+ if (signature === null) {
3565
+ continue;
3566
+ }
3567
+ const group = groups.get(signature);
3568
+ if (group === void 0) {
3569
+ groups.set(signature, { signature, length, starts: [start] });
3570
+ } else {
3571
+ group.starts.push(start);
3572
+ }
3573
+ }
3574
+ }
3575
+ const candidates = [...groups.values()].map((group) => ({ ...group, starts: nonOverlapping(group.starts, group.length) })).filter((group) => group.starts.length >= minOccurrences).sort(
3576
+ (a, b) => b.length - a.length || b.starts.length - a.starts.length || (_nullishCoalesce(a.starts[0], () => ( 0))) - (_nullishCoalesce(b.starts[0], () => ( 0))) || (a.signature < b.signature ? -1 : a.signature > b.signature ? 1 : 0)
3577
+ );
3578
+ const keptByLength = /* @__PURE__ */ new Map();
3579
+ const kept = [];
3580
+ let comparisons = 0;
3581
+ for (const candidate of candidates) {
3582
+ const first = _nullishCoalesce(candidate.starts[0], () => ( 0));
3583
+ let covered = false;
3584
+ for (let length = candidate.length + 1; length <= maxNotes && !covered; length += 1) {
3585
+ const byStart = keptByLength.get(length);
3586
+ if (byStart === void 0) {
3587
+ continue;
3588
+ }
3589
+ for (let from = Math.max(0, first - (length - candidate.length)); from <= first; from += 1) {
3590
+ comparisons += 1;
3591
+ const outer = byStart.get(from);
3592
+ if (outer === void 0 || outer.starts.length < candidate.starts.length) {
3593
+ continue;
3594
+ }
3595
+ comparisons += outer.starts.length + candidate.starts.length;
3596
+ if (subsumes(outer, candidate)) {
3597
+ covered = true;
3598
+ break;
3599
+ }
3600
+ }
3601
+ }
3602
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, comparisons, "motif subsumption comparisons", asked.budget);
3603
+ if (!covered) {
3604
+ kept.push(candidate);
3605
+ let byStart = keptByLength.get(candidate.length);
3606
+ if (byStart === void 0) {
3607
+ byStart = /* @__PURE__ */ new Map();
3608
+ keptByLength.set(candidate.length, byStart);
3609
+ }
3610
+ for (const start of candidate.starts) {
3611
+ byStart.set(start, candidate);
3612
+ }
3613
+ }
3614
+ }
3615
+ return kept.map((group) => motifFromGroup(group, sounding));
3616
+ }
3617
+ function motifFromNotes(notes) {
3618
+ const sounding = orderedNotes(notes, "motif notes").map((note) => ({ ...note }));
3619
+ return motifFromGroup(
3620
+ { signature: _nullishCoalesce(windowSignature(sounding), () => ( "")), length: sounding.length, starts: [0] },
3621
+ sounding
3622
+ );
3623
+ }
3624
+
3625
+ // src/analyze/melody/relation.ts
3626
+ var MOTIF_RELATION_KINDS = Object.freeze([
3627
+ "repetition",
3628
+ "transposition",
3629
+ "tonalTransposition",
3630
+ "inversion",
3631
+ "retrograde",
3632
+ "retrogradeInversion",
3633
+ "augmentation",
3634
+ "diminution"
3635
+ ]);
3636
+ function spellingOf(key) {
3637
+ if (key === void 0) {
3638
+ return "sharp";
3639
+ }
3640
+ return _chunk3R3QVKY5cjs.keySignatureFifths.call(void 0, key.tonic, key.scale) < 0 ? "flat" : "sharp";
3641
+ }
3642
+ function intervalBetween(from, to, key) {
3643
+ const spelling = spellingOf(key);
3644
+ return _chunkS5BKZZGMcjs.spelledInterval.call(void 0, _chunkS5BKZZGMcjs.midiToNote.call(void 0, from, spelling), _chunkS5BKZZGMcjs.midiToNote.call(void 0, to, spelling));
3645
+ }
3646
+ function intervalName(interval) {
3647
+ return `${interval.descending && interval.semitones !== 0 ? "-" : ""}${interval.quality}${interval.number}`;
3648
+ }
3649
+ function ladderIndices(notes, key) {
3650
+ const root = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
3651
+ const offsets = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, key).map((pc) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - root));
3652
+ if (offsets.length === 0) {
3653
+ return null;
3654
+ }
3655
+ const out = [];
3656
+ for (const note of notes) {
3657
+ const semitones = note.pitch - root;
3658
+ const octave = Math.floor(semitones / 12);
3659
+ const degree = offsets.indexOf(semitones - octave * 12);
3660
+ if (degree < 0) {
3661
+ return null;
3662
+ }
3663
+ out.push(octave * offsets.length + degree);
3664
+ }
3665
+ return out;
3666
+ }
3667
+ function ladderSteps(indices) {
3668
+ const out = [];
3669
+ for (let i = 1; i < indices.length; i += 1) {
3670
+ out.push((_nullishCoalesce(indices[i], () => ( 0))) - (_nullishCoalesce(indices[i - 1], () => ( 0))));
3671
+ }
3672
+ return out;
3673
+ }
3674
+ function pitchShapes(a, b) {
3675
+ const shapes = [];
3676
+ if (sameNumbers(a, b)) {
3677
+ shapes.push("exact");
3678
+ }
3679
+ if (sameNumbers(
3680
+ b,
3681
+ a.map((step) => -step)
3682
+ )) {
3683
+ shapes.push("inversion");
3684
+ }
3685
+ const reversed = [...a].reverse();
3686
+ if (sameNumbers(
3687
+ b,
3688
+ reversed.map((step) => -step)
3689
+ )) {
3690
+ shapes.push("retrograde");
3691
+ }
3692
+ if (sameNumbers(b, reversed)) {
3693
+ shapes.push("retrogradeInversion");
3694
+ }
3695
+ return shapes;
3696
+ }
3697
+ function totalGap(gaps) {
3698
+ return gaps.reduce((sum, gap) => sum + gap, 0);
3699
+ }
3700
+ function stretchRatio(modelGaps, answerGaps) {
3701
+ const span = totalGap(modelGaps);
3702
+ return span > _chunkS5BKZZGMcjs.BEAT_EPS ? totalGap(answerGaps) / span : 1;
3703
+ }
3704
+ function stretchPhrase(ratio2) {
3705
+ return `note values ${roundTo(ratio2, 3)}x the model's`;
3706
+ }
3707
+ function relateMotifs(a, b, keyLike) {
3708
+ const key = keyLike === void 0 ? void 0 : _chunk3R3QVKY5cjs.resolveKey.call(void 0, keyLike);
3709
+ const model = _chunkS5BKZZGMcjs.assertArray.call(void 0, _chunkS5BKZZGMcjs.assertRecord.call(void 0, a, "a").notes, "a.notes");
3710
+ const answer = _chunkS5BKZZGMcjs.assertArray.call(void 0, _chunkS5BKZZGMcjs.assertRecord.call(void 0, b, "b").notes, "b.notes");
3711
+ if (model.length === 0 || model.length !== answer.length) {
3712
+ return null;
3713
+ }
3714
+ const modelGaps = onsetGaps(model);
3715
+ const answerGaps = onsetGaps(answer);
3716
+ const modelProfile = rhythmProfile(modelGaps);
3717
+ const answerProfile = rhythmProfile(answerGaps);
3718
+ const retroGaps = retrogradeGaps(model);
3719
+ const retroProfile = rhythmProfile(retroGaps);
3720
+ if (modelProfile === null || answerProfile === null) {
3721
+ return null;
3722
+ }
3723
+ const forward = sameNumbers(modelProfile, answerProfile);
3724
+ const backward = retroProfile !== null && sameNumbers(retroProfile, answerProfile);
3725
+ const semitones = (_nullishCoalesce(_optionalChain([answer, 'access', _97 => _97[0], 'optionalAccess', _98 => _98.pitch]), () => ( 0))) - (_nullishCoalesce(_optionalChain([model, 'access', _99 => _99[0], 'optionalAccess', _100 => _100.pitch]), () => ( 0)));
3726
+ const interval = intervalBetween(_nullishCoalesce(_optionalChain([model, 'access', _101 => _101[0], 'optionalAccess', _102 => _102.pitch]), () => ( 0)), _nullishCoalesce(_optionalChain([answer, 'access', _103 => _103[0], 'optionalAccess', _104 => _104.pitch]), () => ( 0)), key);
3727
+ const gap = (_nullishCoalesce(_optionalChain([answer, 'access', _105 => _105[0], 'optionalAccess', _106 => _106.startBeat]), () => ( 0))) - endBeatOf(model);
3728
+ const sequence = gap >= -HUMANIZE_ADJACENCY && gap <= HUMANIZE_ADJACENCY;
3729
+ const timeRatio = stretchRatio(modelGaps, answerGaps);
3730
+ const stretched = Math.abs(timeRatio - 1) > _chunkS5BKZZGMcjs.BEAT_EPS;
3731
+ const shapes = pitchShapes(intervalsOf(model), intervalsOf(answer));
3732
+ const base = { sequence, semitones, interval, timeRatio };
3733
+ const backwardBase = { ...base, timeRatio: stretchRatio(retroGaps, answerGaps) };
3734
+ if (forward && shapes.includes("exact")) {
3735
+ if (semitones === 0) {
3736
+ if (!stretched) {
3737
+ return {
3738
+ ...base,
3739
+ kind: "repetition",
3740
+ rationale: "Exact repetition: the same pitches in the same rhythm"
3741
+ };
3742
+ }
3743
+ const augmented = timeRatio > 1;
3744
+ return {
3745
+ ...base,
3746
+ kind: augmented ? "augmentation" : "diminution",
3747
+ rationale: `${augmented ? "Augmentation" : "Diminution"}: the same pitches in ${stretchPhrase(timeRatio)}`
3748
+ };
3749
+ }
3750
+ const name = intervalName(interval);
3751
+ return {
3752
+ ...base,
3753
+ kind: "transposition",
3754
+ rationale: sequence ? `Real sequence: the cell restated ${name} away with every interval kept literally` + (stretched ? `, in ${stretchPhrase(timeRatio)}` : "") : `Transposition by ${name}: every interval kept literally` + (stretched ? `, in ${stretchPhrase(timeRatio)}` : "")
3755
+ };
3756
+ }
3757
+ if (forward && key !== void 0) {
3758
+ const modelLadder = ladderIndices(model, key.scale);
3759
+ const answerLadder = ladderIndices(answer, key.scale);
3760
+ if (modelLadder !== null && answerLadder !== null) {
3761
+ const degrees = (_nullishCoalesce(answerLadder[0], () => ( 0))) - (_nullishCoalesce(modelLadder[0], () => ( 0)));
3762
+ if (degrees !== 0 && sameNumbers(ladderSteps(modelLadder), ladderSteps(answerLadder))) {
3763
+ const direction = degrees > 0 ? "higher" : "lower";
3764
+ const count = Math.abs(degrees);
3765
+ return {
3766
+ ...base,
3767
+ kind: "tonalTransposition",
3768
+ degrees,
3769
+ rationale: `${sequence ? "Tonal sequence" : "Tonal transposition"}: the cell restated ${count} scale ${count === 1 ? "degree" : "degrees"} ${direction} inside the key, so the key resizes its intervals \u2014 a real one would have kept them literal`
3770
+ };
3771
+ }
3772
+ }
3773
+ }
3774
+ if (forward && shapes.includes("inversion")) {
3775
+ return {
3776
+ ...base,
3777
+ kind: "inversion",
3778
+ rationale: "Inversion: every interval turned upside down about the first note" + (stretched ? `, in ${stretchPhrase(timeRatio)}` : "")
3779
+ };
3780
+ }
3781
+ if (backward && shapes.includes("retrograde")) {
3782
+ return {
3783
+ ...backwardBase,
3784
+ kind: "retrograde",
3785
+ rationale: "Retrograde: the cell read back to front, rhythm included"
3786
+ };
3787
+ }
3788
+ if (backward && shapes.includes("retrogradeInversion")) {
3789
+ return {
3790
+ ...backwardBase,
3791
+ kind: "retrogradeInversion",
3792
+ rationale: "Retrograde inversion: the cell read back to front and turned upside down"
3793
+ };
3794
+ }
3795
+ return null;
3796
+ }
3797
+
3798
+ // src/analyze/sequence.ts
3799
+ function gradedEditDistance(a, b, cost, gap = 1) {
3800
+ let previous = Array.from({ length: b.length + 1 }, (_, i) => i * gap);
3801
+ for (let i = 1; i <= a.length; i += 1) {
3802
+ const row = new Array(b.length + 1);
3803
+ row[0] = i * gap;
3804
+ for (let j = 1; j <= b.length; j += 1) {
3805
+ const ai = a[i - 1];
3806
+ const bj = b[j - 1];
3807
+ const substitution = (_nullishCoalesce(previous[j - 1], () => ( 0))) + cost(ai, bj);
3808
+ const deletion = (_nullishCoalesce(previous[j], () => ( 0))) + gap;
3809
+ const insertion = (_nullishCoalesce(row[j - 1], () => ( 0))) + gap;
3810
+ row[j] = Math.min(substitution, deletion, insertion);
3811
+ }
3812
+ previous = row;
3813
+ }
3814
+ return _nullishCoalesce(previous[b.length], () => ( 0));
3815
+ }
3816
+ function distanceToSimilarity(distance, a, b) {
3817
+ const longest = Math.max(a, b);
3818
+ if (longest === 0) {
3819
+ return 1;
3820
+ }
3821
+ return Math.min(1, Math.max(0, 1 - distance / longest));
3822
+ }
3823
+
3824
+ // src/analyze/melody/similarity.ts
3825
+ var INTERVAL_TOLERANCE = 6;
3826
+ var PITCH_WEIGHT = 0.75;
3827
+ var RHYTHM_WEIGHT = 0.25;
3828
+ function intervalCost(x, y) {
3829
+ return Math.min(1, Math.abs(x - y) / INTERVAL_TOLERANCE);
3830
+ }
3831
+ function gapCost(x, y) {
3832
+ if (!(x > _chunkS5BKZZGMcjs.BEAT_EPS) || !(y > _chunkS5BKZZGMcjs.BEAT_EPS)) {
3833
+ return Math.abs(x - y) > _chunkS5BKZZGMcjs.BEAT_EPS ? 1 : 0;
3834
+ }
3835
+ return Math.min(1, Math.abs(Math.log2(x / y)));
3836
+ }
3837
+ function compareMelodies(a, b) {
3838
+ const left = orderedNotes(phraseNotes(a), "melody a");
3839
+ const right = orderedNotes(phraseNotes(b), "melody b");
3840
+ const leftIntervals = intervalsOf(left);
3841
+ const rightIntervals = intervalsOf(right);
3842
+ const pitchSimilarity = distanceToSimilarity(
3843
+ gradedEditDistance(leftIntervals, rightIntervals, intervalCost),
3844
+ leftIntervals.length,
3845
+ rightIntervals.length
3846
+ );
3847
+ const leftGaps = _nullishCoalesce(rhythmProfile(onsetGaps(left)), () => ( onsetGaps(left)));
3848
+ const rightGaps = _nullishCoalesce(rhythmProfile(onsetGaps(right)), () => ( onsetGaps(right)));
3849
+ const rhythmSimilarity = distanceToSimilarity(
3850
+ gradedEditDistance(leftGaps, rightGaps, gapCost),
3851
+ leftGaps.length,
3852
+ rightGaps.length
3853
+ );
3854
+ const similarity = PITCH_WEIGHT * pitchSimilarity + RHYTHM_WEIGHT * rhythmSimilarity;
3855
+ return {
3856
+ similarity,
3857
+ pitchSimilarity,
3858
+ rhythmSimilarity,
3859
+ rationale: `Interval shapes ${Math.round(pitchSimilarity * 100)}% alike, rhythms ${Math.round(rhythmSimilarity * 100)}% alike, weighted ${PITCH_WEIGHT}/${RHYTHM_WEIGHT} into ${roundTo(similarity, 3)}`
3860
+ };
3861
+ }
3862
+ function melodicSimilarity(a, b) {
3863
+ return compareMelodies(a, b).similarity;
3864
+ }
3865
+
3866
+ // src/analyze/melody/graph.ts
3867
+ var DEFAULT_VARIATION_THRESHOLD = 0.75;
3868
+ function summarize(relation) {
3869
+ const { kind, sequence, semitones, degrees, timeRatio } = relation;
3870
+ return { kind, sequence, semitones, degrees, timeRatio };
3871
+ }
3872
+ function betterParent(candidate, current) {
3873
+ const candidateNamed = candidate.relation !== null;
3874
+ const currentNamed = current.relation !== null;
3875
+ if (candidateNamed !== currentNamed) {
3876
+ return candidateNamed;
3877
+ }
3878
+ if (candidate.similarity !== current.similarity) {
3879
+ return candidate.similarity > current.similarity;
3880
+ }
3881
+ if (candidate.startBeat !== current.startBeat) {
3882
+ return candidate.startBeat > current.startBeat;
3883
+ }
3884
+ return candidate.index < current.index;
3885
+ }
3886
+ function motifGraph(line, motifs, opts = {}) {
3887
+ const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
3888
+ const variationThreshold = _nullishCoalesce(asked.variationThreshold, () => ( DEFAULT_VARIATION_THRESHOLD));
3889
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, variationThreshold, 0, 1, "motif graph variationThreshold");
3890
+ const ordered = orderedNotes(line, "line", asked.budget);
3891
+ const motifList = _chunkS5BKZZGMcjs.assertArray.call(void 0, motifs, "motifs");
3892
+ const infos = [];
3893
+ for (let mi = 0; mi < motifList.length; mi += 1) {
3894
+ const motif = _chunkS5BKZZGMcjs.assertRecord.call(void 0, motifList[mi], `motifs[${mi}]`);
3895
+ const notes = _chunkS5BKZZGMcjs.assertArray.call(void 0, motif.notes, `motifs[${mi}].notes`);
3896
+ const occurrences = _chunkS5BKZZGMcjs.assertArray.call(void 0,
3897
+ motif.occurrences,
3898
+ `motifs[${mi}].occurrences`
3899
+ );
3900
+ for (let oi = 0; oi < occurrences.length; oi += 1) {
3901
+ const occurrence = _chunkS5BKZZGMcjs.assertRecord.call(void 0,
3902
+ occurrences[oi],
3903
+ `motifs[${mi}].occurrences[${oi}]`
3904
+ );
3905
+ const { noteIndex } = occurrence;
3906
+ const onLine = Number.isInteger(noteIndex) && noteIndex >= 0 && noteIndex + notes.length <= ordered.length && Math.abs((_nullishCoalesce(_optionalChain([ordered, 'access', _107 => _107[noteIndex], 'optionalAccess', _108 => _108.startBeat]), () => ( Number.NaN))) - occurrence.startBeat) <= _chunkS5BKZZGMcjs.BEAT_EPS;
3907
+ if (!onLine) {
3908
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
3909
+ `motif occurrence motifs[${mi}].occurrences[${oi}] does not lie on the line`
3910
+ );
3911
+ }
3912
+ infos.push({
3913
+ node: {
3914
+ motif: mi,
3915
+ occurrence: oi,
3916
+ startBeat: occurrence.startBeat,
3917
+ endBeat: occurrence.endBeat
3918
+ },
3919
+ data: motifFromNotes(ordered.slice(noteIndex, noteIndex + notes.length))
3920
+ });
3921
+ }
3922
+ }
3923
+ infos.sort((a, b) => a.node.startBeat - b.node.startBeat || a.node.motif - b.node.motif);
3924
+ const nodeCount = infos.length;
3925
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, nodeCount * nodeCount, "motif graph comparisons", asked.budget);
3926
+ const edges = [];
3927
+ for (let to = 1; to < nodeCount; to += 1) {
3928
+ const toInfo = infos[to];
3929
+ let best = null;
3930
+ for (let from = 0; from < to; from += 1) {
3931
+ const fromInfo = infos[from];
3932
+ const candidate = {
3933
+ index: from,
3934
+ startBeat: fromInfo.node.startBeat,
3935
+ relation: relateMotifs(fromInfo.data, toInfo.data, asked.key),
3936
+ similarity: melodicSimilarity(fromInfo.data, toInfo.data)
3937
+ };
3938
+ if (best === null || betterParent(candidate, best)) {
3939
+ best = candidate;
3940
+ }
3941
+ }
3942
+ if (best !== null && (best.relation !== null || best.similarity >= variationThreshold)) {
3943
+ edges.push({
3944
+ from: best.index,
3945
+ to,
3946
+ relation: best.relation === null ? null : summarize(best.relation),
3947
+ similarity: best.similarity
3948
+ });
3949
+ }
3950
+ }
3951
+ return { nodes: infos.map((info) => info.node), edges };
3952
+ }
3953
+
3954
+ // src/analyze/reduction/index.ts
3955
+ var REDUCTION_LEVELS = Object.freeze(["structural", "passing", "neighbor"]);
3956
+ var TONIC_ARRIVING = /* @__PURE__ */ new Set(["authentic", "plagal", "modal", "deceptive"]);
3957
+ function signedStep(fromPc, toPc) {
3958
+ return (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, toPc) - _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, fromPc) + 18) % 12 - 6;
3959
+ }
3960
+ function isStep2(distance) {
3961
+ const size = Math.abs(distance);
3962
+ return size === 1 || size === 2;
3963
+ }
3964
+ function touches(before, after) {
3965
+ return Math.abs(after.startBeat - before.endBeat) <= _chunkS5BKZZGMcjs.BEAT_EPS;
3966
+ }
3967
+ function salienceFloors(durations) {
3968
+ const order = durations.map((_, index) => index).sort((a, b) => {
3969
+ const left = _nullishCoalesce(durations[a], () => ( 0));
3970
+ const right = _nullishCoalesce(durations[b], () => ( 0));
3971
+ return left - right || a - b;
3972
+ });
3973
+ const rankOf = new Array(durations.length).fill(0);
3974
+ for (let rank = 0; rank < order.length; rank += 1) {
3975
+ rankOf[_nullishCoalesce(order[rank], () => ( 0))] = rank;
3976
+ }
3977
+ const floors = [];
3978
+ const remaining = durations.length - 1;
3979
+ for (let index = 0; index < durations.length; index += 1) {
3980
+ if (remaining <= 0) {
3981
+ floors.push(0);
3982
+ continue;
3983
+ }
3984
+ const skipped = _nullishCoalesce(rankOf[index], () => ( 0));
3985
+ const at = (position) => _nullishCoalesce(durations[_nullishCoalesce(order[position < skipped ? position : position + 1], () => ( 0))], () => ( 0));
3986
+ const middle = remaining >> 1;
3987
+ floors.push(remaining % 2 === 1 ? at(middle) : (at(middle - 1) + at(middle)) / 2);
3988
+ }
3989
+ return floors;
3990
+ }
3991
+ function isTonicChord(chord, key) {
3992
+ return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) === 0 && !isAppliedDominant(chord, key);
3993
+ }
3994
+ function functionalReason(segment, before, after, keyAt) {
3995
+ const key = keyAt(segment.startBeat);
3996
+ if (after !== void 0 && isCadentialSixFour(segment.chord, after.chord, key)) {
3997
+ return { kind: "cadentialSixFour" };
3998
+ }
3999
+ if (isTonicChord(segment.chord, key)) {
4000
+ return { kind: "tonic" };
4001
+ }
4002
+ if (_chunk3R3QVKY5cjs.isDominantChordOf.call(void 0, segment.chord, key)) {
4003
+ return { kind: "dominant" };
4004
+ }
4005
+ if (before !== void 0) {
4006
+ const arrival = detectCadence(before.chord, segment.chord, key).type;
4007
+ if (arrival !== null) {
4008
+ return { kind: "cadenceArrival", cadence: arrival };
4009
+ }
4010
+ }
4011
+ if (after !== void 0) {
4012
+ const agent = detectCadence(segment.chord, after.chord, keyAt(after.startBeat)).type;
4013
+ if (agent !== null && TONIC_ARRIVING.has(agent)) {
4014
+ return { kind: "cadenceAgent", cadence: agent };
4015
+ }
4016
+ }
4017
+ return null;
4018
+ }
4019
+ function figureReason(segment, before, after) {
4020
+ if (before === void 0 || after === void 0) {
4021
+ return null;
4022
+ }
4023
+ const incoming = signedStep(before.chord.rootPc, segment.chord.rootPc);
4024
+ const outgoing = signedStep(segment.chord.rootPc, after.chord.rootPc);
4025
+ if (!isStep2(incoming) || !isStep2(outgoing)) {
4026
+ return null;
4027
+ }
4028
+ if (incoming > 0 === outgoing > 0) {
4029
+ return { kind: "passing" };
4030
+ }
4031
+ return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, before.chord.rootPc) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, after.chord.rootPc) ? { kind: "neighbor" } : null;
4032
+ }
4033
+ function describe2(reason) {
4034
+ switch (reason.kind) {
4035
+ case "tonic":
4036
+ return "Structural: the tonic of the key, which the progression is heard against";
4037
+ case "dominant":
4038
+ return "Structural: the dominant of the key, the chord its tonic is approached from";
4039
+ case "cadentialSixFour":
4040
+ return "Structural: a tonic six-four on the bass of the dominant that follows, which prolongs that dominant rather than framing the tonic";
4041
+ case "cadenceArrival":
4042
+ return `Structural: the arrival of a ${reason.cadence} cadence`;
4043
+ case "cadenceAgent":
4044
+ return `Structural: the chord that drives a ${reason.cadence} cadence`;
4045
+ case "salient":
4046
+ return "Structural: it holds the harmony longer than the chords around it";
4047
+ case "first":
4048
+ return "Structural: the first chord of the progression frames it";
4049
+ case "last":
4050
+ return "Structural: the last chord of the progression frames it";
4051
+ case "unfigured":
4052
+ return "Structural: its root neither steps through to the next chord nor returns to the last, so it embellishes nothing";
4053
+ case "passing":
4054
+ return "Passing: its root steps in from the previous chord and on to the next in the same direction";
4055
+ case "neighbor":
4056
+ return "Neighbor: its root steps away from the surrounding harmony and returns to it";
4057
+ }
4058
+ }
4059
+ var BASIS_READINGS = {
4060
+ function: ({ segment, before, after, keyAt }) => functionalReason(segment, before, after, keyAt),
4061
+ duration: ({ segment, salienceFloor }) => segment.endBeat - segment.startBeat > salienceFloor ? { kind: "salient" } : null
4062
+ };
4063
+ var REDUCTION_BASES = Object.keys(BASIS_READINGS);
4064
+ function levelOf(reason) {
4065
+ if (reason.kind === "passing") {
4066
+ return "passing";
4067
+ }
4068
+ return reason.kind === "neighbor" ? "neighbor" : "structural";
4069
+ }
4070
+ function reduceProgression(timeline, key, opts = {}) {
4071
+ assertChordTimeline(timeline);
4072
+ const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
4073
+ const keyAt = keyScaleAt(key);
4074
+ const basis = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, _nullishCoalesce(asked.basis, () => ( "function")), REDUCTION_BASES, "reduction basis");
4075
+ const reading = BASIS_READINGS[basis];
4076
+ const segments = timeline.segments;
4077
+ const floors = basis === "duration" ? salienceFloors(segments.map((segment) => segment.endBeat - segment.startBeat)) : [];
4078
+ const result = [];
4079
+ for (let index = 0; index < segments.length; index += 1) {
4080
+ const segment = segments[index];
4081
+ if (segment === void 0) {
4082
+ continue;
4083
+ }
4084
+ const previous = segments[index - 1];
4085
+ const following = segments[index + 1];
4086
+ const before = previous !== void 0 && touches(previous, segment) ? previous : void 0;
4087
+ const after = following !== void 0 && touches(segment, following) ? following : void 0;
4088
+ let reason = reading({ segment, before, after, keyAt, salienceFloor: _nullishCoalesce(floors[index], () => ( 0)) });
4089
+ if (reason === null && index === 0) {
4090
+ reason = { kind: "first" };
4091
+ }
4092
+ if (reason === null && index === segments.length - 1) {
4093
+ reason = { kind: "last" };
4094
+ }
4095
+ reason ??= _nullishCoalesce(figureReason(segment, before, after), () => ( { kind: "unfigured" }));
4096
+ result.push({
4097
+ chord: segment.chord,
4098
+ startBeat: segment.startBeat,
4099
+ endBeat: segment.endBeat,
4100
+ level: levelOf(reason),
4101
+ rationale: describe2(reason)
4102
+ });
4103
+ }
4104
+ return result;
4105
+ }
4106
+
4107
+ // src/analyze/rhythm/internal.ts
4108
+ function isMultipleOf(value, unit) {
4109
+ if (unit <= 0) {
4110
+ return false;
4111
+ }
4112
+ const ratio2 = value / unit;
4113
+ return Math.abs(ratio2 - Math.round(ratio2)) < _chunkS5BKZZGMcjs.BEAT_EPS;
4114
+ }
4115
+ function rhythmLevel(beatInQuarters, meters) {
4116
+ const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, beatInQuarters, meters);
4117
+ const offset = beatInQuarters - _chunkS5BKZZGMcjs.barStartBeat.call(void 0, beatInQuarters, meters);
4118
+ const pulse = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, ts);
4119
+ if (isMultipleOf(offset, pulse)) {
4120
+ return _chunkS5BKZZGMcjs.metricWeight.call(void 0, beatInQuarters, meters) + 2;
4121
+ }
4122
+ const subUnit = pulse / (_chunkS5BKZZGMcjs.isCompound.call(void 0, ts) ? 3 : 2);
4123
+ return isMultipleOf(offset, subUnit) ? 1 : 0;
4124
+ }
4125
+ function ioiBinIndex(ioi) {
4126
+ const exponent = Math.min(4, Math.max(-4, Math.round(2 * Math.log2(ioi)) / 2));
4127
+ return Math.round((exponent + 4) / 0.5);
4128
+ }
4129
+
4130
+ // src/analyze/rhythm/index.ts
4131
+ var RHYTHM_SLOTS_PER_BEAT = 12;
4132
+ var SLOT_WIDTH = 1 / RHYTHM_SLOTS_PER_BEAT;
4133
+ var RHYTHM_OFF_GRID_TOLERANCE = 1 / 32;
4134
+ var RHYTHM_IOI_BINS = Object.freeze(
4135
+ Array.from({ length: 17 }, (_, i) => 2 ** (-4 + i * 0.5))
4136
+ );
4137
+ function emptyAnalysis() {
4138
+ return {
4139
+ startBeat: 0,
4140
+ endBeat: 0,
4141
+ bars: 0,
4142
+ onsets: 0,
4143
+ onsetDensity: 0,
4144
+ barOnsets: [],
4145
+ onsetLevels: new Array(6).fill(0),
4146
+ barPositions: [],
4147
+ interOnsetShares: new Array(RHYTHM_IOI_BINS.length).fill(0),
4148
+ restRatio: 0,
4149
+ syncopation: 0,
4150
+ offGridRatio: 0,
4151
+ rationale: "Nothing sounds, so there is no rhythm to place on a grid"
4152
+ };
4153
+ }
4154
+ function foldOnsets(sounding) {
4155
+ const sorted = [...sounding].sort((a, b) => a.startBeat - b.startBeat);
4156
+ const onsets = [];
4157
+ for (const note of sorted) {
4158
+ const noteEnd = note.startBeat + note.durationBeat;
4159
+ const current = onsets[onsets.length - 1];
4160
+ if (current !== void 0 && note.startBeat - current.beat <= HUMANIZE_ADJACENCY) {
4161
+ current.end = Math.max(current.end, noteEnd);
4162
+ } else {
4163
+ onsets.push({ beat: note.startBeat, end: noteEnd });
4164
+ }
4165
+ }
4166
+ return onsets;
4167
+ }
4168
+ function snapOnset(onset, meters) {
4169
+ const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, onset.beat, meters);
4170
+ const barStart = _chunkS5BKZZGMcjs.barStartBeat.call(void 0, onset.beat, meters);
4171
+ const offset = onset.beat - barStart;
4172
+ const slot = Math.round(offset / SLOT_WIDTH);
4173
+ const snapped = barStart + slot * SLOT_WIDTH;
4174
+ const offGrid = Math.abs(onset.beat - snapped) > RHYTHM_OFF_GRID_TOLERANCE;
4175
+ return { ...onset, ts, barStart, slot, snapped, level: rhythmLevel(snapped, meters), offGrid };
4176
+ }
4177
+ function tsKey(ts) {
4178
+ return ts.grouping === void 0 ? `${ts.numerator}/${ts.denominator}` : `${ts.numerator}/${ts.denominator}:${ts.grouping.join("+")}`;
4179
+ }
4180
+ function barGridBeats(bar, meters) {
4181
+ const barStart = _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar, beat: 0 }, meters);
4182
+ const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, barStart, meters);
4183
+ const barLength = _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, barStart, meters);
4184
+ const subUnit = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, ts) / (_chunkS5BKZZGMcjs.isCompound.call(void 0, ts) ? 3 : 2);
4185
+ const steps = Math.max(1, Math.round(barLength / subUnit));
4186
+ return Array.from({ length: steps }, (_, k) => barStart + k * subUnit);
4187
+ }
4188
+ function restRatioOf(sounding, windowStart, windowEnd) {
4189
+ const span = windowEnd - windowStart;
4190
+ if (span <= 0) {
4191
+ return 0;
4192
+ }
4193
+ const intervals = sounding.map((note) => [
4194
+ Math.max(windowStart, note.startBeat),
4195
+ Math.min(windowEnd, note.startBeat + note.durationBeat)
4196
+ ]).filter(([from, to]) => to > from).sort((a, b) => a[0] - b[0]);
4197
+ let covered = 0;
4198
+ let curStart = 0;
4199
+ let curEnd = Number.NEGATIVE_INFINITY;
4200
+ for (const [from, to] of intervals) {
4201
+ if (from - curEnd > HUMANIZE_ADJACENCY) {
4202
+ if (curEnd > Number.NEGATIVE_INFINITY) {
4203
+ covered += curEnd - curStart;
4204
+ }
4205
+ curStart = from;
4206
+ curEnd = to;
4207
+ } else {
4208
+ curEnd = Math.max(curEnd, to);
4209
+ }
4210
+ }
4211
+ if (curEnd > Number.NEGATIVE_INFINITY) {
4212
+ covered += curEnd - curStart;
4213
+ }
4214
+ return 1 - covered / span;
4215
+ }
4216
+ function syncopationOf(snapped, startBeat, endBeat, meters) {
4217
+ if (snapped.length === 0) {
4218
+ return 0;
4219
+ }
4220
+ const firstBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, startBeat, meters);
4221
+ const lastBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, endBeat, meters);
4222
+ const points = [];
4223
+ for (let bar = firstBar; bar <= lastBar; bar += 1) {
4224
+ for (const beat of barGridBeats(bar, meters)) {
4225
+ if (beat > startBeat + _chunkS5BKZZGMcjs.BEAT_EPS && beat <= endBeat + _chunkS5BKZZGMcjs.BEAT_EPS) {
4226
+ points.push({ beat, level: rhythmLevel(beat, meters) });
4227
+ }
4228
+ }
4229
+ }
4230
+ const normalizer = points.reduce((sum, p) => sum + p.level, 0);
4231
+ if (normalizer <= 0) {
4232
+ return 0;
4233
+ }
4234
+ let numerator = 0;
4235
+ let ptr = 0;
4236
+ for (let i = 0; i < snapped.length; i += 1) {
4237
+ const onset = snapped[i];
4238
+ if (onset === void 0) {
4239
+ continue;
4240
+ }
4241
+ const next = snapped[i + 1];
4242
+ const windowEnd = next !== void 0 ? next.snapped : onset.end;
4243
+ while (ptr < points.length && (_nullishCoalesce(_optionalChain([points, 'access', _109 => _109[ptr], 'optionalAccess', _110 => _110.beat]), () => ( Number.POSITIVE_INFINITY))) <= onset.snapped + _chunkS5BKZZGMcjs.BEAT_EPS) {
4244
+ ptr += 1;
4245
+ }
4246
+ let scan = ptr;
4247
+ let maxLevel = 0;
4248
+ while (scan < points.length && (_nullishCoalesce(_optionalChain([points, 'access', _111 => _111[scan], 'optionalAccess', _112 => _112.beat]), () => ( Number.POSITIVE_INFINITY))) < windowEnd - _chunkS5BKZZGMcjs.BEAT_EPS) {
4249
+ maxLevel = Math.max(maxLevel, _nullishCoalesce(_optionalChain([points, 'access', _113 => _113[scan], 'optionalAccess', _114 => _114.level]), () => ( 0)));
4250
+ scan += 1;
4251
+ }
4252
+ if (maxLevel > onset.level) {
4253
+ numerator += maxLevel - onset.level;
4254
+ }
4255
+ ptr = scan;
4256
+ }
4257
+ return numerator / normalizer;
4258
+ }
4259
+ function analyzeRhythm(notes, opts = {}) {
4260
+ const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "rhythm meters");
4261
+ _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "rhythm notes", { allowNonPositiveDuration: true, budget: opts.budget });
4262
+ const sounding = notes.filter((note) => note.durationBeat > 0);
4263
+ if (sounding.length === 0) {
4264
+ return emptyAnalysis();
4265
+ }
4266
+ const firstOnset = sounding.reduce(
4267
+ (min, n) => Math.min(min, n.startBeat),
4268
+ Number.POSITIVE_INFINITY
4269
+ );
4270
+ const startBeat = barGridStart(firstOnset, meters);
4271
+ const lastEnd = sounding.reduce((end, n) => Math.max(end, n.startBeat + n.durationBeat), 0);
4272
+ const endBeat = Math.max(startBeat, _nullishCoalesce(opts.totalBeats, () => ( lastEnd)));
4273
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, endBeat, 0, Number.MAX_SAFE_INTEGER, "rhythm totalBeats");
4274
+ const bars = barSpanOf(startBeat, endBeat, meters);
4275
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, Math.ceil(bars) * 48, "rhythm analysis slots", opts.budget);
4276
+ const onsets = foldOnsets(sounding);
4277
+ const snapped = onsets.map((onset) => snapOnset(onset, meters));
4278
+ const onsetDensity = bars > 0 ? onsets.length / bars : 0;
4279
+ const firstBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, startBeat, meters);
4280
+ const barOnsets = new Array(lastBarOf(meters, startBeat, endBeat) - firstBar + 1).fill(0);
4281
+ for (const onset of onsets) {
4282
+ const index = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, onset.beat, meters) - firstBar;
4283
+ if (index >= 0 && index < barOnsets.length) {
4284
+ barOnsets[index] = (_nullishCoalesce(barOnsets[index], () => ( 0))) + 1;
4285
+ }
4286
+ }
4287
+ const onsetLevels = new Array(6).fill(0);
4288
+ let offGridCount = 0;
4289
+ for (const onset of snapped) {
4290
+ onsetLevels[onset.level] = (_nullishCoalesce(onsetLevels[onset.level], () => ( 0))) + 1;
4291
+ if (onset.offGrid) {
4292
+ offGridCount += 1;
4293
+ }
4294
+ }
4295
+ for (let i = 0; i < onsetLevels.length; i += 1) {
4296
+ onsetLevels[i] = (_nullishCoalesce(onsetLevels[i], () => ( 0))) / onsets.length;
4297
+ }
4298
+ const profiles = [];
4299
+ const profileIndex = /* @__PURE__ */ new Map();
4300
+ for (const onset of snapped) {
4301
+ const key = tsKey(onset.ts);
4302
+ let index = profileIndex.get(key);
4303
+ if (index === void 0) {
4304
+ index = profiles.length;
4305
+ profileIndex.set(key, index);
4306
+ const slotsPerBar = Math.ceil(_chunkS5BKZZGMcjs.beatsPerBar.call(void 0, onset.ts) * RHYTHM_SLOTS_PER_BEAT);
4307
+ profiles.push({
4308
+ ts: onset.ts,
4309
+ slotsPerBar,
4310
+ shares: new Array(slotsPerBar).fill(0),
4311
+ onsets: 0
4312
+ });
4313
+ }
4314
+ const profile = profiles[index];
4315
+ if (profile !== void 0) {
4316
+ const slotIndex = (onset.slot % profile.slotsPerBar + profile.slotsPerBar) % profile.slotsPerBar;
4317
+ profile.shares[slotIndex] = (_nullishCoalesce(profile.shares[slotIndex], () => ( 0))) + 1;
4318
+ profile.onsets += 1;
4319
+ }
4320
+ }
4321
+ for (const profile of profiles) {
4322
+ for (let i = 0; i < profile.shares.length; i += 1) {
4323
+ profile.shares[i] = (_nullishCoalesce(profile.shares[i], () => ( 0))) / profile.onsets;
4324
+ }
4325
+ }
4326
+ const interOnsetShares = new Array(RHYTHM_IOI_BINS.length).fill(0);
4327
+ for (let i = 0; i < onsets.length; i += 1) {
4328
+ const onset = onsets[i];
4329
+ if (onset === void 0) {
4330
+ continue;
4331
+ }
4332
+ const next = onsets[i + 1];
4333
+ const ioi = next !== void 0 ? next.beat - onset.beat : onset.end - onset.beat;
4334
+ const bin = ioiBinIndex(ioi);
4335
+ interOnsetShares[bin] = (_nullishCoalesce(interOnsetShares[bin], () => ( 0))) + 1;
4336
+ }
4337
+ for (let i = 0; i < interOnsetShares.length; i += 1) {
4338
+ interOnsetShares[i] = (_nullishCoalesce(interOnsetShares[i], () => ( 0))) / onsets.length;
4339
+ }
4340
+ const restRatio = restRatioOf(sounding, startBeat, endBeat);
4341
+ const syncopation = syncopationOf(snapped, startBeat, endBeat, meters);
4342
+ const offGridRatio = offGridCount / onsets.length;
4343
+ return {
4344
+ startBeat,
4345
+ endBeat,
4346
+ bars,
4347
+ onsets: onsets.length,
4348
+ onsetDensity,
4349
+ barOnsets,
4350
+ onsetLevels,
4351
+ barPositions: profiles,
4352
+ interOnsetShares,
4353
+ restRatio,
4354
+ syncopation,
4355
+ offGridRatio,
4356
+ rationale: `${onsets.length} onsets over ${bars.toFixed(2)} bars (${onsetDensity.toFixed(2)} per bar), ${Math.round(restRatio * 100)}% rest, syncopation ${syncopation.toFixed(2)}`
4357
+ };
4358
+ }
4359
+
4360
+ // src/analyze/reference/types.ts
4361
+ var REFERENCE_PROFILE_VERSION = 1;
4362
+
4363
+ // src/analyze/reference/validate.ts
4364
+ var MASS_TOLERANCE = 1e-9;
4365
+ function assertString(value, name) {
4366
+ if (typeof value !== "string") {
4367
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be a string; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, value)}`);
4368
+ }
4369
+ return value;
4370
+ }
4371
+ function assertSpanOrder(startBeat, endBeat, name) {
4372
+ if (endBeat < startBeat) {
4373
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4374
+ `${name}.endBeat must be at least ${name}.startBeat; received ${endBeat} < ${startBeat}`
4375
+ );
4376
+ }
4377
+ }
4378
+ function assertNullable(value, name, validate) {
4379
+ if (value === void 0) {
4380
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be present; received undefined`);
4381
+ }
4382
+ return value === null ? null : validate(value, name);
4383
+ }
4384
+ function assertMassDistribution(value, length, name, allowAllZero) {
4385
+ const shares = _chunkS5BKZZGMcjs.assertArray.call(void 0, value, name);
4386
+ if (shares.length !== length) {
4387
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must have length ${length}; received ${shares.length}`);
4388
+ }
4389
+ let sum = 0;
4390
+ for (let index = 0; index < shares.length; index += 1) {
4391
+ const share = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, shares[index], `${name}[${index}]`);
4392
+ if (share < 0) {
4393
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}[${index}] must be at least 0; received ${share}`);
4394
+ }
4395
+ sum += share;
4396
+ }
4397
+ if (allowAllZero && sum === 0) {
4398
+ return shares;
4399
+ }
4400
+ if (Math.abs(sum - 1) > MASS_TOLERANCE) {
4401
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must sum to 1; received ${sum}`);
4402
+ }
4403
+ return shares;
4404
+ }
4405
+ function assertBarPositionProfile(value, name) {
4406
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4407
+ _chunkS5BKZZGMcjs.assertTimeSignature.call(void 0, read.ts, `${name}.ts`);
4408
+ const slotsPerBar = _chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, read.slotsPerBar, `${name}.slotsPerBar`);
4409
+ const onsets = _chunkS5BKZZGMcjs.assertInteger.call(void 0, read.onsets, `${name}.onsets`, 0);
4410
+ assertMassDistribution(read.shares, slotsPerBar, `${name}.shares`, onsets === 0);
4411
+ return read;
4412
+ }
4413
+ function assertRhythmAnalysis(value, name) {
4414
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4415
+ const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
4416
+ const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
4417
+ assertSpanOrder(startBeat, endBeat, name);
4418
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.bars, 0, Number.MAX_SAFE_INTEGER, `${name}.bars`);
4419
+ const onsets = _chunkS5BKZZGMcjs.assertInteger.call(void 0, read.onsets, `${name}.onsets`, 0);
4420
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.onsetDensity, 0, Number.MAX_SAFE_INTEGER, `${name}.onsetDensity`);
4421
+ const barOnsets = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.barOnsets, `${name}.barOnsets`);
4422
+ for (let index = 0; index < barOnsets.length; index += 1) {
4423
+ _chunkS5BKZZGMcjs.assertRange.call(void 0,
4424
+ barOnsets[index],
4425
+ 0,
4426
+ Number.MAX_SAFE_INTEGER,
4427
+ `${name}.barOnsets[${index}]`
4428
+ );
4429
+ }
4430
+ assertMassDistribution(read.onsetLevels, 6, `${name}.onsetLevels`, onsets === 0);
4431
+ const barPositions = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.barPositions, `${name}.barPositions`);
4432
+ for (let index = 0; index < barPositions.length; index += 1) {
4433
+ assertBarPositionProfile(barPositions[index], `${name}.barPositions[${index}]`);
4434
+ }
4435
+ assertMassDistribution(
4436
+ read.interOnsetShares,
4437
+ RHYTHM_IOI_BINS.length,
4438
+ `${name}.interOnsetShares`,
4439
+ onsets === 0
4440
+ );
4441
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.restRatio, 0, 1, `${name}.restRatio`);
4442
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.syncopation, 0, 1, `${name}.syncopation`);
4443
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.offGridRatio, 0, 1, `${name}.offGridRatio`);
4444
+ assertString(read.rationale, `${name}.rationale`);
4445
+ return read;
4446
+ }
4447
+ function assertFormSection(value, name, sectionCount) {
4448
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4449
+ assertString(read.label, `${name}.label`);
4450
+ const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
4451
+ const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
4452
+ assertSpanOrder(startBeat, endBeat, name);
4453
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.bars, 0, Number.MAX_SAFE_INTEGER, `${name}.bars`);
4454
+ _chunkS5BKZZGMcjs.assertInteger.call(void 0, read.firstOccurrence, `${name}.firstOccurrence`, 0, Math.max(sectionCount - 1, 0));
4455
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.similarity, 0, 1, `${name}.similarity`);
4456
+ assertString(read.rationale, `${name}.rationale`);
4457
+ return read;
4458
+ }
4459
+ function assertReferenceCadence(value, name) {
4460
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4461
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.atBeat, `${name}.atBeat`);
4462
+ _chunkS5BKZZGMcjs.assertOneOf.call(void 0, read.type, CADENCE_TYPES, `${name}.type`);
4463
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.weight, 0, 1, `${name}.weight`);
4464
+ return read;
4465
+ }
4466
+ function assertReferencePhraseMelody(value, name) {
4467
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4468
+ _chunkS5BKZZGMcjs.assertOneOf.call(void 0, read.shape, MELODIC_CONTOUR_SHAPES, `${name}.shape`);
4469
+ _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, read.low, `${name}.low`);
4470
+ _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, read.high, `${name}.high`);
4471
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.mean, 0, 127, `${name}.mean`);
4472
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.peakPitch, 0, 127, `${name}.peakPitch`);
4473
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.peakPosition, 0, 1, `${name}.peakPosition`);
4474
+ const outline = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.outline, `${name}.outline`);
4475
+ if (outline.length !== 8) {
4476
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.outline must have length 8; received ${outline.length}`);
4477
+ }
4478
+ for (let index = 0; index < outline.length; index += 1) {
4479
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, outline[index], `${name}.outline[${index}]`);
4480
+ }
4481
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.onsetDensity, 0, Number.MAX_SAFE_INTEGER, `${name}.onsetDensity`);
4482
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.restRatio, 0, 1, `${name}.restRatio`);
4483
+ return read;
4484
+ }
4485
+ function assertReferencePhrase(value, name, sectionCount, nodeCount) {
4486
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4487
+ const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
4488
+ const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
4489
+ assertSpanOrder(startBeat, endBeat, name);
4490
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.bars, 0, Number.MAX_SAFE_INTEGER, `${name}.bars`);
4491
+ assertNullable(
4492
+ read.section,
4493
+ `${name}.section`,
4494
+ (v, n) => _chunkS5BKZZGMcjs.assertInteger.call(void 0, v, n, 0, Math.max(sectionCount - 1, 0))
4495
+ );
4496
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.confidence, 0, 1, `${name}.confidence`);
4497
+ assertNullable(read.cadence, `${name}.cadence`, assertReferenceCadence);
4498
+ assertNullable(read.melody, `${name}.melody`, assertReferencePhraseMelody);
4499
+ const motifNodes = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.motifNodes, `${name}.motifNodes`);
4500
+ for (let index = 0; index < motifNodes.length; index += 1) {
4501
+ _chunkS5BKZZGMcjs.assertInteger.call(void 0,
4502
+ motifNodes[index],
4503
+ `${name}.motifNodes[${index}]`,
4504
+ 0,
4505
+ Math.max(nodeCount - 1, 0)
4506
+ );
4507
+ }
4508
+ return read;
4509
+ }
4510
+ function assertReferenceForm(value, name, nodeCount) {
4511
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4512
+ const hypermeter = _chunkS5BKZZGMcjs.assertRecord.call(void 0,
4513
+ read.hypermeter,
4514
+ `${name}.hypermeter`
4515
+ );
4516
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, hypermeter.groupBars, 0, Number.MAX_SAFE_INTEGER, `${name}.hypermeter.groupBars`);
4517
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, hypermeter.confidence, 0, 1, `${name}.hypermeter.confidence`);
4518
+ const sections = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.sections, `${name}.sections`);
4519
+ for (let index = 0; index < sections.length; index += 1) {
4520
+ assertFormSection(sections[index], `${name}.sections[${index}]`, sections.length);
4521
+ }
4522
+ const phrases = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.phrases, `${name}.phrases`);
4523
+ for (let index = 0; index < phrases.length; index += 1) {
4524
+ assertReferencePhrase(phrases[index], `${name}.phrases[${index}]`, sections.length, nodeCount);
4525
+ }
4526
+ return read;
4527
+ }
4528
+ function assertResolvedKeyField(value, name) {
4529
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4530
+ try {
4531
+ _chunk3R3QVKY5cjs.resolveKey.call(void 0, read);
4532
+ } catch (error) {
4533
+ if (error instanceof _chunkS5BKZZGMcjs.InvalidInputError) {
4534
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be a valid key: ${error.message}`);
4535
+ }
4536
+ throw error;
4537
+ }
4538
+ return read;
4539
+ }
4540
+ function assertReferenceKeyRegion(value, name) {
4541
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4542
+ const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
4543
+ const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
4544
+ assertSpanOrder(startBeat, endBeat, name);
4545
+ assertResolvedKeyField(read.key, `${name}.key`);
4546
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.confidence, 0, 1, `${name}.confidence`);
4547
+ return read;
4548
+ }
4549
+ function assertReferenceChord(value, name, keys) {
4550
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4551
+ const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
4552
+ const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
4553
+ assertSpanOrder(startBeat, endBeat, name);
4554
+ const keyIndex = _chunkS5BKZZGMcjs.assertInteger.call(void 0, read.key, `${name}.key`, 0, Math.max(keys.length - 1, 0));
4555
+ const roman = assertString(read.roman, `${name}.roman`);
4556
+ try {
4557
+ romanToChord(roman, keys[keyIndex]);
4558
+ } catch (error) {
4559
+ if (error instanceof _chunkS5BKZZGMcjs.InvalidInputError) {
4560
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4561
+ `${name}.roman must be readable by romanToChord; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, roman)}: ${error.message}`
4562
+ );
4563
+ }
4564
+ throw error;
4565
+ }
4566
+ _chunkS5BKZZGMcjs.assertOneOf.call(void 0, read.function, HARMONIC_FUNCTIONS, `${name}.function`);
4567
+ _chunkS5BKZZGMcjs.assertOneOf.call(void 0, read.level, REDUCTION_LEVELS, `${name}.level`);
4568
+ return read;
4569
+ }
4570
+ function assertReferenceHarmony(value, name) {
4571
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4572
+ const keys = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.keys, `${name}.keys`);
4573
+ for (let index = 0; index < keys.length; index += 1) {
4574
+ assertReferenceKeyRegion(keys[index], `${name}.keys[${index}]`);
4575
+ }
4576
+ const resolvedKeys = keys.map((region) => region.key);
4577
+ const chords = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.chords, `${name}.chords`);
4578
+ for (let index = 0; index < chords.length; index += 1) {
4579
+ assertReferenceChord(chords[index], `${name}.chords[${index}]`, resolvedKeys);
4580
+ }
4581
+ assertRhythmAnalysis(read.rhythm, `${name}.rhythm`);
4582
+ return read;
4583
+ }
4584
+ function assertMotifRelationSummary(value, name) {
4585
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4586
+ _chunkS5BKZZGMcjs.assertOneOf.call(void 0, read.kind, MOTIF_RELATION_KINDS, `${name}.kind`);
4587
+ _chunkS5BKZZGMcjs.assertFlag.call(void 0, read.sequence, `${name}.sequence`);
4588
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.semitones, `${name}.semitones`);
4589
+ if (read.degrees !== void 0) {
4590
+ _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.degrees, `${name}.degrees`);
4591
+ }
4592
+ const timeRatio = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.timeRatio, `${name}.timeRatio`);
4593
+ if (timeRatio <= 0) {
4594
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.timeRatio must be positive; received ${timeRatio}`);
4595
+ }
4596
+ return read;
4597
+ }
4598
+ function assertMotifGraphNode(value, name, occurrenceCounts) {
4599
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4600
+ const motif = _chunkS5BKZZGMcjs.assertInteger.call(void 0,
4601
+ read.motif,
4602
+ `${name}.motif`,
4603
+ 0,
4604
+ Math.max(occurrenceCounts.length - 1, 0)
4605
+ );
4606
+ _chunkS5BKZZGMcjs.assertInteger.call(void 0,
4607
+ read.occurrence,
4608
+ `${name}.occurrence`,
4609
+ 0,
4610
+ Math.max((_nullishCoalesce(occurrenceCounts[motif], () => ( 1))) - 1, 0)
4611
+ );
4612
+ const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
4613
+ const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
4614
+ assertSpanOrder(startBeat, endBeat, name);
4615
+ return read;
4616
+ }
4617
+ function assertMotifGraphEdge(value, name, nodeCount) {
4618
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4619
+ const from = _chunkS5BKZZGMcjs.assertInteger.call(void 0, read.from, `${name}.from`, 0, Math.max(nodeCount - 1, 0));
4620
+ const to = _chunkS5BKZZGMcjs.assertInteger.call(void 0, read.to, `${name}.to`, 0, Math.max(nodeCount - 1, 0));
4621
+ if (from >= to) {
4622
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4623
+ `${name}.from must be less than ${name}.to; received from=${from}, to=${to}`
4624
+ );
4625
+ }
4626
+ assertNullable(read.relation, `${name}.relation`, assertMotifRelationSummary);
4627
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.similarity, 0, 1, `${name}.similarity`);
4628
+ return read;
4629
+ }
4630
+ function assertMotifGraph(value, name, occurrenceCounts) {
4631
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4632
+ const nodes = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.nodes, `${name}.nodes`);
4633
+ for (let index = 0; index < nodes.length; index += 1) {
4634
+ assertMotifGraphNode(nodes[index], `${name}.nodes[${index}]`, occurrenceCounts);
4635
+ }
4636
+ const edges = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.edges, `${name}.edges`);
4637
+ const seenTo = /* @__PURE__ */ new Set();
4638
+ for (let index = 0; index < edges.length; index += 1) {
4639
+ const edge = assertMotifGraphEdge(edges[index], `${name}.edges[${index}]`, nodes.length);
4640
+ if (seenTo.has(edge.to)) {
4641
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.edges: node ${edge.to} has more than one incoming edge`);
4642
+ }
4643
+ seenTo.add(edge.to);
4644
+ }
4645
+ return read;
4646
+ }
4647
+ function assertReferenceMotif(value, name) {
4648
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4649
+ const intervals = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.intervals, `${name}.intervals`);
4650
+ let pitch = 0;
4651
+ let low = 0;
4652
+ let high = 0;
4653
+ for (let index = 0; index < intervals.length; index += 1) {
4654
+ const interval = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, intervals[index], `${name}.intervals[${index}]`);
4655
+ if (!Number.isInteger(interval)) {
4656
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4657
+ `${name}.intervals[${index}] must be a whole number of semitones; received ${interval}`
4658
+ );
4659
+ }
4660
+ pitch += interval;
4661
+ low = Math.min(low, pitch);
4662
+ high = Math.max(high, pitch);
4663
+ }
4664
+ if (high - low > 127) {
4665
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4666
+ `${name}.intervals must span at most 127 semitones; received ${high - low}`
4667
+ );
4668
+ }
4669
+ const rhythm = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.rhythm, `${name}.rhythm`);
4670
+ if (rhythm.length !== intervals.length) {
4671
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4672
+ `${name}.rhythm must hold one ratio per interval (${intervals.length}); received ${rhythm.length}`
4673
+ );
4674
+ }
4675
+ for (let index = 0; index < rhythm.length; index += 1) {
4676
+ const ratio2 = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, rhythm[index], `${name}.rhythm[${index}]`);
4677
+ if (!(ratio2 > 0)) {
4678
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.rhythm[${index}] must be positive; received ${ratio2}`);
4679
+ }
4680
+ }
4681
+ const unitBeats = _chunkS5BKZZGMcjs.assertRange.call(void 0, read.unitBeats, 0, Number.MAX_SAFE_INTEGER, `${name}.unitBeats`);
4682
+ if (unitBeats > 0 !== rhythm.length > 0) {
4683
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4684
+ `${name}.unitBeats must be positive exactly when rhythm is non-empty; received ${unitBeats} with ${rhythm.length} ratio(s)`
4685
+ );
4686
+ }
4687
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, read.spanBeats, 0, Number.MAX_SAFE_INTEGER, `${name}.spanBeats`);
4688
+ _chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, read.occurrences, `${name}.occurrences`);
4689
+ return read;
4690
+ }
4691
+ function assertReferenceMelody(value, name) {
4692
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4693
+ assertNullable(read.register, `${name}.register`, (v, n) => {
4694
+ const register = _chunkS5BKZZGMcjs.assertRecord.call(void 0, v, n);
4695
+ _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, register.low, `${n}.low`);
4696
+ _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, register.high, `${n}.high`);
4697
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, register.mean, 0, 127, `${n}.mean`);
4698
+ return register;
4699
+ });
4700
+ assertNullable(read.shape, `${name}.shape`, (v, n) => _chunkS5BKZZGMcjs.assertOneOf.call(void 0, v, MELODIC_CONTOUR_SHAPES, n));
4701
+ const motifs = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.motifs, `${name}.motifs`);
4702
+ const occurrenceCounts = [];
4703
+ for (let index = 0; index < motifs.length; index += 1) {
4704
+ assertReferenceMotif(motifs[index], `${name}.motifs[${index}]`);
4705
+ occurrenceCounts.push(motifs[index].occurrences);
4706
+ }
4707
+ assertMotifGraph(read.graph, `${name}.graph`, occurrenceCounts);
4708
+ assertRhythmAnalysis(read.rhythm, `${name}.rhythm`);
4709
+ return read;
4710
+ }
4711
+ function assertReferenceProfile(value, name = "reference profile") {
4712
+ const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
4713
+ if (read.profileVersion !== REFERENCE_PROFILE_VERSION) {
4714
+ throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
4715
+ `${name}.profileVersion must be ${REFERENCE_PROFILE_VERSION}; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, read.profileVersion)}`
4716
+ );
4717
+ }
4718
+ const span = _chunkS5BKZZGMcjs.assertRecord.call(void 0,
4719
+ read.span,
4720
+ `${name}.span`
4721
+ );
4722
+ const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, span.startBeat, `${name}.span.startBeat`);
4723
+ const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, span.endBeat, `${name}.span.endBeat`);
4724
+ assertSpanOrder(startBeat, endBeat, `${name}.span`);
4725
+ _chunkS5BKZZGMcjs.assertRange.call(void 0, span.bars, 0, Number.MAX_SAFE_INTEGER, `${name}.span.bars`);
4726
+ _chunkS5BKZZGMcjs.assertMeterMap.call(void 0, read.meters, `${name}.meters`);
4727
+ const melody = assertReferenceMelody(read.melody, `${name}.melody`);
4728
+ assertReferenceForm(read.form, `${name}.form`, melody.graph.nodes.length);
4729
+ assertReferenceHarmony(read.harmony, `${name}.harmony`);
4730
+ return read;
4731
+ }
4732
+
4733
+ // src/analyze/reference/measures.ts
4734
+ var PROGRESSION_GAP = 0.75;
4735
+ var SAME_DEGREE_COST = 0.25;
4736
+ var SAME_FUNCTION_COST = 0.5;
4737
+ var HALF_PHRYGIAN_COST = 0.5;
4738
+ var MODE_CHANGE_COST = 0.5;
4739
+ var SHAPE_MISMATCH_COST = 0.25;
4740
+ var REGISTER_SPAN = 24;
4741
+ var PEAK_POSITION_WEIGHT = 0.5;
4742
+ var FAMILY_SIZE_BINS = 5;
4743
+ var DEPTH_BINS = 4;
4744
+ var NAMED_CHORDS = ["Ger", "It", "Fr", "N"];
4745
+ var PITCH_PRESERVING = /* @__PURE__ */ new Set([
4746
+ "repetition",
4747
+ "augmentation",
4748
+ "diminution"
4749
+ ]);
4750
+ var CELL_START_PITCH = 60;
4751
+ function whenBoth(hasA, hasB, measure) {
4752
+ if (!hasA && !hasB) {
4753
+ return null;
4754
+ }
4755
+ if (!hasA || !hasB) {
4756
+ return 0;
4757
+ }
4758
+ return measure();
4759
+ }
4760
+ function aligned(a, b, cost, gap = 1) {
4761
+ return distanceToSimilarity(gradedEditDistance(a, b, cost, gap), a.length, b.length);
4762
+ }
4763
+ function alignedSimilarity(a, b, cost, gap = 1) {
4764
+ return whenBoth(a.length > 0, b.length > 0, () => aligned(a, b, cost, gap));
4765
+ }
4766
+ function massOf(values) {
4767
+ let total = 0;
4768
+ for (const value of values) {
4769
+ total += value;
4770
+ }
4771
+ return total;
4772
+ }
4773
+ function intersection(a, b) {
4774
+ const massA = massOf(a);
4775
+ const massB = massOf(b);
4776
+ let shared2 = 0;
4777
+ for (let i = 0; i < a.length; i += 1) {
4778
+ shared2 += Math.min((_nullishCoalesce(a[i], () => ( 0))) / massA, (_nullishCoalesce(b[i], () => ( 0))) / massB);
4779
+ }
4780
+ return Math.min(1, shared2);
4781
+ }
4782
+ function distributionSimilarity(a, b) {
4783
+ return whenBoth(massOf(a) > 0, massOf(b) > 0, () => intersection(a, b));
4784
+ }
4785
+ function ratio(a, b) {
4786
+ const larger = Math.max(a, b);
4787
+ return larger === 0 ? 1 : Math.min(a, b) / larger;
4788
+ }
4789
+ function sectionSequenceSimilarity(a, b) {
4790
+ return alignedSimilarity(a, b, (x, y) => x === y ? 0 : 1);
4791
+ }
4792
+ function phraseLengthSimilarity(a, b) {
4793
+ return alignedSimilarity(a, b, (x, y) => {
4794
+ const longer = Math.max(x, y);
4795
+ return longer === 0 ? 0 : Math.min(Math.abs(x - y) / longer, 1);
4796
+ });
4797
+ }
4798
+ function simpleDegreeToken(roman) {
4799
+ for (const name of NAMED_CHORDS) {
4800
+ if (roman.startsWith(name)) {
4801
+ return name;
4802
+ }
4803
+ }
4804
+ const match = roman.match(/^([b#]*)([IV]+)/i);
4805
+ return match ? `${match[1]}${match[2].toUpperCase()}` : roman;
4806
+ }
4807
+ function romanDegreeToken(roman) {
4808
+ const slash = roman.indexOf("/");
4809
+ if (slash < 0) {
4810
+ return simpleDegreeToken(roman);
4811
+ }
4812
+ return `${simpleDegreeToken(roman.slice(0, slash))}/${simpleDegreeToken(roman.slice(slash + 1))}`;
4813
+ }
4814
+ function chordCost(x, y) {
4815
+ if (x.roman === y.roman) {
4816
+ return 0;
4817
+ }
4818
+ if (romanDegreeToken(x.roman) === romanDegreeToken(y.roman)) {
4819
+ return SAME_DEGREE_COST;
4820
+ }
4821
+ return x.function === y.function ? SAME_FUNCTION_COST : 1;
4822
+ }
4823
+ function progressionSimilarity(a, b, budget) {
4824
+ _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, a.length * b.length, "reference progression alignment", budget);
4825
+ return alignedSimilarity(a, b, chordCost, PROGRESSION_GAP);
4826
+ }
4827
+ function functionMass(chords) {
4828
+ const mass = HARMONIC_FUNCTIONS.map(() => 0);
4829
+ for (const chord of chords) {
4830
+ const bin = HARMONIC_FUNCTIONS.indexOf(chord.function);
4831
+ mass[bin] = (_nullishCoalesce(mass[bin], () => ( 0))) + Math.max(0, chord.endBeat - chord.startBeat);
4832
+ }
4833
+ return mass;
4834
+ }
4835
+ function functionSimilarity(a, b) {
4836
+ return distributionSimilarity(functionMass(a), functionMass(b));
4837
+ }
4838
+ function cadenceSimilarity(a, b) {
4839
+ return alignedSimilarity(a, b, (x, y) => {
4840
+ if (x === y) {
4841
+ return 0;
4842
+ }
4843
+ const halfAndPhrygian = x === "half" && y === "phrygian" || x === "phrygian" && y === "half";
4844
+ return halfAndPhrygian ? HALF_PHRYGIAN_COST : 1;
4845
+ });
4846
+ }
4847
+ function keyTokens(keys) {
4848
+ const home = _nullishCoalesce(_optionalChain([keys, 'access', _115 => _115[0], 'optionalAccess', _116 => _116.scale, 'access', _117 => _117.rootPc]), () => ( 0));
4849
+ return keys.map((key) => ({
4850
+ distance: ((key.scale.rootPc - home) % 12 + 12) % 12,
4851
+ mask: key.scale.modeMask12
4852
+ }));
4853
+ }
4854
+ function keyPlanSimilarity(a, b) {
4855
+ return alignedSimilarity(keyTokens(a), keyTokens(b), (x, y) => {
4856
+ if (x.distance !== y.distance) {
4857
+ return 1;
4858
+ }
4859
+ return x.mask === y.mask ? 0 : MODE_CHANGE_COST;
4860
+ });
4861
+ }
4862
+ function onsetSimilarity(a, b) {
4863
+ return whenBoth(a.onsets > 0, b.onsets > 0, () => {
4864
+ let weighted = 0;
4865
+ let weight = 0;
4866
+ for (const left of a.barPositions) {
4867
+ for (const right of b.barPositions) {
4868
+ const shared2 = left.ts.numerator === right.ts.numerator && left.ts.denominator === right.ts.denominator && left.onsets > 0 && right.onsets > 0;
4869
+ if (shared2) {
4870
+ const w = left.onsets + right.onsets;
4871
+ weighted += w * intersection(left.shares, right.shares);
4872
+ weight += w;
4873
+ }
4874
+ }
4875
+ }
4876
+ return weight > 0 ? weighted / weight : intersection(a.onsetLevels, b.onsetLevels);
4877
+ });
4878
+ }
4879
+ function densitySimilarity(a, b) {
4880
+ return whenBoth(a.onsets > 0, b.onsets > 0, () => ratio(a.onsetDensity, b.onsetDensity));
4881
+ }
4882
+ function durationSimilarity(a, b) {
4883
+ return whenBoth(
4884
+ a.onsets > 0,
4885
+ b.onsets > 0,
4886
+ () => intersection(a.interOnsetShares, b.interOnsetShares)
4887
+ );
4888
+ }
4889
+ function syncopationSimilarity(a, b) {
4890
+ return whenBoth(a.onsets > 0, b.onsets > 0, () => 1 - Math.abs(a.syncopation - b.syncopation));
4891
+ }
4892
+ function cellNotes(motif) {
4893
+ const notes = [];
4894
+ let low = 0;
4895
+ let high = 0;
4896
+ let offset = 0;
4897
+ for (const interval of motif.intervals) {
4898
+ offset += interval;
4899
+ low = Math.min(low, offset);
4900
+ high = Math.max(high, offset);
4901
+ }
4902
+ let pitch = Math.min(127 - high, Math.max(-low, CELL_START_PITCH));
4903
+ let beat = 0;
4904
+ for (let i = 0; i <= motif.intervals.length; i += 1) {
4905
+ const step = _nullishCoalesce(motif.rhythm[i], () => ( 1));
4906
+ notes.push({ pitch, startBeat: beat, durationBeat: i < motif.intervals.length ? step : 1 });
4907
+ pitch += _nullishCoalesce(motif.intervals[i], () => ( 0));
4908
+ beat += step;
4909
+ }
4910
+ return notes;
4911
+ }
4912
+ function bestMatchMean(from, to) {
4913
+ let weighted = 0;
4914
+ let weight = 0;
4915
+ for (const motif of from) {
4916
+ let best = 0;
4917
+ for (const other of to) {
4918
+ best = Math.max(best, compareMelodies(motif.cell, other.cell).pitchSimilarity);
4919
+ }
4920
+ weighted += motif.occurrences * best;
4921
+ weight += motif.occurrences;
4922
+ }
4923
+ return weighted / weight;
4924
+ }
4925
+ function surfaceSimilarity(a, b) {
4926
+ return whenBoth(a.length > 0, b.length > 0, () => {
4927
+ const left = a.map((motif) => ({ cell: cellNotes(motif), occurrences: motif.occurrences }));
4928
+ const right = b.map((motif) => ({ cell: cellNotes(motif), occurrences: motif.occurrences }));
4929
+ return (bestMatchMean(left, right) + bestMatchMean(right, left)) / 2;
4930
+ });
4931
+ }
4932
+ function coverageOf(graph, spanBeats) {
4933
+ if (!(spanBeats > 0) || graph.nodes.length === 0) {
4934
+ return 0;
4935
+ }
4936
+ const spans = graph.nodes.map((node) => [node.startBeat, node.endBeat]).sort((x, y) => x[0] - y[0] || x[1] - y[1]);
4937
+ let covered = 0;
4938
+ let [runStart, runEnd] = spans[0];
4939
+ for (const [start, end] of spans) {
4940
+ if (start > runEnd) {
4941
+ covered += runEnd - runStart;
4942
+ runStart = start;
4943
+ runEnd = end;
4944
+ } else {
4945
+ runEnd = Math.max(runEnd, end);
4946
+ }
4947
+ }
4948
+ covered += runEnd - runStart;
4949
+ return Math.min(1, covered / spanBeats);
4950
+ }
4951
+ function bump(histogram, bin) {
4952
+ histogram[bin] = (_nullishCoalesce(histogram[bin], () => ( 0))) + 1;
4953
+ }
4954
+ function summarise({ graph, spanBeats }) {
4955
+ const kinds = new Array(MOTIF_RELATION_KINDS.length + 1).fill(0);
4956
+ const parentEdge = /* @__PURE__ */ new Map();
4957
+ for (const edge of graph.edges) {
4958
+ const kind = _optionalChain([edge, 'access', _118 => _118.relation, 'optionalAccess', _119 => _119.kind]);
4959
+ bump(
4960
+ kinds,
4961
+ kind === void 0 ? MOTIF_RELATION_KINDS.length : MOTIF_RELATION_KINDS.indexOf(kind)
4962
+ );
4963
+ parentEdge.set(edge.to, edge);
4964
+ }
4965
+ const depth = new Array(graph.nodes.length).fill(0);
4966
+ const root = graph.nodes.map((_, i) => i);
4967
+ for (let node = 0; node < graph.nodes.length; node += 1) {
4968
+ const edge = parentEdge.get(node);
4969
+ if (edge !== void 0) {
4970
+ const kind = _optionalChain([edge, 'access', _120 => _120.relation, 'optionalAccess', _121 => _121.kind]);
4971
+ const keepsPitch = kind !== void 0 && PITCH_PRESERVING.has(kind);
4972
+ depth[node] = (_nullishCoalesce(depth[edge.from], () => ( 0))) + (keepsPitch ? 0 : 1);
4973
+ root[node] = _nullishCoalesce(root[edge.from], () => ( edge.from));
4974
+ }
4975
+ }
4976
+ const familySize = /* @__PURE__ */ new Map();
4977
+ for (const r of root) {
4978
+ familySize.set(r, (_nullishCoalesce(familySize.get(r), () => ( 0))) + 1);
4979
+ }
4980
+ const families = new Array(FAMILY_SIZE_BINS).fill(0);
4981
+ for (const size of familySize.values()) {
4982
+ bump(families, Math.min(size, FAMILY_SIZE_BINS) - 1);
4983
+ }
4984
+ const depths = new Array(DEPTH_BINS).fill(0);
4985
+ for (const d of depth) {
4986
+ bump(depths, Math.min(d, DEPTH_BINS - 1));
4987
+ }
4988
+ return { kinds, families, depths, coverage: coverageOf(graph, spanBeats) };
4989
+ }
4990
+ function motifStructureSimilarity(a, b) {
4991
+ const left = summarise(a);
4992
+ const right = summarise(b);
4993
+ const terms = [
4994
+ distributionSimilarity(left.kinds, right.kinds),
4995
+ distributionSimilarity(left.families, right.families),
4996
+ distributionSimilarity(left.depths, right.depths),
4997
+ whenBoth(
4998
+ left.coverage > 0,
4999
+ right.coverage > 0,
5000
+ () => 1 - Math.abs(left.coverage - right.coverage)
5001
+ )
5002
+ ].filter((term) => term !== null);
5003
+ return terms.length === 0 ? null : massOf(terms) / terms.length;
5004
+ }
5005
+ function nullableCost(cost) {
5006
+ return (x, y) => {
5007
+ if (x === null || y === null) {
5008
+ return x === y ? 0 : 1;
5009
+ }
5010
+ return cost(x, y);
5011
+ };
5012
+ }
5013
+ function phraseSimilarity(a, b, cost) {
5014
+ const hasA = a.some((phrase) => phrase !== null);
5015
+ const hasB = b.some((phrase) => phrase !== null);
5016
+ return whenBoth(hasA, hasB, () => aligned(a, b, nullableCost(cost)));
5017
+ }
5018
+ function normalisedOutline(phrase) {
5019
+ const mean = massOf(phrase.outline) / (phrase.outline.length || 1);
5020
+ const range = phrase.high - phrase.low || 1;
5021
+ return phrase.outline.map((point) => (point - mean) / range);
5022
+ }
5023
+ function contourCost(x, y) {
5024
+ const left = normalisedOutline(x);
5025
+ const right = normalisedOutline(y);
5026
+ let difference = 0;
5027
+ for (let i = 0; i < left.length; i += 1) {
5028
+ difference += Math.abs((_nullishCoalesce(left[i], () => ( 0))) - (_nullishCoalesce(right[i], () => ( 0))));
5029
+ }
5030
+ const outlineCost = Math.min(1, difference / (left.length || 1));
5031
+ return Math.min(1, outlineCost + (x.shape === y.shape ? 0 : SHAPE_MISMATCH_COST));
5032
+ }
5033
+ function contourSimilarity(a, b) {
5034
+ return phraseSimilarity(a, b, contourCost);
5035
+ }
5036
+ function registerSimilarity(a, b) {
5037
+ const meanA = _nullishCoalesce(a.mean, () => ( 0));
5038
+ const meanB = _nullishCoalesce(b.mean, () => ( 0));
5039
+ return phraseSimilarity(a.phrases, b.phrases, (x, y) => {
5040
+ const offset = Math.abs(x.mean - meanA - (y.mean - meanB));
5041
+ const range = Math.abs(x.high - x.low - (y.high - y.low));
5042
+ const peak = Math.abs(x.peakPosition - y.peakPosition);
5043
+ return Math.min(1, (offset + range) / REGISTER_SPAN + PEAK_POSITION_WEIGHT * peak);
5044
+ });
5045
+ }
5046
+
5047
+ // src/analyze/reference/internal.ts
5048
+ function weightedMean(notes) {
5049
+ let weighted = 0;
5050
+ let total = 0;
5051
+ for (const note of notes) {
5052
+ weighted += note.pitch * note.durationBeat;
5053
+ total += note.durationBeat;
5054
+ }
5055
+ return total > 0 ? weighted / total : 0;
5056
+ }
5057
+ function phraseMelody(line, startBeat, endBeat, lineMean, meters, budget) {
5058
+ const inside = line.filter((note) => note.startBeat >= startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && note.startBeat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS).map((note) => ({
5059
+ ...note,
5060
+ durationBeat: Math.min(note.startBeat + note.durationBeat, endBeat) - note.startBeat
5061
+ }));
5062
+ const first = inside[0];
5063
+ if (first === void 0 || inside.length < 2) {
5064
+ return null;
5065
+ }
5066
+ let low = first.pitch;
5067
+ let peak = first;
5068
+ for (const note of inside) {
5069
+ low = Math.min(low, note.pitch);
5070
+ if (note.pitch > peak.pitch) {
5071
+ peak = note;
5072
+ }
5073
+ }
5074
+ const length = endBeat - startBeat;
5075
+ const outline = [];
5076
+ for (let k = 0; k < 8; k += 1) {
5077
+ const at = startBeat + (k + 0.5) * length / 8;
5078
+ let held = first;
5079
+ for (const note of inside) {
5080
+ if (note.startBeat > at + _chunkS5BKZZGMcjs.BEAT_EPS) {
5081
+ break;
5082
+ }
5083
+ held = note;
5084
+ }
5085
+ outline.push(held.pitch - lineMean);
5086
+ }
5087
+ const rhythm = analyzeRhythm(inside, { meters, totalBeats: endBeat, budget });
5088
+ return {
5089
+ shape: melodicContour(inside).shape,
5090
+ low,
5091
+ high: peak.pitch,
5092
+ mean: weightedMean(inside),
5093
+ peakPitch: peak.pitch,
5094
+ peakPosition: Math.min(1, Math.max(0, (peak.startBeat - startBeat) / length)),
5095
+ outline,
5096
+ onsetDensity: rhythm.onsetDensity,
5097
+ restRatio: rhythm.restRatio
5098
+ };
5099
+ }
5100
+
5101
+
5102
+
5103
+
5104
+
5105
+
5106
+
5107
+
5108
+
5109
+
5110
+
5111
+
5112
+
5113
+
5114
+
5115
+
5116
+
5117
+
5118
+
5119
+
5120
+
5121
+
5122
+
5123
+
5124
+
5125
+
5126
+
5127
+
5128
+
5129
+
5130
+
5131
+
5132
+
5133
+
5134
+
5135
+
3270
5136
 
3271
5137
 
3272
5138
 
@@ -3325,5 +5191,5 @@ function detectCadences(timeline, key) {
3325
5191
 
3326
5192
 
3327
5193
 
3328
- exports.HUMANIZE_ADJACENCY = HUMANIZE_ADJACENCY; exports.sameInstant = sameInstant; exports.adjacent = adjacent; exports.hasEnded = hasEnded; exports.windowWeights = windowWeights; exports.MODAL_SCALE_NAMES = MODAL_SCALE_NAMES; exports.detectChord = detectChord; exports.detectChordBest = detectChordBest; exports.detectKey = detectKey; exports.detectKeyFromNotes = detectKeyFromNotes; exports.detectKeyBest = detectKeyBest; exports.augmentedSixthChord = augmentedSixthChord; exports.augmentedSixthKind = augmentedSixthKind; exports.augmentedSixthFromPitchClasses = augmentedSixthFromPitchClasses; exports.spellAugmentedSixth = spellAugmentedSixth; exports.isCadentialSixFour = isCadentialSixFour; exports.detectCadence = detectCadence; exports.isBorrowedChord = isBorrowedChord; exports.borrowedSource = borrowedSource; exports.isAppliedDominant = isAppliedDominant; exports.romanToChord = romanToChord; exports.chordToRoman = chordToRoman; exports.explainRoman = explainRoman; exports.isMinorKey = isMinorKey; exports.functionOf = functionOf; exports.isDiatonic = isDiatonic; exports.parallelKey = parallelKey; exports.analyzeChord = analyzeChord; exports.secondaryDominant = secondaryDominant; exports.secondaryDominantOf = secondaryDominantOf; exports.pivotChords = pivotChords; exports.clamp01 = clamp01; exports.floorMod = floorMod; exports.firstSoundingBeat = firstSoundingBeat; exports.lastBarOf = lastBarOf; exports.sliceBars = sliceBars; exports.weightSimilarity = weightSimilarity; exports.harmonicNovelty = harmonicNovelty; exports.combineEvidence = combineEvidence; exports.gridForNotes = gridForNotes; exports.barGridStart = barGridStart; exports.keyTimelineFromNotes = keyTimelineFromNotes; exports.detectModulations = detectModulations; exports.attachPivots = attachPivots; exports.keyLookup = keyLookup; exports.prevailingKeyOf = prevailingKeyOf; exports.keyScaleAt = keyScaleAt; exports.toVoiceNotes = toVoiceNotes; exports.analyzeVoice = analyzeVoice; exports.assertChordTimeline = assertChordTimeline; exports.chordTimelineFromChords = chordTimelineFromChords; exports.chordAtBeat = chordAtBeat; exports.segmentStartingAt = segmentStartingAt; exports.chordTimelineFromNotes = chordTimelineFromNotes; exports.dirtySlotsFor = dirtySlotsFor; exports.analyzeTimeline = analyzeTimeline; exports.detectCadences = detectCadences;
3329
- //# sourceMappingURL=chunk-Q6R3QAZD.cjs.map
5194
+ exports.HUMANIZE_ADJACENCY = HUMANIZE_ADJACENCY; exports.sameInstant = sameInstant; exports.adjacent = adjacent; exports.hasEnded = hasEnded; exports.windowWeights = windowWeights; exports.MODAL_SCALE_NAMES = MODAL_SCALE_NAMES; exports.detectChord = detectChord; exports.detectChordBest = detectChordBest; exports.detectKey = detectKey; exports.detectKeyFromNotes = detectKeyFromNotes; exports.detectKeyBest = detectKeyBest; exports.augmentedSixthChord = augmentedSixthChord; exports.augmentedSixthKind = augmentedSixthKind; exports.augmentedSixthFromPitchClasses = augmentedSixthFromPitchClasses; exports.spellAugmentedSixth = spellAugmentedSixth; exports.CADENCE_TYPES = CADENCE_TYPES; exports.detectCadence = detectCadence; exports.isBorrowedChord = isBorrowedChord; exports.borrowedSource = borrowedSource; exports.romanToChord = romanToChord; exports.chordToRoman = chordToRoman; exports.explainRoman = explainRoman; exports.HARMONIC_FUNCTIONS = HARMONIC_FUNCTIONS; exports.isMinorKey = isMinorKey; exports.functionOf = functionOf; exports.isDiatonic = isDiatonic; exports.parallelKey = parallelKey; exports.analyzeChord = analyzeChord; exports.secondaryDominant = secondaryDominant; exports.secondaryDominantOf = secondaryDominantOf; exports.pivotChords = pivotChords; exports.barSpanOf = barSpanOf; exports.clamp01 = clamp01; exports.floorMod = floorMod; exports.firstSoundingBeat = firstSoundingBeat; exports.lastBarOf = lastBarOf; exports.sliceBars = sliceBars; exports.weightSimilarity = weightSimilarity; exports.harmonicNovelty = harmonicNovelty; exports.combineEvidence = combineEvidence; exports.gridForNotes = gridForNotes; exports.barGridStart = barGridStart; exports.keyTimelineFromNotes = keyTimelineFromNotes; exports.detectModulations = detectModulations; exports.attachPivots = attachPivots; exports.keyLookup = keyLookup; exports.prevailingKeyOf = prevailingKeyOf; exports.toVoiceNotes = toVoiceNotes; exports.analyzeVoice = analyzeVoice; exports.assertChordTimeline = assertChordTimeline; exports.chordTimelineFromChords = chordTimelineFromChords; exports.chordAtBeat = chordAtBeat; exports.segmentStartingAt = segmentStartingAt; exports.chordTimelineFromNotes = chordTimelineFromNotes; exports.dirtySlotsFor = dirtySlotsFor; exports.analyzeTimeline = analyzeTimeline; exports.detectCadences = detectCadences; exports.orderedNotes = orderedNotes; exports.MELODIC_CONTOUR_SHAPES = MELODIC_CONTOUR_SHAPES; exports.melodicContour = melodicContour; exports.extractMotifs = extractMotifs; exports.motifFromNotes = motifFromNotes; exports.MOTIF_RELATION_KINDS = MOTIF_RELATION_KINDS; exports.relateMotifs = relateMotifs; exports.compareMelodies = compareMelodies; exports.melodicSimilarity = melodicSimilarity; exports.DEFAULT_VARIATION_THRESHOLD = DEFAULT_VARIATION_THRESHOLD; exports.motifGraph = motifGraph; exports.REDUCTION_LEVELS = REDUCTION_LEVELS; exports.reduceProgression = reduceProgression; exports.sectionSequenceSimilarity = sectionSequenceSimilarity; exports.phraseLengthSimilarity = phraseLengthSimilarity; exports.progressionSimilarity = progressionSimilarity; exports.functionSimilarity = functionSimilarity; exports.cadenceSimilarity = cadenceSimilarity; exports.keyPlanSimilarity = keyPlanSimilarity; exports.onsetSimilarity = onsetSimilarity; exports.densitySimilarity = densitySimilarity; exports.durationSimilarity = durationSimilarity; exports.syncopationSimilarity = syncopationSimilarity; exports.surfaceSimilarity = surfaceSimilarity; exports.motifStructureSimilarity = motifStructureSimilarity; exports.contourSimilarity = contourSimilarity; exports.registerSimilarity = registerSimilarity; exports.rhythmLevel = rhythmLevel; exports.ioiBinIndex = ioiBinIndex; exports.RHYTHM_IOI_BINS = RHYTHM_IOI_BINS; exports.analyzeRhythm = analyzeRhythm; exports.REFERENCE_PROFILE_VERSION = REFERENCE_PROFILE_VERSION; exports.assertReferenceProfile = assertReferenceProfile; exports.weightedMean = weightedMean; exports.phraseMelody = phraseMelody;
5195
+ //# sourceMappingURL=chunk-IFZDWIKM.cjs.map