@libraz/libcantus 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/README_ja.md +4 -0
- package/dist/analyze/index.cjs +31 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +155 -9
- package/dist/analyze/index.d.ts +155 -9
- package/dist/analyze/index.js +37 -13
- package/dist/{chunk-TT6PKMPR.cjs → chunk-35NBV2FT.cjs} +16 -16
- package/dist/{chunk-TT6PKMPR.cjs.map → chunk-35NBV2FT.cjs.map} +1 -1
- package/dist/{chunk-YPB3A3EY.cjs → chunk-3R3QVKY5.cjs} +314 -285
- package/dist/chunk-3R3QVKY5.cjs.map +1 -0
- package/dist/{chunk-GDKE6RQW.cjs → chunk-4R2LWV7E.cjs} +691 -413
- package/dist/chunk-4R2LWV7E.cjs.map +1 -0
- package/dist/{chunk-RVS4G4MR.cjs → chunk-76ZBTRG2.cjs} +198 -198
- package/dist/{chunk-RVS4G4MR.cjs.map → chunk-76ZBTRG2.cjs.map} +1 -1
- package/dist/{chunk-X6RJAHII.js → chunk-7KG3RTYS.js} +2 -2
- package/dist/{chunk-PQL7E5F6.js → chunk-AGOVW7U6.js} +1 -1
- package/dist/{chunk-PQL7E5F6.js.map → chunk-AGOVW7U6.js.map} +1 -1
- package/dist/{chunk-5KW7DNCJ.cjs → chunk-B2PW6EHN.cjs} +2423 -453
- package/dist/chunk-B2PW6EHN.cjs.map +1 -0
- package/dist/{chunk-J772DL3B.cjs → chunk-CGBADIO5.cjs} +53 -53
- package/dist/{chunk-J772DL3B.cjs.map → chunk-CGBADIO5.cjs.map} +1 -1
- package/dist/{chunk-R5VUXQMP.js → chunk-CPMB7P75.js} +1978 -8
- package/dist/chunk-CPMB7P75.js.map +1 -0
- package/dist/{chunk-VLE5R7PF.js → chunk-GNVN4PPJ.js} +1874 -8
- package/dist/chunk-GNVN4PPJ.js.map +1 -0
- package/dist/{chunk-Q6R3QAZD.cjs → chunk-IFZDWIKM.cjs} +2199 -333
- package/dist/chunk-IFZDWIKM.cjs.map +1 -0
- package/dist/{chunk-DKICR7AN.js → chunk-IPEF6NWB.js} +296 -18
- package/dist/chunk-IPEF6NWB.js.map +1 -0
- package/dist/{chunk-AWEMD747.js → chunk-M5RYMAFI.js} +3 -3
- package/dist/{chunk-HSY2VQXZ.js → chunk-MLBPXA4Z.js} +330 -728
- package/dist/chunk-MLBPXA4Z.js.map +1 -0
- package/dist/{chunk-H66ARFU5.js → chunk-NB25P3EH.js} +3 -3
- package/dist/{chunk-5JJ6EHEZ.cjs → chunk-NM7UAMC3.cjs} +62 -62
- package/dist/{chunk-5JJ6EHEZ.cjs.map → chunk-NM7UAMC3.cjs.map} +1 -1
- package/dist/{chunk-R7B5N2JK.cjs → chunk-PM4XJE2Y.cjs} +47 -47
- package/dist/{chunk-R7B5N2JK.cjs.map → chunk-PM4XJE2Y.cjs.map} +1 -1
- package/dist/{chunk-7GOKQJTQ.js → chunk-PUKJP2Z5.js} +2 -2
- package/dist/{chunk-QCXYKSZS.cjs → chunk-PWC4CRWT.cjs} +19 -19
- package/dist/{chunk-QCXYKSZS.cjs.map → chunk-PWC4CRWT.cjs.map} +1 -1
- package/dist/{chunk-FPBZFNCD.js → chunk-RFIBF2RR.js} +47 -18
- package/dist/{chunk-FPBZFNCD.js.map → chunk-RFIBF2RR.js.map} +1 -1
- package/dist/{chunk-XKSO2V5I.cjs → chunk-S5BKZZGM.cjs} +1 -1
- package/dist/{chunk-XKSO2V5I.cjs.map → chunk-S5BKZZGM.cjs.map} +1 -1
- package/dist/{chunk-HOHFYGKW.js → chunk-UMWZ4ZET.js} +2 -2
- package/dist/{chunk-XVMJO3QF.cjs → chunk-YFA7X2F6.cjs} +489 -887
- package/dist/chunk-YFA7X2F6.cjs.map +1 -0
- package/dist/{chunk-57WB2EDF.js → chunk-ZBUROTJQ.js} +3 -3
- package/dist/{coerce-wwdELNYS.d.ts → coerce-DP0vYu-x.d.ts} +77 -1
- package/dist/{coerce-CJlgULrQ.d.cts → coerce-DRERzdve.d.cts} +77 -1
- package/dist/core/index.cjs +5 -5
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +4 -4
- package/dist/generate/index.cjs +20 -8
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +87 -9
- package/dist/generate/index.d.ts +87 -9
- package/dist/generate/index.js +19 -7
- package/dist/{index-BaoKVVhE.d.cts → index-B9QLziDe.d.cts} +2 -2
- package/dist/{index-CnHQgqNh.d.ts → index-BHIUyjhZ.d.ts} +2 -2
- package/dist/{index-CBCP84rv.d.cts → index-BL5N2Oyz.d.cts} +1 -1
- package/dist/{index-D_hzxD8w.d.cts → index-BMweUlm5.d.cts} +3 -0
- package/dist/{index-Ci3xyows.d.ts → index-CL4b4gUQ.d.ts} +3 -0
- package/dist/{index-BzLNkmA7.d.cts → index-CY-3NVfy.d.cts} +486 -5
- package/dist/{index-CnIdP4EZ.d.ts → index-Dw2DP7vm.d.ts} +1 -1
- package/dist/{index-DpC-mDlV.d.ts → index-zaZdmnU4.d.ts} +486 -5
- package/dist/index.cjs +49 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +55 -19
- package/dist/{masks-O73Rhj5d.d.ts → masks-Cc7-MzzY.d.ts} +1 -1
- package/dist/{masks-C8TWLFIi.d.cts → masks-pADfTOiD.d.cts} +1 -1
- package/dist/model/index.cjs +12 -12
- package/dist/model/index.d.cts +213 -16
- package/dist/model/index.d.ts +213 -16
- package/dist/model/index.js +11 -11
- package/dist/{index-DTsKaPaC.d.cts → profile-CQMEqdH9.d.cts} +88 -601
- package/dist/{index-BUtIf2go.d.ts → profile-DLdlIpS9.d.ts} +88 -601
- package/dist/theory/index.cjs +5 -5
- package/dist/theory/index.d.cts +7 -7
- package/dist/theory/index.d.ts +7 -7
- package/dist/theory/index.js +4 -4
- package/dist/{index-BpWOhkkE.d.ts → types-D-XgxGvp.d.cts} +1170 -14
- package/dist/{index-B3WCj_Hm.d.cts → types-Dh7C064C.d.ts} +1170 -14
- package/package.json +6 -5
- package/dist/chunk-5KW7DNCJ.cjs.map +0 -1
- package/dist/chunk-DKICR7AN.js.map +0 -1
- package/dist/chunk-GDKE6RQW.cjs.map +0 -1
- package/dist/chunk-HSY2VQXZ.js.map +0 -1
- package/dist/chunk-Q6R3QAZD.cjs.map +0 -1
- package/dist/chunk-R5VUXQMP.js.map +0 -1
- package/dist/chunk-VLE5R7PF.js.map +0 -1
- package/dist/chunk-XVMJO3QF.cjs.map +0 -1
- package/dist/chunk-YPB3A3EY.cjs.map +0 -1
- /package/dist/{chunk-X6RJAHII.js.map → chunk-7KG3RTYS.js.map} +0 -0
- /package/dist/{chunk-AWEMD747.js.map → chunk-M5RYMAFI.js.map} +0 -0
- /package/dist/{chunk-H66ARFU5.js.map → chunk-NB25P3EH.js.map} +0 -0
- /package/dist/{chunk-7GOKQJTQ.js.map → chunk-PUKJP2Z5.js.map} +0 -0
- /package/dist/{chunk-HOHFYGKW.js.map → chunk-UMWZ4ZET.js.map} +0 -0
- /package/dist/{chunk-57WB2EDF.js.map → chunk-ZBUROTJQ.js.map} +0 -0
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
var _chunkQ6R3QAZDcjs = require('./chunk-Q6R3QAZD.cjs');
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
|
|
@@ -19,14 +18,11 @@ var _chunkQ6R3QAZDcjs = require('./chunk-Q6R3QAZD.cjs');
|
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
|
|
22
|
-
var _chunkJ772DL3Bcjs = require('./chunk-J772DL3B.cjs');
|
|
23
21
|
|
|
24
22
|
|
|
25
|
-
var _chunkTT6PKMPRcjs = require('./chunk-TT6PKMPR.cjs');
|
|
26
23
|
|
|
27
24
|
|
|
28
25
|
|
|
29
|
-
var _chunkR7B5N2JKcjs = require('./chunk-R7B5N2JK.cjs');
|
|
30
26
|
|
|
31
27
|
|
|
32
28
|
|
|
@@ -34,6 +30,7 @@ var _chunkR7B5N2JKcjs = require('./chunk-R7B5N2JK.cjs');
|
|
|
34
30
|
|
|
35
31
|
|
|
36
32
|
|
|
33
|
+
var _chunkIFZDWIKMcjs = require('./chunk-IFZDWIKM.cjs');
|
|
37
34
|
|
|
38
35
|
|
|
39
36
|
|
|
@@ -46,11 +43,14 @@ var _chunkR7B5N2JKcjs = require('./chunk-R7B5N2JK.cjs');
|
|
|
46
43
|
|
|
47
44
|
|
|
48
45
|
|
|
46
|
+
var _chunkCGBADIO5cjs = require('./chunk-CGBADIO5.cjs');
|
|
49
47
|
|
|
50
48
|
|
|
49
|
+
var _chunk35NBV2FTcjs = require('./chunk-35NBV2FT.cjs');
|
|
51
50
|
|
|
52
51
|
|
|
53
52
|
|
|
53
|
+
var _chunkPM4XJE2Ycjs = require('./chunk-PM4XJE2Y.cjs');
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
|
|
@@ -58,7 +58,6 @@ var _chunkR7B5N2JKcjs = require('./chunk-R7B5N2JK.cjs');
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
var _chunkYPB3A3EYcjs = require('./chunk-YPB3A3EY.cjs');
|
|
62
61
|
|
|
63
62
|
|
|
64
63
|
|
|
@@ -85,6 +84,7 @@ var _chunkYPB3A3EYcjs = require('./chunk-YPB3A3EY.cjs');
|
|
|
85
84
|
|
|
86
85
|
|
|
87
86
|
|
|
87
|
+
var _chunk3R3QVKY5cjs = require('./chunk-3R3QVKY5.cjs');
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
|
|
@@ -95,24 +95,59 @@ var _chunkYPB3A3EYcjs = require('./chunk-YPB3A3EY.cjs');
|
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
var _chunkS5BKZZGMcjs = require('./chunk-S5BKZZGM.cjs');
|
|
99
134
|
|
|
100
135
|
// src/generate/context/draw.ts
|
|
101
136
|
var DRAW_METHODS = ["at", "prob", "range", "float"];
|
|
102
137
|
function assertDraw(draw, name = "draw") {
|
|
103
|
-
const sampler =
|
|
138
|
+
const sampler = _chunkS5BKZZGMcjs.assertRecord.call(void 0, draw, name);
|
|
104
139
|
for (const method of DRAW_METHODS) {
|
|
105
|
-
|
|
140
|
+
_chunkS5BKZZGMcjs.assertFunction.call(void 0, sampler[method], `${name}.${method}`);
|
|
106
141
|
}
|
|
107
142
|
return sampler;
|
|
108
143
|
}
|
|
109
144
|
function assertSeedPath(path, name = "draw path") {
|
|
110
|
-
const steps =
|
|
145
|
+
const steps = _chunkS5BKZZGMcjs.assertArray.call(void 0, path, name);
|
|
111
146
|
for (let index = 0; index < steps.length; index += 1) {
|
|
112
147
|
const step = steps[index];
|
|
113
148
|
if (typeof step !== "string" && !Number.isFinite(step)) {
|
|
114
|
-
throw new (0,
|
|
115
|
-
`${name}[${index}] must be a string or a finite number; received ${
|
|
149
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
150
|
+
`${name}[${index}] must be a string or a finite number; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, step)}`
|
|
116
151
|
);
|
|
117
152
|
}
|
|
118
153
|
}
|
|
@@ -121,7 +156,7 @@ function assertSeedPath(path, name = "draw path") {
|
|
|
121
156
|
function drawFrom(rng, path) {
|
|
122
157
|
const draw = rng.at(...path);
|
|
123
158
|
if (!(draw >= 0 && draw < 1)) {
|
|
124
|
-
throw new (0,
|
|
159
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`positional draw must be in [0, 1); received ${draw}`);
|
|
125
160
|
}
|
|
126
161
|
return draw;
|
|
127
162
|
}
|
|
@@ -129,27 +164,27 @@ function drawsFrom(rng, ...prefix) {
|
|
|
129
164
|
const at2 = (...path) => drawFrom(rng, [...prefix, ...path]);
|
|
130
165
|
return {
|
|
131
166
|
at: at2,
|
|
132
|
-
prob: (p, ...path) =>
|
|
167
|
+
prob: (p, ...path) => _chunkCGBADIO5cjs.includeAt.call(void 0, rng, p, ...prefix, ...path),
|
|
133
168
|
range: (lo, hi, ...path) => {
|
|
134
|
-
|
|
135
|
-
|
|
169
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, lo, "range lower bound");
|
|
170
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, hi, "range upper bound");
|
|
136
171
|
if (lo > hi) {
|
|
137
|
-
throw new (0,
|
|
172
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
138
173
|
`range lower bound must not exceed upper bound; received ${lo} > ${hi}`
|
|
139
174
|
);
|
|
140
175
|
}
|
|
141
|
-
|
|
176
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, hi - lo, "range span", 0);
|
|
142
177
|
return lo + Math.floor(at2(...path) * (hi - lo + 1));
|
|
143
178
|
},
|
|
144
179
|
float: (lo, hi, ...path) => {
|
|
145
|
-
|
|
146
|
-
|
|
180
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, lo, "float lower bound");
|
|
181
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, hi, "float upper bound");
|
|
147
182
|
if (lo > hi) {
|
|
148
|
-
throw new (0,
|
|
183
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
149
184
|
`float lower bound must not exceed upper bound; received ${lo} > ${hi}`
|
|
150
185
|
);
|
|
151
186
|
}
|
|
152
|
-
|
|
187
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, hi - lo, "float span");
|
|
153
188
|
return lo + at2(...path) * (hi - lo);
|
|
154
189
|
}
|
|
155
190
|
};
|
|
@@ -378,8 +413,8 @@ function sameTs(a, b) {
|
|
|
378
413
|
return a.numerator === b.numerator && a.denominator === b.denominator;
|
|
379
414
|
}
|
|
380
415
|
function fitsQuery(entry, query) {
|
|
381
|
-
const candidate =
|
|
382
|
-
const asked =
|
|
416
|
+
const candidate = _chunkS5BKZZGMcjs.assertRecord.call(void 0, entry, "vocabulary entry");
|
|
417
|
+
const asked = _chunkS5BKZZGMcjs.assertRecord.call(void 0, query, "vocabulary query");
|
|
383
418
|
if (asked.genre !== void 0 && candidate.genre !== asked.genre) {
|
|
384
419
|
return false;
|
|
385
420
|
}
|
|
@@ -392,7 +427,7 @@ function fitsQuery(entry, query) {
|
|
|
392
427
|
return false;
|
|
393
428
|
}
|
|
394
429
|
}
|
|
395
|
-
if (asked.ts !== void 0 && candidate.ts && !sameTs(candidate.ts,
|
|
430
|
+
if (asked.ts !== void 0 && candidate.ts && !sameTs(candidate.ts, _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, asked.ts, "ts")))) {
|
|
396
431
|
return false;
|
|
397
432
|
}
|
|
398
433
|
if (asked.quality !== void 0 && candidate.fitsOver && !candidate.fitsOver.includes(asked.quality)) {
|
|
@@ -407,7 +442,7 @@ function fitsQuery(entry, query) {
|
|
|
407
442
|
return asked.difficulty === void 0 || candidate.difficulty <= asked.difficulty;
|
|
408
443
|
}
|
|
409
444
|
function selectVocabulary(dictionary, query) {
|
|
410
|
-
return
|
|
445
|
+
return _chunkS5BKZZGMcjs.assertArray.call(void 0, dictionary, "dictionary").filter(
|
|
411
446
|
(entry) => fitsQuery(entry, query)
|
|
412
447
|
);
|
|
413
448
|
}
|
|
@@ -421,12 +456,12 @@ function pickVocabulary(dictionary, query, draw, ...path) {
|
|
|
421
456
|
return candidates[sampler.range(0, candidates.length - 1, ...path)];
|
|
422
457
|
}
|
|
423
458
|
function mergeVocabulary(builtIn, supplied) {
|
|
424
|
-
const library =
|
|
425
|
-
const extra = supplied === void 0 || supplied === null ? [] :
|
|
459
|
+
const library = _chunkS5BKZZGMcjs.assertArray.call(void 0, builtIn, "builtIn");
|
|
460
|
+
const extra = supplied === void 0 || supplied === null ? [] : _chunkS5BKZZGMcjs.assertArray.call(void 0, supplied, "supplied");
|
|
426
461
|
if (extra.length === 0) {
|
|
427
462
|
return [...library];
|
|
428
463
|
}
|
|
429
|
-
const idOf = (entry, index, side) =>
|
|
464
|
+
const idOf = (entry, index, side) => _chunkS5BKZZGMcjs.assertRecord.call(void 0, entry, `${side}[${index}]`).id;
|
|
430
465
|
const byId = new Map(extra.map((entry, index) => [idOf(entry, index, "supplied"), entry]));
|
|
431
466
|
const merged = library.map((entry, index) => _nullishCoalesce(byId.get(idOf(entry, index, "builtIn")), () => ( entry)));
|
|
432
467
|
const replaced = new Set(library.map((entry, index) => idOf(entry, index, "builtIn")));
|
|
@@ -439,9 +474,9 @@ function mergeVocabulary(builtIn, supplied) {
|
|
|
439
474
|
}
|
|
440
475
|
function vocabularyOfKind(entries, isMaterial) {
|
|
441
476
|
const out = [];
|
|
442
|
-
const recognises =
|
|
443
|
-
for (const entry of
|
|
444
|
-
if (recognises(
|
|
477
|
+
const recognises = _chunkS5BKZZGMcjs.assertFunction.call(void 0, isMaterial, "isMaterial");
|
|
478
|
+
for (const entry of _chunkS5BKZZGMcjs.assertArray.call(void 0, entries, "entries")) {
|
|
479
|
+
if (recognises(_chunkS5BKZZGMcjs.assertRecord.call(void 0, entry, "entry").material)) {
|
|
445
480
|
out.push(entry);
|
|
446
481
|
}
|
|
447
482
|
}
|
|
@@ -449,42 +484,42 @@ function vocabularyOfKind(entries, isMaterial) {
|
|
|
449
484
|
}
|
|
450
485
|
function assertNames(values, allowed, label) {
|
|
451
486
|
if (!Array.isArray(values)) {
|
|
452
|
-
throw new (0,
|
|
453
|
-
`${label} must be an array of names; received ${
|
|
487
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
488
|
+
`${label} must be an array of names; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, values)}`
|
|
454
489
|
);
|
|
455
490
|
}
|
|
456
491
|
values.forEach((value, index) => {
|
|
457
|
-
|
|
492
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, value, allowed, `${label}[${index}]`);
|
|
458
493
|
});
|
|
459
494
|
}
|
|
460
495
|
function assertVocabulary(entry, label = "vocabulary entry") {
|
|
461
496
|
if (typeof entry !== "object" || entry === null) {
|
|
462
|
-
throw new (0,
|
|
463
|
-
`${label} must be a dictionary entry; received ${
|
|
497
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
498
|
+
`${label} must be a dictionary entry; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, entry)}`
|
|
464
499
|
);
|
|
465
500
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
assertNames(entry.articulations,
|
|
501
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, entry.genre, GENRES, `${label} genre`);
|
|
502
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, _optionalChain([entry, 'access', _2 => _2.provenance, 'optionalAccess', _3 => _3.basis]), PROVENANCE_BASES, `${label} provenance basis`);
|
|
503
|
+
assertNames(entry.articulations, _chunkS5BKZZGMcjs.ARTICULATIONS, `${label} articulations`);
|
|
469
504
|
if (entry.sections !== void 0) {
|
|
470
505
|
assertNames(entry.sections, PUBLIC_SECTIONS, `${label} sections`);
|
|
471
506
|
}
|
|
472
507
|
if (entry.fitsOver !== void 0) {
|
|
473
|
-
assertNames(entry.fitsOver,
|
|
508
|
+
assertNames(entry.fitsOver, _chunk3R3QVKY5cjs.chordQualities.call(void 0, ), `${label} fitsOver`);
|
|
474
509
|
}
|
|
475
510
|
if (entry.ts !== void 0) {
|
|
476
|
-
|
|
511
|
+
_chunkS5BKZZGMcjs.assertTimeSignature.call(void 0, entry.ts, `${label} ts`);
|
|
477
512
|
}
|
|
478
|
-
|
|
513
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, entry.difficulty, 1, 5, `${label} difficulty`);
|
|
479
514
|
if (entry.tempoRange !== void 0) {
|
|
480
515
|
if (!Array.isArray(entry.tempoRange) || entry.tempoRange.length !== 2) {
|
|
481
|
-
throw new (0,
|
|
482
|
-
`${label} tempoRange must be a low and a high tempo; received ${
|
|
516
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
517
|
+
`${label} tempoRange must be a low and a high tempo; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, entry.tempoRange)}`
|
|
483
518
|
);
|
|
484
519
|
}
|
|
485
520
|
const [low, high] = entry.tempoRange;
|
|
486
|
-
|
|
487
|
-
|
|
521
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, low, Number.MIN_VALUE, 1e3, `${label} tempoRange low`);
|
|
522
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, high, low, 1e3, `${label} tempoRange high`);
|
|
488
523
|
}
|
|
489
524
|
return entry;
|
|
490
525
|
}
|
|
@@ -506,15 +541,15 @@ function atLevel(table, difficulty) {
|
|
|
506
541
|
return low + (high - low) * (level - lower);
|
|
507
542
|
}
|
|
508
543
|
function assertDifficulty(difficulty, label = "complexity difficulty") {
|
|
509
|
-
return
|
|
544
|
+
return _chunkS5BKZZGMcjs.assertRange.call(void 0, difficulty, MIN_DIFFICULTY, MAX_DIFFICULTY, label);
|
|
510
545
|
}
|
|
511
546
|
function sustainsStrokes(stepBeats, bpm, difficulty) {
|
|
512
547
|
if (difficulty === void 0 || bpm === void 0) {
|
|
513
548
|
return true;
|
|
514
549
|
}
|
|
515
550
|
assertDifficulty(difficulty);
|
|
516
|
-
|
|
517
|
-
if (
|
|
551
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, bpm, "bpm");
|
|
552
|
+
if (_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, stepBeats, "stepBeats") <= 0) {
|
|
518
553
|
return true;
|
|
519
554
|
}
|
|
520
555
|
const rate = 1 / (stepBeats * secondsPerBeat(bpm));
|
|
@@ -525,9 +560,9 @@ function sustainsShift(semitones, stepBeats, bpm, difficulty) {
|
|
|
525
560
|
return true;
|
|
526
561
|
}
|
|
527
562
|
assertDifficulty(difficulty);
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if (
|
|
563
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, bpm, "bpm");
|
|
564
|
+
_chunkS5BKZZGMcjs.assertFiniteSemitones.call(void 0, semitones);
|
|
565
|
+
if (_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, stepBeats, "stepBeats") <= 0) {
|
|
531
566
|
return true;
|
|
532
567
|
}
|
|
533
568
|
const seconds = stepBeats * secondsPerBeat(bpm);
|
|
@@ -539,20 +574,20 @@ var DEFAULT_SEED = 0;
|
|
|
539
574
|
var VERSION_SEGMENT = "v";
|
|
540
575
|
function resolveContext(input) {
|
|
541
576
|
if (input !== null && typeof input !== "number" && input !== void 0) {
|
|
542
|
-
|
|
577
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, input, "ctx");
|
|
543
578
|
}
|
|
544
579
|
if (input === null) {
|
|
545
|
-
throw new (0,
|
|
580
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("ctx must be a seed or a generation context; received null");
|
|
546
581
|
}
|
|
547
582
|
const ctx = typeof input === "number" ? { seed: input } : _nullishCoalesce(input, () => ( { seed: DEFAULT_SEED }));
|
|
548
|
-
const seed =
|
|
583
|
+
const seed = _chunkS5BKZZGMcjs.assertInteger.call(void 0, _nullishCoalesce(ctx.seed, () => ( DEFAULT_SEED)), "seed", 0, 4294967295);
|
|
549
584
|
const complexity = _nullishCoalesce(ctx.complexity, () => ( {}));
|
|
550
|
-
const rhythmic = complexity.rhythmic === void 0 ? void 0 :
|
|
551
|
-
const harmonic = complexity.harmonic === void 0 ? void 0 :
|
|
552
|
-
const ornament2 = complexity.ornament === void 0 ? void 0 :
|
|
585
|
+
const rhythmic = complexity.rhythmic === void 0 ? void 0 : _chunkS5BKZZGMcjs.assertRange.call(void 0, complexity.rhythmic, 0, 1, "complexity rhythmic");
|
|
586
|
+
const harmonic = complexity.harmonic === void 0 ? void 0 : _chunkS5BKZZGMcjs.assertRange.call(void 0, complexity.harmonic, 0, 1, "complexity harmonic");
|
|
587
|
+
const ornament2 = complexity.ornament === void 0 ? void 0 : _chunkS5BKZZGMcjs.assertRange.call(void 0, complexity.ornament, 0, 1, "complexity ornament");
|
|
553
588
|
const difficulty = complexity.difficulty === void 0 ? void 0 : assertDifficulty(complexity.difficulty);
|
|
554
|
-
const bpm = ctx.bpm === void 0 ? void 0 :
|
|
555
|
-
const algorithmVersion =
|
|
589
|
+
const bpm = ctx.bpm === void 0 ? void 0 : _chunkS5BKZZGMcjs.assertRange.call(void 0, ctx.bpm, Number.MIN_VALUE, 1e3, "bpm");
|
|
590
|
+
const algorithmVersion = _chunkCGBADIO5cjs.resolveAlgorithmVersion.call(void 0, ctx.algorithmVersion);
|
|
556
591
|
const supplied = ctx.rng;
|
|
557
592
|
const instruments = ctx.instruments;
|
|
558
593
|
const vocabulary = (_nullishCoalesce(ctx.vocabulary, () => ( []))).map(
|
|
@@ -568,12 +603,12 @@ function resolveContext(input) {
|
|
|
568
603
|
algorithmVersion,
|
|
569
604
|
instrument: (part) => _optionalChain([instruments, 'optionalAccess', _4 => _4[part]]),
|
|
570
605
|
vocabulary,
|
|
571
|
-
part: (name) => supplied ? drawsFrom(supplied, name, VERSION_SEGMENT, algorithmVersion) : drawsFrom(
|
|
606
|
+
part: (name) => supplied ? drawsFrom(supplied, name, VERSION_SEGMENT, algorithmVersion) : drawsFrom(_chunkCGBADIO5cjs.createPositionalRng.call(void 0, _chunkCGBADIO5cjs.deriveSeed.call(void 0, seed, name, VERSION_SEGMENT, algorithmVersion)))
|
|
572
607
|
};
|
|
573
608
|
}
|
|
574
609
|
function resolveContextWith(input, sugar) {
|
|
575
610
|
const base = resolveContext(input);
|
|
576
|
-
const supplied = sugar.ornament === void 0 ? void 0 :
|
|
611
|
+
const supplied = sugar.ornament === void 0 ? void 0 : _chunkS5BKZZGMcjs.assertRange.call(void 0, sugar.ornament, 0, 1, "complexity ornament");
|
|
577
612
|
const ornament2 = _nullishCoalesce(base.ornament, () => ( supplied));
|
|
578
613
|
return { ...base, ornament: ornament2 };
|
|
579
614
|
}
|
|
@@ -590,14 +625,14 @@ function placeAboveBass(pc, bassMidi) {
|
|
|
590
625
|
return foldIntoBand(pc + 12 * Math.round((bassMidi - pc) / 12), bassMidi);
|
|
591
626
|
}
|
|
592
627
|
function placeRoot(pc, low) {
|
|
593
|
-
return low +
|
|
628
|
+
return low + _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - low);
|
|
594
629
|
}
|
|
595
630
|
function barTiles(startBeat, endBeat, ts) {
|
|
596
|
-
const barBeats =
|
|
631
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts);
|
|
597
632
|
const tiles = [];
|
|
598
633
|
for (let index = 0; ; index += 1) {
|
|
599
634
|
const tileStart = startBeat + index * barBeats;
|
|
600
|
-
if (tileStart >= endBeat -
|
|
635
|
+
if (tileStart >= endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
601
636
|
break;
|
|
602
637
|
}
|
|
603
638
|
tiles.push({ startBeat: tileStart, endBeat: Math.min(tileStart + barBeats, endBeat) });
|
|
@@ -605,8 +640,8 @@ function barTiles(startBeat, endBeat, ts) {
|
|
|
605
640
|
return tiles;
|
|
606
641
|
}
|
|
607
642
|
function midBarPulse(barStart, ts) {
|
|
608
|
-
const pulse2 =
|
|
609
|
-
return barStart + Math.floor((
|
|
643
|
+
const pulse2 = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, ts);
|
|
644
|
+
return barStart + Math.floor((_chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts) / 2 + _chunkS5BKZZGMcjs.BEAT_EPS) / pulse2) * pulse2;
|
|
610
645
|
}
|
|
611
646
|
function assertBassSegments(segments) {
|
|
612
647
|
for (let index = 0; index < segments.length; index += 1) {
|
|
@@ -614,14 +649,14 @@ function assertBassSegments(segments) {
|
|
|
614
649
|
if (segment === void 0) {
|
|
615
650
|
continue;
|
|
616
651
|
}
|
|
617
|
-
|
|
618
|
-
|
|
652
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, segment.startBeat, 0, Number.MAX_SAFE_INTEGER, `segments[${index}].startBeat`);
|
|
653
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, segment.endBeat, 0, Number.MAX_SAFE_INTEGER, `segments[${index}].endBeat`);
|
|
619
654
|
if (segment.endBeat <= segment.startBeat) {
|
|
620
|
-
throw new (0,
|
|
655
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`segments[${index}] must have a positive duration`);
|
|
621
656
|
}
|
|
622
657
|
const previous = segments[index - 1];
|
|
623
|
-
if (previous !== void 0 && segment.startBeat < previous.endBeat -
|
|
624
|
-
throw new (0,
|
|
658
|
+
if (previous !== void 0 && segment.startBeat < previous.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
659
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
625
660
|
`bass segments must not overlap: segments ${index - 1} and ${index} overlap`
|
|
626
661
|
);
|
|
627
662
|
}
|
|
@@ -631,22 +666,22 @@ function chordTonePcs(chord) {
|
|
|
631
666
|
const seen = /* @__PURE__ */ new Set();
|
|
632
667
|
const pcs = [];
|
|
633
668
|
for (const interval of chord.intervals) {
|
|
634
|
-
const pc =
|
|
669
|
+
const pc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval);
|
|
635
670
|
if (!seen.has(pc)) {
|
|
636
671
|
seen.add(pc);
|
|
637
672
|
pcs.push(pc);
|
|
638
673
|
}
|
|
639
674
|
}
|
|
640
675
|
if (pcs.length === 0) {
|
|
641
|
-
pcs.push(
|
|
676
|
+
pcs.push(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc));
|
|
642
677
|
}
|
|
643
678
|
return pcs;
|
|
644
679
|
}
|
|
645
680
|
function fifthPcOf2(chord) {
|
|
646
|
-
return _nullishCoalesce(
|
|
681
|
+
return _nullishCoalesce(_chunk3R3QVKY5cjs.fifthPcOf.call(void 0, chord), () => ( _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc)));
|
|
647
682
|
}
|
|
648
683
|
function bassPcOf(chord) {
|
|
649
|
-
return
|
|
684
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc)));
|
|
650
685
|
}
|
|
651
686
|
function bassToneCycle(chord) {
|
|
652
687
|
const bass = bassPcOf(chord);
|
|
@@ -656,19 +691,19 @@ function bassToneCycle(chord) {
|
|
|
656
691
|
}
|
|
657
692
|
function beatPositions(start, end, ts) {
|
|
658
693
|
const positions = [];
|
|
659
|
-
const barBeats =
|
|
660
|
-
const pulse2 =
|
|
694
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts);
|
|
695
|
+
const pulse2 = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, ts);
|
|
661
696
|
const firstBar = Math.floor(start / barBeats);
|
|
662
|
-
const lastBar = Math.floor((end -
|
|
697
|
+
const lastBar = Math.floor((end - _chunkS5BKZZGMcjs.BEAT_EPS) / barBeats);
|
|
663
698
|
for (let bar2 = firstBar; bar2 <= lastBar; bar2 += 1) {
|
|
664
699
|
const barStart = bar2 * barBeats;
|
|
665
|
-
const firstPulse = Math.max(0, Math.ceil((start - barStart -
|
|
700
|
+
const firstPulse = Math.max(0, Math.ceil((start - barStart - _chunkS5BKZZGMcjs.BEAT_EPS) / pulse2));
|
|
666
701
|
for (let index = firstPulse; ; index += 1) {
|
|
667
702
|
const position = barStart + index * pulse2;
|
|
668
|
-
if (position >= barStart + barBeats -
|
|
703
|
+
if (position >= barStart + barBeats - _chunkS5BKZZGMcjs.BEAT_EPS || position >= end - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
669
704
|
break;
|
|
670
705
|
}
|
|
671
|
-
if (position >= start -
|
|
706
|
+
if (position >= start - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
672
707
|
positions.push(position);
|
|
673
708
|
}
|
|
674
709
|
}
|
|
@@ -686,7 +721,7 @@ function bandFloor(low, instrument) {
|
|
|
686
721
|
if (!instrument) {
|
|
687
722
|
return low;
|
|
688
723
|
}
|
|
689
|
-
const range =
|
|
724
|
+
const range = _chunkCGBADIO5cjs.instrumentRange.call(void 0, instrument);
|
|
690
725
|
const dropped = low - 12 * Math.max(0, Math.ceil((low + 12 - range.high) / 12));
|
|
691
726
|
return dropped + 12 * Math.max(0, Math.ceil((range.low - dropped) / 12));
|
|
692
727
|
}
|
|
@@ -705,12 +740,12 @@ function neighborOnSide(target, dir, key, chromatic) {
|
|
|
705
740
|
if (chromatic) {
|
|
706
741
|
return semitone;
|
|
707
742
|
}
|
|
708
|
-
const cand =
|
|
743
|
+
const cand = _chunk3R3QVKY5cjs.nearestScaleTone.call(void 0, target + dir * 2, key);
|
|
709
744
|
const step = Math.abs(cand - target);
|
|
710
745
|
return step >= 1 && step <= 2 ? cand : semitone;
|
|
711
746
|
}
|
|
712
747
|
function bassRegister(named, given, octave) {
|
|
713
|
-
const instrument = given === void 0 ? named !== void 0 && named.kind === "stringed" ? named : void 0 :
|
|
748
|
+
const instrument = given === void 0 ? named !== void 0 && named.kind === "stringed" ? named : void 0 : _chunkCGBADIO5cjs.toStringedProfile.call(void 0, given, "instrument");
|
|
714
749
|
return { instrument, low: bandFloor(octave * 12 + 12, instrument) };
|
|
715
750
|
}
|
|
716
751
|
|
|
@@ -719,31 +754,31 @@ var BAR_STEPS = 16;
|
|
|
719
754
|
var BEAT_STEPS = 4;
|
|
720
755
|
var STEP_BEATS = 1 / BEAT_STEPS;
|
|
721
756
|
function assertGridEvents(events) {
|
|
722
|
-
|
|
757
|
+
_chunkS5BKZZGMcjs.assertArray.call(void 0, events, "figure events");
|
|
723
758
|
events.forEach((event, index) => {
|
|
724
|
-
|
|
725
|
-
|
|
759
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, event, `figure events[${index}]`);
|
|
760
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, event.step, `figure events[${index}].step`);
|
|
726
761
|
});
|
|
727
762
|
return events;
|
|
728
763
|
}
|
|
729
764
|
function assertSpanSteps(spanSteps) {
|
|
730
|
-
return
|
|
765
|
+
return _chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, spanSteps, "figure span steps");
|
|
731
766
|
}
|
|
732
767
|
function streamOf(event) {
|
|
733
768
|
return _nullishCoalesce(_nullishCoalesce(event.limb, () => ( event.voice)), () => ( ""));
|
|
734
769
|
}
|
|
735
770
|
var FIGURE_TS = { numerator: 4, denominator: 4 };
|
|
736
771
|
function subdivisionBeats(ts) {
|
|
737
|
-
const pulse2 =
|
|
738
|
-
return
|
|
772
|
+
const pulse2 = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, ts);
|
|
773
|
+
return _chunkS5BKZZGMcjs.isCompound.call(void 0, ts) ? pulse2 / 3 : pulse2 / 2;
|
|
739
774
|
}
|
|
740
775
|
function gridMetricWeight(step, ts) {
|
|
741
|
-
|
|
742
|
-
return stepWeight(step,
|
|
776
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, step, "step");
|
|
777
|
+
return stepWeight(step, _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, ts, "ts")));
|
|
743
778
|
}
|
|
744
779
|
function stepWeight(step, ts) {
|
|
745
780
|
const beats = step * STEP_BEATS;
|
|
746
|
-
const weight =
|
|
781
|
+
const weight = _chunkS5BKZZGMcjs.metricWeight.call(void 0, beats, ts);
|
|
747
782
|
if (weight > 0) {
|
|
748
783
|
return weight + 1;
|
|
749
784
|
}
|
|
@@ -753,8 +788,8 @@ function stepWeight(step, ts) {
|
|
|
753
788
|
}
|
|
754
789
|
function thin(events, amount, ts) {
|
|
755
790
|
const figure = assertGridEvents(events);
|
|
756
|
-
|
|
757
|
-
const signature =
|
|
791
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, amount, 0, 1, "thin amount");
|
|
792
|
+
const signature = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, ts, "ts"));
|
|
758
793
|
const floor = Math.min(4, Math.floor(amount * 5));
|
|
759
794
|
return figure.filter((event) => stepWeight(event.step, signature) >= floor);
|
|
760
795
|
}
|
|
@@ -806,10 +841,10 @@ function syncopate(events, amount, draw, ...path) {
|
|
|
806
841
|
const figure = assertGridEvents(events);
|
|
807
842
|
const sampler = assertDraw(draw);
|
|
808
843
|
assertSeedPath(path);
|
|
809
|
-
const asked = typeof amount === "number" ? void 0 :
|
|
844
|
+
const asked = typeof amount === "number" ? void 0 : _chunkS5BKZZGMcjs.assertRecord.call(void 0, amount, "amount");
|
|
810
845
|
const dial = asked === void 0 ? amount : asked.amount;
|
|
811
|
-
const signature =
|
|
812
|
-
|
|
846
|
+
const signature = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(_optionalChain([asked, 'optionalAccess', _7 => _7.ts]), () => ( FIGURE_TS)), "ts"));
|
|
847
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, dial, 0, 1, "syncopate amount");
|
|
813
848
|
const occupied = new Set(figure.map((event) => `${streamOf(event)}@${event.step}`));
|
|
814
849
|
const out = [...figure];
|
|
815
850
|
for (const event of figure) {
|
|
@@ -826,10 +861,10 @@ function syncopate(events, amount, draw, ...path) {
|
|
|
826
861
|
}
|
|
827
862
|
function ornamentBy(events, isOrnament, amount, draw, ...path) {
|
|
828
863
|
const figure = assertGridEvents(events);
|
|
829
|
-
const marks =
|
|
864
|
+
const marks = _chunkS5BKZZGMcjs.assertFunction.call(void 0, isOrnament, "isOrnament");
|
|
830
865
|
const sampler = assertDraw(draw);
|
|
831
866
|
assertSeedPath(path);
|
|
832
|
-
|
|
867
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, amount, 0, 1, "ornament amount");
|
|
833
868
|
return figure.filter(
|
|
834
869
|
(event) => !marks(event) || sampler.prob(amount, ...path, "ornament", event.step)
|
|
835
870
|
);
|
|
@@ -837,14 +872,14 @@ function ornamentBy(events, isOrnament, amount, draw, ...path) {
|
|
|
837
872
|
var NEUTRAL_RHYTHMIC = 0.5;
|
|
838
873
|
function deform(events, opts, draw, ...path) {
|
|
839
874
|
const figure = assertGridEvents(events);
|
|
840
|
-
const asked =
|
|
875
|
+
const asked = _chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "opts");
|
|
841
876
|
assertDraw(draw);
|
|
842
877
|
assertSeedPath(path);
|
|
843
878
|
const spanSteps = assertSpanSteps(asked.spanSteps === void 0 ? BAR_STEPS : asked.spanSteps);
|
|
844
879
|
const ts = _nullishCoalesce(asked.ts, () => ( FIGURE_TS));
|
|
845
880
|
let out = asked.rate === "half" ? halfTime(figure, spanSteps) : asked.rate === "double" ? doubleTime(figure, spanSteps) : [...figure];
|
|
846
881
|
if (asked.rhythmic !== void 0) {
|
|
847
|
-
const rhythmic =
|
|
882
|
+
const rhythmic = _chunkS5BKZZGMcjs.assertRange.call(void 0, asked.rhythmic, 0, 1, "complexity rhythmic");
|
|
848
883
|
if (rhythmic < NEUTRAL_RHYTHMIC) {
|
|
849
884
|
out = thin(out, (NEUTRAL_RHYTHMIC - rhythmic) / NEUTRAL_RHYTHMIC, ts);
|
|
850
885
|
} else if (rhythmic > NEUTRAL_RHYTHMIC) {
|
|
@@ -857,7 +892,7 @@ function deform(events, opts, draw, ...path) {
|
|
|
857
892
|
}
|
|
858
893
|
}
|
|
859
894
|
if (asked.ornament !== void 0 && asked.isOrnament) {
|
|
860
|
-
const isOrnament =
|
|
895
|
+
const isOrnament = _chunkS5BKZZGMcjs.assertFunction.call(void 0, asked.isOrnament, "opts.isOrnament");
|
|
861
896
|
out = ornamentBy(out, (event) => isOrnament(event), asked.ornament, draw, ...path);
|
|
862
897
|
}
|
|
863
898
|
return out.sort((a, b) => a.step - b.step);
|
|
@@ -867,7 +902,7 @@ function withinCeiling(events, bpm, difficulty) {
|
|
|
867
902
|
if (difficulty === void 0 || bpm === void 0) {
|
|
868
903
|
return true;
|
|
869
904
|
}
|
|
870
|
-
|
|
905
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, bpm, "bpm");
|
|
871
906
|
assertDifficulty(difficulty);
|
|
872
907
|
if (figure.length < 2) {
|
|
873
908
|
return true;
|
|
@@ -905,8 +940,8 @@ function impliedScaleTones(chord) {
|
|
|
905
940
|
if (chordDegreeSemitone(7, chord) === void 0) {
|
|
906
941
|
return void 0;
|
|
907
942
|
}
|
|
908
|
-
for (const match of
|
|
909
|
-
const mask =
|
|
943
|
+
for (const match of _chunkPM4XJE2Ycjs.chordScales.call(void 0, chord)) {
|
|
944
|
+
const mask = _chunk3R3QVKY5cjs.namedScaleMask.call(void 0, match.name);
|
|
910
945
|
if (mask === void 0) {
|
|
911
946
|
continue;
|
|
912
947
|
}
|
|
@@ -926,7 +961,7 @@ function replacedDegreeSemitone(degree, chord) {
|
|
|
926
961
|
if (degree !== 3) {
|
|
927
962
|
return void 0;
|
|
928
963
|
}
|
|
929
|
-
const sounds = (semitones) => chord.intervals.some((interval) =>
|
|
964
|
+
const sounds = (semitones) => chord.intervals.some((interval) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval) === semitones);
|
|
930
965
|
if (sounds(3) || sounds(4)) {
|
|
931
966
|
return void 0;
|
|
932
967
|
}
|
|
@@ -938,12 +973,12 @@ function degreeSemitone(degree, alter, chord, key, implied) {
|
|
|
938
973
|
const template = _nullishCoalesce(MAJOR_DEGREE_SEMITONES[within - 1], () => ( 0));
|
|
939
974
|
const semitone = alter !== 0 ? template : _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(chordDegreeSemitone(within, chord), () => ( replacedDegreeSemitone(within, chord))), () => ( _optionalChain([implied, 'optionalAccess', _8 => _8[within - 1]]))), () => ( // A degree neither the chord nor its quality settles is a passing tone,
|
|
940
975
|
// so the key decides it.
|
|
941
|
-
|
|
942
|
-
return
|
|
976
|
+
_chunk3R3QVKY5cjs.nearestScaleTone.call(void 0, chord.rootPc + template, key) - chord.rootPc));
|
|
977
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, semitone) + 12 * octaves + alter;
|
|
943
978
|
}
|
|
944
979
|
function chordDegreeSemitone(degree, chord) {
|
|
945
980
|
for (const interval of chord.intervals) {
|
|
946
|
-
if (
|
|
981
|
+
if (_chunk3R3QVKY5cjs.degreeOfInterval.call(void 0, interval, chord) === degree) {
|
|
947
982
|
return interval;
|
|
948
983
|
}
|
|
949
984
|
}
|
|
@@ -1173,28 +1208,28 @@ var BASS_LICKS = deepFreeze([
|
|
|
1173
1208
|
var DEFAULT_BPM = 120;
|
|
1174
1209
|
var DEFAULT_LICK_DENSITY = 0.6;
|
|
1175
1210
|
function placeLicks(timeline, key, opts) {
|
|
1176
|
-
const asked =
|
|
1177
|
-
const placement =
|
|
1211
|
+
const asked = _chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "opts");
|
|
1212
|
+
const placement = _chunkS5BKZZGMcjs.assertArray.call(void 0,
|
|
1178
1213
|
timeline,
|
|
1179
1214
|
"timeline"
|
|
1180
1215
|
);
|
|
1181
|
-
|
|
1182
|
-
const genre =
|
|
1183
|
-
const ts =
|
|
1216
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, placement.length, "lick segments", asked.budget);
|
|
1217
|
+
const genre = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, asked.genre, GENRES, "lick genre");
|
|
1218
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(asked.ts, () => ( DEFAULT_TS)), "ts"));
|
|
1184
1219
|
const octave = _nullishCoalesce(asked.octave, () => ( DEFAULT_OCTAVE));
|
|
1185
|
-
|
|
1186
|
-
const scale =
|
|
1187
|
-
const segments = placement.map((segment) => ({ ...segment, chord:
|
|
1220
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, octave, "lick octave", -1, 8);
|
|
1221
|
+
const scale = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key);
|
|
1222
|
+
const segments = placement.map((segment) => ({ ...segment, chord: _chunk3R3QVKY5cjs.toChordData.call(void 0, segment.chord) })).sort((a, b) => a.startBeat - b.startBeat);
|
|
1188
1223
|
assertBassSegments(segments);
|
|
1189
1224
|
if (segments.length === 0) {
|
|
1190
1225
|
return [];
|
|
1191
1226
|
}
|
|
1192
|
-
const barBeats =
|
|
1227
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts);
|
|
1193
1228
|
const estimatedBars = segments.reduce(
|
|
1194
1229
|
(count, segment) => count + Math.max(1, Math.ceil((segment.endBeat - segment.startBeat) / barBeats)),
|
|
1195
1230
|
0
|
|
1196
1231
|
);
|
|
1197
|
-
|
|
1232
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, estimatedBars, "lick bars", asked.budget);
|
|
1198
1233
|
const resolved = resolveContext(asked.ctx);
|
|
1199
1234
|
const draw = resolved.part("bass");
|
|
1200
1235
|
const bpm = _nullishCoalesce(resolved.bpm, () => ( DEFAULT_BPM));
|
|
@@ -1254,7 +1289,7 @@ function placeLicks(timeline, key, opts) {
|
|
|
1254
1289
|
}
|
|
1255
1290
|
raw.push({ startBeat: rootAt, pitch: rootMidi, velocity: STRONG_VELOCITY });
|
|
1256
1291
|
if (notes) {
|
|
1257
|
-
const figureRoot = segment.chord.bassPc === void 0 ? placePc(
|
|
1292
|
+
const figureRoot = segment.chord.bassPc === void 0 ? placePc(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, segment.chord.rootPc), rootMidi, low) : placeAboveBass(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, segment.chord.rootPc), rootMidi);
|
|
1258
1293
|
for (const lickNote of notes) {
|
|
1259
1294
|
const at2 = tileStart + lickNote.step * STEP_BEATS;
|
|
1260
1295
|
const offset = degreeSemitone(
|
|
@@ -1264,12 +1299,12 @@ function placeLicks(timeline, key, opts) {
|
|
|
1264
1299
|
scale,
|
|
1265
1300
|
implied
|
|
1266
1301
|
);
|
|
1267
|
-
const pitch = Math.abs(at2 - rootAt) <
|
|
1302
|
+
const pitch = Math.abs(at2 - rootAt) < _chunkS5BKZZGMcjs.BEAT_EPS && lickNote.degree === 1 && (_nullishCoalesce(lickNote.alter, () => ( 0))) === 0 ? rootMidi : figureRoot + offset;
|
|
1268
1303
|
raw.push({
|
|
1269
1304
|
startBeat: at2,
|
|
1270
1305
|
pitch,
|
|
1271
1306
|
velocity: Math.round(
|
|
1272
|
-
(
|
|
1307
|
+
(_chunkS5BKZZGMcjs.isStrongBeat.call(void 0, at2, ts) ? STRONG_VELOCITY : WEAK_VELOCITY) * lickNote.velocity
|
|
1273
1308
|
),
|
|
1274
1309
|
note: lickNote
|
|
1275
1310
|
});
|
|
@@ -1280,7 +1315,7 @@ function placeLicks(timeline, key, opts) {
|
|
|
1280
1315
|
if (next && lastTilePlayed) {
|
|
1281
1316
|
const lastBeat = next.startBeat - STEP_BEATS * BEAT_STEPS;
|
|
1282
1317
|
const approachAt = _nullishCoalesce(materialOnsetIn(playedTile, lastBeat, next.startBeat), () => ( lastBeat));
|
|
1283
|
-
if (approachAt > firstOnset +
|
|
1318
|
+
if (approachAt > firstOnset + _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1284
1319
|
const nextRoot = placeRoot(bassPcOf(next.chord), low);
|
|
1285
1320
|
const occupied = soundingAt(raw, approachAt);
|
|
1286
1321
|
const distance = occupied === void 0 ? 0 : Math.abs(occupied.pitch - nextRoot);
|
|
@@ -1310,12 +1345,12 @@ function placeLicks(timeline, key, opts) {
|
|
|
1310
1345
|
nextStart - item.startBeat,
|
|
1311
1346
|
written === void 0 ? Number.POSITIVE_INFINITY : written * STEP_BEATS
|
|
1312
1347
|
);
|
|
1313
|
-
if (durationBeat <=
|
|
1348
|
+
if (durationBeat <= _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1314
1349
|
continue;
|
|
1315
1350
|
}
|
|
1316
|
-
const placed = instrument ?
|
|
1351
|
+
const placed = instrument ? _chunkCGBADIO5cjs.foldIntoRange.call(void 0, item.pitch, instrument) : item.pitch;
|
|
1317
1352
|
const event = {
|
|
1318
|
-
pitch:
|
|
1353
|
+
pitch: _chunkS5BKZZGMcjs.clampToMidi.call(void 0, placed, "generated bass pitch"),
|
|
1319
1354
|
startBeat: item.startBeat,
|
|
1320
1355
|
durationBeat,
|
|
1321
1356
|
velocity: Math.max(1, Math.min(127, item.velocity))
|
|
@@ -1330,7 +1365,7 @@ function placeLicks(timeline, key, opts) {
|
|
|
1330
1365
|
function soundingAt(raw, at2) {
|
|
1331
1366
|
for (let index = raw.length - 1; index >= 0; index -= 1) {
|
|
1332
1367
|
const item = raw[index];
|
|
1333
|
-
if (item !== void 0 && Math.abs(item.startBeat - at2) <
|
|
1368
|
+
if (item !== void 0 && Math.abs(item.startBeat - at2) < _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1334
1369
|
return item;
|
|
1335
1370
|
}
|
|
1336
1371
|
}
|
|
@@ -1343,7 +1378,7 @@ function materialOnsetIn(played, from, to) {
|
|
|
1343
1378
|
let last;
|
|
1344
1379
|
for (const note2 of played.material.notes) {
|
|
1345
1380
|
const at2 = played.tileStart + note2.step * STEP_BEATS;
|
|
1346
|
-
if (at2 < from -
|
|
1381
|
+
if (at2 < from - _chunkS5BKZZGMcjs.BEAT_EPS || at2 > to - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1347
1382
|
continue;
|
|
1348
1383
|
}
|
|
1349
1384
|
last = last === void 0 ? at2 : Math.max(last, at2);
|
|
@@ -1353,7 +1388,7 @@ function materialOnsetIn(played, from, to) {
|
|
|
1353
1388
|
function lastPitchBefore(raw, at2, fallback) {
|
|
1354
1389
|
for (let index = raw.length - 1; index >= 0; index -= 1) {
|
|
1355
1390
|
const item = raw[index];
|
|
1356
|
-
if (item !== void 0 && item.startBeat < at2 -
|
|
1391
|
+
if (item !== void 0 && item.startBeat < at2 - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1357
1392
|
return item.pitch;
|
|
1358
1393
|
}
|
|
1359
1394
|
}
|
|
@@ -1366,7 +1401,7 @@ function anchorStepOf(material, spanBeats) {
|
|
|
1366
1401
|
first = note2.step;
|
|
1367
1402
|
}
|
|
1368
1403
|
}
|
|
1369
|
-
if (first === void 0 || first < 0 || first * STEP_BEATS >= spanBeats -
|
|
1404
|
+
if (first === void 0 || first < 0 || first * STEP_BEATS >= spanBeats - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1370
1405
|
return 0;
|
|
1371
1406
|
}
|
|
1372
1407
|
return first;
|
|
@@ -1393,7 +1428,7 @@ function fitToSegment(material, spanBeats, density, resolved, draw, path, bpm, d
|
|
|
1393
1428
|
...path
|
|
1394
1429
|
);
|
|
1395
1430
|
const spanSteps = spanBeats / STEP_BEATS;
|
|
1396
|
-
const inside = deformed.filter((lickNote) => lickNote.step < spanSteps -
|
|
1431
|
+
const inside = deformed.filter((lickNote) => lickNote.step < spanSteps - _chunkS5BKZZGMcjs.BEAT_EPS);
|
|
1397
1432
|
if (inside.length === 0 || !withinCeiling(inside, bpm, difficulty)) {
|
|
1398
1433
|
return void 0;
|
|
1399
1434
|
}
|
|
@@ -1411,15 +1446,15 @@ var BASS_STYLES = Object.freeze([
|
|
|
1411
1446
|
var DEFAULT_STYLE = "root";
|
|
1412
1447
|
var DEFAULT_PICKUP_DENSITY = 0.35;
|
|
1413
1448
|
function sounding(ctx, placed) {
|
|
1414
|
-
return ctx.instrument ?
|
|
1449
|
+
return ctx.instrument ? _chunkCGBADIO5cjs.foldIntoRange.call(void 0, placed, ctx.instrument) : placed;
|
|
1415
1450
|
}
|
|
1416
1451
|
function placeTone(ctx, pc) {
|
|
1417
1452
|
return ctx.overBass ? placeAboveBass(pc, ctx.rootMidi) : placePc(pc, ctx.rootMidi, ctx.low);
|
|
1418
1453
|
}
|
|
1419
1454
|
function emit(ctx, pos, pc, midiOverride) {
|
|
1420
|
-
const placed =
|
|
1455
|
+
const placed = _chunkS5BKZZGMcjs.clampToMidi.call(void 0, _nullishCoalesce(midiOverride, () => ( placeTone(ctx, pc))), "generated bass pitch");
|
|
1421
1456
|
const midi = sounding(ctx, placed);
|
|
1422
|
-
const velocity =
|
|
1457
|
+
const velocity = _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, pos, ctx.ts) ? STRONG_VELOCITY : WEAK_VELOCITY;
|
|
1423
1458
|
ctx.notes.push({ startBeat: pos, pitch: midi, velocity });
|
|
1424
1459
|
ctx.prevMidi = midi;
|
|
1425
1460
|
return midi;
|
|
@@ -1431,7 +1466,7 @@ function buildRootFifth(ctx, seg) {
|
|
|
1431
1466
|
for (const tile of barTiles(seg.startBeat, seg.endBeat, ctx.ts)) {
|
|
1432
1467
|
emit(ctx, tile.startBeat, bassPcOf(seg.chord));
|
|
1433
1468
|
const answer = midBarPulse(tile.startBeat, ctx.ts);
|
|
1434
|
-
if (answer > tile.startBeat +
|
|
1469
|
+
if (answer > tile.startBeat + _chunkS5BKZZGMcjs.BEAT_EPS && answer < tile.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1435
1470
|
emit(ctx, answer, fifthPcOf2(seg.chord));
|
|
1436
1471
|
}
|
|
1437
1472
|
}
|
|
@@ -1441,7 +1476,7 @@ function buildPop(ctx, seg, index) {
|
|
|
1441
1476
|
const rootPc = bassPcOf(seg.chord);
|
|
1442
1477
|
let emitted = false;
|
|
1443
1478
|
for (const pos of positions) {
|
|
1444
|
-
if (
|
|
1479
|
+
if (_chunkS5BKZZGMcjs.isStrongBeat.call(void 0, pos, ctx.ts)) {
|
|
1445
1480
|
emit(ctx, pos, rootPc);
|
|
1446
1481
|
emitted = true;
|
|
1447
1482
|
} else if (ctx.draw.prob(ctx.pickupDensity, "pickup", index, pos)) {
|
|
@@ -1502,7 +1537,7 @@ function buildWalking(ctx, seg, next, index) {
|
|
|
1502
1537
|
if (next && count > 1 && i === count - 1) {
|
|
1503
1538
|
const nextBass = placeRoot(bassPcOf(next.chord), ctx.low);
|
|
1504
1539
|
const midi = approachNote2(ctx, nextBass, ctx.prevMidi, index);
|
|
1505
|
-
emit(ctx, pos,
|
|
1540
|
+
emit(ctx, pos, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, midi), midi);
|
|
1506
1541
|
return;
|
|
1507
1542
|
}
|
|
1508
1543
|
const pc = _nullishCoalesce(tones[i % tones.length], () => ( bassPcOf(seg.chord)));
|
|
@@ -1510,29 +1545,29 @@ function buildWalking(ctx, seg, next, index) {
|
|
|
1510
1545
|
});
|
|
1511
1546
|
}
|
|
1512
1547
|
function generateBassLine(opts) {
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
const segments = opts.segments.map((segment) => ({ ...segment, chord:
|
|
1548
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "bass line options");
|
|
1549
|
+
_chunkS5BKZZGMcjs.assertArray.call(void 0, opts.segments, "bass segments");
|
|
1550
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, opts.segments.length, "bass segments", opts.budget);
|
|
1551
|
+
const segments = opts.segments.map((segment) => ({ ...segment, chord: _chunk3R3QVKY5cjs.toChordData.call(void 0, segment.chord) })).sort((a, b) => a.startBeat - b.startBeat);
|
|
1517
1552
|
assertBassSegments(segments);
|
|
1518
1553
|
if (segments.length === 0) {
|
|
1519
1554
|
return [];
|
|
1520
1555
|
}
|
|
1521
|
-
const ts =
|
|
1522
|
-
const style =
|
|
1556
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(opts.ts, () => ( DEFAULT_TS)), "ts"));
|
|
1557
|
+
const style = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, _nullishCoalesce(opts.style, () => ( DEFAULT_STYLE)), BASS_STYLES, "bass style");
|
|
1523
1558
|
const octave = _nullishCoalesce(opts.octave, () => ( DEFAULT_OCTAVE));
|
|
1524
|
-
|
|
1559
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, octave, "bass octave", -1, 8);
|
|
1525
1560
|
const estimatedNotes = segments.reduce(
|
|
1526
1561
|
(count, segment) => count + Math.max(1, Math.ceil(segment.endBeat - segment.startBeat)),
|
|
1527
1562
|
0
|
|
1528
1563
|
);
|
|
1529
|
-
|
|
1564
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, estimatedNotes, "bass notes", opts.budget);
|
|
1530
1565
|
const resolved = resolveContext(opts.ctx);
|
|
1531
1566
|
const { instrument, low } = bassRegister(resolved.instrument("bass"), opts.instrument, octave);
|
|
1532
1567
|
const ctx = {
|
|
1533
1568
|
ts,
|
|
1534
1569
|
low,
|
|
1535
|
-
key:
|
|
1570
|
+
key: _chunk3R3QVKY5cjs.toKeyScale.call(void 0, opts.key),
|
|
1536
1571
|
draw: resolved.part("bass"),
|
|
1537
1572
|
notes: [],
|
|
1538
1573
|
rootMidi: low,
|
|
@@ -1578,11 +1613,11 @@ function generateBassLine(opts) {
|
|
|
1578
1613
|
}
|
|
1579
1614
|
const nextStart = _nullishCoalesce(_optionalChain([ctx, 'access', _17 => _17.notes, 'access', _18 => _18[i + 1], 'optionalAccess', _19 => _19.startBeat]), () => ( lastEnd));
|
|
1580
1615
|
const durationBeat = nextStart - note2.startBeat;
|
|
1581
|
-
if (durationBeat <=
|
|
1616
|
+
if (durationBeat <= _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1582
1617
|
continue;
|
|
1583
1618
|
}
|
|
1584
1619
|
out.push({
|
|
1585
|
-
pitch:
|
|
1620
|
+
pitch: _chunkS5BKZZGMcjs.clampToMidi.call(void 0, note2.pitch, "generated bass pitch"),
|
|
1586
1621
|
startBeat: note2.startBeat,
|
|
1587
1622
|
durationBeat,
|
|
1588
1623
|
velocity: note2.velocity
|
|
@@ -1599,31 +1634,31 @@ function degreesOf(interval) {
|
|
|
1599
1634
|
}
|
|
1600
1635
|
function assertPlayable(pitch) {
|
|
1601
1636
|
if (pitch < 0 || pitch > 127) {
|
|
1602
|
-
throw new (0,
|
|
1637
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`imitated pitch ${pitch} is outside the MIDI range 0..127`);
|
|
1603
1638
|
}
|
|
1604
1639
|
return pitch;
|
|
1605
1640
|
}
|
|
1606
1641
|
function imitate(lead, opts) {
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
const interval =
|
|
1611
|
-
const key =
|
|
1642
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, lead, "imitate lead", { allowNonPositiveDuration: true });
|
|
1643
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "opts");
|
|
1644
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, opts.atBeat, "atBeat");
|
|
1645
|
+
const interval = _chunkS5BKZZGMcjs.toSpelledInterval.call(void 0, opts.interval);
|
|
1646
|
+
const key = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, opts.key);
|
|
1612
1647
|
const from = _nullishCoalesce(opts.from, () => ( Number.NEGATIVE_INFINITY));
|
|
1613
1648
|
const to = _nullishCoalesce(opts.to, () => ( Number.POSITIVE_INFINITY));
|
|
1614
1649
|
if (opts.from !== void 0) {
|
|
1615
|
-
|
|
1650
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, opts.from, "from");
|
|
1616
1651
|
}
|
|
1617
1652
|
if (opts.to !== void 0) {
|
|
1618
|
-
|
|
1653
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, opts.to, "to");
|
|
1619
1654
|
}
|
|
1620
1655
|
if (from > to) {
|
|
1621
|
-
throw new (0,
|
|
1656
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`imitate needs from <= to; received ${from} > ${to}`);
|
|
1622
1657
|
}
|
|
1623
1658
|
const velocityScale = _nullishCoalesce(opts.velocityScale, () => ( 1));
|
|
1624
|
-
|
|
1625
|
-
const tonal =
|
|
1626
|
-
const subject =
|
|
1659
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, velocityScale, "velocityScale");
|
|
1660
|
+
const tonal = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, _nullishCoalesce(opts.answer, () => ( "real")), IMITATION_ANSWERS, "imitate answer") === "tonal";
|
|
1661
|
+
const subject = _chunkS5BKZZGMcjs.dropSilentNotes.call(void 0, lead).filter((note2) => note2.startBeat >= from && note2.startBeat < to).sort((a, b) => a.startBeat - b.startBeat);
|
|
1627
1662
|
const origin = _optionalChain([subject, 'access', _20 => _20[0], 'optionalAccess', _21 => _21.startBeat]);
|
|
1628
1663
|
const pivot = _optionalChain([subject, 'access', _22 => _22[0], 'optionalAccess', _23 => _23.pitch]);
|
|
1629
1664
|
if (origin === void 0 || pivot === void 0) {
|
|
@@ -1637,14 +1672,14 @@ function imitate(lead, opts) {
|
|
|
1637
1672
|
let offset = 0;
|
|
1638
1673
|
if (invert) {
|
|
1639
1674
|
if (tonal) {
|
|
1640
|
-
const here =
|
|
1641
|
-
pitch =
|
|
1675
|
+
const here = _chunk3R3QVKY5cjs.scaleLadderPosition.call(void 0, pitch, key);
|
|
1676
|
+
pitch = _chunk3R3QVKY5cjs.scaleLadderPitch.call(void 0, 2 * _chunk3R3QVKY5cjs.scaleLadderPosition.call(void 0, pivot, key).rung - here.rung, key);
|
|
1642
1677
|
offset = -here.offset;
|
|
1643
1678
|
} else {
|
|
1644
1679
|
pitch = 2 * pivot - pitch;
|
|
1645
1680
|
}
|
|
1646
1681
|
}
|
|
1647
|
-
pitch = tonal ?
|
|
1682
|
+
pitch = tonal ? _chunk3R3QVKY5cjs.shiftByScaleDegrees.call(void 0, pitch, degrees, key) + offset : pitch + Math.round(interval.semitones);
|
|
1648
1683
|
const answer = {
|
|
1649
1684
|
...note2,
|
|
1650
1685
|
pitch: assertPlayable(pitch),
|
|
@@ -1669,7 +1704,7 @@ var DEFAULT_MELODY_VELOCITY = 96;
|
|
|
1669
1704
|
var VELOCITY_DROP = 16;
|
|
1670
1705
|
var TIE_BREAK_JITTER = 1e-6;
|
|
1671
1706
|
function isWholeBeat(beat) {
|
|
1672
|
-
return Math.abs(beat - Math.round(beat)) <
|
|
1707
|
+
return Math.abs(beat - Math.round(beat)) < _chunkS5BKZZGMcjs.BEAT_EPS;
|
|
1673
1708
|
}
|
|
1674
1709
|
function melodyNoteAt(melody, beat) {
|
|
1675
1710
|
return _optionalChain([melody, 'access', _24 => _24.at, 'call', _25 => _25(beat), 'optionalAccess', _26 => _26.note]);
|
|
@@ -1682,8 +1717,8 @@ function melodySnapshotAt(melody, beat) {
|
|
|
1682
1717
|
if (current === void 0) {
|
|
1683
1718
|
return void 0;
|
|
1684
1719
|
}
|
|
1685
|
-
const attacked = Math.abs(current.startBeat - beat) <
|
|
1686
|
-
const previous = attacked ? melodyNoteAt(melody, beat -
|
|
1720
|
+
const attacked = Math.abs(current.startBeat - beat) < _chunkS5BKZZGMcjs.BEAT_EPS;
|
|
1721
|
+
const previous = attacked ? melodyNoteAt(melody, beat - _chunkS5BKZZGMcjs.BEAT_EPS * 2) : current;
|
|
1687
1722
|
const snapshot = { pitch: current.pitch };
|
|
1688
1723
|
if (previous !== void 0) {
|
|
1689
1724
|
snapshot.prevPitch = previous.pitch;
|
|
@@ -1699,7 +1734,7 @@ function complementOnsets(melody, ts, spanStart, spanEnd, draw) {
|
|
|
1699
1734
|
const onsets = [];
|
|
1700
1735
|
const gridStart = Math.floor(spanStart / GRID_STEP) * GRID_STEP;
|
|
1701
1736
|
let last = Number.NEGATIVE_INFINITY;
|
|
1702
|
-
for (let beat = gridStart; beat < spanEnd -
|
|
1737
|
+
for (let beat = gridStart; beat < spanEnd - _chunkS5BKZZGMcjs.BEAT_EPS; beat += GRID_STEP) {
|
|
1703
1738
|
const attacked = melodyAttacksAt(melody, beat);
|
|
1704
1739
|
const sounding2 = melodyNoteAt(melody, beat) !== void 0;
|
|
1705
1740
|
let place = false;
|
|
@@ -1707,10 +1742,10 @@ function complementOnsets(melody, ts, spanStart, spanEnd, draw) {
|
|
|
1707
1742
|
place = isWholeBeat(beat);
|
|
1708
1743
|
} else if (!attacked) {
|
|
1709
1744
|
place = draw.prob(isWholeBeat(beat) ? HOLD_ON_BEAT_PROB : HOLD_OFF_BEAT_PROB, "hold", beat);
|
|
1710
|
-
} else if (
|
|
1745
|
+
} else if (_chunkS5BKZZGMcjs.isStrongBeat.call(void 0, beat, ts)) {
|
|
1711
1746
|
place = draw.prob(REINFORCE_PROB, "reinforce", beat);
|
|
1712
1747
|
}
|
|
1713
|
-
if (place && beat - last >= MIN_ONSET_GAP -
|
|
1748
|
+
if (place && beat - last >= MIN_ONSET_GAP - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1714
1749
|
onsets.push(beat);
|
|
1715
1750
|
last = beat;
|
|
1716
1751
|
}
|
|
@@ -1731,12 +1766,12 @@ function assertWeightOverrides(overrides) {
|
|
|
1731
1766
|
return;
|
|
1732
1767
|
}
|
|
1733
1768
|
if (typeof overrides !== "object" || overrides === null) {
|
|
1734
|
-
throw new (0,
|
|
1735
|
-
`countermelody weights must be an object of weight overrides; received ${
|
|
1769
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
1770
|
+
`countermelody weights must be an object of weight overrides; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, overrides)}`
|
|
1736
1771
|
);
|
|
1737
1772
|
}
|
|
1738
1773
|
for (const [field, value] of Object.entries(overrides)) {
|
|
1739
|
-
|
|
1774
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, value, `countermelody weights.${field}`);
|
|
1740
1775
|
}
|
|
1741
1776
|
}
|
|
1742
1777
|
function scoreCandidate(pitch, melPitch, melPrev, prevPitch, chord, center, weights) {
|
|
@@ -1751,7 +1786,7 @@ function scoreCandidate(pitch, melPitch, melPrev, prevPitch, chord, center, weig
|
|
|
1751
1786
|
score += weights.dissonance;
|
|
1752
1787
|
}
|
|
1753
1788
|
}
|
|
1754
|
-
if (chord &&
|
|
1789
|
+
if (chord && _chunk3R3QVKY5cjs.chordToneRole.call(void 0, pitch, chord) !== null) {
|
|
1755
1790
|
score += weights.chordTone;
|
|
1756
1791
|
}
|
|
1757
1792
|
if (prevPitch !== void 0) {
|
|
@@ -1761,7 +1796,7 @@ function scoreCandidate(pitch, melPitch, melPrev, prevPitch, chord, center, weig
|
|
|
1761
1796
|
if (dist > 0 && dist <= 2) {
|
|
1762
1797
|
score += weights.stepwise;
|
|
1763
1798
|
}
|
|
1764
|
-
if (
|
|
1799
|
+
if (_chunk3R3QVKY5cjs.isForbiddenMelodicLeap.call(void 0, prevPitch, pitch)) {
|
|
1765
1800
|
score += weights.forbiddenLeap;
|
|
1766
1801
|
}
|
|
1767
1802
|
if (melPitch !== void 0 && melPrev !== void 0 && ic !== void 0) {
|
|
@@ -1786,12 +1821,12 @@ function heldNoteBoundaries(melody, startBeat, endBeat, chordChangeBeats) {
|
|
|
1786
1821
|
boundaries.add(onset);
|
|
1787
1822
|
}
|
|
1788
1823
|
for (const beat of chordChangeBeats) {
|
|
1789
|
-
if (beat > startBeat +
|
|
1824
|
+
if (beat > startBeat + _chunkS5BKZZGMcjs.BEAT_EPS && beat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
1790
1825
|
boundaries.add(beat);
|
|
1791
1826
|
}
|
|
1792
1827
|
}
|
|
1793
1828
|
const firstGrid = Math.floor(startBeat / GRID_STEP + 1) * GRID_STEP;
|
|
1794
|
-
for (let beat = firstGrid; beat < endBeat -
|
|
1829
|
+
for (let beat = firstGrid; beat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS; beat += GRID_STEP) {
|
|
1795
1830
|
boundaries.add(beat);
|
|
1796
1831
|
}
|
|
1797
1832
|
return [...boundaries].sort((a, b) => a - b);
|
|
@@ -1804,8 +1839,8 @@ function boundaryContexts(melody, harmony, startBeat, endBeat, ts) {
|
|
|
1804
1839
|
melodyVoice,
|
|
1805
1840
|
otherVoices: melodyVoice === void 0 ? [] : [melodyVoice],
|
|
1806
1841
|
chord: harmony.chordAt(boundary),
|
|
1807
|
-
strongBeat:
|
|
1808
|
-
atCounterOnset: Math.abs(boundary - startBeat) <
|
|
1842
|
+
strongBeat: _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, boundary, ts),
|
|
1843
|
+
atCounterOnset: Math.abs(boundary - startBeat) < _chunkS5BKZZGMcjs.BEAT_EPS
|
|
1809
1844
|
};
|
|
1810
1845
|
});
|
|
1811
1846
|
}
|
|
@@ -1816,7 +1851,7 @@ function heldPitchSafety(pitch, contexts, prevPitch, key, profile, register, low
|
|
|
1816
1851
|
if (melodyVoice !== void 0 && (register === "below" && pitch >= melodyVoice.pitch || register === "above" && pitch <= melodyVoice.pitch)) {
|
|
1817
1852
|
return null;
|
|
1818
1853
|
}
|
|
1819
|
-
const result =
|
|
1854
|
+
const result = _chunk3R3QVKY5cjs.evaluateSafety.call(void 0,
|
|
1820
1855
|
{
|
|
1821
1856
|
profile,
|
|
1822
1857
|
candidatePitch: pitch,
|
|
@@ -1838,51 +1873,51 @@ function heldPitchSafety(pitch, contexts, prevPitch, key, profile, register, low
|
|
|
1838
1873
|
return worst;
|
|
1839
1874
|
}
|
|
1840
1875
|
function generateCounterMelody(opts) {
|
|
1841
|
-
|
|
1876
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "countermelody options");
|
|
1842
1877
|
const timeline = opts.timeline;
|
|
1843
1878
|
const chordAt = timeline === void 0 ? opts.chordAt : (beat) => timeline.at(beat);
|
|
1844
1879
|
if (chordAt === void 0) {
|
|
1845
|
-
throw new (0,
|
|
1880
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("countermelody needs a timeline or a chordAt callback");
|
|
1846
1881
|
}
|
|
1847
1882
|
const chordChangeBeats = timeline === void 0 ? _nullishCoalesce(opts.chordChangeBeats, () => ( [])) : timeline.segments.flatMap((segment) => [segment.startBeat, segment.endBeat]);
|
|
1848
1883
|
const register = _nullishCoalesce(opts.register, () => ( "below"));
|
|
1849
|
-
|
|
1850
|
-
const melody =
|
|
1884
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, opts.melody, "countermelody melody", { allowNonPositiveDuration: true });
|
|
1885
|
+
const melody = _chunk35NBV2FTcjs.createNoteEventIndex.call(void 0, _chunkS5BKZZGMcjs.soundingNotesOnly.call(void 0, opts.melody), {
|
|
1851
1886
|
tieBreak: register === "below" ? "highest" : "lowest"
|
|
1852
1887
|
});
|
|
1853
|
-
const ts =
|
|
1854
|
-
|
|
1855
|
-
const rhythm =
|
|
1856
|
-
const profile =
|
|
1888
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(opts.ts, () => ( DEFAULT_TS2)), "ts"));
|
|
1889
|
+
_chunkS5BKZZGMcjs.assertTimeSignature.call(void 0, ts);
|
|
1890
|
+
const rhythm = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, _nullishCoalesce(opts.rhythm, () => ( "complement")), ["complement", "follow"], "rhythm");
|
|
1891
|
+
const profile = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, _nullishCoalesce(opts.profile, () => ( "pop")), ["strict", "pop"], "safety profile");
|
|
1857
1892
|
assertWeightOverrides(opts.weights);
|
|
1858
|
-
const weights =
|
|
1859
|
-
const key =
|
|
1893
|
+
const weights = _chunk3R3QVKY5cjs.profileWeights.call(void 0, profile, opts.weights);
|
|
1894
|
+
const key = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, opts.key);
|
|
1860
1895
|
const draw = resolveContext(opts.ctx).part("countermelody");
|
|
1861
1896
|
if (melody.notes.length === 0) {
|
|
1862
1897
|
return [];
|
|
1863
1898
|
}
|
|
1864
1899
|
const spanStart = _nullishCoalesce(_optionalChain([melody, 'access', _27 => _27.notes, 'access', _28 => _28[0], 'optionalAccess', _29 => _29.note, 'access', _30 => _30.startBeat]), () => ( 0));
|
|
1865
1900
|
const spanEnd = melody.notes.reduce((end, n) => Math.max(end, n.endBeat), spanStart);
|
|
1866
|
-
|
|
1901
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, Math.ceil((spanEnd - spanStart) / GRID_STEP), "countermelody grid");
|
|
1867
1902
|
const meanPitch = melody.notes.reduce((sum, n) => sum + n.note.pitch, 0) / melody.notes.length;
|
|
1868
1903
|
const defaultCenter = register === "below" ? meanPitch - REGISTER_OFFSET : meanPitch + REGISTER_OFFSET;
|
|
1869
|
-
const low =
|
|
1904
|
+
const low = _chunkS5BKZZGMcjs.clampToMidi.call(void 0,
|
|
1870
1905
|
_nullishCoalesce(opts.pitchLow, () => ( Math.round(defaultCenter) - DEFAULT_HALF_RANGE)),
|
|
1871
1906
|
"countermelody pitchLow"
|
|
1872
1907
|
);
|
|
1873
|
-
const high =
|
|
1908
|
+
const high = _chunkS5BKZZGMcjs.clampToMidi.call(void 0,
|
|
1874
1909
|
_nullishCoalesce(opts.pitchHigh, () => ( Math.round(defaultCenter) + DEFAULT_HALF_RANGE)),
|
|
1875
1910
|
"countermelody pitchHigh"
|
|
1876
1911
|
);
|
|
1877
1912
|
if (low > high) {
|
|
1878
|
-
throw new (0,
|
|
1913
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
1879
1914
|
`countermelody pitchLow must not exceed pitchHigh; received ${low} > ${high}`
|
|
1880
1915
|
);
|
|
1881
1916
|
}
|
|
1882
|
-
|
|
1883
|
-
|
|
1917
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, high - low + 1, "countermelody pitch candidates");
|
|
1918
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, chordChangeBeats.length, "chord change beats");
|
|
1884
1919
|
for (let index = 0; index < chordChangeBeats.length; index += 1) {
|
|
1885
|
-
|
|
1920
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0,
|
|
1886
1921
|
_nullishCoalesce(chordChangeBeats[index], () => ( Number.NaN)),
|
|
1887
1922
|
0,
|
|
1888
1923
|
Number.MAX_SAFE_INTEGER,
|
|
@@ -1892,7 +1927,7 @@ function generateCounterMelody(opts) {
|
|
|
1892
1927
|
const center = (low + high) / 2;
|
|
1893
1928
|
const onsets = rhythm === "follow" ? followOnsets(melody) : complementOnsets(melody, ts, spanStart, spanEnd, draw);
|
|
1894
1929
|
const boundaryEstimate = onsets.length + Math.ceil((spanEnd - spanStart) / GRID_STEP) + melody.notes.length + chordChangeBeats.length;
|
|
1895
|
-
|
|
1930
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, boundaryEstimate * (high - low + 1), "countermelody search");
|
|
1896
1931
|
const jitter = Array.from(
|
|
1897
1932
|
{ length: high - low + 1 },
|
|
1898
1933
|
(_, index) => draw.at("jitter", index) * TIE_BREAK_JITTER
|
|
@@ -1913,14 +1948,14 @@ function generateCounterMelody(opts) {
|
|
|
1913
1948
|
const contexts = boundaryContexts(melody, { chordAt, chordChangeBeats }, beat, endBeat, ts);
|
|
1914
1949
|
const chord = _nullishCoalesce(_optionalChain([contexts, 'access', _33 => _33[0], 'optionalAccess', _34 => _34.chord]), () => ( chordAt(beat)));
|
|
1915
1950
|
const otherVoices = melodyVoice !== void 0 ? [melodyVoice] : [];
|
|
1916
|
-
const candidates =
|
|
1951
|
+
const candidates = _chunk3R3QVKY5cjs.enumerateSafePitches.call(void 0,
|
|
1917
1952
|
{
|
|
1918
1953
|
profile,
|
|
1919
1954
|
prevPitch,
|
|
1920
1955
|
chord,
|
|
1921
1956
|
key,
|
|
1922
1957
|
otherVoices,
|
|
1923
|
-
strongBeat:
|
|
1958
|
+
strongBeat: _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, beat, ts),
|
|
1924
1959
|
vocalLow: low,
|
|
1925
1960
|
vocalHigh: high
|
|
1926
1961
|
},
|
|
@@ -1947,7 +1982,7 @@ function generateCounterMelody(opts) {
|
|
|
1947
1982
|
if (melPitch !== void 0) {
|
|
1948
1983
|
if (prevPitch !== void 0 && melPrev !== void 0 && // Parallel octaves are the perfect-class-zero case of this predicate,
|
|
1949
1984
|
// so a single check covers both parallel fifths and octaves.
|
|
1950
|
-
|
|
1985
|
+
_chunk3R3QVKY5cjs.createsParallelPerfect.call(void 0, prevPitch, candidate, melPrev, melPitch)) {
|
|
1951
1986
|
continue;
|
|
1952
1987
|
}
|
|
1953
1988
|
}
|
|
@@ -1969,7 +2004,7 @@ function generateCounterMelody(opts) {
|
|
|
1969
2004
|
Math.min(127, Math.round((_nullishCoalesce(_optionalChain([melNote, 'optionalAccess', _35 => _35.velocity]), () => ( DEFAULT_MELODY_VELOCITY))) - VELOCITY_DROP))
|
|
1970
2005
|
);
|
|
1971
2006
|
out.push({
|
|
1972
|
-
pitch:
|
|
2007
|
+
pitch: _chunkS5BKZZGMcjs.clampToMidi.call(void 0, pitch),
|
|
1973
2008
|
startBeat: beat,
|
|
1974
2009
|
durationBeat: endBeat - beat,
|
|
1975
2010
|
velocity
|
|
@@ -2566,10 +2601,10 @@ function generateHiHatForBeat(ctx, sec) {
|
|
|
2566
2601
|
|
|
2567
2602
|
// src/generate/drums/euclid.ts
|
|
2568
2603
|
function euclideanRhythm(pulses, steps, rotation = 0) {
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2604
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, steps, "euclidean steps");
|
|
2605
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, pulses, "euclidean pulses");
|
|
2606
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, rotation, "euclidean rotation");
|
|
2607
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, steps, "euclidean pattern steps");
|
|
2573
2608
|
const p = Math.max(0, Math.min(pulses, steps));
|
|
2574
2609
|
const base = bjorklund(p, steps);
|
|
2575
2610
|
const shift = (rotation % steps + steps) % steps;
|
|
@@ -2905,7 +2940,7 @@ function drumNoteOf(voice) {
|
|
|
2905
2940
|
return Object.hasOwn(DRUM_NOTES, voice) ? DRUM_NOTES[voice] : void 0;
|
|
2906
2941
|
}
|
|
2907
2942
|
function drumVoiceOf(pitch) {
|
|
2908
|
-
return VOICE_BY_NOTE.get(
|
|
2943
|
+
return VOICE_BY_NOTE.get(_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, pitch));
|
|
2909
2944
|
}
|
|
2910
2945
|
var ONSET_KEY_SCALE = 128;
|
|
2911
2946
|
var HitList = (_class = class {constructor() { _class.prototype.__init.call(this); }
|
|
@@ -3216,12 +3251,12 @@ var KIT_ARTICULATIONS = Object.freeze([
|
|
|
3216
3251
|
var DRUM_KIT = Object.freeze({
|
|
3217
3252
|
kind: "percussion",
|
|
3218
3253
|
name: "drum kit",
|
|
3219
|
-
limbs:
|
|
3254
|
+
limbs: _chunkCGBADIO5cjs.LIMBS,
|
|
3220
3255
|
reach: deepFreeze(reachByNote()),
|
|
3221
3256
|
overdub: deepFreeze(OVERDUB_VOICES.map((voice) => DRUM_NOTES[voice])),
|
|
3222
3257
|
articulations: KIT_ARTICULATIONS,
|
|
3223
3258
|
// One stroke per limb, and one more per voice dubbed over them.
|
|
3224
|
-
polyphony:
|
|
3259
|
+
polyphony: _chunkCGBADIO5cjs.LIMBS.length + OVERDUB_VOICES.length
|
|
3225
3260
|
});
|
|
3226
3261
|
|
|
3227
3262
|
// src/generate/drums/vocabulary.ts
|
|
@@ -3232,8 +3267,8 @@ function isDrumPattern(material) {
|
|
|
3232
3267
|
function assertDrumPattern(material, label) {
|
|
3233
3268
|
material.strokes.forEach((stroke, index) => {
|
|
3234
3269
|
if (typeof stroke !== "object" || stroke === null || typeof stroke.voice !== "string" || drumNoteOf(stroke.voice) === void 0) {
|
|
3235
|
-
throw new (0,
|
|
3236
|
-
`${label} strokes[${index}].voice must name a drum voice; received ${
|
|
3270
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
3271
|
+
`${label} strokes[${index}].voice must name a drum voice; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, _optionalChain([stroke, 'optionalAccess', _44 => _44.voice]))}`
|
|
3237
3272
|
);
|
|
3238
3273
|
}
|
|
3239
3274
|
});
|
|
@@ -3425,21 +3460,21 @@ var DEFAULT_VELOCITY = 100;
|
|
|
3425
3460
|
var DEFAULT_BPM2 = 120;
|
|
3426
3461
|
var MAX_STROKES_PER_BAR = 64;
|
|
3427
3462
|
function placeDrumPattern(opts) {
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
const genre =
|
|
3432
|
-
const section = opts.section === void 0 ? void 0 :
|
|
3433
|
-
const ts =
|
|
3463
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "drum pattern options");
|
|
3464
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, opts.bars, "drum pattern bars");
|
|
3465
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, opts.bars * MAX_STROKES_PER_BAR, "drum pattern hits", opts.budget);
|
|
3466
|
+
const genre = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.genre, GENRES, "drum pattern genre");
|
|
3467
|
+
const section = opts.section === void 0 ? void 0 : _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.section, PUBLIC_SECTIONS, "drum pattern section");
|
|
3468
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(opts.ts, () => ( FOUR_FOUR2)), "ts"));
|
|
3434
3469
|
if (opts.velocity !== void 0) {
|
|
3435
|
-
|
|
3470
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, opts.velocity, 1, 127, "drum pattern velocity");
|
|
3436
3471
|
}
|
|
3437
|
-
const feel = opts.feel === void 0 ? "straight" :
|
|
3472
|
+
const feel = opts.feel === void 0 ? "straight" : _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.feel, DRUM_FEELS, "feel");
|
|
3438
3473
|
const resolved = resolveContext(opts.ctx);
|
|
3439
3474
|
const bpm = _nullishCoalesce(resolved.bpm, () => ( DEFAULT_BPM2));
|
|
3440
3475
|
const draw = resolved.part("drums");
|
|
3441
3476
|
const baseVelocity = _nullishCoalesce(opts.velocity, () => ( DEFAULT_VELOCITY));
|
|
3442
|
-
const barBeats =
|
|
3477
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts);
|
|
3443
3478
|
const kit = resolved.instrument("drums");
|
|
3444
3479
|
const swing = effectiveSwing(feel, feelSwingAmount(feel));
|
|
3445
3480
|
const supplied = vocabularyOfKind(resolved.vocabulary, isDrumPattern);
|
|
@@ -3448,8 +3483,8 @@ function placeDrumPattern(opts) {
|
|
|
3448
3483
|
});
|
|
3449
3484
|
const dictionary = mergeVocabulary(DRUM_PATTERNS, supplied);
|
|
3450
3485
|
if (selectVocabulary(dictionary, { ts }).length === 0) {
|
|
3451
|
-
throw new (0,
|
|
3452
|
-
`drum pattern ts names a meter no figure is written in: ${
|
|
3486
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
3487
|
+
`drum pattern ts names a meter no figure is written in: ${_chunkS5BKZZGMcjs.formatTimeSignature.call(void 0, ts)}. The built-in figures are written in 4/4; supply vocabulary in another meter through the context.`
|
|
3453
3488
|
);
|
|
3454
3489
|
}
|
|
3455
3490
|
const track = new HitList();
|
|
@@ -3514,26 +3549,26 @@ function placeDrumPattern(opts) {
|
|
|
3514
3549
|
}
|
|
3515
3550
|
}
|
|
3516
3551
|
const endBeat = opts.bars * barBeats;
|
|
3517
|
-
return track.hits.filter((h) => h.startBeat < endBeat && (kit === void 0 ||
|
|
3552
|
+
return track.hits.filter((h) => h.startBeat < endBeat && (kit === void 0 || _chunkCGBADIO5cjs.canSound.call(void 0, kit, h.pitch))).sort((a, b) => a.startBeat - b.startBeat || a.pitch - b.pitch);
|
|
3518
3553
|
}
|
|
3519
3554
|
|
|
3520
3555
|
// src/generate/drums/index.ts
|
|
3521
3556
|
var MAX_HITS_PER_BAR = 128;
|
|
3522
3557
|
var DEFAULT_BPM3 = 120;
|
|
3523
3558
|
function generateDrums(opts) {
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3559
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "drum options");
|
|
3560
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, opts.bars, "drum bars");
|
|
3561
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, opts.bars * MAX_HITS_PER_BAR, "drum hits", opts.budget);
|
|
3527
3562
|
if (opts.euclideanKick) {
|
|
3528
3563
|
const steps = _nullishCoalesce(opts.euclideanKick.steps, () => ( 16));
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3564
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, steps, "euclidean steps", 1, 16);
|
|
3565
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, opts.euclideanKick.pulses, "euclidean pulses");
|
|
3566
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, _nullishCoalesce(opts.euclideanKick.rotation, () => ( 0)), "euclidean rotation");
|
|
3532
3567
|
}
|
|
3533
|
-
const publicStyle =
|
|
3534
|
-
const publicSection =
|
|
3568
|
+
const publicStyle = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.style, GROOVE_STYLES, "drum style");
|
|
3569
|
+
const publicSection = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.section, PUBLIC_SECTIONS, "drum section");
|
|
3535
3570
|
if (opts.nextSection !== void 0) {
|
|
3536
|
-
|
|
3571
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.nextSection, PUBLIC_SECTIONS, "drum nextSection");
|
|
3537
3572
|
}
|
|
3538
3573
|
const track = new HitList();
|
|
3539
3574
|
const resolved = resolveContext(opts.ctx);
|
|
@@ -3544,18 +3579,18 @@ function generateDrums(opts) {
|
|
|
3544
3579
|
const difficulty = resolved.difficulty;
|
|
3545
3580
|
const mapping = mapStyle(publicStyle);
|
|
3546
3581
|
const style = mapping.style;
|
|
3547
|
-
const feel = opts.feel === void 0 ? mapping.feel :
|
|
3548
|
-
const role = opts.role === void 0 ? "full" :
|
|
3549
|
-
const meters =
|
|
3582
|
+
const feel = opts.feel === void 0 ? mapping.feel : _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.feel, DRUM_FEELS, "drum feel");
|
|
3583
|
+
const role = opts.role === void 0 ? "full" : _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.role, DRUM_ROLES, "drum role");
|
|
3584
|
+
const meters = _chunkS5BKZZGMcjs.resolveMeters.call(void 0, { ts: opts.ts }, "ts");
|
|
3550
3585
|
for (const change of meters) {
|
|
3551
3586
|
if (change.ts.numerator !== 4 || change.ts.denominator !== 4) {
|
|
3552
|
-
throw new (0,
|
|
3587
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
3553
3588
|
`drum time signature must be 4/4 throughout; received ${change.ts.numerator}/${change.ts.denominator} at beat ${change.startBeat}`
|
|
3554
3589
|
);
|
|
3555
3590
|
}
|
|
3556
3591
|
}
|
|
3557
|
-
const ts =
|
|
3558
|
-
const barBeats =
|
|
3592
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, meters);
|
|
3593
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts);
|
|
3559
3594
|
const playMainVoices = role !== "fxOnly";
|
|
3560
3595
|
const section = mapSection(publicSection);
|
|
3561
3596
|
const swingAmount = feelSwingAmount(feel);
|
|
@@ -3748,7 +3783,7 @@ function underCeiling(hits, bpm, difficulty, exempt) {
|
|
|
3748
3783
|
return kept;
|
|
3749
3784
|
}
|
|
3750
3785
|
function playableOn(kit, pitch) {
|
|
3751
|
-
return kit === void 0 ||
|
|
3786
|
+
return kit === void 0 || _chunkCGBADIO5cjs.canSound.call(void 0, kit, pitch);
|
|
3752
3787
|
}
|
|
3753
3788
|
|
|
3754
3789
|
// src/generate/groove/index.ts
|
|
@@ -3763,24 +3798,24 @@ var MAX_METRIC_WEIGHT = 3;
|
|
|
3763
3798
|
var MIN_VELOCITY = 1;
|
|
3764
3799
|
var MAX_VELOCITY = 127;
|
|
3765
3800
|
function humanize(events, opts = {}) {
|
|
3766
|
-
const asked =
|
|
3767
|
-
const ts =
|
|
3768
|
-
|
|
3769
|
-
const sounding2 =
|
|
3801
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
3802
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(asked.ts, () => ( DEFAULT_TS3)), "ts"));
|
|
3803
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, events, "humanize events", { allowNonPositiveDuration: true });
|
|
3804
|
+
const sounding2 = _chunkS5BKZZGMcjs.dropSilentNotes.call(void 0, events);
|
|
3770
3805
|
const timing = _nullishCoalesce(asked.timing, () => ( DEFAULT_TIMING));
|
|
3771
3806
|
const velocityJitter = _nullishCoalesce(asked.velocity, () => ( DEFAULT_VELOCITY_JITTER));
|
|
3772
3807
|
const accent2 = _nullishCoalesce(asked.accent, () => ( DEFAULT_ACCENT));
|
|
3773
3808
|
const baseVelocity = _nullishCoalesce(asked.baseVelocity, () => ( DEFAULT_BASE_VELOCITY));
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3809
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, timing, 0, Number.MAX_SAFE_INTEGER, "humanize timing");
|
|
3810
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, velocityJitter, 0, 127, "humanize velocity jitter");
|
|
3811
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, accent2, 0, 127, "humanize accent");
|
|
3812
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, baseVelocity, 0, 127, "humanize base velocity");
|
|
3778
3813
|
const ctx = resolveContext(asked.ctx);
|
|
3779
3814
|
const draw = ctx.part(_nullishCoalesce(asked.part, () => ( DEFAULT_PART)));
|
|
3780
3815
|
return sounding2.map((event) => {
|
|
3781
3816
|
const timingOffset = draw.float(-timing, timing, "timing", event.startBeat, event.pitch);
|
|
3782
3817
|
const startBeat = event.startBeat + timingOffset;
|
|
3783
|
-
const weight =
|
|
3818
|
+
const weight = _chunkS5BKZZGMcjs.metricWeight.call(void 0, event.startBeat, ts);
|
|
3784
3819
|
const accentBoost = weight / MAX_METRIC_WEIGHT * accent2;
|
|
3785
3820
|
const velocityOffset = draw.float(
|
|
3786
3821
|
-velocityJitter,
|
|
@@ -3809,18 +3844,18 @@ function quantizeToGrid(beat, barBeats, subdivision, slotsPerBar) {
|
|
|
3809
3844
|
};
|
|
3810
3845
|
}
|
|
3811
3846
|
function extractGrooveTemplate(events, ts, subdivision = DEFAULT_GROOVE_SUBDIVISION) {
|
|
3812
|
-
const meter =
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
const barBeats =
|
|
3847
|
+
const meter = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, ts, "ts"));
|
|
3848
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, events, "groove source events", { allowNonPositiveDuration: true });
|
|
3849
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, subdivision, "groove subdivision");
|
|
3850
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, meter);
|
|
3816
3851
|
const slotsPerBar = Math.ceil(barBeats * subdivision);
|
|
3817
|
-
|
|
3818
|
-
|
|
3852
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, slotsPerBar, "groove template slots");
|
|
3853
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, slotsPerBar, "groove template slots");
|
|
3819
3854
|
const offsetSums = new Array(slotsPerBar).fill(0);
|
|
3820
3855
|
const velocitySums = new Array(slotsPerBar).fill(0);
|
|
3821
3856
|
const counts = new Array(slotsPerBar).fill(0);
|
|
3822
3857
|
const velocityCounts = new Array(slotsPerBar).fill(0);
|
|
3823
|
-
for (const event of
|
|
3858
|
+
for (const event of _chunkS5BKZZGMcjs.dropSilentNotes.call(void 0, events)) {
|
|
3824
3859
|
const { quantizedBeat, slotIndex } = quantizeToGrid(
|
|
3825
3860
|
event.startBeat,
|
|
3826
3861
|
barBeats,
|
|
@@ -3850,24 +3885,24 @@ function extractGrooveTemplate(events, ts, subdivision = DEFAULT_GROOVE_SUBDIVIS
|
|
|
3850
3885
|
return { subdivision, slotsPerBar, slots, ts: meter };
|
|
3851
3886
|
}
|
|
3852
3887
|
function applyGrooveTemplate(events, template, ts) {
|
|
3853
|
-
const meter =
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3888
|
+
const meter = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, ts, "ts"));
|
|
3889
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, events, "groove target events", { allowNonPositiveDuration: true });
|
|
3890
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, template.subdivision, "template subdivision");
|
|
3891
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, template.slotsPerBar, "template slotsPerBar");
|
|
3892
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, template.slots.length, "template slots");
|
|
3858
3893
|
if (template.slots.length !== template.slotsPerBar) {
|
|
3859
|
-
throw new (0,
|
|
3894
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("template slots length must equal slotsPerBar");
|
|
3860
3895
|
}
|
|
3861
3896
|
if (template.ts && (template.ts.numerator !== meter.numerator || template.ts.denominator !== meter.denominator)) {
|
|
3862
|
-
throw new (0,
|
|
3863
|
-
`Groove template meter ${
|
|
3897
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
3898
|
+
`Groove template meter ${_chunkS5BKZZGMcjs.formatTimeSignature.call(void 0, template.ts)} does not match apply-time meter ${_chunkS5BKZZGMcjs.formatTimeSignature.call(void 0, meter)}`
|
|
3864
3899
|
);
|
|
3865
3900
|
}
|
|
3866
|
-
const barBeats =
|
|
3901
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, meter);
|
|
3867
3902
|
const expectedSlots = Math.ceil(barBeats * template.subdivision);
|
|
3868
3903
|
if (template.slotsPerBar !== expectedSlots) {
|
|
3869
|
-
throw new (0,
|
|
3870
|
-
`Groove template slotsPerBar ${template.slotsPerBar} does not match ${expectedSlots} slots per bar of ${
|
|
3904
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
3905
|
+
`Groove template slotsPerBar ${template.slotsPerBar} does not match ${expectedSlots} slots per bar of ${_chunkS5BKZZGMcjs.formatTimeSignature.call(void 0, meter)} at subdivision ${template.subdivision}`
|
|
3871
3906
|
);
|
|
3872
3907
|
}
|
|
3873
3908
|
for (let index = 0; index < template.slots.length; index += 1) {
|
|
@@ -3875,12 +3910,12 @@ function applyGrooveTemplate(events, template, ts) {
|
|
|
3875
3910
|
if (slot === void 0) {
|
|
3876
3911
|
continue;
|
|
3877
3912
|
}
|
|
3878
|
-
|
|
3913
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, slot.timingOffset, `template slots[${index}].timingOffset`);
|
|
3879
3914
|
if (slot.velocity !== null && slot.velocity !== void 0) {
|
|
3880
|
-
|
|
3915
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, slot.velocity, 0, 127, `template slots[${index}].velocity`);
|
|
3881
3916
|
}
|
|
3882
3917
|
}
|
|
3883
|
-
return
|
|
3918
|
+
return _chunkS5BKZZGMcjs.dropSilentNotes.call(void 0, events).map((event) => {
|
|
3884
3919
|
const { quantizedBeat, slotIndex } = quantizeToGrid(
|
|
3885
3920
|
event.startBeat,
|
|
3886
3921
|
barBeats,
|
|
@@ -3897,7 +3932,7 @@ function applyGrooveTemplate(events, template, ts) {
|
|
|
3897
3932
|
// src/generate/harmonize/nct.ts
|
|
3898
3933
|
function snapToPulse(beat, pulse2) {
|
|
3899
3934
|
const snapped = Math.round(beat / pulse2) * pulse2;
|
|
3900
|
-
return Math.abs(snapped - beat) <=
|
|
3935
|
+
return Math.abs(snapped - beat) <= _chunkIFZDWIKMcjs.HUMANIZE_ADJACENCY ? snapped : beat;
|
|
3901
3936
|
}
|
|
3902
3937
|
var STEP_SEMITONES = 2;
|
|
3903
3938
|
function isStep(a, b) {
|
|
@@ -3911,9 +3946,9 @@ function sameDirection(prev, note2, next) {
|
|
|
3911
3946
|
return prev !== note2 && next !== note2 && note2 - prev > 0 === next - note2 > 0;
|
|
3912
3947
|
}
|
|
3913
3948
|
function classifyMelodyTones(melody, ts) {
|
|
3914
|
-
const meter =
|
|
3915
|
-
|
|
3916
|
-
const pulse2 =
|
|
3949
|
+
const meter = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, ts, "ts"));
|
|
3950
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, melody, "melody notes", { allowNonPositiveDuration: true });
|
|
3951
|
+
const pulse2 = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, meter);
|
|
3917
3952
|
return melody.map((_, index) => {
|
|
3918
3953
|
const role = roleOfNote(melody, index, meter, pulse2);
|
|
3919
3954
|
return { noteIndex: index, role, ornamental: role !== "structural" };
|
|
@@ -3928,12 +3963,12 @@ function roleOfNote(melody, index, ts, pulse2) {
|
|
|
3928
3963
|
}
|
|
3929
3964
|
const intoNote = Math.abs(prev.startBeat + prev.durationBeat - note2.startBeat);
|
|
3930
3965
|
const outOfNote = Math.abs(note2.startBeat + note2.durationBeat - next.startBeat);
|
|
3931
|
-
if (intoNote >
|
|
3966
|
+
if (intoNote > _chunkIFZDWIKMcjs.HUMANIZE_ADJACENCY || outOfNote > _chunkIFZDWIKMcjs.HUMANIZE_ADJACENCY) {
|
|
3932
3967
|
return "structural";
|
|
3933
3968
|
}
|
|
3934
|
-
const weight =
|
|
3935
|
-
const weightPrev =
|
|
3936
|
-
const weightNext =
|
|
3969
|
+
const weight = _chunkS5BKZZGMcjs.metricWeight.call(void 0, snapToPulse(note2.startBeat, pulse2), ts);
|
|
3970
|
+
const weightPrev = _chunkS5BKZZGMcjs.metricWeight.call(void 0, snapToPulse(prev.startBeat, pulse2), ts);
|
|
3971
|
+
const weightNext = _chunkS5BKZZGMcjs.metricWeight.call(void 0, snapToPulse(next.startBeat, pulse2), ts);
|
|
3937
3972
|
const subordinate = weight <= weightPrev && weight <= weightNext && note2.durationBeat <= prev.durationBeat && note2.durationBeat <= next.durationBeat;
|
|
3938
3973
|
const leaning = weight > weightPrev && weight >= weightNext;
|
|
3939
3974
|
if (leaning && prev.pitch === note2.pitch && note2.pitch - next.pitch >= 1 && isStep(note2.pitch, next.pitch)) {
|
|
@@ -3965,12 +4000,12 @@ var FALLBACK = {
|
|
|
3965
4000
|
quality: "maj",
|
|
3966
4001
|
secondaryDominant: false,
|
|
3967
4002
|
base: 0,
|
|
3968
|
-
pcs:
|
|
4003
|
+
pcs: _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, 0, "maj"))
|
|
3969
4004
|
};
|
|
3970
4005
|
function defaultHarmonicRhythm(ts) {
|
|
3971
|
-
const bar2 =
|
|
4006
|
+
const bar2 = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts);
|
|
3972
4007
|
const half = bar2 / 2;
|
|
3973
|
-
return half %
|
|
4008
|
+
return half % _chunkS5BKZZGMcjs.pulseBeats.call(void 0, ts) === 0 ? half : bar2;
|
|
3974
4009
|
}
|
|
3975
4010
|
var DEFAULT_PLACEMENT = {
|
|
3976
4011
|
transposeSearch: false,
|
|
@@ -3979,24 +4014,24 @@ var DEFAULT_PLACEMENT = {
|
|
|
3979
4014
|
var DEFAULT_METER = { numerator: 4, denominator: 4 };
|
|
3980
4015
|
var TIE_BREAK_JITTER2 = 1e-6;
|
|
3981
4016
|
function cadencesThroughRaisedSeventh(key) {
|
|
3982
|
-
return
|
|
4017
|
+
return _chunkIFZDWIKMcjs.isMinorKey.call(void 0, key) && _chunk3R3QVKY5cjs.scaleSystemOf.call(void 0, key) === "common-practice";
|
|
3983
4018
|
}
|
|
3984
4019
|
function isKeyTone(pitch, key) {
|
|
3985
|
-
return
|
|
4020
|
+
return _chunk3R3QVKY5cjs.isScaleTone.call(void 0, pitch, key) || cadencesThroughRaisedSeventh(key) && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch) === _chunk3R3QVKY5cjs.leadingTonePcOf.call(void 0, key);
|
|
3986
4021
|
}
|
|
3987
4022
|
function inferKey(melody) {
|
|
3988
|
-
let best =
|
|
4023
|
+
let best = _chunk3R3QVKY5cjs.majorKey.call(void 0, 0);
|
|
3989
4024
|
let bestScore = Number.NEGATIVE_INFINITY;
|
|
3990
4025
|
const candidates = [];
|
|
3991
4026
|
for (let tonic = 0; tonic < 12; tonic += 1) {
|
|
3992
|
-
candidates.push(
|
|
4027
|
+
candidates.push(_chunk3R3QVKY5cjs.majorKey.call(void 0, tonic), _chunk3R3QVKY5cjs.minorKey.call(void 0, tonic));
|
|
3993
4028
|
}
|
|
3994
4029
|
for (const key of candidates) {
|
|
3995
|
-
const tonic =
|
|
4030
|
+
const tonic = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
3996
4031
|
let score = 0;
|
|
3997
4032
|
for (const n of melody) {
|
|
3998
4033
|
const w = Math.max(0.25, n.durationBeat);
|
|
3999
|
-
const pc =
|
|
4034
|
+
const pc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, n.pitch);
|
|
4000
4035
|
if (isKeyTone(n.pitch, key)) {
|
|
4001
4036
|
score += w;
|
|
4002
4037
|
}
|
|
@@ -4031,7 +4066,7 @@ function emissionCost(seg, cand, melody, key) {
|
|
|
4031
4066
|
let cost = cand.base * seg.weight;
|
|
4032
4067
|
for (const { index, weight, strong } of seg.costNotes) {
|
|
4033
4068
|
const note2 = melody[index];
|
|
4034
|
-
if (!note2 || pcs.includes(
|
|
4069
|
+
if (!note2 || pcs.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, note2.pitch))) {
|
|
4035
4070
|
continue;
|
|
4036
4071
|
}
|
|
4037
4072
|
cost += (strong ? NON_CHORD_TONE_STRONG : NON_CHORD_TONE_WEAK) * weight;
|
|
@@ -4070,7 +4105,7 @@ function phraseEndBonus(prev, cur, tonicPc, seg, melody) {
|
|
|
4070
4105
|
return 0;
|
|
4071
4106
|
}
|
|
4072
4107
|
const closing = melody[seg.closingIndex];
|
|
4073
|
-
if (!closing ||
|
|
4108
|
+
if (!closing || _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, closing.pitch) !== tonicPc) {
|
|
4074
4109
|
return 0;
|
|
4075
4110
|
}
|
|
4076
4111
|
const weight = Math.max(seg.weight, seg.beats);
|
|
@@ -4107,7 +4142,7 @@ function sameHarmony(a, b) {
|
|
|
4107
4142
|
return a.rootPc === b.rootPc && a.quality === b.quality;
|
|
4108
4143
|
}
|
|
4109
4144
|
function harmonizeOnce(melody, key, candidates, segments, jitter, phraseEnds, articulated) {
|
|
4110
|
-
const tonicPc =
|
|
4145
|
+
const tonicPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
4111
4146
|
const n = candidates.length;
|
|
4112
4147
|
const candAt = (i) => _nullishCoalesce(candidates[i], () => ( FALLBACK));
|
|
4113
4148
|
const seg0 = segments[0];
|
|
@@ -4169,13 +4204,13 @@ function gridBounds(segmentStart, hr, gridCount, ends) {
|
|
|
4169
4204
|
}
|
|
4170
4205
|
const last = segmentStart + gridCount * hr;
|
|
4171
4206
|
for (const end of ends) {
|
|
4172
|
-
if (end > segmentStart +
|
|
4207
|
+
if (end > segmentStart + _chunkS5BKZZGMcjs.BEAT_EPS && end < last - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
4173
4208
|
bounds.push(end);
|
|
4174
4209
|
}
|
|
4175
4210
|
}
|
|
4176
4211
|
bounds.sort((a, b) => a - b);
|
|
4177
4212
|
return bounds.filter(
|
|
4178
|
-
(beat, index) => index === 0 || beat - (_nullishCoalesce(bounds[index - 1], () => ( beat))) >
|
|
4213
|
+
(beat, index) => index === 0 || beat - (_nullishCoalesce(bounds[index - 1], () => ( beat))) > _chunkS5BKZZGMcjs.BEAT_EPS
|
|
4179
4214
|
);
|
|
4180
4215
|
}
|
|
4181
4216
|
function closingNoteIndices(spans, ends) {
|
|
@@ -4184,7 +4219,7 @@ function closingNoteIndices(spans, ends) {
|
|
|
4184
4219
|
let index = -1;
|
|
4185
4220
|
let start = Number.NEGATIVE_INFINITY;
|
|
4186
4221
|
for (const [i, span] of spans.entries()) {
|
|
4187
|
-
if (span.startBeat < end -
|
|
4222
|
+
if (span.startBeat < end - _chunkS5BKZZGMcjs.BEAT_EPS && span.startBeat >= start) {
|
|
4188
4223
|
start = span.startBeat;
|
|
4189
4224
|
index = i;
|
|
4190
4225
|
}
|
|
@@ -4227,7 +4262,7 @@ function phraseEndSegments(segments, ends) {
|
|
|
4227
4262
|
for (const end of ends) {
|
|
4228
4263
|
let index = -1;
|
|
4229
4264
|
for (let s = 0; s < segments.length; s += 1) {
|
|
4230
|
-
if ((_nullishCoalesce(_optionalChain([segments, 'access', _48 => _48[s], 'optionalAccess', _49 => _49.startBeat]), () => ( 0))) < end -
|
|
4265
|
+
if ((_nullishCoalesce(_optionalChain([segments, 'access', _48 => _48[s], 'optionalAccess', _49 => _49.startBeat]), () => ( 0))) < end - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
4231
4266
|
index = s;
|
|
4232
4267
|
}
|
|
4233
4268
|
}
|
|
@@ -4244,13 +4279,13 @@ function buildSegments(spans, melody, ts, grid, phraseEnds, budget) {
|
|
|
4244
4279
|
const hr = grid.harmonicRhythm;
|
|
4245
4280
|
const segmentStart = Math.floor(melodyStart / hr) * hr;
|
|
4246
4281
|
const gridCount = Math.max(1, Math.ceil((melodyEnd - segmentStart) / hr));
|
|
4247
|
-
|
|
4282
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, gridCount, "harmonic segments", budget);
|
|
4248
4283
|
const innerEnds = phraseEnds.filter(
|
|
4249
|
-
(end) => end > segmentStart +
|
|
4284
|
+
(end) => end > segmentStart + _chunkS5BKZZGMcjs.BEAT_EPS && end < melodyEnd - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
4250
4285
|
);
|
|
4251
4286
|
const bounds = gridBounds(segmentStart, hr, gridCount, innerEnds);
|
|
4252
4287
|
const segCount = bounds.length - 1;
|
|
4253
|
-
|
|
4288
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, segCount, "harmonic segments", budget);
|
|
4254
4289
|
const segments = Array.from({ length: segCount }, (_, s) => {
|
|
4255
4290
|
const startBeat = _nullishCoalesce(bounds[s], () => ( segmentStart));
|
|
4256
4291
|
const endBeat = _nullishCoalesce(bounds[s + 1], () => ( startBeat + hr));
|
|
@@ -4271,7 +4306,7 @@ function buildSegments(spans, melody, ts, grid, phraseEnds, budget) {
|
|
|
4271
4306
|
lastExclusive += 1;
|
|
4272
4307
|
}
|
|
4273
4308
|
memberships += Math.max(0, lastExclusive - first);
|
|
4274
|
-
|
|
4309
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, memberships, "note-to-segment memberships", budget);
|
|
4275
4310
|
for (let segment = first; segment < lastExclusive; segment += 1) {
|
|
4276
4311
|
_optionalChain([segments, 'access', _50 => _50[segment], 'optionalAccess', _51 => _51.noteIndices, 'access', _52 => _52.push, 'call', _53 => _53(index)]);
|
|
4277
4312
|
}
|
|
@@ -4295,7 +4330,7 @@ function buildSegments(spans, melody, ts, grid, phraseEnds, budget) {
|
|
|
4295
4330
|
continue;
|
|
4296
4331
|
}
|
|
4297
4332
|
const weight = Math.max(0.25, overlap);
|
|
4298
|
-
segment.costNotes.push({ index, weight, strong:
|
|
4333
|
+
segment.costNotes.push({ index, weight, strong: _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, overlapStart, ts) });
|
|
4299
4334
|
segment.weight += weight;
|
|
4300
4335
|
if (span.startBeat >= closingStart) {
|
|
4301
4336
|
closingStart = span.startBeat;
|
|
@@ -4317,7 +4352,7 @@ var UNSTABLE_QUALITIES = /* @__PURE__ */ new Set([
|
|
|
4317
4352
|
"aug7"
|
|
4318
4353
|
]);
|
|
4319
4354
|
function vocabularyBase(rootPc, quality, tonicPc) {
|
|
4320
|
-
const above = (
|
|
4355
|
+
const above = (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc) - tonicPc + 12) % 12;
|
|
4321
4356
|
const root = _nullishCoalesce(ROOT_WEIGHT_BY_SEMITONE[above], () => ( UNSTABLE_TRIAD));
|
|
4322
4357
|
return UNSTABLE_QUALITIES.has(quality) ? Math.max(root, UNSTABLE_TRIAD) : root;
|
|
4323
4358
|
}
|
|
@@ -4326,7 +4361,7 @@ var BORROWED_BASE = 0.5;
|
|
|
4326
4361
|
var SECONDARY_DOMINANT_TARGETS = [2, 4, 5, 6];
|
|
4327
4362
|
function secondaryDominantTargets(key) {
|
|
4328
4363
|
const tonicizable = new Map(
|
|
4329
|
-
|
|
4364
|
+
_chunk3R3QVKY5cjs.tonicizableDegrees.call(void 0, key).map((degree) => [degree.degreeNumber, degree])
|
|
4330
4365
|
);
|
|
4331
4366
|
return SECONDARY_DOMINANT_TARGETS.map((degree) => tonicizable.get(degree)).filter(
|
|
4332
4367
|
(degree) => degree !== void 0
|
|
@@ -4345,19 +4380,19 @@ function admittedCount(fraction, size) {
|
|
|
4345
4380
|
return Math.max(0, Math.min(size, Math.ceil(fraction * size)));
|
|
4346
4381
|
}
|
|
4347
4382
|
function buildCandidates(key, harmonic) {
|
|
4348
|
-
const tonicPc =
|
|
4349
|
-
const frame =
|
|
4350
|
-
const tones =
|
|
4383
|
+
const tonicPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
4384
|
+
const frame = _chunk3R3QVKY5cjs.heptatonicFrameOf.call(void 0, key);
|
|
4385
|
+
const tones = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, frame);
|
|
4351
4386
|
const candidates = tones.map((rootPc, index) => {
|
|
4352
4387
|
const degree = index + 1;
|
|
4353
|
-
const quality =
|
|
4388
|
+
const quality = _chunk3R3QVKY5cjs.diatonicTriad.call(void 0, degree, frame).quality;
|
|
4354
4389
|
return {
|
|
4355
4390
|
rootPc,
|
|
4356
4391
|
quality,
|
|
4357
4392
|
degree,
|
|
4358
4393
|
secondaryDominant: false,
|
|
4359
4394
|
base: vocabularyBase(rootPc, quality, tonicPc),
|
|
4360
|
-
pcs:
|
|
4395
|
+
pcs: _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, rootPc, quality))
|
|
4361
4396
|
};
|
|
4362
4397
|
});
|
|
4363
4398
|
if (cadencesThroughRaisedSeventh(key)) {
|
|
@@ -4368,7 +4403,7 @@ function buildCandidates(key, harmonic) {
|
|
|
4368
4403
|
degree: 5,
|
|
4369
4404
|
secondaryDominant: false,
|
|
4370
4405
|
base: vocabularyBase(rootPc, "maj", tonicPc),
|
|
4371
|
-
pcs:
|
|
4406
|
+
pcs: _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, rootPc, "maj"))
|
|
4372
4407
|
});
|
|
4373
4408
|
}
|
|
4374
4409
|
const targets = secondaryDominantTargets(key);
|
|
@@ -4387,20 +4422,20 @@ function buildCandidates(key, harmonic) {
|
|
|
4387
4422
|
secondaryDominant: true,
|
|
4388
4423
|
targetDegree: target.degreeNumber,
|
|
4389
4424
|
base: SECONDARY_DOMINANT_BASE,
|
|
4390
|
-
pcs:
|
|
4425
|
+
pcs: _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, rootPc, "dom7"))
|
|
4391
4426
|
});
|
|
4392
4427
|
}
|
|
4393
|
-
const parallel =
|
|
4394
|
-
const parallelTones =
|
|
4428
|
+
const parallel = _chunkIFZDWIKMcjs.parallelKey.call(void 0, key);
|
|
4429
|
+
const parallelTones = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, parallel);
|
|
4395
4430
|
const borrowed = [];
|
|
4396
4431
|
for (let degree = 1; degree <= parallelTones.length; degree += 1) {
|
|
4397
|
-
const chord =
|
|
4398
|
-
if (!
|
|
4432
|
+
const chord = _chunk3R3QVKY5cjs.diatonicTriad.call(void 0, degree, parallel);
|
|
4433
|
+
if (!_chunkIFZDWIKMcjs.isDiatonic.call(void 0, chord, key)) {
|
|
4399
4434
|
borrowed.push(chord);
|
|
4400
4435
|
}
|
|
4401
4436
|
}
|
|
4402
4437
|
const borrowedRank = (chord) => {
|
|
4403
|
-
const offset = BORROWED_ENTRY_ORDER.indexOf(
|
|
4438
|
+
const offset = BORROWED_ENTRY_ORDER.indexOf(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - tonicPc));
|
|
4404
4439
|
return offset < 0 ? BORROWED_ENTRY_ORDER.length : offset;
|
|
4405
4440
|
};
|
|
4406
4441
|
borrowed.sort((a, b) => borrowedRank(a) - borrowedRank(b));
|
|
@@ -4419,7 +4454,7 @@ function buildCandidates(key, harmonic) {
|
|
|
4419
4454
|
// which of the two a phrase took was decided by the tie-break jitter
|
|
4420
4455
|
// rather than by the melody.
|
|
4421
4456
|
base: UNSTABLE_QUALITIES.has(chord.quality) ? Math.max(BORROWED_BASE, UNSTABLE_TRIAD) : BORROWED_BASE,
|
|
4422
|
-
pcs:
|
|
4457
|
+
pcs: _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord)
|
|
4423
4458
|
});
|
|
4424
4459
|
}
|
|
4425
4460
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -4435,26 +4470,26 @@ function buildCandidates(key, harmonic) {
|
|
|
4435
4470
|
|
|
4436
4471
|
// src/generate/harmonize/index.ts
|
|
4437
4472
|
function harmonizeMelody(opts) {
|
|
4438
|
-
|
|
4439
|
-
|
|
4473
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "harmonize options");
|
|
4474
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, opts.melody, "harmonize melody", {
|
|
4440
4475
|
allowNonPositiveDuration: true,
|
|
4441
4476
|
budget: opts.budget
|
|
4442
4477
|
});
|
|
4443
4478
|
const phraseEnds = _nullishCoalesce(opts.phraseEnds, () => ( []));
|
|
4444
4479
|
for (const end of phraseEnds) {
|
|
4445
|
-
|
|
4480
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, end, "harmonize phrase end");
|
|
4446
4481
|
}
|
|
4447
|
-
const soundingMelody =
|
|
4448
|
-
const ts =
|
|
4449
|
-
|
|
4482
|
+
const soundingMelody = _chunkS5BKZZGMcjs.soundingNotesOnly.call(void 0, opts.melody);
|
|
4483
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(opts.ts, () => ( DEFAULT_METER)), "ts"));
|
|
4484
|
+
_chunkS5BKZZGMcjs.assertTimeSignature.call(void 0, ts);
|
|
4450
4485
|
const requestedKey = _nullishCoalesce(opts.key, () => ( "infer"));
|
|
4451
|
-
const resolvedKey =
|
|
4486
|
+
const resolvedKey = _chunk3R3QVKY5cjs.resolveKey.call(void 0,
|
|
4452
4487
|
requestedKey === "infer" ? inferKey(soundingMelody) : requestedKey
|
|
4453
4488
|
);
|
|
4454
4489
|
const key = resolvedKey.scale;
|
|
4455
4490
|
const placement = _nullishCoalesce(opts.placement, () => ( DEFAULT_PLACEMENT));
|
|
4456
4491
|
const ctx = resolveContext(opts.ctx);
|
|
4457
|
-
const reharmonize =
|
|
4492
|
+
const reharmonize = _chunkS5BKZZGMcjs.assertOneOf.call(void 0,
|
|
4458
4493
|
_nullishCoalesce(opts.reharmonize, () => ( "diatonic")),
|
|
4459
4494
|
REHARMONIZE_STRENGTHS,
|
|
4460
4495
|
"reharmonize"
|
|
@@ -4467,7 +4502,7 @@ function harmonizeMelody(opts) {
|
|
|
4467
4502
|
const candAt = (i) => _nullishCoalesce(candidates[i], () => ( FALLBACK));
|
|
4468
4503
|
const draw = ctx.part("harmony");
|
|
4469
4504
|
const jitter = candidates.map((_, index) => draw.at("jitter", index) * TIE_BREAK_JITTER2);
|
|
4470
|
-
const pulse2 =
|
|
4505
|
+
const pulse2 = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, ts);
|
|
4471
4506
|
const spans = soundingMelody.map((note2) => ({
|
|
4472
4507
|
startBeat: snapToPulse(note2.startBeat, pulse2),
|
|
4473
4508
|
endBeat: snapToPulse(note2.startBeat + note2.durationBeat, pulse2)
|
|
@@ -4480,7 +4515,7 @@ function harmonizeMelody(opts) {
|
|
|
4480
4515
|
(end, span) => Math.max(end, span.endBeat),
|
|
4481
4516
|
Number.NEGATIVE_INFINITY
|
|
4482
4517
|
);
|
|
4483
|
-
const hr =
|
|
4518
|
+
const hr = _chunkS5BKZZGMcjs.assertRange.call(void 0,
|
|
4484
4519
|
_nullishCoalesce(opts.harmonicRhythm, () => ( defaultHarmonicRhythm(ts))),
|
|
4485
4520
|
Number.MIN_VALUE,
|
|
4486
4521
|
Number.MAX_SAFE_INTEGER,
|
|
@@ -4509,7 +4544,7 @@ function harmonizeMelody(opts) {
|
|
|
4509
4544
|
}
|
|
4510
4545
|
const octaveShifts = placement.octaveSearch ? [0, -12, 12] : [0];
|
|
4511
4546
|
const transposes = semitoneShifts.flatMap((s) => octaveShifts.map((o) => s + o));
|
|
4512
|
-
|
|
4547
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0,
|
|
4513
4548
|
transposes.length * segments.length * candidates.length * candidates.length,
|
|
4514
4549
|
"harmonization placement search",
|
|
4515
4550
|
opts.budget
|
|
@@ -4555,8 +4590,8 @@ function harmonizeMelody(opts) {
|
|
|
4555
4590
|
const melodyRoles = opts.melody.map((note2, noteIndex) => {
|
|
4556
4591
|
const segIdx = segmentIndexAt(bounds, snapToPulse(note2.startBeat, pulse2));
|
|
4557
4592
|
const cand = candAt(_nullishCoalesce(bestPath[segIdx], () => ( 0)));
|
|
4558
|
-
const chord =
|
|
4559
|
-
return { noteIndex, role:
|
|
4593
|
+
const chord = _chunk3R3QVKY5cjs.makeChord.call(void 0, cand.rootPc, cand.quality);
|
|
4594
|
+
return { noteIndex, role: _chunkPM4XJE2Ycjs.roleOf.call(void 0, note2.pitch + bestTs, chord).role };
|
|
4560
4595
|
});
|
|
4561
4596
|
return { transposeSemitones: bestTs, key: resolvedKey, chords, melodyRoles };
|
|
4562
4597
|
}
|
|
@@ -4575,15 +4610,15 @@ var MIN_TILE_SPAN = 1 / 256;
|
|
|
4575
4610
|
var DEFAULT_TS4 = { numerator: 4, denominator: 4 };
|
|
4576
4611
|
function isDownbeat(startBeat, barBeats) {
|
|
4577
4612
|
const bar2 = startBeat / barBeats;
|
|
4578
|
-
return Math.abs(bar2 - Math.round(bar2)) <
|
|
4613
|
+
return Math.abs(bar2 - Math.round(bar2)) < _chunkS5BKZZGMcjs.BEAT_EPS;
|
|
4579
4614
|
}
|
|
4580
4615
|
function nearestChordTone(pitch, chord) {
|
|
4581
|
-
const pcs =
|
|
4616
|
+
const pcs = _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord);
|
|
4582
4617
|
for (let d = 0; d <= 12; d += 1) {
|
|
4583
|
-
if (pcs.includes(
|
|
4618
|
+
if (pcs.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch - d))) {
|
|
4584
4619
|
return pitch - d;
|
|
4585
4620
|
}
|
|
4586
|
-
if (pcs.includes(
|
|
4621
|
+
if (pcs.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch + d))) {
|
|
4587
4622
|
return pitch + d;
|
|
4588
4623
|
}
|
|
4589
4624
|
}
|
|
@@ -4663,20 +4698,20 @@ function contourOffsets(contour, count) {
|
|
|
4663
4698
|
return offsets;
|
|
4664
4699
|
}
|
|
4665
4700
|
function generateMotif(opts) {
|
|
4666
|
-
|
|
4701
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "motif options");
|
|
4667
4702
|
const contour = _nullishCoalesce(opts.contour, () => ( "arch"));
|
|
4668
|
-
const bars =
|
|
4669
|
-
const barBeats =
|
|
4703
|
+
const bars = _chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, opts.bars, "motif bars");
|
|
4704
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(opts.ts, () => ( DEFAULT_TS4)), "ts")));
|
|
4670
4705
|
const totalBeats = bars * barBeats;
|
|
4671
4706
|
const noteCount = Math.max(3, bars * 2);
|
|
4672
|
-
|
|
4707
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, noteCount, "motif notes");
|
|
4673
4708
|
const beatsPerNote = totalBeats / noteCount;
|
|
4674
4709
|
const ctx = resolveContextWith(opts.ctx, { ornament: opts.jitter });
|
|
4675
4710
|
const jitterProb = _nullishCoalesce(ctx.ornament, () => ( 0));
|
|
4676
4711
|
const draw = ctx.part("motif");
|
|
4677
|
-
const key =
|
|
4678
|
-
const chord = opts.chord ?
|
|
4679
|
-
const tonic =
|
|
4712
|
+
const key = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, opts.key);
|
|
4713
|
+
const chord = opts.chord ? _chunk3R3QVKY5cjs.toChordData.call(void 0, opts.chord) : null;
|
|
4714
|
+
const tonic = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc) + 60;
|
|
4680
4715
|
const offsets = contourOffsets(contour, noteCount);
|
|
4681
4716
|
const notes = [];
|
|
4682
4717
|
for (let i = 0; i < noteCount; i += 1) {
|
|
@@ -4684,13 +4719,13 @@ function generateMotif(opts) {
|
|
|
4684
4719
|
if (draw.prob(jitterProb, "jitter", i)) {
|
|
4685
4720
|
jitter = draw.prob(0.5, "direction", i) ? 1 : -1;
|
|
4686
4721
|
}
|
|
4687
|
-
let pitch =
|
|
4722
|
+
let pitch = _chunk3R3QVKY5cjs.shiftByScaleDegrees.call(void 0, tonic, (_nullishCoalesce(offsets[i], () => ( 0))) + jitter, key);
|
|
4688
4723
|
const startBeat = i * beatsPerNote;
|
|
4689
4724
|
if (chord && isDownbeat(startBeat, barBeats)) {
|
|
4690
4725
|
pitch = nearestChordTone(pitch, chord);
|
|
4691
4726
|
}
|
|
4692
4727
|
notes.push({
|
|
4693
|
-
pitch:
|
|
4728
|
+
pitch: _chunkS5BKZZGMcjs.clampToMidi.call(void 0, pitch, "generated motif pitch"),
|
|
4694
4729
|
startBeat,
|
|
4695
4730
|
durationBeat: beatsPerNote
|
|
4696
4731
|
});
|
|
@@ -4701,12 +4736,12 @@ function motifToNoteEvents(cell) {
|
|
|
4701
4736
|
return assertCellNotes(cell, "motif cell notes").map((note2) => ({ ...note2 }));
|
|
4702
4737
|
}
|
|
4703
4738
|
function assertCellNotes(cell, name) {
|
|
4704
|
-
const read =
|
|
4705
|
-
|
|
4739
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, cell, "motif cell");
|
|
4740
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, read.notes, name);
|
|
4706
4741
|
return read.notes;
|
|
4707
4742
|
}
|
|
4708
4743
|
function transformMotif(cell, t, amount, key) {
|
|
4709
|
-
return transformCell(cell, t, amount, key === void 0 ? void 0 :
|
|
4744
|
+
return transformCell(cell, t, amount, key === void 0 ? void 0 : _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key));
|
|
4710
4745
|
}
|
|
4711
4746
|
function transformCell(cell, t, amount, key) {
|
|
4712
4747
|
return assertInRange(inTimeOrder(transformUnchecked(cell, t, amount, key)));
|
|
@@ -4714,7 +4749,7 @@ function transformCell(cell, t, amount, key) {
|
|
|
4714
4749
|
function assertInRange(cell) {
|
|
4715
4750
|
for (const note2 of cell.notes) {
|
|
4716
4751
|
if (note2.pitch < 0 || note2.pitch > 127) {
|
|
4717
|
-
throw new (0,
|
|
4752
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
4718
4753
|
`transformed motif pitch ${note2.pitch} is outside the MIDI range 0..127`
|
|
4719
4754
|
);
|
|
4720
4755
|
}
|
|
@@ -4723,18 +4758,18 @@ function assertInRange(cell) {
|
|
|
4723
4758
|
}
|
|
4724
4759
|
function transformUnchecked(cell, t, amount, key) {
|
|
4725
4760
|
const notes = assertCellNotes(cell, "motif notes");
|
|
4726
|
-
|
|
4761
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, t, MOTIF_TRANSFORMS, "motif transform");
|
|
4727
4762
|
if (amount !== void 0) {
|
|
4728
|
-
|
|
4763
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, amount, "motif transform amount");
|
|
4729
4764
|
}
|
|
4730
4765
|
if ((t === "transposeChromatic" || t === "transposeDiatonic" || t === "sequence") && amount !== void 0) {
|
|
4731
|
-
|
|
4766
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0,
|
|
4732
4767
|
amount,
|
|
4733
4768
|
`${t === "transposeChromatic" ? "chromatic" : "diatonic"} transform amount`
|
|
4734
4769
|
);
|
|
4735
4770
|
}
|
|
4736
4771
|
if ((t === "augment" || t === "diminish") && amount !== void 0 && amount <= 0) {
|
|
4737
|
-
throw new (0,
|
|
4772
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("time transform amount must be positive");
|
|
4738
4773
|
}
|
|
4739
4774
|
switch (t) {
|
|
4740
4775
|
case "transposeChromatic": {
|
|
@@ -4752,7 +4787,7 @@ function transformUnchecked(cell, t, amount, key) {
|
|
|
4752
4787
|
// notes a motif is written with — a blues lick, a semitone neighbour —
|
|
4753
4788
|
// come through as themselves, and shifting by no degrees returns the
|
|
4754
4789
|
// cell it was given.
|
|
4755
|
-
pitch: key ?
|
|
4790
|
+
pitch: key ? _chunk3R3QVKY5cjs.shiftByScaleDegrees.call(void 0, n.pitch, degrees, key) : n.pitch + degrees
|
|
4756
4791
|
}))
|
|
4757
4792
|
};
|
|
4758
4793
|
}
|
|
@@ -4798,13 +4833,13 @@ function scaleTime(cell, factor) {
|
|
|
4798
4833
|
};
|
|
4799
4834
|
}
|
|
4800
4835
|
function developMotif(cell, timeline, key, bars, ts) {
|
|
4801
|
-
const meter =
|
|
4802
|
-
|
|
4803
|
-
|
|
4836
|
+
const meter = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, ts, "ts"));
|
|
4837
|
+
_chunkIFZDWIKMcjs.assertChordTimeline.call(void 0, timeline);
|
|
4838
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, bars, "development bars");
|
|
4804
4839
|
const cellNotes = assertCellNotes(cell, "motif notes");
|
|
4805
|
-
const scale =
|
|
4840
|
+
const scale = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, key);
|
|
4806
4841
|
const span = cellSpan(cell);
|
|
4807
|
-
const barBeats =
|
|
4842
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, meter);
|
|
4808
4843
|
const totalBeats = bars * barBeats;
|
|
4809
4844
|
const origin = cellOrigin(cellNotes);
|
|
4810
4845
|
const out = [];
|
|
@@ -4813,7 +4848,7 @@ function developMotif(cell, timeline, key, bars, ts) {
|
|
|
4813
4848
|
}
|
|
4814
4849
|
const tileSpan = Math.max(span, MIN_TILE_SPAN);
|
|
4815
4850
|
const tileCount = Math.ceil(totalBeats / tileSpan);
|
|
4816
|
-
|
|
4851
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, tileCount * cellNotes.length, "developed motif notes");
|
|
4817
4852
|
for (let k = 0; k < tileCount; k += 1) {
|
|
4818
4853
|
const offset = k * tileSpan;
|
|
4819
4854
|
const taken = /* @__PURE__ */ new Map();
|
|
@@ -4825,8 +4860,8 @@ function developMotif(cell, timeline, key, bars, ts) {
|
|
|
4825
4860
|
}
|
|
4826
4861
|
const chord = timeline.at(startBeat);
|
|
4827
4862
|
const structural = n.startBeat === origin || isDownbeat(startBeat, barBeats);
|
|
4828
|
-
const chordTones = chord && structural ?
|
|
4829
|
-
const allows = chordTones ? (candidate) => chordTones.includes(
|
|
4863
|
+
const chordTones = chord && structural ? _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord) : null;
|
|
4864
|
+
const allows = chordTones ? (candidate) => chordTones.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, candidate)) : (candidate) => _chunk3R3QVKY5cjs.isScaleTone.call(void 0, candidate, scale);
|
|
4830
4865
|
const direction = previous === void 0 ? 0 : n.pitch - previous;
|
|
4831
4866
|
const pitch = developedPitch(n.pitch, allows, direction, taken);
|
|
4832
4867
|
taken.set(pitch, n.pitch);
|
|
@@ -4837,6 +4872,1063 @@ function developMotif(cell, timeline, key, bars, ts) {
|
|
|
4837
4872
|
return inTimeOrder({ notes: out });
|
|
4838
4873
|
}
|
|
4839
4874
|
|
|
4875
|
+
// src/generate/plan/internal.ts
|
|
4876
|
+
var STRONG_WEIGHT = 2;
|
|
4877
|
+
function positionClass(beat, meters) {
|
|
4878
|
+
const weight = _chunkS5BKZZGMcjs.metricWeight.call(void 0, beat, meters);
|
|
4879
|
+
return weight >= STRONG_WEIGHT ? "strong" : weight > 0 ? "weak" : "off";
|
|
4880
|
+
}
|
|
4881
|
+
|
|
4882
|
+
// src/generate/plan/types.ts
|
|
4883
|
+
var COMPOSITION_PLAN_VERSION = 1;
|
|
4884
|
+
function tent(t, apex) {
|
|
4885
|
+
if (t <= apex) {
|
|
4886
|
+
return apex === 0 ? 1 : -1 + 2 * t / apex;
|
|
4887
|
+
}
|
|
4888
|
+
return apex === 1 ? 1 : 1 - 2 * (t - apex) / (1 - apex);
|
|
4889
|
+
}
|
|
4890
|
+
function plannedContourAt(shape, peakPosition, t) {
|
|
4891
|
+
switch (shape) {
|
|
4892
|
+
case "arch":
|
|
4893
|
+
return tent(t, peakPosition);
|
|
4894
|
+
case "ascending":
|
|
4895
|
+
return -1 + 2 * t;
|
|
4896
|
+
case "descending":
|
|
4897
|
+
return 1 - 2 * t;
|
|
4898
|
+
case "wave":
|
|
4899
|
+
return t < 0.5 ? tent(2 * t, 0.5) : tent(2 * t - 1, 0.5);
|
|
4900
|
+
case "static":
|
|
4901
|
+
return 0;
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
|
|
4905
|
+
// src/generate/plan/validate.ts
|
|
4906
|
+
var MASS_TOLERANCE = 1e-9;
|
|
4907
|
+
function assertString(value, name) {
|
|
4908
|
+
if (typeof value !== "string") {
|
|
4909
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be a string; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, value)}`);
|
|
4910
|
+
}
|
|
4911
|
+
return value;
|
|
4912
|
+
}
|
|
4913
|
+
function assertSpanOrder(startBeat, endBeat, name) {
|
|
4914
|
+
if (endBeat < startBeat) {
|
|
4915
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
4916
|
+
`${name}.endBeat must be at least ${name}.startBeat; received ${endBeat} < ${startBeat}`
|
|
4917
|
+
);
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
function assertNullable(value, name, validate) {
|
|
4921
|
+
if (value === void 0) {
|
|
4922
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be present; received undefined`);
|
|
4923
|
+
}
|
|
4924
|
+
return value === null ? null : validate(value, name);
|
|
4925
|
+
}
|
|
4926
|
+
function assertMassDistribution(value, length, name) {
|
|
4927
|
+
const shares = _chunkS5BKZZGMcjs.assertArray.call(void 0, value, name);
|
|
4928
|
+
if (shares.length !== length) {
|
|
4929
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must have length ${length}; received ${shares.length}`);
|
|
4930
|
+
}
|
|
4931
|
+
let sum = 0;
|
|
4932
|
+
for (let index = 0; index < shares.length; index += 1) {
|
|
4933
|
+
const share = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, shares[index], `${name}[${index}]`);
|
|
4934
|
+
if (share < 0) {
|
|
4935
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}[${index}] must be at least 0; received ${share}`);
|
|
4936
|
+
}
|
|
4937
|
+
sum += share;
|
|
4938
|
+
}
|
|
4939
|
+
if (Math.abs(sum - 1) > MASS_TOLERANCE) {
|
|
4940
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must sum to 1; received ${sum}`);
|
|
4941
|
+
}
|
|
4942
|
+
return shares;
|
|
4943
|
+
}
|
|
4944
|
+
function assertResolvedKeyField(value, name) {
|
|
4945
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
4946
|
+
try {
|
|
4947
|
+
_chunk3R3QVKY5cjs.resolveKey.call(void 0, read);
|
|
4948
|
+
} catch (error) {
|
|
4949
|
+
if (error instanceof _chunkS5BKZZGMcjs.InvalidInputError) {
|
|
4950
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be a valid key: ${error.message}`);
|
|
4951
|
+
}
|
|
4952
|
+
throw error;
|
|
4953
|
+
}
|
|
4954
|
+
return read;
|
|
4955
|
+
}
|
|
4956
|
+
function assertPlannedSection(value, name) {
|
|
4957
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
4958
|
+
assertString(read.label, `${name}.label`);
|
|
4959
|
+
const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
|
|
4960
|
+
const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
|
|
4961
|
+
assertSpanOrder(startBeat, endBeat, name);
|
|
4962
|
+
return read;
|
|
4963
|
+
}
|
|
4964
|
+
function assertPlannedPhrase(value, name, sectionCount, motifCount) {
|
|
4965
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
4966
|
+
const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
|
|
4967
|
+
const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
|
|
4968
|
+
assertSpanOrder(startBeat, endBeat, name);
|
|
4969
|
+
assertNullable(
|
|
4970
|
+
read.section,
|
|
4971
|
+
`${name}.section`,
|
|
4972
|
+
(v, n) => _chunkS5BKZZGMcjs.assertInteger.call(void 0, v, n, 0, Math.max(sectionCount - 1, 0))
|
|
4973
|
+
);
|
|
4974
|
+
assertNullable(read.cadence, `${name}.cadence`, (v, n) => _chunkS5BKZZGMcjs.assertOneOf.call(void 0, v, _chunkIFZDWIKMcjs.CADENCE_TYPES, n));
|
|
4975
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, read.shape, _chunkIFZDWIKMcjs.MELODIC_CONTOUR_SHAPES, `${name}.shape`);
|
|
4976
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, read.peakPosition, 0, 1, `${name}.peakPosition`);
|
|
4977
|
+
const register = _chunkS5BKZZGMcjs.assertRecord.call(void 0,
|
|
4978
|
+
read.register,
|
|
4979
|
+
`${name}.register`
|
|
4980
|
+
);
|
|
4981
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, register.low, `${name}.register.low`);
|
|
4982
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, register.high, `${name}.register.high`);
|
|
4983
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, register.mean, 0, 127, `${name}.register.mean`);
|
|
4984
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, read.onsetDensity, 0, Number.MAX_SAFE_INTEGER, `${name}.onsetDensity`);
|
|
4985
|
+
const motifs = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.motifs, `${name}.motifs`);
|
|
4986
|
+
for (let index = 0; index < motifs.length; index += 1) {
|
|
4987
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0,
|
|
4988
|
+
motifs[index],
|
|
4989
|
+
`${name}.motifs[${index}]`,
|
|
4990
|
+
0,
|
|
4991
|
+
Math.max(motifCount - 1, 0)
|
|
4992
|
+
);
|
|
4993
|
+
}
|
|
4994
|
+
return read;
|
|
4995
|
+
}
|
|
4996
|
+
function assertPlannedChord(value, name, keys) {
|
|
4997
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
4998
|
+
const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
|
|
4999
|
+
const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
|
|
5000
|
+
assertSpanOrder(startBeat, endBeat, name);
|
|
5001
|
+
const keyIndex = _chunkS5BKZZGMcjs.assertInteger.call(void 0, read.key, `${name}.key`, 0, Math.max(keys.length - 1, 0));
|
|
5002
|
+
const roman = assertString(read.roman, `${name}.roman`);
|
|
5003
|
+
try {
|
|
5004
|
+
_chunkIFZDWIKMcjs.romanToChord.call(void 0, roman, keys[keyIndex]);
|
|
5005
|
+
} catch (error) {
|
|
5006
|
+
if (error instanceof _chunkS5BKZZGMcjs.InvalidInputError) {
|
|
5007
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5008
|
+
`${name}.roman must be readable by romanToChord; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, roman)}: ${error.message}`
|
|
5009
|
+
);
|
|
5010
|
+
}
|
|
5011
|
+
throw error;
|
|
5012
|
+
}
|
|
5013
|
+
return read;
|
|
5014
|
+
}
|
|
5015
|
+
function assertPlannedMotifRelation(value, name) {
|
|
5016
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
5017
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, read.kind, _chunkIFZDWIKMcjs.MOTIF_RELATION_KINDS, `${name}.kind`);
|
|
5018
|
+
_chunkS5BKZZGMcjs.assertFlag.call(void 0, read.sequence, `${name}.sequence`);
|
|
5019
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.semitones, `${name}.semitones`);
|
|
5020
|
+
if (read.kind === "tonalTransposition") {
|
|
5021
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.degrees, `${name}.degrees`);
|
|
5022
|
+
} else if (read.degrees !== void 0) {
|
|
5023
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.degrees, `${name}.degrees`);
|
|
5024
|
+
}
|
|
5025
|
+
const timeRatio = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.timeRatio, `${name}.timeRatio`);
|
|
5026
|
+
if (timeRatio <= 0) {
|
|
5027
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.timeRatio must be positive; received ${timeRatio}`);
|
|
5028
|
+
}
|
|
5029
|
+
return read;
|
|
5030
|
+
}
|
|
5031
|
+
function assertPlannedMotif(value, name, ownIndex, motifCount, phraseCount) {
|
|
5032
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
5033
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, read.phrase, `${name}.phrase`, 0, Math.max(phraseCount - 1, 0));
|
|
5034
|
+
const startBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.startBeat, `${name}.startBeat`);
|
|
5035
|
+
const endBeat = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.endBeat, `${name}.endBeat`);
|
|
5036
|
+
assertSpanOrder(startBeat, endBeat, name);
|
|
5037
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, read.notes, `${name}.notes`);
|
|
5038
|
+
const from = assertNullable(
|
|
5039
|
+
read.from,
|
|
5040
|
+
`${name}.from`,
|
|
5041
|
+
(v, n) => _chunkS5BKZZGMcjs.assertInteger.call(void 0, v, n, 0, Math.max(motifCount - 1, 0))
|
|
5042
|
+
);
|
|
5043
|
+
if (from !== null && from >= ownIndex) {
|
|
5044
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5045
|
+
`${name}.from must be less than this motif's own index (${ownIndex}); received ${from}`
|
|
5046
|
+
);
|
|
5047
|
+
}
|
|
5048
|
+
const relation = assertNullable(read.relation, `${name}.relation`, assertPlannedMotifRelation);
|
|
5049
|
+
if (from === null && relation !== null) {
|
|
5050
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5051
|
+
`${name}.relation must be null for a root motif (from = null); received a relation`
|
|
5052
|
+
);
|
|
5053
|
+
}
|
|
5054
|
+
const rhythm = assertNullable(read.rhythm, `${name}.rhythm`, (v, n) => _chunkS5BKZZGMcjs.assertArray.call(void 0, v, n));
|
|
5055
|
+
if (rhythm !== null) {
|
|
5056
|
+
if (from !== null) {
|
|
5057
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.rhythm must be null for a derived statement`);
|
|
5058
|
+
}
|
|
5059
|
+
if (rhythm.length !== read.notes - 1) {
|
|
5060
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5061
|
+
`${name}.rhythm must hold notes - 1 (${read.notes - 1}) gaps; received ${rhythm.length}`
|
|
5062
|
+
);
|
|
5063
|
+
}
|
|
5064
|
+
let total = 0;
|
|
5065
|
+
for (let index = 0; index < rhythm.length; index += 1) {
|
|
5066
|
+
const gap = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, rhythm[index], `${name}.rhythm[${index}]`);
|
|
5067
|
+
if (gap <= 0) {
|
|
5068
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.rhythm[${index}] must be positive; received ${gap}`);
|
|
5069
|
+
}
|
|
5070
|
+
total += gap;
|
|
5071
|
+
}
|
|
5072
|
+
if (total >= endBeat - startBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5073
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5074
|
+
`${name}.rhythm must sum to less than the statement's length (${endBeat - startBeat}); received ${total}`
|
|
5075
|
+
);
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
return read;
|
|
5079
|
+
}
|
|
5080
|
+
function assertPlannedRhythm(value, name) {
|
|
5081
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
5082
|
+
assertMassDistribution(read.onsetLevels, 6, `${name}.onsetLevels`);
|
|
5083
|
+
assertMassDistribution(read.interOnsetShares, _chunkIFZDWIKMcjs.RHYTHM_IOI_BINS.length, `${name}.interOnsetShares`);
|
|
5084
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, read.syncopation, 0, 1, `${name}.syncopation`);
|
|
5085
|
+
return read;
|
|
5086
|
+
}
|
|
5087
|
+
function assertCompositionPlan(value, name = "composition plan") {
|
|
5088
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, name);
|
|
5089
|
+
if (read.planVersion !== COMPOSITION_PLAN_VERSION) {
|
|
5090
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5091
|
+
`${name}.planVersion must be ${COMPOSITION_PLAN_VERSION}; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, read.planVersion)}`
|
|
5092
|
+
);
|
|
5093
|
+
}
|
|
5094
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, read.seed, `${name}.seed`, 0, 4294967295);
|
|
5095
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0,
|
|
5096
|
+
read.algorithmVersion,
|
|
5097
|
+
`${name}.algorithmVersion`,
|
|
5098
|
+
_chunkCGBADIO5cjs.MIN_ALGORITHM_VERSION,
|
|
5099
|
+
_chunkCGBADIO5cjs.ALGORITHM_VERSION
|
|
5100
|
+
);
|
|
5101
|
+
const keys = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.keys, `${name}.keys`);
|
|
5102
|
+
if (keys.length === 0) {
|
|
5103
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name}.keys must hold at least one key; received an empty array`);
|
|
5104
|
+
}
|
|
5105
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
5106
|
+
assertResolvedKeyField(keys[index], `${name}.keys[${index}]`);
|
|
5107
|
+
}
|
|
5108
|
+
_chunkS5BKZZGMcjs.assertMeterMap.call(void 0, read.meters, `${name}.meters`);
|
|
5109
|
+
const span = _chunkS5BKZZGMcjs.assertRecord.call(void 0,
|
|
5110
|
+
read.span,
|
|
5111
|
+
`${name}.span`
|
|
5112
|
+
);
|
|
5113
|
+
const spanStart = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, span.startBeat, `${name}.span.startBeat`);
|
|
5114
|
+
const spanEnd = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, span.endBeat, `${name}.span.endBeat`);
|
|
5115
|
+
assertSpanOrder(spanStart, spanEnd, `${name}.span`);
|
|
5116
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, span.bars, 0, Number.MAX_SAFE_INTEGER, `${name}.span.bars`);
|
|
5117
|
+
const sections = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.sections, `${name}.sections`);
|
|
5118
|
+
for (let index = 0; index < sections.length; index += 1) {
|
|
5119
|
+
assertPlannedSection(sections[index], `${name}.sections[${index}]`);
|
|
5120
|
+
}
|
|
5121
|
+
const phrases = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.phrases, `${name}.phrases`);
|
|
5122
|
+
const motifs = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.motifs, `${name}.motifs`);
|
|
5123
|
+
for (let index = 0; index < phrases.length; index += 1) {
|
|
5124
|
+
assertPlannedPhrase(
|
|
5125
|
+
phrases[index],
|
|
5126
|
+
`${name}.phrases[${index}]`,
|
|
5127
|
+
sections.length,
|
|
5128
|
+
motifs.length
|
|
5129
|
+
);
|
|
5130
|
+
}
|
|
5131
|
+
const harmony = _chunkS5BKZZGMcjs.assertArray.call(void 0, read.harmony, `${name}.harmony`);
|
|
5132
|
+
for (let index = 0; index < harmony.length; index += 1) {
|
|
5133
|
+
assertPlannedChord(harmony[index], `${name}.harmony[${index}]`, keys);
|
|
5134
|
+
}
|
|
5135
|
+
for (let index = 0; index < motifs.length; index += 1) {
|
|
5136
|
+
assertPlannedMotif(
|
|
5137
|
+
motifs[index],
|
|
5138
|
+
`${name}.motifs[${index}]`,
|
|
5139
|
+
index,
|
|
5140
|
+
motifs.length,
|
|
5141
|
+
phrases.length
|
|
5142
|
+
);
|
|
5143
|
+
}
|
|
5144
|
+
assertPlannedRhythm(read.rhythm, `${name}.rhythm`);
|
|
5145
|
+
return read;
|
|
5146
|
+
}
|
|
5147
|
+
|
|
5148
|
+
// src/generate/plan/timeline.ts
|
|
5149
|
+
function planTimeline(plan) {
|
|
5150
|
+
return planChordTimeline(assertCompositionPlan(plan));
|
|
5151
|
+
}
|
|
5152
|
+
function planChordTimeline(plan) {
|
|
5153
|
+
const spans = plan.harmony.map((chord) => {
|
|
5154
|
+
const key = plan.keys[chord.key];
|
|
5155
|
+
return _chunk3R3QVKY5cjs.spanFromChord.call(void 0, _chunkIFZDWIKMcjs.romanToChord.call(void 0, chord.roman, key), chord.startBeat);
|
|
5156
|
+
});
|
|
5157
|
+
return _chunkIFZDWIKMcjs.chordTimelineFromChords.call(void 0, spans, plan.span.endBeat);
|
|
5158
|
+
}
|
|
5159
|
+
|
|
5160
|
+
// src/generate/plan/harmony.ts
|
|
5161
|
+
var HARMONY_OK_KINDS = /* @__PURE__ */ new Set([
|
|
5162
|
+
"chordTone",
|
|
5163
|
+
"tension",
|
|
5164
|
+
"suspension",
|
|
5165
|
+
"appoggiatura",
|
|
5166
|
+
"anticipation",
|
|
5167
|
+
"passing",
|
|
5168
|
+
"neighbor"
|
|
5169
|
+
]);
|
|
5170
|
+
var CADENCE_DEGREES = {
|
|
5171
|
+
authentic: [1, 3],
|
|
5172
|
+
plagal: [1, 3],
|
|
5173
|
+
half: [2, 5, 7],
|
|
5174
|
+
phrygian: [2, 5, 7],
|
|
5175
|
+
modal: [1]
|
|
5176
|
+
};
|
|
5177
|
+
function planKeyAt(plan) {
|
|
5178
|
+
const regions = [...plan.harmony].sort((a, b) => a.startBeat - b.startBeat).map((chord) => ({
|
|
5179
|
+
startBeat: chord.startBeat,
|
|
5180
|
+
endBeat: chord.endBeat,
|
|
5181
|
+
key: plan.keys[chord.key],
|
|
5182
|
+
confidence: 1
|
|
5183
|
+
}));
|
|
5184
|
+
return _chunkIFZDWIKMcjs.keyLookup.call(void 0, regions, plan.keys[0]);
|
|
5185
|
+
}
|
|
5186
|
+
function cadencePitchClasses(plan, timeline, cadence, beat) {
|
|
5187
|
+
if (cadence === "deceptive") {
|
|
5188
|
+
const chord = timeline.at(beat);
|
|
5189
|
+
return chord === null ? null : _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord);
|
|
5190
|
+
}
|
|
5191
|
+
const entry = plan.harmony.find((chord) => beat >= chord.startBeat && beat < chord.endBeat);
|
|
5192
|
+
const tones = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, _chunk3R3QVKY5cjs.scaleOf.call(void 0, plan.keys[_nullishCoalesce(_optionalChain([entry, 'optionalAccess', _59 => _59.key]), () => ( 0))]));
|
|
5193
|
+
return CADENCE_DEGREES[cadence].map((degree) => tones[degree - 1]).filter((pc) => pc !== void 0);
|
|
5194
|
+
}
|
|
5195
|
+
function planHarmonyMisfits(plan, timeline = planChordTimeline(plan)) {
|
|
5196
|
+
const keyAt = planKeyAt(plan);
|
|
5197
|
+
const scaleAt2 = (beat) => _chunk3R3QVKY5cjs.scaleOf.call(void 0, keyAt(beat));
|
|
5198
|
+
return (line) => {
|
|
5199
|
+
const analyzed = _chunkIFZDWIKMcjs.analyzeVoice.call(void 0, line, timeline.at, scaleAt2);
|
|
5200
|
+
return line.map((note2, index) => {
|
|
5201
|
+
const position = positionClass(note2.startBeat, plan.meters);
|
|
5202
|
+
if (position === "off") {
|
|
5203
|
+
return null;
|
|
5204
|
+
}
|
|
5205
|
+
const kinds = (_nullishCoalesce(_optionalChain([analyzed, 'access', _60 => _60[index], 'optionalAccess', _61 => _61.labels]), () => ( []))).map((label) => label.kind);
|
|
5206
|
+
if (kinds.some((kind) => HARMONY_OK_KINDS.has(kind))) {
|
|
5207
|
+
return null;
|
|
5208
|
+
}
|
|
5209
|
+
return position === "weak" && _chunk3R3QVKY5cjs.isScaleTone.call(void 0, note2.pitch, scaleAt2(note2.startBeat)) ? null : kinds;
|
|
5210
|
+
});
|
|
5211
|
+
};
|
|
5212
|
+
}
|
|
5213
|
+
|
|
5214
|
+
// src/generate/melody/pitch-dp.ts
|
|
5215
|
+
var NO_LEAP = 0;
|
|
5216
|
+
var LEAP_UP = 1;
|
|
5217
|
+
var LEAP_DOWN = 2;
|
|
5218
|
+
var LEAP_STATES = 3;
|
|
5219
|
+
var SEARCH_LABEL = "melody pitch search";
|
|
5220
|
+
var WIDEST_THIRD = 4;
|
|
5221
|
+
var LEAP_CONTINUATION_COST = 0.5;
|
|
5222
|
+
function intervalCost(size) {
|
|
5223
|
+
if (size === 0) {
|
|
5224
|
+
return 0.2;
|
|
5225
|
+
}
|
|
5226
|
+
if (size <= 2) {
|
|
5227
|
+
return 0;
|
|
5228
|
+
}
|
|
5229
|
+
if (size <= WIDEST_THIRD) {
|
|
5230
|
+
return 0.3;
|
|
5231
|
+
}
|
|
5232
|
+
if (size <= 7) {
|
|
5233
|
+
return 0.6;
|
|
5234
|
+
}
|
|
5235
|
+
return 1;
|
|
5236
|
+
}
|
|
5237
|
+
function leapOf(delta) {
|
|
5238
|
+
if (Math.abs(delta) <= WIDEST_THIRD) {
|
|
5239
|
+
return NO_LEAP;
|
|
5240
|
+
}
|
|
5241
|
+
return delta > 0 ? LEAP_UP : LEAP_DOWN;
|
|
5242
|
+
}
|
|
5243
|
+
function stepCost(from, to, leap, bothFixed) {
|
|
5244
|
+
const delta = to - from;
|
|
5245
|
+
const size = Math.abs(delta);
|
|
5246
|
+
if (!bothFixed && _chunk3R3QVKY5cjs.isForbiddenMelodicLeap.call(void 0, from, to)) {
|
|
5247
|
+
return Number.POSITIVE_INFINITY;
|
|
5248
|
+
}
|
|
5249
|
+
let cost = intervalCost(size);
|
|
5250
|
+
if (leap === LEAP_UP && delta > 0 || leap === LEAP_DOWN && delta < 0) {
|
|
5251
|
+
cost += LEAP_CONTINUATION_COST;
|
|
5252
|
+
}
|
|
5253
|
+
return cost;
|
|
5254
|
+
}
|
|
5255
|
+
function searchPitches(slots, budget, extra) {
|
|
5256
|
+
const first = slots[0];
|
|
5257
|
+
if (first === void 0) {
|
|
5258
|
+
return [];
|
|
5259
|
+
}
|
|
5260
|
+
let previous = _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0,
|
|
5261
|
+
first.candidates.length,
|
|
5262
|
+
LEAP_STATES,
|
|
5263
|
+
SEARCH_LABEL,
|
|
5264
|
+
budget
|
|
5265
|
+
).fill(Number.POSITIVE_INFINITY);
|
|
5266
|
+
for (let j = 0; j < first.candidates.length; j += 1) {
|
|
5267
|
+
previous[j * LEAP_STATES + NO_LEAP] = first.cost(first.candidates[j]);
|
|
5268
|
+
}
|
|
5269
|
+
const backs = [];
|
|
5270
|
+
for (let k = 1; k < slots.length; k += 1) {
|
|
5271
|
+
const before = slots[k - 1];
|
|
5272
|
+
const slot = slots[k];
|
|
5273
|
+
const unary = slot.candidates.map((pitch) => slot.cost(pitch));
|
|
5274
|
+
const current = _chunkS5BKZZGMcjs.allocateCandidateTable.call(void 0,
|
|
5275
|
+
slot.candidates.length,
|
|
5276
|
+
LEAP_STATES,
|
|
5277
|
+
SEARCH_LABEL,
|
|
5278
|
+
budget
|
|
5279
|
+
).fill(Number.POSITIVE_INFINITY);
|
|
5280
|
+
const back = _chunkS5BKZZGMcjs.allocateChoiceTable.call(void 0,
|
|
5281
|
+
slot.candidates.length,
|
|
5282
|
+
LEAP_STATES,
|
|
5283
|
+
SEARCH_LABEL,
|
|
5284
|
+
budget
|
|
5285
|
+
).fill(-1);
|
|
5286
|
+
const bothFixed = before.fixed && slot.fixed;
|
|
5287
|
+
for (let state2 = 0; state2 < previous.length; state2 += 1) {
|
|
5288
|
+
const reached = previous[state2];
|
|
5289
|
+
if (reached === Number.POSITIVE_INFINITY) {
|
|
5290
|
+
continue;
|
|
5291
|
+
}
|
|
5292
|
+
const from = before.candidates[Math.floor(state2 / LEAP_STATES)];
|
|
5293
|
+
const leap = state2 % LEAP_STATES;
|
|
5294
|
+
for (let j = 0; j < slot.candidates.length; j += 1) {
|
|
5295
|
+
const to = slot.candidates[j];
|
|
5296
|
+
const step = stepCost(from, to, leap, bothFixed);
|
|
5297
|
+
if (step === Number.POSITIVE_INFINITY) {
|
|
5298
|
+
continue;
|
|
5299
|
+
}
|
|
5300
|
+
const total = reached + step + unary[j] + (extra ? extra(k, from, to) : 0);
|
|
5301
|
+
const index = j * LEAP_STATES + leapOf(to - from);
|
|
5302
|
+
if (total < current[index]) {
|
|
5303
|
+
current[index] = total;
|
|
5304
|
+
back[index] = state2;
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5308
|
+
backs.push(back);
|
|
5309
|
+
previous = current;
|
|
5310
|
+
}
|
|
5311
|
+
let best = -1;
|
|
5312
|
+
for (let state2 = 0; state2 < previous.length; state2 += 1) {
|
|
5313
|
+
if (previous[state2] < Number.POSITIVE_INFINITY && (best < 0 || previous[state2] < previous[best])) {
|
|
5314
|
+
best = state2;
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
if (best < 0) {
|
|
5318
|
+
return null;
|
|
5319
|
+
}
|
|
5320
|
+
const pitches = new Array(slots.length);
|
|
5321
|
+
let state = best;
|
|
5322
|
+
for (let k = slots.length - 1; k >= 0; k -= 1) {
|
|
5323
|
+
pitches[k] = slots[k].candidates[Math.floor(state / LEAP_STATES)];
|
|
5324
|
+
if (k > 0) {
|
|
5325
|
+
state = backs[k - 1][state];
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
return pitches;
|
|
5329
|
+
}
|
|
5330
|
+
|
|
5331
|
+
// src/generate/melody/derive.ts
|
|
5332
|
+
var VARIATION_STEP_COST = 0.2;
|
|
5333
|
+
var OCTAVE = 12;
|
|
5334
|
+
var LEVEL_TARGET_COST = 0.1;
|
|
5335
|
+
var LEVEL_PLAN_COST = 0.02;
|
|
5336
|
+
var LEVEL_REACH = 24;
|
|
5337
|
+
var TONAL_LEVEL_REACH = 14;
|
|
5338
|
+
function stretched(cell, timeRatio) {
|
|
5339
|
+
return timeRatio === 1 ? cell : transformMotif(cell, "augment", timeRatio);
|
|
5340
|
+
}
|
|
5341
|
+
function shaped(cell, relation) {
|
|
5342
|
+
switch (relation.kind) {
|
|
5343
|
+
case "repetition":
|
|
5344
|
+
case "tonalTransposition":
|
|
5345
|
+
return cell;
|
|
5346
|
+
case "transposition":
|
|
5347
|
+
return stretched(cell, relation.timeRatio);
|
|
5348
|
+
case "inversion":
|
|
5349
|
+
return stretched(transformMotif(cell, "invert"), relation.timeRatio);
|
|
5350
|
+
case "retrograde":
|
|
5351
|
+
return transformMotif(cell, "retrograde");
|
|
5352
|
+
case "retrogradeInversion":
|
|
5353
|
+
return transformMotif(transformMotif(cell, "invert"), "retrograde");
|
|
5354
|
+
case "augmentation":
|
|
5355
|
+
return transformMotif(cell, "augment", relation.timeRatio);
|
|
5356
|
+
case "diminution":
|
|
5357
|
+
return transformMotif(cell, "diminish", 1 / relation.timeRatio);
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
function relationLevels(kind, low = -LEVEL_REACH, high = LEVEL_REACH) {
|
|
5361
|
+
const between = (from, to, skipZero) => {
|
|
5362
|
+
const levels = [];
|
|
5363
|
+
for (let level = Math.ceil(from); level <= to; level += 1) {
|
|
5364
|
+
if (!(skipZero && level === 0)) levels.push(level);
|
|
5365
|
+
}
|
|
5366
|
+
return levels;
|
|
5367
|
+
};
|
|
5368
|
+
switch (kind) {
|
|
5369
|
+
case "repetition":
|
|
5370
|
+
case "augmentation":
|
|
5371
|
+
case "diminution":
|
|
5372
|
+
return [-OCTAVE, 0, OCTAVE];
|
|
5373
|
+
case "transposition":
|
|
5374
|
+
return between(low, high, true);
|
|
5375
|
+
case "tonalTransposition":
|
|
5376
|
+
return between(-TONAL_LEVEL_REACH, TONAL_LEVEL_REACH, true);
|
|
5377
|
+
case "inversion":
|
|
5378
|
+
case "retrograde":
|
|
5379
|
+
case "retrogradeInversion":
|
|
5380
|
+
return between(low, high, false);
|
|
5381
|
+
}
|
|
5382
|
+
}
|
|
5383
|
+
function replayAt(source, relation, level, startBeat, key) {
|
|
5384
|
+
const head = source[0];
|
|
5385
|
+
const cell = shaped({ notes: source.map((n) => ({ ...n })) }, relation);
|
|
5386
|
+
const first = cell.notes[0];
|
|
5387
|
+
const offset = startBeat - first.startBeat;
|
|
5388
|
+
const shift = head.pitch + level - first.pitch;
|
|
5389
|
+
return cell.notes.map((n) => ({
|
|
5390
|
+
...n,
|
|
5391
|
+
pitch: relation.kind === "tonalTransposition" ? _chunk3R3QVKY5cjs.shiftByScaleDegrees.call(void 0, n.pitch, level, key) : n.pitch + shift,
|
|
5392
|
+
startBeat: n.startBeat + offset
|
|
5393
|
+
}));
|
|
5394
|
+
}
|
|
5395
|
+
function clipStatement(notes, endBeat) {
|
|
5396
|
+
return notes.filter((n) => n.startBeat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS).map((n) => ({ ...n, durationBeat: Math.min(n.durationBeat, endBeat - n.startBeat) }));
|
|
5397
|
+
}
|
|
5398
|
+
function outsideCount(notes, frame) {
|
|
5399
|
+
return notes.filter((n) => n.pitch < frame.low || n.pitch > frame.high).length;
|
|
5400
|
+
}
|
|
5401
|
+
function nearerLevel(level, best, planned) {
|
|
5402
|
+
const distance = Math.abs(level - planned);
|
|
5403
|
+
const bestDistance = Math.abs(best - planned);
|
|
5404
|
+
return distance < bestDistance || distance === bestDistance && level < best;
|
|
5405
|
+
}
|
|
5406
|
+
function repairStatement(notes, forced, frame) {
|
|
5407
|
+
const slots = notes.map(
|
|
5408
|
+
(n, index) => forced[index] ? {
|
|
5409
|
+
candidates: frame.candidatesAt(n.startBeat),
|
|
5410
|
+
cost: frame.costAt(n.startBeat),
|
|
5411
|
+
fixed: false
|
|
5412
|
+
} : { candidates: [n.pitch], cost: () => 0, fixed: true }
|
|
5413
|
+
);
|
|
5414
|
+
const pitches = searchPitches(slots, frame.budget);
|
|
5415
|
+
if (pitches === null) {
|
|
5416
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(
|
|
5417
|
+
`no repair fits the statement into the register ${frame.low}..${frame.high}`,
|
|
5418
|
+
{ at: frame.at }
|
|
5419
|
+
);
|
|
5420
|
+
}
|
|
5421
|
+
return notes.map((n, index) => ({ ...n, pitch: pitches[index] }));
|
|
5422
|
+
}
|
|
5423
|
+
function placeDerived(source, relation, startBeat, endBeat, key, frame, before) {
|
|
5424
|
+
const planned = relation.kind === "tonalTransposition" ? _nullishCoalesce(relation.degrees, () => ( 0)) : relation.semitones;
|
|
5425
|
+
const replay = (level) => clipStatement(replayAt(source, relation, level, startBeat, key), endBeat);
|
|
5426
|
+
const base = replay(0).map((n) => n.pitch);
|
|
5427
|
+
const levels = relationLevels(
|
|
5428
|
+
relation.kind,
|
|
5429
|
+
Math.max(-LEVEL_REACH, frame.low - Math.min(...base)),
|
|
5430
|
+
Math.min(LEVEL_REACH, frame.high - Math.max(...base))
|
|
5431
|
+
);
|
|
5432
|
+
let best = null;
|
|
5433
|
+
for (const level of levels) {
|
|
5434
|
+
const notes2 = replay(level);
|
|
5435
|
+
if (outsideCount(notes2, frame) > 0) {
|
|
5436
|
+
continue;
|
|
5437
|
+
}
|
|
5438
|
+
const distance = notes2.reduce((sum, n) => sum + Math.abs(n.pitch - frame.targetAt(n.startBeat)), 0) / notes2.length;
|
|
5439
|
+
const cost = frame.misfits(notes2, before) + LEVEL_TARGET_COST * distance + LEVEL_PLAN_COST * Math.abs(level - planned);
|
|
5440
|
+
if (best === null || cost < best.cost || cost === best.cost && nearerLevel(level, best.level, planned)) {
|
|
5441
|
+
best = { level, notes: notes2, cost };
|
|
5442
|
+
}
|
|
5443
|
+
}
|
|
5444
|
+
if (best !== null) {
|
|
5445
|
+
return best.notes;
|
|
5446
|
+
}
|
|
5447
|
+
let fallback = null;
|
|
5448
|
+
for (const level of relationLevels(relation.kind)) {
|
|
5449
|
+
const notes2 = replay(level);
|
|
5450
|
+
const outside = outsideCount(notes2, frame);
|
|
5451
|
+
if (fallback === null || outside < fallback.outside || outside === fallback.outside && nearerLevel(level, fallback.level, planned)) {
|
|
5452
|
+
fallback = { level, notes: notes2, outside };
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
const notes = fallback.notes;
|
|
5456
|
+
return repairStatement(
|
|
5457
|
+
notes,
|
|
5458
|
+
notes.map((n) => n.pitch < frame.low || n.pitch > frame.high),
|
|
5459
|
+
frame
|
|
5460
|
+
);
|
|
5461
|
+
}
|
|
5462
|
+
function varyStatement(source, startBeat, frame) {
|
|
5463
|
+
const offset = startBeat - source[0].startBeat;
|
|
5464
|
+
const last = source.length - 1;
|
|
5465
|
+
const inside = (pitch) => pitch >= frame.low && pitch <= frame.high;
|
|
5466
|
+
const outer = [source[0].pitch, source[last].pitch];
|
|
5467
|
+
const shift = [0, OCTAVE, -OCTAVE].find((s) => outer.every((pitch) => inside(pitch + s)));
|
|
5468
|
+
const notes = source.map((n) => ({ ...n, startBeat: n.startBeat + offset }));
|
|
5469
|
+
const slots = notes.map(
|
|
5470
|
+
(n, index) => (index === 0 || index === last) && shift !== void 0 ? { candidates: [n.pitch + shift], cost: () => 0, fixed: true } : {
|
|
5471
|
+
candidates: frame.candidatesAt(n.startBeat),
|
|
5472
|
+
cost: frame.costAt(n.startBeat),
|
|
5473
|
+
fixed: false
|
|
5474
|
+
}
|
|
5475
|
+
);
|
|
5476
|
+
const pitches = searchPitches(
|
|
5477
|
+
slots,
|
|
5478
|
+
frame.budget,
|
|
5479
|
+
(index, from, to) => VARIATION_STEP_COST * Math.abs(
|
|
5480
|
+
to - from - (source[index].pitch - source[index - 1].pitch)
|
|
5481
|
+
)
|
|
5482
|
+
);
|
|
5483
|
+
if (pitches === null) {
|
|
5484
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(`no variation line fits the register ${frame.low}..${frame.high}`, {
|
|
5485
|
+
at: frame.at
|
|
5486
|
+
});
|
|
5487
|
+
}
|
|
5488
|
+
return notes.map((n, index) => ({ ...n, pitch: pitches[index] }));
|
|
5489
|
+
}
|
|
5490
|
+
|
|
5491
|
+
// src/generate/melody/index.ts
|
|
5492
|
+
var RHYTHM_SUBDIVISION = 4;
|
|
5493
|
+
var OFF_SCALE_COST = 1;
|
|
5494
|
+
var TARGET_COST = 0.1;
|
|
5495
|
+
var TIE_BREAK = 1e-6;
|
|
5496
|
+
var SEARCH_STATES_SQUARED = 9;
|
|
5497
|
+
function melodyContext(plan, input) {
|
|
5498
|
+
const fromPlan = { seed: plan.seed, algorithmVersion: plan.algorithmVersion };
|
|
5499
|
+
if (input === void 0) {
|
|
5500
|
+
return resolveContext(fromPlan);
|
|
5501
|
+
}
|
|
5502
|
+
if (typeof input === "number") {
|
|
5503
|
+
return resolveContext({ ...fromPlan, seed: input });
|
|
5504
|
+
}
|
|
5505
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, input, "ctx");
|
|
5506
|
+
if (read.rng !== void 0) {
|
|
5507
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5508
|
+
"ctx.rng cannot drive a melody: every onset and tie-break is drawn at an address of phrase and beat under a seed; pass a seed instead"
|
|
5509
|
+
);
|
|
5510
|
+
}
|
|
5511
|
+
return resolveContext({
|
|
5512
|
+
...read,
|
|
5513
|
+
seed: _nullishCoalesce(read.seed, () => ( plan.seed)),
|
|
5514
|
+
algorithmVersion: _nullishCoalesce(read.algorithmVersion, () => ( plan.algorithmVersion))
|
|
5515
|
+
});
|
|
5516
|
+
}
|
|
5517
|
+
function chordEntryAt(plan, beat) {
|
|
5518
|
+
return plan.harmony.find((chord) => beat >= chord.startBeat && beat < chord.endBeat);
|
|
5519
|
+
}
|
|
5520
|
+
function scaleAt(scene, beat) {
|
|
5521
|
+
return scene.scales[_nullishCoalesce(_optionalChain([chordEntryAt, 'call', _62 => _62(scene.plan, beat), 'optionalAccess', _63 => _63.key]), () => ( 0))];
|
|
5522
|
+
}
|
|
5523
|
+
function targetPitch(phrase, beat) {
|
|
5524
|
+
const length = phrase.endBeat - phrase.startBeat;
|
|
5525
|
+
const t = length > 0 ? Math.min(Math.max((beat - phrase.startBeat) / length, 0), 1) : 0;
|
|
5526
|
+
const { low, high, mean } = phrase.register;
|
|
5527
|
+
return mean + (high - low) / 2 * plannedContourAt(phrase.shape, phrase.peakPosition, t);
|
|
5528
|
+
}
|
|
5529
|
+
function registerPitches(phrase) {
|
|
5530
|
+
const pitches = [];
|
|
5531
|
+
for (let pitch = phrase.register.low; pitch <= phrase.register.high; pitch += 1) {
|
|
5532
|
+
pitches.push(pitch);
|
|
5533
|
+
}
|
|
5534
|
+
return pitches;
|
|
5535
|
+
}
|
|
5536
|
+
function frameOf(scene, index) {
|
|
5537
|
+
const phrase = scene.plan.phrases[index];
|
|
5538
|
+
const { low, high } = phrase.register;
|
|
5539
|
+
const register = registerPitches(phrase);
|
|
5540
|
+
const draw = scene.ctx.part("melody");
|
|
5541
|
+
return {
|
|
5542
|
+
low,
|
|
5543
|
+
high,
|
|
5544
|
+
at: phrase.startBeat,
|
|
5545
|
+
budget: scene.budget,
|
|
5546
|
+
candidatesAt: (beat) => {
|
|
5547
|
+
const position = positionClass(beat, scene.plan.meters);
|
|
5548
|
+
const chord = scene.timeline.at(beat);
|
|
5549
|
+
const tones = position === "strong" && chord !== null ? _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, chord) : null;
|
|
5550
|
+
const scale = scaleAt(scene, beat);
|
|
5551
|
+
const candidates = position === "off" ? register : tones !== null ? register.filter((pitch) => tones.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch))) : register.filter((pitch) => _chunk3R3QVKY5cjs.isScaleTone.call(void 0, pitch, scale));
|
|
5552
|
+
if (candidates.length === 0) {
|
|
5553
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(
|
|
5554
|
+
`no ${position} pitch at beat ${beat} fits the register ${low}..${high}`,
|
|
5555
|
+
{ at: phrase.startBeat }
|
|
5556
|
+
);
|
|
5557
|
+
}
|
|
5558
|
+
return candidates;
|
|
5559
|
+
},
|
|
5560
|
+
costAt: (beat) => {
|
|
5561
|
+
const off = positionClass(beat, scene.plan.meters) === "off";
|
|
5562
|
+
const scale = scaleAt(scene, beat);
|
|
5563
|
+
const target = targetPitch(phrase, beat);
|
|
5564
|
+
return (pitch) => {
|
|
5565
|
+
let cost = TARGET_COST * Math.abs(pitch - target);
|
|
5566
|
+
if (off && !_chunk3R3QVKY5cjs.isScaleTone.call(void 0, pitch, scale)) {
|
|
5567
|
+
cost += OFF_SCALE_COST;
|
|
5568
|
+
}
|
|
5569
|
+
return cost + draw.float(0, TIE_BREAK, index, "tie", beat, pitch);
|
|
5570
|
+
};
|
|
5571
|
+
},
|
|
5572
|
+
targetAt: (beat) => targetPitch(phrase, beat),
|
|
5573
|
+
misfits: (notes, before) => scene.harmonyMisfits([...before, ...notes]).slice(before.length).filter((kinds) => kinds !== null).length
|
|
5574
|
+
};
|
|
5575
|
+
}
|
|
5576
|
+
function membersOf(plan) {
|
|
5577
|
+
return plan.phrases.map((phrase, index) => {
|
|
5578
|
+
const found = new Set(phrase.motifs);
|
|
5579
|
+
plan.motifs.forEach((motif, m) => {
|
|
5580
|
+
if (motif.phrase === index) {
|
|
5581
|
+
found.add(m);
|
|
5582
|
+
}
|
|
5583
|
+
});
|
|
5584
|
+
return [...found].sort(
|
|
5585
|
+
(a, b) => (_nullishCoalesce(_optionalChain([plan, 'access', _64 => _64.motifs, 'access', _65 => _65[a], 'optionalAccess', _66 => _66.startBeat]), () => ( 0))) - (_nullishCoalesce(_optionalChain([plan, 'access', _67 => _67.motifs, 'access', _68 => _68[b], 'optionalAccess', _69 => _69.startBeat]), () => ( 0))) || a - b
|
|
5586
|
+
);
|
|
5587
|
+
});
|
|
5588
|
+
}
|
|
5589
|
+
function segmentsOf(scene, index) {
|
|
5590
|
+
const phrase = scene.plan.phrases[index];
|
|
5591
|
+
const segments = [];
|
|
5592
|
+
let cursor = phrase.startBeat;
|
|
5593
|
+
for (const m of scene.members[index]) {
|
|
5594
|
+
const motif = scene.plan.motifs[m];
|
|
5595
|
+
if (motif === void 0) {
|
|
5596
|
+
continue;
|
|
5597
|
+
}
|
|
5598
|
+
if (motif.startBeat > cursor + _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5599
|
+
segments.push({ startBeat: cursor, endBeat: motif.startBeat, motif: null });
|
|
5600
|
+
}
|
|
5601
|
+
segments.push({ startBeat: motif.startBeat, endBeat: motif.endBeat, motif: m });
|
|
5602
|
+
cursor = Math.max(cursor, motif.endBeat);
|
|
5603
|
+
}
|
|
5604
|
+
if (phrase.endBeat > cursor + _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5605
|
+
segments.push({ startBeat: cursor, endBeat: phrase.endBeat, motif: null });
|
|
5606
|
+
}
|
|
5607
|
+
return segments;
|
|
5608
|
+
}
|
|
5609
|
+
function notesAt(onsets, endBeat) {
|
|
5610
|
+
return onsets.map((startBeat, i) => ({
|
|
5611
|
+
pitch: 0,
|
|
5612
|
+
startBeat,
|
|
5613
|
+
durationBeat: (_nullishCoalesce(onsets[i + 1], () => ( endBeat))) - startBeat
|
|
5614
|
+
}));
|
|
5615
|
+
}
|
|
5616
|
+
function onsetSlots(scene, startBeat, endBeat) {
|
|
5617
|
+
const { meters } = scene.plan;
|
|
5618
|
+
const slots = [startBeat];
|
|
5619
|
+
let bar2 = _chunkS5BKZZGMcjs.barStartBeat.call(void 0, startBeat, meters);
|
|
5620
|
+
while (bar2 < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5621
|
+
const barEnd = bar2 + _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, bar2, meters);
|
|
5622
|
+
for (let k = 0; bar2 + k / RHYTHM_SUBDIVISION < barEnd - _chunkS5BKZZGMcjs.BEAT_EPS; k += 1) {
|
|
5623
|
+
const beat = bar2 + k / RHYTHM_SUBDIVISION;
|
|
5624
|
+
if (beat > startBeat + _chunkS5BKZZGMcjs.BEAT_EPS && beat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5625
|
+
slots.push(beat);
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
bar2 = barEnd;
|
|
5629
|
+
}
|
|
5630
|
+
return slots;
|
|
5631
|
+
}
|
|
5632
|
+
function drawOnsets(scene, phraseIndex, startBeat, endBeat, count) {
|
|
5633
|
+
const slots = onsetSlots(scene, startBeat, endBeat);
|
|
5634
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, slots.length * Math.max(1, count - 1), "melody onset slots", scene.budget);
|
|
5635
|
+
if (count - 1 > slots.length - 1) {
|
|
5636
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(
|
|
5637
|
+
`${count} onsets do not fit the sixteenth grid of beats ${startBeat}..${endBeat}`,
|
|
5638
|
+
{ at: scene.plan.phrases[phraseIndex].startBeat }
|
|
5639
|
+
);
|
|
5640
|
+
}
|
|
5641
|
+
const levels = slots.map((beat) => _chunkIFZDWIKMcjs.rhythmLevel.call(void 0, beat, scene.plan.meters));
|
|
5642
|
+
const perLevel = /* @__PURE__ */ new Map();
|
|
5643
|
+
for (const level of levels) {
|
|
5644
|
+
perLevel.set(level, (_nullishCoalesce(perLevel.get(level), () => ( 0))) + 1);
|
|
5645
|
+
}
|
|
5646
|
+
const levelWeight = levels.map(
|
|
5647
|
+
(level) => (_nullishCoalesce(scene.plan.rhythm.onsetLevels[level], () => ( 0))) / perLevel.get(level)
|
|
5648
|
+
);
|
|
5649
|
+
const draw = scene.ctx.part("melody");
|
|
5650
|
+
const onsets = [startBeat];
|
|
5651
|
+
let current = 0;
|
|
5652
|
+
for (let k = 1; k < count; k += 1) {
|
|
5653
|
+
const last = slots.length - 1 - (count - 1 - k);
|
|
5654
|
+
const candidates = [];
|
|
5655
|
+
for (let j = current + 1; j <= last; j += 1) candidates.push(j);
|
|
5656
|
+
const gapShare = (j) => _nullishCoalesce(scene.plan.rhythm.interOnsetShares[_chunkIFZDWIKMcjs.ioiBinIndex.call(void 0, slots[j] - slots[current])], () => ( 0));
|
|
5657
|
+
let weights = candidates.map((j) => levelWeight[j] * gapShare(j));
|
|
5658
|
+
if (!weights.some((w) => w > 0)) weights = candidates.map((j) => levelWeight[j]);
|
|
5659
|
+
if (!weights.some((w) => w > 0)) weights = candidates.map(() => 1);
|
|
5660
|
+
const total = weights.reduce((sum, w) => sum + w, 0);
|
|
5661
|
+
let target = draw.float(0, 1, phraseIndex, "onset", startBeat, k) * total;
|
|
5662
|
+
let pick = candidates.length - 1;
|
|
5663
|
+
for (let c = 0; c < candidates.length; c += 1) {
|
|
5664
|
+
target -= weights[c];
|
|
5665
|
+
if (target < 0) {
|
|
5666
|
+
pick = c;
|
|
5667
|
+
break;
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5670
|
+
current = candidates[pick];
|
|
5671
|
+
onsets.push(slots[current]);
|
|
5672
|
+
}
|
|
5673
|
+
return notesAt(onsets, endBeat);
|
|
5674
|
+
}
|
|
5675
|
+
function placeRhythm(scene, motif) {
|
|
5676
|
+
const { rhythm, startBeat, endBeat, notes } = motif;
|
|
5677
|
+
if (rhythm === null) {
|
|
5678
|
+
return drawOnsets(scene, motif.phrase, startBeat, endBeat, notes);
|
|
5679
|
+
}
|
|
5680
|
+
const onsets = [startBeat];
|
|
5681
|
+
for (const gap of rhythm) {
|
|
5682
|
+
onsets.push(onsets.at(-1) + gap);
|
|
5683
|
+
}
|
|
5684
|
+
return notesAt(onsets, endBeat);
|
|
5685
|
+
}
|
|
5686
|
+
function searchedLine(rhythm, frame) {
|
|
5687
|
+
const slots = rhythm.map((note2) => ({
|
|
5688
|
+
candidates: frame.candidatesAt(note2.startBeat),
|
|
5689
|
+
cost: frame.costAt(note2.startBeat),
|
|
5690
|
+
fixed: false
|
|
5691
|
+
}));
|
|
5692
|
+
const pitches = searchPitches(slots, frame.budget);
|
|
5693
|
+
if (pitches === null) {
|
|
5694
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(`no pitch line fits the register ${frame.low}..${frame.high}`, {
|
|
5695
|
+
at: frame.at
|
|
5696
|
+
});
|
|
5697
|
+
}
|
|
5698
|
+
return rhythm.map((note2, i) => ({ ...note2, pitch: pitches[i] }));
|
|
5699
|
+
}
|
|
5700
|
+
function statementOf(scene, m) {
|
|
5701
|
+
const known = scene.statements.get(m);
|
|
5702
|
+
if (known !== void 0) {
|
|
5703
|
+
return known;
|
|
5704
|
+
}
|
|
5705
|
+
scene.inProgress.add(m);
|
|
5706
|
+
const motif = scene.plan.motifs[m];
|
|
5707
|
+
const frame = scene.frames[motif.phrase];
|
|
5708
|
+
let notes;
|
|
5709
|
+
if (motif.from === null) {
|
|
5710
|
+
if (motif.endBeat - motif.startBeat <= _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5711
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(`root motif ${m} spans no time to place its notes in`, {
|
|
5712
|
+
at: frame.at
|
|
5713
|
+
});
|
|
5714
|
+
}
|
|
5715
|
+
notes = searchedLine(placeRhythm(scene, motif), frame);
|
|
5716
|
+
} else {
|
|
5717
|
+
const source = statementOf(scene, motif.from);
|
|
5718
|
+
notes = motif.relation === null ? varyStatement(source, motif.startBeat, frame) : placeDerived(
|
|
5719
|
+
source,
|
|
5720
|
+
motif.relation,
|
|
5721
|
+
motif.startBeat,
|
|
5722
|
+
motif.endBeat,
|
|
5723
|
+
scaleAt(scene, motif.startBeat),
|
|
5724
|
+
frame,
|
|
5725
|
+
lineBefore(scene, motif.phrase, motif.startBeat)
|
|
5726
|
+
);
|
|
5727
|
+
}
|
|
5728
|
+
scene.inProgress.delete(m);
|
|
5729
|
+
scene.statements.set(m, notes);
|
|
5730
|
+
return notes;
|
|
5731
|
+
}
|
|
5732
|
+
function freeNoteCount(scene, index, segment) {
|
|
5733
|
+
const phrase = scene.plan.phrases[index];
|
|
5734
|
+
const bars = _chunkIFZDWIKMcjs.barSpanOf.call(void 0, segment.startBeat, segment.endBeat, scene.plan.meters);
|
|
5735
|
+
return Math.max(1, Math.round(phrase.onsetDensity * bars));
|
|
5736
|
+
}
|
|
5737
|
+
function freeSpan(scene, index, segment) {
|
|
5738
|
+
const key = `${index}:${segment.startBeat}`;
|
|
5739
|
+
const known = scene.free.get(key);
|
|
5740
|
+
if (known !== void 0) {
|
|
5741
|
+
return known;
|
|
5742
|
+
}
|
|
5743
|
+
const rhythm = drawOnsets(
|
|
5744
|
+
scene,
|
|
5745
|
+
index,
|
|
5746
|
+
segment.startBeat,
|
|
5747
|
+
segment.endBeat,
|
|
5748
|
+
freeNoteCount(scene, index, segment)
|
|
5749
|
+
);
|
|
5750
|
+
const notes = searchedLine(rhythm, scene.frames[index]);
|
|
5751
|
+
scene.free.set(key, notes);
|
|
5752
|
+
return notes;
|
|
5753
|
+
}
|
|
5754
|
+
function lineBefore(scene, index, beat) {
|
|
5755
|
+
const line = [];
|
|
5756
|
+
for (const segment of segmentsOf(scene, index)) {
|
|
5757
|
+
if (segment.endBeat > beat + _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5758
|
+
break;
|
|
5759
|
+
}
|
|
5760
|
+
if (segment.motif === null) {
|
|
5761
|
+
line.push(...freeSpan(scene, index, segment));
|
|
5762
|
+
} else if (!scene.inProgress.has(segment.motif)) {
|
|
5763
|
+
line.push(...statementOf(scene, segment.motif));
|
|
5764
|
+
}
|
|
5765
|
+
}
|
|
5766
|
+
return line.sort((a, b) => a.startBeat - b.startBeat);
|
|
5767
|
+
}
|
|
5768
|
+
function finalDownbeat(scene, index) {
|
|
5769
|
+
const phrase = scene.plan.phrases[index];
|
|
5770
|
+
const { meters } = scene.plan;
|
|
5771
|
+
let downbeat = _chunkS5BKZZGMcjs.barStartBeat.call(void 0, phrase.startBeat, meters);
|
|
5772
|
+
while (downbeat + _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, downbeat, meters) < phrase.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5773
|
+
downbeat += _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, downbeat, meters);
|
|
5774
|
+
}
|
|
5775
|
+
return Math.max(downbeat, phrase.startBeat);
|
|
5776
|
+
}
|
|
5777
|
+
function heldNoteIndex(scene, index, line, downbeat) {
|
|
5778
|
+
const phrase = scene.plan.phrases[index];
|
|
5779
|
+
const sounding2 = line.findIndex(
|
|
5780
|
+
(note2) => note2.startBeat <= downbeat + _chunkS5BKZZGMcjs.BEAT_EPS && note2.startBeat + note2.durationBeat > downbeat + _chunkS5BKZZGMcjs.BEAT_EPS
|
|
5781
|
+
);
|
|
5782
|
+
return sounding2 >= 0 ? sounding2 : line.findIndex(
|
|
5783
|
+
(note2) => note2.startBeat >= downbeat - _chunkS5BKZZGMcjs.BEAT_EPS && note2.startBeat < phrase.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
5784
|
+
);
|
|
5785
|
+
}
|
|
5786
|
+
function repairCadence(scene, index, line, held) {
|
|
5787
|
+
const phrase = scene.plan.phrases[index];
|
|
5788
|
+
if (phrase.cadence === null) {
|
|
5789
|
+
return;
|
|
5790
|
+
}
|
|
5791
|
+
let target = held;
|
|
5792
|
+
for (let i = line.length - 1; target < 0 && i >= 0; i -= 1) {
|
|
5793
|
+
if (positionClass(line[i].startBeat, scene.plan.meters) !== "off") {
|
|
5794
|
+
target = i;
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5797
|
+
if (target < 0) {
|
|
5798
|
+
return;
|
|
5799
|
+
}
|
|
5800
|
+
const note2 = line[target];
|
|
5801
|
+
const allowed = cadencePitchClasses(scene.plan, scene.timeline, phrase.cadence, note2.startBeat);
|
|
5802
|
+
if (allowed === null) {
|
|
5803
|
+
return;
|
|
5804
|
+
}
|
|
5805
|
+
const frame = scene.frames[index];
|
|
5806
|
+
const candidates = registerPitches(phrase).filter(
|
|
5807
|
+
(pitch) => allowed.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch))
|
|
5808
|
+
);
|
|
5809
|
+
if (candidates.length === 0) {
|
|
5810
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(
|
|
5811
|
+
`no pitch in the register ${frame.low}..${frame.high} can end the ${phrase.cadence} cadence`,
|
|
5812
|
+
{ at: frame.at }
|
|
5813
|
+
);
|
|
5814
|
+
}
|
|
5815
|
+
if (allowed.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, note2.pitch))) {
|
|
5816
|
+
return;
|
|
5817
|
+
}
|
|
5818
|
+
const slots = line.map(
|
|
5819
|
+
(n, i) => i === target ? { candidates, cost: frame.costAt(n.startBeat), fixed: false } : { candidates: [n.pitch], cost: () => 0, fixed: true }
|
|
5820
|
+
);
|
|
5821
|
+
const pitches = searchPitches(slots, frame.budget);
|
|
5822
|
+
if (pitches === null) {
|
|
5823
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(`no cadence pitch joins its neighbours without an augmented step`, {
|
|
5824
|
+
at: frame.at
|
|
5825
|
+
});
|
|
5826
|
+
}
|
|
5827
|
+
note2.pitch = pitches[target];
|
|
5828
|
+
}
|
|
5829
|
+
function repickCutOnset(scene, index, line, held) {
|
|
5830
|
+
const note2 = line[held];
|
|
5831
|
+
const derived = scene.plan.motifs.some(
|
|
5832
|
+
(motif) => motif.from !== null && note2.startBeat >= motif.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && note2.startBeat < motif.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
5833
|
+
);
|
|
5834
|
+
if (scene.plan.phrases[index].cadence !== null || derived) {
|
|
5835
|
+
return;
|
|
5836
|
+
}
|
|
5837
|
+
const frame = scene.frames[index];
|
|
5838
|
+
const candidates = frame.candidatesAt(note2.startBeat);
|
|
5839
|
+
if (candidates.includes(note2.pitch)) {
|
|
5840
|
+
return;
|
|
5841
|
+
}
|
|
5842
|
+
const slots = line.map(
|
|
5843
|
+
(n, i) => i === held ? { candidates, cost: frame.costAt(n.startBeat), fixed: false } : { candidates: [n.pitch], cost: () => 0, fixed: true }
|
|
5844
|
+
);
|
|
5845
|
+
const pitches = searchPitches(slots, frame.budget);
|
|
5846
|
+
if (pitches === null) {
|
|
5847
|
+
throw new (0, _chunkS5BKZZGMcjs.NoSolutionError)(`no pitch at the final downbeat joins its neighbours`, {
|
|
5848
|
+
at: frame.at
|
|
5849
|
+
});
|
|
5850
|
+
}
|
|
5851
|
+
line[held] = { ...note2, pitch: pitches[held] };
|
|
5852
|
+
}
|
|
5853
|
+
function phraseLine(scene, index) {
|
|
5854
|
+
const line = [];
|
|
5855
|
+
for (const segment of segmentsOf(scene, index)) {
|
|
5856
|
+
line.push(
|
|
5857
|
+
...segment.motif === null ? freeSpan(scene, index, segment) : statementOf(scene, segment.motif)
|
|
5858
|
+
);
|
|
5859
|
+
}
|
|
5860
|
+
return line.sort((a, b) => a.startBeat - b.startBeat);
|
|
5861
|
+
}
|
|
5862
|
+
function chargePitchSearch(scene) {
|
|
5863
|
+
const { plan } = scene;
|
|
5864
|
+
let estimate = 0;
|
|
5865
|
+
plan.phrases.forEach((phrase, index) => {
|
|
5866
|
+
let searched = 0;
|
|
5867
|
+
for (const segment of segmentsOf(scene, index)) {
|
|
5868
|
+
const motif = segment.motif === null ? void 0 : plan.motifs[segment.motif];
|
|
5869
|
+
if (motif === void 0) {
|
|
5870
|
+
searched += freeNoteCount(scene, index, segment);
|
|
5871
|
+
} else if (motif.relation === null) {
|
|
5872
|
+
searched += motif.notes;
|
|
5873
|
+
} else {
|
|
5874
|
+
estimate += motif.notes * relationLevels(motif.relation.kind).length;
|
|
5875
|
+
}
|
|
5876
|
+
}
|
|
5877
|
+
const register = Math.max(0, phrase.register.high - phrase.register.low + 1);
|
|
5878
|
+
estimate += searched * SEARCH_STATES_SQUARED * register * register;
|
|
5879
|
+
});
|
|
5880
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, estimate, "melody pitch search", scene.budget);
|
|
5881
|
+
}
|
|
5882
|
+
function generateMelody(plan, opts) {
|
|
5883
|
+
assertCompositionPlan(plan);
|
|
5884
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
5885
|
+
if (asked.budget !== void 0) {
|
|
5886
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, asked.budget, "budget", Number.MAX_SAFE_INTEGER);
|
|
5887
|
+
}
|
|
5888
|
+
const timeline = planChordTimeline(plan);
|
|
5889
|
+
const scene = {
|
|
5890
|
+
plan,
|
|
5891
|
+
ctx: melodyContext(plan, asked.ctx),
|
|
5892
|
+
budget: asked.budget,
|
|
5893
|
+
timeline,
|
|
5894
|
+
harmonyMisfits: planHarmonyMisfits(plan, timeline),
|
|
5895
|
+
scales: plan.keys.map((key) => _chunk3R3QVKY5cjs.scaleOf.call(void 0, key)),
|
|
5896
|
+
members: membersOf(plan),
|
|
5897
|
+
frames: [],
|
|
5898
|
+
statements: /* @__PURE__ */ new Map(),
|
|
5899
|
+
free: /* @__PURE__ */ new Map(),
|
|
5900
|
+
inProgress: /* @__PURE__ */ new Set()
|
|
5901
|
+
};
|
|
5902
|
+
scene.frames = plan.phrases.map((_, index) => frameOf(scene, index));
|
|
5903
|
+
chargePitchSearch(scene);
|
|
5904
|
+
const melody = [];
|
|
5905
|
+
plan.phrases.forEach((_, index) => {
|
|
5906
|
+
const line = phraseLine(scene, index);
|
|
5907
|
+
const downbeat = finalDownbeat(scene, index);
|
|
5908
|
+
let held = heldNoteIndex(scene, index, line, downbeat);
|
|
5909
|
+
if (held >= 0) {
|
|
5910
|
+
line.length = held + 1;
|
|
5911
|
+
const note2 = line[held];
|
|
5912
|
+
if (note2.startBeat < downbeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
5913
|
+
const cut = downbeat - note2.startBeat;
|
|
5914
|
+
line[held] = { ...note2, durationBeat: cut };
|
|
5915
|
+
line.push({ ...note2, startBeat: downbeat, durationBeat: note2.durationBeat - cut });
|
|
5916
|
+
held += 1;
|
|
5917
|
+
repickCutOnset(scene, index, line, held);
|
|
5918
|
+
}
|
|
5919
|
+
}
|
|
5920
|
+
repairCadence(scene, index, line, held);
|
|
5921
|
+
if (held >= 0) {
|
|
5922
|
+
const note2 = line[held];
|
|
5923
|
+
const phraseEnd = plan.phrases[index].endBeat;
|
|
5924
|
+
line[held] = { ...note2, durationBeat: phraseEnd - note2.startBeat };
|
|
5925
|
+
}
|
|
5926
|
+
melody.push(...line);
|
|
5927
|
+
});
|
|
5928
|
+
melody.sort((a, b) => a.startBeat - b.startBeat);
|
|
5929
|
+
return motifToNoteEvents({ notes: melody });
|
|
5930
|
+
}
|
|
5931
|
+
|
|
4840
5932
|
// src/generate/ornament/index.ts
|
|
4841
5933
|
var ORNAMENT_STYLES = Object.freeze(["ghost", "flam", "drag", "slide", "accent"]);
|
|
4842
5934
|
var DEFAULT_TS5 = { numerator: 4, denominator: 4 };
|
|
@@ -4849,7 +5941,7 @@ var MIN_VELOCITY2 = 1;
|
|
|
4849
5941
|
var MAX_VELOCITY2 = 127;
|
|
4850
5942
|
var SLIDE_MIN_SEMITONES = 1;
|
|
4851
5943
|
function eligible(style, note2, previous, next, ts) {
|
|
4852
|
-
const strong =
|
|
5944
|
+
const strong = _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, note2.startBeat, ts);
|
|
4853
5945
|
switch (style) {
|
|
4854
5946
|
case "ghost":
|
|
4855
5947
|
return !strong;
|
|
@@ -4857,7 +5949,7 @@ function eligible(style, note2, previous, next, ts) {
|
|
|
4857
5949
|
case "accent":
|
|
4858
5950
|
return strong;
|
|
4859
5951
|
case "drag":
|
|
4860
|
-
return !strong && next !== void 0 &&
|
|
5952
|
+
return !strong && next !== void 0 && _chunkS5BKZZGMcjs.isStrongBeat.call(void 0, next.startBeat, ts);
|
|
4861
5953
|
case "slide":
|
|
4862
5954
|
return previous !== void 0 && Math.abs(note2.pitch - previous.pitch) >= SLIDE_MIN_SEMITONES;
|
|
4863
5955
|
}
|
|
@@ -4882,18 +5974,18 @@ function clampVelocity(velocity) {
|
|
|
4882
5974
|
return Math.min(MAX_VELOCITY2, Math.max(MIN_VELOCITY2, Math.round(velocity)));
|
|
4883
5975
|
}
|
|
4884
5976
|
function ornament(notes, opts = {}) {
|
|
4885
|
-
const asked =
|
|
4886
|
-
|
|
4887
|
-
const style =
|
|
4888
|
-
const ts =
|
|
4889
|
-
|
|
5977
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
5978
|
+
_chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, notes, "ornament notes", { allowNonPositiveDuration: true });
|
|
5979
|
+
const style = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, _nullishCoalesce(asked.style, () => ( DEFAULT_STYLE2)), ORNAMENT_STYLES, "ornament style");
|
|
5980
|
+
const ts = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, _nullishCoalesce(asked.ts, () => ( DEFAULT_TS5)), "ts"));
|
|
5981
|
+
_chunkS5BKZZGMcjs.assertTimeSignature.call(void 0, ts);
|
|
4890
5982
|
if (asked.amount !== void 0) {
|
|
4891
|
-
|
|
5983
|
+
_chunkS5BKZZGMcjs.assertRange.call(void 0, asked.amount, 0, 1, "ornament amount");
|
|
4892
5984
|
}
|
|
4893
5985
|
const ctx = resolveContextWith(asked.ctx, { ornament: asked.amount });
|
|
4894
5986
|
const amount = _nullishCoalesce(ctx.ornament, () => ( DEFAULT_AMOUNT));
|
|
4895
5987
|
const draw = ctx.part("ornament");
|
|
4896
|
-
const sounding2 =
|
|
5988
|
+
const sounding2 = _chunkS5BKZZGMcjs.dropSilentNotes.call(void 0, notes);
|
|
4897
5989
|
const ordered = [...sounding2].sort((a, b) => a.startBeat - b.startBeat || a.pitch - b.pitch);
|
|
4898
5990
|
const previousOf = previousOnsets(ordered);
|
|
4899
5991
|
const nextOf = nextOnsets(ordered);
|
|
@@ -4961,6 +6053,878 @@ function strokeGaps(ordered) {
|
|
|
4961
6053
|
return gaps;
|
|
4962
6054
|
}
|
|
4963
6055
|
|
|
6056
|
+
// src/generate/plan/derive.ts
|
|
6057
|
+
var PRESERVE_ASPECTS = [
|
|
6058
|
+
"form",
|
|
6059
|
+
"phraseLengths",
|
|
6060
|
+
"harmonicFunction",
|
|
6061
|
+
"harmonicRhythm",
|
|
6062
|
+
"motifRelations",
|
|
6063
|
+
"registerShape",
|
|
6064
|
+
"rhythm"
|
|
6065
|
+
];
|
|
6066
|
+
var NEUTRAL_SHAPE = "arch";
|
|
6067
|
+
var NEUTRAL_PEAK_POSITION = 0.6;
|
|
6068
|
+
var SHAPE_KEEP_THRESHOLD = 0.5;
|
|
6069
|
+
var NEUTRAL_ONSET_LEVELS = Object.freeze([0, 1, 2, 3, 4, 5].map((level) => level / 15));
|
|
6070
|
+
var FUNCTION_DEGREES = {
|
|
6071
|
+
tonic: [1, 6, 3],
|
|
6072
|
+
subdominant: [4, 2],
|
|
6073
|
+
dominant: [5, 7]
|
|
6074
|
+
};
|
|
6075
|
+
var STRONG_WEIGHT2 = 2;
|
|
6076
|
+
var HEPTATONIC_DEGREES = 7;
|
|
6077
|
+
function mod12(value) {
|
|
6078
|
+
return (value % 12 + 12) % 12;
|
|
6079
|
+
}
|
|
6080
|
+
function lerp(weight, reference, neutral) {
|
|
6081
|
+
return weight * reference + (1 - weight) * neutral;
|
|
6082
|
+
}
|
|
6083
|
+
function readPreserve(value) {
|
|
6084
|
+
const read = value === void 0 ? {} : _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, "opts.preserve");
|
|
6085
|
+
const weights = {};
|
|
6086
|
+
for (const aspect of PRESERVE_ASPECTS) {
|
|
6087
|
+
const weight = read[aspect];
|
|
6088
|
+
weights[aspect] = weight === void 0 ? 1 : _chunkS5BKZZGMcjs.assertRange.call(void 0, weight, 0, 1, `opts.preserve.${aspect}`);
|
|
6089
|
+
}
|
|
6090
|
+
return weights;
|
|
6091
|
+
}
|
|
6092
|
+
function readRegister(value) {
|
|
6093
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, value, "opts.register");
|
|
6094
|
+
const low = _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, read.low, "opts.register.low");
|
|
6095
|
+
const high = _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, read.high, "opts.register.high");
|
|
6096
|
+
if (low > high) {
|
|
6097
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
6098
|
+
`opts.register.low must not exceed opts.register.high; received ${low} > ${high}`
|
|
6099
|
+
);
|
|
6100
|
+
}
|
|
6101
|
+
return { low, high };
|
|
6102
|
+
}
|
|
6103
|
+
function rejectSuppliedRng(ctx) {
|
|
6104
|
+
if (typeof ctx === "object" && ctx !== null && ctx.rng !== void 0) {
|
|
6105
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
6106
|
+
"opts.ctx.rng is not accepted: a composition plan records its seed, not a source"
|
|
6107
|
+
);
|
|
6108
|
+
}
|
|
6109
|
+
}
|
|
6110
|
+
function plannedKeys(profile, requested) {
|
|
6111
|
+
const regions = profile.harmony.keys.map(
|
|
6112
|
+
({ key }) => ({
|
|
6113
|
+
scale: { ...key.scale },
|
|
6114
|
+
tonic: { ...key.tonic },
|
|
6115
|
+
variant: key.variant
|
|
6116
|
+
})
|
|
6117
|
+
);
|
|
6118
|
+
const home = regions[0];
|
|
6119
|
+
if (requested === void 0) {
|
|
6120
|
+
return regions;
|
|
6121
|
+
}
|
|
6122
|
+
const target = _chunk3R3QVKY5cjs.resolveKey.call(void 0, requested);
|
|
6123
|
+
if (target.variant !== home.variant || target.scale.modeMask12 !== home.scale.modeMask12) {
|
|
6124
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
6125
|
+
"opts.key must be in the same mode as the reference's home key; a key change moves the tonic only"
|
|
6126
|
+
);
|
|
6127
|
+
}
|
|
6128
|
+
const step = _chunkS5BKZZGMcjs.spelledInterval.call(void 0,
|
|
6129
|
+
{ letter: home.tonic.letter, alter: home.tonic.alter },
|
|
6130
|
+
{ letter: target.tonic.letter, alter: target.tonic.alter }
|
|
6131
|
+
);
|
|
6132
|
+
const moved = regions.map(
|
|
6133
|
+
(key) => ({
|
|
6134
|
+
scale: {
|
|
6135
|
+
rootPc: mod12(key.scale.rootPc + step.semitones),
|
|
6136
|
+
modeMask12: key.scale.modeMask12
|
|
6137
|
+
},
|
|
6138
|
+
tonic: _chunkS5BKZZGMcjs.transposeByInterval.call(void 0, { letter: key.tonic.letter, alter: key.tonic.alter }, step),
|
|
6139
|
+
variant: key.variant
|
|
6140
|
+
})
|
|
6141
|
+
);
|
|
6142
|
+
moved[0] = target;
|
|
6143
|
+
return moved;
|
|
6144
|
+
}
|
|
6145
|
+
function nearestBoundary(beat, boundaries) {
|
|
6146
|
+
let best = beat;
|
|
6147
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
6148
|
+
for (const boundary of boundaries) {
|
|
6149
|
+
const distance = Math.abs(boundary - beat);
|
|
6150
|
+
if (distance < bestDistance - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6151
|
+
best = boundary;
|
|
6152
|
+
bestDistance = distance;
|
|
6153
|
+
}
|
|
6154
|
+
}
|
|
6155
|
+
return best;
|
|
6156
|
+
}
|
|
6157
|
+
function plannedSections(profile, weight, draw) {
|
|
6158
|
+
const sections = profile.form.sections;
|
|
6159
|
+
const boundaries = [profile.span.startBeat, profile.span.endBeat];
|
|
6160
|
+
for (const phrase of profile.form.phrases) {
|
|
6161
|
+
boundaries.push(phrase.startBeat, phrase.endBeat);
|
|
6162
|
+
}
|
|
6163
|
+
boundaries.sort((a, b) => a - b);
|
|
6164
|
+
const planned = [];
|
|
6165
|
+
sections.forEach((section, index) => {
|
|
6166
|
+
const keep = sections.length < 2 || draw.prob(weight, "form", index);
|
|
6167
|
+
const neighbour = index + 1 < sections.length ? index + 1 : index - 1;
|
|
6168
|
+
const startBeat = nearestBoundary(section.startBeat, boundaries);
|
|
6169
|
+
const endBeat = nearestBoundary(section.endBeat, boundaries);
|
|
6170
|
+
if (endBeat - startBeat > _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6171
|
+
planned.push({
|
|
6172
|
+
label: keep ? section.label : _nullishCoalesce(_optionalChain([sections, 'access', _70 => _70[neighbour], 'optionalAccess', _71 => _71.label]), () => ( section.label)),
|
|
6173
|
+
startBeat,
|
|
6174
|
+
endBeat
|
|
6175
|
+
});
|
|
6176
|
+
}
|
|
6177
|
+
});
|
|
6178
|
+
return planned;
|
|
6179
|
+
}
|
|
6180
|
+
function beatAfterBars(startBeat, bars, meters) {
|
|
6181
|
+
let beat = startBeat;
|
|
6182
|
+
let left = bars;
|
|
6183
|
+
while (left > _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6184
|
+
const step = Math.min(1, left);
|
|
6185
|
+
beat += step * _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, beat, meters);
|
|
6186
|
+
left -= step;
|
|
6187
|
+
}
|
|
6188
|
+
return beat;
|
|
6189
|
+
}
|
|
6190
|
+
function barsBetween(startBeat, endBeat, meters) {
|
|
6191
|
+
let beat = startBeat;
|
|
6192
|
+
let bars = 0;
|
|
6193
|
+
while (beat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6194
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBarAt.call(void 0, beat, meters);
|
|
6195
|
+
const step = Math.min(_chunkS5BKZZGMcjs.barStartBeat.call(void 0, beat, meters) + barBeats, endBeat) - beat;
|
|
6196
|
+
bars += step / barBeats;
|
|
6197
|
+
beat += step;
|
|
6198
|
+
}
|
|
6199
|
+
return bars;
|
|
6200
|
+
}
|
|
6201
|
+
function spanSegments(profile, sections) {
|
|
6202
|
+
const { startBeat, endBeat } = profile.span;
|
|
6203
|
+
const cuts = [startBeat, endBeat];
|
|
6204
|
+
for (const section of sections) {
|
|
6205
|
+
for (const beat of [section.startBeat, section.endBeat]) {
|
|
6206
|
+
if (beat > startBeat + _chunkS5BKZZGMcjs.BEAT_EPS && beat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) cuts.push(beat);
|
|
6207
|
+
}
|
|
6208
|
+
}
|
|
6209
|
+
cuts.sort((a, b) => a - b);
|
|
6210
|
+
const segments = [];
|
|
6211
|
+
for (let index = 1; index < cuts.length; index += 1) {
|
|
6212
|
+
const from = cuts[index - 1];
|
|
6213
|
+
const to = cuts[index];
|
|
6214
|
+
if (to - from > _chunkS5BKZZGMcjs.BEAT_EPS) segments.push([from, to]);
|
|
6215
|
+
}
|
|
6216
|
+
return segments;
|
|
6217
|
+
}
|
|
6218
|
+
function plannedPhraseSpans(profile, sections, weight, draw) {
|
|
6219
|
+
const segments = spanSegments(profile, sections);
|
|
6220
|
+
const pieces = profile.form.phrases.map((phrase, source) => ({
|
|
6221
|
+
startBeat: phrase.startBeat,
|
|
6222
|
+
endBeat: phrase.endBeat,
|
|
6223
|
+
source,
|
|
6224
|
+
cadence: _nullishCoalesce(_optionalChain([phrase, 'access', _72 => _72.cadence, 'optionalAccess', _73 => _73.type]), () => ( null))
|
|
6225
|
+
}));
|
|
6226
|
+
const replaced = pieces.map((_, index) => !draw.prob(weight, "phraseLengths", index));
|
|
6227
|
+
const spans = [];
|
|
6228
|
+
for (const [segmentStart, segmentEnd] of segments) {
|
|
6229
|
+
const members = pieces.map((piece, index) => ({ piece, index })).filter(
|
|
6230
|
+
({ piece }) => piece.startBeat >= segmentStart - _chunkS5BKZZGMcjs.BEAT_EPS && piece.startBeat < segmentEnd - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6231
|
+
);
|
|
6232
|
+
const laid = [];
|
|
6233
|
+
let cursor = segmentStart;
|
|
6234
|
+
for (const { piece, index } of members) {
|
|
6235
|
+
const lengths = [];
|
|
6236
|
+
if (replaced[index]) {
|
|
6237
|
+
const bars = barsBetween(piece.startBeat, piece.endBeat, profile.meters);
|
|
6238
|
+
const rounded = 2 ** Math.round(Math.log2(bars));
|
|
6239
|
+
const overflows = beatAfterBars(cursor, rounded, profile.meters) > segmentEnd + _chunkS5BKZZGMcjs.BEAT_EPS;
|
|
6240
|
+
let partStart = cursor;
|
|
6241
|
+
for (const part of overflows ? [rounded / 2, rounded / 2] : [rounded]) {
|
|
6242
|
+
const partEnd = beatAfterBars(partStart, part, profile.meters);
|
|
6243
|
+
lengths.push(partEnd - partStart);
|
|
6244
|
+
partStart = partEnd;
|
|
6245
|
+
}
|
|
6246
|
+
} else {
|
|
6247
|
+
lengths.push(piece.endBeat - piece.startBeat);
|
|
6248
|
+
}
|
|
6249
|
+
lengths.forEach((length, part) => {
|
|
6250
|
+
if (cursor >= segmentEnd - _chunkS5BKZZGMcjs.BEAT_EPS) return;
|
|
6251
|
+
const end = cursor + length;
|
|
6252
|
+
laid.push({
|
|
6253
|
+
startBeat: cursor,
|
|
6254
|
+
endBeat: Math.min(end, segmentEnd),
|
|
6255
|
+
source: piece.source,
|
|
6256
|
+
cadence: part === lengths.length - 1 ? piece.cadence : null
|
|
6257
|
+
});
|
|
6258
|
+
cursor = end;
|
|
6259
|
+
});
|
|
6260
|
+
}
|
|
6261
|
+
const last = laid.at(-1);
|
|
6262
|
+
if (last) {
|
|
6263
|
+
last.endBeat = segmentEnd;
|
|
6264
|
+
} else {
|
|
6265
|
+
laid.push({
|
|
6266
|
+
startBeat: segmentStart,
|
|
6267
|
+
endBeat: segmentEnd,
|
|
6268
|
+
source: _nullishCoalesce(_optionalChain([spans, 'access', _74 => _74.at, 'call', _75 => _75(-1), 'optionalAccess', _76 => _76.source]), () => ( (profile.form.phrases.length > 0 ? 0 : -1))),
|
|
6269
|
+
cadence: null
|
|
6270
|
+
});
|
|
6271
|
+
}
|
|
6272
|
+
spans.push(...laid);
|
|
6273
|
+
}
|
|
6274
|
+
return spans;
|
|
6275
|
+
}
|
|
6276
|
+
function sectionAt(sections, beat) {
|
|
6277
|
+
const index = sections.findIndex(
|
|
6278
|
+
(section) => beat >= section.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && beat < section.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6279
|
+
);
|
|
6280
|
+
return index < 0 ? null : index;
|
|
6281
|
+
}
|
|
6282
|
+
function phraseHolding(phrases, startBeat, endBeat) {
|
|
6283
|
+
return phrases.findIndex(
|
|
6284
|
+
(phrase) => startBeat >= phrase.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && endBeat <= phrase.endBeat + _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6285
|
+
);
|
|
6286
|
+
}
|
|
6287
|
+
function better(a, b) {
|
|
6288
|
+
for (let field = 0; field < a.length; field += 1) {
|
|
6289
|
+
if (a[field] !== b[field]) return a[field] > b[field];
|
|
6290
|
+
}
|
|
6291
|
+
return false;
|
|
6292
|
+
}
|
|
6293
|
+
function scheduleMotifs(candidates, meters) {
|
|
6294
|
+
const order = [...candidates].sort((a, b) => a.startBeat - b.startBeat || a.node - b.node);
|
|
6295
|
+
const count = order.length;
|
|
6296
|
+
const firstFrom = (from, beat) => {
|
|
6297
|
+
let low = from;
|
|
6298
|
+
let high = count;
|
|
6299
|
+
while (low < high) {
|
|
6300
|
+
const mid = low + high >> 1;
|
|
6301
|
+
if (order[mid].startBeat < beat - _chunkS5BKZZGMcjs.BEAT_EPS) low = mid + 1;
|
|
6302
|
+
else high = mid;
|
|
6303
|
+
}
|
|
6304
|
+
return low;
|
|
6305
|
+
};
|
|
6306
|
+
const next = order.map((candidate, index2) => firstFrom(index2 + 1, candidate.endBeat));
|
|
6307
|
+
const own = order.map(
|
|
6308
|
+
(candidate) => [
|
|
6309
|
+
candidate.notes,
|
|
6310
|
+
_chunkS5BKZZGMcjs.metricWeight.call(void 0, candidate.startBeat, meters) < STRONG_WEIGHT2 ? -1 : 0,
|
|
6311
|
+
1
|
|
6312
|
+
]
|
|
6313
|
+
);
|
|
6314
|
+
const taking = (index2) => {
|
|
6315
|
+
const rest = best[next[index2]];
|
|
6316
|
+
const mine = own[index2];
|
|
6317
|
+
return [mine[0] + rest[0], mine[1] + rest[1], mine[2] + rest[2]];
|
|
6318
|
+
};
|
|
6319
|
+
const best = new Array(count + 1).fill([0, 0, 0]);
|
|
6320
|
+
for (let index2 = count - 1; index2 >= 0; index2 -= 1) {
|
|
6321
|
+
const taken = taking(index2);
|
|
6322
|
+
const skipped = best[index2 + 1];
|
|
6323
|
+
best[index2] = better(taken, skipped) ? taken : skipped;
|
|
6324
|
+
}
|
|
6325
|
+
const chosen = [];
|
|
6326
|
+
let index = 0;
|
|
6327
|
+
while (index < count) {
|
|
6328
|
+
if (!better(best[index], taking(index))) {
|
|
6329
|
+
chosen.push(order[index]);
|
|
6330
|
+
index = next[index];
|
|
6331
|
+
} else {
|
|
6332
|
+
index += 1;
|
|
6333
|
+
}
|
|
6334
|
+
}
|
|
6335
|
+
return chosen.sort((a, b) => a.node - b.node);
|
|
6336
|
+
}
|
|
6337
|
+
function selectedDerivation(graph, parentEdge, selectedAt, node) {
|
|
6338
|
+
let plain = true;
|
|
6339
|
+
let semitones = 0;
|
|
6340
|
+
let steps = 0;
|
|
6341
|
+
for (let edge = parentEdge.get(node); edge !== void 0; edge = parentEdge.get(edge.from)) {
|
|
6342
|
+
const relation = edge.relation;
|
|
6343
|
+
steps += 1;
|
|
6344
|
+
plain &&= relation !== null && (relation.kind === "repetition" || relation.kind === "transposition" && Math.abs(relation.timeRatio - 1) <= _chunkS5BKZZGMcjs.BEAT_EPS);
|
|
6345
|
+
semitones += _nullishCoalesce(_optionalChain([relation, 'optionalAccess', _77 => _77.semitones]), () => ( 0));
|
|
6346
|
+
const from = selectedAt.get(edge.from);
|
|
6347
|
+
if (from === void 0) continue;
|
|
6348
|
+
if (steps === 1) {
|
|
6349
|
+
return { from, relation: relation === null ? null : { ...relation } };
|
|
6350
|
+
}
|
|
6351
|
+
if (!plain) {
|
|
6352
|
+
return { from: null, relation: null };
|
|
6353
|
+
}
|
|
6354
|
+
const gap = (_nullishCoalesce(_optionalChain([graph, 'access', _78 => _78.nodes, 'access', _79 => _79[node], 'optionalAccess', _80 => _80.startBeat]), () => ( 0))) - (_nullishCoalesce(_optionalChain([graph, 'access', _81 => _81.nodes, 'access', _82 => _82[edge.from], 'optionalAccess', _83 => _83.endBeat]), () => ( 0)));
|
|
6355
|
+
return {
|
|
6356
|
+
from,
|
|
6357
|
+
relation: {
|
|
6358
|
+
kind: semitones === 0 ? "repetition" : "transposition",
|
|
6359
|
+
sequence: gap >= -_chunkIFZDWIKMcjs.HUMANIZE_ADJACENCY && gap <= _chunkIFZDWIKMcjs.HUMANIZE_ADJACENCY,
|
|
6360
|
+
semitones,
|
|
6361
|
+
timeRatio: 1
|
|
6362
|
+
}
|
|
6363
|
+
};
|
|
6364
|
+
}
|
|
6365
|
+
return { from: null, relation: null };
|
|
6366
|
+
}
|
|
6367
|
+
function functionCandidates(fn, key) {
|
|
6368
|
+
if (_chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, key).length !== HEPTATONIC_DEGREES) {
|
|
6369
|
+
return null;
|
|
6370
|
+
}
|
|
6371
|
+
return FUNCTION_DEGREES[fn].map((degree) => _chunkIFZDWIKMcjs.chordToRoman.call(void 0, _chunk3R3QVKY5cjs.diatonicTriad.call(void 0, degree, key), key));
|
|
6372
|
+
}
|
|
6373
|
+
function plannedHarmony(profile, keys, preserve, draw) {
|
|
6374
|
+
const chords = profile.harmony.chords;
|
|
6375
|
+
const romans = chords.map((chord, index) => {
|
|
6376
|
+
if (chord.level !== "structural" || draw.prob(preserve.harmonicFunction, "harmonicFunction", index)) {
|
|
6377
|
+
return chord.roman;
|
|
6378
|
+
}
|
|
6379
|
+
const candidates = functionCandidates(chord.function, keys[chord.key]);
|
|
6380
|
+
if (candidates === null) {
|
|
6381
|
+
return chord.roman;
|
|
6382
|
+
}
|
|
6383
|
+
const pick = draw.range(0, candidates.length - 1, "harmonicFunction", index, "pick");
|
|
6384
|
+
return candidates[pick];
|
|
6385
|
+
});
|
|
6386
|
+
const starts = [];
|
|
6387
|
+
chords.forEach((chord, index) => {
|
|
6388
|
+
const keep = index === 0 || draw.prob(preserve.harmonicRhythm, "harmonicRhythm", index);
|
|
6389
|
+
const start = keep ? chord.startBeat : _chunkS5BKZZGMcjs.barStartBeat.call(void 0, chord.startBeat, profile.meters);
|
|
6390
|
+
starts.push(index === 0 ? start : Math.max(start, starts[index - 1]));
|
|
6391
|
+
});
|
|
6392
|
+
const planned = [];
|
|
6393
|
+
chords.forEach((chord, index) => {
|
|
6394
|
+
const next = chords[index + 1];
|
|
6395
|
+
const nextStart = starts[index + 1];
|
|
6396
|
+
let endBeat = chord.endBeat;
|
|
6397
|
+
if (next !== void 0 && nextStart !== void 0) {
|
|
6398
|
+
endBeat = Math.abs(chord.endBeat - next.startBeat) <= _chunkS5BKZZGMcjs.BEAT_EPS ? nextStart : Math.min(chord.endBeat, nextStart);
|
|
6399
|
+
}
|
|
6400
|
+
const startBeat = starts[index];
|
|
6401
|
+
if (endBeat - startBeat > _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6402
|
+
planned.push({ startBeat, endBeat, key: chord.key, roman: romans[index] });
|
|
6403
|
+
}
|
|
6404
|
+
});
|
|
6405
|
+
return planned;
|
|
6406
|
+
}
|
|
6407
|
+
function plannedRhythm(profile, weight) {
|
|
6408
|
+
const reference = profile.melody.rhythm;
|
|
6409
|
+
return {
|
|
6410
|
+
onsetLevels: reference.onsetLevels.map(
|
|
6411
|
+
(share, level) => lerp(weight, share, NEUTRAL_ONSET_LEVELS[level])
|
|
6412
|
+
),
|
|
6413
|
+
interOnsetShares: [...reference.interOnsetShares],
|
|
6414
|
+
syncopation: lerp(weight, reference.syncopation, 0)
|
|
6415
|
+
};
|
|
6416
|
+
}
|
|
6417
|
+
function deriveCompositionPlan(reference, opts) {
|
|
6418
|
+
const profile = _chunkIFZDWIKMcjs.assertReferenceProfile.call(void 0, reference, "reference");
|
|
6419
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
6420
|
+
const preserve = readPreserve(asked.preserve);
|
|
6421
|
+
const requestedRegister = asked.register === void 0 ? void 0 : readRegister(asked.register);
|
|
6422
|
+
rejectSuppliedRng(asked.ctx);
|
|
6423
|
+
const ctx = resolveContext(asked.ctx);
|
|
6424
|
+
const draw = ctx.part("plan");
|
|
6425
|
+
const melodyRegister = profile.melody.register;
|
|
6426
|
+
if (profile.melody.rhythm.onsets === 0 || melodyRegister === null) {
|
|
6427
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("reference must carry melody onsets to derive a plan from");
|
|
6428
|
+
}
|
|
6429
|
+
const keys = plannedKeys(profile, asked.key);
|
|
6430
|
+
const homeShift = mod12(
|
|
6431
|
+
keys[0].scale.rootPc - (_nullishCoalesce(_optionalChain([profile, 'access', _84 => _84.harmony, 'access', _85 => _85.keys, 'access', _86 => _86[0], 'optionalAccess', _87 => _87.key, 'access', _88 => _88.scale, 'access', _89 => _89.rootPc]), () => ( 0)))
|
|
6432
|
+
);
|
|
6433
|
+
const shift = homeShift >= 6 ? homeShift - 12 : homeShift;
|
|
6434
|
+
const source = { low: melodyRegister.low + shift, high: melodyRegister.high + shift };
|
|
6435
|
+
if (source.low < 0 || source.high > 127) {
|
|
6436
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
6437
|
+
`the reference melody range moved to the new key leaves the MIDI range; received ${source.low}..${source.high}`
|
|
6438
|
+
);
|
|
6439
|
+
}
|
|
6440
|
+
const target = _nullishCoalesce(requestedRegister, () => ( source));
|
|
6441
|
+
const scale = source.high === source.low ? 0 : (target.high - target.low) / (source.high - source.low);
|
|
6442
|
+
const offset = source.high === source.low ? (target.low + target.high) / 2 : target.low - source.low * scale;
|
|
6443
|
+
const mapPitch = (pitch) => (pitch + shift) * scale + offset;
|
|
6444
|
+
const neutralRegister = {
|
|
6445
|
+
low: target.low,
|
|
6446
|
+
high: target.high,
|
|
6447
|
+
mean: (target.low + target.high) / 2
|
|
6448
|
+
};
|
|
6449
|
+
const sections = plannedSections(profile, preserve.form, draw);
|
|
6450
|
+
const shapeWeight = preserve.registerShape;
|
|
6451
|
+
const spans = plannedPhraseSpans(profile, sections, preserve.phraseLengths, draw);
|
|
6452
|
+
const phrases = spans.map((span) => {
|
|
6453
|
+
const melody = _nullishCoalesce(_optionalChain([profile, 'access', _90 => _90.form, 'access', _91 => _91.phrases, 'access', _92 => _92[span.source], 'optionalAccess', _93 => _93.melody]), () => ( null));
|
|
6454
|
+
const register = melody ? {
|
|
6455
|
+
low: Math.round(lerp(shapeWeight, mapPitch(melody.low), neutralRegister.low)),
|
|
6456
|
+
high: Math.round(lerp(shapeWeight, mapPitch(melody.high), neutralRegister.high)),
|
|
6457
|
+
mean: lerp(shapeWeight, mapPitch(melody.mean), neutralRegister.mean)
|
|
6458
|
+
} : { ...neutralRegister };
|
|
6459
|
+
return {
|
|
6460
|
+
startBeat: span.startBeat,
|
|
6461
|
+
endBeat: span.endBeat,
|
|
6462
|
+
section: sectionAt(sections, span.startBeat),
|
|
6463
|
+
cadence: span.cadence,
|
|
6464
|
+
shape: melody && shapeWeight >= SHAPE_KEEP_THRESHOLD ? melody.shape : NEUTRAL_SHAPE,
|
|
6465
|
+
peakPosition: melody ? lerp(shapeWeight, melody.peakPosition, NEUTRAL_PEAK_POSITION) : NEUTRAL_PEAK_POSITION,
|
|
6466
|
+
register,
|
|
6467
|
+
onsetDensity: melody ? melody.onsetDensity : profile.melody.rhythm.onsetDensity,
|
|
6468
|
+
motifs: []
|
|
6469
|
+
};
|
|
6470
|
+
});
|
|
6471
|
+
const graph = profile.melody.graph;
|
|
6472
|
+
const noteCount = (node) => (_nullishCoalesce(_optionalChain([profile, 'access', _94 => _94.melody, 'access', _95 => _95.motifs, 'access', _96 => _96[_nullishCoalesce(_optionalChain([graph, 'access', _97 => _97.nodes, 'access', _98 => _98[node], 'optionalAccess', _99 => _99.motif]), () => ( -1))], 'optionalAccess', _100 => _100.intervals, 'access', _101 => _101.length]), () => ( 0))) + 1;
|
|
6473
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, graph.nodes.length * phrases.length, "plan motif selection", asked.budget);
|
|
6474
|
+
const candidates = [];
|
|
6475
|
+
graph.nodes.forEach((node, index) => {
|
|
6476
|
+
const phrase = phraseHolding(phrases, node.startBeat, node.endBeat);
|
|
6477
|
+
if (phrase >= 0) {
|
|
6478
|
+
candidates.push({
|
|
6479
|
+
node: index,
|
|
6480
|
+
phrase,
|
|
6481
|
+
startBeat: node.startBeat,
|
|
6482
|
+
endBeat: node.endBeat,
|
|
6483
|
+
notes: noteCount(index)
|
|
6484
|
+
});
|
|
6485
|
+
}
|
|
6486
|
+
});
|
|
6487
|
+
const selected = scheduleMotifs(candidates, profile.meters);
|
|
6488
|
+
const selectedAt = new Map(selected.map((candidate, index) => [candidate.node, index]));
|
|
6489
|
+
const parentEdge = new Map(graph.edges.map((edge) => [edge.to, edge]));
|
|
6490
|
+
const motifs = selected.map((candidate, index) => {
|
|
6491
|
+
const { from, relation } = selectedDerivation(graph, parentEdge, selectedAt, candidate.node);
|
|
6492
|
+
const keepRelation = draw.prob(preserve.motifRelations, "motifRelations", index);
|
|
6493
|
+
const keepRhythm = from === null && draw.prob(preserve.rhythm, "rhythm", index);
|
|
6494
|
+
const cell = profile.melody.motifs[_nullishCoalesce(_optionalChain([graph, 'access', _102 => _102.nodes, 'access', _103 => _103[candidate.node], 'optionalAccess', _104 => _104.motif]), () => ( -1))];
|
|
6495
|
+
_optionalChain([phrases, 'access', _105 => _105[candidate.phrase], 'optionalAccess', _106 => _106.motifs, 'access', _107 => _107.push, 'call', _108 => _108(index)]);
|
|
6496
|
+
return {
|
|
6497
|
+
phrase: candidate.phrase,
|
|
6498
|
+
startBeat: candidate.startBeat,
|
|
6499
|
+
endBeat: candidate.endBeat,
|
|
6500
|
+
notes: candidate.notes,
|
|
6501
|
+
rhythm: keepRhythm && cell !== void 0 ? cell.rhythm.map((ratio) => ratio * cell.unitBeats) : null,
|
|
6502
|
+
from,
|
|
6503
|
+
relation: keepRelation ? relation : null
|
|
6504
|
+
};
|
|
6505
|
+
});
|
|
6506
|
+
return {
|
|
6507
|
+
planVersion: COMPOSITION_PLAN_VERSION,
|
|
6508
|
+
seed: ctx.seed,
|
|
6509
|
+
algorithmVersion: ctx.algorithmVersion,
|
|
6510
|
+
keys,
|
|
6511
|
+
meters: profile.meters.map((entry) => ({
|
|
6512
|
+
startBeat: entry.startBeat,
|
|
6513
|
+
ts: entry.ts.grouping === void 0 ? { ...entry.ts } : { ...entry.ts, grouping: [...entry.ts.grouping] }
|
|
6514
|
+
})),
|
|
6515
|
+
span: { ...profile.span },
|
|
6516
|
+
sections,
|
|
6517
|
+
phrases,
|
|
6518
|
+
harmony: plannedHarmony(profile, keys, preserve, draw),
|
|
6519
|
+
motifs,
|
|
6520
|
+
rhythm: plannedRhythm(profile, preserve.rhythm)
|
|
6521
|
+
};
|
|
6522
|
+
}
|
|
6523
|
+
|
|
6524
|
+
// src/generate/plan/evaluate.ts
|
|
6525
|
+
var PEAK_POSITION_TOLERANCE = 0.2;
|
|
6526
|
+
var OUTLINE_POINTS = 8;
|
|
6527
|
+
var HELD_NOTE_BEATS = 1;
|
|
6528
|
+
function interiorBoundaries(plan) {
|
|
6529
|
+
const beats = /* @__PURE__ */ new Set();
|
|
6530
|
+
for (const phrase of plan.phrases) {
|
|
6531
|
+
for (const beat of [phrase.startBeat, phrase.endBeat]) {
|
|
6532
|
+
if (beat > plan.span.startBeat + _chunkS5BKZZGMcjs.BEAT_EPS && beat < plan.span.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6533
|
+
beats.add(beat);
|
|
6534
|
+
}
|
|
6535
|
+
}
|
|
6536
|
+
}
|
|
6537
|
+
return [...beats].sort((a, b) => a - b);
|
|
6538
|
+
}
|
|
6539
|
+
function restsOf(melody, plan) {
|
|
6540
|
+
const rests = [];
|
|
6541
|
+
let reach = plan.span.startBeat;
|
|
6542
|
+
for (const note2 of [...melody].sort((a, b) => a.startBeat - b.startBeat)) {
|
|
6543
|
+
if (note2.startBeat > reach + _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6544
|
+
rests.push({ startBeat: reach, endBeat: note2.startBeat });
|
|
6545
|
+
}
|
|
6546
|
+
reach = Math.max(reach, note2.startBeat + note2.durationBeat);
|
|
6547
|
+
}
|
|
6548
|
+
if (plan.span.endBeat > reach + _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6549
|
+
rests.push({ startBeat: reach, endBeat: plan.span.endBeat });
|
|
6550
|
+
}
|
|
6551
|
+
return rests;
|
|
6552
|
+
}
|
|
6553
|
+
function phraseBoundaryViolations(melody, plan) {
|
|
6554
|
+
const rests = restsOf(melody, plan);
|
|
6555
|
+
const violations = [];
|
|
6556
|
+
for (const beat of interiorBoundaries(plan)) {
|
|
6557
|
+
const pulse2 = _chunkS5BKZZGMcjs.pulseBeats.call(void 0, _chunkS5BKZZGMcjs.meterAt.call(void 0, beat, plan.meters));
|
|
6558
|
+
const held = melody.some(
|
|
6559
|
+
(note2) => note2.durationBeat >= HELD_NOTE_BEATS - _chunkS5BKZZGMcjs.BEAT_EPS && Math.abs(note2.startBeat + note2.durationBeat - beat) <= pulse2 + _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6560
|
+
);
|
|
6561
|
+
const rested = rests.some(
|
|
6562
|
+
(rest) => rest.endBeat - rest.startBeat >= pulse2 - _chunkS5BKZZGMcjs.BEAT_EPS && rest.startBeat <= beat + pulse2 + _chunkS5BKZZGMcjs.BEAT_EPS && rest.endBeat >= beat - pulse2 - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6563
|
+
);
|
|
6564
|
+
if (!held && !rested) {
|
|
6565
|
+
violations.push({
|
|
6566
|
+
kind: "phraseBoundary",
|
|
6567
|
+
severity: "error",
|
|
6568
|
+
atBeat: beat,
|
|
6569
|
+
expected: `a note of at least ${HELD_NOTE_BEATS} beat(s) ending, or a rest of at least ${pulse2} beat(s), within ${pulse2} beat(s)`,
|
|
6570
|
+
actual: "neither",
|
|
6571
|
+
rationale: `the plan places a phrase boundary at beat ${beat}, which the candidate does not mark`
|
|
6572
|
+
});
|
|
6573
|
+
}
|
|
6574
|
+
}
|
|
6575
|
+
return violations;
|
|
6576
|
+
}
|
|
6577
|
+
function spanViolation(melody, plan) {
|
|
6578
|
+
const end = melody.reduce((max, note2) => Math.max(max, note2.startBeat + note2.durationBeat), 0);
|
|
6579
|
+
if (end <= plan.span.endBeat + _chunkS5BKZZGMcjs.BEAT_EPS) {
|
|
6580
|
+
return [];
|
|
6581
|
+
}
|
|
6582
|
+
return [
|
|
6583
|
+
{
|
|
6584
|
+
kind: "span",
|
|
6585
|
+
severity: "error",
|
|
6586
|
+
atBeat: plan.span.endBeat,
|
|
6587
|
+
expected: `ending by beat ${plan.span.endBeat}`,
|
|
6588
|
+
actual: `ending at beat ${end}`,
|
|
6589
|
+
rationale: "the candidate's last note runs past the plan's span"
|
|
6590
|
+
}
|
|
6591
|
+
];
|
|
6592
|
+
}
|
|
6593
|
+
function phraseLines(melody, plan) {
|
|
6594
|
+
return plan.phrases.map(
|
|
6595
|
+
(phrase) => melody.flatMap(
|
|
6596
|
+
(note2, index) => note2.startBeat >= phrase.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && note2.startBeat < phrase.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS ? [index] : []
|
|
6597
|
+
)
|
|
6598
|
+
);
|
|
6599
|
+
}
|
|
6600
|
+
function cadenceViolations(melody, plan, timeline, lines) {
|
|
6601
|
+
const violations = [];
|
|
6602
|
+
plan.phrases.forEach((phrase, index) => {
|
|
6603
|
+
if (phrase.cadence === null) {
|
|
6604
|
+
return;
|
|
6605
|
+
}
|
|
6606
|
+
const last = _optionalChain([lines, 'access', _109 => _109[index], 'optionalAccess', _110 => _110.at, 'call', _111 => _111(-1)]);
|
|
6607
|
+
const note2 = last === void 0 ? void 0 : melody[last];
|
|
6608
|
+
const allowed = note2 === void 0 ? [] : cadencePitchClasses(plan, timeline, phrase.cadence, note2.startBeat);
|
|
6609
|
+
if (note2 !== void 0 && (allowed === null || allowed.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, note2.pitch)))) {
|
|
6610
|
+
return;
|
|
6611
|
+
}
|
|
6612
|
+
violations.push({
|
|
6613
|
+
kind: "cadence",
|
|
6614
|
+
severity: "error",
|
|
6615
|
+
atBeat: phrase.endBeat,
|
|
6616
|
+
expected: `a closing note on pitch class ${(_nullishCoalesce(allowed, () => ( []))).join(" or ")} for a ${phrase.cadence} cadence`,
|
|
6617
|
+
actual: note2 === void 0 ? "no note" : `pitch ${note2.pitch}`,
|
|
6618
|
+
rationale: `the phrase ending at beat ${phrase.endBeat} is planned to close on a ${phrase.cadence} cadence`
|
|
6619
|
+
});
|
|
6620
|
+
});
|
|
6621
|
+
return violations;
|
|
6622
|
+
}
|
|
6623
|
+
function harmonyViolations(melody, plan, timeline, lines) {
|
|
6624
|
+
const misfits = planHarmonyMisfits(plan, timeline);
|
|
6625
|
+
const violations = [];
|
|
6626
|
+
for (const line of lines) {
|
|
6627
|
+
const read = misfits(line.map((index) => melody[index]));
|
|
6628
|
+
read.forEach((kinds, at2) => {
|
|
6629
|
+
if (kinds === null) {
|
|
6630
|
+
return;
|
|
6631
|
+
}
|
|
6632
|
+
const note2 = melody[line[at2]];
|
|
6633
|
+
const derived = plan.motifs.some(
|
|
6634
|
+
(motif) => motif.from !== null && note2.startBeat >= motif.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && note2.startBeat < motif.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6635
|
+
);
|
|
6636
|
+
const strong = positionClass(note2.startBeat, plan.meters) === "strong";
|
|
6637
|
+
violations.push({
|
|
6638
|
+
kind: "harmony",
|
|
6639
|
+
severity: derived ? "warning" : "error",
|
|
6640
|
+
atBeat: note2.startBeat,
|
|
6641
|
+
expected: strong ? "a chord tone or an ornamental tone" : "a chord tone, an ornamental tone, or a scale tone",
|
|
6642
|
+
actual: kinds.length === 0 ? "no harmonic label" : kinds.join(", "),
|
|
6643
|
+
rationale: derived ? `the note at beat ${note2.startBeat} sits in a derived statement, whose transformation takes precedence over the harmony` : `the note at beat ${note2.startBeat} does not fit the planned harmony`
|
|
6644
|
+
});
|
|
6645
|
+
});
|
|
6646
|
+
}
|
|
6647
|
+
return violations;
|
|
6648
|
+
}
|
|
6649
|
+
function notesInRange(melody, startBeat, endBeat) {
|
|
6650
|
+
return melody.filter(
|
|
6651
|
+
(note2) => note2.startBeat >= startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && note2.startBeat < endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6652
|
+
);
|
|
6653
|
+
}
|
|
6654
|
+
function replayLevel(source, derived, statement, sourceEnd, plan, key, closing) {
|
|
6655
|
+
const relation = statement.relation;
|
|
6656
|
+
const planned = relation.kind === "tonalTransposition" ? _nullishCoalesce(relation.degrees, () => ( 0)) : relation.semitones;
|
|
6657
|
+
const { low, high } = plan.phrases[statement.phrase].register;
|
|
6658
|
+
const outside = (pitch) => pitch < low || pitch > high;
|
|
6659
|
+
const backward = relation.kind === "retrograde" || relation.kind === "retrogradeInversion";
|
|
6660
|
+
const cell = clipStatement(
|
|
6661
|
+
source.map((note2) => ({
|
|
6662
|
+
pitch: note2.pitch,
|
|
6663
|
+
startBeat: note2.startBeat,
|
|
6664
|
+
durationBeat: note2.durationBeat
|
|
6665
|
+
})),
|
|
6666
|
+
sourceEnd
|
|
6667
|
+
);
|
|
6668
|
+
const replays = relationLevels(relation.kind).map((level) => {
|
|
6669
|
+
const notes = clipStatement(
|
|
6670
|
+
replayAt(cell, relation, level, statement.startBeat, key),
|
|
6671
|
+
statement.endBeat
|
|
6672
|
+
);
|
|
6673
|
+
return { level, notes, outside: notes.filter((note2) => outside(note2.pitch)).length };
|
|
6674
|
+
});
|
|
6675
|
+
const fewestOutside = Math.min(...replays.map((replay) => replay.outside));
|
|
6676
|
+
let best = null;
|
|
6677
|
+
for (const { level, notes: expected, outside: away } of replays) {
|
|
6678
|
+
if (expected.length !== derived.length) {
|
|
6679
|
+
continue;
|
|
6680
|
+
}
|
|
6681
|
+
let forced = 0;
|
|
6682
|
+
let holds = true;
|
|
6683
|
+
for (let i = 0; holds && i < expected.length; i += 1) {
|
|
6684
|
+
const want = expected[i];
|
|
6685
|
+
const got = derived[i];
|
|
6686
|
+
if (i > 0) {
|
|
6687
|
+
const gap = got.startBeat - derived[i - 1].startBeat;
|
|
6688
|
+
holds = Math.abs(gap - (want.startBeat - expected[i - 1].startBeat)) <= _chunkS5BKZZGMcjs.BEAT_EPS;
|
|
6689
|
+
}
|
|
6690
|
+
if (!holds || got.pitch === want.pitch) {
|
|
6691
|
+
continue;
|
|
6692
|
+
}
|
|
6693
|
+
const origin = source[backward ? cell.length - 1 - i : i];
|
|
6694
|
+
forced += 1;
|
|
6695
|
+
holds = closing.has(got) || origin !== void 0 && closing.has(origin) || away === fewestOutside && outside(want.pitch);
|
|
6696
|
+
}
|
|
6697
|
+
const distance = Math.abs(level - planned);
|
|
6698
|
+
const nearer = best === null || distance < Math.abs(best.level - planned) || distance === Math.abs(best.level - planned) && level < best.level;
|
|
6699
|
+
if (holds && nearer) {
|
|
6700
|
+
best = { level, forced };
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
return best;
|
|
6704
|
+
}
|
|
6705
|
+
function motifDerivationViolations(melody, plan, closing) {
|
|
6706
|
+
const keyAt = planKeyAt(plan);
|
|
6707
|
+
const errors = [];
|
|
6708
|
+
const warnings = [];
|
|
6709
|
+
for (const statement of plan.motifs) {
|
|
6710
|
+
if (statement.from === null) {
|
|
6711
|
+
continue;
|
|
6712
|
+
}
|
|
6713
|
+
const source = plan.motifs[statement.from];
|
|
6714
|
+
const sourceNotes = notesInRange(melody, source.startBeat, source.endBeat);
|
|
6715
|
+
const derivedNotes = notesInRange(melody, statement.startBeat, statement.endBeat);
|
|
6716
|
+
const relation = statement.relation;
|
|
6717
|
+
const rationale = `the statement at beat ${statement.startBeat} does not derive from its source the way the plan names`;
|
|
6718
|
+
if (sourceNotes.length === 0 || derivedNotes.length === 0) {
|
|
6719
|
+
errors.push({
|
|
6720
|
+
kind: "motifDerivation",
|
|
6721
|
+
severity: "error",
|
|
6722
|
+
atBeat: statement.startBeat,
|
|
6723
|
+
expected: relation === null ? "a variation" : relation.kind,
|
|
6724
|
+
actual: "no notes to compare",
|
|
6725
|
+
rationale
|
|
6726
|
+
});
|
|
6727
|
+
continue;
|
|
6728
|
+
}
|
|
6729
|
+
if (relation === null) {
|
|
6730
|
+
const similarity = _chunkIFZDWIKMcjs.melodicSimilarity.call(void 0, sourceNotes, derivedNotes);
|
|
6731
|
+
if (similarity < _chunkIFZDWIKMcjs.DEFAULT_VARIATION_THRESHOLD) {
|
|
6732
|
+
errors.push({
|
|
6733
|
+
kind: "motifDerivation",
|
|
6734
|
+
severity: "error",
|
|
6735
|
+
atBeat: statement.startBeat,
|
|
6736
|
+
expected: `a variation (melodicSimilarity >= ${_chunkIFZDWIKMcjs.DEFAULT_VARIATION_THRESHOLD})`,
|
|
6737
|
+
actual: `melodicSimilarity ${similarity.toFixed(3)}`,
|
|
6738
|
+
rationale
|
|
6739
|
+
});
|
|
6740
|
+
}
|
|
6741
|
+
continue;
|
|
6742
|
+
}
|
|
6743
|
+
const replay = replayLevel(
|
|
6744
|
+
sourceNotes,
|
|
6745
|
+
derivedNotes,
|
|
6746
|
+
statement,
|
|
6747
|
+
source.endBeat,
|
|
6748
|
+
plan,
|
|
6749
|
+
_chunk3R3QVKY5cjs.scaleOf.call(void 0, keyAt(statement.startBeat)),
|
|
6750
|
+
closing
|
|
6751
|
+
);
|
|
6752
|
+
const planned = relation.kind === "tonalTransposition" ? _nullishCoalesce(relation.degrees, () => ( 0)) : relation.semitones;
|
|
6753
|
+
if (replay === null) {
|
|
6754
|
+
errors.push({
|
|
6755
|
+
kind: "motifDerivation",
|
|
6756
|
+
severity: "error",
|
|
6757
|
+
atBeat: statement.startBeat,
|
|
6758
|
+
expected: relation.kind,
|
|
6759
|
+
actual: "no pitch level replays the source",
|
|
6760
|
+
rationale
|
|
6761
|
+
});
|
|
6762
|
+
} else if (replay.level !== planned || replay.forced > 0) {
|
|
6763
|
+
warnings.push({
|
|
6764
|
+
kind: "motifDisplaced",
|
|
6765
|
+
severity: "warning",
|
|
6766
|
+
atBeat: statement.startBeat,
|
|
6767
|
+
expected: `${relation.kind} at level ${planned} with every pitch replayed`,
|
|
6768
|
+
actual: `level ${replay.level}, ${replay.forced} excused note(s)`,
|
|
6769
|
+
rationale: `the statement at beat ${statement.startBeat} carries out its planned derivation at another pitch level or with notes excused`
|
|
6770
|
+
});
|
|
6771
|
+
}
|
|
6772
|
+
}
|
|
6773
|
+
return { errors, warnings };
|
|
6774
|
+
}
|
|
6775
|
+
function phraseAt(plan, beat) {
|
|
6776
|
+
return plan.phrases.find(
|
|
6777
|
+
(phrase) => beat >= phrase.startBeat - _chunkS5BKZZGMcjs.BEAT_EPS && beat < phrase.endBeat - _chunkS5BKZZGMcjs.BEAT_EPS
|
|
6778
|
+
);
|
|
6779
|
+
}
|
|
6780
|
+
function registerViolations(melody, plan) {
|
|
6781
|
+
const violations = [];
|
|
6782
|
+
for (const note2 of melody) {
|
|
6783
|
+
const phrase = phraseAt(plan, note2.startBeat);
|
|
6784
|
+
if (phrase === void 0) {
|
|
6785
|
+
continue;
|
|
6786
|
+
}
|
|
6787
|
+
if (note2.pitch < phrase.register.low || note2.pitch > phrase.register.high) {
|
|
6788
|
+
violations.push({
|
|
6789
|
+
kind: "register",
|
|
6790
|
+
severity: "error",
|
|
6791
|
+
atBeat: note2.startBeat,
|
|
6792
|
+
expected: `a pitch within [${phrase.register.low}, ${phrase.register.high}]`,
|
|
6793
|
+
actual: `pitch ${note2.pitch}`,
|
|
6794
|
+
rationale: `the note at beat ${note2.startBeat} falls outside its phrase's planned register`
|
|
6795
|
+
});
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
6798
|
+
return violations;
|
|
6799
|
+
}
|
|
6800
|
+
function planOutline(phrase) {
|
|
6801
|
+
const amplitude = (phrase.register.high - phrase.register.low) / 2;
|
|
6802
|
+
const outline = [];
|
|
6803
|
+
for (let k = 0; k < OUTLINE_POINTS; k += 1) {
|
|
6804
|
+
const t = (k + 0.5) / OUTLINE_POINTS;
|
|
6805
|
+
outline.push(
|
|
6806
|
+
phrase.register.mean + plannedContourAt(phrase.shape, phrase.peakPosition, t) * amplitude
|
|
6807
|
+
);
|
|
6808
|
+
}
|
|
6809
|
+
return outline;
|
|
6810
|
+
}
|
|
6811
|
+
function planContourPhrase(phrase) {
|
|
6812
|
+
return {
|
|
6813
|
+
shape: phrase.shape,
|
|
6814
|
+
low: phrase.register.low,
|
|
6815
|
+
high: phrase.register.high,
|
|
6816
|
+
outline: planOutline(phrase)
|
|
6817
|
+
};
|
|
6818
|
+
}
|
|
6819
|
+
function planRegisterPlan(plan) {
|
|
6820
|
+
const phrases = plan.phrases.map((phrase) => ({
|
|
6821
|
+
low: phrase.register.low,
|
|
6822
|
+
high: phrase.register.high,
|
|
6823
|
+
mean: phrase.register.mean,
|
|
6824
|
+
peakPosition: phrase.peakPosition
|
|
6825
|
+
}));
|
|
6826
|
+
let weighted = 0;
|
|
6827
|
+
let weight = 0;
|
|
6828
|
+
for (const phrase of plan.phrases) {
|
|
6829
|
+
const length = phrase.endBeat - phrase.startBeat;
|
|
6830
|
+
weighted += phrase.register.mean * length;
|
|
6831
|
+
weight += length;
|
|
6832
|
+
}
|
|
6833
|
+
return { phrases, mean: weight > 0 ? weighted / weight : null };
|
|
6834
|
+
}
|
|
6835
|
+
function planRhythmReading(plan) {
|
|
6836
|
+
const hasOnsets = plan.rhythm.onsetLevels.some((share) => share > 0);
|
|
6837
|
+
return {
|
|
6838
|
+
onsets: hasOnsets ? 1 : 0,
|
|
6839
|
+
onsetLevels: plan.rhythm.onsetLevels,
|
|
6840
|
+
barPositions: [],
|
|
6841
|
+
interOnsetShares: plan.rhythm.interOnsetShares,
|
|
6842
|
+
syncopation: plan.rhythm.syncopation
|
|
6843
|
+
};
|
|
6844
|
+
}
|
|
6845
|
+
function peakPositionWarnings(plan, readings) {
|
|
6846
|
+
const violations = [];
|
|
6847
|
+
plan.phrases.forEach((phrase, index) => {
|
|
6848
|
+
const reading = readings[index];
|
|
6849
|
+
if (reading == null) {
|
|
6850
|
+
return;
|
|
6851
|
+
}
|
|
6852
|
+
const drift = Math.abs(reading.peakPosition - phrase.peakPosition);
|
|
6853
|
+
if (drift > PEAK_POSITION_TOLERANCE) {
|
|
6854
|
+
violations.push({
|
|
6855
|
+
kind: "peakPosition",
|
|
6856
|
+
severity: "warning",
|
|
6857
|
+
atBeat: phrase.startBeat,
|
|
6858
|
+
expected: `a peak position within ${PEAK_POSITION_TOLERANCE} of ${phrase.peakPosition}`,
|
|
6859
|
+
actual: `${reading.peakPosition}`,
|
|
6860
|
+
rationale: `the phrase starting at beat ${phrase.startBeat} places its melodic peak further from the planned position than the tolerance allows`
|
|
6861
|
+
});
|
|
6862
|
+
}
|
|
6863
|
+
});
|
|
6864
|
+
return violations;
|
|
6865
|
+
}
|
|
6866
|
+
function lineMeanOf(melody) {
|
|
6867
|
+
let weighted = 0;
|
|
6868
|
+
let total = 0;
|
|
6869
|
+
for (const note2 of melody) {
|
|
6870
|
+
weighted += note2.pitch * note2.durationBeat;
|
|
6871
|
+
total += note2.durationBeat;
|
|
6872
|
+
}
|
|
6873
|
+
return total > 0 ? weighted / total : null;
|
|
6874
|
+
}
|
|
6875
|
+
function planDensity(plan) {
|
|
6876
|
+
let weighted = 0;
|
|
6877
|
+
let bars = 0;
|
|
6878
|
+
for (const phrase of plan.phrases) {
|
|
6879
|
+
const span = _chunkIFZDWIKMcjs.barSpanOf.call(void 0, phrase.startBeat, phrase.endBeat, plan.meters);
|
|
6880
|
+
weighted += phrase.onsetDensity * span;
|
|
6881
|
+
bars += span;
|
|
6882
|
+
}
|
|
6883
|
+
return { onsets: 1, onsetDensity: bars > 0 ? weighted / bars : 0 };
|
|
6884
|
+
}
|
|
6885
|
+
function evaluateComposition(melody, plan, opts) {
|
|
6886
|
+
assertCompositionPlan(plan, "evaluated plan");
|
|
6887
|
+
const { budget } = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "evaluate options");
|
|
6888
|
+
const notes = [
|
|
6889
|
+
..._chunkS5BKZZGMcjs.assertNoteEvents.call(void 0, melody, "evaluated melody", { budget, allowNonPositiveDuration: true })
|
|
6890
|
+
].sort((a, b) => a.startBeat - b.startBeat);
|
|
6891
|
+
const timeline = planChordTimeline(plan);
|
|
6892
|
+
const lines = phraseLines(notes, plan);
|
|
6893
|
+
const closing = new Set(
|
|
6894
|
+
lines.flatMap((line) => line.length === 0 ? [] : [notes[line.at(-1)]])
|
|
6895
|
+
);
|
|
6896
|
+
const derivations = motifDerivationViolations(notes, plan, closing);
|
|
6897
|
+
const lineMean = lineMeanOf(notes);
|
|
6898
|
+
const readings = plan.phrases.map(
|
|
6899
|
+
(phrase) => _chunkIFZDWIKMcjs.phraseMelody.call(void 0, notes, phrase.startBeat, phrase.endBeat, _nullishCoalesce(lineMean, () => ( 0)), plan.meters, budget)
|
|
6900
|
+
);
|
|
6901
|
+
const violations = [
|
|
6902
|
+
...spanViolation(notes, plan),
|
|
6903
|
+
...phraseBoundaryViolations(notes, plan),
|
|
6904
|
+
...cadenceViolations(notes, plan, timeline, lines),
|
|
6905
|
+
...harmonyViolations(notes, plan, timeline, lines),
|
|
6906
|
+
...registerViolations(notes, plan),
|
|
6907
|
+
...derivations.errors,
|
|
6908
|
+
...derivations.warnings,
|
|
6909
|
+
...peakPositionWarnings(plan, readings)
|
|
6910
|
+
];
|
|
6911
|
+
const rhythm = _chunkIFZDWIKMcjs.analyzeRhythm.call(void 0, notes, {
|
|
6912
|
+
meters: plan.meters,
|
|
6913
|
+
totalBeats: plan.span.endBeat,
|
|
6914
|
+
budget
|
|
6915
|
+
});
|
|
6916
|
+
const target = planRhythmReading(plan);
|
|
6917
|
+
const fit = {
|
|
6918
|
+
contour: _chunkIFZDWIKMcjs.contourSimilarity.call(void 0, plan.phrases.map(planContourPhrase), readings),
|
|
6919
|
+
register: _chunkIFZDWIKMcjs.registerSimilarity.call(void 0, planRegisterPlan(plan), { phrases: readings, mean: lineMean }),
|
|
6920
|
+
onset: _chunkIFZDWIKMcjs.onsetSimilarity.call(void 0, target, rhythm),
|
|
6921
|
+
duration: _chunkIFZDWIKMcjs.durationSimilarity.call(void 0, target, rhythm),
|
|
6922
|
+
syncopation: _chunkIFZDWIKMcjs.syncopationSimilarity.call(void 0, target, rhythm),
|
|
6923
|
+
density: _chunkIFZDWIKMcjs.densitySimilarity.call(void 0, planDensity(plan), rhythm)
|
|
6924
|
+
};
|
|
6925
|
+
return { violations, fit };
|
|
6926
|
+
}
|
|
6927
|
+
|
|
4964
6928
|
// src/generate/progression/index.ts
|
|
4965
6929
|
var DEFAULT_TS6 = { numerator: 4, denominator: 4 };
|
|
4966
6930
|
var PROG_STYLES = Object.freeze(["minimal", "dance", "idol", "rock"]);
|
|
@@ -5147,12 +7111,12 @@ function progressions() {
|
|
|
5147
7111
|
return PRESETS.map((p) => ({ ...p, degrees: [...p.degrees], styles: [...p.styles] }));
|
|
5148
7112
|
}
|
|
5149
7113
|
function progressionsByStyle(style) {
|
|
5150
|
-
const named =
|
|
7114
|
+
const named = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, style, PROG_STYLES, "style");
|
|
5151
7115
|
return progressions().filter((p) => p.styles.includes(named));
|
|
5152
7116
|
}
|
|
5153
7117
|
function degreeToRootPc(degree, key) {
|
|
5154
7118
|
if (degree >= 1 && degree <= 7) {
|
|
5155
|
-
const tones =
|
|
7119
|
+
const tones = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, _chunk3R3QVKY5cjs.heptatonicFrameOf.call(void 0, key));
|
|
5156
7120
|
return _nullishCoalesce(tones[degree - 1], () => ( key.rootPc % 12));
|
|
5157
7121
|
}
|
|
5158
7122
|
const offset = _nullishCoalesce(BORROWED_OFFSET[degree], () => ( 0));
|
|
@@ -5160,10 +7124,10 @@ function degreeToRootPc(degree, key) {
|
|
|
5160
7124
|
}
|
|
5161
7125
|
function autoQuality(degree, key, harmonicDominant) {
|
|
5162
7126
|
if (degree >= 1 && degree <= 7) {
|
|
5163
|
-
if (harmonicDominant &&
|
|
7127
|
+
if (harmonicDominant && _chunkIFZDWIKMcjs.isMinorKey.call(void 0, key) && degree === 5) {
|
|
5164
7128
|
return "maj";
|
|
5165
7129
|
}
|
|
5166
|
-
return
|
|
7130
|
+
return _chunk3R3QVKY5cjs.diatonicTriad.call(void 0, degree, _chunk3R3QVKY5cjs.heptatonicFrameOf.call(void 0, key)).quality;
|
|
5167
7131
|
}
|
|
5168
7132
|
if (degree === 14) {
|
|
5169
7133
|
return "dim";
|
|
@@ -5192,39 +7156,39 @@ function pickProgressionPreset(style, ctx = 0) {
|
|
|
5192
7156
|
function presetFor(style, ctx) {
|
|
5193
7157
|
const pool = PRESETS.filter((preset) => preset.styles.includes(style));
|
|
5194
7158
|
if (pool.length === 0) {
|
|
5195
|
-
throw new (0,
|
|
7159
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unknown progression style: ${style}`);
|
|
5196
7160
|
}
|
|
5197
7161
|
const index = ctx.part("progression").range(0, pool.length - 1, "preset");
|
|
5198
7162
|
return _nullishCoalesce(pool[index], () => ( PRESETS[0]));
|
|
5199
7163
|
}
|
|
5200
7164
|
function tonicizableRootPcs(key) {
|
|
5201
|
-
return new Set(
|
|
7165
|
+
return new Set(_chunk3R3QVKY5cjs.tonicizableDegrees.call(void 0, key).map((degree) => degree.rootPc));
|
|
5202
7166
|
}
|
|
5203
7167
|
function canBeTonicized(span, tonicizable) {
|
|
5204
7168
|
if (!tonicizable.has(span.rootPc)) {
|
|
5205
7169
|
return false;
|
|
5206
7170
|
}
|
|
5207
|
-
return
|
|
7171
|
+
return _chunk3R3QVKY5cjs.fifthPcOf.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, span.rootPc, span.quality)) === (span.rootPc + 7) % 12;
|
|
5208
7172
|
}
|
|
5209
7173
|
function generateProgression(opts) {
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
const key =
|
|
7174
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, opts, "progression options");
|
|
7175
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, opts.bars, "progression bars");
|
|
7176
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, opts.bars, "progression chords");
|
|
7177
|
+
const key = _chunk3R3QVKY5cjs.toKeyScale.call(void 0, opts.key);
|
|
5214
7178
|
const ctx = resolveContext(opts.ctx);
|
|
5215
7179
|
let preset;
|
|
5216
7180
|
if (opts.preset !== void 0) {
|
|
5217
7181
|
if (opts.preset.degrees.length === 0) {
|
|
5218
|
-
throw new (0,
|
|
7182
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("progression preset must name at least one degree");
|
|
5219
7183
|
}
|
|
5220
7184
|
preset = {
|
|
5221
7185
|
id: _nullishCoalesce(opts.preset.id, () => ( "custom")),
|
|
5222
7186
|
name: _nullishCoalesce(opts.preset.name, () => ( "Custom")),
|
|
5223
7187
|
degrees: opts.preset.degrees.map((degree, index) => {
|
|
5224
|
-
|
|
7188
|
+
_chunkS5BKZZGMcjs.assertDegree.call(void 0, degree, `progression preset degrees[${index}]`);
|
|
5225
7189
|
const supported = degree >= 1 && degree <= 7 || Object.values(BORROWED_DEGREES).includes(degree);
|
|
5226
7190
|
if (!supported) {
|
|
5227
|
-
throw new (0,
|
|
7191
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
5228
7192
|
`progression preset degrees[${index}] is not a supported progression degree; received ${degree}`
|
|
5229
7193
|
);
|
|
5230
7194
|
}
|
|
@@ -5237,27 +7201,27 @@ function generateProgression(opts) {
|
|
|
5237
7201
|
if (preset === void 0 && opts.presetId !== void 0) {
|
|
5238
7202
|
preset = PRESETS.find((p) => p.id === opts.presetId);
|
|
5239
7203
|
if (preset === void 0) {
|
|
5240
|
-
throw new (0,
|
|
7204
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unknown progression preset: ${opts.presetId}`);
|
|
5241
7205
|
}
|
|
5242
7206
|
}
|
|
5243
7207
|
preset ??= presetFor(opts.style, ctx);
|
|
5244
|
-
const ext = opts.ext === void 0 ? "auto" :
|
|
7208
|
+
const ext = opts.ext === void 0 ? "auto" : _chunkS5BKZZGMcjs.assertOneOf.call(void 0, opts.ext, ["auto", ..._chunk3R3QVKY5cjs.chordQualities.call(void 0, )], "progression extension");
|
|
5245
7209
|
const cycle = resolveCycle(
|
|
5246
|
-
_nullishCoalesce(_optionalChain([preset, 'optionalAccess',
|
|
7210
|
+
_nullishCoalesce(_optionalChain([preset, 'optionalAccess', _112 => _112.degrees]), () => ( [0])),
|
|
5247
7211
|
key,
|
|
5248
7212
|
ext,
|
|
5249
|
-
_optionalChain([preset, 'optionalAccess',
|
|
7213
|
+
_optionalChain([preset, 'optionalAccess', _113 => _113.functional]) === "cadenceStrong"
|
|
5250
7214
|
);
|
|
5251
|
-
const barBeats =
|
|
7215
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, _nullishCoalesce(opts.ts, () => ( DEFAULT_TS6)));
|
|
5252
7216
|
const chords = [];
|
|
5253
7217
|
for (let bar2 = 0; bar2 < opts.bars; bar2 += 1) {
|
|
5254
7218
|
const step = cycle[bar2 % cycle.length];
|
|
5255
7219
|
const chord = {
|
|
5256
|
-
rootPc: _nullishCoalesce(_optionalChain([step, 'optionalAccess',
|
|
5257
|
-
quality: _nullishCoalesce(_optionalChain([step, 'optionalAccess',
|
|
7220
|
+
rootPc: _nullishCoalesce(_optionalChain([step, 'optionalAccess', _114 => _114.rootPc]), () => ( 0)),
|
|
7221
|
+
quality: _nullishCoalesce(_optionalChain([step, 'optionalAccess', _115 => _115.quality]), () => ( "maj")),
|
|
5258
7222
|
startBeat: bar2 * barBeats
|
|
5259
7223
|
};
|
|
5260
|
-
if (_optionalChain([step, 'optionalAccess',
|
|
7224
|
+
if (_optionalChain([step, 'optionalAccess', _116 => _116.degree]) !== void 0) {
|
|
5261
7225
|
chord.degree = step.degree;
|
|
5262
7226
|
}
|
|
5263
7227
|
chords.push(chord);
|
|
@@ -5278,7 +7242,7 @@ function generateProgression(opts) {
|
|
|
5278
7242
|
const targetsTonic = (next.rootPc - tonicPc + 12) % 12 === 0;
|
|
5279
7243
|
const isLastTonicStatement = cur.rootPc === tonicPc && tonicStatements <= 1;
|
|
5280
7244
|
const alreadySecondary = cur.rootPc === domRoot && cur.quality === "dom7";
|
|
5281
|
-
const isResolutionTarget = _optionalChain([chords, 'access',
|
|
7245
|
+
const isResolutionTarget = _optionalChain([chords, 'access', _117 => _117[i - 1], 'optionalAccess', _118 => _118.secondaryDominant]) === true;
|
|
5282
7246
|
const takesNoDominant = !canBeTonicized(next, tonicizable);
|
|
5283
7247
|
if (targetsTonic || isLastTonicStatement || alreadySecondary || isResolutionTarget || takesNoDominant) {
|
|
5284
7248
|
continue;
|
|
@@ -5305,7 +7269,7 @@ function commonToneCount(a, b) {
|
|
|
5305
7269
|
return a.filter((pc) => set.has(pc)).length;
|
|
5306
7270
|
}
|
|
5307
7271
|
function triadQualityOf(chord) {
|
|
5308
|
-
const semis = new Set(chord.intervals.map((interval) =>
|
|
7272
|
+
const semis = new Set(chord.intervals.map((interval) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval)));
|
|
5309
7273
|
const hasThird = semis.has(4) ? "maj" : semis.has(3) ? "min" : void 0;
|
|
5310
7274
|
if (hasThird === void 0) {
|
|
5311
7275
|
return chord.quality;
|
|
@@ -5319,15 +7283,15 @@ function triadQualityOf(chord) {
|
|
|
5319
7283
|
return hasThird;
|
|
5320
7284
|
}
|
|
5321
7285
|
function diatonicTriadsOf(key) {
|
|
5322
|
-
const degrees =
|
|
7286
|
+
const degrees = _chunk3R3QVKY5cjs.scaleTonesInDegreeOrder.call(void 0, key).length;
|
|
5323
7287
|
const triads = [];
|
|
5324
7288
|
for (let degree = 1; degree <= degrees; degree += 1) {
|
|
5325
|
-
triads.push(
|
|
7289
|
+
triads.push(_chunk3R3QVKY5cjs.diatonicTriad.call(void 0, degree, key));
|
|
5326
7290
|
}
|
|
5327
7291
|
return triads;
|
|
5328
7292
|
}
|
|
5329
7293
|
function sameChord(a, b) {
|
|
5330
|
-
return
|
|
7294
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, a.rootPc) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, b.rootPc) && a.quality === b.quality;
|
|
5331
7295
|
}
|
|
5332
7296
|
var THIRD_OFFSETS = [3, 4, 8, 9];
|
|
5333
7297
|
var MAX_HINT_ALTER = 2;
|
|
@@ -5335,75 +7299,75 @@ function bareSpelling(note2) {
|
|
|
5335
7299
|
return { letter: note2.letter, alter: note2.alter };
|
|
5336
7300
|
}
|
|
5337
7301
|
function spelledOnRoot(chord, root, tonic, key) {
|
|
5338
|
-
const usable =
|
|
7302
|
+
const usable = _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, root) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc) && Math.abs(root.alter) <= MAX_HINT_ALTER;
|
|
5339
7303
|
const spelled = {
|
|
5340
7304
|
...chord,
|
|
5341
|
-
rootSpelling: bareSpelling(usable ? root :
|
|
7305
|
+
rootSpelling: bareSpelling(usable ? root : _chunk3R3QVKY5cjs.spellPitchClass.call(void 0, chord.rootPc, tonic, key))
|
|
5342
7306
|
};
|
|
5343
7307
|
if (chord.bassPc !== void 0) {
|
|
5344
|
-
spelled.bassSpelling = bareSpelling(
|
|
7308
|
+
spelled.bassSpelling = bareSpelling(_chunk3R3QVKY5cjs.spellPitchClass.call(void 0, chord.bassPc, tonic, key));
|
|
5345
7309
|
}
|
|
5346
7310
|
return spelled;
|
|
5347
7311
|
}
|
|
5348
7312
|
function spelledInKey(chord, tonic, key) {
|
|
5349
|
-
return spelledOnRoot(chord,
|
|
7313
|
+
return spelledOnRoot(chord, _chunk3R3QVKY5cjs.spellPitchClass.call(void 0, chord.rootPc, tonic, key), tonic, key);
|
|
5350
7314
|
}
|
|
5351
7315
|
function tritoneSubstituteRoot(dominant, tonic, key) {
|
|
5352
|
-
const substituteRootPc =
|
|
5353
|
-
if (
|
|
5354
|
-
return
|
|
7316
|
+
const substituteRootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, dominant.rootPc + 6);
|
|
7317
|
+
if (_chunk3R3QVKY5cjs.isScaleTone.call(void 0, substituteRootPc, key)) {
|
|
7318
|
+
return _chunk3R3QVKY5cjs.spellPitchClass.call(void 0, substituteRootPc, tonic, key);
|
|
5355
7319
|
}
|
|
5356
|
-
const resolution =
|
|
5357
|
-
return
|
|
7320
|
+
const resolution = _chunk3R3QVKY5cjs.spellPitchClass.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, dominant.rootPc + 5), tonic, key);
|
|
7321
|
+
return _chunkS5BKZZGMcjs.transposeNote.call(void 0, resolution, 1);
|
|
5358
7322
|
}
|
|
5359
7323
|
function substituteChord(chord, key, opts) {
|
|
5360
|
-
|
|
5361
|
-
const source =
|
|
5362
|
-
const { scale, tonic } =
|
|
5363
|
-
const originalTriad =
|
|
7324
|
+
_chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
7325
|
+
const source = _chunk3R3QVKY5cjs.toChordData.call(void 0, chord);
|
|
7326
|
+
const { scale, tonic } = _chunk3R3QVKY5cjs.resolveKey.call(void 0, key);
|
|
7327
|
+
const originalTriad = _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, _chunk3R3QVKY5cjs.makeChord.call(void 0, source.rootPc, triadQualityOf(source)));
|
|
5364
7328
|
const candidates = [];
|
|
5365
|
-
if (
|
|
5366
|
-
const substitute =
|
|
7329
|
+
if (_chunk3R3QVKY5cjs.soundsDominantSeventh.call(void 0, source)) {
|
|
7330
|
+
const substitute = _chunk3R3QVKY5cjs.makeChord.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, source.rootPc + 6), "dom7");
|
|
5367
7331
|
candidates.push({
|
|
5368
7332
|
chord: spelledOnRoot(substitute, tritoneSubstituteRoot(source, tonic, scale), tonic, scale),
|
|
5369
7333
|
type: "tritone"
|
|
5370
7334
|
});
|
|
5371
7335
|
}
|
|
5372
7336
|
for (const triad of diatonicTriadsOf(scale)) {
|
|
5373
|
-
const offset =
|
|
5374
|
-
if (THIRD_OFFSETS.includes(offset) && commonToneCount(originalTriad,
|
|
7337
|
+
const offset = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, triad.rootPc - source.rootPc);
|
|
7338
|
+
if (THIRD_OFFSETS.includes(offset) && commonToneCount(originalTriad, _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, triad)) === 2) {
|
|
5375
7339
|
candidates.push({ chord: spelledInKey(triad, tonic, scale), type: "relative" });
|
|
5376
7340
|
}
|
|
5377
7341
|
}
|
|
5378
|
-
const targetFunction =
|
|
5379
|
-
const parallel =
|
|
7342
|
+
const targetFunction = _chunkIFZDWIKMcjs.functionOf.call(void 0, source, scale);
|
|
7343
|
+
const parallel = _chunkIFZDWIKMcjs.parallelKey.call(void 0, scale);
|
|
5380
7344
|
for (const triad of diatonicTriadsOf(parallel)) {
|
|
5381
|
-
if (
|
|
7345
|
+
if (_chunkIFZDWIKMcjs.functionOf.call(void 0, triad, scale) === targetFunction && !_chunkIFZDWIKMcjs.isDiatonic.call(void 0, triad, scale)) {
|
|
5382
7346
|
candidates.push({ chord: spelledInKey(triad, tonic, parallel), type: "borrowed" });
|
|
5383
7347
|
}
|
|
5384
7348
|
}
|
|
5385
7349
|
for (const offset of THIRD_OFFSETS) {
|
|
5386
7350
|
for (const quality of ["maj", "min"]) {
|
|
5387
|
-
const mediant =
|
|
5388
|
-
if (commonToneCount(originalTriad,
|
|
7351
|
+
const mediant = _chunk3R3QVKY5cjs.makeChord.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, source.rootPc + offset), quality);
|
|
7352
|
+
if (commonToneCount(originalTriad, _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, mediant)) === 1 && !_chunkIFZDWIKMcjs.isDiatonic.call(void 0, mediant, scale)) {
|
|
5389
7353
|
candidates.push({ chord: spelledInKey(mediant, tonic, scale), type: "chromaticMediant" });
|
|
5390
7354
|
}
|
|
5391
7355
|
}
|
|
5392
7356
|
}
|
|
5393
|
-
const melodyPcs = _optionalChain([opts, 'optionalAccess',
|
|
7357
|
+
const melodyPcs = _optionalChain([opts, 'optionalAccess', _119 => _119.melodyPcs, 'optionalAccess', _120 => _120.map, 'call', _121 => _121(_chunkS5BKZZGMcjs.pitchClassOf)]);
|
|
5394
7358
|
const seen = /* @__PURE__ */ new Set();
|
|
5395
7359
|
const results = [];
|
|
5396
7360
|
for (const candidate of candidates) {
|
|
5397
7361
|
if (sameChord(candidate.chord, source)) {
|
|
5398
7362
|
continue;
|
|
5399
7363
|
}
|
|
5400
|
-
const dedupeKey = `${
|
|
7364
|
+
const dedupeKey = `${_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, candidate.chord.rootPc)}:${candidate.chord.quality}`;
|
|
5401
7365
|
if (seen.has(dedupeKey)) {
|
|
5402
7366
|
continue;
|
|
5403
7367
|
}
|
|
5404
7368
|
seen.add(dedupeKey);
|
|
5405
7369
|
if (melodyPcs !== void 0) {
|
|
5406
|
-
const pcs = new Set(
|
|
7370
|
+
const pcs = new Set(_chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, candidate.chord));
|
|
5407
7371
|
if (!melodyPcs.every((pc) => pcs.has(pc))) {
|
|
5408
7372
|
continue;
|
|
5409
7373
|
}
|
|
@@ -5411,65 +7375,65 @@ function substituteChord(chord, key, opts) {
|
|
|
5411
7375
|
results.push({
|
|
5412
7376
|
chord: candidate.chord,
|
|
5413
7377
|
type: candidate.type,
|
|
5414
|
-
roman:
|
|
5415
|
-
function:
|
|
7378
|
+
roman: _chunkIFZDWIKMcjs.chordToRoman.call(void 0, candidate.chord, scale),
|
|
7379
|
+
function: _chunkIFZDWIKMcjs.functionOf.call(void 0, candidate.chord, scale)
|
|
5416
7380
|
});
|
|
5417
7381
|
}
|
|
5418
7382
|
return results;
|
|
5419
7383
|
}
|
|
5420
7384
|
function modalInterchangePalette(key) {
|
|
5421
|
-
const { scale, tonic } =
|
|
7385
|
+
const { scale, tonic } = _chunk3R3QVKY5cjs.resolveKey.call(void 0, key);
|
|
5422
7386
|
const palette = [];
|
|
5423
7387
|
const seen = /* @__PURE__ */ new Set();
|
|
5424
7388
|
const add = (chord) => {
|
|
5425
|
-
const dedupeKey = `${
|
|
7389
|
+
const dedupeKey = `${_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc)}:${chord.quality}`;
|
|
5426
7390
|
if (seen.has(dedupeKey)) {
|
|
5427
7391
|
return;
|
|
5428
7392
|
}
|
|
5429
7393
|
seen.add(dedupeKey);
|
|
5430
7394
|
palette.push({
|
|
5431
7395
|
chord,
|
|
5432
|
-
roman:
|
|
5433
|
-
source:
|
|
7396
|
+
roman: _chunkIFZDWIKMcjs.chordToRoman.call(void 0, chord, scale),
|
|
7397
|
+
source: _chunkIFZDWIKMcjs.borrowedSource.call(void 0, chord, scale)
|
|
5434
7398
|
});
|
|
5435
7399
|
};
|
|
5436
|
-
const parallel =
|
|
7400
|
+
const parallel = _chunkIFZDWIKMcjs.parallelKey.call(void 0, scale);
|
|
5437
7401
|
for (const triad of diatonicTriadsOf(parallel)) {
|
|
5438
|
-
if (!
|
|
7402
|
+
if (!_chunkIFZDWIKMcjs.isDiatonic.call(void 0, triad, scale) && _chunkIFZDWIKMcjs.borrowedSource.call(void 0, triad, scale) !== null) {
|
|
5439
7403
|
add(spelledInKey(triad, tonic, parallel));
|
|
5440
7404
|
}
|
|
5441
7405
|
}
|
|
5442
|
-
const neapolitan =
|
|
5443
|
-
if (!
|
|
5444
|
-
add(spelledOnRoot(neapolitan,
|
|
7406
|
+
const neapolitan = _chunk3R3QVKY5cjs.makeChord.call(void 0, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, scale.rootPc + 1), "maj");
|
|
7407
|
+
if (!_chunkIFZDWIKMcjs.isDiatonic.call(void 0, neapolitan, scale)) {
|
|
7408
|
+
add(spelledOnRoot(neapolitan, _chunkS5BKZZGMcjs.transposeNote.call(void 0, tonic, 1), tonic, scale));
|
|
5445
7409
|
}
|
|
5446
7410
|
return palette;
|
|
5447
7411
|
}
|
|
5448
7412
|
function negativeHarmonyMirror(chord, key) {
|
|
5449
|
-
const source =
|
|
5450
|
-
const { scale, tonic } =
|
|
5451
|
-
const tonicPc =
|
|
5452
|
-
const mirror = (p) =>
|
|
5453
|
-
const pcs =
|
|
7413
|
+
const source = _chunk3R3QVKY5cjs.toChordData.call(void 0, chord);
|
|
7414
|
+
const { scale, tonic } = _chunk3R3QVKY5cjs.resolveKey.call(void 0, key);
|
|
7415
|
+
const tonicPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, scale.rootPc);
|
|
7416
|
+
const mirror = (p) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, 2 * tonicPc + 7 - p);
|
|
7417
|
+
const pcs = _chunk3R3QVKY5cjs.chordPitchClasses.call(void 0, source).map(mirror);
|
|
5454
7418
|
const bassPc = source.bassPc !== void 0 ? mirror(source.bassPc) : void 0;
|
|
5455
7419
|
const pitches = bassPc !== void 0 ? [bassPc, ...pcs.map((pc) => pc + 12)] : pcs;
|
|
5456
|
-
const detected =
|
|
7420
|
+
const detected = _chunkIFZDWIKMcjs.detectChordBest.call(void 0, pitches);
|
|
5457
7421
|
if (detected) {
|
|
5458
7422
|
if (bassPc === void 0 && detected.bassPc !== void 0) {
|
|
5459
|
-
return spelledInKey(
|
|
7423
|
+
return spelledInKey(_chunk3R3QVKY5cjs.makeChord.call(void 0, detected.rootPc, detected.quality), tonic, scale);
|
|
5460
7424
|
}
|
|
5461
7425
|
return spelledInKey(detected, tonic, scale);
|
|
5462
7426
|
}
|
|
5463
7427
|
const quality = source.quality;
|
|
5464
|
-
return spelledInKey(
|
|
7428
|
+
return spelledInKey(_chunk3R3QVKY5cjs.makeChord.call(void 0, mirror(source.rootPc), quality, bassPc), tonic, scale);
|
|
5465
7429
|
}
|
|
5466
7430
|
|
|
5467
7431
|
// src/generate/rhythm/index.ts
|
|
5468
7432
|
var DEFAULT_RHYTHM_VELOCITY = 96;
|
|
5469
7433
|
function rhythmToNoteEvents(events, pitch, velocity = DEFAULT_RHYTHM_VELOCITY) {
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
return
|
|
7434
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, pitch, "pitch");
|
|
7435
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, velocity, "velocity", 0, 127);
|
|
7436
|
+
return _chunkS5BKZZGMcjs.assertArray.call(void 0, events, "events").map((event) => ({
|
|
5473
7437
|
pitch,
|
|
5474
7438
|
startBeat: event.position,
|
|
5475
7439
|
durationBeat: event.duration,
|
|
@@ -5480,7 +7444,7 @@ var DEFAULT_SUBDIVISION = 2;
|
|
|
5480
7444
|
var DEFAULT_DENSITY = 0.5;
|
|
5481
7445
|
var DEFAULT_BARS = 1;
|
|
5482
7446
|
function onsetWeightCurve(weight) {
|
|
5483
|
-
|
|
7447
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, weight, "weight", 0, 3);
|
|
5484
7448
|
switch (weight) {
|
|
5485
7449
|
case 3:
|
|
5486
7450
|
return 1;
|
|
@@ -5493,20 +7457,20 @@ function onsetWeightCurve(weight) {
|
|
|
5493
7457
|
}
|
|
5494
7458
|
}
|
|
5495
7459
|
function generateRhythm(ts, opts = {}) {
|
|
5496
|
-
const asked =
|
|
5497
|
-
const meter =
|
|
7460
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
7461
|
+
const meter = _chunkS5BKZZGMcjs.meterAt.call(void 0, 0, _chunkS5BKZZGMcjs.toMeterData.call(void 0, ts, "ts"));
|
|
5498
7462
|
const bars = _nullishCoalesce(asked.bars, () => ( DEFAULT_BARS));
|
|
5499
7463
|
const subdivision = _nullishCoalesce(asked.subdivision, () => ( DEFAULT_SUBDIVISION));
|
|
5500
7464
|
const ctx = resolveContext(asked.ctx);
|
|
5501
7465
|
const density = _nullishCoalesce(ctx.rhythmic, () => ( DEFAULT_DENSITY));
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
const barBeats =
|
|
7466
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, bars, "rhythm bars");
|
|
7467
|
+
_chunkS5BKZZGMcjs.assertPositiveInt.call(void 0, subdivision, "rhythm subdivision");
|
|
7468
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, meter);
|
|
5505
7469
|
const spanBeats = barBeats * bars;
|
|
5506
7470
|
const step = 1 / subdivision;
|
|
5507
7471
|
const slotsPerBar = Math.ceil(barBeats * subdivision);
|
|
5508
7472
|
const slotCount = slotsPerBar * bars;
|
|
5509
|
-
|
|
7473
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, slotCount, "rhythm grid slots");
|
|
5510
7474
|
const draw = ctx.part("rhythm");
|
|
5511
7475
|
const positions = [];
|
|
5512
7476
|
for (let bar2 = 0; bar2 < bars; bar2 += 1) {
|
|
@@ -5521,7 +7485,7 @@ function generateRhythm(ts, opts = {}) {
|
|
|
5521
7485
|
positions.push(position);
|
|
5522
7486
|
continue;
|
|
5523
7487
|
}
|
|
5524
|
-
const weight =
|
|
7488
|
+
const weight = _chunkS5BKZZGMcjs.metricWeight.call(void 0, position, meter);
|
|
5525
7489
|
const probability = onsetWeightCurve(weight) * density;
|
|
5526
7490
|
if (draw.prob(probability, "onset", bar2, slot)) {
|
|
5527
7491
|
positions.push(position);
|
|
@@ -5537,13 +7501,13 @@ function generateRhythm(ts, opts = {}) {
|
|
|
5537
7501
|
return events;
|
|
5538
7502
|
}
|
|
5539
7503
|
function rhythmDensity(events, ts) {
|
|
5540
|
-
|
|
5541
|
-
const barBeats =
|
|
7504
|
+
_chunkS5BKZZGMcjs.assertArray.call(void 0, events, "events");
|
|
7505
|
+
const barBeats = _chunkS5BKZZGMcjs.beatsPerBar.call(void 0, ts);
|
|
5542
7506
|
if (events.length === 0) {
|
|
5543
7507
|
return 0;
|
|
5544
7508
|
}
|
|
5545
7509
|
const last = events[events.length - 1];
|
|
5546
|
-
const spanBeats = (_nullishCoalesce(_optionalChain([last, 'optionalAccess',
|
|
7510
|
+
const spanBeats = (_nullishCoalesce(_optionalChain([last, 'optionalAccess', _122 => _122.position]), () => ( 0))) + (_nullishCoalesce(_optionalChain([last, 'optionalAccess', _123 => _123.duration]), () => ( 0)));
|
|
5547
7511
|
const bars = spanBeats / barBeats;
|
|
5548
7512
|
return bars > 0 ? events.length / bars : 0;
|
|
5549
7513
|
}
|
|
@@ -5617,5 +7581,11 @@ function rhythmDensity(events, ts) {
|
|
|
5617
7581
|
|
|
5618
7582
|
|
|
5619
7583
|
|
|
5620
|
-
|
|
5621
|
-
|
|
7584
|
+
|
|
7585
|
+
|
|
7586
|
+
|
|
7587
|
+
|
|
7588
|
+
|
|
7589
|
+
|
|
7590
|
+
exports.GENRES = GENRES; exports.PROVENANCE_BASES = PROVENANCE_BASES; exports.fitsQuery = fitsQuery; exports.selectVocabulary = selectVocabulary; exports.pickVocabulary = pickVocabulary; exports.mergeVocabulary = mergeVocabulary; exports.vocabularyOfKind = vocabularyOfKind; exports.assertVocabulary = assertVocabulary; exports.MIN_DIFFICULTY = MIN_DIFFICULTY; exports.MAX_DIFFICULTY = MAX_DIFFICULTY; exports.sustainsStrokes = sustainsStrokes; exports.sustainsShift = sustainsShift; exports.resolveContext = resolveContext; exports.BAR_STEPS = BAR_STEPS; exports.BEAT_STEPS = BEAT_STEPS; exports.STEP_BEATS = STEP_BEATS; exports.gridMetricWeight = gridMetricWeight; exports.thin = thin; exports.double = double; exports.halfTime = halfTime; exports.doubleTime = doubleTime; exports.syncopate = syncopate; exports.ornamentBy = ornamentBy; exports.deform = deform; exports.withinCeiling = withinCeiling; exports.isLickMaterial = isLickMaterial; exports.BASS_LICKS = BASS_LICKS; exports.placeLicks = placeLicks; exports.BASS_STYLES = BASS_STYLES; exports.generateBassLine = generateBassLine; exports.imitate = imitate; exports.generateCounterMelody = generateCounterMelody; exports.FILL_TYPES = FILL_TYPES; exports.FILL_ARCHETYPES = FILL_ARCHETYPES; exports.isFillArchetype = isFillArchetype; exports.DRUM_NOTES = DRUM_NOTES; exports.drumVoiceOf = drumVoiceOf; exports.KICK_STEPS = KICK_STEPS; exports.KICK_FIGURES = KICK_FIGURES; exports.DRUM_KIT = DRUM_KIT; exports.isDrumPattern = isDrumPattern; exports.DRUM_PATTERNS = DRUM_PATTERNS; exports.placeDrumPattern = placeDrumPattern; exports.generateDrums = generateDrums; exports.humanize = humanize; exports.extractGrooveTemplate = extractGrooveTemplate; exports.applyGrooveTemplate = applyGrooveTemplate; exports.classifyMelodyTones = classifyMelodyTones; exports.harmonizeMelody = harmonizeMelody; exports.cellSpan = cellSpan; exports.generateMotif = generateMotif; exports.motifToNoteEvents = motifToNoteEvents; exports.transformMotif = transformMotif; exports.developMotif = developMotif; exports.COMPOSITION_PLAN_VERSION = COMPOSITION_PLAN_VERSION; exports.assertCompositionPlan = assertCompositionPlan; exports.planTimeline = planTimeline; exports.generateMelody = generateMelody; exports.ORNAMENT_STYLES = ORNAMENT_STYLES; exports.ornament = ornament; exports.deriveCompositionPlan = deriveCompositionPlan; exports.evaluateComposition = evaluateComposition; exports.BORROWED_DEGREES = BORROWED_DEGREES; exports.progressions = progressions; exports.progressionsByStyle = progressionsByStyle; exports.pickProgressionPreset = pickProgressionPreset; exports.generateProgression = generateProgression; exports.substituteChord = substituteChord; exports.modalInterchangePalette = modalInterchangePalette; exports.negativeHarmonyMirror = negativeHarmonyMirror; exports.rhythmToNoteEvents = rhythmToNoteEvents; exports.onsetWeightCurve = onsetWeightCurve; exports.generateRhythm = generateRhythm; exports.rhythmDensity = rhythmDensity;
|
|
7591
|
+
//# sourceMappingURL=chunk-B2PW6EHN.cjs.map
|