@libraz/libcantus 0.9.4 → 0.9.5
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 +27 -18
- package/README_ja.md +268 -0
- package/dist/analyze/index.cjs +7 -7
- package/dist/analyze/index.d.cts +9 -99
- package/dist/analyze/index.d.ts +9 -99
- package/dist/analyze/index.js +6 -6
- package/dist/{chunk-36N73KZ3.cjs → chunk-2A2QMA74.cjs} +80 -65
- package/dist/chunk-2A2QMA74.cjs.map +1 -0
- package/dist/{chunk-YLEMGEFH.js → chunk-2PTFGVD7.js} +50 -35
- package/dist/chunk-2PTFGVD7.js.map +1 -0
- package/dist/{chunk-ZEJR4TKL.cjs → chunk-357ZDPVU.cjs} +36 -47
- package/dist/chunk-357ZDPVU.cjs.map +1 -0
- package/dist/{chunk-EHVEBWM5.js → chunk-3KX76RLG.js} +136 -37
- package/dist/chunk-3KX76RLG.js.map +1 -0
- package/dist/{chunk-RC6GBMCD.cjs → chunk-4VZ5MZAM.cjs} +155 -111
- package/dist/chunk-4VZ5MZAM.cjs.map +1 -0
- package/dist/{chunk-RK35RIN7.js → chunk-7EONYVI5.js} +115 -28
- package/dist/chunk-7EONYVI5.js.map +1 -0
- package/dist/{chunk-GQSGS2N4.js → chunk-7JEP3MFY.js} +5 -16
- package/dist/chunk-7JEP3MFY.js.map +1 -0
- package/dist/{chunk-7NKDPF74.js → chunk-AID75RN3.js} +203 -104
- package/dist/chunk-AID75RN3.js.map +1 -0
- package/dist/{chunk-FNDWXRRI.cjs → chunk-BSLTLGM3.cjs} +55 -37
- package/dist/chunk-BSLTLGM3.cjs.map +1 -0
- package/dist/{chunk-NP4NA2FB.cjs → chunk-CU6VG2YM.cjs} +39 -36
- package/dist/chunk-CU6VG2YM.cjs.map +1 -0
- package/dist/{chunk-NYYWMV2C.js → chunk-DZMHIGI4.js} +27 -17
- package/dist/chunk-DZMHIGI4.js.map +1 -0
- package/dist/{chunk-I24MV65U.js → chunk-EDOTEABK.js} +18 -15
- package/dist/{chunk-I24MV65U.js.map → chunk-EDOTEABK.js.map} +1 -1
- package/dist/{chunk-NKIBQ6PT.js → chunk-HN2OEUN2.js} +7 -4
- package/dist/chunk-HN2OEUN2.js.map +1 -0
- package/dist/{chunk-D2FAJBYL.js → chunk-KBTTEX7Q.js} +30 -12
- package/dist/chunk-KBTTEX7Q.js.map +1 -0
- package/dist/{chunk-CAN76NCU.cjs → chunk-KQN2ZYND.cjs} +147 -102
- package/dist/chunk-KQN2ZYND.cjs.map +1 -0
- package/dist/{chunk-4HLLZPXT.cjs → chunk-MPTVJIVG.cjs} +350 -251
- package/dist/chunk-MPTVJIVG.cjs.map +1 -0
- package/dist/{chunk-RUMU3UA6.cjs → chunk-MTMZTMWM.cjs} +12 -12
- package/dist/{chunk-RUMU3UA6.cjs.map → chunk-MTMZTMWM.cjs.map} +1 -1
- package/dist/{chunk-KMHOICIY.js → chunk-NNB67XA2.js} +90 -45
- package/dist/chunk-NNB67XA2.js.map +1 -0
- package/dist/{chunk-LW53AHQU.cjs → chunk-OL3IHHSJ.cjs} +228 -141
- package/dist/chunk-OL3IHHSJ.cjs.map +1 -0
- package/dist/{chunk-7MGZ7D62.cjs → chunk-PI3UXRWK.cjs} +43 -13
- package/dist/chunk-PI3UXRWK.cjs.map +1 -0
- package/dist/{chunk-XEBG3G53.js → chunk-R2VVFAIN.js} +42 -12
- package/dist/chunk-R2VVFAIN.js.map +1 -0
- package/dist/{chunk-Q6OP4U43.cjs → chunk-WFDXOLUB.cjs} +50 -40
- package/dist/chunk-WFDXOLUB.cjs.map +1 -0
- package/dist/{chunk-NVE34YGZ.cjs → chunk-WTAN4ACG.cjs} +212 -113
- package/dist/chunk-WTAN4ACG.cjs.map +1 -0
- package/dist/{chunk-FCANXBAT.cjs → chunk-YFJXS3AU.cjs} +8 -5
- package/dist/chunk-YFJXS3AU.cjs.map +1 -0
- package/dist/{chunk-Q2XUP227.js → chunk-YUE6TJ4M.js} +89 -45
- package/dist/chunk-YUE6TJ4M.js.map +1 -0
- package/dist/{chunk-HKGYCQ34.js → chunk-ZGLJM4A4.js} +2 -2
- package/dist/core/index.cjs +15 -5
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +14 -4
- package/dist/core/index.d.ts +14 -4
- package/dist/core/index.js +14 -4
- package/dist/{function-DNugAOrt.d.cts → function-CxixTB02.d.cts} +98 -7
- package/dist/{function-BtiZb9i9.d.ts → function-DTCt675z.d.ts} +98 -7
- package/dist/generate/index.cjs +10 -10
- package/dist/generate/index.d.cts +21 -21
- package/dist/generate/index.d.ts +21 -21
- package/dist/generate/index.js +9 -9
- package/dist/{index-tJhkmQgE.d.cts → index-B2Ulxxpo.d.cts} +3 -2
- package/dist/{index-Be74mcon.d.cts → index-BkYJ0xMq.d.cts} +2 -2
- package/dist/{index-6VR8-kit.d.ts → index-BuaB-ypt.d.ts} +3 -2
- package/dist/{index-70p168VM.d.ts → index-CAN7v-kw.d.ts} +9 -2
- package/dist/{index-C83mZI1P.d.ts → index-COw1Ky9g.d.ts} +1 -1
- package/dist/{index-tSQh-xwY.d.ts → index-Cfx8xgH0.d.ts} +1 -1
- package/dist/{index-C5UBbQ4G.d.ts → index-DRtIhlJj.d.ts} +2 -2
- package/dist/{index-BtXT6UQ0.d.cts → index-alrRninU.d.cts} +9 -2
- package/dist/{index-y_ak9_Hi.d.cts → index-oTQbYYIs.d.cts} +1 -1
- package/dist/{index-OG65ocOr.d.ts → index-tR9jTn26.d.cts} +4 -1
- package/dist/{index-OG65ocOr.d.cts → index-tR9jTn26.d.ts} +4 -1
- package/dist/{index-D6b6na69.d.cts → index-x2vcsduE.d.cts} +1 -1
- package/dist/index.cjs +24 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.js +23 -13
- package/dist/model/index.cjs +7 -7
- package/dist/model/index.d.cts +48 -16
- package/dist/model/index.d.ts +48 -16
- package/dist/model/index.js +6 -6
- package/dist/{styled-DIRkk9Uz.d.ts → styled-Bl0ZK28h.d.ts} +40 -3
- package/dist/{styled-DJbkJQfj.d.cts → styled-Crv6SA4S.d.cts} +40 -3
- package/dist/theory/index.cjs +6 -6
- package/dist/theory/index.d.cts +9 -9
- package/dist/theory/index.d.ts +9 -9
- package/dist/theory/index.js +5 -5
- package/package.json +12 -9
- package/dist/chunk-36N73KZ3.cjs.map +0 -1
- package/dist/chunk-4HLLZPXT.cjs.map +0 -1
- package/dist/chunk-7MGZ7D62.cjs.map +0 -1
- package/dist/chunk-7NKDPF74.js.map +0 -1
- package/dist/chunk-CAN76NCU.cjs.map +0 -1
- package/dist/chunk-D2FAJBYL.js.map +0 -1
- package/dist/chunk-EHVEBWM5.js.map +0 -1
- package/dist/chunk-FCANXBAT.cjs.map +0 -1
- package/dist/chunk-FNDWXRRI.cjs.map +0 -1
- package/dist/chunk-GQSGS2N4.js.map +0 -1
- package/dist/chunk-KMHOICIY.js.map +0 -1
- package/dist/chunk-LW53AHQU.cjs.map +0 -1
- package/dist/chunk-NKIBQ6PT.js.map +0 -1
- package/dist/chunk-NP4NA2FB.cjs.map +0 -1
- package/dist/chunk-NVE34YGZ.cjs.map +0 -1
- package/dist/chunk-NYYWMV2C.js.map +0 -1
- package/dist/chunk-Q2XUP227.js.map +0 -1
- package/dist/chunk-Q6OP4U43.cjs.map +0 -1
- package/dist/chunk-RC6GBMCD.cjs.map +0 -1
- package/dist/chunk-RK35RIN7.js.map +0 -1
- package/dist/chunk-XEBG3G53.js.map +0 -1
- package/dist/chunk-YLEMGEFH.js.map +0 -1
- package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
- /package/dist/{chunk-HKGYCQ34.js.map → chunk-ZGLJM4A4.js.map} +0 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkMTMZTMWMcjs = require('./chunk-MTMZTMWM.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var _chunk36N73KZ3cjs = require('./chunk-36N73KZ3.cjs');
|
|
11
10
|
|
|
11
|
+
var _chunk2A2QMA74cjs = require('./chunk-2A2QMA74.cjs');
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
var _chunkCAN76NCUcjs = require('./chunk-CAN76NCU.cjs');
|
|
15
14
|
|
|
15
|
+
var _chunkKQN2ZYNDcjs = require('./chunk-KQN2ZYND.cjs');
|
|
16
16
|
|
|
17
|
-
var _chunkFCANXBATcjs = require('./chunk-FCANXBAT.cjs');
|
|
18
17
|
|
|
18
|
+
var _chunkYFJXS3AUcjs = require('./chunk-YFJXS3AU.cjs');
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
var _chunkQ6OP4U43cjs = require('./chunk-Q6OP4U43.cjs');
|
|
22
21
|
|
|
22
|
+
var _chunkWFDXOLUBcjs = require('./chunk-WFDXOLUB.cjs');
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
|
|
@@ -32,9 +32,9 @@ var _chunkQ6OP4U43cjs = require('./chunk-Q6OP4U43.cjs');
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
var _chunkFNDWXRRIcjs = require('./chunk-FNDWXRRI.cjs');
|
|
36
35
|
|
|
37
36
|
|
|
37
|
+
var _chunkBSLTLGM3cjs = require('./chunk-BSLTLGM3.cjs');
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
|
|
@@ -45,10 +45,21 @@ var _chunkFNDWXRRIcjs = require('./chunk-FNDWXRRI.cjs');
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
var _chunkPI3UXRWKcjs = require('./chunk-PI3UXRWK.cjs');
|
|
49
54
|
|
|
50
55
|
// src/generate/bass/index.ts
|
|
51
|
-
var BASS_STYLES = [
|
|
56
|
+
var BASS_STYLES = Object.freeze([
|
|
57
|
+
"root",
|
|
58
|
+
"rootFifth",
|
|
59
|
+
"pop",
|
|
60
|
+
"walking",
|
|
61
|
+
"arpeggio"
|
|
62
|
+
]);
|
|
52
63
|
var DEFAULT_TS = { numerator: 4, denominator: 4 };
|
|
53
64
|
var DEFAULT_STYLE = "root";
|
|
54
65
|
var DEFAULT_OCTAVE = 2;
|
|
@@ -71,29 +82,43 @@ function chordTonePcs(chord) {
|
|
|
71
82
|
const seen = /* @__PURE__ */ new Set();
|
|
72
83
|
const pcs = [];
|
|
73
84
|
for (const interval of chord.intervals) {
|
|
74
|
-
const pc =
|
|
85
|
+
const pc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc + interval);
|
|
75
86
|
if (!seen.has(pc)) {
|
|
76
87
|
seen.add(pc);
|
|
77
88
|
pcs.push(pc);
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
91
|
if (pcs.length === 0) {
|
|
81
|
-
pcs.push(
|
|
92
|
+
pcs.push(_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc));
|
|
82
93
|
}
|
|
83
94
|
return pcs;
|
|
84
95
|
}
|
|
85
96
|
function fifthPcOf(chord) {
|
|
86
|
-
const fifths = new Set(chord.intervals.map((i) =>
|
|
97
|
+
const fifths = new Set(chord.intervals.map((i) => _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, i)));
|
|
87
98
|
const chosen = fifths.has(7) ? 7 : fifths.has(6) ? 6 : fifths.has(8) ? 8 : void 0;
|
|
88
|
-
return chosen === void 0 ?
|
|
99
|
+
return chosen === void 0 ? _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc) : _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc + chosen);
|
|
89
100
|
}
|
|
90
101
|
function bassPcOf(chord) {
|
|
91
|
-
return
|
|
102
|
+
return _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, _nullishCoalesce(chord.bassPc, () => ( chord.rootPc)));
|
|
92
103
|
}
|
|
93
|
-
function beatPositions(start, end) {
|
|
104
|
+
function beatPositions(start, end, ts) {
|
|
94
105
|
const positions = [];
|
|
95
|
-
|
|
96
|
-
|
|
106
|
+
const barBeats = _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts);
|
|
107
|
+
const pulse = _chunk2A2QMA74cjs.pulseBeats.call(void 0, ts);
|
|
108
|
+
const firstBar = Math.floor(start / barBeats);
|
|
109
|
+
const lastBar = Math.floor((end - EPS) / barBeats);
|
|
110
|
+
for (let bar = firstBar; bar <= lastBar; bar += 1) {
|
|
111
|
+
const barStart = bar * barBeats;
|
|
112
|
+
const firstPulse = Math.max(0, Math.ceil((start - barStart - EPS) / pulse));
|
|
113
|
+
for (let index = firstPulse; ; index += 1) {
|
|
114
|
+
const position = barStart + index * pulse;
|
|
115
|
+
if (position >= barStart + barBeats - EPS || position >= end - EPS) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
if (position >= start - EPS) {
|
|
119
|
+
positions.push(position);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
97
122
|
}
|
|
98
123
|
if (positions.length === 0) {
|
|
99
124
|
positions.push(start);
|
|
@@ -101,8 +126,11 @@ function beatPositions(start, end) {
|
|
|
101
126
|
return positions;
|
|
102
127
|
}
|
|
103
128
|
function emit(ctx, pos, pc, midiOverride) {
|
|
104
|
-
const midi =
|
|
105
|
-
|
|
129
|
+
const midi = _chunkPI3UXRWKcjs.clampToMidi.call(void 0,
|
|
130
|
+
_nullishCoalesce(midiOverride, () => ( placePc(pc, ctx.prevMidi, ctx.low))),
|
|
131
|
+
"generated bass pitch"
|
|
132
|
+
);
|
|
133
|
+
const velocity = _chunk2A2QMA74cjs.isStrongBeat.call(void 0, pos, ctx.ts) ? STRONG_VELOCITY : WEAK_VELOCITY;
|
|
106
134
|
ctx.notes.push({ startBeat: pos, pitch: midi, velocity });
|
|
107
135
|
return midi;
|
|
108
136
|
}
|
|
@@ -117,11 +145,11 @@ function buildRootFifth(ctx, seg) {
|
|
|
117
145
|
}
|
|
118
146
|
}
|
|
119
147
|
function buildPop(ctx, seg) {
|
|
120
|
-
const positions = beatPositions(seg.startBeat, seg.endBeat);
|
|
148
|
+
const positions = beatPositions(seg.startBeat, seg.endBeat, ctx.ts);
|
|
121
149
|
const rootPc = bassPcOf(seg.chord);
|
|
122
150
|
let emitted = false;
|
|
123
151
|
for (const pos of positions) {
|
|
124
|
-
if (
|
|
152
|
+
if (_chunk2A2QMA74cjs.isStrongBeat.call(void 0, pos, ctx.ts)) {
|
|
125
153
|
ctx.prevMidi = emit(ctx, pos, rootPc);
|
|
126
154
|
emitted = true;
|
|
127
155
|
} else if (ctx.rng.prob(PICKUP_PROB)) {
|
|
@@ -140,7 +168,7 @@ function buildPop(ctx, seg) {
|
|
|
140
168
|
}
|
|
141
169
|
function buildArpeggio(ctx, seg) {
|
|
142
170
|
const tones = chordTonePcs(seg.chord);
|
|
143
|
-
const positions = beatPositions(seg.startBeat, seg.endBeat);
|
|
171
|
+
const positions = beatPositions(seg.startBeat, seg.endBeat, ctx.ts);
|
|
144
172
|
positions.forEach((pos, i) => {
|
|
145
173
|
const pc = _nullishCoalesce(tones[i % tones.length], () => ( bassPcOf(seg.chord)));
|
|
146
174
|
ctx.prevMidi = emit(ctx, pos, pc);
|
|
@@ -152,7 +180,7 @@ function approachNote(ctx, target, from) {
|
|
|
152
180
|
if (ctx.rng.prob(0.5)) {
|
|
153
181
|
return foldIntoBand(chromatic, ctx.low);
|
|
154
182
|
}
|
|
155
|
-
const cand =
|
|
183
|
+
const cand = _chunkBSLTLGM3cjs.nearestScaleTone.call(void 0, target + dir * 2, ctx.key);
|
|
156
184
|
const step = Math.abs(cand - target);
|
|
157
185
|
return foldIntoBand(step >= 1 && step <= 2 ? cand : chromatic, ctx.low);
|
|
158
186
|
}
|
|
@@ -168,7 +196,7 @@ function foldIntoBand(midi, low) {
|
|
|
168
196
|
}
|
|
169
197
|
function buildWalking(ctx, seg, next) {
|
|
170
198
|
const tones = chordTonePcs(seg.chord);
|
|
171
|
-
const positions = beatPositions(seg.startBeat, seg.endBeat);
|
|
199
|
+
const positions = beatPositions(seg.startBeat, seg.endBeat, ctx.ts);
|
|
172
200
|
const count = positions.length;
|
|
173
201
|
positions.forEach((pos, i) => {
|
|
174
202
|
if (i === 0) {
|
|
@@ -178,7 +206,7 @@ function buildWalking(ctx, seg, next) {
|
|
|
178
206
|
if (next && count > 1 && i === count - 1) {
|
|
179
207
|
const nextBass = placePc(bassPcOf(next.chord), ctx.prevMidi, ctx.low);
|
|
180
208
|
const midi = approachNote(ctx, nextBass, ctx.prevMidi);
|
|
181
|
-
ctx.prevMidi = emit(ctx, pos,
|
|
209
|
+
ctx.prevMidi = emit(ctx, pos, _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, midi), midi);
|
|
182
210
|
return;
|
|
183
211
|
}
|
|
184
212
|
const pc = _nullishCoalesce(tones[i % tones.length], () => ( bassPcOf(seg.chord)));
|
|
@@ -186,36 +214,45 @@ function buildWalking(ctx, seg, next) {
|
|
|
186
214
|
});
|
|
187
215
|
}
|
|
188
216
|
function generateBassLine(opts) {
|
|
189
|
-
|
|
217
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, opts.segments.length, "bass segments");
|
|
190
218
|
for (let index = 0; index < opts.segments.length; index += 1) {
|
|
191
219
|
const segment = opts.segments[index];
|
|
192
220
|
if (!segment) continue;
|
|
193
|
-
|
|
194
|
-
|
|
221
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, segment.startBeat, 0, Number.MAX_SAFE_INTEGER, `segments[${index}].startBeat`);
|
|
222
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, segment.endBeat, 0, Number.MAX_SAFE_INTEGER, `segments[${index}].endBeat`);
|
|
195
223
|
if (segment.endBeat <= segment.startBeat) {
|
|
196
|
-
throw new (0,
|
|
224
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`segments[${index}] must have a positive duration`);
|
|
197
225
|
}
|
|
198
226
|
}
|
|
199
227
|
const segments = [...opts.segments].sort((a, b) => a.startBeat - b.startBeat);
|
|
228
|
+
for (let index = 1; index < segments.length; index += 1) {
|
|
229
|
+
const previous = segments[index - 1];
|
|
230
|
+
const current = segments[index];
|
|
231
|
+
if (previous !== void 0 && current !== void 0 && current.startBeat < previous.endBeat) {
|
|
232
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(
|
|
233
|
+
`bass segments must not overlap: segments ${index - 1} and ${index} overlap`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
200
237
|
if (segments.length === 0) {
|
|
201
238
|
return [];
|
|
202
239
|
}
|
|
203
240
|
const ts = _nullishCoalesce(opts.ts, () => ( DEFAULT_TS));
|
|
204
|
-
|
|
205
|
-
const style =
|
|
241
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
242
|
+
const style = _chunkPI3UXRWKcjs.assertOneOf.call(void 0, _nullishCoalesce(opts.style, () => ( DEFAULT_STYLE)), BASS_STYLES, "bass style");
|
|
206
243
|
const octave = _nullishCoalesce(opts.octave, () => ( DEFAULT_OCTAVE));
|
|
207
|
-
|
|
244
|
+
_chunkPI3UXRWKcjs.assertInteger.call(void 0, octave, "bass octave", -1, 8);
|
|
208
245
|
const estimatedNotes = segments.reduce(
|
|
209
246
|
(count, segment) => count + Math.max(1, Math.ceil(segment.endBeat - segment.startBeat)),
|
|
210
247
|
0
|
|
211
248
|
);
|
|
212
|
-
|
|
249
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, estimatedNotes, "bass notes");
|
|
213
250
|
const low = octave * 12 + 12;
|
|
214
251
|
const ctx = {
|
|
215
252
|
ts,
|
|
216
253
|
low,
|
|
217
254
|
key: opts.key,
|
|
218
|
-
rng:
|
|
255
|
+
rng: _chunkMTMZTMWMcjs.createRng.call(void 0, _nullishCoalesce(opts.seed, () => ( 0))),
|
|
219
256
|
notes: [],
|
|
220
257
|
prevMidi: low
|
|
221
258
|
};
|
|
@@ -256,7 +293,7 @@ function generateBassLine(opts) {
|
|
|
256
293
|
continue;
|
|
257
294
|
}
|
|
258
295
|
out.push({
|
|
259
|
-
pitch: note.pitch,
|
|
296
|
+
pitch: _chunkPI3UXRWKcjs.clampToMidi.call(void 0, note.pitch, "generated bass pitch"),
|
|
260
297
|
startBeat: note.startBeat,
|
|
261
298
|
durationBeat,
|
|
262
299
|
velocity: note.velocity
|
|
@@ -315,7 +352,7 @@ function complementOnsets(melody, ts, spanStart, spanEnd, rng) {
|
|
|
315
352
|
place = isWholeBeat(beat);
|
|
316
353
|
} else if (!attacked) {
|
|
317
354
|
place = rng.prob(isWholeBeat(beat) ? HOLD_ON_BEAT_PROB : HOLD_OFF_BEAT_PROB);
|
|
318
|
-
} else if (
|
|
355
|
+
} else if (_chunk2A2QMA74cjs.isStrongBeat.call(void 0, beat, ts)) {
|
|
319
356
|
place = rng.prob(REINFORCE_PROB);
|
|
320
357
|
}
|
|
321
358
|
if (place && beat - last >= MIN_ONSET_GAP - EPS2) {
|
|
@@ -337,7 +374,7 @@ function scoreCandidate(pitch, melPitch, melPrev, prevPitch, chord, center) {
|
|
|
337
374
|
score -= 2;
|
|
338
375
|
}
|
|
339
376
|
}
|
|
340
|
-
if (chord &&
|
|
377
|
+
if (chord && _chunkBSLTLGM3cjs.chordToneRole.call(void 0, pitch, chord) !== null) {
|
|
341
378
|
score += 1;
|
|
342
379
|
}
|
|
343
380
|
if (prevPitch !== void 0) {
|
|
@@ -347,7 +384,7 @@ function scoreCandidate(pitch, melPitch, melPrev, prevPitch, chord, center) {
|
|
|
347
384
|
if (dist > 0 && dist <= 2) {
|
|
348
385
|
score += 1;
|
|
349
386
|
}
|
|
350
|
-
if (
|
|
387
|
+
if (_chunkBSLTLGM3cjs.isForbiddenMelodicLeap.call(void 0, prevPitch, pitch)) {
|
|
351
388
|
score -= 6;
|
|
352
389
|
}
|
|
353
390
|
if (melPitch !== void 0 && melPrev !== void 0) {
|
|
@@ -388,7 +425,7 @@ function boundaryContexts(melody, harmony, startBeat, endBeat, ts) {
|
|
|
388
425
|
melodyVoice,
|
|
389
426
|
otherVoices: melodyVoice === void 0 ? [] : [melodyVoice],
|
|
390
427
|
chord: harmony.chordAt(boundary),
|
|
391
|
-
strongBeat:
|
|
428
|
+
strongBeat: _chunk2A2QMA74cjs.isStrongBeat.call(void 0, boundary, ts),
|
|
392
429
|
atCounterOnset: Math.abs(boundary - startBeat) < EPS2
|
|
393
430
|
};
|
|
394
431
|
});
|
|
@@ -400,7 +437,7 @@ function heldPitchSafety(pitch, contexts, prevPitch, key, profile, register, low
|
|
|
400
437
|
if (melodyVoice !== void 0 && (register === "below" && pitch >= melodyVoice.pitch || register === "above" && pitch <= melodyVoice.pitch)) {
|
|
401
438
|
return null;
|
|
402
439
|
}
|
|
403
|
-
const result =
|
|
440
|
+
const result = _chunkWFDXOLUBcjs.evaluateSafety.call(void 0,
|
|
404
441
|
{
|
|
405
442
|
profile,
|
|
406
443
|
candidatePitch: pitch,
|
|
@@ -429,42 +466,40 @@ function generateCounterMelody(opts) {
|
|
|
429
466
|
}
|
|
430
467
|
const chordChangeBeats = timeline === void 0 ? _nullishCoalesce(opts.chordChangeBeats, () => ( [])) : timeline.segments.flatMap((segment) => [segment.startBeat, segment.endBeat]);
|
|
431
468
|
const register = _nullishCoalesce(opts.register, () => ( "below"));
|
|
432
|
-
|
|
433
|
-
|
|
469
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, opts.melody, "countermelody melody", { allowNonPositiveDuration: true });
|
|
470
|
+
const melody = _chunk2A2QMA74cjs.createNoteEventIndex.call(void 0, _chunkPI3UXRWKcjs.soundingNotesOnly.call(void 0, opts.melody), {
|
|
434
471
|
tieBreak: register === "below" ? "highest" : "lowest"
|
|
435
472
|
});
|
|
436
473
|
const ts = _nullishCoalesce(opts.ts, () => ( DEFAULT_TS2));
|
|
437
|
-
|
|
438
|
-
const rhythm =
|
|
439
|
-
const profile =
|
|
440
|
-
const rng =
|
|
441
|
-
if (
|
|
442
|
-
_chunk7MGZ7D62cjs.assertInteger.call(void 0, opts.pitchLow, "countermelody pitchLow");
|
|
443
|
-
}
|
|
444
|
-
if (opts.pitchHigh !== void 0) {
|
|
445
|
-
_chunk7MGZ7D62cjs.assertInteger.call(void 0, opts.pitchHigh, "countermelody pitchHigh");
|
|
446
|
-
}
|
|
447
|
-
if (melody.notes.every((indexed) => indexed.note.durationBeat <= 0)) {
|
|
474
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
475
|
+
const rhythm = _chunkPI3UXRWKcjs.assertOneOf.call(void 0, _nullishCoalesce(opts.rhythm, () => ( "complement")), ["complement", "follow"], "rhythm");
|
|
476
|
+
const profile = _chunkPI3UXRWKcjs.assertOneOf.call(void 0, _nullishCoalesce(opts.profile, () => ( "pop")), ["strict", "pop"], "safety profile");
|
|
477
|
+
const rng = _chunkMTMZTMWMcjs.createRng.call(void 0, _nullishCoalesce(opts.seed, () => ( 0)));
|
|
478
|
+
if (melody.notes.length === 0) {
|
|
448
479
|
return [];
|
|
449
480
|
}
|
|
450
481
|
const spanStart = _nullishCoalesce(_optionalChain([melody, 'access', _8 => _8.notes, 'access', _9 => _9[0], 'optionalAccess', _10 => _10.note, 'access', _11 => _11.startBeat]), () => ( 0));
|
|
451
482
|
const spanEnd = melody.notes.reduce((end, n) => Math.max(end, n.endBeat), spanStart);
|
|
452
|
-
|
|
483
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, Math.ceil((spanEnd - spanStart) / GRID_STEP), "countermelody grid");
|
|
453
484
|
const meanPitch = melody.notes.reduce((sum, n) => sum + n.note.pitch, 0) / melody.notes.length;
|
|
454
485
|
const defaultCenter = register === "below" ? meanPitch - REGISTER_OFFSET : meanPitch + REGISTER_OFFSET;
|
|
455
|
-
const low =
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
486
|
+
const low = _chunkPI3UXRWKcjs.clampToMidi.call(void 0,
|
|
487
|
+
_nullishCoalesce(opts.pitchLow, () => ( Math.round(defaultCenter) - DEFAULT_HALF_RANGE)),
|
|
488
|
+
"countermelody pitchLow"
|
|
489
|
+
);
|
|
490
|
+
const high = _chunkPI3UXRWKcjs.clampToMidi.call(void 0,
|
|
491
|
+
_nullishCoalesce(opts.pitchHigh, () => ( Math.round(defaultCenter) + DEFAULT_HALF_RANGE)),
|
|
492
|
+
"countermelody pitchHigh"
|
|
493
|
+
);
|
|
459
494
|
if (low > high) {
|
|
460
|
-
throw new (0,
|
|
495
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(
|
|
461
496
|
`countermelody pitchLow must not exceed pitchHigh; received ${low} > ${high}`
|
|
462
497
|
);
|
|
463
498
|
}
|
|
464
|
-
|
|
465
|
-
|
|
499
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, high - low + 1, "countermelody pitch candidates");
|
|
500
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, chordChangeBeats.length, "chord change beats");
|
|
466
501
|
for (let index = 0; index < chordChangeBeats.length; index += 1) {
|
|
467
|
-
|
|
502
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0,
|
|
468
503
|
_nullishCoalesce(chordChangeBeats[index], () => ( Number.NaN)),
|
|
469
504
|
0,
|
|
470
505
|
Number.MAX_SAFE_INTEGER,
|
|
@@ -474,7 +509,7 @@ function generateCounterMelody(opts) {
|
|
|
474
509
|
const center = (low + high) / 2;
|
|
475
510
|
const onsets = rhythm === "follow" ? followOnsets(melody) : complementOnsets(melody, ts, spanStart, spanEnd, rng);
|
|
476
511
|
const boundaryEstimate = onsets.length + Math.ceil((spanEnd - spanStart) / GRID_STEP) + melody.notes.length + chordChangeBeats.length;
|
|
477
|
-
|
|
512
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, boundaryEstimate * (high - low + 1), "countermelody search");
|
|
478
513
|
const jitter = Array.from({ length: high - low + 1 }, () => rng.next() * TIE_BREAK_JITTER);
|
|
479
514
|
const out = [];
|
|
480
515
|
let prevPitch;
|
|
@@ -492,14 +527,14 @@ function generateCounterMelody(opts) {
|
|
|
492
527
|
const contexts = boundaryContexts(melody, { chordAt, chordChangeBeats }, beat, endBeat, ts);
|
|
493
528
|
const chord = _nullishCoalesce(_optionalChain([contexts, 'access', _14 => _14[0], 'optionalAccess', _15 => _15.chord]), () => ( chordAt(beat)));
|
|
494
529
|
const otherVoices = melodyVoice !== void 0 ? [melodyVoice] : [];
|
|
495
|
-
const candidates =
|
|
530
|
+
const candidates = _chunkWFDXOLUBcjs.enumerateSafePitches.call(void 0,
|
|
496
531
|
{
|
|
497
532
|
profile,
|
|
498
533
|
prevPitch,
|
|
499
534
|
chord,
|
|
500
535
|
key: opts.key,
|
|
501
536
|
otherVoices,
|
|
502
|
-
strongBeat:
|
|
537
|
+
strongBeat: _chunk2A2QMA74cjs.isStrongBeat.call(void 0, beat, ts),
|
|
503
538
|
vocalLow: low,
|
|
504
539
|
vocalHigh: high
|
|
505
540
|
},
|
|
@@ -526,7 +561,7 @@ function generateCounterMelody(opts) {
|
|
|
526
561
|
if (melPitch !== void 0) {
|
|
527
562
|
if (prevPitch !== void 0 && melPrev !== void 0 && // Parallel octaves are the perfect-class-zero case of this predicate,
|
|
528
563
|
// so a single check covers both parallel fifths and octaves.
|
|
529
|
-
|
|
564
|
+
_chunkBSLTLGM3cjs.createsParallelPerfect.call(void 0, prevPitch, candidate, melPrev, melPitch)) {
|
|
530
565
|
continue;
|
|
531
566
|
}
|
|
532
567
|
}
|
|
@@ -547,7 +582,12 @@ function generateCounterMelody(opts) {
|
|
|
547
582
|
1,
|
|
548
583
|
Math.min(127, Math.round((_nullishCoalesce(_optionalChain([melNote, 'optionalAccess', _16 => _16.velocity]), () => ( DEFAULT_MELODY_VELOCITY))) - VELOCITY_DROP))
|
|
549
584
|
);
|
|
550
|
-
out.push({
|
|
585
|
+
out.push({
|
|
586
|
+
pitch: _chunkPI3UXRWKcjs.clampToMidi.call(void 0, pitch),
|
|
587
|
+
startBeat: beat,
|
|
588
|
+
durationBeat: endBeat - beat,
|
|
589
|
+
velocity
|
|
590
|
+
});
|
|
551
591
|
prevPitch = pitch;
|
|
552
592
|
}
|
|
553
593
|
return out;
|
|
@@ -819,13 +859,10 @@ function getGhostProbabilityAtPosition(beat, sixteenthInBeat) {
|
|
|
819
859
|
const leadsIntoBackbeat = (beat === 0 || beat === 2) && sixteenthInBeat === 3;
|
|
820
860
|
return leadsIntoBackbeat ? 0.6 : 0.25;
|
|
821
861
|
}
|
|
822
|
-
function selectGhostPositions(mood
|
|
862
|
+
function selectGhostPositions(mood) {
|
|
823
863
|
if (mood === 2 /* Energetic */) {
|
|
824
864
|
return ["e", "a"];
|
|
825
865
|
}
|
|
826
|
-
if (mood === 0 /* Calm */) {
|
|
827
|
-
return rng.prob(0.5) ? ["e"] : [];
|
|
828
|
-
}
|
|
829
866
|
return ["e"];
|
|
830
867
|
}
|
|
831
868
|
|
|
@@ -841,6 +878,9 @@ function roleHiHatInstrument(role, useRide) {
|
|
|
841
878
|
if (role === "ambient") {
|
|
842
879
|
return GM.RIDE;
|
|
843
880
|
}
|
|
881
|
+
if (role === "minimal") {
|
|
882
|
+
return GM.FHH;
|
|
883
|
+
}
|
|
844
884
|
return useRide ? GM.RIDE : GM.CHH;
|
|
845
885
|
}
|
|
846
886
|
function sparser(level) {
|
|
@@ -1161,7 +1201,7 @@ function generateGhostNotesForBeat(ctx, sec) {
|
|
|
1161
1201
|
if (ctx.beat !== 0 && ctx.beat !== 2) {
|
|
1162
1202
|
return;
|
|
1163
1203
|
}
|
|
1164
|
-
const positions = selectGhostPositions(sec.ghostMood
|
|
1204
|
+
const positions = selectGhostPositions(sec.ghostMood);
|
|
1165
1205
|
let ghostProb = getGhostDensity(sec.ghostMood, ctx.section, sec.backingDensity, ctx.bpm);
|
|
1166
1206
|
if (sec.ghostBoost) {
|
|
1167
1207
|
ghostProb = Math.min(1, ghostProb * 1.4);
|
|
@@ -1196,16 +1236,18 @@ function generatePreChorusBuildup(ctx, sec, isSectionLastBar) {
|
|
|
1196
1236
|
const progress = (barInLift * 4 + ctx.beat) / (barsInLift * 4);
|
|
1197
1237
|
const buildupVel = ctx.velocity * (0.5 + 0.5 * progress);
|
|
1198
1238
|
ctx.track.add(GM.SD, ctx.beatTick, EIGHTH, buildupVel);
|
|
1199
|
-
ctx.track.add(
|
|
1239
|
+
ctx.track.add(
|
|
1240
|
+
GM.SD,
|
|
1241
|
+
swing16(ctx.beatTick + EIGHTH, sec, ctx.swingAmount),
|
|
1242
|
+
EIGHTH,
|
|
1243
|
+
buildupVel * 0.85
|
|
1244
|
+
);
|
|
1200
1245
|
if (isSectionLastBar && ctx.beat === 3) {
|
|
1201
1246
|
ctx.track.add(GM.CRASH, ctx.beatTick + EIGHTH + SIXTEENTH, SIXTEENTH, ctx.velocity * 1.1);
|
|
1202
1247
|
}
|
|
1203
1248
|
}
|
|
1204
1249
|
function generateHiHatForBeat(ctx, sec) {
|
|
1205
1250
|
if (!shouldPlayHiHat(sec.role)) {
|
|
1206
|
-
if (sec.useFootHh && (ctx.beat === 0 || ctx.beat === 2)) {
|
|
1207
|
-
ctx.track.add(GM.FHH, ctx.beatTick, EIGHTH, footHiHatVelocity(ctx.rng));
|
|
1208
|
-
}
|
|
1209
1251
|
return;
|
|
1210
1252
|
}
|
|
1211
1253
|
const crossStick = sec.useRide && shouldUseBridgeCrossStick(ctx.section, ctx.beat);
|
|
@@ -1213,11 +1255,12 @@ function generateHiHatForBeat(ctx, sec) {
|
|
|
1213
1255
|
const hhType = sectionHiHatType(ctx.section, sec.role);
|
|
1214
1256
|
const typeMult = hiHatTypeVelocityMultiplier(hhType);
|
|
1215
1257
|
const isDynamicOpen = ctx.barHasOpenHh && ctx.beat === ctx.openHhBeat;
|
|
1258
|
+
const allowsOpenHiHat = sec.role !== "ambient" && sec.role !== "minimal";
|
|
1216
1259
|
const dm = sec.densityMult;
|
|
1217
1260
|
if (sec.hhLevel === "quarter") {
|
|
1218
1261
|
const introRest = ctx.section === "intro" && ctx.beat !== 0;
|
|
1219
1262
|
if (!introRest) {
|
|
1220
|
-
if (isDynamicOpen) {
|
|
1263
|
+
if (isDynamicOpen && allowsOpenHiHat) {
|
|
1221
1264
|
ctx.track.add(
|
|
1222
1265
|
GM.OHH,
|
|
1223
1266
|
ctx.beatTick,
|
|
@@ -1250,7 +1293,7 @@ function generateHiHatForBeat(ctx, sec) {
|
|
|
1250
1293
|
continue;
|
|
1251
1294
|
}
|
|
1252
1295
|
const hhVel = Math.max(20, ctx.velocity * dm * typeMult * (eighth === 0 ? 0.9 : 0.65));
|
|
1253
|
-
if (isDynamicOpen && eighth === 0) {
|
|
1296
|
+
if (isDynamicOpen && allowsOpenHiHat && eighth === 0) {
|
|
1254
1297
|
ctx.track.add(GM.OHH, hhTick, EIGHTH, hhVel + OHH_VEL_BOOST);
|
|
1255
1298
|
continue;
|
|
1256
1299
|
}
|
|
@@ -1261,7 +1304,7 @@ function generateHiHatForBeat(ctx, sec) {
|
|
|
1261
1304
|
} else if (eighth === 0) {
|
|
1262
1305
|
useOpen = shouldAddOpenHHAccent(ctx.section, ctx.beat, ctx.bar, ctx.rng);
|
|
1263
1306
|
}
|
|
1264
|
-
if (useOpen) {
|
|
1307
|
+
if (useOpen && allowsOpenHiHat) {
|
|
1265
1308
|
ctx.track.add(hiHatNote("open"), hhTick, EIGHTH, Math.max(20, hhVel * 1.1));
|
|
1266
1309
|
} else {
|
|
1267
1310
|
ctx.track.add(hhInstrument, hhTick, EIGHTH / 2, hhVel);
|
|
@@ -1276,11 +1319,11 @@ function generateHiHatForBeat(ctx, sec) {
|
|
|
1276
1319
|
}
|
|
1277
1320
|
const metricVel = hiHatVelocityMultiplier(sixteenth, ctx.rng);
|
|
1278
1321
|
const hhVel = Math.max(20, ctx.velocity * dm * typeMult * metricVel);
|
|
1279
|
-
if (isDynamicOpen && sixteenth === 0) {
|
|
1322
|
+
if (isDynamicOpen && allowsOpenHiHat && sixteenth === 0) {
|
|
1280
1323
|
ctx.track.add(GM.OHH, hhTick, SIXTEENTH, hhVel + OHH_VEL_BOOST);
|
|
1281
1324
|
continue;
|
|
1282
1325
|
}
|
|
1283
|
-
if (ctx.beat === 3 && sixteenth === 3) {
|
|
1326
|
+
if (allowsOpenHiHat && ctx.beat === 3 && sixteenth === 3) {
|
|
1284
1327
|
const openProb = Math.max(0.1, Math.min(0.4, 30 / ctx.bpm));
|
|
1285
1328
|
if (ctx.rng.prob(openProb)) {
|
|
1286
1329
|
ctx.track.add(GM.OHH, hhTick, SIXTEENTH, Math.max(20, hhVel * 1.2));
|
|
@@ -1293,10 +1336,10 @@ function generateHiHatForBeat(ctx, sec) {
|
|
|
1293
1336
|
|
|
1294
1337
|
// src/generate/drums/euclid.ts
|
|
1295
1338
|
function euclideanRhythm(pulses, steps, rotation = 0) {
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1339
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, steps, "euclidean steps");
|
|
1340
|
+
_chunkPI3UXRWKcjs.assertInteger.call(void 0, pulses, "euclidean pulses");
|
|
1341
|
+
_chunkPI3UXRWKcjs.assertInteger.call(void 0, rotation, "euclidean rotation");
|
|
1342
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, steps, "euclidean pattern steps");
|
|
1300
1343
|
const p = Math.max(0, Math.min(pulses, steps));
|
|
1301
1344
|
const base = bjorklund(p, steps);
|
|
1302
1345
|
const shift = (rotation % steps + steps) % steps;
|
|
@@ -1335,7 +1378,7 @@ function getFillStartBeat(energy) {
|
|
|
1335
1378
|
return 2;
|
|
1336
1379
|
case "high":
|
|
1337
1380
|
case "peak":
|
|
1338
|
-
return
|
|
1381
|
+
return 2;
|
|
1339
1382
|
}
|
|
1340
1383
|
}
|
|
1341
1384
|
function selectFillType(from, to, style, nextEnergy, rng) {
|
|
@@ -1600,7 +1643,7 @@ function generateFill(track, beatTick, beat, fillType, velocity) {
|
|
|
1600
1643
|
}
|
|
1601
1644
|
|
|
1602
1645
|
// src/generate/drums/hit.ts
|
|
1603
|
-
var DRUM_NOTES = {
|
|
1646
|
+
var DRUM_NOTES = Object.freeze({
|
|
1604
1647
|
kick: GM.BD,
|
|
1605
1648
|
snare: GM.SD,
|
|
1606
1649
|
sideStick: GM.SIDESTICK,
|
|
@@ -1615,7 +1658,7 @@ var DRUM_NOTES = {
|
|
|
1615
1658
|
midTom: GM.TOM_M,
|
|
1616
1659
|
lowTom: GM.TOM_L,
|
|
1617
1660
|
shaker: GM.SHAKER
|
|
1618
|
-
};
|
|
1661
|
+
});
|
|
1619
1662
|
var VOICE_BY_NOTE = new Map(
|
|
1620
1663
|
Object.entries(DRUM_NOTES).map(([voice, note]) => [note, voice])
|
|
1621
1664
|
);
|
|
@@ -1794,12 +1837,12 @@ function getPercussionConfig(mood, section) {
|
|
|
1794
1837
|
shaker16th: act[1]
|
|
1795
1838
|
};
|
|
1796
1839
|
}
|
|
1797
|
-
function generateAuxPercussionForBar(track, barStart, config, role, densityMult, rng, bpm) {
|
|
1840
|
+
function generateAuxPercussionForBar(track, barStart, config, role, densityMult, rng, bpm, sec, swingAmount, barBeats = 4) {
|
|
1798
1841
|
if (role === "minimal") {
|
|
1799
1842
|
return;
|
|
1800
1843
|
}
|
|
1801
1844
|
if (config.tambourine) {
|
|
1802
|
-
for (let beat = 1; beat
|
|
1845
|
+
for (let beat = 1; beat < barBeats; beat += 2) {
|
|
1803
1846
|
const raw = 70 * densityMult * rng.float(0.9, 1.1);
|
|
1804
1847
|
track.add(GM.TAMBOURINE, barStart + beat, EIGHTH, Math.max(40, Math.min(90, raw)));
|
|
1805
1848
|
}
|
|
@@ -1808,12 +1851,12 @@ function generateAuxPercussionForBar(track, barStart, config, role, densityMult,
|
|
|
1808
1851
|
const use16th = config.shaker16th && bpm < HH_16TH_BPM_THRESHOLD;
|
|
1809
1852
|
if (use16th) {
|
|
1810
1853
|
const velCurve = [0.75, 0.45, 0.6, 0.45];
|
|
1811
|
-
for (let beat = 0; beat <
|
|
1854
|
+
for (let beat = 0; beat < barBeats; beat += 1) {
|
|
1812
1855
|
for (let sub = 0; sub < 4; sub += 1) {
|
|
1813
1856
|
const raw = 80 * (_nullishCoalesce(velCurve[sub], () => ( 0.5))) * densityMult * rng.float(0.9, 1.1);
|
|
1814
1857
|
track.add(
|
|
1815
1858
|
GM.SHAKER,
|
|
1816
|
-
barStart + beat + sub * SIXTEENTH,
|
|
1859
|
+
swing16(barStart + beat + sub * SIXTEENTH, sec, swingAmount),
|
|
1817
1860
|
SIXTEENTH,
|
|
1818
1861
|
Math.max(25, Math.min(85, raw))
|
|
1819
1862
|
);
|
|
@@ -1821,12 +1864,12 @@ function generateAuxPercussionForBar(track, barStart, config, role, densityMult,
|
|
|
1821
1864
|
}
|
|
1822
1865
|
} else {
|
|
1823
1866
|
const velCurve = [0.75, 0.55];
|
|
1824
|
-
for (let beat = 0; beat <
|
|
1867
|
+
for (let beat = 0; beat < barBeats; beat += 1) {
|
|
1825
1868
|
for (let sub = 0; sub < 2; sub += 1) {
|
|
1826
1869
|
const raw = 80 * (_nullishCoalesce(velCurve[sub], () => ( 0.6))) * densityMult * rng.float(0.9, 1.1);
|
|
1827
1870
|
track.add(
|
|
1828
1871
|
GM.SHAKER,
|
|
1829
|
-
barStart + beat + sub * EIGHTH,
|
|
1872
|
+
swing16(barStart + beat + sub * EIGHTH, sec, swingAmount),
|
|
1830
1873
|
EIGHTH,
|
|
1831
1874
|
Math.max(25, Math.min(85, raw))
|
|
1832
1875
|
);
|
|
@@ -1835,7 +1878,7 @@ function generateAuxPercussionForBar(track, barStart, config, role, densityMult,
|
|
|
1835
1878
|
}
|
|
1836
1879
|
}
|
|
1837
1880
|
if (config.handclap) {
|
|
1838
|
-
for (let beat = 1; beat
|
|
1881
|
+
for (let beat = 1; beat < barBeats; beat += 2) {
|
|
1839
1882
|
const raw = 85 * densityMult * rng.float(0.9, 1.1);
|
|
1840
1883
|
track.add(GM.HANDCLAP, barStart + beat, EIGHTH, Math.max(50, Math.min(100, raw)));
|
|
1841
1884
|
}
|
|
@@ -1845,27 +1888,30 @@ function generateAuxPercussionForBar(track, barStart, config, role, densityMult,
|
|
|
1845
1888
|
// src/generate/drums/index.ts
|
|
1846
1889
|
var MAX_HITS_PER_BAR = 128;
|
|
1847
1890
|
function generateDrums(opts) {
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1891
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, opts.bars, "drum bars");
|
|
1892
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, opts.bpm, Number.MIN_VALUE, 1e3, "drum bpm");
|
|
1893
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, opts.density, 0, 1, "drum density");
|
|
1894
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, opts.bars * MAX_HITS_PER_BAR, "drum hits");
|
|
1852
1895
|
if (opts.euclideanKick) {
|
|
1853
1896
|
const steps = _nullishCoalesce(opts.euclideanKick.steps, () => ( 16));
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1897
|
+
_chunkPI3UXRWKcjs.assertInteger.call(void 0, steps, "euclidean steps", 1, 16);
|
|
1898
|
+
_chunkPI3UXRWKcjs.assertInteger.call(void 0, opts.euclideanKick.pulses, "euclidean pulses");
|
|
1899
|
+
_chunkPI3UXRWKcjs.assertInteger.call(void 0, _nullishCoalesce(opts.euclideanKick.rotation, () => ( 0)), "euclidean rotation");
|
|
1857
1900
|
}
|
|
1858
|
-
const publicStyle =
|
|
1859
|
-
const publicSection =
|
|
1901
|
+
const publicStyle = _chunkPI3UXRWKcjs.assertOneOf.call(void 0, opts.style, GROOVE_STYLES, "drum style");
|
|
1902
|
+
const publicSection = _chunkPI3UXRWKcjs.assertOneOf.call(void 0, opts.section, PUBLIC_SECTIONS, "drum section");
|
|
1860
1903
|
if (opts.nextSection !== void 0) {
|
|
1861
|
-
|
|
1904
|
+
_chunkPI3UXRWKcjs.assertOneOf.call(void 0, opts.nextSection, PUBLIC_SECTIONS, "drum nextSection");
|
|
1862
1905
|
}
|
|
1863
1906
|
const track = new HitList();
|
|
1864
|
-
const rng =
|
|
1907
|
+
const rng = _chunkMTMZTMWMcjs.createRng.call(void 0, _nullishCoalesce(opts.seed, () => ( 0)));
|
|
1865
1908
|
const mapping = mapStyle(publicStyle);
|
|
1866
1909
|
const style = mapping.style;
|
|
1867
|
-
const feel = opts.feel === void 0 ? mapping.feel :
|
|
1868
|
-
const role = opts.role === void 0 ? "full" :
|
|
1910
|
+
const feel = opts.feel === void 0 ? mapping.feel : _chunkPI3UXRWKcjs.assertOneOf.call(void 0, opts.feel, DRUM_FEELS, "drum feel");
|
|
1911
|
+
const role = opts.role === void 0 ? "full" : _chunkPI3UXRWKcjs.assertOneOf.call(void 0, opts.role, DRUM_ROLES, "drum role");
|
|
1912
|
+
const ts = _nullishCoalesce(opts.ts, () => ( { numerator: 4, denominator: 4 }));
|
|
1913
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts, "drum time signature");
|
|
1914
|
+
const barBeats = _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts);
|
|
1869
1915
|
const playMainVoices = role !== "fxOnly";
|
|
1870
1916
|
const section = mapSection(publicSection);
|
|
1871
1917
|
const backingDensity = mapDensity(opts.density);
|
|
@@ -1901,7 +1947,7 @@ function generateDrums(opts) {
|
|
|
1901
1947
|
const reuseSectionKick = (section === "b" || section === "chorus") && style !== "sparse";
|
|
1902
1948
|
let sectionKick;
|
|
1903
1949
|
for (let bar = 0; bar < opts.bars; bar += 1) {
|
|
1904
|
-
const barStart = bar *
|
|
1950
|
+
const barStart = bar * barBeats;
|
|
1905
1951
|
const isLastBar = bar === opts.bars - 1;
|
|
1906
1952
|
if (bar === 0 && section === "chorus") {
|
|
1907
1953
|
track.add(GM.CRASH, barStart, 0.5, 100 * densityMult);
|
|
@@ -1921,7 +1967,7 @@ function generateDrums(opts) {
|
|
|
1921
1967
|
}
|
|
1922
1968
|
const inLift = isInPreChorusLift(section, bar, opts.bars, nextSection === "chorus");
|
|
1923
1969
|
let currentFill = "snareRoll";
|
|
1924
|
-
for (let beat = 0; beat <
|
|
1970
|
+
for (let beat = 0; beat < barBeats; beat += 1) {
|
|
1925
1971
|
const beatTick = barStart + beat;
|
|
1926
1972
|
const velocity = calculateVelocity(section, beat);
|
|
1927
1973
|
if (opts.fills && isLastBar && !inLift && beat >= fillStartBeat) {
|
|
@@ -1958,14 +2004,14 @@ function generateDrums(opts) {
|
|
|
1958
2004
|
generatePreChorusBuildup(ctx, sec, isLastBar);
|
|
1959
2005
|
}
|
|
1960
2006
|
if (euclidKick && !inLift) {
|
|
1961
|
-
const stepLength =
|
|
2007
|
+
const stepLength = barBeats / euclidSteps;
|
|
1962
2008
|
for (let step = 0; step < euclidKick.length; step += 1) {
|
|
1963
2009
|
const onset = step * stepLength;
|
|
1964
2010
|
if (euclidKick[step] && Math.floor(onset) === beat) {
|
|
1965
2011
|
const wholeBeat = Math.abs(onset - Math.round(onset)) < 1e-9;
|
|
1966
2012
|
track.add(
|
|
1967
2013
|
GM.BD,
|
|
1968
|
-
barStart + onset,
|
|
2014
|
+
swing16(barStart + onset, sec, swingAmount),
|
|
1969
2015
|
Math.min(0.5, stepLength),
|
|
1970
2016
|
velocity * (wholeBeat ? 1 : 0.85)
|
|
1971
2017
|
);
|
|
@@ -1982,7 +2028,7 @@ function generateDrums(opts) {
|
|
|
1982
2028
|
generateHiHatForBeat(ctx, sec);
|
|
1983
2029
|
}
|
|
1984
2030
|
if (sec.useFootHh && shouldPlayHiHat(role)) {
|
|
1985
|
-
for (let fhhBeat = 0; fhhBeat <
|
|
2031
|
+
for (let fhhBeat = 0; fhhBeat < barBeats; fhhBeat += 2) {
|
|
1986
2032
|
const fhhTick = barStart + fhhBeat;
|
|
1987
2033
|
if (!track.hasOnset(GM.FHH, fhhTick)) {
|
|
1988
2034
|
track.add(GM.FHH, fhhTick, 0.5, footHiHatVelocity(rng));
|
|
@@ -2005,10 +2051,14 @@ function generateDrums(opts) {
|
|
|
2005
2051
|
role,
|
|
2006
2052
|
densityMult,
|
|
2007
2053
|
rng,
|
|
2008
|
-
opts.bpm
|
|
2054
|
+
opts.bpm,
|
|
2055
|
+
sec,
|
|
2056
|
+
swingAmount,
|
|
2057
|
+
barBeats
|
|
2009
2058
|
);
|
|
2010
2059
|
}
|
|
2011
|
-
|
|
2060
|
+
const endBeat = opts.bars * barBeats;
|
|
2061
|
+
return track.hits.filter((hit) => hit.startBeat < endBeat).sort((a, b) => a.startBeat - b.startBeat || a.pitch - b.pitch);
|
|
2012
2062
|
}
|
|
2013
2063
|
|
|
2014
2064
|
// src/generate/groove/index.ts
|
|
@@ -2023,22 +2073,22 @@ var MIN_VELOCITY = 1;
|
|
|
2023
2073
|
var MAX_VELOCITY = 127;
|
|
2024
2074
|
function humanize(events, opts = {}) {
|
|
2025
2075
|
const ts = _nullishCoalesce(opts.ts, () => ( DEFAULT_TS3));
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
const sounding =
|
|
2076
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
2077
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, events, "humanize events", { allowNonPositiveDuration: true });
|
|
2078
|
+
const sounding = _chunkPI3UXRWKcjs.dropSilentNotes.call(void 0, events);
|
|
2029
2079
|
const timing = _nullishCoalesce(opts.timing, () => ( DEFAULT_TIMING));
|
|
2030
2080
|
const velocityJitter = _nullishCoalesce(opts.velocity, () => ( DEFAULT_VELOCITY_JITTER));
|
|
2031
2081
|
const accent = _nullishCoalesce(opts.accent, () => ( DEFAULT_ACCENT));
|
|
2032
2082
|
const baseVelocity = _nullishCoalesce(opts.baseVelocity, () => ( DEFAULT_BASE_VELOCITY));
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
const rng =
|
|
2083
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, timing, 0, Number.MAX_SAFE_INTEGER, "humanize timing");
|
|
2084
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, velocityJitter, 0, 127, "humanize velocity jitter");
|
|
2085
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, accent, 0, 127, "humanize accent");
|
|
2086
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, baseVelocity, 0, 127, "humanize base velocity");
|
|
2087
|
+
const rng = _chunkMTMZTMWMcjs.createRng.call(void 0, _nullishCoalesce(opts.seed, () => ( 0)));
|
|
2038
2088
|
return sounding.map((event) => {
|
|
2039
2089
|
const timingOffset = rng.float(-timing, timing);
|
|
2040
2090
|
const startBeat = Math.max(0, event.startBeat + timingOffset);
|
|
2041
|
-
const weight =
|
|
2091
|
+
const weight = _chunk2A2QMA74cjs.metricWeight.call(void 0, event.startBeat, ts);
|
|
2042
2092
|
const accentBoost = weight / MAX_METRIC_WEIGHT * accent;
|
|
2043
2093
|
const velocityOffset = rng.float(-velocityJitter, velocityJitter);
|
|
2044
2094
|
const rawVelocity = (_nullishCoalesce(event.velocity, () => ( baseVelocity))) + accentBoost + velocityOffset;
|
|
@@ -2066,17 +2116,18 @@ function quantizeToGrid(beat, barBeats, subdivision, slotsPerBar) {
|
|
|
2066
2116
|
};
|
|
2067
2117
|
}
|
|
2068
2118
|
function extractGrooveTemplate(events, ts, subdivision = DEFAULT_GROOVE_SUBDIVISION) {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
const barBeats =
|
|
2073
|
-
const slotsPerBar = Math.
|
|
2074
|
-
|
|
2119
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
2120
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, events, "groove source events", { allowNonPositiveDuration: true });
|
|
2121
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, subdivision, "groove subdivision");
|
|
2122
|
+
const barBeats = _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts);
|
|
2123
|
+
const slotsPerBar = Math.ceil(barBeats * subdivision);
|
|
2124
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, slotsPerBar, "groove template slots");
|
|
2125
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, slotsPerBar, "groove template slots");
|
|
2075
2126
|
const offsetSums = new Array(slotsPerBar).fill(0);
|
|
2076
2127
|
const velocitySums = new Array(slotsPerBar).fill(0);
|
|
2077
2128
|
const counts = new Array(slotsPerBar).fill(0);
|
|
2078
2129
|
const velocityCounts = new Array(slotsPerBar).fill(0);
|
|
2079
|
-
for (const event of
|
|
2130
|
+
for (const event of _chunkPI3UXRWKcjs.dropSilentNotes.call(void 0, events)) {
|
|
2080
2131
|
const { quantizedBeat, slotIndex } = quantizeToGrid(
|
|
2081
2132
|
event.startBeat,
|
|
2082
2133
|
barBeats,
|
|
@@ -2106,21 +2157,21 @@ function extractGrooveTemplate(events, ts, subdivision = DEFAULT_GROOVE_SUBDIVIS
|
|
|
2106
2157
|
return { subdivision, slotsPerBar, slots, ts };
|
|
2107
2158
|
}
|
|
2108
2159
|
function applyGrooveTemplate(events, template, ts) {
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2160
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
2161
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, events, "groove target events", { allowNonPositiveDuration: true });
|
|
2162
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, template.subdivision, "template subdivision");
|
|
2163
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, template.slotsPerBar, "template slotsPerBar");
|
|
2164
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, template.slots.length, "template slots");
|
|
2114
2165
|
if (template.slots.length !== template.slotsPerBar) {
|
|
2115
|
-
throw new (0,
|
|
2166
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)("template slots length must equal slotsPerBar");
|
|
2116
2167
|
}
|
|
2117
2168
|
if (template.ts && (template.ts.numerator !== ts.numerator || template.ts.denominator !== ts.denominator)) {
|
|
2118
|
-
throw new (0,
|
|
2119
|
-
`Groove template meter ${
|
|
2169
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(
|
|
2170
|
+
`Groove template meter ${_chunk2A2QMA74cjs.formatTimeSignature.call(void 0, template.ts)} does not match apply-time meter ${_chunk2A2QMA74cjs.formatTimeSignature.call(void 0, ts)}`
|
|
2120
2171
|
);
|
|
2121
2172
|
}
|
|
2122
|
-
const barBeats =
|
|
2123
|
-
return
|
|
2173
|
+
const barBeats = _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts);
|
|
2174
|
+
return _chunkPI3UXRWKcjs.dropSilentNotes.call(void 0, events).map((event) => {
|
|
2124
2175
|
const { quantizedBeat, slotIndex } = quantizeToGrid(
|
|
2125
2176
|
event.startBeat,
|
|
2126
2177
|
barBeats,
|
|
@@ -2128,7 +2179,7 @@ function applyGrooveTemplate(events, template, ts) {
|
|
|
2128
2179
|
template.slotsPerBar
|
|
2129
2180
|
);
|
|
2130
2181
|
const slot = template.slots[slotIndex];
|
|
2131
|
-
const startBeat = quantizedBeat + (_nullishCoalesce(_optionalChain([slot, 'optionalAccess', _21 => _21.timingOffset]), () => ( 0)));
|
|
2182
|
+
const startBeat = Math.max(0, quantizedBeat + (_nullishCoalesce(_optionalChain([slot, 'optionalAccess', _21 => _21.timingOffset]), () => ( 0))));
|
|
2132
2183
|
const velocity = slot && slot.velocity !== null && slot.velocity !== void 0 ? Math.round(slot.velocity) : event.velocity;
|
|
2133
2184
|
return {
|
|
2134
2185
|
pitch: event.pitch,
|
|
@@ -2145,7 +2196,7 @@ var FALLBACK = {
|
|
|
2145
2196
|
quality: "maj",
|
|
2146
2197
|
secondaryDominant: false,
|
|
2147
2198
|
base: 0,
|
|
2148
|
-
pcs:
|
|
2199
|
+
pcs: _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, _chunkBSLTLGM3cjs.makeChord.call(void 0, 0, "maj"))
|
|
2149
2200
|
};
|
|
2150
2201
|
var DEFAULT_HARMONIC_RHYTHM = 2;
|
|
2151
2202
|
var DEFAULT_PLACEMENT = { transposeSearch: false, octaveSearch: false };
|
|
@@ -2155,21 +2206,21 @@ var COMFORT_HIGH = 79;
|
|
|
2155
2206
|
var TESSITURA_WEIGHT = 1e-3;
|
|
2156
2207
|
var TIE_BREAK_JITTER2 = 1e-6;
|
|
2157
2208
|
function inferKey(melody) {
|
|
2158
|
-
let best =
|
|
2209
|
+
let best = _chunkBSLTLGM3cjs.majorKey.call(void 0, 0);
|
|
2159
2210
|
let bestScore = Number.NEGATIVE_INFINITY;
|
|
2160
2211
|
const candidates = [];
|
|
2161
2212
|
for (let tonic = 0; tonic < 12; tonic += 1) {
|
|
2162
|
-
candidates.push(
|
|
2213
|
+
candidates.push(_chunkBSLTLGM3cjs.majorKey.call(void 0, tonic), _chunkBSLTLGM3cjs.minorKey.call(void 0, tonic));
|
|
2163
2214
|
}
|
|
2164
2215
|
for (const key of candidates) {
|
|
2165
|
-
const tonic =
|
|
2166
|
-
const isMinor = key.modeMask12 ===
|
|
2216
|
+
const tonic = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
2217
|
+
const isMinor = key.modeMask12 === _chunkBSLTLGM3cjs.NATURAL_MINOR_MASK;
|
|
2167
2218
|
const leadingTone = (tonic + 11) % 12;
|
|
2168
2219
|
let score = 0;
|
|
2169
2220
|
for (const n of melody) {
|
|
2170
2221
|
const w = Math.max(0.25, n.durationBeat);
|
|
2171
|
-
const pc =
|
|
2172
|
-
if (
|
|
2222
|
+
const pc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, n.pitch);
|
|
2223
|
+
if (_chunkBSLTLGM3cjs.isScaleTone.call(void 0, n.pitch, key) || isMinor && pc === leadingTone) {
|
|
2173
2224
|
score += w;
|
|
2174
2225
|
}
|
|
2175
2226
|
if (pc === tonic) {
|
|
@@ -2184,16 +2235,16 @@ function inferKey(melody) {
|
|
|
2184
2235
|
return best;
|
|
2185
2236
|
}
|
|
2186
2237
|
function buildCandidates(key, reharmonize) {
|
|
2187
|
-
const tones =
|
|
2238
|
+
const tones = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, key);
|
|
2188
2239
|
const candidates = tones.map((rootPc, degree) => {
|
|
2189
|
-
const quality =
|
|
2240
|
+
const quality = _chunkBSLTLGM3cjs.diatonicTriad.call(void 0, degree, key).quality;
|
|
2190
2241
|
return {
|
|
2191
2242
|
rootPc,
|
|
2192
2243
|
quality,
|
|
2193
2244
|
degree,
|
|
2194
2245
|
secondaryDominant: false,
|
|
2195
2246
|
base: 0,
|
|
2196
|
-
pcs:
|
|
2247
|
+
pcs: _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, _chunkBSLTLGM3cjs.makeChord.call(void 0, rootPc, quality))
|
|
2197
2248
|
};
|
|
2198
2249
|
});
|
|
2199
2250
|
if (reharmonize !== "diatonic") {
|
|
@@ -2206,22 +2257,22 @@ function buildCandidates(key, reharmonize) {
|
|
|
2206
2257
|
secondaryDominant: true,
|
|
2207
2258
|
targetDegree: target,
|
|
2208
2259
|
base: 1.5,
|
|
2209
|
-
pcs:
|
|
2260
|
+
pcs: _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, _chunkBSLTLGM3cjs.makeChord.call(void 0, rootPc, "dom7"))
|
|
2210
2261
|
});
|
|
2211
2262
|
}
|
|
2212
2263
|
}
|
|
2213
2264
|
if (reharmonize === "borrowed") {
|
|
2214
|
-
const parallel =
|
|
2215
|
-
const parallelTones =
|
|
2265
|
+
const parallel = _chunkKQN2ZYNDcjs.parallelKey.call(void 0, key);
|
|
2266
|
+
const parallelTones = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, parallel);
|
|
2216
2267
|
for (let degree = 0; degree < parallelTones.length; degree += 1) {
|
|
2217
|
-
const chord =
|
|
2218
|
-
if (!
|
|
2268
|
+
const chord = _chunkBSLTLGM3cjs.diatonicTriad.call(void 0, degree, parallel);
|
|
2269
|
+
if (!_chunkKQN2ZYNDcjs.isDiatonic.call(void 0, chord, key)) {
|
|
2219
2270
|
candidates.push({
|
|
2220
2271
|
rootPc: chord.rootPc,
|
|
2221
2272
|
quality: chord.quality,
|
|
2222
2273
|
secondaryDominant: false,
|
|
2223
2274
|
base: 1.25,
|
|
2224
|
-
pcs:
|
|
2275
|
+
pcs: _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord)
|
|
2225
2276
|
});
|
|
2226
2277
|
}
|
|
2227
2278
|
}
|
|
@@ -2250,12 +2301,12 @@ function emissionCost(seg, cand, melody, key, ts) {
|
|
|
2250
2301
|
continue;
|
|
2251
2302
|
}
|
|
2252
2303
|
const w = Math.max(0.25, overlap);
|
|
2253
|
-
if (pcs.includes(
|
|
2304
|
+
if (pcs.includes(_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, note.pitch))) {
|
|
2254
2305
|
continue;
|
|
2255
2306
|
}
|
|
2256
|
-
const strong =
|
|
2307
|
+
const strong = _chunk2A2QMA74cjs.isStrongBeat.call(void 0, overlapStart, ts);
|
|
2257
2308
|
cost += (strong ? 10 : 2) * w;
|
|
2258
|
-
if (!
|
|
2309
|
+
if (!_chunkBSLTLGM3cjs.isScaleTone.call(void 0, note.pitch, key)) {
|
|
2259
2310
|
cost += w;
|
|
2260
2311
|
}
|
|
2261
2312
|
}
|
|
@@ -2288,7 +2339,7 @@ function transitionCost(prev, cur, tonicPc) {
|
|
|
2288
2339
|
return cost;
|
|
2289
2340
|
}
|
|
2290
2341
|
function harmonizeOnce(melody, key, candidates, segments, jitter, ts) {
|
|
2291
|
-
const tonicPc =
|
|
2342
|
+
const tonicPc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
2292
2343
|
const n = candidates.length;
|
|
2293
2344
|
const candAt = (i) => _nullishCoalesce(candidates[i], () => ( FALLBACK));
|
|
2294
2345
|
const seg0 = segments[0];
|
|
@@ -2338,43 +2389,49 @@ function harmonizeOnce(melody, key, candidates, segments, jitter, ts) {
|
|
|
2338
2389
|
return { cost: bestCost, path };
|
|
2339
2390
|
}
|
|
2340
2391
|
function harmonizeMelody(opts) {
|
|
2341
|
-
|
|
2392
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, opts.melody, "harmonize melody", { allowNonPositiveDuration: true });
|
|
2393
|
+
const soundingMelody = _chunkPI3UXRWKcjs.soundingNotesOnly.call(void 0, opts.melody);
|
|
2394
|
+
const noteIndex = _chunk2A2QMA74cjs.createNoteEventIndex.call(void 0, soundingMelody);
|
|
2342
2395
|
const ts = _nullishCoalesce(opts.ts, () => ( DEFAULT_METER));
|
|
2343
|
-
|
|
2396
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
2344
2397
|
const requestedKey = _nullishCoalesce(opts.key, () => ( "infer"));
|
|
2345
|
-
const key = requestedKey === "infer" ? inferKey(
|
|
2398
|
+
const key = requestedKey === "infer" ? inferKey(soundingMelody) : requestedKey;
|
|
2346
2399
|
const placement = _nullishCoalesce(opts.placement, () => ( DEFAULT_PLACEMENT));
|
|
2347
|
-
if (noteIndex.notes.
|
|
2400
|
+
if (noteIndex.notes.length === 0) {
|
|
2348
2401
|
return { transposeSemitones: 0, key, chords: [], melodyRoles: [] };
|
|
2349
2402
|
}
|
|
2350
2403
|
const candidates = buildCandidates(key, _nullishCoalesce(opts.reharmonize, () => ( "diatonic")));
|
|
2351
2404
|
const candAt = (i) => _nullishCoalesce(candidates[i], () => ( FALLBACK));
|
|
2352
|
-
const rng =
|
|
2405
|
+
const rng = _chunkMTMZTMWMcjs.createRng.call(void 0, _nullishCoalesce(opts.seed, () => ( 0)));
|
|
2353
2406
|
const jitter = candidates.map(() => rng.next() * TIE_BREAK_JITTER2);
|
|
2354
|
-
const
|
|
2355
|
-
|
|
2407
|
+
const melodyStart = noteIndex.notes.reduce(
|
|
2408
|
+
(start, indexed) => Math.min(start, indexed.note.startBeat),
|
|
2409
|
+
Number.POSITIVE_INFINITY
|
|
2410
|
+
);
|
|
2411
|
+
const melodyEnd = noteIndex.notes.reduce((end, indexed) => Math.max(end, indexed.endBeat), 0);
|
|
2412
|
+
const hr = _chunkPI3UXRWKcjs.assertRange.call(void 0,
|
|
2356
2413
|
_nullishCoalesce(opts.harmonicRhythm, () => ( DEFAULT_HARMONIC_RHYTHM)),
|
|
2357
2414
|
Number.MIN_VALUE,
|
|
2358
2415
|
Number.MAX_SAFE_INTEGER,
|
|
2359
2416
|
"harmonic rhythm"
|
|
2360
2417
|
);
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2363
|
-
|
|
2418
|
+
const segmentStart = Math.floor(melodyStart / hr) * hr;
|
|
2419
|
+
const segCount = Math.max(1, Math.ceil((melodyEnd - segmentStart) / hr));
|
|
2420
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, segCount, "harmonic segments");
|
|
2364
2421
|
const segments = Array.from({ length: segCount }, (_, s) => ({
|
|
2365
|
-
startBeat: s * hr,
|
|
2366
|
-
endBeat: (s + 1) * hr,
|
|
2422
|
+
startBeat: segmentStart + s * hr,
|
|
2423
|
+
endBeat: segmentStart + (s + 1) * hr,
|
|
2367
2424
|
noteIndices: []
|
|
2368
2425
|
}));
|
|
2369
2426
|
let memberships = 0;
|
|
2370
2427
|
for (const indexed of noteIndex.notes) {
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2428
|
+
const first = Math.max(0, Math.floor((indexed.note.startBeat - segmentStart) / hr));
|
|
2429
|
+
const lastExclusive = Math.min(
|
|
2430
|
+
segCount,
|
|
2431
|
+
Math.ceil((indexed.endBeat - segmentStart) / hr - Number.EPSILON)
|
|
2432
|
+
);
|
|
2376
2433
|
memberships += Math.max(0, lastExclusive - first);
|
|
2377
|
-
|
|
2434
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, memberships, "note-to-segment memberships");
|
|
2378
2435
|
for (let segment = first; segment < lastExclusive; segment += 1) {
|
|
2379
2436
|
_optionalChain([segments, 'access', _22 => _22[segment], 'optionalAccess', _23 => _23.noteIndices, 'access', _24 => _24.push, 'call', _25 => _25(indexed.originalIndex)]);
|
|
2380
2437
|
}
|
|
@@ -2394,6 +2451,10 @@ function harmonizeMelody(opts) {
|
|
|
2394
2451
|
}
|
|
2395
2452
|
}
|
|
2396
2453
|
}
|
|
2454
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0,
|
|
2455
|
+
transposes.length * segCount * candidates.length * candidates.length,
|
|
2456
|
+
"harmonization placement search"
|
|
2457
|
+
);
|
|
2397
2458
|
let bestCost = Number.POSITIVE_INFINITY;
|
|
2398
2459
|
let bestTs = 0;
|
|
2399
2460
|
let bestPath = [];
|
|
@@ -2414,7 +2475,7 @@ function harmonizeMelody(opts) {
|
|
|
2414
2475
|
const chord = {
|
|
2415
2476
|
rootPc: cand.rootPc,
|
|
2416
2477
|
quality: cand.quality,
|
|
2417
|
-
startBeat: _nullishCoalesce(_optionalChain([segments, 'access', _26 => _26[s], 'optionalAccess', _27 => _27.startBeat]), () => ( s * hr))
|
|
2478
|
+
startBeat: _nullishCoalesce(_optionalChain([segments, 'access', _26 => _26[s], 'optionalAccess', _27 => _27.startBeat]), () => ( segmentStart + s * hr))
|
|
2418
2479
|
};
|
|
2419
2480
|
if (cand.degree !== void 0) {
|
|
2420
2481
|
chord.degree = cand.degree;
|
|
@@ -2427,8 +2488,8 @@ function harmonizeMelody(opts) {
|
|
|
2427
2488
|
const melodyRoles = bestMelody.map((note, noteIndex2) => {
|
|
2428
2489
|
const segIdx = Math.min(segments.length - 1, Math.max(0, Math.floor(note.startBeat / hr)));
|
|
2429
2490
|
const cand = candAt(_nullishCoalesce(bestPath[segIdx], () => ( 0)));
|
|
2430
|
-
const chord =
|
|
2431
|
-
return { noteIndex: noteIndex2, role:
|
|
2491
|
+
const chord = _chunkBSLTLGM3cjs.makeChord.call(void 0, cand.rootPc, cand.quality);
|
|
2492
|
+
return { noteIndex: noteIndex2, role: _chunkYFJXS3AUcjs.roleOf.call(void 0, note.pitch, chord).role };
|
|
2432
2493
|
});
|
|
2433
2494
|
return { transposeSemitones: bestTs, key, chords, melodyRoles };
|
|
2434
2495
|
}
|
|
@@ -2443,7 +2504,7 @@ function isDownbeat(startBeat, barBeats) {
|
|
|
2443
2504
|
}
|
|
2444
2505
|
function upScaleTone(pitch, key) {
|
|
2445
2506
|
for (let d = 1; d <= 12; d += 1) {
|
|
2446
|
-
if (
|
|
2507
|
+
if (_chunkBSLTLGM3cjs.isScaleTone.call(void 0, pitch + d, key)) {
|
|
2447
2508
|
return pitch + d;
|
|
2448
2509
|
}
|
|
2449
2510
|
}
|
|
@@ -2451,14 +2512,14 @@ function upScaleTone(pitch, key) {
|
|
|
2451
2512
|
}
|
|
2452
2513
|
function downScaleTone(pitch, key) {
|
|
2453
2514
|
for (let d = 1; d <= 12; d += 1) {
|
|
2454
|
-
if (
|
|
2515
|
+
if (_chunkBSLTLGM3cjs.isScaleTone.call(void 0, pitch - d, key)) {
|
|
2455
2516
|
return pitch - d;
|
|
2456
2517
|
}
|
|
2457
2518
|
}
|
|
2458
2519
|
return pitch - 12;
|
|
2459
2520
|
}
|
|
2460
2521
|
function stepDiatonic(pitch, degrees, key) {
|
|
2461
|
-
let p =
|
|
2522
|
+
let p = _chunkBSLTLGM3cjs.nearestScaleTone.call(void 0, pitch, key);
|
|
2462
2523
|
const steps = Math.abs(Math.trunc(degrees));
|
|
2463
2524
|
for (let i = 0; i < steps; i += 1) {
|
|
2464
2525
|
p = degrees >= 0 ? upScaleTone(p, key) : downScaleTone(p, key);
|
|
@@ -2466,12 +2527,12 @@ function stepDiatonic(pitch, degrees, key) {
|
|
|
2466
2527
|
return p;
|
|
2467
2528
|
}
|
|
2468
2529
|
function nearestChordTone(pitch, chord) {
|
|
2469
|
-
const pcs =
|
|
2530
|
+
const pcs = _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord);
|
|
2470
2531
|
for (let d = 0; d <= 12; d += 1) {
|
|
2471
|
-
if (pcs.includes(
|
|
2532
|
+
if (pcs.includes(_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, pitch - d))) {
|
|
2472
2533
|
return pitch - d;
|
|
2473
2534
|
}
|
|
2474
|
-
if (pcs.includes(
|
|
2535
|
+
if (pcs.includes(_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, pitch + d))) {
|
|
2475
2536
|
return pitch + d;
|
|
2476
2537
|
}
|
|
2477
2538
|
}
|
|
@@ -2524,16 +2585,16 @@ function contourOffsets(contour, count) {
|
|
|
2524
2585
|
}
|
|
2525
2586
|
function generateMotif(opts) {
|
|
2526
2587
|
const contour = _nullishCoalesce(opts.contour, () => ( "arch"));
|
|
2527
|
-
const bars =
|
|
2528
|
-
const barBeats =
|
|
2588
|
+
const bars = _chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, opts.bars, "motif bars");
|
|
2589
|
+
const barBeats = _chunk2A2QMA74cjs.beatsPerBar.call(void 0, _nullishCoalesce(opts.ts, () => ( DEFAULT_TS4)));
|
|
2529
2590
|
const totalBeats = bars * barBeats;
|
|
2530
2591
|
const noteCount = Math.max(3, bars * 2);
|
|
2531
|
-
|
|
2592
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, noteCount, "motif notes");
|
|
2532
2593
|
const beatsPerNote = totalBeats / noteCount;
|
|
2533
|
-
const rng =
|
|
2534
|
-
const requestedJitter =
|
|
2594
|
+
const rng = _chunkMTMZTMWMcjs.createRng.call(void 0, _nullishCoalesce(opts.seed, () => ( 0)));
|
|
2595
|
+
const requestedJitter = _chunkPI3UXRWKcjs.assertFiniteNumber.call(void 0, _nullishCoalesce(opts.jitter, () => ( 0)), "motif jitter");
|
|
2535
2596
|
const jitterProb = Math.min(1, Math.max(0, requestedJitter));
|
|
2536
|
-
const tonic =
|
|
2597
|
+
const tonic = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, opts.key.rootPc) + 60;
|
|
2537
2598
|
const offsets = contourOffsets(contour, noteCount);
|
|
2538
2599
|
const notes = [];
|
|
2539
2600
|
for (let i = 0; i < noteCount; i += 1) {
|
|
@@ -2546,7 +2607,11 @@ function generateMotif(opts) {
|
|
|
2546
2607
|
if (opts.chord && isDownbeat(startBeat, barBeats)) {
|
|
2547
2608
|
pitch = nearestChordTone(pitch, opts.chord);
|
|
2548
2609
|
}
|
|
2549
|
-
notes.push({
|
|
2610
|
+
notes.push({
|
|
2611
|
+
pitch: _chunkPI3UXRWKcjs.clampToMidi.call(void 0, pitch, "generated motif pitch"),
|
|
2612
|
+
startBeat,
|
|
2613
|
+
durationBeat: beatsPerNote
|
|
2614
|
+
});
|
|
2550
2615
|
}
|
|
2551
2616
|
return { notes };
|
|
2552
2617
|
}
|
|
@@ -2559,7 +2624,7 @@ function transformMotif(cell, t, amount, key) {
|
|
|
2559
2624
|
function assertInRange(cell) {
|
|
2560
2625
|
for (const note of cell.notes) {
|
|
2561
2626
|
if (note.pitch < 0 || note.pitch > 127) {
|
|
2562
|
-
throw new (0,
|
|
2627
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(
|
|
2563
2628
|
`transformed motif pitch ${note.pitch} is outside the MIDI range 0..127`
|
|
2564
2629
|
);
|
|
2565
2630
|
}
|
|
@@ -2567,15 +2632,18 @@ function assertInRange(cell) {
|
|
|
2567
2632
|
return cell;
|
|
2568
2633
|
}
|
|
2569
2634
|
function transformUnchecked(cell, t, amount, key) {
|
|
2570
|
-
|
|
2635
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, cell.notes, "motif notes");
|
|
2571
2636
|
if (amount !== void 0) {
|
|
2572
|
-
|
|
2637
|
+
_chunkPI3UXRWKcjs.assertFiniteNumber.call(void 0, amount, "motif transform amount");
|
|
2573
2638
|
}
|
|
2574
|
-
if ((t === "transposeDiatonic" || t === "sequence") && amount !== void 0) {
|
|
2575
|
-
|
|
2639
|
+
if ((t === "transposeChromatic" || t === "transposeDiatonic" || t === "sequence") && amount !== void 0) {
|
|
2640
|
+
_chunkPI3UXRWKcjs.assertInteger.call(void 0,
|
|
2641
|
+
amount,
|
|
2642
|
+
`${t === "transposeChromatic" ? "chromatic" : "diatonic"} transform amount`
|
|
2643
|
+
);
|
|
2576
2644
|
}
|
|
2577
2645
|
if ((t === "augment" || t === "diminish") && amount !== void 0 && amount <= 0) {
|
|
2578
|
-
throw new (0,
|
|
2646
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)("time transform amount must be positive");
|
|
2579
2647
|
}
|
|
2580
2648
|
const notes = cell.notes;
|
|
2581
2649
|
switch (t) {
|
|
@@ -2636,10 +2704,10 @@ function scaleTime(cell, factor) {
|
|
|
2636
2704
|
};
|
|
2637
2705
|
}
|
|
2638
2706
|
function developMotif(cell, timeline, key, bars, ts = DEFAULT_TS4) {
|
|
2639
|
-
|
|
2640
|
-
|
|
2707
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, bars, "development bars");
|
|
2708
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, cell.notes, "motif notes");
|
|
2641
2709
|
const span = cellSpan(cell);
|
|
2642
|
-
const totalBeats = bars *
|
|
2710
|
+
const totalBeats = bars * _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts);
|
|
2643
2711
|
const origin = cellOrigin(cell.notes);
|
|
2644
2712
|
const out = [];
|
|
2645
2713
|
if (span <= 0) {
|
|
@@ -2647,7 +2715,7 @@ function developMotif(cell, timeline, key, bars, ts = DEFAULT_TS4) {
|
|
|
2647
2715
|
}
|
|
2648
2716
|
const tileSpan = Math.max(span, MIN_TILE_SPAN);
|
|
2649
2717
|
const tileCount = Math.ceil(totalBeats / tileSpan);
|
|
2650
|
-
|
|
2718
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, tileCount * cell.notes.length, "developed motif notes");
|
|
2651
2719
|
for (let k = 0; k < tileCount; k += 1) {
|
|
2652
2720
|
const offset = k * tileSpan;
|
|
2653
2721
|
for (const n of cell.notes) {
|
|
@@ -2658,10 +2726,10 @@ function developMotif(cell, timeline, key, bars, ts = DEFAULT_TS4) {
|
|
|
2658
2726
|
const chord = timeline.at(startBeat);
|
|
2659
2727
|
let pitch = n.pitch;
|
|
2660
2728
|
if (chord) {
|
|
2661
|
-
const isMember =
|
|
2729
|
+
const isMember = _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord).includes(_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, pitch));
|
|
2662
2730
|
pitch = isMember ? pitch : nearestChordTone(pitch, chord);
|
|
2663
2731
|
} else {
|
|
2664
|
-
pitch =
|
|
2732
|
+
pitch = _chunkBSLTLGM3cjs.nearestScaleTone.call(void 0, pitch, key);
|
|
2665
2733
|
}
|
|
2666
2734
|
out.push({ pitch, startBeat, durationBeat: n.durationBeat });
|
|
2667
2735
|
}
|
|
@@ -2670,7 +2738,7 @@ function developMotif(cell, timeline, key, bars, ts = DEFAULT_TS4) {
|
|
|
2670
2738
|
}
|
|
2671
2739
|
|
|
2672
2740
|
// src/generate/progression/index.ts
|
|
2673
|
-
var BORROWED_DEGREES = {
|
|
2741
|
+
var BORROWED_DEGREES = Object.freeze({
|
|
2674
2742
|
/** Flat submediant: bVI. */
|
|
2675
2743
|
bVI: 8,
|
|
2676
2744
|
/** Flat subtonic: bVII. */
|
|
@@ -2683,7 +2751,7 @@ var BORROWED_DEGREES = {
|
|
|
2683
2751
|
bII: 13,
|
|
2684
2752
|
/** Sharp subdominant, the diminished #IV. */
|
|
2685
2753
|
sharpIV: 14
|
|
2686
|
-
};
|
|
2754
|
+
});
|
|
2687
2755
|
var PRESETS = [
|
|
2688
2756
|
{
|
|
2689
2757
|
id: "fourChordPop",
|
|
@@ -2856,15 +2924,19 @@ function progressionsByStyle(style) {
|
|
|
2856
2924
|
}
|
|
2857
2925
|
function degreeToRootPc(degree, key) {
|
|
2858
2926
|
if (degree >= 0 && degree <= 6) {
|
|
2859
|
-
const tones =
|
|
2927
|
+
const tones = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, key);
|
|
2860
2928
|
return tones.length > 0 ? _nullishCoalesce(tones[degree % tones.length], () => ( key.rootPc % 12)) : key.rootPc % 12;
|
|
2861
2929
|
}
|
|
2862
2930
|
const offset = _nullishCoalesce(BORROWED_OFFSET[degree], () => ( 0));
|
|
2863
2931
|
return ((key.rootPc % 12 + offset) % 12 + 12) % 12;
|
|
2864
2932
|
}
|
|
2865
|
-
function autoQuality(degree, key) {
|
|
2933
|
+
function autoQuality(degree, key, harmonicDominant) {
|
|
2866
2934
|
if (degree >= 0 && degree <= 6) {
|
|
2867
|
-
|
|
2935
|
+
const isMinor = (key.modeMask12 >> 3 & 1) === 1 && (key.modeMask12 >> 4 & 1) === 0;
|
|
2936
|
+
if (harmonicDominant && isMinor && degree === 4) {
|
|
2937
|
+
return "maj";
|
|
2938
|
+
}
|
|
2939
|
+
return _chunkBSLTLGM3cjs.diatonicTriad.call(void 0, degree, key).quality;
|
|
2868
2940
|
}
|
|
2869
2941
|
if (degree === 14) {
|
|
2870
2942
|
return "dim";
|
|
@@ -2874,13 +2946,13 @@ function autoQuality(degree, key) {
|
|
|
2874
2946
|
}
|
|
2875
2947
|
return "maj";
|
|
2876
2948
|
}
|
|
2877
|
-
function resolveCycle(degrees, key, ext) {
|
|
2949
|
+
function resolveCycle(degrees, key, ext, harmonicDominant) {
|
|
2878
2950
|
const steps = [];
|
|
2879
2951
|
for (const degree of degrees) {
|
|
2880
2952
|
const step = {
|
|
2881
2953
|
source: degree,
|
|
2882
2954
|
rootPc: degreeToRootPc(degree, key),
|
|
2883
|
-
quality: ext !== void 0 && ext !== "auto" ? ext : autoQuality(degree, key)
|
|
2955
|
+
quality: ext !== void 0 && ext !== "auto" ? ext : autoQuality(degree, key, harmonicDominant)
|
|
2884
2956
|
};
|
|
2885
2957
|
if (degree >= 0 && degree <= 6) {
|
|
2886
2958
|
step.degree = degree;
|
|
@@ -2904,25 +2976,34 @@ function sameStep(a, b) {
|
|
|
2904
2976
|
function pickProgressionPreset(style, seed = 0) {
|
|
2905
2977
|
const pool = PRESETS.filter((preset) => preset.styles.includes(style));
|
|
2906
2978
|
if (pool.length === 0) {
|
|
2907
|
-
throw new (0,
|
|
2979
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`Unknown progression style: ${style}`);
|
|
2908
2980
|
}
|
|
2909
|
-
const rng =
|
|
2981
|
+
const rng = _chunkMTMZTMWMcjs.createRng.call(void 0, seed);
|
|
2910
2982
|
const index = Math.floor(rng.next() * pool.length) % pool.length;
|
|
2911
2983
|
return _nullishCoalesce(pool[index], () => ( PRESETS[0]));
|
|
2912
2984
|
}
|
|
2913
2985
|
function generateProgression(opts) {
|
|
2914
|
-
|
|
2915
|
-
|
|
2986
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, opts.bars, "progression bars");
|
|
2987
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, opts.bars, "progression chords");
|
|
2916
2988
|
const seed = _nullishCoalesce(opts.seed, () => ( 0));
|
|
2917
2989
|
let preset;
|
|
2918
2990
|
if (opts.preset !== void 0) {
|
|
2919
2991
|
if (opts.preset.degrees.length === 0) {
|
|
2920
|
-
throw new (0,
|
|
2992
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)("progression preset must name at least one degree");
|
|
2921
2993
|
}
|
|
2922
2994
|
preset = {
|
|
2923
2995
|
id: _nullishCoalesce(opts.preset.id, () => ( "custom")),
|
|
2924
2996
|
name: _nullishCoalesce(opts.preset.name, () => ( "Custom")),
|
|
2925
|
-
degrees: opts.preset.degrees,
|
|
2997
|
+
degrees: opts.preset.degrees.map((degree, index) => {
|
|
2998
|
+
_chunkPI3UXRWKcjs.assertDegree.call(void 0, degree, `progression preset degrees[${index}]`);
|
|
2999
|
+
const supported = degree >= 0 && degree <= 6 || Object.values(BORROWED_DEGREES).includes(degree);
|
|
3000
|
+
if (!supported) {
|
|
3001
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(
|
|
3002
|
+
`progression preset degrees[${index}] is not a supported progression degree; received ${degree}`
|
|
3003
|
+
);
|
|
3004
|
+
}
|
|
3005
|
+
return degree;
|
|
3006
|
+
}),
|
|
2926
3007
|
functional: _nullishCoalesce(opts.preset.functional, () => ( "loop")),
|
|
2927
3008
|
styles: _nullishCoalesce(opts.preset.styles, () => ( [opts.style]))
|
|
2928
3009
|
};
|
|
@@ -2930,27 +3011,34 @@ function generateProgression(opts) {
|
|
|
2930
3011
|
if (preset === void 0 && opts.presetId !== void 0) {
|
|
2931
3012
|
preset = PRESETS.find((p) => p.id === opts.presetId);
|
|
2932
3013
|
if (preset === void 0) {
|
|
2933
|
-
throw new (0,
|
|
3014
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`Unknown progression preset: ${opts.presetId}`);
|
|
2934
3015
|
}
|
|
2935
3016
|
}
|
|
2936
3017
|
preset ??= pickProgressionPreset(opts.style, seed);
|
|
2937
|
-
const
|
|
3018
|
+
const ext = opts.ext === void 0 ? "auto" : _chunkPI3UXRWKcjs.assertOneOf.call(void 0, opts.ext, ["auto", ..._chunkBSLTLGM3cjs.chordQualities.call(void 0, )], "progression extension");
|
|
3019
|
+
const cycle = resolveCycle(
|
|
3020
|
+
_nullishCoalesce(_optionalChain([preset, 'optionalAccess', _30 => _30.degrees]), () => ( [0])),
|
|
3021
|
+
opts.key,
|
|
3022
|
+
ext,
|
|
3023
|
+
_optionalChain([preset, 'optionalAccess', _31 => _31.functional]) === "cadenceStrong"
|
|
3024
|
+
);
|
|
2938
3025
|
const chords = [];
|
|
2939
3026
|
for (let bar = 0; bar < opts.bars; bar += 1) {
|
|
2940
3027
|
const step = cycle[bar % cycle.length];
|
|
2941
3028
|
const chord = {
|
|
2942
|
-
rootPc: _nullishCoalesce(_optionalChain([step, 'optionalAccess',
|
|
2943
|
-
quality: _nullishCoalesce(_optionalChain([step, 'optionalAccess',
|
|
3029
|
+
rootPc: _nullishCoalesce(_optionalChain([step, 'optionalAccess', _32 => _32.rootPc]), () => ( 0)),
|
|
3030
|
+
quality: _nullishCoalesce(_optionalChain([step, 'optionalAccess', _33 => _33.quality]), () => ( "maj")),
|
|
2944
3031
|
startBeat: bar * 4
|
|
2945
3032
|
};
|
|
2946
|
-
if (_optionalChain([step, 'optionalAccess',
|
|
3033
|
+
if (_optionalChain([step, 'optionalAccess', _34 => _34.degree]) !== void 0) {
|
|
2947
3034
|
chord.degree = step.degree;
|
|
2948
3035
|
}
|
|
2949
3036
|
chords.push(chord);
|
|
2950
3037
|
}
|
|
2951
3038
|
if (opts.reharmonize) {
|
|
2952
3039
|
const tonicPc = (opts.key.rootPc % 12 + 12) % 12;
|
|
2953
|
-
const rrng =
|
|
3040
|
+
const rrng = _chunkMTMZTMWMcjs.createRng.call(void 0, (seed ^ 2654435769) >>> 0);
|
|
3041
|
+
let tonicStatements = chords.filter((chord) => chord.rootPc === tonicPc).length;
|
|
2954
3042
|
for (let i = 0; i < chords.length - 1; i += 1) {
|
|
2955
3043
|
const cur = chords[i];
|
|
2956
3044
|
const next = chords[i + 1];
|
|
@@ -2959,12 +3047,16 @@ function generateProgression(opts) {
|
|
|
2959
3047
|
}
|
|
2960
3048
|
const domRoot = (next.rootPc + 7) % 12;
|
|
2961
3049
|
const targetsTonic = (next.rootPc - tonicPc + 12) % 12 === 0;
|
|
3050
|
+
const isLastTonicStatement = cur.rootPc === tonicPc && tonicStatements <= 1;
|
|
2962
3051
|
const alreadySecondary = cur.rootPc === domRoot && cur.quality === "dom7";
|
|
2963
|
-
const isResolutionTarget = _optionalChain([chords, 'access',
|
|
2964
|
-
if (targetsTonic || alreadySecondary || isResolutionTarget) {
|
|
3052
|
+
const isResolutionTarget = _optionalChain([chords, 'access', _35 => _35[i - 1], 'optionalAccess', _36 => _36.secondaryDominant]) === true;
|
|
3053
|
+
if (targetsTonic || isLastTonicStatement || alreadySecondary || isResolutionTarget) {
|
|
2965
3054
|
continue;
|
|
2966
3055
|
}
|
|
2967
3056
|
if (rrng.next() < 0.5) {
|
|
3057
|
+
if (cur.rootPc === tonicPc) {
|
|
3058
|
+
tonicStatements -= 1;
|
|
3059
|
+
}
|
|
2968
3060
|
chords[i] = {
|
|
2969
3061
|
rootPc: domRoot,
|
|
2970
3062
|
quality: "dom7",
|
|
@@ -2980,8 +3072,8 @@ function generateProgression(opts) {
|
|
|
2980
3072
|
// src/generate/rhythm/index.ts
|
|
2981
3073
|
var DEFAULT_RHYTHM_VELOCITY = 96;
|
|
2982
3074
|
function rhythmToNoteEvents(events, pitch, velocity = DEFAULT_RHYTHM_VELOCITY) {
|
|
2983
|
-
|
|
2984
|
-
|
|
3075
|
+
_chunkPI3UXRWKcjs.assertFiniteNumber.call(void 0, pitch, "pitch");
|
|
3076
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, velocity, 0, 127, "velocity");
|
|
2985
3077
|
return events.map((event) => ({
|
|
2986
3078
|
pitch,
|
|
2987
3079
|
startBeat: event.position,
|
|
@@ -3008,27 +3100,34 @@ function generateRhythm(ts, opts = {}) {
|
|
|
3008
3100
|
const seed = _nullishCoalesce(opts.seed, () => ( 0));
|
|
3009
3101
|
const bars = _nullishCoalesce(opts.bars, () => ( DEFAULT_BARS));
|
|
3010
3102
|
const subdivision = _nullishCoalesce(opts.subdivision, () => ( DEFAULT_SUBDIVISION));
|
|
3011
|
-
const density =
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
const barBeats =
|
|
3103
|
+
const density = _chunkPI3UXRWKcjs.assertRange.call(void 0, _nullishCoalesce(opts.density, () => ( DEFAULT_DENSITY)), 0, 1, "rhythm density");
|
|
3104
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, bars, "rhythm bars");
|
|
3105
|
+
_chunkPI3UXRWKcjs.assertPositiveInt.call(void 0, subdivision, "rhythm subdivision");
|
|
3106
|
+
const barBeats = _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts);
|
|
3015
3107
|
const spanBeats = barBeats * bars;
|
|
3016
3108
|
const step = 1 / subdivision;
|
|
3017
|
-
const
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
const rng =
|
|
3109
|
+
const slotsPerBar = Math.ceil(barBeats * subdivision);
|
|
3110
|
+
const slotCount = slotsPerBar * bars;
|
|
3111
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, slotCount, "rhythm grid slots");
|
|
3112
|
+
const rng = _chunkMTMZTMWMcjs.createRng.call(void 0, seed);
|
|
3021
3113
|
const positions = [];
|
|
3022
|
-
for (let
|
|
3023
|
-
const
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3114
|
+
for (let bar = 0; bar < bars; bar += 1) {
|
|
3115
|
+
const barStart = bar * barBeats;
|
|
3116
|
+
const barEnd = barStart + barBeats;
|
|
3117
|
+
for (let slot = 0; slot < slotsPerBar; slot += 1) {
|
|
3118
|
+
const position = barStart + slot * step;
|
|
3119
|
+
if (position >= barEnd - Number.EPSILON) {
|
|
3120
|
+
break;
|
|
3121
|
+
}
|
|
3122
|
+
if (slot === 0) {
|
|
3123
|
+
positions.push(position);
|
|
3124
|
+
continue;
|
|
3125
|
+
}
|
|
3126
|
+
const weight = _chunk2A2QMA74cjs.metricWeight.call(void 0, position, ts);
|
|
3127
|
+
const probability = onsetWeightCurve(weight) * density;
|
|
3128
|
+
if (rng.prob(probability)) {
|
|
3129
|
+
positions.push(position);
|
|
3130
|
+
}
|
|
3032
3131
|
}
|
|
3033
3132
|
}
|
|
3034
3133
|
const events = [];
|
|
@@ -3044,8 +3143,8 @@ function rhythmDensity(events, ts) {
|
|
|
3044
3143
|
return 0;
|
|
3045
3144
|
}
|
|
3046
3145
|
const last = events[events.length - 1];
|
|
3047
|
-
const spanBeats = (_nullishCoalesce(_optionalChain([last, 'optionalAccess',
|
|
3048
|
-
const bars = spanBeats /
|
|
3146
|
+
const spanBeats = (_nullishCoalesce(_optionalChain([last, 'optionalAccess', _37 => _37.position]), () => ( 0))) + (_nullishCoalesce(_optionalChain([last, 'optionalAccess', _38 => _38.duration]), () => ( 0)));
|
|
3147
|
+
const bars = spanBeats / _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts);
|
|
3049
3148
|
return bars > 0 ? events.length / bars : 0;
|
|
3050
3149
|
}
|
|
3051
3150
|
|
|
@@ -3074,4 +3173,4 @@ function rhythmDensity(events, ts) {
|
|
|
3074
3173
|
|
|
3075
3174
|
|
|
3076
3175
|
exports.BASS_STYLES = BASS_STYLES; exports.generateBassLine = generateBassLine; exports.generateCounterMelody = generateCounterMelody; exports.DRUM_NOTES = DRUM_NOTES; exports.drumVoiceOf = drumVoiceOf; exports.generateDrums = generateDrums; exports.humanize = humanize; exports.extractGrooveTemplate = extractGrooveTemplate; exports.applyGrooveTemplate = applyGrooveTemplate; exports.harmonizeMelody = harmonizeMelody; exports.generateMotif = generateMotif; exports.motifToNoteEvents = motifToNoteEvents; exports.transformMotif = transformMotif; exports.developMotif = developMotif; exports.BORROWED_DEGREES = BORROWED_DEGREES; exports.progressions = progressions; exports.progressionsByStyle = progressionsByStyle; exports.pickProgressionPreset = pickProgressionPreset; exports.generateProgression = generateProgression; exports.rhythmToNoteEvents = rhythmToNoteEvents; exports.onsetWeightCurve = onsetWeightCurve; exports.generateRhythm = generateRhythm; exports.rhythmDensity = rhythmDensity;
|
|
3077
|
-
//# sourceMappingURL=chunk-
|
|
3176
|
+
//# sourceMappingURL=chunk-MPTVJIVG.cjs.map
|