@libraz/libcantus 0.9.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -261
- package/README_ja.md +115 -0
- package/dist/analyze/index.cjs +54 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +213 -456
- package/dist/analyze/index.d.ts +213 -456
- package/dist/analyze/index.js +56 -9
- package/dist/chunk-3JXCW6DX.cjs +3220 -0
- package/dist/chunk-3JXCW6DX.cjs.map +1 -0
- package/dist/chunk-4A2RMUCC.js +7647 -0
- package/dist/chunk-4A2RMUCC.js.map +1 -0
- package/dist/chunk-6XPTBE7Y.cjs +49 -0
- package/dist/chunk-6XPTBE7Y.cjs.map +1 -0
- package/dist/chunk-AFM2ULJH.cjs +5121 -0
- package/dist/chunk-AFM2ULJH.cjs.map +1 -0
- package/dist/chunk-E3F4AHAH.cjs +690 -0
- package/dist/chunk-E3F4AHAH.cjs.map +1 -0
- package/dist/chunk-ELCTZUJJ.js +379 -0
- package/dist/chunk-ELCTZUJJ.js.map +1 -0
- package/dist/chunk-FVSI36UV.js +690 -0
- package/dist/chunk-FVSI36UV.js.map +1 -0
- package/dist/chunk-GEDTJHAC.cjs +1 -0
- package/dist/chunk-GEDTJHAC.cjs.map +1 -0
- package/dist/chunk-GOZG57ER.js +3220 -0
- package/dist/chunk-GOZG57ER.js.map +1 -0
- package/dist/chunk-H3VORETI.js +2243 -0
- package/dist/chunk-H3VORETI.js.map +1 -0
- package/dist/chunk-H42UHPYW.js +1577 -0
- package/dist/chunk-H42UHPYW.js.map +1 -0
- package/dist/chunk-HFPS7JFD.js +1 -0
- package/dist/chunk-INHVXP6Z.js +3053 -0
- package/dist/chunk-INHVXP6Z.js.map +1 -0
- package/dist/chunk-K4ZJUGF4.cjs +379 -0
- package/dist/chunk-K4ZJUGF4.cjs.map +1 -0
- package/dist/chunk-KNJEKLKV.js +49 -0
- package/dist/chunk-KNJEKLKV.js.map +1 -0
- package/dist/chunk-M4CWTJWJ.cjs +7647 -0
- package/dist/chunk-M4CWTJWJ.cjs.map +1 -0
- package/dist/chunk-MXO72PLY.cjs +211 -0
- package/dist/chunk-MXO72PLY.cjs.map +1 -0
- package/dist/chunk-NLEU4QSE.cjs +360 -0
- package/dist/chunk-NLEU4QSE.cjs.map +1 -0
- package/dist/chunk-OE6WK2Y2.cjs +1577 -0
- package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
- package/dist/chunk-Q2WGKJNN.cjs +1064 -0
- package/dist/chunk-Q2WGKJNN.cjs.map +1 -0
- package/dist/chunk-QYQQ5J6E.js +1 -0
- package/dist/chunk-QYQQ5J6E.js.map +1 -0
- package/dist/chunk-RHIJ3S4I.cjs +1 -0
- package/dist/chunk-RHIJ3S4I.cjs.map +1 -0
- package/dist/chunk-TTCLJX6D.js +211 -0
- package/dist/chunk-TTCLJX6D.js.map +1 -0
- package/dist/chunk-UADYAYAT.cjs +3053 -0
- package/dist/chunk-UADYAYAT.cjs.map +1 -0
- package/dist/chunk-VOHZB45S.js +5121 -0
- package/dist/chunk-VOHZB45S.js.map +1 -0
- package/dist/chunk-VTI6FOLB.js +1064 -0
- package/dist/chunk-VTI6FOLB.js.map +1 -0
- package/dist/chunk-WWURE4XT.cjs +2243 -0
- package/dist/chunk-WWURE4XT.cjs.map +1 -0
- package/dist/chunk-YH3BIKHH.js +360 -0
- package/dist/chunk-YH3BIKHH.js.map +1 -0
- package/dist/core/index.cjs +103 -6
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +96 -345
- package/dist/core/index.d.ts +96 -345
- package/dist/core/index.js +104 -7
- package/dist/generate/index.cjs +89 -10
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +437 -1095
- package/dist/generate/index.d.ts +437 -1095
- package/dist/generate/index.js +94 -15
- package/dist/index-9wcMhG73.d.ts +1095 -0
- package/dist/{index-D6b6na69.d.cts → index-B4o55NDr.d.cts} +13 -9
- package/dist/index-B9MNZboQ.d.cts +770 -0
- package/dist/index-B9MNZboQ.d.ts +770 -0
- package/dist/index-BGFW-8P2.d.cts +2307 -0
- package/dist/index-BO6xE9YU.d.cts +1804 -0
- package/dist/index-BkGmlyI3.d.cts +470 -0
- package/dist/index-CCNJRG-P.d.cts +1095 -0
- package/dist/index-CGpRv5sl.d.cts +643 -0
- package/dist/index-C_8o--VE.d.cts +1242 -0
- package/dist/index-CgHqxdps.d.ts +2307 -0
- package/dist/index-Chbst3Jx.d.ts +1343 -0
- package/dist/index-Cj49F892.d.ts +470 -0
- package/dist/{index-tSQh-xwY.d.ts → index-CunYKLiu.d.ts} +13 -9
- package/dist/index-D57QRbVn.d.ts +1804 -0
- package/dist/index-DInQqT8Q.d.cts +66 -0
- package/dist/index-DInQqT8Q.d.ts +66 -0
- package/dist/index-Dzr13q3d.d.cts +1343 -0
- package/dist/index-G1uwGGWQ.d.ts +643 -0
- package/dist/index-szBv3496.d.ts +1242 -0
- package/dist/index.cjs +358 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -15
- package/dist/index.d.ts +17 -15
- package/dist/index.js +407 -64
- package/dist/masks-DYbE485J.d.cts +445 -0
- package/dist/masks-DYbE485J.d.ts +445 -0
- package/dist/model/index.cjs +39 -7
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +4685 -243
- package/dist/model/index.d.ts +4685 -243
- package/dist/model/index.js +40 -8
- package/dist/positional-Cptlj-xs.d.ts +287 -0
- package/dist/positional-DvH_sd8u.d.cts +287 -0
- package/dist/theory/index.cjs +101 -7
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +513 -173
- package/dist/theory/index.d.ts +513 -173
- package/dist/theory/index.js +118 -24
- package/package.json +16 -11
- package/dist/chunk-36N73KZ3.cjs +0 -246
- package/dist/chunk-36N73KZ3.cjs.map +0 -1
- package/dist/chunk-4HLLZPXT.cjs +0 -3077
- package/dist/chunk-4HLLZPXT.cjs.map +0 -1
- package/dist/chunk-7MGZ7D62.cjs +0 -498
- package/dist/chunk-7MGZ7D62.cjs.map +0 -1
- package/dist/chunk-7NKDPF74.js +0 -3077
- package/dist/chunk-7NKDPF74.js.map +0 -1
- package/dist/chunk-CAN76NCU.cjs +0 -679
- package/dist/chunk-CAN76NCU.cjs.map +0 -1
- package/dist/chunk-D2FAJBYL.js +0 -479
- package/dist/chunk-D2FAJBYL.js.map +0 -1
- package/dist/chunk-EHVEBWM5.js +0 -1449
- package/dist/chunk-EHVEBWM5.js.map +0 -1
- package/dist/chunk-FCANXBAT.cjs +0 -30
- package/dist/chunk-FCANXBAT.cjs.map +0 -1
- package/dist/chunk-FNDWXRRI.cjs +0 -479
- package/dist/chunk-FNDWXRRI.cjs.map +0 -1
- package/dist/chunk-GQSGS2N4.js +0 -173
- package/dist/chunk-GQSGS2N4.js.map +0 -1
- package/dist/chunk-HKGYCQ34.js +0 -53
- package/dist/chunk-HKGYCQ34.js.map +0 -1
- package/dist/chunk-I24MV65U.js +0 -106
- package/dist/chunk-I24MV65U.js.map +0 -1
- package/dist/chunk-KMHOICIY.js +0 -679
- package/dist/chunk-KMHOICIY.js.map +0 -1
- package/dist/chunk-LW53AHQU.cjs +0 -1117
- package/dist/chunk-LW53AHQU.cjs.map +0 -1
- package/dist/chunk-N6IHQUOX.js +0 -1
- package/dist/chunk-NKIBQ6PT.js +0 -30
- package/dist/chunk-NKIBQ6PT.js.map +0 -1
- package/dist/chunk-NP4NA2FB.cjs +0 -106
- package/dist/chunk-NP4NA2FB.cjs.map +0 -1
- package/dist/chunk-NVE34YGZ.cjs +0 -1449
- package/dist/chunk-NVE34YGZ.cjs.map +0 -1
- package/dist/chunk-NYYWMV2C.js +0 -327
- package/dist/chunk-NYYWMV2C.js.map +0 -1
- package/dist/chunk-Q2XUP227.js +0 -845
- package/dist/chunk-Q2XUP227.js.map +0 -1
- package/dist/chunk-Q6OP4U43.cjs +0 -327
- package/dist/chunk-Q6OP4U43.cjs.map +0 -1
- package/dist/chunk-RC6GBMCD.cjs +0 -845
- package/dist/chunk-RC6GBMCD.cjs.map +0 -1
- package/dist/chunk-RK35RIN7.js +0 -1117
- package/dist/chunk-RK35RIN7.js.map +0 -1
- package/dist/chunk-RUMU3UA6.cjs +0 -53
- package/dist/chunk-RUMU3UA6.cjs.map +0 -1
- package/dist/chunk-T64C7ZD7.cjs +0 -1
- package/dist/chunk-T64C7ZD7.cjs.map +0 -1
- package/dist/chunk-XEBG3G53.js +0 -498
- package/dist/chunk-XEBG3G53.js.map +0 -1
- package/dist/chunk-YLEMGEFH.js +0 -246
- package/dist/chunk-YLEMGEFH.js.map +0 -1
- package/dist/chunk-ZEJR4TKL.cjs +0 -173
- package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
- package/dist/function-BtiZb9i9.d.ts +0 -208
- package/dist/function-DNugAOrt.d.cts +0 -208
- package/dist/index-6VR8-kit.d.ts +0 -143
- package/dist/index-70p168VM.d.ts +0 -192
- package/dist/index-Be74mcon.d.cts +0 -152
- package/dist/index-BtXT6UQ0.d.cts +0 -192
- package/dist/index-C5UBbQ4G.d.ts +0 -152
- package/dist/index-C83mZI1P.d.ts +0 -242
- package/dist/index-DXd9JikN.d.cts +0 -246
- package/dist/index-DXd9JikN.d.ts +0 -246
- package/dist/index-OG65ocOr.d.cts +0 -272
- package/dist/index-OG65ocOr.d.ts +0 -272
- package/dist/index-tJhkmQgE.d.cts +0 -143
- package/dist/index-y_ak9_Hi.d.cts +0 -242
- package/dist/styled-DIRkk9Uz.d.ts +0 -506
- package/dist/styled-DJbkJQfj.d.cts +0 -506
- package/dist/types-BN6_Q9Kl.d.cts +0 -39
- package/dist/types-BN6_Q9Kl.d.ts +0 -39
- /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InvalidInputError,
|
|
3
|
+
assertFiniteNumber,
|
|
4
|
+
assertInteger,
|
|
5
|
+
assertNoteEvents,
|
|
6
|
+
assertRange
|
|
7
|
+
} from "./chunk-VTI6FOLB.js";
|
|
8
|
+
|
|
9
|
+
// src/core/instrument/articulation.ts
|
|
10
|
+
var ARTICULATIONS = Object.freeze([
|
|
11
|
+
"accent",
|
|
12
|
+
"ghost",
|
|
13
|
+
"staccato",
|
|
14
|
+
"legato",
|
|
15
|
+
"slide",
|
|
16
|
+
"hammer",
|
|
17
|
+
"mute",
|
|
18
|
+
"flam",
|
|
19
|
+
"drag",
|
|
20
|
+
"roll",
|
|
21
|
+
"choke",
|
|
22
|
+
"open"
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
// src/core/instrument/profile.ts
|
|
26
|
+
var LIMBS = Object.freeze(["rightHand", "leftHand", "rightFoot", "leftFoot"]);
|
|
27
|
+
function toInstrumentProfile(value, name = "instrument") {
|
|
28
|
+
if (typeof value !== "object" || value === null) {
|
|
29
|
+
throw new InvalidInputError(`${name} must be an instrument profile; received ${typeof value}`);
|
|
30
|
+
}
|
|
31
|
+
const data = "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON() : value;
|
|
32
|
+
const kind = data?.kind;
|
|
33
|
+
if (kind !== "stringed" && kind !== "percussion") {
|
|
34
|
+
throw new InvalidInputError(
|
|
35
|
+
`${name} must be a stringed or percussion profile; received kind ${String(kind)}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
assertProfile(data);
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
function toStringedProfile(value, name = "instrument") {
|
|
42
|
+
const profile = toInstrumentProfile(value, name);
|
|
43
|
+
if (profile.kind !== "stringed") {
|
|
44
|
+
throw new InvalidInputError(
|
|
45
|
+
`${name} must be a stringed instrument; ${profile.name} has no strings`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return profile;
|
|
49
|
+
}
|
|
50
|
+
function assertProfile(profile) {
|
|
51
|
+
if (profile.kind === "stringed") {
|
|
52
|
+
if (profile.tuning.length === 0) {
|
|
53
|
+
throw new InvalidInputError(`${profile.name} must have at least one string`);
|
|
54
|
+
}
|
|
55
|
+
if (!Number.isInteger(profile.frets) || profile.frets < 0) {
|
|
56
|
+
throw new InvalidInputError(`${profile.name} frets must be a non-negative integer`);
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (Object.keys(profile.reach).length === 0) {
|
|
61
|
+
throw new InvalidInputError(`${profile.name} must have at least one voice within reach`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function reachOf(profile, pitch) {
|
|
65
|
+
if (pitch === void 0) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
return (profile.reach[pitch] ?? []).filter((limb) => profile.limbs.includes(limb));
|
|
69
|
+
}
|
|
70
|
+
function instrumentRange(profile) {
|
|
71
|
+
assertProfile(profile);
|
|
72
|
+
if (profile.kind === "stringed") {
|
|
73
|
+
let low2 = Number.POSITIVE_INFINITY;
|
|
74
|
+
let high2 = Number.NEGATIVE_INFINITY;
|
|
75
|
+
for (const open of profile.tuning) {
|
|
76
|
+
low2 = Math.min(low2, open);
|
|
77
|
+
high2 = Math.max(high2, open + profile.frets);
|
|
78
|
+
}
|
|
79
|
+
return { low: low2, high: high2 };
|
|
80
|
+
}
|
|
81
|
+
let low = Number.POSITIVE_INFINITY;
|
|
82
|
+
let high = Number.NEGATIVE_INFINITY;
|
|
83
|
+
for (const key of Object.keys(profile.reach)) {
|
|
84
|
+
const pitch = Number(key);
|
|
85
|
+
if (reachOf(profile, pitch).length === 0) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
low = Math.min(low, pitch);
|
|
89
|
+
high = Math.max(high, pitch);
|
|
90
|
+
}
|
|
91
|
+
return { low, high };
|
|
92
|
+
}
|
|
93
|
+
function canSound(profile, pitch) {
|
|
94
|
+
assertProfile(profile);
|
|
95
|
+
if (profile.kind === "stringed") {
|
|
96
|
+
return profile.tuning.some((open) => pitch >= open && pitch - open <= profile.frets);
|
|
97
|
+
}
|
|
98
|
+
return reachOf(profile, pitch).length > 0;
|
|
99
|
+
}
|
|
100
|
+
function fingeringsFor(profile, pitch) {
|
|
101
|
+
assertProfile(profile);
|
|
102
|
+
const out = [];
|
|
103
|
+
for (let string = 0; string < profile.tuning.length; string += 1) {
|
|
104
|
+
const open = profile.tuning[string];
|
|
105
|
+
if (open === void 0) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const fret = pitch - open;
|
|
109
|
+
if (fret >= 0 && fret <= profile.frets) {
|
|
110
|
+
out.push({ string, fret });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
function foldIntoRange(pitch, profile) {
|
|
116
|
+
if (canSound(profile, pitch)) {
|
|
117
|
+
return pitch;
|
|
118
|
+
}
|
|
119
|
+
const { low, high } = instrumentRange(profile);
|
|
120
|
+
for (let candidate = pitch + 12; candidate <= high; candidate += 12) {
|
|
121
|
+
if (canSound(profile, candidate)) {
|
|
122
|
+
return candidate;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
for (let candidate = pitch - 12; candidate >= low; candidate -= 12) {
|
|
126
|
+
if (canSound(profile, candidate)) {
|
|
127
|
+
return candidate;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return pitch;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/core/instrument/playability.ts
|
|
134
|
+
var REFERENCE_BPM = 120;
|
|
135
|
+
var MAX_FRET_SHIFT_PER_SECOND = 100;
|
|
136
|
+
var MIN_LIMB_STROKE_SECONDS = 0.06;
|
|
137
|
+
var DIFFICULTY_SCALE = 12;
|
|
138
|
+
var MIN_DIFFICULTY = 1;
|
|
139
|
+
var MAX_DIFFICULTY = 5;
|
|
140
|
+
var STRING_CROSSING_COST = 2;
|
|
141
|
+
var ONSET_GRID = 128;
|
|
142
|
+
var EPS = 1e-9;
|
|
143
|
+
function playability(notes, profile, bpm) {
|
|
144
|
+
assertNoteEvents(notes, "playability notes", { allowNonPositiveDuration: true });
|
|
145
|
+
if (bpm !== void 0) {
|
|
146
|
+
assertRange(bpm, Number.MIN_VALUE, 1e3, "playability bpm");
|
|
147
|
+
}
|
|
148
|
+
const order = notes.map((_, index) => index).sort((a, b) => {
|
|
149
|
+
const left = notes[a];
|
|
150
|
+
const right = notes[b];
|
|
151
|
+
if (!left || !right) {
|
|
152
|
+
return a - b;
|
|
153
|
+
}
|
|
154
|
+
return left.startBeat - right.startBeat || left.pitch - right.pitch || a - b;
|
|
155
|
+
});
|
|
156
|
+
const state = {
|
|
157
|
+
notes,
|
|
158
|
+
order,
|
|
159
|
+
placements: notes.map((_, index) => ({ note: index })),
|
|
160
|
+
issues: [],
|
|
161
|
+
movement: 0,
|
|
162
|
+
secondsPerBeat: bpm === void 0 ? void 0 : 60 / bpm
|
|
163
|
+
};
|
|
164
|
+
checkExistence(state, profile);
|
|
165
|
+
if (profile.kind === "stringed") {
|
|
166
|
+
placeOnNeck(state, profile);
|
|
167
|
+
} else {
|
|
168
|
+
placeOnKit(state, profile);
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
difficulty: difficultyOf(state, bpm),
|
|
172
|
+
issues: state.issues,
|
|
173
|
+
placements: state.placements
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function checkExistence(state, profile) {
|
|
177
|
+
for (const index of state.order) {
|
|
178
|
+
const note = state.notes[index];
|
|
179
|
+
if (!note) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (!canSound(profile, note.pitch)) {
|
|
183
|
+
state.issues.push({
|
|
184
|
+
type: "noteOutOfRange",
|
|
185
|
+
layer: 1,
|
|
186
|
+
notes: [index],
|
|
187
|
+
startBeat: note.startBeat,
|
|
188
|
+
impossible: true,
|
|
189
|
+
message: `${profile.name} cannot sound MIDI ${note.pitch}`
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const articulation = note.articulation;
|
|
193
|
+
if (articulation !== void 0 && !profile.articulations.includes(articulation)) {
|
|
194
|
+
state.issues.push({
|
|
195
|
+
type: "articulationUnavailable",
|
|
196
|
+
layer: 1,
|
|
197
|
+
notes: [index],
|
|
198
|
+
startBeat: note.startBeat,
|
|
199
|
+
impossible: true,
|
|
200
|
+
message: `${profile.name} cannot play ${articulation}`
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function soundingGroups(state) {
|
|
206
|
+
const groups = [];
|
|
207
|
+
let active = [];
|
|
208
|
+
let cursor = 0;
|
|
209
|
+
let previousKey = Number.NaN;
|
|
210
|
+
for (const index of state.order) {
|
|
211
|
+
const note = state.notes[index];
|
|
212
|
+
if (!note) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const key = Math.round(note.startBeat * ONSET_GRID);
|
|
216
|
+
if (key === previousKey) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
previousKey = key;
|
|
220
|
+
const at = note.startBeat;
|
|
221
|
+
active = active.filter((member) => {
|
|
222
|
+
const held = state.notes[member];
|
|
223
|
+
return held !== void 0 && held.startBeat + held.durationBeat > at + EPS;
|
|
224
|
+
});
|
|
225
|
+
while (cursor < state.order.length) {
|
|
226
|
+
const candidateIndex = state.order[cursor];
|
|
227
|
+
const candidate = candidateIndex === void 0 ? void 0 : state.notes[candidateIndex];
|
|
228
|
+
if (!candidate || candidate.startBeat > at + EPS) {
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
if (candidateIndex !== void 0 && candidate.startBeat + candidate.durationBeat > at + EPS) {
|
|
232
|
+
active.push(candidateIndex);
|
|
233
|
+
}
|
|
234
|
+
cursor += 1;
|
|
235
|
+
}
|
|
236
|
+
groups.push({ startBeat: at, members: [...active] });
|
|
237
|
+
}
|
|
238
|
+
return groups;
|
|
239
|
+
}
|
|
240
|
+
function placeOnNeck(state, profile) {
|
|
241
|
+
const stringFreeAt = profile.tuning.map(() => Number.NEGATIVE_INFINITY);
|
|
242
|
+
const stringHeldBy = profile.tuning.map(() => void 0);
|
|
243
|
+
let previous;
|
|
244
|
+
let previousIndex;
|
|
245
|
+
for (const index of state.order) {
|
|
246
|
+
const note = state.notes[index];
|
|
247
|
+
const placement = state.placements[index];
|
|
248
|
+
if (!note || !placement) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const candidates = fingeringsFor(profile, note.pitch);
|
|
252
|
+
if (candidates.length === 0) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const free = candidates.filter(
|
|
256
|
+
(candidate) => (stringFreeAt[candidate.string] ?? 0) <= note.startBeat + EPS
|
|
257
|
+
);
|
|
258
|
+
if (free.length === 0) {
|
|
259
|
+
const blocked = candidates.map((candidate) => stringHeldBy[candidate.string]).filter((held) => held !== void 0);
|
|
260
|
+
state.issues.push({
|
|
261
|
+
type: "stringConflict",
|
|
262
|
+
layer: 2,
|
|
263
|
+
notes: [.../* @__PURE__ */ new Set([...blocked, index])].sort((a, b) => a - b),
|
|
264
|
+
startBeat: note.startBeat,
|
|
265
|
+
impossible: true,
|
|
266
|
+
message: `MIDI ${note.pitch} needs a string already sounding on ${profile.name}`
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const pool = free.length > 0 ? free : candidates;
|
|
270
|
+
const chosen = pool.reduce(
|
|
271
|
+
(best, candidate) => fingeringCost(candidate, previous) < fingeringCost(best, previous) ? candidate : best
|
|
272
|
+
);
|
|
273
|
+
placement.fingering = chosen;
|
|
274
|
+
stringFreeAt[chosen.string] = note.startBeat + note.durationBeat;
|
|
275
|
+
stringHeldBy[chosen.string] = index;
|
|
276
|
+
state.movement += 1;
|
|
277
|
+
if (previous) {
|
|
278
|
+
state.movement += Math.abs(chosen.fret - previous.fret) + Math.abs(chosen.string - previous.string);
|
|
279
|
+
checkShiftSpeed(state, profile, previousIndex, index, previous, chosen);
|
|
280
|
+
}
|
|
281
|
+
previous = chosen;
|
|
282
|
+
previousIndex = index;
|
|
283
|
+
}
|
|
284
|
+
for (const group of soundingGroups(state)) {
|
|
285
|
+
checkStretch(state, profile, group);
|
|
286
|
+
checkPolyphony(state, profile, group);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function fingeringCost(candidate, previous) {
|
|
290
|
+
if (!previous) {
|
|
291
|
+
return candidate.fret + candidate.string / 100;
|
|
292
|
+
}
|
|
293
|
+
return Math.abs(candidate.fret - previous.fret) + STRING_CROSSING_COST * Math.abs(candidate.string - previous.string) + candidate.string / 100;
|
|
294
|
+
}
|
|
295
|
+
function checkShiftSpeed(state, profile, fromIndex, toIndex, from, to) {
|
|
296
|
+
const secondsPerBeat = state.secondsPerBeat;
|
|
297
|
+
if (secondsPerBeat === void 0 || fromIndex === void 0) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const previousNote = state.notes[fromIndex];
|
|
301
|
+
const note = state.notes[toIndex];
|
|
302
|
+
if (!previousNote || !note) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const seconds = (note.startBeat - previousNote.startBeat) * secondsPerBeat;
|
|
306
|
+
const shift = Math.abs(to.fret - from.fret);
|
|
307
|
+
if (seconds <= EPS || shift === 0) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (shift / seconds > MAX_FRET_SHIFT_PER_SECOND) {
|
|
311
|
+
state.issues.push({
|
|
312
|
+
type: "tooFast",
|
|
313
|
+
layer: 3,
|
|
314
|
+
notes: [fromIndex, toIndex].sort((a, b) => a - b),
|
|
315
|
+
startBeat: note.startBeat,
|
|
316
|
+
impossible: false,
|
|
317
|
+
message: `a ${shift}-fret shift in ${seconds.toFixed(3)}s is beyond ${profile.name}`
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function checkStretch(state, profile, group) {
|
|
322
|
+
const frets = group.members.map((member) => state.placements[member]?.fingering).filter(
|
|
323
|
+
(fingering) => fingering !== void 0 && fingering.fret > 0
|
|
324
|
+
).map((fingering) => fingering.fret);
|
|
325
|
+
if (frets.length < 2) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const span = Math.max(...frets) - Math.min(...frets);
|
|
329
|
+
if (span > profile.maxStretch) {
|
|
330
|
+
state.issues.push({
|
|
331
|
+
type: "stretchTooWide",
|
|
332
|
+
layer: 2,
|
|
333
|
+
notes: [...group.members].sort((a, b) => a - b),
|
|
334
|
+
startBeat: group.startBeat,
|
|
335
|
+
impossible: true,
|
|
336
|
+
message: `a ${span}-fret stretch exceeds the ${profile.maxStretch} frets one hand spans on ${profile.name}`
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function checkPolyphony(state, profile, group) {
|
|
341
|
+
if (group.members.length <= profile.polyphony) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
state.issues.push({
|
|
345
|
+
type: "polyphonyExceeded",
|
|
346
|
+
layer: 2,
|
|
347
|
+
notes: [...group.members].sort((a, b) => a - b),
|
|
348
|
+
startBeat: group.startBeat,
|
|
349
|
+
impossible: true,
|
|
350
|
+
message: `${group.members.length} notes sound at once; ${profile.name} has ${profile.polyphony}`
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
function placeOnKit(state, profile) {
|
|
354
|
+
const limbForVoice = /* @__PURE__ */ new Map();
|
|
355
|
+
const lastStroke = /* @__PURE__ */ new Map();
|
|
356
|
+
for (const group of onsetGroups(state)) {
|
|
357
|
+
const taken = /* @__PURE__ */ new Set();
|
|
358
|
+
let conflicted = false;
|
|
359
|
+
const members = [...group.members].sort((a, b) => {
|
|
360
|
+
const left = reachOf(profile, state.notes[a]?.pitch);
|
|
361
|
+
const right = reachOf(profile, state.notes[b]?.pitch);
|
|
362
|
+
return left.length - right.length || a - b;
|
|
363
|
+
});
|
|
364
|
+
for (const index of members) {
|
|
365
|
+
const note = state.notes[index];
|
|
366
|
+
const placement = state.placements[index];
|
|
367
|
+
if (!note || !placement) {
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const candidates = reachOf(profile, note.pitch);
|
|
371
|
+
if (candidates.length === 0) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
const preferred = limbForVoice.get(note.pitch);
|
|
375
|
+
const free = candidates.filter((limb) => !taken.has(limb));
|
|
376
|
+
const chosen = free.length === 0 ? candidates[0] : preferred !== void 0 && free.includes(preferred) ? preferred : free[0];
|
|
377
|
+
if (free.length === 0) {
|
|
378
|
+
conflicted = true;
|
|
379
|
+
}
|
|
380
|
+
if (chosen === void 0) {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
taken.add(chosen);
|
|
384
|
+
placement.limb = chosen;
|
|
385
|
+
limbForVoice.set(note.pitch, chosen);
|
|
386
|
+
state.movement += 1;
|
|
387
|
+
const previousIndex = lastStroke.get(chosen);
|
|
388
|
+
if (previousIndex !== void 0) {
|
|
389
|
+
const previousNote = state.notes[previousIndex];
|
|
390
|
+
if (previousNote && previousNote.pitch !== note.pitch) {
|
|
391
|
+
state.movement += 1;
|
|
392
|
+
}
|
|
393
|
+
checkStrokeSpeed(state, profile, previousIndex, index, chosen);
|
|
394
|
+
}
|
|
395
|
+
lastStroke.set(chosen, index);
|
|
396
|
+
}
|
|
397
|
+
if (conflicted) {
|
|
398
|
+
state.issues.push({
|
|
399
|
+
type: "limbConflict",
|
|
400
|
+
layer: 2,
|
|
401
|
+
notes: [...group.members].sort((a, b) => a - b),
|
|
402
|
+
startBeat: group.startBeat,
|
|
403
|
+
impossible: true,
|
|
404
|
+
message: `${group.members.length} simultaneous strokes cannot be shared among the limbs of ${profile.name}`
|
|
405
|
+
});
|
|
406
|
+
} else {
|
|
407
|
+
checkPolyphony(state, profile, group);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function checkStrokeSpeed(state, profile, fromIndex, toIndex, limb) {
|
|
412
|
+
const secondsPerBeat = state.secondsPerBeat;
|
|
413
|
+
if (secondsPerBeat === void 0) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const previousNote = state.notes[fromIndex];
|
|
417
|
+
const note = state.notes[toIndex];
|
|
418
|
+
if (!previousNote || !note) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const seconds = (note.startBeat - previousNote.startBeat) * secondsPerBeat;
|
|
422
|
+
if (seconds <= EPS || seconds >= MIN_LIMB_STROKE_SECONDS) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
state.issues.push({
|
|
426
|
+
type: "tooFast",
|
|
427
|
+
layer: 3,
|
|
428
|
+
notes: [fromIndex, toIndex].sort((a, b) => a - b),
|
|
429
|
+
startBeat: note.startBeat,
|
|
430
|
+
impossible: false,
|
|
431
|
+
message: `${limb} strikes twice ${seconds.toFixed(3)}s apart on ${profile.name}`
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
function onsetGroups(state) {
|
|
435
|
+
const groups = [];
|
|
436
|
+
let key = Number.NaN;
|
|
437
|
+
let current;
|
|
438
|
+
for (const index of state.order) {
|
|
439
|
+
const note = state.notes[index];
|
|
440
|
+
if (!note) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
const onsetKey = Math.round(note.startBeat * ONSET_GRID);
|
|
444
|
+
if (!current || onsetKey !== key) {
|
|
445
|
+
current = { startBeat: note.startBeat, members: [] };
|
|
446
|
+
groups.push(current);
|
|
447
|
+
key = onsetKey;
|
|
448
|
+
}
|
|
449
|
+
current.members.push(index);
|
|
450
|
+
}
|
|
451
|
+
return groups;
|
|
452
|
+
}
|
|
453
|
+
function difficultyOf(state, bpm) {
|
|
454
|
+
let first = Number.POSITIVE_INFINITY;
|
|
455
|
+
let last = Number.NEGATIVE_INFINITY;
|
|
456
|
+
for (const note of state.notes) {
|
|
457
|
+
if (!note) {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
first = Math.min(first, note.startBeat);
|
|
461
|
+
last = Math.max(last, note.startBeat + Math.max(0, note.durationBeat));
|
|
462
|
+
}
|
|
463
|
+
const spanBeats = last - first;
|
|
464
|
+
if (!Number.isFinite(spanBeats) || spanBeats <= EPS) {
|
|
465
|
+
return MIN_DIFFICULTY;
|
|
466
|
+
}
|
|
467
|
+
const seconds = spanBeats * 60 / (bpm ?? REFERENCE_BPM);
|
|
468
|
+
const rate = state.movement / seconds;
|
|
469
|
+
const scaled = MIN_DIFFICULTY + (MAX_DIFFICULTY - MIN_DIFFICULTY) * (1 - Math.exp(-rate / DIFFICULTY_SCALE));
|
|
470
|
+
return Math.round(scaled * 1e4) / 1e4;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/core/instrument/profiles.ts
|
|
474
|
+
var STRINGED_ARTICULATIONS = Object.freeze([
|
|
475
|
+
"accent",
|
|
476
|
+
"ghost",
|
|
477
|
+
"staccato",
|
|
478
|
+
"legato",
|
|
479
|
+
"slide",
|
|
480
|
+
"hammer",
|
|
481
|
+
"mute",
|
|
482
|
+
"open"
|
|
483
|
+
]);
|
|
484
|
+
var BASS_4_STRING = Object.freeze({
|
|
485
|
+
kind: "stringed",
|
|
486
|
+
name: "4-string bass",
|
|
487
|
+
tuning: Object.freeze([28, 33, 38, 43]),
|
|
488
|
+
frets: 24,
|
|
489
|
+
maxStretch: 4,
|
|
490
|
+
articulations: STRINGED_ARTICULATIONS,
|
|
491
|
+
polyphony: 4
|
|
492
|
+
});
|
|
493
|
+
var BASS_5_STRING = Object.freeze({
|
|
494
|
+
kind: "stringed",
|
|
495
|
+
name: "5-string bass",
|
|
496
|
+
tuning: Object.freeze([23, 28, 33, 38, 43]),
|
|
497
|
+
frets: 24,
|
|
498
|
+
maxStretch: 4,
|
|
499
|
+
articulations: STRINGED_ARTICULATIONS,
|
|
500
|
+
polyphony: 5
|
|
501
|
+
});
|
|
502
|
+
var GUITAR_STANDARD = Object.freeze({
|
|
503
|
+
kind: "stringed",
|
|
504
|
+
name: "guitar",
|
|
505
|
+
tuning: Object.freeze([40, 45, 50, 55, 59, 64]),
|
|
506
|
+
frets: 24,
|
|
507
|
+
maxStretch: 5,
|
|
508
|
+
articulations: STRINGED_ARTICULATIONS,
|
|
509
|
+
polyphony: 6
|
|
510
|
+
});
|
|
511
|
+
var GUITAR_DROP_D = Object.freeze({
|
|
512
|
+
kind: "stringed",
|
|
513
|
+
name: "guitar (drop D)",
|
|
514
|
+
tuning: Object.freeze([38, 45, 50, 55, 59, 64]),
|
|
515
|
+
frets: 24,
|
|
516
|
+
maxStretch: 5,
|
|
517
|
+
articulations: STRINGED_ARTICULATIONS,
|
|
518
|
+
polyphony: 6
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
// src/core/random/internal.ts
|
|
522
|
+
var UINT32_RANGE = 4294967296;
|
|
523
|
+
var FNV_OFFSET_BASIS = 2166136261;
|
|
524
|
+
var FNV_PRIME = 16777619;
|
|
525
|
+
var DOMAIN_SEED = 1;
|
|
526
|
+
var DOMAIN_POSITION = 2;
|
|
527
|
+
var TAG_STRING = 1;
|
|
528
|
+
var TAG_NUMBER = 2;
|
|
529
|
+
var numberBytes = new DataView(new ArrayBuffer(8));
|
|
530
|
+
function absorb(hash, byte) {
|
|
531
|
+
return Math.imul(hash ^ byte & 255, FNV_PRIME) >>> 0;
|
|
532
|
+
}
|
|
533
|
+
function absorbUint32(hash, value) {
|
|
534
|
+
let next = hash;
|
|
535
|
+
for (let shift = 0; shift < 32; shift += 8) {
|
|
536
|
+
next = absorb(next, value >>> shift & 255);
|
|
537
|
+
}
|
|
538
|
+
return next;
|
|
539
|
+
}
|
|
540
|
+
function fmix32(value) {
|
|
541
|
+
let mixed = value >>> 0;
|
|
542
|
+
mixed ^= mixed >>> 16;
|
|
543
|
+
mixed = Math.imul(mixed, 2246822507);
|
|
544
|
+
mixed ^= mixed >>> 13;
|
|
545
|
+
mixed = Math.imul(mixed, 3266489909);
|
|
546
|
+
mixed ^= mixed >>> 16;
|
|
547
|
+
return mixed >>> 0;
|
|
548
|
+
}
|
|
549
|
+
function absorbSegment(hash, segment, index) {
|
|
550
|
+
if (typeof segment === "string") {
|
|
551
|
+
let next = absorb(hash, TAG_STRING);
|
|
552
|
+
next = absorbUint32(next, segment.length);
|
|
553
|
+
for (let i = 0; i < segment.length; i += 1) {
|
|
554
|
+
const unit = segment.charCodeAt(i);
|
|
555
|
+
next = absorb(next, unit & 255);
|
|
556
|
+
next = absorb(next, unit >>> 8 & 255);
|
|
557
|
+
}
|
|
558
|
+
return next;
|
|
559
|
+
}
|
|
560
|
+
if (typeof segment === "number") {
|
|
561
|
+
assertFiniteNumber(segment, `seed path segment ${index}`);
|
|
562
|
+
numberBytes.setFloat64(0, segment === 0 ? 0 : segment, true);
|
|
563
|
+
let next = absorb(hash, TAG_NUMBER);
|
|
564
|
+
for (let i = 0; i < 8; i += 1) {
|
|
565
|
+
next = absorb(next, numberBytes.getUint8(i));
|
|
566
|
+
}
|
|
567
|
+
return next;
|
|
568
|
+
}
|
|
569
|
+
throw new InvalidInputError(
|
|
570
|
+
`seed path segment ${index} must be a string or a number; received ${typeof segment}`
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
function hashPath(domain, root, path) {
|
|
574
|
+
let hash = absorb(FNV_OFFSET_BASIS, domain);
|
|
575
|
+
hash = absorbUint32(hash, root);
|
|
576
|
+
for (let index = 0; index < path.length; index += 1) {
|
|
577
|
+
const segment = path[index];
|
|
578
|
+
if (segment === void 0) {
|
|
579
|
+
throw new InvalidInputError(
|
|
580
|
+
`seed path segment ${index} must be a string or a number; received undefined`
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
hash = absorbSegment(hash, segment, index);
|
|
584
|
+
}
|
|
585
|
+
return fmix32(hash);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// src/core/random/positional.ts
|
|
589
|
+
function createPositionalRng(seed) {
|
|
590
|
+
assertInteger(seed, "seed", 0, 4294967295);
|
|
591
|
+
return {
|
|
592
|
+
at: (...path) => hashPath(DOMAIN_POSITION, seed, path) / UINT32_RANGE
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
function includeAt(rng, complexity, ...path) {
|
|
596
|
+
assertRange(complexity, 0, 1, "complexity");
|
|
597
|
+
const draw = rng.at(...path);
|
|
598
|
+
if (!(draw >= 0 && draw < 1)) {
|
|
599
|
+
throw new InvalidInputError(`positional draw must be in [0, 1); received ${draw}`);
|
|
600
|
+
}
|
|
601
|
+
return draw < complexity;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/core/random/seed.ts
|
|
605
|
+
function deriveSeed(root, ...path) {
|
|
606
|
+
assertInteger(root, "root seed", 0, 4294967295);
|
|
607
|
+
return hashPath(DOMAIN_SEED, root, path);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/core/random/version.ts
|
|
611
|
+
var ALGORITHM_VERSION = 1;
|
|
612
|
+
var MIN_ALGORITHM_VERSION = 1;
|
|
613
|
+
function resolveAlgorithmVersion(requested) {
|
|
614
|
+
if (requested === void 0) {
|
|
615
|
+
return ALGORITHM_VERSION;
|
|
616
|
+
}
|
|
617
|
+
assertInteger(requested, "algorithm version");
|
|
618
|
+
if (requested < MIN_ALGORITHM_VERSION || requested > ALGORITHM_VERSION) {
|
|
619
|
+
throw new InvalidInputError(
|
|
620
|
+
`algorithm version ${requested} is not produced by this build; supported versions are ${MIN_ALGORITHM_VERSION}..${ALGORITHM_VERSION}`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
return requested;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// src/core/random/index.ts
|
|
627
|
+
function createRng(seed) {
|
|
628
|
+
assertInteger(seed, "seed", 0, 4294967295);
|
|
629
|
+
let state = seed >>> 0;
|
|
630
|
+
const next = () => {
|
|
631
|
+
state = state + 1831565813 >>> 0;
|
|
632
|
+
let t = state;
|
|
633
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
634
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
635
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
636
|
+
};
|
|
637
|
+
return {
|
|
638
|
+
next,
|
|
639
|
+
prob: (p) => {
|
|
640
|
+
assertRange(p, 0, 1, "probability");
|
|
641
|
+
return next() < p;
|
|
642
|
+
},
|
|
643
|
+
range: (lo, hi) => {
|
|
644
|
+
assertInteger(lo, "range lower bound");
|
|
645
|
+
assertInteger(hi, "range upper bound");
|
|
646
|
+
if (lo > hi) {
|
|
647
|
+
throw new InvalidInputError(
|
|
648
|
+
`range lower bound must not exceed upper bound; received ${lo} > ${hi}`
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
assertInteger(hi - lo, "range span", 0);
|
|
652
|
+
return lo + Math.floor(next() * (hi - lo + 1));
|
|
653
|
+
},
|
|
654
|
+
float: (lo, hi) => {
|
|
655
|
+
assertFiniteNumber(lo, "float lower bound");
|
|
656
|
+
assertFiniteNumber(hi, "float upper bound");
|
|
657
|
+
if (lo > hi) {
|
|
658
|
+
throw new InvalidInputError(
|
|
659
|
+
`float lower bound must not exceed upper bound; received ${lo} > ${hi}`
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
assertFiniteNumber(hi - lo, "float span");
|
|
663
|
+
return lo + next() * (hi - lo);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
export {
|
|
669
|
+
ARTICULATIONS,
|
|
670
|
+
LIMBS,
|
|
671
|
+
toInstrumentProfile,
|
|
672
|
+
toStringedProfile,
|
|
673
|
+
instrumentRange,
|
|
674
|
+
canSound,
|
|
675
|
+
fingeringsFor,
|
|
676
|
+
foldIntoRange,
|
|
677
|
+
playability,
|
|
678
|
+
BASS_4_STRING,
|
|
679
|
+
BASS_5_STRING,
|
|
680
|
+
GUITAR_STANDARD,
|
|
681
|
+
GUITAR_DROP_D,
|
|
682
|
+
createPositionalRng,
|
|
683
|
+
includeAt,
|
|
684
|
+
deriveSeed,
|
|
685
|
+
ALGORITHM_VERSION,
|
|
686
|
+
MIN_ALGORITHM_VERSION,
|
|
687
|
+
resolveAlgorithmVersion,
|
|
688
|
+
createRng
|
|
689
|
+
};
|
|
690
|
+
//# sourceMappingURL=chunk-FVSI36UV.js.map
|