@libraz/libcantus 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/NOTICE +63 -0
  2. package/README.md +3 -1
  3. package/README_ja.md +13 -11
  4. package/dist/analyze/index.cjs +7 -7
  5. package/dist/analyze/index.cjs.map +1 -1
  6. package/dist/analyze/index.d.cts +14 -12
  7. package/dist/analyze/index.d.ts +14 -12
  8. package/dist/analyze/index.js +6 -6
  9. package/dist/{chunk-NB25P3EH.js → chunk-2G5MCGYU.js} +33 -11
  10. package/dist/chunk-2G5MCGYU.js.map +1 -0
  11. package/dist/{chunk-NM7UAMC3.cjs → chunk-3FDBMIPR.cjs} +64 -64
  12. package/dist/chunk-3FDBMIPR.cjs.map +1 -0
  13. package/dist/{chunk-YFA7X2F6.cjs → chunk-3MDOEFIQ.cjs} +411 -327
  14. package/dist/chunk-3MDOEFIQ.cjs.map +1 -0
  15. package/dist/{chunk-IPEF6NWB.js → chunk-5MWRBYAT.js} +278 -154
  16. package/dist/chunk-5MWRBYAT.js.map +1 -0
  17. package/dist/{chunk-B2PW6EHN.cjs → chunk-6TTBEON3.cjs} +1253 -889
  18. package/dist/chunk-6TTBEON3.cjs.map +1 -0
  19. package/dist/{chunk-UMWZ4ZET.js → chunk-7NQ6AL3H.js} +4 -4
  20. package/dist/chunk-7NQ6AL3H.js.map +1 -0
  21. package/dist/{chunk-PWC4CRWT.cjs → chunk-E3QO3UET.cjs} +31 -23
  22. package/dist/chunk-E3QO3UET.cjs.map +1 -0
  23. package/dist/{chunk-GNVN4PPJ.js → chunk-FJFULJZE.js} +531 -213
  24. package/dist/chunk-FJFULJZE.js.map +1 -0
  25. package/dist/{chunk-CPMB7P75.js → chunk-FK3DGAIZ.js} +608 -244
  26. package/dist/chunk-FK3DGAIZ.js.map +1 -0
  27. package/dist/chunk-GEDTJHAC.cjs.map +1 -1
  28. package/dist/{chunk-RFIBF2RR.js → chunk-H7FVMBUC.js} +138 -65
  29. package/dist/chunk-H7FVMBUC.js.map +1 -0
  30. package/dist/{chunk-4R2LWV7E.cjs → chunk-HYSVSFNI.cjs} +664 -540
  31. package/dist/chunk-HYSVSFNI.cjs.map +1 -0
  32. package/dist/{chunk-35NBV2FT.cjs → chunk-KMYGRFZ6.cjs} +47 -24
  33. package/dist/chunk-KMYGRFZ6.cjs.map +1 -0
  34. package/dist/{chunk-IFZDWIKM.cjs → chunk-LQZQDBCD.cjs} +1048 -730
  35. package/dist/chunk-LQZQDBCD.cjs.map +1 -0
  36. package/dist/{chunk-PM4XJE2Y.cjs → chunk-P3CPXAJ5.cjs} +76 -54
  37. package/dist/chunk-P3CPXAJ5.cjs.map +1 -0
  38. package/dist/{chunk-S5BKZZGM.cjs → chunk-S3QELJUE.cjs} +72 -56
  39. package/dist/chunk-S3QELJUE.cjs.map +1 -0
  40. package/dist/{chunk-PUKJP2Z5.js → chunk-TXFWSU5D.js} +31 -8
  41. package/dist/chunk-TXFWSU5D.js.map +1 -0
  42. package/dist/{chunk-76ZBTRG2.cjs → chunk-U4EQTDGN.cjs} +258 -218
  43. package/dist/chunk-U4EQTDGN.cjs.map +1 -0
  44. package/dist/chunk-UGLFDG7L.cjs.map +1 -1
  45. package/dist/{chunk-MLBPXA4Z.js → chunk-UTE5A36R.js} +198 -114
  46. package/dist/chunk-UTE5A36R.js.map +1 -0
  47. package/dist/{chunk-ZBUROTJQ.js → chunk-UZKQISRF.js} +17 -9
  48. package/dist/chunk-UZKQISRF.js.map +1 -0
  49. package/dist/{chunk-7KG3RTYS.js → chunk-VL5NXVCN.js} +281 -155
  50. package/dist/chunk-VL5NXVCN.js.map +1 -0
  51. package/dist/{chunk-CGBADIO5.cjs → chunk-WOMCXN2W.cjs} +328 -202
  52. package/dist/chunk-WOMCXN2W.cjs.map +1 -0
  53. package/dist/{chunk-3R3QVKY5.cjs → chunk-YDGMWH43.cjs} +397 -324
  54. package/dist/chunk-YDGMWH43.cjs.map +1 -0
  55. package/dist/{chunk-AGOVW7U6.js → chunk-YYVXRV3V.js} +72 -56
  56. package/dist/chunk-YYVXRV3V.js.map +1 -0
  57. package/dist/{chunk-M5RYMAFI.js → chunk-ZLNSH4UL.js} +71 -31
  58. package/dist/chunk-ZLNSH4UL.js.map +1 -0
  59. package/dist/{coerce-DRERzdve.d.cts → coerce-CUhHc3Tu.d.ts} +16 -8
  60. package/dist/{coerce-DP0vYu-x.d.ts → coerce-Ytt2Eiq9.d.cts} +16 -8
  61. package/dist/core/index.cjs +5 -5
  62. package/dist/core/index.cjs.map +1 -1
  63. package/dist/core/index.d.cts +9 -8
  64. package/dist/core/index.d.ts +9 -8
  65. package/dist/core/index.js +4 -4
  66. package/dist/generate/index.cjs +8 -8
  67. package/dist/generate/index.cjs.map +1 -1
  68. package/dist/generate/index.d.cts +28 -18
  69. package/dist/generate/index.d.ts +28 -18
  70. package/dist/generate/index.js +7 -7
  71. package/dist/{index-BMweUlm5.d.cts → index-5VJgKz_Q.d.cts} +6 -2
  72. package/dist/{index-BHIUyjhZ.d.ts → index-BLuDesVG.d.ts} +20 -13
  73. package/dist/{index-B9QLziDe.d.cts → index-BV6APVa6.d.cts} +20 -13
  74. package/dist/{index-CL4b4gUQ.d.ts → index-Bf0Sv8a9.d.ts} +6 -2
  75. package/dist/{index-Dw2DP7vm.d.ts → index-BkT21EMv.d.cts} +3 -2
  76. package/dist/{index-BL5N2Oyz.d.cts → index-C7KCaTRz.d.ts} +3 -2
  77. package/dist/{index-Cy15oTvh.d.ts → index-C9MYbuKS.d.cts} +7 -3
  78. package/dist/{index-Cy15oTvh.d.cts → index-C9MYbuKS.d.ts} +7 -3
  79. package/dist/{index-CY-3NVfy.d.cts → index-DVInzCDS.d.cts} +53 -29
  80. package/dist/{index-9eoQs2C1.d.ts → index-Dg-SAfhz.d.ts} +6 -4
  81. package/dist/{index-zaZdmnU4.d.ts → index-jgeug9EA.d.ts} +53 -29
  82. package/dist/{index-cHvbYgJI.d.cts → index-pQihL4z7.d.cts} +6 -4
  83. package/dist/index.cjs +13 -13
  84. package/dist/index.cjs.map +1 -1
  85. package/dist/index.d.cts +11 -11
  86. package/dist/index.d.ts +11 -11
  87. package/dist/index.js +12 -12
  88. package/dist/{masks-Cc7-MzzY.d.ts → masks-BnzXnBj0.d.cts} +3 -2
  89. package/dist/{masks-pADfTOiD.d.cts → masks-tycmkrgs.d.ts} +3 -2
  90. package/dist/model/index.cjs +12 -12
  91. package/dist/model/index.cjs.map +1 -1
  92. package/dist/model/index.d.cts +63 -48
  93. package/dist/model/index.d.ts +63 -48
  94. package/dist/model/index.js +11 -11
  95. package/dist/{positional-DJgs6ltD.d.ts → positional-CscpxtlE.d.cts} +3 -2
  96. package/dist/{positional-DMZer-FM.d.cts → positional-DLnfUgqG.d.ts} +3 -2
  97. package/dist/{profile-DLdlIpS9.d.ts → profile-B4WqcM4H.d.ts} +25 -17
  98. package/dist/{profile-CQMEqdH9.d.cts → profile-BJd1XkPB.d.cts} +25 -17
  99. package/dist/theory/index.cjs +5 -5
  100. package/dist/theory/index.cjs.map +1 -1
  101. package/dist/theory/index.d.cts +18 -14
  102. package/dist/theory/index.d.ts +18 -14
  103. package/dist/theory/index.js +4 -4
  104. package/dist/{types-D-XgxGvp.d.cts → types-7mGFwvMm.d.ts} +45 -22
  105. package/dist/{types-Dh7C064C.d.ts → types-_ofpb2be.d.cts} +45 -22
  106. package/package.json +13 -13
  107. package/dist/chunk-35NBV2FT.cjs.map +0 -1
  108. package/dist/chunk-3R3QVKY5.cjs.map +0 -1
  109. package/dist/chunk-4R2LWV7E.cjs.map +0 -1
  110. package/dist/chunk-76ZBTRG2.cjs.map +0 -1
  111. package/dist/chunk-7KG3RTYS.js.map +0 -1
  112. package/dist/chunk-AGOVW7U6.js.map +0 -1
  113. package/dist/chunk-B2PW6EHN.cjs.map +0 -1
  114. package/dist/chunk-CGBADIO5.cjs.map +0 -1
  115. package/dist/chunk-CPMB7P75.js.map +0 -1
  116. package/dist/chunk-GNVN4PPJ.js.map +0 -1
  117. package/dist/chunk-IFZDWIKM.cjs.map +0 -1
  118. package/dist/chunk-IPEF6NWB.js.map +0 -1
  119. package/dist/chunk-M5RYMAFI.js.map +0 -1
  120. package/dist/chunk-MLBPXA4Z.js.map +0 -1
  121. package/dist/chunk-NB25P3EH.js.map +0 -1
  122. package/dist/chunk-NM7UAMC3.cjs.map +0 -1
  123. package/dist/chunk-PM4XJE2Y.cjs.map +0 -1
  124. package/dist/chunk-PUKJP2Z5.js.map +0 -1
  125. package/dist/chunk-PWC4CRWT.cjs.map +0 -1
  126. package/dist/chunk-RFIBF2RR.js.map +0 -1
  127. package/dist/chunk-S5BKZZGM.cjs.map +0 -1
  128. package/dist/chunk-UMWZ4ZET.js.map +0 -1
  129. package/dist/chunk-YFA7X2F6.cjs.map +0 -1
  130. package/dist/chunk-ZBUROTJQ.js.map +0 -1
@@ -52,21 +52,21 @@
52
52
 
53
53
 
54
54
 
55
- var _chunkIFZDWIKMcjs = require('./chunk-IFZDWIKM.cjs');
56
55
 
57
56
 
58
57
 
59
58
 
60
59
 
61
60
 
61
+ var _chunkLQZQDBCDcjs = require('./chunk-LQZQDBCD.cjs');
62
62
 
63
- var _chunk3R3QVKY5cjs = require('./chunk-3R3QVKY5.cjs');
64
63
 
65
64
 
66
65
 
67
66
 
68
67
 
69
68
 
69
+ var _chunkYDGMWH43cjs = require('./chunk-YDGMWH43.cjs');
70
70
 
71
71
 
72
72
 
@@ -82,12 +82,18 @@ var _chunk3R3QVKY5cjs = require('./chunk-3R3QVKY5.cjs');
82
82
 
83
83
 
84
84
 
85
- var _chunkS5BKZZGMcjs = require('./chunk-S5BKZZGM.cjs');
85
+
86
+
87
+
88
+
89
+
90
+
91
+ var _chunkS3QELJUEcjs = require('./chunk-S3QELJUE.cjs');
86
92
 
87
93
  // src/analyze/arrange/internal.ts
88
94
  var MAX_LANE_LEAP = 24;
89
95
  function covers(note, beat) {
90
- return beat >= note.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && beat < note.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS;
96
+ return beat >= note.startBeat - _chunkS3QELJUEcjs.BEAT_EPS && beat < note.endBeat - _chunkS3QELJUEcjs.BEAT_EPS;
91
97
  }
92
98
  function isPercussion(role) {
93
99
  return role === "drums";
@@ -101,31 +107,31 @@ var TRACK_ROLE_TABLE = {
101
107
  };
102
108
  var TRACK_ROLES = Object.keys(TRACK_ROLE_TABLE);
103
109
  function trackRoleOf(role, name) {
104
- return role === void 0 ? "other" : _chunkS5BKZZGMcjs.assertOneOf.call(void 0, role, TRACK_ROLES, name);
110
+ return role === void 0 ? "other" : _chunkS3QELJUEcjs.assertOneOf.call(void 0, role, TRACK_ROLES, name);
105
111
  }
106
112
  var DEFAULT_PROFILE = "pop";
107
- var SAFETY_PROFILES = Object.keys(_chunk3R3QVKY5cjs.PROFILE_WEIGHTS);
113
+ var SAFETY_PROFILES = Object.keys(_chunkYDGMWH43cjs.PROFILE_WEIGHTS);
108
114
  function arrangementProfile(profile) {
109
- return _chunkS5BKZZGMcjs.assertOneOf.call(void 0, _nullishCoalesce(profile, () => ( DEFAULT_PROFILE)), SAFETY_PROFILES, "arrangement profile");
115
+ return _chunkS3QELJUEcjs.assertOneOf.call(void 0, _nullishCoalesce(profile, () => ( DEFAULT_PROFILE)), SAFETY_PROFILES, "arrangement profile");
110
116
  }
111
117
  function assertTrackNotes(tracks, options) {
112
- _chunkS5BKZZGMcjs.assertArray.call(void 0, tracks, "arrangement tracks");
118
+ _chunkS3QELJUEcjs.assertArray.call(void 0, tracks, "arrangement tracks");
113
119
  let noteCount = 0;
114
120
  for (let index = 0; index < tracks.length; index += 1) {
115
121
  const notes = _optionalChain([tracks, 'access', _2 => _2[index], 'optionalAccess', _3 => _3.notes]);
116
122
  if (!Array.isArray(notes)) {
117
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
118
- `tracks[${index}].notes must be an array; received ${typeof notes}`
123
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
124
+ `tracks[${index}].notes must be an array; received ${_chunkS3QELJUEcjs.describeRejected.call(void 0, notes)}`
119
125
  );
120
126
  }
121
- _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, `tracks[${index}].notes`, options);
127
+ _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, notes, `tracks[${index}].notes`, options);
122
128
  noteCount += notes.length;
123
129
  }
124
130
  return noteCount;
125
131
  }
126
132
  function assertGivenTimeline(timeline, name) {
127
133
  if (timeline !== void 0) {
128
- _chunkIFZDWIKMcjs.assertChordTimeline.call(void 0, timeline, name);
134
+ _chunkLQZQDBCDcjs.assertChordTimeline.call(void 0, timeline, name);
129
135
  }
130
136
  }
131
137
  function assertGivenKeys(keys, name) {
@@ -133,26 +139,27 @@ function assertGivenKeys(keys, name) {
133
139
  return;
134
140
  }
135
141
  if (!Array.isArray(keys)) {
136
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
137
- `${name} must be an array of key regions; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, keys)}`
142
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
143
+ `${name} must be an array of key regions; received ${_chunkS3QELJUEcjs.describeRejected.call(void 0, keys)}`
138
144
  );
139
145
  }
140
146
  for (let index = 0; index < keys.length; index += 1) {
141
147
  const region = keys[index];
142
148
  if (typeof region !== "object" || region === null) {
143
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
144
- `${name}[${index}] must be a key region; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, region)}`
149
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
150
+ `${name}[${index}] must be a key region; received ${_chunkS3QELJUEcjs.describeRejected.call(void 0, region)}`
145
151
  );
146
152
  }
