@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
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunk2A2QMA74cjs = require('./chunk-2A2QMA74.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
var _chunkKQN2ZYNDcjs = require('./chunk-KQN2ZYND.cjs');
|
|
13
14
|
|
|
14
|
-
var _chunkCAN76NCUcjs = require('./chunk-CAN76NCU.cjs');
|
|
15
15
|
|
|
16
|
+
var _chunkWFDXOLUBcjs = require('./chunk-WFDXOLUB.cjs');
|
|
16
17
|
|
|
17
|
-
var _chunkQ6OP4U43cjs = require('./chunk-Q6OP4U43.cjs');
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
@@ -24,8 +24,8 @@ var _chunkQ6OP4U43cjs = require('./chunk-Q6OP4U43.cjs');
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
var _chunkBSLTLGM3cjs = require('./chunk-BSLTLGM3.cjs');
|
|
27
28
|
|
|
28
|
-
var _chunkFNDWXRRIcjs = require('./chunk-FNDWXRRI.cjs');
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
|
|
@@ -33,16 +33,15 @@ var _chunkFNDWXRRIcjs = require('./chunk-FNDWXRRI.cjs');
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
var _chunk7MGZ7D62cjs = require('./chunk-7MGZ7D62.cjs');
|
|
36
|
+
var _chunkPI3UXRWKcjs = require('./chunk-PI3UXRWK.cjs');
|
|
38
37
|
|
|
39
38
|
// src/analyze/timeline/index.ts
|
|
40
39
|
function chordTimelineFromChords(chords, totalBeats) {
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "timeline totalBeats");
|
|
41
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, chords.length, "timeline chords");
|
|
43
42
|
for (let index = 0; index < chords.length; index += 1) {
|
|
44
|
-
|
|
45
|
-
_nullishCoalesce(_optionalChain([chords, 'access',
|
|
43
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0,
|
|
44
|
+
_nullishCoalesce(_optionalChain([chords, 'access', _ => _[index], 'optionalAccess', _2 => _2.startBeat]), () => ( Number.NaN)),
|
|
46
45
|
0,
|
|
47
46
|
Number.MAX_SAFE_INTEGER,
|
|
48
47
|
`chords[${index}].startBeat`
|
|
@@ -56,19 +55,19 @@ function chordTimelineFromChords(chords, totalBeats) {
|
|
|
56
55
|
return {
|
|
57
56
|
startBeat: gc.startBeat,
|
|
58
57
|
endBeat,
|
|
59
|
-
chord:
|
|
58
|
+
chord: _chunkBSLTLGM3cjs.makeChord.call(void 0, gc.rootPc, gc.quality, gc.bassPc)
|
|
60
59
|
};
|
|
61
60
|
}).filter((seg) => seg.endBeat > seg.startBeat);
|
|
62
61
|
return { at: segmentLookup(segments), segments };
|
|
63
62
|
}
|
|
64
63
|
function segmentLookup(segments) {
|
|
65
64
|
return (beat) => {
|
|
66
|
-
|
|
65
|
+
_chunkPI3UXRWKcjs.assertFiniteNumber.call(void 0, beat, "timeline query beat");
|
|
67
66
|
let low = 0;
|
|
68
67
|
let high = segments.length;
|
|
69
68
|
while (low < high) {
|
|
70
69
|
const middle = Math.floor((low + high) / 2);
|
|
71
|
-
if ((_nullishCoalesce(_optionalChain([segments, 'access',
|
|
70
|
+
if ((_nullishCoalesce(_optionalChain([segments, 'access', _3 => _3[middle], 'optionalAccess', _4 => _4.startBeat]), () => ( Number.POSITIVE_INFINITY))) <= beat) {
|
|
72
71
|
low = middle + 1;
|
|
73
72
|
} else {
|
|
74
73
|
high = middle;
|
|
@@ -81,16 +80,15 @@ function segmentLookup(segments) {
|
|
|
81
80
|
var EPS = 1e-9;
|
|
82
81
|
var NOISE_THRESHOLD_RATIO = 0.2;
|
|
83
82
|
var MAX_DETECTION_PCS = 6;
|
|
84
|
-
var FALLBACK_PCS = 3;
|
|
85
83
|
var INEXACT_CONFIDENCE_FACTOR = 0.85;
|
|
86
84
|
var DIATONIC_BONUS = 0.5;
|
|
87
85
|
var EXACT_BONUS = 0.5;
|
|
88
86
|
var MISMATCH_PENALTY = 0.3;
|
|
89
87
|
function scoreMatch(match, weights, maxWeight, key) {
|
|
90
88
|
const rootWeight = maxWeight > 0 ? (_nullishCoalesce(weights[match.rootPc], () => ( 0))) / maxWeight : 0;
|
|
91
|
-
const tones =
|
|
89
|
+
const tones = _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, _chunkBSLTLGM3cjs.makeChord.call(void 0, match.rootPc, match.quality));
|
|
92
90
|
let score = rootWeight;
|
|
93
|
-
if (tones.every((pc) =>
|
|
91
|
+
if (tones.every((pc) => _chunkBSLTLGM3cjs.isScaleTone.call(void 0, pc, key))) {
|
|
94
92
|
score += DIATONIC_BONUS;
|
|
95
93
|
}
|
|
96
94
|
if (match.exact) {
|
|
@@ -100,7 +98,7 @@ function scoreMatch(match, weights, maxWeight, key) {
|
|
|
100
98
|
return score;
|
|
101
99
|
}
|
|
102
100
|
function chordConfidence(chord, weights, totalWeight, exact) {
|
|
103
|
-
const tones = new Set(
|
|
101
|
+
const tones = new Set(_chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord));
|
|
104
102
|
let chordWeight = 0;
|
|
105
103
|
for (let pc = 0; pc < 12; pc += 1) {
|
|
106
104
|
if (tones.has(pc)) {
|
|
@@ -122,8 +120,8 @@ function analyzeWindow(notes, windowStart, windowEnd, ts, key) {
|
|
|
122
120
|
}
|
|
123
121
|
const velocityFactor = note.velocity !== void 0 ? note.velocity / 127 : 1;
|
|
124
122
|
const onsetInWindow = note.startBeat >= windowStart - EPS && note.startBeat < windowEnd - EPS;
|
|
125
|
-
const accent = onsetInWindow ? 1 +
|
|
126
|
-
const pc =
|
|
123
|
+
const accent = onsetInWindow ? 1 + _chunk2A2QMA74cjs.metricWeight.call(void 0, note.startBeat, ts) / 3 : 1;
|
|
124
|
+
const pc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, note.pitch);
|
|
127
125
|
weights[pc] = (_nullishCoalesce(weights[pc], () => ( 0))) + overlap * velocityFactor * accent;
|
|
128
126
|
if (note.pitch < lowestPitch) {
|
|
129
127
|
lowestPitch = note.pitch;
|
|
@@ -140,10 +138,10 @@ function analyzeWindow(notes, windowStart, windowEnd, ts, key) {
|
|
|
140
138
|
}
|
|
141
139
|
const ranked = weights.map((weight, pc) => ({ pc, weight })).filter(({ weight }) => weight > 0).sort((a, b) => b.weight - a.weight || a.pc - b.pc);
|
|
142
140
|
const selected = ranked.filter(({ weight }) => weight >= maxWeight * NOISE_THRESHOLD_RATIO).slice(0, MAX_DETECTION_PCS).map(({ pc }) => pc);
|
|
143
|
-
const bassPc =
|
|
144
|
-
const
|
|
145
|
-
const detectionPitches = selected.map((pc) => pc ===
|
|
146
|
-
const matches =
|
|
141
|
+
const bassPc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, lowestPitch);
|
|
142
|
+
const hasBass = selected.includes(bassPc);
|
|
143
|
+
const detectionPitches = hasBass ? selected.map((pc) => pc === bassPc ? pc : pc + 12) : selected;
|
|
144
|
+
const matches = _chunkKQN2ZYNDcjs.detectChord.call(void 0, detectionPitches, { input: hasBass ? "midi" : "pitchClass" });
|
|
147
145
|
let bestMatch = null;
|
|
148
146
|
let bestScore = Number.NEGATIVE_INFINITY;
|
|
149
147
|
for (const match of matches) {
|
|
@@ -154,47 +152,43 @@ function analyzeWindow(notes, windowStart, windowEnd, ts, key) {
|
|
|
154
152
|
}
|
|
155
153
|
}
|
|
156
154
|
if (bestMatch) {
|
|
157
|
-
const chord =
|
|
155
|
+
const chord = _chunkBSLTLGM3cjs.makeChord.call(void 0, bestMatch.rootPc, bestMatch.quality, bestMatch.bassPc);
|
|
158
156
|
return { chord, confidence: chordConfidence(chord, weights, totalWeight, bestMatch.exact) };
|
|
159
157
|
}
|
|
160
|
-
const fallback = _chunkCAN76NCUcjs.detectChordBest.call(void 0, selected.slice(0, FALLBACK_PCS));
|
|
161
|
-
if (fallback) {
|
|
162
|
-
return { chord: fallback, confidence: chordConfidence(fallback, weights, totalWeight, false) };
|
|
163
|
-
}
|
|
164
158
|
return null;
|
|
165
159
|
}
|
|
166
160
|
function sameChord(a, b) {
|
|
167
161
|
return a.rootPc === b.rootPc && a.quality === b.quality && a.bassPc === b.bassPc;
|
|
168
162
|
}
|
|
169
163
|
function chordTimelineFromNotes(notes, opts = {}) {
|
|
170
|
-
const ts = _nullishCoalesce(opts.ts, () => (
|
|
171
|
-
|
|
172
|
-
const harmonicRhythm = _nullishCoalesce(opts.harmonicRhythm, () => (
|
|
173
|
-
|
|
164
|
+
const ts = _nullishCoalesce(opts.ts, () => ( _chunk2A2QMA74cjs.parseTimeSignature.call(void 0, "4/4")));
|
|
165
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
166
|
+
const harmonicRhythm = _nullishCoalesce(opts.harmonicRhythm, () => ( _chunk2A2QMA74cjs.beatsPerBar.call(void 0, ts)));
|
|
167
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, harmonicRhythm, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "harmonic rhythm");
|
|
174
168
|
const budget = opts.budget;
|
|
175
|
-
|
|
176
|
-
const soundingIndex =
|
|
169
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, notes, "timeline notes", { allowNonPositiveDuration: true, budget });
|
|
170
|
+
const soundingIndex = _chunk2A2QMA74cjs.createNoteEventIndex.call(void 0,
|
|
177
171
|
notes.filter((note) => note.durationBeat > 0),
|
|
178
172
|
{ name: "timeline notes", budget }
|
|
179
173
|
);
|
|
180
174
|
const sounding = soundingIndex.notes.map(({ note }) => note);
|
|
181
175
|
const lastNoteEnd = sounding.reduce((end, n) => Math.max(end, n.startBeat + n.durationBeat), 0);
|
|
182
176
|
const totalBeats = _nullishCoalesce(opts.totalBeats, () => ( lastNoteEnd));
|
|
183
|
-
|
|
184
|
-
const key = _nullishCoalesce(_nullishCoalesce(opts.key, () => ( _optionalChain([
|
|
177
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, totalBeats, 0, Number.MAX_SAFE_INTEGER, "timeline totalBeats");
|
|
178
|
+
const key = _nullishCoalesce(_nullishCoalesce(opts.key, () => ( _optionalChain([_chunkKQN2ZYNDcjs.detectKeyFromNotes.call(void 0, sounding, { budget }), 'access', _5 => _5[0], 'optionalAccess', _6 => _6.key]))), () => ( _chunkBSLTLGM3cjs.majorKey.call(void 0, 0)));
|
|
185
179
|
const segments = [];
|
|
186
180
|
const segmentConfidence = [];
|
|
187
181
|
const windowCount = Math.max(0, Math.ceil(totalBeats / harmonicRhythm - EPS));
|
|
188
|
-
|
|
182
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, windowCount, "timeline windows", budget);
|
|
189
183
|
const windowNotes = Array.from({ length: windowCount }, () => []);
|
|
190
184
|
let memberships = 0;
|
|
191
185
|
for (const indexed of soundingIndex.notes) {
|
|
192
186
|
const first = Math.max(0, Math.floor(indexed.note.startBeat / harmonicRhythm));
|
|
193
187
|
const lastExclusive = Math.min(windowCount, Math.ceil(indexed.endBeat / harmonicRhythm));
|
|
194
188
|
memberships += Math.max(0, lastExclusive - first);
|
|
195
|
-
|
|
189
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, memberships, "timeline note-to-window memberships", budget);
|
|
196
190
|
for (let window = first; window < lastExclusive; window += 1) {
|
|
197
|
-
_optionalChain([windowNotes, 'access',
|
|
191
|
+
_optionalChain([windowNotes, 'access', _7 => _7[window], 'optionalAccess', _8 => _8.push, 'call', _9 => _9(indexed.note)]);
|
|
198
192
|
}
|
|
199
193
|
}
|
|
200
194
|
for (let i = 0; i < windowCount; i += 1) {
|
|
@@ -233,7 +227,7 @@ function detectCadences(timeline, key) {
|
|
|
233
227
|
if (Math.abs(cur.startBeat - prev.endBeat) > EPS) {
|
|
234
228
|
continue;
|
|
235
229
|
}
|
|
236
|
-
const type =
|
|
230
|
+
const type = _chunkKQN2ZYNDcjs.detectCadence.call(void 0, prev.chord, cur.chord, key);
|
|
237
231
|
if (type !== null) {
|
|
238
232
|
hits.push({ atBeat: cur.startBeat, type, from: prev.chord, to: cur.chord });
|
|
239
233
|
}
|
|
@@ -270,12 +264,15 @@ function poolNotes(tracks, only) {
|
|
|
270
264
|
}
|
|
271
265
|
function splitIntoSubVoices(ordered) {
|
|
272
266
|
const lanes = [];
|
|
273
|
-
|
|
267
|
+
const attachNearest = (note, excluded = /* @__PURE__ */ new Set()) => {
|
|
274
268
|
let best = -1;
|
|
275
269
|
let bestDistance = Number.POSITIVE_INFINITY;
|
|
276
270
|
let bestEnd = Number.NEGATIVE_INFINITY;
|
|
277
271
|
for (let lane = 0; lane < lanes.length; lane += 1) {
|
|
278
|
-
|
|
272
|
+
if (excluded.has(lane)) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const last = _optionalChain([lanes, 'access', _10 => _10[lane], 'optionalAccess', _11 => _11[(_nullishCoalesce(_optionalChain([lanes, 'access', _12 => _12[lane], 'optionalAccess', _13 => _13.length]), () => ( 0))) - 1]]);
|
|
279
276
|
if (last === void 0) {
|
|
280
277
|
continue;
|
|
281
278
|
}
|
|
@@ -294,10 +291,40 @@ function splitIntoSubVoices(ordered) {
|
|
|
294
291
|
}
|
|
295
292
|
}
|
|
296
293
|
if (best >= 0) {
|
|
297
|
-
_optionalChain([lanes, 'access',
|
|
294
|
+
_optionalChain([lanes, 'access', _14 => _14[best], 'optionalAccess', _15 => _15.push, 'call', _16 => _16(note)]);
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
};
|
|
299
|
+
for (let start = 0; start < ordered.length; ) {
|
|
300
|
+
const onset = _nullishCoalesce(_optionalChain([ordered, 'access', _17 => _17[start], 'optionalAccess', _18 => _18.startBeat]), () => ( 0));
|
|
301
|
+
let end = start + 1;
|
|
302
|
+
while (end < ordered.length && Math.abs((_nullishCoalesce(_optionalChain([ordered, 'access', _19 => _19[end], 'optionalAccess', _20 => _20.startBeat]), () => ( 0))) - onset) <= EPS2) {
|
|
303
|
+
end += 1;
|
|
304
|
+
}
|
|
305
|
+
const block = ordered.slice(start, end);
|
|
306
|
+
if (block.length > 1) {
|
|
307
|
+
const freeLanes = lanes.map((lane, index) => ({ index, last: lane[lane.length - 1] })).filter(
|
|
308
|
+
(entry) => entry.last !== void 0 && entry.last.startBeat + entry.last.durationBeat <= onset + EPS2
|
|
309
|
+
).sort((a, b) => a.last.pitch - b.last.pitch);
|
|
310
|
+
const paired = /* @__PURE__ */ new Set();
|
|
311
|
+
for (let index = 0; index < block.length; index += 1) {
|
|
312
|
+
const note = block[index];
|
|
313
|
+
const lane = freeLanes[index];
|
|
314
|
+
if (note !== void 0 && lane !== void 0 && Math.abs(lane.last.pitch - note.pitch) <= MAX_LANE_LEAP) {
|
|
315
|
+
_optionalChain([lanes, 'access', _21 => _21[lane.index], 'optionalAccess', _22 => _22.push, 'call', _23 => _23(note)]);
|
|
316
|
+
paired.add(lane.index);
|
|
317
|
+
} else if (note !== void 0 && !attachNearest(note, paired)) {
|
|
318
|
+
lanes.push([note]);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
298
321
|
} else {
|
|
299
|
-
|
|
322
|
+
const note = block[0];
|
|
323
|
+
if (note !== void 0 && !attachNearest(note)) {
|
|
324
|
+
lanes.push([note]);
|
|
325
|
+
}
|
|
300
326
|
}
|
|
327
|
+
start = end;
|
|
301
328
|
}
|
|
302
329
|
return lanes;
|
|
303
330
|
}
|
|
@@ -306,7 +333,7 @@ function lastStartingAtOrBefore(sounding, beat) {
|
|
|
306
333
|
let high = sounding.length;
|
|
307
334
|
while (low < high) {
|
|
308
335
|
const middle = Math.floor((low + high) / 2);
|
|
309
|
-
if ((_nullishCoalesce(_optionalChain([sounding, 'access',
|
|
336
|
+
if ((_nullishCoalesce(_optionalChain([sounding, 'access', _24 => _24[middle], 'optionalAccess', _25 => _25.startBeat]), () => ( Number.POSITIVE_INFINITY))) <= beat + EPS2) {
|
|
310
337
|
low = middle + 1;
|
|
311
338
|
} else {
|
|
312
339
|
high = middle;
|
|
@@ -325,7 +352,7 @@ function prepareTracks(tracks) {
|
|
|
325
352
|
const contiguous = prevEnd !== void 0 && Math.abs(prevEnd - note.startBeat) <= EPS2;
|
|
326
353
|
return {
|
|
327
354
|
pitch: note.pitch,
|
|
328
|
-
prevPitch: contiguous ? _optionalChain([prev, 'optionalAccess',
|
|
355
|
+
prevPitch: contiguous ? _optionalChain([prev, 'optionalAccess', _26 => _26.pitch]) : void 0,
|
|
329
356
|
startBeat: note.startBeat,
|
|
330
357
|
endBeat: note.startBeat + note.durationBeat
|
|
331
358
|
};
|
|
@@ -362,19 +389,19 @@ function clamp01(value) {
|
|
|
362
389
|
return Math.min(1, Math.max(0, value));
|
|
363
390
|
}
|
|
364
391
|
function tensionCurve(tracks, opts = {}) {
|
|
365
|
-
const ts = _nullishCoalesce(opts.ts, () => (
|
|
366
|
-
|
|
392
|
+
const ts = _nullishCoalesce(opts.ts, () => ( _chunk2A2QMA74cjs.parseTimeSignature.call(void 0, "4/4")));
|
|
393
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
367
394
|
const budget = opts.budget;
|
|
368
|
-
|
|
395
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, tracks.length, "arrangement tracks", budget);
|
|
369
396
|
for (let index = 0; index < tracks.length; index += 1) {
|
|
370
|
-
|
|
397
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, _nullishCoalesce(_optionalChain([tracks, 'access', _27 => _27[index], 'optionalAccess', _28 => _28.notes]), () => ( [])), `tracks[${index}].notes`, {
|
|
371
398
|
allowNonPositiveDuration: true,
|
|
372
399
|
budget
|
|
373
400
|
});
|
|
374
401
|
}
|
|
375
402
|
const profile = _nullishCoalesce(opts.profile, () => ( "pop"));
|
|
376
403
|
const step = _nullishCoalesce(opts.step, () => ( 1));
|
|
377
|
-
|
|
404
|
+
_chunkPI3UXRWKcjs.assertRange.call(void 0, step, Number.MIN_VALUE, Number.MAX_SAFE_INTEGER, "tension sampling step");
|
|
378
405
|
const harmonyTracks = opts.harmonyTracks === void 0 ? void 0 : new Set(opts.harmonyTracks.map(Math.trunc));
|
|
379
406
|
const pooled = poolNotes(tracks, harmonyTracks);
|
|
380
407
|
const totalBeats = poolNotes(tracks).reduce(
|
|
@@ -388,14 +415,18 @@ function tensionCurve(tracks, opts = {}) {
|
|
|
388
415
|
budget
|
|
389
416
|
}) : {
|
|
390
417
|
timeline: opts.timeline,
|
|
391
|
-
key: _nullishCoalesce(_nullishCoalesce(opts.key, () => ( _optionalChain([
|
|
418
|
+
key: _nullishCoalesce(_nullishCoalesce(opts.key, () => ( _optionalChain([_chunkKQN2ZYNDcjs.detectKeyFromNotes.call(void 0, pooled, { budget }), 'access', _29 => _29[0], 'optionalAccess', _30 => _30.key]))), () => ( _chunkBSLTLGM3cjs.majorKey.call(void 0, 0)))
|
|
392
419
|
};
|
|
393
420
|
const prepared = prepareTracks(tracks);
|
|
394
421
|
const points = [];
|
|
395
422
|
const sampleCount = Math.max(0, Math.ceil(totalBeats / step - EPS2));
|
|
396
|
-
|
|
423
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, sampleCount, "tension samples", budget);
|
|
397
424
|
const voiceCount = prepared.reduce((sum, track) => sum + track.voices.length, 0);
|
|
398
|
-
|
|
425
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0,
|
|
426
|
+
sampleCount * Math.min(128, voiceCount) * voiceCount,
|
|
427
|
+
"tension sample-voice comparisons",
|
|
428
|
+
budget
|
|
429
|
+
);
|
|
399
430
|
for (let i = 0; i < sampleCount; i += 1) {
|
|
400
431
|
const beat = i * step;
|
|
401
432
|
points.push({ beat, tension: sampleTension(prepared, timeline, key, ts, profile, beat) });
|
|
@@ -427,24 +458,28 @@ function sampleTension(prepared, timeline, key, ts, profile, beat) {
|
|
|
427
458
|
return 0;
|
|
428
459
|
}
|
|
429
460
|
const chord = timeline.at(beat);
|
|
430
|
-
const functionScore = chord ? FUNCTION_TENSION[
|
|
431
|
-
const chordPcs = chord ? new Set(
|
|
432
|
-
const strongBeat =
|
|
461
|
+
const functionScore = chord ? FUNCTION_TENSION[_chunkKQN2ZYNDcjs.functionOf.call(void 0, chord, key)] : 0;
|
|
462
|
+
const chordPcs = chord ? new Set(_chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord)) : null;
|
|
463
|
+
const strongBeat = _chunk2A2QMA74cjs.isStrongBeat.call(void 0, beat, ts);
|
|
433
464
|
let nonChord = 0;
|
|
434
465
|
let dissonant = 0;
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (chordPcs && !chordPcs.has(
|
|
441
|
-
nonChord +=
|
|
466
|
+
const pitches = /* @__PURE__ */ new Map();
|
|
467
|
+
for (const voice of sounding) {
|
|
468
|
+
pitches.set(voice.pitch, (_nullishCoalesce(pitches.get(voice.pitch), () => ( 0))) + 1);
|
|
469
|
+
}
|
|
470
|
+
for (const [pitch, count] of pitches) {
|
|
471
|
+
if (chordPcs && !chordPcs.has(_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, pitch))) {
|
|
472
|
+
nonChord += count;
|
|
442
473
|
}
|
|
443
|
-
const others =
|
|
444
|
-
|
|
474
|
+
const others = [...pitches].flatMap(
|
|
475
|
+
([otherPitch, otherCount]) => Array.from({ length: otherCount - (otherPitch === pitch ? 1 : 0) }, () => ({
|
|
476
|
+
pitch: otherPitch
|
|
477
|
+
}))
|
|
478
|
+
);
|
|
479
|
+
const result = _chunkWFDXOLUBcjs.evaluateSafety.call(void 0,
|
|
445
480
|
{
|
|
446
481
|
profile,
|
|
447
|
-
candidatePitch:
|
|
482
|
+
candidatePitch: pitch,
|
|
448
483
|
chord,
|
|
449
484
|
key,
|
|
450
485
|
otherVoices: others,
|
|
@@ -453,7 +488,7 @@ function sampleTension(prepared, timeline, key, ts, profile, beat) {
|
|
|
453
488
|
{ suggestions: false }
|
|
454
489
|
);
|
|
455
490
|
if (result.safety === 2 /* Dissonant */) {
|
|
456
|
-
dissonant +=
|
|
491
|
+
dissonant += count;
|
|
457
492
|
}
|
|
458
493
|
}
|
|
459
494
|
const dissonanceScore = Math.max(nonChord, dissonant) / sounding.length;
|
|
@@ -473,7 +508,7 @@ function sampleTension(prepared, timeline, key, ts, profile, beat) {
|
|
|
473
508
|
function toVoiceNotes(events) {
|
|
474
509
|
return events.map((event, index) => ({ ...event, id: index, originalIndex: index }));
|
|
475
510
|
}
|
|
476
|
-
var
|
|
511
|
+
var HUMANIZE_ADJACENCY = 0.05;
|
|
477
512
|
function intervalAboveBass(pitch, others, chord) {
|
|
478
513
|
let bass = Number.POSITIVE_INFINITY;
|
|
479
514
|
for (const ov of others) {
|
|
@@ -483,7 +518,7 @@ function intervalAboveBass(pitch, others, chord) {
|
|
|
483
518
|
return ((pitch - bass) % 12 + 12) % 12;
|
|
484
519
|
}
|
|
485
520
|
const ref = _nullishCoalesce(chord.bassPc, () => ( chord.rootPc));
|
|
486
|
-
return ((
|
|
521
|
+
return ((_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, pitch) - _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, ref)) % 12 + 12) % 12;
|
|
487
522
|
}
|
|
488
523
|
function tensionDegree(ic) {
|
|
489
524
|
if (ic === 1 || ic === 2) {
|
|
@@ -518,14 +553,14 @@ function suspensionType(ic, delta) {
|
|
|
518
553
|
}
|
|
519
554
|
function stepResolution(pitch, chord) {
|
|
520
555
|
for (let delta = 1; delta <= 2; delta += 1) {
|
|
521
|
-
if (
|
|
556
|
+
if (_chunkBSLTLGM3cjs.isChordMember.call(void 0, pitch - delta, chord)) {
|
|
522
557
|
return pitch - delta;
|
|
523
558
|
}
|
|
524
559
|
}
|
|
525
560
|
return void 0;
|
|
526
561
|
}
|
|
527
562
|
function analyzeVoice(voice, chordAtBeat, key, otherVoicesAtBeat = () => []) {
|
|
528
|
-
|
|
563
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, voice, "voice notes", { allowNonPositiveDuration: true });
|
|
529
564
|
const result = [];
|
|
530
565
|
for (let i = 0; i < voice.length; i += 1) {
|
|
531
566
|
const note = voice[i];
|
|
@@ -536,29 +571,29 @@ function analyzeVoice(voice, chordAtBeat, key, otherVoicesAtBeat = () => []) {
|
|
|
536
571
|
const nextNote = i + 1 < voice.length ? voice[i + 1] : void 0;
|
|
537
572
|
const prevEnd = prevNote === void 0 ? Number.NEGATIVE_INFINITY : prevNote.startBeat + prevNote.durationBeat;
|
|
538
573
|
const noteEnd = note.startBeat + note.durationBeat;
|
|
539
|
-
const prev = prevNote !== void 0 && Math.abs(prevEnd - note.startBeat) <=
|
|
540
|
-
const next = nextNote !== void 0 && Math.abs(noteEnd - nextNote.startBeat) <=
|
|
574
|
+
const prev = prevNote !== void 0 && Math.abs(prevEnd - note.startBeat) <= HUMANIZE_ADJACENCY ? prevNote : void 0;
|
|
575
|
+
const next = nextNote !== void 0 && Math.abs(noteEnd - nextNote.startBeat) <= HUMANIZE_ADJACENCY ? nextNote : void 0;
|
|
541
576
|
const chord = chordAtBeat(note.startBeat);
|
|
542
577
|
const labels = [];
|
|
543
|
-
const member =
|
|
578
|
+
const member = _chunkBSLTLGM3cjs.isChordMember.call(void 0, note.pitch, chord);
|
|
544
579
|
let handled = false;
|
|
545
580
|
if (chord && member) {
|
|
546
|
-
const role =
|
|
581
|
+
const role = _chunkBSLTLGM3cjs.chordToneRole.call(void 0, note.pitch, chord);
|
|
547
582
|
if (role) {
|
|
548
583
|
labels.push({ kind: "chordTone", role });
|
|
549
584
|
} else {
|
|
550
|
-
const ic =
|
|
585
|
+
const ic = _chunkBSLTLGM3cjs.intervalAboveRoot.call(void 0, note.pitch, chord);
|
|
551
586
|
labels.push({ kind: "tension", degree: tensionDegree(ic) });
|
|
552
587
|
}
|
|
553
588
|
handled = true;
|
|
554
589
|
}
|
|
555
590
|
if (!handled && chord && prev && next) {
|
|
556
591
|
const prevChord = chordAtBeat(prev.startBeat);
|
|
557
|
-
const prepared = prev.pitch === note.pitch &&
|
|
592
|
+
const prepared = prev.pitch === note.pitch && _chunkBSLTLGM3cjs.isChordMember.call(void 0, prev.pitch, prevChord);
|
|
558
593
|
const resolves = isStep(next.pitch, note.pitch);
|
|
559
594
|
const others = otherVoicesAtBeat(note.startBeat);
|
|
560
595
|
const verticallyDissonant = others.some(
|
|
561
|
-
(ov) =>
|
|
596
|
+
(ov) => _chunkBSLTLGM3cjs.createsVerticalDissonance.call(void 0, note.pitch, ov.pitch, true)
|
|
562
597
|
);
|
|
563
598
|
if (prepared && verticallyDissonant && resolves) {
|
|
564
599
|
const ic = intervalAboveBass(note.pitch, others, chord);
|
|
@@ -570,8 +605,8 @@ function analyzeVoice(voice, chordAtBeat, key, otherVoicesAtBeat = () => []) {
|
|
|
570
605
|
}
|
|
571
606
|
}
|
|
572
607
|
if (!handled && chord && prev && next) {
|
|
573
|
-
const prevMember =
|
|
574
|
-
const nextMember =
|
|
608
|
+
const prevMember = _chunkBSLTLGM3cjs.isChordMember.call(void 0, prev.pitch, chordAtBeat(prev.startBeat));
|
|
609
|
+
const nextMember = _chunkBSLTLGM3cjs.isChordMember.call(void 0, next.pitch, chordAtBeat(next.startBeat));
|
|
575
610
|
const up = note.pitch - prev.pitch > 0;
|
|
576
611
|
const contInto = next.pitch - note.pitch > 0;
|
|
577
612
|
const sameDir = note.pitch !== prev.pitch && next.pitch !== note.pitch && up === contInto;
|
|
@@ -580,20 +615,20 @@ function analyzeVoice(voice, chordAtBeat, key, otherVoicesAtBeat = () => []) {
|
|
|
580
615
|
handled = true;
|
|
581
616
|
}
|
|
582
617
|
}
|
|
583
|
-
if (!handled && chord && prev && next && !member && prev.pitch === next.pitch &&
|
|
618
|
+
if (!handled && chord && prev && next && !member && prev.pitch === next.pitch && _chunkBSLTLGM3cjs.isChordMember.call(void 0, prev.pitch, chordAtBeat(prev.startBeat)) && isStep(note.pitch, prev.pitch)) {
|
|
584
619
|
labels.push({ kind: "neighbor" });
|
|
585
620
|
handled = true;
|
|
586
621
|
}
|
|
587
622
|
if (!handled && chord && next && !member && note.pitch === next.pitch) {
|
|
588
623
|
const nextChord = chordAtBeat(next.startBeat);
|
|
589
|
-
if (
|
|
624
|
+
if (_chunkBSLTLGM3cjs.isChordMember.call(void 0, next.pitch, nextChord)) {
|
|
590
625
|
labels.push({ kind: "anticipation" });
|
|
591
626
|
handled = true;
|
|
592
627
|
}
|
|
593
628
|
}
|
|
594
629
|
if (!handled && chord && prev && next && !member) {
|
|
595
|
-
const prevMember =
|
|
596
|
-
const nextMember =
|
|
630
|
+
const prevMember = _chunkBSLTLGM3cjs.isChordMember.call(void 0, prev.pitch, chordAtBeat(prev.startBeat));
|
|
631
|
+
const nextMember = _chunkBSLTLGM3cjs.isChordMember.call(void 0, next.pitch, chordAtBeat(next.startBeat));
|
|
597
632
|
const stepFromPrev = isStep(note.pitch, prev.pitch);
|
|
598
633
|
const leapToNext = Math.abs(next.pitch - note.pitch) >= 3;
|
|
599
634
|
const opposite = note.pitch - prev.pitch > 0 !== next.pitch - note.pitch > 0;
|
|
@@ -603,7 +638,7 @@ function analyzeVoice(voice, chordAtBeat, key, otherVoicesAtBeat = () => []) {
|
|
|
603
638
|
}
|
|
604
639
|
}
|
|
605
640
|
if (!handled && chord && !member) {
|
|
606
|
-
const ic =
|
|
641
|
+
const ic = _chunkBSLTLGM3cjs.intervalAboveRoot.call(void 0, note.pitch, chord);
|
|
607
642
|
const isTension = ic === 2 || ic === 5 || ic === 9;
|
|
608
643
|
const avoid = ic === 5 && chord.intervals.includes(4) && !chord.intervals.includes(5) || ic === 11 && chord.intervals.includes(4) && chord.intervals.includes(10);
|
|
609
644
|
if (avoid) {
|
|
@@ -621,7 +656,7 @@ function analyzeVoice(voice, chordAtBeat, key, otherVoicesAtBeat = () => []) {
|
|
|
621
656
|
}
|
|
622
657
|
}
|
|
623
658
|
}
|
|
624
|
-
if (next &&
|
|
659
|
+
if (next && _chunkBSLTLGM3cjs.isLeadingToneResolution.call(void 0, note.pitch, next.pitch, key)) {
|
|
625
660
|
labels.push({ kind: "leadingTone", resolveTo: next.pitch });
|
|
626
661
|
}
|
|
627
662
|
const analyzed = {
|
|
@@ -669,7 +704,7 @@ function describe(labels) {
|
|
|
669
704
|
}
|
|
670
705
|
|
|
671
706
|
// src/analyze/arrange/tracks.ts
|
|
672
|
-
function
|
|
707
|
+
function soundingVoicesAt(prepared, beat) {
|
|
673
708
|
const out = [];
|
|
674
709
|
for (let t = 0; t < prepared.length; t += 1) {
|
|
675
710
|
const track = prepared[t];
|
|
@@ -677,10 +712,7 @@ function otherVoicesSounding(prepared, excludeTrack, excludeVoice, beat) {
|
|
|
677
712
|
continue;
|
|
678
713
|
}
|
|
679
714
|
for (let v = 0; v < track.voices.length; v += 1) {
|
|
680
|
-
|
|
681
|
-
continue;
|
|
682
|
-
}
|
|
683
|
-
const note = _optionalChain([track, 'access', _25 => _25.voices, 'access', _26 => _26[v], 'optionalAccess', _27 => _27.at, 'call', _28 => _28(beat)]);
|
|
715
|
+
const note = _optionalChain([track, 'access', _31 => _31.voices, 'access', _32 => _32[v], 'optionalAccess', _33 => _33.at, 'call', _34 => _34(beat)]);
|
|
684
716
|
if (note === void 0) {
|
|
685
717
|
continue;
|
|
686
718
|
}
|
|
@@ -689,17 +721,22 @@ function otherVoicesSounding(prepared, excludeTrack, excludeVoice, beat) {
|
|
|
689
721
|
if (previous !== void 0) {
|
|
690
722
|
snap.prevPitch = previous;
|
|
691
723
|
}
|
|
692
|
-
out.push(snap);
|
|
724
|
+
out.push({ track: t, voice: v, snapshot: snap });
|
|
693
725
|
}
|
|
694
726
|
}
|
|
695
727
|
return out;
|
|
696
728
|
}
|
|
729
|
+
function otherVoicesSounding(prepared, excludeTrack, excludeVoice, beat, cache) {
|
|
730
|
+
const sounding = _nullishCoalesce(cache.get(beat), () => ( soundingVoicesAt(prepared, beat)));
|
|
731
|
+
cache.set(beat, sounding);
|
|
732
|
+
return sounding.filter(({ track, voice }) => track !== excludeTrack || voice !== excludeVoice).map(({ snapshot }) => snapshot);
|
|
733
|
+
}
|
|
697
734
|
function firstSegmentAfter(timeline, beat) {
|
|
698
735
|
let low = 0;
|
|
699
736
|
let high = timeline.segments.length;
|
|
700
737
|
while (low < high) {
|
|
701
738
|
const middle = Math.floor((low + high) / 2);
|
|
702
|
-
if ((_nullishCoalesce(_optionalChain([timeline, 'access',
|
|
739
|
+
if ((_nullishCoalesce(_optionalChain([timeline, 'access', _35 => _35.segments, 'access', _36 => _36[middle], 'optionalAccess', _37 => _37.startBeat]), () => ( Number.POSITIVE_INFINITY))) <= beat + EPS2) {
|
|
703
740
|
low = middle + 1;
|
|
704
741
|
} else {
|
|
705
742
|
high = middle;
|
|
@@ -711,7 +748,7 @@ function evaluationBeats(note, timeline) {
|
|
|
711
748
|
const noteEnd = note.startBeat + note.durationBeat;
|
|
712
749
|
const beats = [note.startBeat];
|
|
713
750
|
for (let i = firstSegmentAfter(timeline, note.startBeat); i < timeline.segments.length; i += 1) {
|
|
714
|
-
const start = _optionalChain([timeline, 'access',
|
|
751
|
+
const start = _optionalChain([timeline, 'access', _38 => _38.segments, 'access', _39 => _39[i], 'optionalAccess', _40 => _40.startBeat]);
|
|
715
752
|
if (start === void 0 || start >= noteEnd - EPS2) {
|
|
716
753
|
break;
|
|
717
754
|
}
|
|
@@ -720,25 +757,25 @@ function evaluationBeats(note, timeline) {
|
|
|
720
757
|
return beats;
|
|
721
758
|
}
|
|
722
759
|
function analyzeArrangement(tracks, opts = {}) {
|
|
723
|
-
const ts = _nullishCoalesce(opts.ts, () => (
|
|
724
|
-
|
|
760
|
+
const ts = _nullishCoalesce(opts.ts, () => ( _chunk2A2QMA74cjs.parseTimeSignature.call(void 0, "4/4")));
|
|
761
|
+
_chunkPI3UXRWKcjs.assertTimeSignature.call(void 0, ts);
|
|
725
762
|
const budget = opts.budget;
|
|
726
|
-
|
|
763
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, tracks.length, "arrangement tracks", budget);
|
|
727
764
|
let noteCount = 0;
|
|
728
765
|
for (let index = 0; index < tracks.length; index += 1) {
|
|
729
|
-
const notes = _optionalChain([tracks, 'access',
|
|
766
|
+
const notes = _optionalChain([tracks, 'access', _41 => _41[index], 'optionalAccess', _42 => _42.notes]);
|
|
730
767
|
if (!Array.isArray(notes)) {
|
|
731
|
-
throw new (0,
|
|
768
|
+
throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(
|
|
732
769
|
`tracks[${index}].notes must be an array; received ${typeof notes}`
|
|
733
770
|
);
|
|
734
771
|
}
|
|
735
|
-
|
|
772
|
+
_chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, notes, `tracks[${index}].notes`, {
|
|
736
773
|
allowNonPositiveDuration: true,
|
|
737
774
|
budget
|
|
738
775
|
});
|
|
739
776
|
noteCount += notes.length;
|
|
740
777
|
}
|
|
741
|
-
|
|
778
|
+
_chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, noteCount, "arrangement notes", budget);
|
|
742
779
|
const profile = _nullishCoalesce(opts.profile, () => ( "pop"));
|
|
743
780
|
const minSeverity = _nullishCoalesce(opts.minSeverity, () => ( 1)) /* Warning */;
|
|
744
781
|
const harmonyTracks = opts.harmonyTracks === void 0 ? void 0 : new Set(opts.harmonyTracks.map(Math.trunc));
|
|
@@ -746,15 +783,20 @@ function analyzeArrangement(tracks, opts = {}) {
|
|
|
746
783
|
const inferred = opts.timeline === void 0 ? chordTimelineFromNotes(pooled, {
|
|
747
784
|
key: opts.key,
|
|
748
785
|
ts,
|
|
749
|
-
harmonicRhythm: opts.harmonicRhythm
|
|
786
|
+
harmonicRhythm: opts.harmonicRhythm,
|
|
787
|
+
budget
|
|
750
788
|
}) : {
|
|
751
789
|
timeline: opts.timeline,
|
|
752
|
-
key: _nullishCoalesce(_nullishCoalesce(opts.key, () => ( _optionalChain([
|
|
753
|
-
|
|
790
|
+
key: _nullishCoalesce(_nullishCoalesce(opts.key, () => ( _optionalChain([_chunkKQN2ZYNDcjs.detectKeyFromNotes.call(void 0, pooled, { budget }), 'access', _43 => _43[0], 'optionalAccess', _44 => _44.key]))), () => ( _chunkBSLTLGM3cjs.majorKey.call(void 0, 0))),
|
|
791
|
+
// A caller-provided timeline was not inferred from these notes, so
|
|
792
|
+
// it has no measured confidence. Reporting 1 would turn confidence
|
|
793
|
+
// gates into unconditional passes.
|
|
794
|
+
segmentConfidence: opts.timeline.segments.map(() => 0)
|
|
754
795
|
};
|
|
755
796
|
const { timeline, key, segmentConfidence } = inferred;
|
|
756
797
|
const cadences = detectCadences(timeline, key);
|
|
757
798
|
const prepared = prepareTracks(tracks);
|
|
799
|
+
const soundingCache = /* @__PURE__ */ new Map();
|
|
758
800
|
const trackAnalyses = [];
|
|
759
801
|
const conflicts = [];
|
|
760
802
|
for (let t = 0; t < prepared.length; t += 1) {
|
|
@@ -776,7 +818,7 @@ function analyzeArrangement(tracks, opts = {}) {
|
|
|
776
818
|
subVoice.voice,
|
|
777
819
|
timeline.at,
|
|
778
820
|
key,
|
|
779
|
-
(beat) => otherVoicesSounding(prepared, t, v, beat)
|
|
821
|
+
(beat) => otherVoicesSounding(prepared, t, v, beat, soundingCache)
|
|
780
822
|
);
|
|
781
823
|
notes.push(...analyzed.map((note) => ({ ...note, trackIndex: track.trackIndex })));
|
|
782
824
|
const labelsById = new Map(analyzed.map((note) => [note.noteId, note.labels]));
|
|
@@ -788,16 +830,18 @@ function analyzeArrangement(tracks, opts = {}) {
|
|
|
788
830
|
}
|
|
789
831
|
for (const beat of evaluationBeats(note, timeline)) {
|
|
790
832
|
const atOnset = Math.abs(beat - note.startBeat) <= EPS2;
|
|
791
|
-
const
|
|
833
|
+
const safetyQuery = {
|
|
792
834
|
profile,
|
|
793
835
|
candidatePitch: note.pitch,
|
|
794
836
|
prevPitch: atOnset ? preparedNote.prevPitch : note.pitch,
|
|
795
837
|
chord: timeline.at(beat),
|
|
796
838
|
key,
|
|
797
|
-
otherVoices: otherVoicesSounding(prepared, t, v, beat),
|
|
798
|
-
strongBeat:
|
|
799
|
-
}
|
|
839
|
+
otherVoices: otherVoicesSounding(prepared, t, v, beat, soundingCache),
|
|
840
|
+
strongBeat: _chunk2A2QMA74cjs.isStrongBeat.call(void 0, beat, ts)
|
|
841
|
+
};
|
|
842
|
+
let result = _chunkWFDXOLUBcjs.evaluateSafety.call(void 0, safetyQuery, { suggestions: false });
|
|
800
843
|
if (result.safety !== 0 /* Safe */ && result.safety >= minSeverity) {
|
|
844
|
+
result = _chunkWFDXOLUBcjs.evaluateSafety.call(void 0, safetyQuery);
|
|
801
845
|
const conflict = {
|
|
802
846
|
beat,
|
|
803
847
|
trackName: track.name,
|
|
@@ -842,4 +886,4 @@ function analyzeArrangement(tracks, opts = {}) {
|
|
|
842
886
|
|
|
843
887
|
|
|
844
888
|
exports.chordTimelineFromChords = chordTimelineFromChords; exports.chordTimelineFromNotes = chordTimelineFromNotes; exports.detectCadences = detectCadences; exports.tensionCurve = tensionCurve; exports.tensionCurveFrom = tensionCurveFrom; exports.toVoiceNotes = toVoiceNotes; exports.analyzeVoice = analyzeVoice; exports.analyzeArrangement = analyzeArrangement;
|
|
845
|
-
//# sourceMappingURL=chunk-
|
|
889
|
+
//# sourceMappingURL=chunk-4VZ5MZAM.cjs.map
|