147
- _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, region.startBeat, `${name}[${index}].startBeat`);
148
- _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, region.endBeat, `${name}[${index}].endBeat`);
153
+ _chunkS3QELJUEcjs.assertFiniteNumber.call(void 0, region.startBeat, `${name}[${index}].startBeat`);
154
+ _chunkS3QELJUEcjs.assertFiniteNumber.call(void 0, region.endBeat, `${name}[${index}].endBeat`);
149
155
  if (region.key === void 0 || region.key === null || typeof region.key !== "string" && typeof region.key !== "object") {
150
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
151
- `${name}[${index}].key must name a key; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, region.key)}`
156
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
157
+ `${name}[${index}].key must name a key; received ${_chunkS3QELJUEcjs.describeRejected.call(void 0, region.key)}`
152
158
  );
153
159
  }
154
- _chunk3R3QVKY5cjs.resolveKey.call(void 0, region.key);
160
+ _chunkYDGMWH43cjs.resolveKey.call(void 0, region.key);
155
161
  }
162
+ _chunkLQZQDBCDcjs.assertSpansInOrder.call(void 0, keys, name);
156
163
  }
157
164
  function harmonyTrackSet(harmonyTracks, tracks, name = "harmonyTracks") {
158
165
  if (harmonyTracks === void 0) {
@@ -162,16 +169,16 @@ function harmonyTrackSet(harmonyTracks, tracks, name = "harmonyTracks") {
162
169
  for (let index = 0; index < harmonyTracks.length; index += 1) {
163
170
  const value = harmonyTracks[index];
164
171
  if (value === void 0 || !Number.isFinite(value)) {
165
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}[${index}] must be a track index; received ${value}`);
172
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(`${name}[${index}] must be a track index; received ${value}`);
166
173
  }
167
174
  const track = Math.trunc(value);
168
175
  if (track < 0 || track >= tracks.length) {
169
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
176
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
170
177
  `${name}[${index}] ${track} is outside the arrangement's ${tracks.length} tracks`
171
178
  );
172
179
  }
173
180
  if (isPercussion(_optionalChain([tracks, 'access', _4 => _4[track], 'optionalAccess', _5 => _5.role]))) {
174
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
181
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
175
182
  `${name}[${index}] ${track} names a percussion track, whose pitches state no harmony`
176
183
  );
177
184
  }
@@ -212,7 +219,7 @@ function splitIntoSubVoices(ordered) {
212
219
  continue;
213
220
  }
214
221
  const end = last.startBeat + last.durationBeat;
215
- if (!_chunkIFZDWIKMcjs.hasEnded.call(void 0, end, note.startBeat)) {
222
+ if (!_chunkLQZQDBCDcjs.hasEnded.call(void 0, end, note.startBeat)) {
216
223
  continue;
217
224
  }
218
225
  const distance = Math.abs(last.pitch - note.pitch);
@@ -233,13 +240,13 @@ function splitIntoSubVoices(ordered) {
233
240
  for (let start = 0; start < ordered.length; ) {
234
241
  const onset = _nullishCoalesce(_optionalChain([ordered, 'access', _13 => _13[start], 'optionalAccess', _14 => _14.startBeat]), () => ( 0));
235
242
  let end = start + 1;
236
- while (end < ordered.length && _chunkIFZDWIKMcjs.sameInstant.call(void 0, _nullishCoalesce(_optionalChain([ordered, 'access', _15 => _15[end], 'optionalAccess', _16 => _16.startBeat]), () => ( 0)), onset)) {
243
+ while (end < ordered.length && _chunkLQZQDBCDcjs.sameInstant.call(void 0, _nullishCoalesce(_optionalChain([ordered, 'access', _15 => _15[end], 'optionalAccess', _16 => _16.startBeat]), () => ( 0)), onset)) {
237
244
  end += 1;
238
245
  }
239
246
  const block = ordered.slice(start, end);
240
247
  if (block.length > 1) {
241
248
  const freeLanes = lanes.map((lane, index) => ({ index, last: lane[lane.length - 1] })).filter(
242
- (entry) => entry.last !== void 0 && _chunkIFZDWIKMcjs.hasEnded.call(void 0, entry.last.startBeat + entry.last.durationBeat, onset)
249
+ (entry) => entry.last !== void 0 && _chunkLQZQDBCDcjs.hasEnded.call(void 0, entry.last.startBeat + entry.last.durationBeat, onset)
243
250
  ).sort((a, b) => a.last.pitch - b.last.pitch);
244
251
  const assignment = pairWithFreeLanes(block, freeLanes);
245
252
  const taken = new Set(
@@ -327,7 +334,7 @@ function lastStartingAtOrBefore(sounding, beat) {
327
334
  let high = sounding.length;
328
335
  while (low < high) {
329
336
  const middle = Math.floor((low + high) / 2);
330
- if ((_nullishCoalesce(_optionalChain([sounding, 'access', _22 => _22[middle], 'optionalAccess', _23 => _23.startBeat]), () => ( Number.POSITIVE_INFINITY))) <= beat + _chunkS5BKZZGMcjs.BEAT_EPS) {
337
+ if ((_nullishCoalesce(_optionalChain([sounding, 'access', _22 => _22[middle], 'optionalAccess', _23 => _23.startBeat]), () => ( Number.POSITIVE_INFINITY))) <= beat + _chunkS3QELJUEcjs.BEAT_EPS) {
331
338
  low = middle + 1;
332
339
  } else {
333
340
  high = middle;
@@ -338,12 +345,17 @@ function lastStartingAtOrBefore(sounding, beat) {
338
345
  function prepareTracks(tracks) {
339
346
  let nextId = 0;
340
347
  return tracks.map((track, index) => {
341
- const ordered = track.notes.map((note, originalIndex) => ({ note, originalIndex })).filter(({ note }) => note.durationBeat > 0).sort((a, b) => a.note.startBeat - b.note.startBeat || a.note.pitch - b.note.pitch).map(({ note, originalIndex }) => ({ ...note, id: nextId++, originalIndex }));
348
+ const ordered = track.notes.map((note, originalIndex) => ({ note, originalIndex })).filter(({ note }) => note.durationBeat > 0).sort((a, b) => a.note.startBeat - b.note.startBeat || a.note.pitch - b.note.pitch).map(({ note, originalIndex }) => ({
349
+ ...note,
350
+ pitch: note.pitch === 0 ? 0 : note.pitch,
351
+ id: nextId++,
352
+ originalIndex
353
+ }));
342
354
  const voices = splitIntoSubVoices(ordered).map((voice) => {
343
355
  const sounding = voice.map((note, i) => {
344
356
  const prev = i > 0 ? voice[i - 1] : void 0;
345
357
  const prevEnd = prev === void 0 ? void 0 : prev.startBeat + prev.durationBeat;
346
- const contiguous = prevEnd !== void 0 && _chunkIFZDWIKMcjs.adjacent.call(void 0, prevEnd, note.startBeat);
358
+ const contiguous = prevEnd !== void 0 && _chunkLQZQDBCDcjs.adjacent.call(void 0, prevEnd, note.startBeat);
347
359
  return {
348
360
  id: note.id,
349
361
  originalIndex: note.originalIndex,
@@ -376,24 +388,25 @@ function withGivenKeys(result, given) {
376
388
  if (given === void 0) {
377
389
  return result;
378
390
  }
379
- return { ...result, keys: given, prevailingKey: _nullishCoalesce(_chunkIFZDWIKMcjs.prevailingKeyOf.call(void 0, given), () => ( result.prevailingKey)) };
391
+ return { ...result, keys: given, prevailingKey: _nullishCoalesce(_chunkLQZQDBCDcjs.prevailingKeyOf.call(void 0, given), () => ( result.prevailingKey)) };
380
392
  }
381
393
  function callerTimeline(timeline, key, given, pooled, meters, budget) {
382
- const chartEnd = timeline.segments.reduce((end, segment) => Math.max(end, segment.endBeat), 0);
383
- const soundingEnd = pooled.reduce(
384
- (end, note) => Math.max(end, note.startBeat + note.durationBeat),
385
- 0
394
+ const chartEnd = timeline.segments.reduce(
395
+ (end, segment) => Math.max(end, segment.endBeat),
396
+ Number.NEGATIVE_INFINITY
386
397
  );
387
- const totalBeats = Math.max(chartEnd, soundingEnd);
388
- const { startBeat: musicStart } = _chunkIFZDWIKMcjs.gridForNotes.call(void 0, pooled, _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, 0, meters));
389
- const keys = _nullishCoalesce(given, () => ( _chunkIFZDWIKMcjs.attachPivots.call(void 0,
390
- key !== void 0 ? [{ startBeat: musicStart, endBeat: totalBeats, key: _chunk3R3QVKY5cjs.resolveKey.call(void 0, key), confidence: 1 }] : _chunkIFZDWIKMcjs.keyTimelineFromNotes.call(void 0, pooled, { meters, totalBeats, budget }),
398
+ const soundingEnd = _chunkLQZQDBCDcjs.latestSoundingEnd.call(void 0, pooled, Number.NEGATIVE_INFINITY);
399
+ const spanEnd = Math.max(chartEnd, soundingEnd);
400
+ const totalBeats = Number.isFinite(spanEnd) ? spanEnd : 0;
401
+ const { startBeat: musicStart } = _chunkLQZQDBCDcjs.gridForNotes.call(void 0, pooled, _chunkS3QELJUEcjs.beatsPerBarAt.call(void 0, 0, meters));
402
+ const keys = _nullishCoalesce(given, () => ( _chunkLQZQDBCDcjs.attachPivots.call(void 0,
403
+ key !== void 0 ? _chunkLQZQDBCDcjs.statedKeyRegions.call(void 0, _chunkYDGMWH43cjs.resolveKey.call(void 0, key), musicStart, totalBeats) : _chunkLQZQDBCDcjs.keyTimelineFromNotes.call(void 0, pooled, { meters, totalBeats, budget }),
391
404
  timeline.segments
392
405
  )));
393
406
  return {
394
407
  timeline,
395
408
  keys,
396
- prevailingKey: _nullishCoalesce(_chunkIFZDWIKMcjs.prevailingKeyOf.call(void 0, keys), () => ( _chunk3R3QVKY5cjs.resolveKey.call(void 0, _chunk3R3QVKY5cjs.majorKey.call(void 0, 0)))),
409
+ prevailingKey: _nullishCoalesce(_chunkLQZQDBCDcjs.prevailingKeyOf.call(void 0, keys), () => ( _chunkYDGMWH43cjs.resolveKey.call(void 0, _chunkYDGMWH43cjs.majorKey.call(void 0, 0)))),
397
410
  segmentConfidence: timeline.segments.map(() => 0)
398
411
  };
399
412
  }
@@ -410,7 +423,7 @@ function soundingVoicesAt(prepared, beat) {
410
423
  continue;
411
424
  }
412
425
  const snap = { pitch: note.pitch };
413
- const previous = _chunkIFZDWIKMcjs.sameInstant.call(void 0, note.startBeat, beat) ? note.prevPitch : note.pitch;
426
+ const previous = _chunkLQZQDBCDcjs.sameInstant.call(void 0, note.startBeat, beat) ? note.prevPitch : note.pitch;
414
427
  if (previous !== void 0) {
415
428
  snap.prevPitch = previous;
416
429
  }
@@ -439,11 +452,11 @@ function snapshotsOf(voices) {
439
452
  return voices.map(({ snapshot }) => snapshot);
440
453
  }
441
454
  function analyzePolyphony(notes, chordAtBeat, key) {
442
- const passage = _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "notes", { allowNonPositiveDuration: true });
443
- _chunkS5BKZZGMcjs.assertFunction.call(void 0, chordAtBeat, "chordAtBeat");
455
+ const passage = _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, notes, "notes", { allowNonPositiveDuration: true });
456
+ _chunkS3QELJUEcjs.assertFunction.call(void 0, chordAtBeat, "chordAtBeat");
444
457
  const prepared = prepareTracks([{ notes: [...passage] }]);
445
458
  const track = prepared[0];
446
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0,
459
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0,
447
460
  passage.length * (_nullishCoalesce(_optionalChain([track, 'optionalAccess', _29 => _29.voices, 'access', _30 => _30.length]), () => ( 0))),
448
461
  "polyphony note-voice comparisons"
449
462
  );
@@ -454,7 +467,7 @@ function analyzePolyphony(notes, chordAtBeat, key) {
454
467
  if (subVoice === void 0) {
455
468
  continue;
456
469
  }
457
- const analyzed = _chunkIFZDWIKMcjs.analyzeVoice.call(void 0,
470
+ const analyzed = _chunkLQZQDBCDcjs.analyzeVoice.call(void 0,
458
471
  subVoice.voice,
459
472
  chordAtBeat,
460
473
  key,
@@ -472,7 +485,7 @@ function analyzePolyphony(notes, chordAtBeat, key) {
472
485
  if (analyzed !== void 0) {
473
486
  return analyzed;
474
487
  }
475
- const [only] = _chunkIFZDWIKMcjs.analyzeVoice.call(void 0, [{ ...note, id: index }], chordAtBeat, key);
488
+ const [only] = _chunkLQZQDBCDcjs.analyzeVoice.call(void 0, [{ ...note, id: index }], chordAtBeat, key);
476
489
  return _nullishCoalesce(only, () => ( {
477
490
  noteId: index,
478
491
  pitch: note.pitch,
@@ -487,7 +500,7 @@ function firstSegmentAfter(timeline, beat) {
487
500
  let high = timeline.segments.length;
488
501
  while (low < high) {
489
502
  const middle = Math.floor((low + high) / 2);
490
- if ((_nullishCoalesce(_optionalChain([timeline, 'access', _35 => _35.segments, 'access', _36 => _36[middle], 'optionalAccess', _37 => _37.startBeat]), () => ( Number.POSITIVE_INFINITY))) <= beat + _chunkS5BKZZGMcjs.BEAT_EPS) {
503
+ if ((_nullishCoalesce(_optionalChain([timeline, 'access', _35 => _35.segments, 'access', _36 => _36[middle], 'optionalAccess', _37 => _37.startBeat]), () => ( Number.POSITIVE_INFINITY))) <= beat + _chunkS3QELJUEcjs.BEAT_EPS) {
491
504
  low = middle + 1;
492
505
  } else {
493
506
  high = middle;
@@ -500,7 +513,7 @@ function evaluationBeats(note, timeline) {
500
513
  const beats = [note.startBeat];
501
514
  for (let i = firstSegmentAfter(timeline, note.startBeat); i < timeline.segments.length; i += 1) {
502
515
  const start = _optionalChain([timeline, 'access', _38 => _38.segments, 'access', _39 => _39[i], 'optionalAccess', _40 => _40.startBeat]);
503
- if (start === void 0 || start >= noteEnd - _chunkS5BKZZGMcjs.BEAT_EPS) {
516
+ if (start === void 0 || start >= noteEnd - _chunkS3QELJUEcjs.BEAT_EPS) {
504
517
  break;
505
518
  }
506
519
  beats.push(start);
@@ -511,19 +524,19 @@ function analyzeArrangement(tracks, opts = {}) {
511
524
  return analyzeArrangementWith(tracks, opts).analysis;
512
525
  }
513
526
  function analyzeArrangementWith(tracks, opts = {}, previous, dirty) {
514
- const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "arrangement meters");
527
+ const meters = _chunkS3QELJUEcjs.resolveMeters.call(void 0, opts, "arrangement meters");
515
528
  const budget = opts.budget;
516
529
  const noteOptions = { allowNonPositiveDuration: true, budget };
517
530
  if (opts.pickupBeats !== void 0) {
518
- _chunkS5BKZZGMcjs.assertRange.call(void 0, opts.pickupBeats, 0, Number.MAX_SAFE_INTEGER, "arrangement pickupBeats");
531
+ _chunkS3QELJUEcjs.assertRange.call(void 0, opts.pickupBeats, 0, Number.MAX_SAFE_INTEGER, "arrangement pickupBeats");
519
532
  noteOptions.minStartBeat = -opts.pickupBeats;
520
533
  }
521
- _chunkS5BKZZGMcjs.assertArray.call(void 0, tracks, "arrangement tracks");
522
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, tracks.length, "arrangement tracks", budget);
534
+ _chunkS3QELJUEcjs.assertArray.call(void 0, tracks, "arrangement tracks");
535
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, tracks.length, "arrangement tracks", budget);
523
536
  const noteCount = assertTrackNotes(tracks, noteOptions);
524
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, noteCount, "arrangement notes", budget);
537
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, noteCount, "arrangement notes", budget);
525
538
  const profile = arrangementProfile(opts.profile);
526
- const minSeverity = opts.minSeverity === void 0 ? 1 /* Warning */ : _chunkS5BKZZGMcjs.assertInteger.call(void 0,
539
+ const minSeverity = opts.minSeverity === void 0 ? 1 /* Warning */ : _chunkS3QELJUEcjs.assertInteger.call(void 0,
527
540
  opts.minSeverity,
528
541
  "arrangement minSeverity",
529
542
  0 /* Safe */,
@@ -534,12 +547,12 @@ function analyzeArrangementWith(tracks, opts = {}, previous, dirty) {
534
547
  const harmonyTracks = harmonyTrackSet(opts.harmonyTracks, tracks);
535
548
  const prepared = prepareTracks(tracks);
536
549
  const voiceCount = prepared.reduce((sum, track) => sum + track.voices.length, 0);
537
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, noteCount * voiceCount, "arrangement note-voice comparisons", budget);
550
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, noteCount * voiceCount, "arrangement note-voice comparisons", budget);
538
551
  const pooled = poolNotes(tracks, harmonyTracks);
539
552
  let evidence;
540
553
  let inferred;
541
554
  if (opts.timeline === void 0) {
542
- const run = _chunkIFZDWIKMcjs.analyzeTimeline.call(void 0,
555
+ const run = _chunkLQZQDBCDcjs.analyzeTimeline.call(void 0,
543
556
  pooled,
544
557
  {
545
558
  key: opts.key,
@@ -557,9 +570,9 @@ function analyzeArrangementWith(tracks, opts = {}, previous, dirty) {
557
570
  inferred = callerTimeline(opts.timeline, opts.key, opts.keys, pooled, meters, budget);
558
571
  }
559
572
  const { timeline, keys, prevailingKey, segmentConfidence } = inferred;
560
- const keyAt = _chunkIFZDWIKMcjs.keyLookup.call(void 0, keys, prevailingKey);
561
- const scaleAt = (beat) => _chunk3R3QVKY5cjs.scaleOf.call(void 0, keyAt(beat));
562
- const cadences = _chunkIFZDWIKMcjs.detectCadences.call(void 0, timeline, scaleAt);
573
+ const keyAt = _chunkLQZQDBCDcjs.keyLookup.call(void 0, keys, prevailingKey);
574
+ const scaleAt = (beat) => _chunkYDGMWH43cjs.scaleOf.call(void 0, keyAt(beat));
575
+ const cadences = _chunkLQZQDBCDcjs.detectCadences.call(void 0, timeline, scaleAt);
563
576
  const soundingCache = /* @__PURE__ */ new Map();
564
577
  const trackAnalyses = [];
565
578
  const conflicts = [];
@@ -578,7 +591,7 @@ function analyzeArrangementWith(tracks, opts = {}, previous, dirty) {
578
591
  if (!subVoice) {
579
592
  continue;
580
593
  }
581
- const analyzed = _chunkIFZDWIKMcjs.analyzeVoice.call(void 0,
594
+ const analyzed = _chunkLQZQDBCDcjs.analyzeVoice.call(void 0,
582
595
  subVoice.voice,
583
596
  timeline.at,
584
597
  scaleAt,
@@ -595,7 +608,7 @@ function analyzeArrangementWith(tracks, opts = {}, previous, dirty) {
595
608
  continue;
596
609
  }
597
610
  for (const beat of evaluationBeats(note, timeline)) {
598
- const atOnset = _chunkIFZDWIKMcjs.sameInstant.call(void 0, beat, note.startBeat);
611
+ const atOnset = _chunkLQZQDBCDcjs.sameInstant.call(void 0, beat, note.startBeat);
599
612
  const others = otherVoicesSounding(prepared, t, v, beat, soundingCache);
600
613
  const safetyQuery = {
601
614
  profile,
@@ -604,11 +617,11 @@ function analyzeArrangementWith(tracks, opts = {}, previous, dirty) {
604
617
  chord: timeline.at(beat),
605
618
  key: scaleAt(beat),
606
619
  otherVoices: snapshotsOf(others),
607
- strongBeat: _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, beat, meters)
620
+ strongBeat: _chunkS3QELJUEcjs.isStrongBeat.call(void 0, beat, meters)
608
621
  };
609
- let result = _chunk3R3QVKY5cjs.evaluateSafety.call(void 0, safetyQuery, { suggestions: false });
622
+ let result = _chunkYDGMWH43cjs.evaluateSafety.call(void 0, safetyQuery, { suggestions: false });
610
623
  if (result.safety !== 0 /* Safe */ && result.safety >= minSeverity) {
611
- result = _chunk3R3QVKY5cjs.evaluateSafety.call(void 0, safetyQuery, { partners: true });
624
+ result = _chunkYDGMWH43cjs.evaluateSafety.call(void 0, safetyQuery, { partners: true });
612
625
  const conflict = {
613
626
  beat,
614
627
  trackName: track.name,
@@ -721,7 +734,7 @@ function sessionOf(tracks, opts, analysis, evidence) {
721
734
  tracks,
722
735
  analysis,
723
736
  update(edits) {
724
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, edits.length, "arrangement edits", opts.budget);
737
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, edits.length, "arrangement edits", opts.budget);
725
738
  const next = [...tracks];
726
739
  let edited = null;
727
740
  let reordered = false;
@@ -732,16 +745,16 @@ function sessionOf(tracks, opts, analysis, evidence) {
732
745
  }
733
746
  const target = next[edit.trackIndex];
734
747
  if (target === void 0) {
735
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
748
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
736
749
  `edits[${index}].trackIndex ${edit.trackIndex} is outside the session's ${tracks.length} tracks`
737
750
  );
738
751
  }
739
752
  if (!Array.isArray(edit.notes)) {
740
- throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
741
- `edits[${index}].notes must be an array; received ${typeof edit.notes}`
753
+ throw new (0, _chunkS3QELJUEcjs.InvalidInputError)(
754
+ `edits[${index}].notes must be an array; received ${_chunkS3QELJUEcjs.describeRejected.call(void 0, edit.notes)}`
742
755
  );
743
756
  }
744
- _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, edit.notes, `edits[${index}].notes`, {
757
+ _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, edit.notes, `edits[${index}].notes`, {
745
758
  allowNonPositiveDuration: true,
746
759
  budget: opts.budget
747
760
  });
@@ -752,7 +765,7 @@ function sessionOf(tracks, opts, analysis, evidence) {
752
765
  if (edited === null && !reordered) {
753
766
  return sessionOf(next, opts, analysis, evidence);
754
767
  }
755
- const dirty = evidence === void 0 ? void 0 : edited === null ? { from: 0, to: 0 } : _chunkIFZDWIKMcjs.dirtySlotsFor.call(void 0, evidence, edited.startBeat, edited.endBeat);
768
+ const dirty = evidence === void 0 ? void 0 : edited === null ? { from: 0, to: 0 } : _chunkLQZQDBCDcjs.dirtySlotsFor.call(void 0, evidence, edited.startBeat, edited.endBeat);
756
769
  const run = analyzeArrangementWith(next, opts, evidence, dirty);
757
770
  return sessionOf(next, opts, run.analysis, run.evidence);
758
771
  }
@@ -773,26 +786,27 @@ var FUNCTION_WEIGHT = 0.5;
773
786
  var DISSONANCE_WEIGHT = 0.35;
774
787
  var SPAN_WEIGHT = 0.15;
775
788
  var SPAN_SATURATION = 24;
789
+ var MAX_DISTINCT_PITCHES = 128;
776
790
  function clamp012(value) {
777
791
  return Math.min(1, Math.max(0, value));
778
792
  }
779
793
  function tensionCurve(tracks, opts = {}) {
780
- const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "arrangement meters");
794
+ const meters = _chunkS3QELJUEcjs.resolveMeters.call(void 0, opts, "arrangement meters");
781
795
  const budget = opts.budget;
782
796
  const noteOptions = { allowNonPositiveDuration: true, budget };
783
797
  if (opts.pickupBeats !== void 0) {
784
- _chunkS5BKZZGMcjs.assertRange.call(void 0, opts.pickupBeats, 0, Number.MAX_SAFE_INTEGER, "arrangement pickupBeats");
798
+ _chunkS3QELJUEcjs.assertRange.call(void 0, opts.pickupBeats, 0, Number.MAX_SAFE_INTEGER, "arrangement pickupBeats");
785
799
  noteOptions.minStartBeat = -opts.pickupBeats;
786
800
  }
787
- _chunkS5BKZZGMcjs.assertArray.call(void 0, tracks, "arrangement tracks");
788
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, tracks.length, "arrangement tracks", budget);
801
+ _chunkS3QELJUEcjs.assertArray.call(void 0, tracks, "arrangement tracks");
802
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, tracks.length, "arrangement tracks", budget);
789
803
  const noteCount = assertTrackNotes(tracks, noteOptions);
790
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, noteCount, "arrangement notes", budget);
804
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, noteCount, "arrangement notes", budget);
791
805
  const profile = arrangementProfile(opts.profile);
792
806
  const step = _nullishCoalesce(opts.step, () => ( 1));
793
- _chunkS5BKZZGMcjs.assertRange.call(void 0, step, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "tension sampling step");
807
+ _chunkS3QELJUEcjs.assertRange.call(void 0, step, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "tension sampling step");
794
808
  if (opts.minSeverity !== void 0) {
795
- _chunkS5BKZZGMcjs.assertInteger.call(void 0,
809
+ _chunkS3QELJUEcjs.assertInteger.call(void 0,
796
810
  opts.minSeverity,
797
811
  "arrangement minSeverity",
798
812
  0 /* Safe */,
@@ -804,20 +818,15 @@ function tensionCurve(tracks, opts = {}) {
804
818
  const harmonyTracks = harmonyTrackSet(opts.harmonyTracks, tracks);
805
819
  const pooled = poolNotes(tracks, harmonyTracks);
806
820
  const all = poolNotes(tracks);
807
- const totalBeats = all.reduce((end, n) => Math.max(end, n.startBeat + n.durationBeat), 0);
808
- const { origin: sampleStart, startBeat: musicStart } = _chunkIFZDWIKMcjs.gridForNotes.call(void 0, all, step);
809
- const suppliedKeys = opts.timeline === void 0 ? void 0 : _nullishCoalesce(opts.keys, () => ( (opts.key !== void 0 ? [
810
- {
811
- // The one region a named key holds starts where the music does,
812
- // as the searched regions and the timeline's own key window do:
813
- // a key cannot be in force over beats nothing sounds in.
814
- startBeat: musicStart,
815
- endBeat: totalBeats,
816
- key: _chunk3R3QVKY5cjs.resolveKey.call(void 0, opts.key),
817
- confidence: 1
818
- }
819
- ] : _chunkIFZDWIKMcjs.keyTimelineFromNotes.call(void 0, pooled, { meters, totalBeats, budget }))));
820
- const { timeline, keys, prevailingKey } = opts.timeline === void 0 || suppliedKeys === void 0 ? _chunkIFZDWIKMcjs.chordTimelineFromNotes.call(void 0, pooled, {
821
+ const totalBeats = _chunkLQZQDBCDcjs.latestSoundingEnd.call(void 0, all);
822
+ const { origin: sampleStart, startBeat: musicStart } = _chunkLQZQDBCDcjs.gridForNotes.call(void 0, all, step);
823
+ const suppliedKeys = opts.timeline === void 0 ? void 0 : _nullishCoalesce(opts.keys, () => ( (opts.key !== void 0 ? (
824
+ // The one region a named key holds starts where the music does, as
825
+ // the searched regions and the timeline's own key window do: a key
826
+ // cannot be in force over beats nothing sounds in.
827
+ _chunkLQZQDBCDcjs.statedKeyRegions.call(void 0, _chunkYDGMWH43cjs.resolveKey.call(void 0, opts.key), musicStart, totalBeats)
828
+ ) : _chunkLQZQDBCDcjs.keyTimelineFromNotes.call(void 0, pooled, { meters, totalBeats, budget }))));
829
+ const { timeline, keys, prevailingKey } = opts.timeline === void 0 || suppliedKeys === void 0 ? _chunkLQZQDBCDcjs.chordTimelineFromNotes.call(void 0, pooled, {
821
830
  key: opts.key,
822
831
  meters,
823
832
  pickupBeats: opts.pickupBeats,
@@ -826,17 +835,17 @@ function tensionCurve(tracks, opts = {}) {
826
835
  }) : {
827
836
  timeline: opts.timeline,
828
837
  keys: suppliedKeys,
829
- prevailingKey: _nullishCoalesce(_chunkIFZDWIKMcjs.prevailingKeyOf.call(void 0, suppliedKeys), () => ( _chunk3R3QVKY5cjs.resolveKey.call(void 0, _chunk3R3QVKY5cjs.majorKey.call(void 0, 0))))
838
+ prevailingKey: _nullishCoalesce(_chunkLQZQDBCDcjs.prevailingKeyOf.call(void 0, suppliedKeys), () => ( _chunkYDGMWH43cjs.resolveKey.call(void 0, _chunkYDGMWH43cjs.majorKey.call(void 0, 0))))
830
839
  };
831
840
  const regions = _nullishCoalesce(opts.keys, () => ( keys));
832
- const keyAt = _chunkIFZDWIKMcjs.keyLookup.call(void 0, regions, _nullishCoalesce(_chunkIFZDWIKMcjs.prevailingKeyOf.call(void 0, regions), () => ( prevailingKey)));
841
+ const keyAt = _chunkLQZQDBCDcjs.keyLookup.call(void 0, regions, _nullishCoalesce(_chunkLQZQDBCDcjs.prevailingKeyOf.call(void 0, regions), () => ( prevailingKey)));
833
842
  const prepared = prepareTracks(tracks);
834
843
  const points = [];
835
- const sampleCount = Math.max(0, Math.ceil((totalBeats - sampleStart) / step - _chunkS5BKZZGMcjs.BEAT_EPS));
836
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, sampleCount, "tension samples", budget);
844
+ const sampleCount = Math.max(0, Math.ceil((totalBeats - sampleStart) / step - _chunkS3QELJUEcjs.BEAT_EPS));
845
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, sampleCount, "tension samples", budget);
837
846
  const voiceCount = prepared.reduce((sum, track) => sum + track.voices.length, 0);
838
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0,
839
- sampleCount * Math.min(128, voiceCount) * voiceCount,
847
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0,
848
+ sampleCount * Math.min(MAX_DISTINCT_PITCHES, voiceCount) * voiceCount,
840
849
  "tension sample-voice comparisons",
841
850
  budget
842
851
  );
@@ -844,16 +853,15 @@ function tensionCurve(tracks, opts = {}) {
844
853
  const beat = i === 0 ? Math.max(sampleStart, musicStart) : sampleStart + i * step;
845
854
  points.push({
846
855
  beat,
847
- // The pitch classes alone: tension is scored from what sounds against
848
- // the tonic, and no reading below here asks how the key is written.
849
- tension: sampleTension(prepared, timeline, _chunk3R3QVKY5cjs.scaleOf.call(void 0, keyAt(beat)), meters, profile, beat)
856
+ // The key whole: an augmented sixth is told from a dominant by its letters.
857
+ tension: sampleTension(prepared, timeline, keyAt(beat), meters, profile, beat)
850
858
  });
851
859
  }
852
860
  return points;
853
861
  }
854
862
  function tensionCurveFrom(tracks, analysis, opts = {}) {
855
- const asked = _chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "opts");
856
- const carried = carriedHarmony(_chunkS5BKZZGMcjs.assertRecord.call(void 0, analysis, "analysis"), asked);
863
+ const asked = _chunkS3QELJUEcjs.assertRecord.call(void 0, opts, "opts");
864
+ const carried = carriedHarmony(_chunkS3QELJUEcjs.assertRecord.call(void 0, analysis, "analysis"), asked);
857
865
  return tensionCurve(tracks, { ...carried, ...asked });
858
866
  }
859
867
  function carriedHarmony(analysis, opts) {
@@ -887,9 +895,9 @@ function sampleTension(prepared, timeline, key, meters, profile, beat) {
887
895
  return 0;
888
896
  }
889
897
  const chord = timeline.at(beat);
890
- const functionScore = chord ? FUNCTION_TENSION[_chunkIFZDWIKMcjs.functionOf.call(void 0, chord, key)] : 0;
891
- const chordPcs = chord ? new Set(_chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord)) : null;
892
- const strongBeat = _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, beat, meters);
898
+ const functionScore = chord ? FUNCTION_TENSION[_chunkLQZQDBCDcjs.functionOf.call(void 0, chord, key)] : 0;
899
+ const chordPcs = chord ? new Set(_chunkYDGMWH43cjs.chordPitchClasses.call(void 0, chord)) : null;
900
+ const strongBeat = _chunkS3QELJUEcjs.isStrongBeat.call(void 0, beat, meters);
893
901
  let nonChord = 0;
894
902
  let dissonant = 0;
895
903
  const pitches = /* @__PURE__ */ new Map();
@@ -905,7 +913,7 @@ function sampleTension(prepared, timeline, key, meters, profile, beat) {
905
913
  }
906
914
  }
907
915
  for (const [pitch, count] of pitches) {
908
- if (chordPcs && !chordPcs.has(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch))) {
916
+ if (chordPcs && !chordPcs.has(_chunkS3QELJUEcjs.pitchClassOf.call(void 0, pitch))) {
909
917
  nonChord += count;
910
918
  }
911
919
  const at = _nullishCoalesce(firstOf.get(pitch), () => ( 0));
@@ -916,8 +924,8 @@ function sampleTension(prepared, timeline, key, meters, profile, beat) {
916
924
  others[at] = tail;
917
925
  others.pop();
918
926
  }
919
- const result = _chunk3R3QVKY5cjs.evaluateSafety.call(void 0,
920
- { profile, candidatePitch: pitch, chord, key, otherVoices: others, strongBeat },
927
+ const result = _chunkYDGMWH43cjs.evaluateSafety.call(void 0,
928
+ { profile, candidatePitch: pitch, chord, key: key.scale, otherVoices: others, strongBeat },
921
929
  { suggestions: false }
922
930
  );
923
931
  if (held !== void 0 && tail !== void 0) {
@@ -943,19 +951,34 @@ function sampleTension(prepared, timeline, key, meters, profile, beat) {
943
951
 
944
952
  // src/analyze/form/hypermeter.ts
945
953
  var GROUP_CANDIDATES = [2, 3, 4, 6, 8];
946
- var GROUP_PRIOR = /* @__PURE__ */ new Map([
954
+ var GROUP_PRIOR_LIST = [
947
955
  [2, 0.9],
948
956
  [3, 0.75],
949
957
  [4, 1],
950
958
  [6, 0.7],
951
959
  [8, 0.85]
952
- ]);
960
+ ];
961
+ var GROUP_PRIOR = new Map(GROUP_PRIOR_LIST);
953
962
  var CONTRAST_SHARE = 0.65;
954
963
  var CADENCE_SHARE = 0.35;
955
964
  var GROUP_FINAL_FIT = 1;
956
965
  var ELIDED_FIT = 0.5;
957
966
  var MIN_GROUPS = 2;
958
967
  var MARGIN_FLOOR = 0.7;
968
+ function cadenceSpans(arrivals, segments) {
969
+ return arrivals.map(({ atBeat, strength }) => ({
970
+ atBeat,
971
+ endBeat: _nullishCoalesce(_optionalChain([_chunkLQZQDBCDcjs.segmentStartingAt.call(void 0, segments, atBeat), 'optionalAccess', _41 => _41.endBeat]), () => ( atBeat)),
972
+ strength
973
+ }));
974
+ }
975
+ function cadenceBarsOf(spans, meter) {
976
+ return spans.map((span) => ({
977
+ arrival: _chunkS3QELJUEcjs.barIndexAt.call(void 0, span.atBeat, meter),
978
+ last: _chunkLQZQDBCDcjs.lastBarOf.call(void 0, meter, span.atBeat, span.endBeat),
979
+ strength: span.strength
980
+ }));
981
+ }
959
982
  function accentContrast(novelty, slices, groupBars, phase) {
960
983
  let headSum = 0;
961
984
  let headCount = 0;
@@ -967,7 +990,7 @@ function accentContrast(novelty, slices, groupBars, phase) {
967
990
  continue;
968
991
  }
969
992
  const value = _nullishCoalesce(novelty[i], () => ( 0));
970
- if (_chunkIFZDWIKMcjs.floorMod.call(void 0, slice.index - phase, groupBars) === 0) {
993
+ if (_chunkLQZQDBCDcjs.floorMod.call(void 0, slice.index - phase, groupBars) === 0) {
971
994
  headSum += value;
972
995
  headCount += 1;
973
996
  } else {
@@ -980,22 +1003,41 @@ function accentContrast(novelty, slices, groupBars, phase) {
980
1003
  }
981
1004
  return headSum / headCount - otherSum / otherCount;
982
1005
  }
983
- function cadenceFitOf(cadenceBars, slices, groupBars, phase) {
984
- const lastBar = _nullishCoalesce(_optionalChain([slices, 'access', _41 => _41[slices.length - 1], 'optionalAccess', _42 => _42.index]), () => ( -1));
1006
+ function cadenceFitOf(cadences, slices, groupBars, phase) {
1007
+ const lastBar = _nullishCoalesce(_optionalChain([slices, 'access', _42 => _42[slices.length - 1], 'optionalAccess', _43 => _43.index]), () => ( -1));
1008
+ const closing = /* @__PURE__ */ new Map();
1009
+ const eliding = /* @__PURE__ */ new Map();
1010
+ const credit = (bars, bar, strength) => {
1011
+ bars.set(bar, Math.max(_nullishCoalesce(bars.get(bar), () => ( 0)), strength));
1012
+ };
1013
+ for (const cadence of cadences) {
1014
+ const end = cadence.arrival + _chunkLQZQDBCDcjs.floorMod.call(void 0, groupBars - 1 + phase - cadence.arrival, groupBars);
1015
+ if (end <= cadence.last) {
1016
+ credit(closing, end, cadence.strength);
1017
+ } else if (_chunkLQZQDBCDcjs.floorMod.call(void 0, cadence.arrival - phase, groupBars) === 0 && // Elision needs a next group to arrive into. Past the last bar the span
1018
+ // holds there is none, so a cadence beat beyond the music is not evidence
1019
+ // about how the music that was read is grouped.
1020
+ cadence.arrival <= lastBar) {
1021
+ credit(eliding, cadence.arrival - 1, cadence.strength);
1022
+ }
1023
+ }
985
1024
  let ends = 0;
986
- let fit = 0;
1025
+ let closed = 0;
1026
+ let weighted = 0;
987
1027
  for (const slice of slices) {
988
- if (slice.index < 0 || _chunkIFZDWIKMcjs.floorMod.call(void 0, slice.index - phase, groupBars) !== groupBars - 1) {
1028
+ if (slice.index < 0 || _chunkLQZQDBCDcjs.floorMod.call(void 0, slice.index - phase, groupBars) !== groupBars - 1) {
989
1029
  continue;
990
1030
  }
991
1031
  ends += 1;
992
- if (cadenceBars.has(slice.index)) {
993
- fit += GROUP_FINAL_FIT;
994
- } else if (slice.index < lastBar && cadenceBars.has(slice.index + 1)) {
995
- fit += ELIDED_FIT;
996
- }
1032
+ const final = closing.get(slice.index);
1033
+ const elided = eliding.get(slice.index);
1034
+ closed += Math.max(
1035
+ final === void 0 ? 0 : GROUP_FINAL_FIT,
1036
+ elided === void 0 ? 0 : ELIDED_FIT
1037
+ );
1038
+ weighted += Math.max(GROUP_FINAL_FIT * (_nullishCoalesce(final, () => ( 0))), ELIDED_FIT * (_nullishCoalesce(elided, () => ( 0))));
997
1039
  }
998
- return ends === 0 ? 0 : _chunkIFZDWIKMcjs.clamp01.call(void 0, fit / ends);
1040
+ return ends === 0 ? { closed: 0, weighted: 0 } : { closed: _chunkLQZQDBCDcjs.clamp01.call(void 0, closed / ends), weighted: _chunkLQZQDBCDcjs.clamp01.call(void 0, weighted / ends) };
999
1041
  }
1000
1042
  function undecidedReading(slices) {
1001
1043
  const fullBars = slices.filter((slice) => slice.index >= 0);
@@ -1009,52 +1051,70 @@ function undecidedReading(slices) {
1009
1051
  };
1010
1052
  }
1011
1053
  function hypermeter(notes, meter, opts = {}) {
1012
- const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
1013
- const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, { meters: meter }, "meter");
1014
- _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "hypermeter notes", {
1054
+ return hypermeterOver(
1055
+ notes,
1056
+ meter,
1057
+ opts,
1058
+ (asked) => cadenceSpans(
1059
+ (_nullishCoalesce(asked.cadenceBeats, () => ( []))).map((atBeat) => ({ atBeat, strength: 1 })),
1060
+ []
1061
+ )
1062
+ );
1063
+ }
1064
+ function hypermeterOver(notes, meter, opts, spansOf) {
1065
+ const asked = _chunkS3QELJUEcjs.assertOptions.call(void 0, opts, "opts");
1066
+ const meters = _chunkS3QELJUEcjs.resolveMeters.call(void 0, { meters: meter }, "meter");
1067
+ _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, notes, "hypermeter notes", {
1015
1068
  allowNonPositiveDuration: true,
1016
1069
  budget: asked.budget
1017
1070
  });
1018
1071
  const sounding = notes.filter((note) => note.durationBeat > 0);
1019
- const firstOnset = _chunkIFZDWIKMcjs.firstSoundingBeat.call(void 0, sounding);
1020
- const lastEnd = sounding.reduce((end, n) => Math.max(end, n.startBeat + n.durationBeat), 0);
1021
- const spanEnd = _nullishCoalesce(asked.totalBeats, () => ( lastEnd));
1022
- _chunkS5BKZZGMcjs.assertRange.call(void 0, spanEnd, 0, Number.MAX_SAFE_INTEGER, "hypermeter totalBeats");
1023
- const spanStart = _chunkIFZDWIKMcjs.barGridStart.call(void 0, firstOnset, meters);
1024
- const slices = _chunkIFZDWIKMcjs.sliceBars.call(void 0, sounding, meters, spanStart, spanEnd, asked.budget);
1072
+ const firstOnset = _chunkLQZQDBCDcjs.firstSoundingBeat.call(void 0, sounding);
1073
+ const spanEnd = _chunkLQZQDBCDcjs.resolveSpanEnd.call(void 0,
1074
+ asked.totalBeats,
1075
+ firstOnset,
1076
+ _chunkLQZQDBCDcjs.latestSoundingEnd.call(void 0, sounding),
1077
+ "hypermeter totalBeats"
1078
+ );
1079
+ const spanStart = _chunkLQZQDBCDcjs.barGridStart.call(void 0, firstOnset, meters);
1080
+ if (sounding.length === 0 || spanEnd <= spanStart + _chunkS3QELJUEcjs.BEAT_EPS) {
1081
+ return undecidedReading([]);
1082
+ }
1083
+ const slices = _chunkLQZQDBCDcjs.sliceBars.call(void 0, sounding, meters, spanStart, spanEnd, asked.budget);
1025
1084
  const fullBars = slices.reduce((count, slice) => slice.index >= 0 ? count + 1 : count, 0);
1026
1085
  const candidates = GROUP_CANDIDATES.filter((groupBars) => fullBars >= groupBars * MIN_GROUPS);
1027
1086
  if (candidates.length === 0) {
1028
1087
  return undecidedReading(slices);
1029
1088
  }
1030
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0,
1089
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0,
1031
1090
  candidates.reduce((sum, groupBars) => sum + groupBars * slices.length, 0),
1032
1091
  "hypermeter readings",
1033
1092
  asked.budget
1034
1093
  );
1035
- const novelty = slices.map((_, index) => _chunkIFZDWIKMcjs.harmonicNovelty.call(void 0, slices, index));
1036
- const cadenceBars = new Set((_nullishCoalesce(asked.cadenceBeats, () => ( []))).map((beat) => _chunkS5BKZZGMcjs.barIndexAt.call(void 0, beat, meters)));
1037
- const hasCadences = cadenceBars.size > 0;
1094
+ const novelty = slices.map((_, index) => _chunkLQZQDBCDcjs.harmonicNovelty.call(void 0, slices, index));
1095
+ const cadenceBars = cadenceBarsOf(spansOf(asked), meters);
1096
+ const hasCadences = cadenceBars.length > 0;
1038
1097
  const readings = [];
1039
1098
  for (const groupBars of candidates) {
1040
1099
  const phases = Array.from({ length: groupBars }, (_, phase) => ({
1041
1100
  phase,
1042
1101
  contrast: accentContrast(novelty, slices, groupBars, phase),
1043
- cadenceFit: cadenceFitOf(cadenceBars, slices, groupBars, phase)
1102
+ fit: cadenceFitOf(cadenceBars, slices, groupBars, phase)
1044
1103
  }));
1045
- const bestFit = phases.reduce((best2, reading) => Math.max(best2, reading.cadenceFit), 0);
1046
- for (const { phase, contrast, cadenceFit } of phases) {
1047
- if (hasCadences && cadenceFit < bestFit - _chunkS5BKZZGMcjs.BEAT_EPS) {
1104
+ const bestFit = phases.reduce((best2, reading) => Math.max(best2, reading.fit.weighted), 0);
1105
+ for (const { phase, contrast, fit } of phases) {
1106
+ if (hasCadences && fit.weighted < bestFit - _chunkS3QELJUEcjs.BEAT_EPS) {
1048
1107
  continue;
1049
1108
  }
1050
- const evidence = _chunkIFZDWIKMcjs.clamp01.call(void 0,
1109
+ const cadenceFit = fit.closed;
1110
+ const evidence = _chunkLQZQDBCDcjs.clamp01.call(void 0,
1051
1111
  hasCadences ? (
1052
1112
  // Floored at zero rather than summed raw: group heads that restate
1053
1113
  // the harmony their group opened with — the commonest way a phrase
1054
1114
  // begins — change less than the bars between them, and a negative
1055
1115
  // contrast subtracted from the cadence term would count that
1056
1116
  // restatement as evidence against the very phase it confirms.
1057
- CONTRAST_SHARE * _chunkIFZDWIKMcjs.clamp01.call(void 0, contrast) + CADENCE_SHARE * cadenceFit
1117
+ CONTRAST_SHARE * _chunkLQZQDBCDcjs.clamp01.call(void 0, contrast) + CADENCE_SHARE * cadenceFit
1058
1118
  ) : contrast
1059
1119
  );
1060
1120
  readings.push({
@@ -1075,8 +1135,8 @@ function hypermeter(notes, meter, opts = {}) {
1075
1135
  return undecidedReading(slices);
1076
1136
  }
1077
1137
  const runnerUp = readings.find((reading) => reading.groupBars !== best.groupBars);
1078
- const margin = runnerUp === void 0 || best.score <= _chunkS5BKZZGMcjs.BEAT_EPS ? 1 : _chunkIFZDWIKMcjs.clamp01.call(void 0, (best.score - runnerUp.score) / best.score);
1079
- const downbeats = slices.filter((slice) => slice.index >= 0 && _chunkIFZDWIKMcjs.floorMod.call(void 0, slice.index - best.phase, best.groupBars) === 0).map((slice) => slice.startBeat);
1138
+ const margin = runnerUp === void 0 || best.score <= _chunkS3QELJUEcjs.BEAT_EPS ? 1 : _chunkLQZQDBCDcjs.clamp01.call(void 0, (best.score - runnerUp.score) / best.score);
1139
+ const downbeats = slices.filter((slice) => slice.index >= 0 && _chunkLQZQDBCDcjs.floorMod.call(void 0, slice.index - best.phase, best.groupBars) === 0).map((slice) => slice.startBeat);
1080
1140
  const cadencePart = hasCadences ? `${Math.round(best.cadenceFit * 100)}% of group ends closed by a cadence` : "no cadences given";
1081
1141
  return {
1082
1142
  groupBars: best.groupBars,
@@ -1086,7 +1146,7 @@ function hypermeter(notes, meter, opts = {}) {
1086
1146
  // runner-up is nearly always a multiple or a divisor of the winner — four
1087
1147
  // bars nest inside eight — and a reading of the same accents at another
1088
1148
  // level is weaker counter-evidence than an unrelated rival would be.
1089
- confidence: _chunkIFZDWIKMcjs.clamp01.call(void 0, best.evidence * (MARGIN_FLOOR + (1 - MARGIN_FLOOR) * margin)),
1149
+ confidence: _chunkLQZQDBCDcjs.clamp01.call(void 0, best.evidence * (MARGIN_FLOOR + (1 - MARGIN_FLOOR) * margin)),
1090
1150
  rationale: `${best.groupBars}-bar groups from bar ${best.phase}: harmonic change ${Math.round(best.contrast * 100)}% stronger on group heads, ${cadencePart}`
1091
1151
  };
1092
1152
  }
@@ -1118,6 +1178,7 @@ var PHRASE_CUT_COST = 1.3;
1118
1178
  var CLOSING_SHARE = 0.65;
1119
1179
  var FINAL_PHRASE_BONUS = 0.15;
1120
1180
  var HYPERMETRIC_CLOSE_BONUS = 0.1;
1181
+ var IMPERFECT_CLOSURE_FACTOR = 0.8;
1121
1182
  var EVADED_FACTOR = 0.6;
1122
1183
  var SIGNAL_ORDER = [
1123
1184
  "cadence",
@@ -1128,7 +1189,7 @@ var SIGNAL_ORDER = [
1128
1189
  "hypermeter"
1129
1190
  ];
1130
1191
  function addSignal(boundaries, beat, signal, strength, cadence = null) {
1131
- const key = Math.round(beat / _chunkS5BKZZGMcjs.BEAT_EPS);
1192
+ const key = Math.round(beat / _chunkS3QELJUEcjs.BEAT_EPS);
1132
1193
  const existing = boundaries.get(key);
1133
1194
  const boundary = _nullishCoalesce(existing, () => ( { beat, strengths: /* @__PURE__ */ new Map(), cadence: null }));
1134
1195
  boundary.strengths.set(signal, Math.max(_nullishCoalesce(boundary.strengths.get(signal), () => ( 0)), strength));
@@ -1142,17 +1203,23 @@ function readBoundary(boundary) {
1142
1203
  (a, b) => b[1] - a[1] || SIGNAL_ORDER.indexOf(a[0]) - SIGNAL_ORDER.indexOf(b[0])
1143
1204
  );
1144
1205
  return {
1145
- strength: _chunkIFZDWIKMcjs.combineEvidence.call(void 0, signals.map(([, strength]) => strength)),
1206
+ strength: _chunkLQZQDBCDcjs.combineEvidence.call(void 0, signals.map(([, strength]) => strength)),
1207
+ uncredited: _chunkLQZQDBCDcjs.combineEvidence.call(void 0,
1208
+ signals.filter(([signal]) => signal !== "cadence").map(([, strength]) => strength)
1209
+ ),
1146
1210
  signals: signals.map(([signal]) => signal)
1147
1211
  };
1148
1212
  }
1213
+ function closesPhrase(atBeat, startBeat, endBeat) {
1214
+ return atBeat >= startBeat - _chunkS3QELJUEcjs.BEAT_EPS && atBeat < endBeat - _chunkS3QELJUEcjs.BEAT_EPS;
1215
+ }
1149
1216
  function lengthFit(length, expected) {
1150
1217
  if (!(expected > 0)) {
1151
1218
  return 0;
1152
1219
  }
1153
1220
  return Math.max(-1, 1 - Math.abs(length - expected) / expected);
1154
1221
  }
1155
- function choosePhrasePath(beats, strengths, minPhraseBeats, expected) {
1222
+ function choosePhrasePath(beats, strengths, minPhraseBeats, expected, held) {
1156
1223
  const value = new Array(beats.length).fill(Number.NEGATIVE_INFINITY);
1157
1224
  const cameFrom = new Array(beats.length).fill(-1);
1158
1225
  value[0] = 0;
@@ -1163,10 +1230,12 @@ function choosePhrasePath(beats, strengths, minPhraseBeats, expected) {
1163
1230
  continue;
1164
1231
  }
1165
1232
  const length = endBeat - (_nullishCoalesce(beats[i], () => ( 0)));
1166
- if (length < minPhraseBeats - _chunkS5BKZZGMcjs.BEAT_EPS) {
1233
+ if (length < minPhraseBeats - _chunkS3QELJUEcjs.BEAT_EPS) {
1167
1234
  continue;
1168
1235
  }
1169
- const gain = (_nullishCoalesce(value[i], () => ( 0))) + (_nullishCoalesce(strengths[j], () => ( 0))) + lengthFit(length, expected) - PHRASE_CUT_COST;
1236
+ const credited = held === void 0 || closesPhrase(_nullishCoalesce(held.arrivals[j], () => ( endBeat)), _nullishCoalesce(beats[i], () => ( 0)), endBeat);
1237
+ const strength = credited ? _nullishCoalesce(strengths[j], () => ( 0)) : _nullishCoalesce(held.uncredited[j], () => ( 0));
1238
+ const gain = (_nullishCoalesce(value[i], () => ( 0))) + strength + lengthFit(length, expected) - PHRASE_CUT_COST;
1170
1239
  if (gain > (_nullishCoalesce(value[j], () => ( Number.NEGATIVE_INFINITY)))) {
1171
1240
  value[j] = gain;
1172
1241
  cameFrom[j] = i;
@@ -1185,33 +1254,47 @@ function choosePhrasePath(beats, strengths, minPhraseBeats, expected) {
1185
1254
  }
1186
1255
  return path;
1187
1256
  }
1188
- function arrivalEnd(timeline, atBeat) {
1189
- return _nullishCoalesce(_optionalChain([_chunkIFZDWIKMcjs.segmentStartingAt.call(void 0, timeline.segments, atBeat), 'optionalAccess', _43 => _43.endBeat]), () => ( atBeat));
1257
+ function boundaryCadences(timeline, key) {
1258
+ const hits = _chunkLQZQDBCDcjs.detectCadences.call(void 0, timeline, key).filter((hit) => hit.cadence.type !== null);
1259
+ const spans = cadenceSpans(
1260
+ hits.map((hit) => ({
1261
+ atBeat: hit.atBeat,
1262
+ strength: CADENCE_BOUNDARY_STRENGTH[hit.cadence.type]
1263
+ })),
1264
+ timeline.segments
1265
+ );
1266
+ return { hits, spans };
1267
+ }
1268
+ function keyContextFor(key, timeline, meters, totalBeats, budget) {
1269
+ if (key !== void 0) {
1270
+ return key;
1271
+ }
1272
+ const regions = _chunkLQZQDBCDcjs.detectModulations.call(void 0, timeline.segments, { meters, totalBeats, budget });
1273
+ const keyAt = _chunkLQZQDBCDcjs.keyLookup.call(void 0, regions, _nullishCoalesce(_chunkLQZQDBCDcjs.prevailingKeyOf.call(void 0, regions), () => ( _chunkYDGMWH43cjs.resolveKey.call(void 0, _chunkYDGMWH43cjs.majorKey.call(void 0, 0)))));
1274
+ return (beat) => _chunkYDGMWH43cjs.scaleOf.call(void 0, keyAt(beat));
1190
1275
  }
1191
- function keyContextFor(opts, notes, meters, totalBeats) {
1192
- if (opts.key !== void 0) {
1193
- return opts.key;
1276
+ function heldCadenceBoundaries(boundaries, hit, span, meters, spanEnd) {
1277
+ const firstLine = _chunkS3QELJUEcjs.barIndexAt.call(void 0, span.atBeat, meters) + 1;
1278
+ const lastLine = _chunkS3QELJUEcjs.barIndexAt.call(void 0, Math.min(span.endBeat, spanEnd), meters);
1279
+ for (let bar = firstLine; bar <= lastLine; bar += 1) {
1280
+ const line = _chunkS3QELJUEcjs.barPositionToBeat.call(void 0, { bar, beat: 0 }, meters);
1281
+ if (line < span.endBeat - _chunkS3QELJUEcjs.BEAT_EPS) {
1282
+ addSignal(boundaries, line, "cadence", span.strength, hit);
1283
+ }
1194
1284
  }
1195
- const regions = _chunkIFZDWIKMcjs.keyTimelineFromNotes.call(void 0, notes, {
1196
- meters,
1197
- totalBeats,
1198
- budget: opts.budget
1199
- });
1200
- const keyAt = _chunkIFZDWIKMcjs.keyLookup.call(void 0, regions, _nullishCoalesce(_chunkIFZDWIKMcjs.prevailingKeyOf.call(void 0, regions), () => ( _chunk3R3QVKY5cjs.resolveKey.call(void 0, _chunk3R3QVKY5cjs.majorKey.call(void 0, 0)))));
1201
- return (beat) => _chunk3R3QVKY5cjs.scaleOf.call(void 0, keyAt(beat));
1202
1285
  }
1203
1286
  function restBoundaries(boundaries, notes, meters, restBeats) {
1204
1287
  const ordered = [...notes].sort((a, b) => a.startBeat - b.startBeat || a.pitch - b.pitch);
1205
1288
  let covered = Number.NEGATIVE_INFINITY;
1206
1289
  for (const note of ordered) {
1207
1290
  const gap = note.startBeat - covered;
1208
- if (Number.isFinite(covered) && gap >= restBeats - _chunkS5BKZZGMcjs.BEAT_EPS) {
1209
- const bar = _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, note.startBeat, meters);
1291
+ if (Number.isFinite(covered) && gap >= restBeats - _chunkS3QELJUEcjs.BEAT_EPS) {
1292
+ const bar = _chunkS3QELJUEcjs.beatsPerBarAt.call(void 0, note.startBeat, meters);
1210
1293
  addSignal(
1211
1294
  boundaries,
1212
1295
  note.startBeat,
1213
1296
  "rest",
1214
- REST_STRENGTH * _chunkIFZDWIKMcjs.clamp01.call(void 0, bar > 0 ? gap / bar : 1)
1297
+ REST_STRENGTH * _chunkLQZQDBCDcjs.clamp01.call(void 0, bar > 0 ? gap / bar : 1)
1215
1298
  );
1216
1299
  }
1217
1300
  covered = Math.max(covered, note.startBeat + note.durationBeat);
@@ -1221,13 +1304,13 @@ function repetitionBoundaries(boundaries, notes, meters, spanStart, spanEnd, win
1221
1304
  if (!(windowBeats > 0)) {
1222
1305
  return;
1223
1306
  }
1224
- const slices = _chunkIFZDWIKMcjs.sliceBars.call(void 0, notes, meters, spanStart, spanEnd, budget);
1225
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, slices.length * notes.length, "form repetition comparisons", budget);
1226
- const onsetsIn = (from, to) => notes.filter((note) => note.startBeat >= from - _chunkS5BKZZGMcjs.BEAT_EPS && note.startBeat < to - _chunkS5BKZZGMcjs.BEAT_EPS);
1307
+ const slices = _chunkLQZQDBCDcjs.sliceBars.call(void 0, notes, meters, spanStart, spanEnd, budget);
1308
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, slices.length * notes.length, "form repetition comparisons", budget);
1309
+ const onsetsIn = (from, to) => notes.filter((note) => note.startBeat >= from - _chunkS3QELJUEcjs.BEAT_EPS && note.startBeat < to - _chunkS3QELJUEcjs.BEAT_EPS);
1227
1310
  let comparisons = 0;
1228
1311
  for (const slice of slices) {
1229
1312
  const beat = slice.startBeat;
1230
- if (beat - windowBeats < spanStart - _chunkS5BKZZGMcjs.BEAT_EPS || beat + windowBeats > spanEnd + _chunkS5BKZZGMcjs.BEAT_EPS) {
1313
+ if (beat - windowBeats < spanStart - _chunkS3QELJUEcjs.BEAT_EPS || beat + windowBeats > spanEnd + _chunkS3QELJUEcjs.BEAT_EPS) {
1231
1314
  continue;
1232
1315
  }
1233
1316
  const before = onsetsIn(beat - windowBeats, beat);
@@ -1236,8 +1319,8 @@ function repetitionBoundaries(boundaries, notes, meters, spanStart, spanEnd, win
1236
1319
  continue;
1237
1320
  }
1238
1321
  comparisons += before.length * after.length;
1239
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, comparisons, "form repetition melody comparisons", budget);
1240
- const similarity = _chunkIFZDWIKMcjs.melodicSimilarity.call(void 0, before, after);
1322
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, comparisons, "form repetition melody comparisons", budget);
1323
+ const similarity = _chunkLQZQDBCDcjs.melodicSimilarity.call(void 0, before, after);
1241
1324
  if (similarity >= REPETITION_THRESHOLD) {
1242
1325
  addSignal(boundaries, beat, "repetition", REPETITION_STRENGTH * similarity);
1243
1326
  }
@@ -1253,7 +1336,7 @@ function structuralWeightOf(cadence, confidence, aligned, isLast) {
1253
1336
  if (result.strength === "perfect") {
1254
1337
  base = 1;
1255
1338
  } else if (result.strength === "imperfect") {
1256
- base *= 0.8;
1339
+ base *= IMPERFECT_CLOSURE_FACTOR;
1257
1340
  }
1258
1341
  }
1259
1342
  if (result.evaded) {
@@ -1266,7 +1349,7 @@ function structuralWeightOf(cadence, confidence, aligned, isLast) {
1266
1349
  if (aligned) {
1267
1350
  weight += HYPERMETRIC_CLOSE_BONUS;
1268
1351
  }
1269
- return _chunkIFZDWIKMcjs.clamp01.call(void 0, weight);
1352
+ return _chunkLQZQDBCDcjs.clamp01.call(void 0, weight);
1270
1353
  }
1271
1354
  function describeCadence(cadence) {
1272
1355
  if (cadence === null || cadence.cadence.type === null) {
@@ -1277,72 +1360,61 @@ function describeCadence(cadence) {
1277
1360
  return `a ${graded} cadence at beat ${cadence.atBeat}`;
1278
1361
  }
1279
1362
  function phrasesFromTimeline(timeline, notes, opts = {}) {
1280
- _chunkIFZDWIKMcjs.assertChordTimeline.call(void 0, timeline);
1281
- const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "phrase meters");
1282
- _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "phrase notes", {
1363
+ _chunkLQZQDBCDcjs.assertChordTimeline.call(void 0, timeline);
1364
+ const meters = _chunkS3QELJUEcjs.resolveMeters.call(void 0, opts, "phrase meters");
1365
+ _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, notes, "phrase notes", {
1283
1366
  allowNonPositiveDuration: true,
1284
1367
  budget: opts.budget
1285
1368
  });
1286
1369
  if (opts.hypermeter !== void 0) {
1287
- _chunkS5BKZZGMcjs.assertRange.call(void 0, opts.hypermeter.confidence, 0, 1, "phrase hypermeter confidence");
1288
- _chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, opts.hypermeter.groupBars, "phrase hypermeter groupBars");
1370
+ _chunkS3QELJUEcjs.assertRange.call(void 0, opts.hypermeter.confidence, 0, 1, "phrase hypermeter confidence");
1371
+ _chunkS3QELJUEcjs.assertPositiveInt.call(void 0, opts.hypermeter.groupBars, "phrase hypermeter groupBars");
1289
1372
  }
1290
1373
  const sounding = notes.filter((note) => note.durationBeat > 0);
1291
1374
  const segments = timeline.segments;
1292
1375
  const firstSegment = segments[0];
1293
1376
  const lastSegment = segments[segments.length - 1];
1294
- const firstOnset = sounding.reduce(
1295
- (first, n) => Math.min(first, n.startBeat),
1296
- _nullishCoalesce(_optionalChain([firstSegment, 'optionalAccess', _44 => _44.startBeat]), () => ( 0))
1377
+ const earliest = Math.min(
1378
+ _chunkLQZQDBCDcjs.firstSoundingBeat.call(void 0, sounding, Number.POSITIVE_INFINITY),
1379
+ _nullishCoalesce(_optionalChain([firstSegment, 'optionalAccess', _44 => _44.startBeat]), () => ( Number.POSITIVE_INFINITY))
1297
1380
  );
1298
- const spanStart = _chunkIFZDWIKMcjs.barGridStart.call(void 0, firstOnset, meters);
1299
- const notesEnd = sounding.reduce(
1300
- (end, n) => Math.max(end, n.startBeat + n.durationBeat),
1301
- _nullishCoalesce(_optionalChain([lastSegment, 'optionalAccess', _45 => _45.endBeat]), () => ( 0))
1381
+ const firstOnset = Number.isFinite(earliest) ? earliest : 0;
1382
+ const spanStart = _chunkLQZQDBCDcjs.barGridStart.call(void 0, firstOnset, meters);
1383
+ const latestEnd = Math.max(
1384
+ _nullishCoalesce(_optionalChain([lastSegment, 'optionalAccess', _45 => _45.endBeat]), () => ( Number.NEGATIVE_INFINITY)),
1385
+ _chunkLQZQDBCDcjs.latestSoundingEnd.call(void 0, sounding, Number.NEGATIVE_INFINITY)
1302
1386
  );
1303
- const spanEnd = Math.max(spanStart, _nullishCoalesce(opts.totalBeats, () => ( notesEnd)));
1304
- _chunkS5BKZZGMcjs.assertRange.call(void 0, spanEnd, 0, Number.MAX_SAFE_INTEGER, "phrase totalBeats");
1305
- if (spanEnd <= spanStart + _chunkS5BKZZGMcjs.BEAT_EPS) {
1387
+ const notesEnd = Number.isFinite(latestEnd) ? latestEnd : 0;
1388
+ const spanEnd = _chunkLQZQDBCDcjs.resolveSpanEnd.call(void 0, opts.totalBeats, spanStart, notesEnd, "phrase totalBeats");
1389
+ if (spanEnd <= spanStart + _chunkS3QELJUEcjs.BEAT_EPS) {
1306
1390
  return [];
1307
1391
  }
1308
- const barBeats = _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, Math.max(0, spanStart), meters);
1392
+ const barBeats = _chunkS3QELJUEcjs.beatsPerBarAt.call(void 0, Math.max(0, spanStart), meters);
1309
1393
  const restBeats = _nullishCoalesce(opts.restBeats, () => ( barBeats / 2));
1310
- _chunkS5BKZZGMcjs.assertRange.call(void 0, restBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase restBeats");
1394
+ _chunkS3QELJUEcjs.assertRange.call(void 0, restBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase restBeats");
1311
1395
  const longNoteBeats = _nullishCoalesce(opts.longNoteBeats, () => ( barBeats));
1312
- _chunkS5BKZZGMcjs.assertRange.call(void 0, longNoteBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase longNoteBeats");
1396
+ _chunkS3QELJUEcjs.assertRange.call(void 0, longNoteBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase longNoteBeats");
1313
1397
  const minPhraseBeats = _nullishCoalesce(opts.minPhraseBeats, () => ( barBeats));
1314
- _chunkS5BKZZGMcjs.assertRange.call(void 0, minPhraseBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase minPhraseBeats");
1315
- const key = keyContextFor(opts, sounding, meters, spanEnd);
1316
- const cadences = _chunkIFZDWIKMcjs.detectCadences.call(void 0, timeline, key);
1317
- const grouping = _nullishCoalesce(opts.hypermeter, () => ( hypermeter(sounding, meters, {
1318
- totalBeats: spanEnd,
1319
- cadenceBeats: cadences.map((hit) => hit.atBeat),
1320
- budget: opts.budget
1321
- })));
1322
- const firstBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, Math.max(0, spanStart), meters);
1398
+ _chunkS3QELJUEcjs.assertRange.call(void 0, minPhraseBeats, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase minPhraseBeats");
1399
+ const key = keyContextFor(opts.key, timeline, meters, spanEnd, opts.budget);
1400
+ const { hits: cadences, spans } = boundaryCadences(timeline, key);
1401
+ const grouping = _nullishCoalesce(opts.hypermeter, () => ( hypermeterOver(sounding, meters, { totalBeats: spanEnd, budget: opts.budget }, () => spans)));
1402
+ const firstBar = _chunkS3QELJUEcjs.barIndexAt.call(void 0, Math.max(0, spanStart), meters);
1323
1403
  const hyperBeats = Math.max(
1324
1404
  barBeats,
1325
- _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar: firstBar + grouping.groupBars, beat: 0 }, meters) - _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar: firstBar, beat: 0 }, meters)
1405
+ _chunkS3QELJUEcjs.barPositionToBeat.call(void 0, { bar: firstBar + grouping.groupBars, beat: 0 }, meters) - _chunkS3QELJUEcjs.barPositionToBeat.call(void 0, { bar: firstBar, beat: 0 }, meters)
1326
1406
  );
1327
1407
  const expected = _nullishCoalesce(opts.expectedPhraseBeats, () => ( hyperBeats));
1328
- _chunkS5BKZZGMcjs.assertRange.call(void 0, expected, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase expectedPhraseBeats");
1408
+ _chunkS3QELJUEcjs.assertRange.call(void 0, expected, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "phrase expectedPhraseBeats");
1329
1409
  const boundaries = /* @__PURE__ */ new Map();
1330
- for (const hit of cadences) {
1331
- const type = hit.cadence.type;
1332
- if (type === null) {
1333
- continue;
1334
- }
1335
- const strength = CADENCE_BOUNDARY_STRENGTH[type];
1336
- const chordEnd = arrivalEnd(timeline, hit.atBeat);
1337
- addSignal(boundaries, chordEnd, "cadence", strength, hit);
1338
- const barEnd = _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar: _chunkS5BKZZGMcjs.barIndexAt.call(void 0, hit.atBeat, meters) + 1, beat: 0 }, meters);
1339
- if (chordEnd > barEnd + _chunkS5BKZZGMcjs.BEAT_EPS) {
1340
- addSignal(boundaries, barEnd, "cadence", strength, hit);
1341
- }
1342
- }
1410
+ cadences.forEach((hit, index) => {
1411
+ const span = spans[index];
1412
+ addSignal(boundaries, span.endBeat, "cadence", span.strength, hit);
1413
+ heldCadenceBoundaries(boundaries, hit, span, meters, spanEnd);
1414
+ });
1343
1415
  restBoundaries(boundaries, sounding, meters, restBeats);
1344
1416
  for (const note of sounding) {
1345
- if (note.durationBeat >= longNoteBeats - _chunkS5BKZZGMcjs.BEAT_EPS) {
1417
+ if (note.durationBeat >= longNoteBeats - _chunkS3QELJUEcjs.BEAT_EPS) {
1346
1418
  addSignal(boundaries, note.startBeat + note.durationBeat, "longNote", LONG_NOTE_STRENGTH);
1347
1419
  }
1348
1420
  }
@@ -1352,9 +1424,9 @@ function phrasesFromTimeline(timeline, notes, opts = {}) {
1352
1424
  }
1353
1425
  addSignal(boundaries, spanEnd, "pieceEnd", PIECE_END_STRENGTH);
1354
1426
  const candidates = [...boundaries.values()].filter(
1355
- (boundary) => boundary.beat > spanStart + _chunkS5BKZZGMcjs.BEAT_EPS && boundary.beat < spanEnd - _chunkS5BKZZGMcjs.BEAT_EPS
1427
+ (boundary) => boundary.beat > spanStart + _chunkS3QELJUEcjs.BEAT_EPS && boundary.beat < spanEnd - _chunkS3QELJUEcjs.BEAT_EPS
1356
1428
  ).filter((boundary) => readBoundary(boundary).strength > 0).sort((a, b) => a.beat - b.beat);
1357
- const endBoundary = _nullishCoalesce(boundaries.get(Math.round(spanEnd / _chunkS5BKZZGMcjs.BEAT_EPS)), () => ( {
1429
+ const endBoundary = _nullishCoalesce(boundaries.get(Math.round(spanEnd / _chunkS3QELJUEcjs.BEAT_EPS)), () => ( {
1358
1430
  beat: spanEnd,
1359
1431
  strengths: /* @__PURE__ */ new Map(),
1360
1432
  cadence: null
@@ -1364,40 +1436,45 @@ function phrasesFromTimeline(timeline, notes, opts = {}) {
1364
1436
  ...candidates,
1365
1437
  endBoundary
1366
1438
  ];
1367
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, stops.length * stops.length, "form phrase boundary pairs", opts.budget);
1439
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, stops.length * stops.length, "form phrase boundary pairs", opts.budget);
1368
1440
  const readings = stops.map(readBoundary);
1369
1441
  const path = choosePhrasePath(
1370
1442
  stops.map((stop) => stop.beat),
1371
1443
  readings.map((reading) => reading.strength),
1372
1444
  minPhraseBeats,
1373
- expected
1445
+ expected,
1446
+ {
1447
+ arrivals: stops.map((stop) => _nullishCoalesce(_optionalChain([stop, 'access', _46 => _46.cadence, 'optionalAccess', _47 => _47.atBeat]), () => ( stop.beat))),
1448
+ uncredited: readings.map((reading) => reading.uncredited)
1449
+ }
1374
1450
  );
1375
1451
  const downbeatKeys = new Set(
1376
- grouping.downbeats.map((downbeat) => Math.round(downbeat / _chunkS5BKZZGMcjs.BEAT_EPS))
1452
+ grouping.downbeats.map((downbeat) => Math.round(downbeat / _chunkS3QELJUEcjs.BEAT_EPS))
1377
1453
  );
1378
1454
  const phrases = [];
1379
1455
  let from = 0;
1380
1456
  for (let n = 0; n < path.length; n += 1) {
1381
1457
  const to = _nullishCoalesce(path[n], () => ( stops.length - 1));
1382
- const startBeat = _nullishCoalesce(_optionalChain([stops, 'access', _46 => _46[from], 'optionalAccess', _47 => _47.beat]), () => ( spanStart));
1458
+ const startBeat = _nullishCoalesce(_optionalChain([stops, 'access', _48 => _48[from], 'optionalAccess', _49 => _49.beat]), () => ( spanStart));
1383
1459
  const stop = stops[to];
1384
- const endBeat = _nullishCoalesce(_optionalChain([stop, 'optionalAccess', _48 => _48.beat]), () => ( spanEnd));
1385
- const reading = _nullishCoalesce(readings[to], () => ( { strength: 0, signals: [] }));
1460
+ const endBeat = _nullishCoalesce(_optionalChain([stop, 'optionalAccess', _50 => _50.beat]), () => ( spanEnd));
1461
+ const reading = _nullishCoalesce(readings[to], () => ( { strength: 0, uncredited: 0, signals: [] }));
1386
1462
  const length = endBeat - startBeat;
1387
- const confidence = _chunkIFZDWIKMcjs.clamp01.call(void 0,
1388
- CLOSING_SHARE * reading.strength + (1 - CLOSING_SHARE) * Math.max(0, lengthFit(length, expected))
1389
- );
1390
1463
  const isLast = n === path.length - 1;
1391
- const closing = _nullishCoalesce(_optionalChain([stop, 'optionalAccess', _49 => _49.cadence]), () => ( null));
1392
- const cadence = closing !== null && closing.atBeat >= startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && closing.atBeat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS ? closing : null;
1464
+ const closing = _nullishCoalesce(_optionalChain([stop, 'optionalAccess', _51 => _51.cadence]), () => ( null));
1465
+ const cadence = closing !== null && closesPhrase(closing.atBeat, startBeat, endBeat) ? closing : null;
1466
+ const closingStrength = cadence === null ? reading.uncredited : reading.strength;
1467
+ const confidence = _chunkLQZQDBCDcjs.clamp01.call(void 0,
1468
+ CLOSING_SHARE * closingStrength + (1 - CLOSING_SHARE) * Math.max(0, lengthFit(length, expected))
1469
+ );
1393
1470
  const structuralWeight = structuralWeightOf(
1394
1471
  cadence,
1395
1472
  confidence,
1396
- downbeatKeys.has(Math.round(endBeat / _chunkS5BKZZGMcjs.BEAT_EPS)),
1473
+ downbeatKeys.has(Math.round(endBeat / _chunkS3QELJUEcjs.BEAT_EPS)),
1397
1474
  isLast
1398
1475
  );
1399
1476
  const signals = cadence === null ? reading.signals.filter((signal) => signal !== "cadence") : reading.signals;
1400
- const bars = Math.round(_chunkIFZDWIKMcjs.barSpanOf.call(void 0, startBeat, endBeat, meters) * 100) / 100;
1477
+ const bars = Math.round(_chunkLQZQDBCDcjs.barSpanOf.call(void 0, startBeat, endBeat, meters) * 100) / 100;
1401
1478
  phrases.push({
1402
1479
  startBeat,
1403
1480
  endBeat,
@@ -1412,10 +1489,10 @@ function phrasesFromTimeline(timeline, notes, opts = {}) {
1412
1489
  return phrases;
1413
1490
  }
1414
1491
  function structuralCadences(phrases) {
1415
- _chunkS5BKZZGMcjs.assertArray.call(void 0, phrases, "phrases");
1492
+ _chunkS3QELJUEcjs.assertArray.call(void 0, phrases, "phrases");
1416
1493
  const ranked = [];
1417
1494
  for (let index = 0; index < phrases.length; index += 1) {
1418
- const phrase = _chunkS5BKZZGMcjs.assertRecord.call(void 0, phrases[index], `phrases[${index}]`);
1495
+ const phrase = _chunkS3QELJUEcjs.assertRecord.call(void 0, phrases[index], `phrases[${index}]`);
1419
1496
  if (phrase.cadence === null || phrase.cadence === void 0 || phrase.cadence.cadence.type === null) {
1420
1497
  continue;
1421
1498
  }
@@ -1449,50 +1526,55 @@ function isSilent(unit) {
1449
1526
  return unit.notes.length === 0;
1450
1527
  }
1451
1528
  function unitSimilarity(a, b) {
1452
- const harmony = _chunkIFZDWIKMcjs.weightSimilarity.call(void 0, a.weights, b.weights);
1529
+ const harmony = _chunkLQZQDBCDcjs.weightSimilarity.call(void 0, a.weights, b.weights);
1453
1530
  if (a.notes.length < 2 || b.notes.length < 2) {
1454
1531
  return a.notes.length === b.notes.length ? harmony : 0;
1455
1532
  }
1456
- const melody = _chunkIFZDWIKMcjs.melodicSimilarity.call(void 0, a.notes, b.notes);
1457
- return _chunkIFZDWIKMcjs.clamp01.call(void 0, MELODY_SHARE * melody + HARMONY_SHARE * harmony);
1533
+ const melody = _chunkLQZQDBCDcjs.melodicSimilarity.call(void 0, a.notes, b.notes);
1534
+ return _chunkLQZQDBCDcjs.clamp01.call(void 0, MELODY_SHARE * melody + HARMONY_SHARE * harmony);
1458
1535
  }
1459
1536
  function sectionsFromNotes(notes, opts = {}) {
1460
- const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, opts, "section meters");
1461
- _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "section notes", {
1537
+ const meters = _chunkS3QELJUEcjs.resolveMeters.call(void 0, opts, "section meters");
1538
+ _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, notes, "section notes", {
1462
1539
  allowNonPositiveDuration: true,
1463
1540
  budget: opts.budget
1464
1541
  });
1465
1542
  const sounding = notes.filter((note) => note.durationBeat > 0);
1543
+ const firstSounding = _chunkLQZQDBCDcjs.firstSoundingBeat.call(void 0, sounding);
1544
+ const firstOnset = _chunkLQZQDBCDcjs.barGridStart.call(void 0, firstSounding, meters);
1545
+ const spanEnd = _chunkLQZQDBCDcjs.resolveSpanEnd.call(void 0,
1546
+ opts.totalBeats,
1547
+ firstOnset,
1548
+ _chunkLQZQDBCDcjs.latestSoundingEnd.call(void 0, sounding),
1549
+ "section totalBeats"
1550
+ );
1466
1551
  if (sounding.length === 0) {
1467
1552
  return [];
1468
1553
  }
1469
- const firstOnset = _chunkIFZDWIKMcjs.barGridStart.call(void 0, _chunkIFZDWIKMcjs.firstSoundingBeat.call(void 0, sounding), meters);
1470
- const lastEnd = sounding.reduce((end, n) => Math.max(end, n.startBeat + n.durationBeat), 0);
1471
- const spanEnd = Math.max(firstOnset, _nullishCoalesce(opts.totalBeats, () => ( lastEnd)));
1472
- _chunkS5BKZZGMcjs.assertRange.call(void 0, spanEnd, 0, Number.MAX_SAFE_INTEGER, "section totalBeats");
1473
1554
  const threshold = _nullishCoalesce(opts.threshold, () => ( DEFAULT_THRESHOLD));
1474
- _chunkS5BKZZGMcjs.assertRange.call(void 0, threshold, 0, 1, "section threshold");
1555
+ _chunkS3QELJUEcjs.assertRange.call(void 0, threshold, 0, 1, "section threshold");
1475
1556
  const unitBars = _nullishCoalesce(opts.unitBars, () => ( hypermeter(sounding, meters, { totalBeats: spanEnd, budget: opts.budget }).groupBars));
1476
- _chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, unitBars, "section unitBars");
1477
- const firstBar = _chunkS5BKZZGMcjs.barIndexAt.call(void 0, firstOnset, meters);
1478
- const lastBar = _chunkIFZDWIKMcjs.lastBarOf.call(void 0, meters, firstOnset, spanEnd);
1557
+ _chunkS3QELJUEcjs.assertPositiveInt.call(void 0, unitBars, "section unitBars");
1558
+ const firstBar = _chunkS3QELJUEcjs.barIndexAt.call(void 0, firstOnset, meters);
1559
+ const lastBar = _chunkLQZQDBCDcjs.lastBarOf.call(void 0, meters, firstOnset, spanEnd);
1479
1560
  const startBar = Math.max(0, firstBar);
1480
1561
  const unitCount = Math.max(1, Math.ceil((lastBar - startBar + 1) / unitBars));
1481
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, unitCount * unitCount, "form section comparisons", opts.budget);
1482
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, unitCount * sounding.length, "form section unit notes", opts.budget);
1562
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, unitCount * unitCount, "form section comparisons", opts.budget);
1563
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, unitCount * sounding.length, "form section unit notes", opts.budget);
1483
1564
  const units = [];
1484
1565
  for (let index = 0; index < unitCount; index += 1) {
1485
1566
  const barStart = startBar + index * unitBars;
1486
- const startBeat = index === 0 ? firstOnset : _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar: barStart, beat: 0 }, meters);
1487
- const endBeat = index === unitCount - 1 ? spanEnd : _chunkS5BKZZGMcjs.barPositionToBeat.call(void 0, { bar: barStart + unitBars, beat: 0 }, meters);
1567
+ const startBeat = index === 0 ? firstOnset : _chunkS3QELJUEcjs.barPositionToBeat.call(void 0, { bar: barStart, beat: 0 }, meters);
1568
+ const endBeat = index === unitCount - 1 ? spanEnd : _chunkS3QELJUEcjs.barPositionToBeat.call(void 0, { bar: barStart + unitBars, beat: 0 }, meters);
1569
+ const fromBeat = index === 0 ? Math.min(firstSounding, startBeat) : startBeat;
1488
1570
  const unitNotes = sounding.filter(
1489
- (note) => note.startBeat >= startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && note.startBeat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
1571
+ (note) => note.startBeat >= fromBeat - _chunkS3QELJUEcjs.BEAT_EPS && note.startBeat < endBeat - _chunkS3QELJUEcjs.BEAT_EPS
1490
1572
  ).sort((a, b) => a.startBeat - b.startBeat || a.pitch - b.pitch);
1491
1573
  units.push({
1492
1574
  startBeat,
1493
1575
  endBeat,
1494
1576
  notes: unitNotes,
1495
- weights: _chunkIFZDWIKMcjs.windowWeights.call(void 0, unitNotes, startBeat, endBeat, meters).weights
1577
+ weights: _chunkLQZQDBCDcjs.windowWeights.call(void 0, unitNotes, startBeat, endBeat, meters).weights
1496
1578
  });
1497
1579
  }
1498
1580
  let comparisons = 0;
@@ -1501,7 +1583,7 @@ function sectionsFromNotes(notes, opts = {}) {
1501
1583
  comparisons += unit.notes.length * earlierNotes;
1502
1584
  earlierNotes += unit.notes.length;
1503
1585
  }
1504
- _chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, comparisons, "form section melody comparisons", opts.budget);
1586
+ _chunkS3QELJUEcjs.assertGenerationBudget.call(void 0, comparisons, "form section melody comparisons", opts.budget);
1505
1587
  const labels = [];
1506
1588
  const scores = [];
1507
1589
  let distinct = 0;
@@ -1556,8 +1638,8 @@ function sectionsFromNotes(notes, opts = {}) {
1556
1638
  while (end < units.length && labels[end] === null) {
1557
1639
  end += 1;
1558
1640
  }
1559
- const startBeat = _nullishCoalesce(_optionalChain([units, 'access', _50 => _50[index], 'optionalAccess', _51 => _51.startBeat]), () => ( 0));
1560
- const endBeat = _nullishCoalesce(_optionalChain([units, 'access', _52 => _52[end - 1], 'optionalAccess', _53 => _53.endBeat]), () => ( spanEnd));
1641
+ const startBeat = _nullishCoalesce(_optionalChain([units, 'access', _52 => _52[index], 'optionalAccess', _53 => _53.startBeat]), () => ( 0));
1642
+ const endBeat = _nullishCoalesce(_optionalChain([units, 'access', _54 => _54[end - 1], 'optionalAccess', _55 => _55.endBeat]), () => ( spanEnd));
1561
1643
  const sectionFirstBar = startBar + index * unitBars;
1562
1644
  const sectionLastBar = Math.max(
1563
1645
  sectionFirstBar,
@@ -1568,7 +1650,7 @@ function sectionsFromNotes(notes, opts = {}) {
1568
1650
  if (first === void 0) {
1569
1651
  firstByLabel.set(label, sectionIndex);
1570
1652
  }
1571
- const similarity = first === void 0 ? 1 : _chunkIFZDWIKMcjs.clamp01.call(void 0, scoreSum / Math.max(1, sounded));
1653
+ const similarity = first === void 0 ? 1 : _chunkLQZQDBCDcjs.clamp01.call(void 0, scoreSum / Math.max(1, sounded));
1572
1654
  sections.push({
1573
1655
  label,
1574
1656
  startBeat,
@@ -1576,7 +1658,7 @@ function sectionsFromNotes(notes, opts = {}) {
1576
1658
  bars: sectionLastBar - sectionFirstBar + 1,
1577
1659
  firstOccurrence: _nullishCoalesce(first, () => ( sectionIndex)),
1578
1660
  similarity,
1579
- rationale: first === void 0 ? `Section ${label}: material first heard at beat ${startBeat}` : `Section ${label}: ${Math.round(similarity * 100)}% alike the ${label} at beat ${_nullishCoalesce(_optionalChain([sections, 'access', _54 => _54[first], 'optionalAccess', _55 => _55.startBeat]), () => ( 0))}`
1661
+ rationale: first === void 0 ? `Section ${label}: material first heard at beat ${startBeat}` : `Section ${label}: ${Math.round(similarity * 100)}% alike the ${label} at beat ${_nullishCoalesce(_optionalChain([sections, 'access', _56 => _56[first], 'optionalAccess', _57 => _57.startBeat]), () => ( 0))}`
1580
1662
  });
1581
1663
  index = end;
1582
1664
  }
@@ -1603,51 +1685,51 @@ function rationaleOf(comparison) {
1603
1685
  return `Most alike: ${describe(highest.slice(0, RATIONALE_FIELDS))}; least alike: ${describe(lowest.slice(0, RATIONALE_FIELDS))}`;
1604
1686
  }
1605
1687
  function compareReferences(a, b, opts) {
1606
- _chunkIFZDWIKMcjs.assertReferenceProfile.call(void 0, a, "reference profile a");
1607
- _chunkIFZDWIKMcjs.assertReferenceProfile.call(void 0, b, "reference profile b");
1608
- const { budget } = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "compare options");
1688
+ _chunkLQZQDBCDcjs.assertReferenceProfile.call(void 0, a, "reference profile a");
1689
+ _chunkLQZQDBCDcjs.assertReferenceProfile.call(void 0, b, "reference profile b");
1690
+ const { budget } = _chunkS3QELJUEcjs.assertOptions.call(void 0, opts, "compare options");
1609
1691
  const structural = (profile) => profile.harmony.chords.filter((chord) => chord.level === "structural");
1610
- const cadences = (profile) => profile.form.phrases.map((phrase) => _nullishCoalesce(_optionalChain([phrase, 'access', _56 => _56.cadence, 'optionalAccess', _57 => _57.type]), () => ( null)));
1692
+ const cadences = (profile) => profile.form.phrases.map((phrase) => _nullishCoalesce(_optionalChain([phrase, 'access', _58 => _58.cadence, 'optionalAccess', _59 => _59.type]), () => ( null)));
1611
1693
  const phraseMelodies = (profile) => profile.form.phrases.map((phrase) => phrase.melody);
1612
1694
  const comparison = {
1613
1695
  form: {
1614
- sectionSequenceSimilarity: _chunkIFZDWIKMcjs.sectionSequenceSimilarity.call(void 0,
1696
+ sectionSequenceSimilarity: _chunkLQZQDBCDcjs.sectionSequenceSimilarity.call(void 0,
1615
1697
  a.form.sections.map((section) => section.label),
1616
1698
  b.form.sections.map((section) => section.label)
1617
1699
  ),
1618
- phraseLengthSimilarity: _chunkIFZDWIKMcjs.phraseLengthSimilarity.call(void 0,
1700
+ phraseLengthSimilarity: _chunkLQZQDBCDcjs.phraseLengthSimilarity.call(void 0,
1619
1701
  a.form.phrases.map((phrase) => phrase.bars),
1620
1702
  b.form.phrases.map((phrase) => phrase.bars)
1621
1703
  )
1622
1704
  },
1623
1705
  harmony: {
1624
- progressionSimilarity: _chunkIFZDWIKMcjs.progressionSimilarity.call(void 0, structural(a), structural(b), budget),
1625
- functionSimilarity: _chunkIFZDWIKMcjs.functionSimilarity.call(void 0, a.harmony.chords, b.harmony.chords),
1626
- cadenceSimilarity: _chunkIFZDWIKMcjs.cadenceSimilarity.call(void 0, cadences(a), cadences(b)),
1627
- keyPlanSimilarity: _chunkIFZDWIKMcjs.keyPlanSimilarity.call(void 0,
1706
+ progressionSimilarity: _chunkLQZQDBCDcjs.progressionSimilarity.call(void 0, structural(a), structural(b), budget),
1707
+ functionSimilarity: _chunkLQZQDBCDcjs.functionSimilarity.call(void 0, a.harmony.chords, b.harmony.chords),
1708
+ cadenceSimilarity: _chunkLQZQDBCDcjs.cadenceSimilarity.call(void 0, cadences(a), cadences(b)),
1709
+ keyPlanSimilarity: _chunkLQZQDBCDcjs.keyPlanSimilarity.call(void 0,
1628
1710
  a.harmony.keys.map((region) => region.key),
1629
1711
  b.harmony.keys.map((region) => region.key)
1630
1712
  ),
1631
- harmonicRhythmOnsetSimilarity: _chunkIFZDWIKMcjs.onsetSimilarity.call(void 0, a.harmony.rhythm, b.harmony.rhythm),
1632
- harmonicRhythmDensitySimilarity: _chunkIFZDWIKMcjs.densitySimilarity.call(void 0, a.harmony.rhythm, b.harmony.rhythm)
1713
+ harmonicRhythmOnsetSimilarity: _chunkLQZQDBCDcjs.onsetSimilarity.call(void 0, a.harmony.rhythm, b.harmony.rhythm),
1714
+ harmonicRhythmDensitySimilarity: _chunkLQZQDBCDcjs.densitySimilarity.call(void 0, a.harmony.rhythm, b.harmony.rhythm)
1633
1715
  },
1634
1716
  melody: {
1635
- surfaceSimilarity: _chunkIFZDWIKMcjs.surfaceSimilarity.call(void 0, a.melody.motifs, b.melody.motifs),
1636
- motifStructureSimilarity: _chunkIFZDWIKMcjs.motifStructureSimilarity.call(void 0,
1717
+ surfaceSimilarity: _chunkLQZQDBCDcjs.surfaceSimilarity.call(void 0, a.melody.motifs, b.melody.motifs),
1718
+ motifStructureSimilarity: _chunkLQZQDBCDcjs.motifStructureSimilarity.call(void 0,
1637
1719
  { graph: a.melody.graph, spanBeats: a.span.endBeat - a.span.startBeat },
1638
1720
  { graph: b.melody.graph, spanBeats: b.span.endBeat - b.span.startBeat }
1639
1721
  ),
1640
- contourSimilarity: _chunkIFZDWIKMcjs.contourSimilarity.call(void 0, phraseMelodies(a), phraseMelodies(b)),
1641
- registerSimilarity: _chunkIFZDWIKMcjs.registerSimilarity.call(void 0,
1642
- { phrases: phraseMelodies(a), mean: _nullishCoalesce(_optionalChain([a, 'access', _58 => _58.melody, 'access', _59 => _59.register, 'optionalAccess', _60 => _60.mean]), () => ( null)) },
1643
- { phrases: phraseMelodies(b), mean: _nullishCoalesce(_optionalChain([b, 'access', _61 => _61.melody, 'access', _62 => _62.register, 'optionalAccess', _63 => _63.mean]), () => ( null)) }
1722
+ contourSimilarity: _chunkLQZQDBCDcjs.contourSimilarity.call(void 0, phraseMelodies(a), phraseMelodies(b)),
1723
+ registerSimilarity: _chunkLQZQDBCDcjs.registerSimilarity.call(void 0,
1724
+ { phrases: phraseMelodies(a), mean: _nullishCoalesce(_optionalChain([a, 'access', _60 => _60.melody, 'access', _61 => _61.register, 'optionalAccess', _62 => _62.mean]), () => ( null)) },
1725
+ { phrases: phraseMelodies(b), mean: _nullishCoalesce(_optionalChain([b, 'access', _63 => _63.melody, 'access', _64 => _64.register, 'optionalAccess', _65 => _65.mean]), () => ( null)) }
1644
1726
  )
1645
1727
  },
1646
1728
  rhythm: {
1647
- onsetSimilarity: _chunkIFZDWIKMcjs.onsetSimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm),
1648
- densitySimilarity: _chunkIFZDWIKMcjs.densitySimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm),
1649
- durationSimilarity: _chunkIFZDWIKMcjs.durationSimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm),
1650
- syncopationSimilarity: _chunkIFZDWIKMcjs.syncopationSimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm)
1729
+ onsetSimilarity: _chunkLQZQDBCDcjs.onsetSimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm),
1730
+ densitySimilarity: _chunkLQZQDBCDcjs.densitySimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm),
1731
+ durationSimilarity: _chunkLQZQDBCDcjs.durationSimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm),
1732
+ syncopationSimilarity: _chunkLQZQDBCDcjs.syncopationSimilarity.call(void 0, a.melody.rhythm, b.melody.rhythm)
1651
1733
  }
1652
1734
  };
1653
1735
  return { ...comparison, rationale: rationaleOf(comparison) };
@@ -1658,19 +1740,20 @@ function spanOf(sounding, timeline, meters, totalBeats) {
1658
1740
  const segments = timeline.segments;
1659
1741
  const firstSegment = segments[0];
1660
1742
  const lastSegment = segments[segments.length - 1];
1661
- const firstOnset = _chunkIFZDWIKMcjs.firstSoundingBeat.call(void 0, sounding, _nullishCoalesce(_optionalChain([firstSegment, 'optionalAccess', _64 => _64.startBeat]), () => ( 0)));
1662
- const startBeat = _chunkIFZDWIKMcjs.barGridStart.call(void 0,
1663
- Math.min(firstOnset, _nullishCoalesce(_optionalChain([firstSegment, 'optionalAccess', _65 => _65.startBeat]), () => ( firstOnset))),
1743
+ const firstOnset = _chunkLQZQDBCDcjs.firstSoundingBeat.call(void 0, sounding, _nullishCoalesce(_optionalChain([firstSegment, 'optionalAccess', _66 => _66.startBeat]), () => ( 0)));
1744
+ const startBeat = _chunkLQZQDBCDcjs.barGridStart.call(void 0,
1745
+ Math.min(firstOnset, _nullishCoalesce(_optionalChain([firstSegment, 'optionalAccess', _67 => _67.startBeat]), () => ( firstOnset))),
1664
1746
  meters
1665
1747
  );
1666
- const notesEnd = sounding.reduce(
1667
- (end, note) => Math.max(end, note.startBeat + note.durationBeat),
1668
- _nullishCoalesce(_optionalChain([lastSegment, 'optionalAccess', _66 => _66.endBeat]), () => ( 0))
1748
+ const latestEnd = Math.max(
1749
+ _nullishCoalesce(_optionalChain([lastSegment, 'optionalAccess', _68 => _68.endBeat]), () => ( Number.NEGATIVE_INFINITY)),
1750
+ _chunkLQZQDBCDcjs.latestSoundingEnd.call(void 0, sounding, Number.NEGATIVE_INFINITY)
1669
1751
  );
1752
+ const notesEnd = Number.isFinite(latestEnd) ? latestEnd : 0;
1670
1753
  return { startBeat, endBeat: Math.max(startBeat, _nullishCoalesce(totalBeats, () => ( notesEnd))) };
1671
1754
  }
1672
1755
  function sameKey(a, b) {
1673
- return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, a.scale.rootPc) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, b.scale.rootPc) && a.scale.modeMask12 === b.scale.modeMask12;
1756
+ return _chunkS3QELJUEcjs.pitchClassOf.call(void 0, a.scale.rootPc) === _chunkS3QELJUEcjs.pitchClassOf.call(void 0, b.scale.rootPc) && a.scale.modeMask12 === b.scale.modeMask12;
1674
1757
  }
1675
1758
  function keyIndexAt(regions, beat, prevailing) {
1676
1759
  const holding = regions.findIndex((region) => region.startBeat <= beat && beat < region.endBeat);
@@ -1684,61 +1767,56 @@ function keyIndexAt(regions, beat, prevailing) {
1684
1767
  }
1685
1768
  function sectionAt(sections, beat) {
1686
1769
  const index = sections.findIndex(
1687
- (section) => beat >= section.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && beat < section.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
1770
+ (section) => beat >= section.startBeat - _chunkS3QELJUEcjs.BEAT_EPS && beat < section.endBeat - _chunkS3QELJUEcjs.BEAT_EPS
1688
1771
  );
1689
1772
  return index < 0 ? null : index;
1690
1773
  }
1691
1774
  function readingsFor(notes, opts = {}) {
1692
- const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "reference options");
1693
- const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, asked, "reference meters");
1775
+ const asked = _chunkS3QELJUEcjs.assertOptions.call(void 0, opts, "reference options");
1776
+ const meters = _chunkS3QELJUEcjs.resolveMeters.call(void 0, asked, "reference meters");
1694
1777
  const budget = asked.budget;
1695
1778
  if (asked.timeline === void 0) {
1696
- return _chunkIFZDWIKMcjs.chordTimelineFromNotes.call(void 0, notes, {
1779
+ return _chunkLQZQDBCDcjs.chordTimelineFromNotes.call(void 0, notes, {
1697
1780
  meters,
1698
1781
  key: asked.key,
1699
1782
  totalBeats: asked.totalBeats,
1700
1783
  budget
1701
1784
  });
1702
1785
  }
1703
- const timeline = _chunkIFZDWIKMcjs.assertChordTimeline.call(void 0, asked.timeline, "reference timeline");
1786
+ const timeline = _chunkLQZQDBCDcjs.assertChordTimeline.call(void 0, asked.timeline, "reference timeline");
1704
1787
  let keys;
1705
1788
  if (asked.key === void 0) {
1706
- keys = _chunkIFZDWIKMcjs.keyTimelineFromNotes.call(void 0, notes, { meters, totalBeats: asked.totalBeats, budget });
1789
+ keys = _chunkLQZQDBCDcjs.keyTimelineFromNotes.call(void 0, notes, { meters, totalBeats: asked.totalBeats, budget });
1707
1790
  } else {
1708
- const sounding = _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "reference notes", {
1791
+ const sounding = _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, notes, "reference notes", {
1709
1792
  allowNonPositiveDuration: true,
1710
1793
  budget
1711
1794
  }).filter((note) => note.durationBeat > 0);
1712
1795
  const span = spanOf(sounding, timeline, meters, asked.totalBeats);
1713
- keys = [
1714
- {
1715
- startBeat: span.startBeat,
1716
- endBeat: span.endBeat,
1717
- key: _chunk3R3QVKY5cjs.resolveKey.call(void 0, asked.key),
1718
- confidence: 1
1719
- }
1720
- ];
1796
+ keys = _chunkLQZQDBCDcjs.statedKeyRegions.call(void 0, _chunkYDGMWH43cjs.resolveKey.call(void 0, asked.key), span.startBeat, span.endBeat);
1721
1797
  }
1722
- return { timeline, keys, prevailingKey: _nullishCoalesce(_chunkIFZDWIKMcjs.prevailingKeyOf.call(void 0, keys), () => ( _chunk3R3QVKY5cjs.resolveKey.call(void 0, _chunk3R3QVKY5cjs.majorKey.call(void 0, 0)))) };
1798
+ return { timeline, keys, prevailingKey: _nullishCoalesce(_chunkLQZQDBCDcjs.prevailingKeyOf.call(void 0, keys), () => ( _chunkYDGMWH43cjs.resolveKey.call(void 0, _chunkYDGMWH43cjs.majorKey.call(void 0, 0)))) };
1723
1799
  }
1724
1800
  function referenceFromReadings(notes, readings, opts = {}) {
1725
- const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "reference options");
1726
- const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, asked, "reference meters");
1801
+ const asked = _chunkS3QELJUEcjs.assertOptions.call(void 0, opts, "reference options");
1802
+ const meters = _chunkS3QELJUEcjs.resolveMeters.call(void 0, asked, "reference meters");
1727
1803
  const budget = asked.budget;
1728
- const sounding = _chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "reference notes", {
1804
+ const sounding = _chunkS3QELJUEcjs.assertNoteEvents.call(void 0, notes, "reference notes", {
1729
1805
  allowNonPositiveDuration: true,
1730
1806
  budget
1731
1807
  }).filter((note) => note.durationBeat > 0);
1732
1808
  if (asked.totalBeats !== void 0) {
1733
- _chunkS5BKZZGMcjs.assertRange.call(void 0, asked.totalBeats, 0, Number.MAX_SAFE_INTEGER, "reference totalBeats");
1809
+ _chunkS3QELJUEcjs.assertRange.call(void 0, asked.totalBeats, 0, Number.MAX_SAFE_INTEGER, "reference totalBeats");
1734
1810
  }
1735
- const line = _chunkIFZDWIKMcjs.orderedNotes.call(void 0, _nullishCoalesce(asked.melody, () => ( notes)), "reference melody", budget);
1811
+ const line = _chunkLQZQDBCDcjs.orderedNotes.call(void 0, _nullishCoalesce(asked.melody, () => ( notes)), "reference melody", budget).map(
1812
+ (note) => Object.is(note.pitch, -0) ? { ...note, pitch: 0 } : note
1813
+ );
1736
1814
  const { timeline, prevailingKey } = readings;
1737
1815
  const span = spanOf(sounding, timeline, meters, asked.totalBeats);
1738
1816
  const spanEnd = span.endBeat;
1739
- const keyAt = _chunkIFZDWIKMcjs.keyLookup.call(void 0, readings.keys, prevailingKey);
1740
- const scaleAt = (beat) => _chunk3R3QVKY5cjs.scaleOf.call(void 0, keyAt(beat));
1741
- const cadenceBeats = _chunkIFZDWIKMcjs.detectCadences.call(void 0, timeline, scaleAt).map((hit) => hit.atBeat);
1817
+ const keyAt = _chunkLQZQDBCDcjs.keyLookup.call(void 0, readings.keys, prevailingKey);
1818
+ const scaleAt = (beat) => _chunkYDGMWH43cjs.scaleOf.call(void 0, keyAt(beat));
1819
+ const cadenceBeats = _chunkLQZQDBCDcjs.detectCadences.call(void 0, timeline, scaleAt).map((hit) => hit.atBeat);
1742
1820
  const grouping = hypermeter(sounding, meters, { cadenceBeats, totalBeats: spanEnd, budget });
1743
1821
  const phrases = phrasesFromTimeline(timeline, notes, {
1744
1822
  meters,
@@ -1768,24 +1846,24 @@ function referenceFromReadings(notes, readings, opts = {}) {
1768
1846
  {
1769
1847
  startBeat: span.startBeat,
1770
1848
  endBeat: spanEnd,
1771
- key: _chunk3R3QVKY5cjs.resolveKey.call(void 0, prevailingKey),
1849
+ key: _chunkYDGMWH43cjs.resolveKey.call(void 0, prevailingKey),
1772
1850
  confidence: 0
1773
1851
  }
1774
1852
  ] : readings.keys.map((region) => ({
1775
1853
  startBeat: region.startBeat,
1776
1854
  endBeat: region.endBeat,
1777
- key: _chunk3R3QVKY5cjs.resolveKey.call(void 0, region.key),
1855
+ key: _chunkYDGMWH43cjs.resolveKey.call(void 0, region.key),
1778
1856
  confidence: region.confidence
1779
1857
  }));
1780
- const chords = _chunkIFZDWIKMcjs.reduceProgression.call(void 0, timeline, scaleAt).map((reduced) => {
1858
+ const chords = _chunkLQZQDBCDcjs.reduceProgression.call(void 0, timeline, scaleAt).map((reduced) => {
1781
1859
  const index = keyIndexAt(keys, (reduced.startBeat + reduced.endBeat) / 2, prevailingKey);
1782
1860
  const key = keys[index].key;
1783
1861
  return {
1784
1862
  startBeat: reduced.startBeat,
1785
1863
  endBeat: reduced.endBeat,
1786
1864
  key: index,
1787
- roman: _chunkIFZDWIKMcjs.chordToRoman.call(void 0, reduced.chord, key),
1788
- function: _chunkIFZDWIKMcjs.functionOf.call(void 0, reduced.chord, key),
1865
+ roman: _chunkLQZQDBCDcjs.chordToRoman.call(void 0, reduced.chord, key),
1866
+ function: _chunkLQZQDBCDcjs.functionOf.call(void 0, reduced.chord, key),
1789
1867
  level: reduced.level
1790
1868
  };
1791
1869
  });
@@ -1794,19 +1872,19 @@ function referenceFromReadings(notes, readings, opts = {}) {
1794
1872
  startBeat: segment.startBeat,
1795
1873
  durationBeat: segment.endBeat - segment.startBeat
1796
1874
  }));
1797
- const harmonyRhythm = _chunkIFZDWIKMcjs.analyzeRhythm.call(void 0, chordOnsets, { meters, totalBeats: spanEnd, budget });
1798
- const motifs = _chunkIFZDWIKMcjs.extractMotifs.call(void 0, line, { budget });
1799
- const graph = _chunkIFZDWIKMcjs.motifGraph.call(void 0, line, motifs, { key: prevailingKey, budget });
1875
+ const harmonyRhythm = _chunkLQZQDBCDcjs.analyzeRhythm.call(void 0, chordOnsets, { meters, totalBeats: spanEnd, budget });
1876
+ const motifs = _chunkLQZQDBCDcjs.extractMotifs.call(void 0, line, { budget });
1877
+ const graph = _chunkLQZQDBCDcjs.motifGraph.call(void 0, line, motifs, { key: prevailingKey, budget });
1800
1878
  let register = null;
1801
1879
  if (line.length > 0) {
1802
1880
  const pitches = line.map((note) => note.pitch);
1803
1881
  register = {
1804
1882
  low: Math.min(...pitches),
1805
1883
  high: Math.max(...pitches),
1806
- mean: _chunkIFZDWIKMcjs.weightedMean.call(void 0, line)
1884
+ mean: _chunkLQZQDBCDcjs.weightedMean.call(void 0, line)
1807
1885
  };
1808
1886
  }
1809
- const lineMean = _nullishCoalesce(_optionalChain([register, 'optionalAccess', _67 => _67.mean]), () => ( 0));
1887
+ const lineMean = _nullishCoalesce(_optionalChain([register, 'optionalAccess', _69 => _69.mean]), () => ( 0));
1810
1888
  const referenceMotifs = motifs.map((motif) => {
1811
1889
  const first = motif.occurrences[0];
1812
1890
  return {
@@ -1820,21 +1898,21 @@ function referenceFromReadings(notes, readings, opts = {}) {
1820
1898
  const referencePhrases = phrases.map((phrase, index) => ({
1821
1899
  startBeat: phrase.startBeat,
1822
1900
  endBeat: phrase.endBeat,
1823
- bars: _chunkIFZDWIKMcjs.barSpanOf.call(void 0, phrase.startBeat, phrase.endBeat, meters),
1901
+ bars: _chunkLQZQDBCDcjs.barSpanOf.call(void 0, phrase.startBeat, phrase.endBeat, meters),
1824
1902
  section: sectionAt(sections, phrase.startBeat),
1825
1903
  confidence: phrase.confidence,
1826
1904
  cadence: _nullishCoalesce(cadences.get(index), () => ( null)),
1827
- melody: _chunkIFZDWIKMcjs.phraseMelody.call(void 0, line, phrase.startBeat, phrase.endBeat, lineMean, meters, budget),
1905
+ melody: _chunkLQZQDBCDcjs.phraseMelody.call(void 0, line, phrase.startBeat, phrase.endBeat, lineMean, meters, budget),
1828
1906
  motifNodes: graph.nodes.flatMap(
1829
- (node, nodeIndex) => node.startBeat >= phrase.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && node.startBeat < phrase.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS ? [nodeIndex] : []
1907
+ (node, nodeIndex) => node.startBeat >= phrase.startBeat - _chunkS3QELJUEcjs.BEAT_EPS && node.startBeat < phrase.endBeat - _chunkS3QELJUEcjs.BEAT_EPS ? [nodeIndex] : []
1830
1908
  )
1831
1909
  }));
1832
1910
  return {
1833
- profileVersion: _chunkIFZDWIKMcjs.REFERENCE_PROFILE_VERSION,
1911
+ profileVersion: _chunkLQZQDBCDcjs.REFERENCE_PROFILE_VERSION,
1834
1912
  span: {
1835
1913
  startBeat: span.startBeat,
1836
1914
  endBeat: spanEnd,
1837
- bars: _chunkIFZDWIKMcjs.barSpanOf.call(void 0, span.startBeat, spanEnd, meters)
1915
+ bars: _chunkLQZQDBCDcjs.barSpanOf.call(void 0, span.startBeat, spanEnd, meters)
1838
1916
  },
1839
1917
  meters,
1840
1918
  form: {
@@ -1845,10 +1923,10 @@ function referenceFromReadings(notes, readings, opts = {}) {
1845
1923
  harmony: { keys, chords, rhythm: harmonyRhythm },
1846
1924
  melody: {
1847
1925
  register,
1848
- shape: line.length < 2 ? null : _chunkIFZDWIKMcjs.melodicContour.call(void 0, line).shape,
1926
+ shape: line.length < 2 ? null : _chunkLQZQDBCDcjs.melodicContour.call(void 0, line).shape,
1849
1927
  motifs: referenceMotifs,
1850
1928
  graph,
1851
- rhythm: _chunkIFZDWIKMcjs.analyzeRhythm.call(void 0, line, { meters, totalBeats: spanEnd, budget })
1929
+ rhythm: _chunkLQZQDBCDcjs.rhythmOver.call(void 0, line, { meters, totalBeats: spanEnd, budget }, span.startBeat)
1852
1930
  }
1853
1931
  };
1854
1932
  }
@@ -1870,5 +1948,11 @@ function analyzeReference(notes, opts) {
1870
1948
 
1871
1949
 
1872
1950
 
1873
- exports.trackRoleOf = trackRoleOf; exports.analyzePolyphony = analyzePolyphony; exports.analyzeArrangement = analyzeArrangement; exports.createArrangementSession = createArrangementSession; exports.tensionCurve = tensionCurve; exports.tensionCurveFrom = tensionCurveFrom; exports.hypermeter = hypermeter; exports.phrasesFromTimeline = phrasesFromTimeline; exports.structuralCadences = structuralCadences; exports.sectionsFromNotes = sectionsFromNotes; exports.compareReferences = compareReferences; exports.referenceFromReadings = referenceFromReadings; exports.analyzeReference = analyzeReference;
1874
- //# sourceMappingURL=chunk-YFA7X2F6.cjs.map
1951
+
1952
+
1953
+
1954
+
1955
+
1956
+
1957
+ exports.trackRoleOf = trackRoleOf; exports.arrangementProfile = arrangementProfile; exports.assertTrackNotes = assertTrackNotes; exports.harmonyTrackSet = harmonyTrackSet; exports.analyzePolyphony = analyzePolyphony; exports.analyzeArrangement = analyzeArrangement; exports.createArrangementSession = createArrangementSession; exports.tensionCurve = tensionCurve; exports.tensionCurveFrom = tensionCurveFrom; exports.hypermeter = hypermeter; exports.hypermeterOver = hypermeterOver; exports.boundaryCadences = boundaryCadences; exports.keyContextFor = keyContextFor; exports.phrasesFromTimeline = phrasesFromTimeline; exports.structuralCadences = structuralCadences; exports.sectionsFromNotes = sectionsFromNotes; exports.compareReferences = compareReferences; exports.referenceFromReadings = referenceFromReadings; exports.analyzeReference = analyzeReference;
1958
+ //# sourceMappingURL=chunk-3MDOEFIQ.cjs.map