@libraz/libcantus 1.0.1 → 1.2.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 +27 -65
- package/README_ja.md +28 -66
- package/dist/analyze/index.cjs +11 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +79 -144
- package/dist/analyze/index.d.ts +79 -144
- package/dist/analyze/index.js +20 -16
- package/dist/chunk-35NBV2FT.cjs +145 -0
- package/dist/chunk-35NBV2FT.cjs.map +1 -0
- package/dist/{chunk-UADYAYAT.cjs → chunk-3R3QVKY5.cjs} +1353 -580
- package/dist/chunk-3R3QVKY5.cjs.map +1 -0
- package/dist/{chunk-WWURE4XT.cjs → chunk-76ZBTRG2.cjs} +624 -729
- package/dist/chunk-76ZBTRG2.cjs.map +1 -0
- package/dist/{chunk-FVSI36UV.js → chunk-7KG3RTYS.js} +197 -110
- package/dist/chunk-7KG3RTYS.js.map +1 -0
- package/dist/{chunk-VTI6FOLB.js → chunk-AGOVW7U6.js} +709 -133
- package/dist/chunk-AGOVW7U6.js.map +1 -0
- package/dist/{chunk-E3F4AHAH.cjs → chunk-CGBADIO5.cjs} +221 -134
- package/dist/chunk-CGBADIO5.cjs.map +1 -0
- package/dist/{chunk-6XH6QZYQ.cjs → chunk-DSMJRXCZ.cjs} +1455 -849
- package/dist/chunk-DSMJRXCZ.cjs.map +1 -0
- package/dist/{chunk-PKFNUHDY.js → chunk-FBH75DAY.js} +1218 -612
- package/dist/chunk-FBH75DAY.js.map +1 -0
- package/dist/chunk-H2KJHBW4.js +3329 -0
- package/dist/chunk-H2KJHBW4.js.map +1 -0
- package/dist/chunk-HPVSH7SF.cjs +2294 -0
- package/dist/chunk-HPVSH7SF.cjs.map +1 -0
- package/dist/{chunk-MXO72PLY.cjs → chunk-HWHGOVO6.cjs} +21 -19
- package/dist/chunk-HWHGOVO6.cjs.map +1 -0
- package/dist/chunk-HYJJ2V2I.js +2294 -0
- package/dist/chunk-HYJJ2V2I.js.map +1 -0
- package/dist/{chunk-AFM2ULJH.cjs → chunk-J7FHVZII.cjs} +1567 -1067
- package/dist/chunk-J7FHVZII.cjs.map +1 -0
- package/dist/chunk-K6OZXIR6.js +1 -0
- package/dist/{chunk-H3VORETI.js → chunk-M5RYMAFI.js} +487 -592
- package/dist/chunk-M5RYMAFI.js.map +1 -0
- package/dist/chunk-NB25P3EH.js +363 -0
- package/dist/chunk-NB25P3EH.js.map +1 -0
- package/dist/{chunk-TTCLJX6D.js → chunk-NFJ4P6ZZ.js} +10 -8
- package/dist/chunk-NFJ4P6ZZ.js.map +1 -0
- package/dist/chunk-NM7UAMC3.cjs +457 -0
- package/dist/chunk-NM7UAMC3.cjs.map +1 -0
- package/dist/chunk-PM4XJE2Y.cjs +363 -0
- package/dist/chunk-PM4XJE2Y.cjs.map +1 -0
- package/dist/chunk-PUKJP2Z5.js +145 -0
- package/dist/chunk-PUKJP2Z5.js.map +1 -0
- package/dist/{chunk-VOHZB45S.js → chunk-Q6LFSAKV.js} +1321 -821
- package/dist/chunk-Q6LFSAKV.js.map +1 -0
- package/dist/{chunk-INHVXP6Z.js → chunk-RFIBF2RR.js} +1203 -430
- package/dist/chunk-RFIBF2RR.js.map +1 -0
- package/dist/{chunk-Q2WGKJNN.cjs → chunk-S5BKZZGM.cjs} +699 -123
- package/dist/chunk-S5BKZZGM.cjs.map +1 -0
- package/dist/chunk-SGLEQVJH.cjs +3329 -0
- package/dist/chunk-SGLEQVJH.cjs.map +1 -0
- package/dist/chunk-UGLFDG7L.cjs +1 -0
- package/dist/chunk-UGLFDG7L.cjs.map +1 -0
- package/dist/{chunk-YH3BIKHH.js → chunk-UMWZ4ZET.js} +146 -49
- package/dist/chunk-UMWZ4ZET.js.map +1 -0
- package/dist/{index-szBv3496.d.ts → coerce-DP0vYu-x.d.ts} +286 -199
- package/dist/{index-C_8o--VE.d.cts → coerce-DRERzdve.d.cts} +286 -199
- package/dist/core/index.cjs +9 -5
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +122 -108
- package/dist/core/index.d.ts +122 -108
- package/dist/core/index.js +32 -28
- package/dist/generate/index.cjs +8 -8
- package/dist/generate/index.d.cts +168 -84
- package/dist/generate/index.d.ts +168 -84
- package/dist/generate/index.js +7 -7
- package/dist/{index-CGpRv5sl.d.cts → index-9eoQs2C1.d.ts} +34 -19
- package/dist/{index-CCNJRG-P.d.cts → index-B9QLziDe.d.cts} +293 -56
- package/dist/{index-Dzr13q3d.d.cts → index-BBWNZS0f.d.cts} +135 -58
- package/dist/{index-9wcMhG73.d.ts → index-BHIUyjhZ.d.ts} +293 -56
- package/dist/{index-BGFW-8P2.d.cts → index-BJgP97N1.d.ts} +196 -114
- package/dist/{index-CunYKLiu.d.ts → index-BL5N2Oyz.d.cts} +1 -1
- package/dist/{index-Cj49F892.d.ts → index-BMweUlm5.d.cts} +63 -23
- package/dist/{index-CgHqxdps.d.ts → index-BNSM-DSk.d.cts} +196 -114
- package/dist/{index-D57QRbVn.d.ts → index-BRMbPkHE.d.ts} +480 -254
- package/dist/{index-Chbst3Jx.d.ts → index-CJBBiAmU.d.ts} +135 -58
- package/dist/{index-BkGmlyI3.d.cts → index-CL4b4gUQ.d.ts} +63 -23
- package/dist/{index-B9MNZboQ.d.ts → index-Cy15oTvh.d.cts} +52 -22
- package/dist/{index-B9MNZboQ.d.cts → index-Cy15oTvh.d.ts} +52 -22
- package/dist/{index-BO6xE9YU.d.cts → index-DGCNKAUr.d.cts} +480 -254
- package/dist/{index-B4o55NDr.d.cts → index-Dw2DP7vm.d.ts} +1 -1
- package/dist/{index-G1uwGGWQ.d.ts → index-cHvbYgJI.d.cts} +34 -19
- package/dist/index.cjs +42 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +82 -54
- package/dist/{masks-DYbE485J.d.cts → masks-Cc7-MzzY.d.ts} +49 -2
- package/dist/{masks-DYbE485J.d.ts → masks-pADfTOiD.d.cts} +49 -2
- package/dist/model/index.cjs +19 -12
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +504 -182
- package/dist/model/index.d.ts +504 -182
- package/dist/model/index.js +18 -11
- package/dist/{positional-Cptlj-xs.d.ts → positional-DJgs6ltD.d.ts} +85 -8
- package/dist/{positional-DvH_sd8u.d.cts → positional-DMZer-FM.d.cts} +85 -8
- package/dist/theory/index.cjs +35 -6
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +257 -62
- package/dist/theory/index.d.ts +257 -62
- package/dist/theory/index.js +41 -12
- package/package.json +7 -5
- package/dist/chunk-2LCPM3EG.js +0 -3224
- package/dist/chunk-2LCPM3EG.js.map +0 -1
- package/dist/chunk-6XH6QZYQ.cjs.map +0 -1
- package/dist/chunk-6XPTBE7Y.cjs +0 -49
- package/dist/chunk-6XPTBE7Y.cjs.map +0 -1
- package/dist/chunk-AFM2ULJH.cjs.map +0 -1
- package/dist/chunk-B6XNKWZV.cjs +0 -3224
- package/dist/chunk-B6XNKWZV.cjs.map +0 -1
- package/dist/chunk-E3F4AHAH.cjs.map +0 -1
- package/dist/chunk-ELCTZUJJ.js +0 -379
- package/dist/chunk-ELCTZUJJ.js.map +0 -1
- package/dist/chunk-FVSI36UV.js.map +0 -1
- package/dist/chunk-H3VORETI.js.map +0 -1
- package/dist/chunk-H42UHPYW.js +0 -1577
- package/dist/chunk-H42UHPYW.js.map +0 -1
- package/dist/chunk-HFPS7JFD.js +0 -1
- package/dist/chunk-INHVXP6Z.js.map +0 -1
- package/dist/chunk-K4ZJUGF4.cjs +0 -379
- package/dist/chunk-K4ZJUGF4.cjs.map +0 -1
- package/dist/chunk-KNJEKLKV.js +0 -49
- package/dist/chunk-KNJEKLKV.js.map +0 -1
- package/dist/chunk-MXO72PLY.cjs.map +0 -1
- package/dist/chunk-NLEU4QSE.cjs +0 -360
- package/dist/chunk-NLEU4QSE.cjs.map +0 -1
- package/dist/chunk-OE6WK2Y2.cjs +0 -1577
- package/dist/chunk-OE6WK2Y2.cjs.map +0 -1
- package/dist/chunk-PKFNUHDY.js.map +0 -1
- package/dist/chunk-Q2WGKJNN.cjs.map +0 -1
- package/dist/chunk-RHIJ3S4I.cjs +0 -1
- package/dist/chunk-RHIJ3S4I.cjs.map +0 -1
- package/dist/chunk-TTCLJX6D.js.map +0 -1
- package/dist/chunk-UADYAYAT.cjs.map +0 -1
- package/dist/chunk-VOHZB45S.js.map +0 -1
- package/dist/chunk-VTI6FOLB.js.map +0 -1
- package/dist/chunk-WWURE4XT.cjs.map +0 -1
- package/dist/chunk-YH3BIKHH.js.map +0 -1
- /package/dist/{chunk-HFPS7JFD.js.map → chunk-K6OZXIR6.js.map} +0 -0
|
@@ -24,13 +24,23 @@
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
var _chunkS5BKZZGMcjs = require('./chunk-S5BKZZGM.cjs');
|
|
28
37
|
|
|
29
38
|
// src/theory/scale/masks.ts
|
|
30
39
|
function maskFromOffsets(offsets) {
|
|
40
|
+
_chunkS5BKZZGMcjs.assertArray.call(void 0, offsets, "offsets");
|
|
31
41
|
let mask = 1;
|
|
32
42
|
for (const [index, offset] of offsets.entries()) {
|
|
33
|
-
|
|
43
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, offset, `offsets[${index}]`);
|
|
34
44
|
mask |= 1 << (offset % 12 + 12) % 12;
|
|
35
45
|
}
|
|
36
46
|
return mask;
|
|
@@ -51,6 +61,12 @@ var WHOLE_TONE_MASK = maskFromOffsets([0, 2, 4, 6, 8, 10]);
|
|
|
51
61
|
var OCTATONIC_HALF_WHOLE_MASK = maskFromOffsets([0, 1, 3, 4, 6, 7, 9, 10]);
|
|
52
62
|
var OCTATONIC_WHOLE_HALF_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 9, 11]);
|
|
53
63
|
var CHROMATIC_MASK = 4095;
|
|
64
|
+
function assertModeMask(modeMask12, name = "modeMask12") {
|
|
65
|
+
return _chunkS5BKZZGMcjs.assertInteger.call(void 0, modeMask12, name, 1, CHROMATIC_MASK);
|
|
66
|
+
}
|
|
67
|
+
function maskOf(scale, name = "key") {
|
|
68
|
+
return assertModeMask(_chunkS5BKZZGMcjs.assertRecord.call(void 0, scale, name).modeMask12, `${name}.modeMask12`);
|
|
69
|
+
}
|
|
54
70
|
var LYDIAN_DOMINANT_MASK = maskFromOffsets([0, 2, 4, 6, 7, 9, 10]);
|
|
55
71
|
var MIXOLYDIAN_B13_MASK = maskFromOffsets([0, 2, 4, 5, 7, 8, 10]);
|
|
56
72
|
var LOCRIAN_NATURAL2_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 10]);
|
|
@@ -156,6 +172,9 @@ var SCALE_ALIASES = Object.freeze({
|
|
|
156
172
|
poorvi: "purvi"
|
|
157
173
|
});
|
|
158
174
|
function resolveScaleName(name) {
|
|
175
|
+
if (typeof name !== "string") {
|
|
176
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`scale name must be a string; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, name)}`);
|
|
177
|
+
}
|
|
159
178
|
if (Object.hasOwn(NAMED_SCALES, name)) {
|
|
160
179
|
return name;
|
|
161
180
|
}
|
|
@@ -174,61 +193,158 @@ function namedScaleMask(name) {
|
|
|
174
193
|
function requireScaleMask(name, label = "scale") {
|
|
175
194
|
const mask = namedScaleMask(name);
|
|
176
195
|
if (mask === void 0) {
|
|
177
|
-
throw new (0,
|
|
196
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unknown ${label}: ${String(name)}`);
|
|
178
197
|
}
|
|
179
198
|
return mask;
|
|
180
199
|
}
|
|
200
|
+
var VARIANT_MASKS = {
|
|
201
|
+
major: MAJOR_MASK,
|
|
202
|
+
natural: NATURAL_MINOR_MASK,
|
|
203
|
+
harmonic: HARMONIC_MINOR_MASK,
|
|
204
|
+
melodic: MELODIC_MINOR_MASK
|
|
205
|
+
};
|
|
206
|
+
function isMinorMask(modeMask12) {
|
|
207
|
+
return (modeMask12 >> 3 & 1) === 1 && (modeMask12 >> 4 & 1) === 0;
|
|
208
|
+
}
|
|
209
|
+
function variantOfMask(modeMask12) {
|
|
210
|
+
assertModeMask(modeMask12);
|
|
211
|
+
for (const [variant, mask] of Object.entries(VARIANT_MASKS)) {
|
|
212
|
+
if (mask === modeMask12) {
|
|
213
|
+
return variant;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return "modal";
|
|
217
|
+
}
|
|
218
|
+
var KEY_VARIANTS = [
|
|
219
|
+
...Object.keys(VARIANT_MASKS),
|
|
220
|
+
"modal"
|
|
221
|
+
];
|
|
222
|
+
function assertKeyVariant(variant, modeMask12) {
|
|
223
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, variant, KEY_VARIANTS, "variant");
|
|
224
|
+
assertModeMask(modeMask12);
|
|
225
|
+
const named = VARIANT_MASKS[variant];
|
|
226
|
+
const matches = named === void 0 ? !Object.values(VARIANT_MASKS).includes(modeMask12) : named === modeMask12;
|
|
227
|
+
if (!matches) {
|
|
228
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
229
|
+
`variant ${variant} does not match the scale mask ${modeMask12}; pass the scale that variant names, or omit the variant`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
181
233
|
|
|
182
|
-
// src/theory/scale/
|
|
183
|
-
function
|
|
184
|
-
return { rootPc:
|
|
234
|
+
// src/theory/scale/scales.ts
|
|
235
|
+
function majorScale(rootPc) {
|
|
236
|
+
return { rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc), modeMask12: MAJOR_MASK };
|
|
185
237
|
}
|
|
186
|
-
function
|
|
187
|
-
return { rootPc:
|
|
238
|
+
function minorScale(rootPc) {
|
|
239
|
+
return { rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc), modeMask12: NATURAL_MINOR_MASK };
|
|
188
240
|
}
|
|
189
|
-
function
|
|
190
|
-
return { rootPc:
|
|
241
|
+
function namedScale(name, rootPc) {
|
|
242
|
+
return { rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc), modeMask12: requireScaleMask(name) };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/theory/scale/name.ts
|
|
246
|
+
function scaleWordKey(text) {
|
|
247
|
+
return text.replace(/[^a-z0-9]/gi, "").toLowerCase();
|
|
248
|
+
}
|
|
249
|
+
var BUILT_IN_SCALE_NAMES = [
|
|
250
|
+
...Object.keys(NAMED_SCALES),
|
|
251
|
+
...Object.keys(WORLD_SCALES),
|
|
252
|
+
...Object.keys(SCALE_ALIASES)
|
|
253
|
+
];
|
|
254
|
+
var SCALE_BY_WORD = new Map(
|
|
255
|
+
BUILT_IN_SCALE_NAMES.map((name) => [scaleWordKey(name), name])
|
|
256
|
+
);
|
|
257
|
+
function scaleNameOfMask(mask) {
|
|
258
|
+
for (const name of Object.keys(NAMED_SCALES)) {
|
|
259
|
+
if (NAMED_SCALES[name] === mask) {
|
|
260
|
+
return name;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
for (const name of Object.keys(WORLD_SCALES)) {
|
|
264
|
+
if (WORLD_SCALES[name] === mask) {
|
|
265
|
+
return name;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return void 0;
|
|
269
|
+
}
|
|
270
|
+
function bareTonic(note) {
|
|
271
|
+
return { letter: note.letter, alter: note.alter };
|
|
272
|
+
}
|
|
273
|
+
function tryNamedScaleKey(text) {
|
|
274
|
+
const trimmed = text.trim();
|
|
275
|
+
const separator = trimmed.search(/\s/);
|
|
276
|
+
if (separator < 0) {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const name = SCALE_BY_WORD.get(scaleWordKey(trimmed.slice(separator)));
|
|
280
|
+
if (name === void 0) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
const tonic = _chunkS5BKZZGMcjs.tryParseNote.call(void 0, trimmed.slice(0, separator));
|
|
284
|
+
if (!tonic.ok) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
const scale = namedScale(name, _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, tonic.value));
|
|
288
|
+
return { scale, tonic: bareTonic(tonic.value), variant: variantOfMask(scale.modeMask12) };
|
|
289
|
+
}
|
|
290
|
+
function tryResolveKeyName(text, opts) {
|
|
291
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
292
|
+
if (typeof text === "string" && (asked.system === void 0 || asked.system === "english")) {
|
|
293
|
+
const named = tryNamedScaleKey(text);
|
|
294
|
+
if (named !== null) {
|
|
295
|
+
return { ok: true, value: named };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const parsed = _chunkS5BKZZGMcjs.tryParseKeyName.call(void 0, text, asked);
|
|
299
|
+
if (!parsed.ok) {
|
|
300
|
+
return parsed;
|
|
301
|
+
}
|
|
302
|
+
const tonic = bareTonic(parsed.value.tonic);
|
|
303
|
+
const rootPc = _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, tonic);
|
|
304
|
+
return parsed.value.mode === "major" ? { ok: true, value: { scale: majorScale(rootPc), tonic, variant: "major" } } : { ok: true, value: { scale: minorScale(rootPc), tonic, variant: "natural" } };
|
|
305
|
+
}
|
|
306
|
+
function resolveKeyName(text, opts) {
|
|
307
|
+
return _chunkS5BKZZGMcjs.unwrapParse.call(void 0, tryResolveKeyName(text, opts));
|
|
191
308
|
}
|
|
192
309
|
|
|
193
310
|
// src/theory/scale/coerce.ts
|
|
194
311
|
function normalizedKeyScale(scale) {
|
|
195
|
-
|
|
312
|
+
assertModeMask(scale.modeMask12, "key.modeMask12");
|
|
196
313
|
if ((scale.modeMask12 & 1) === 0) {
|
|
197
|
-
throw new (0,
|
|
314
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
198
315
|
`key.modeMask12 must include its root; received ${scale.modeMask12}`
|
|
199
316
|
);
|
|
200
317
|
}
|
|
201
|
-
|
|
202
|
-
return { rootPc:
|
|
318
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, scale.rootPc, "key.rootPc");
|
|
319
|
+
return { rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, scale.rootPc), modeMask12: scale.modeMask12 };
|
|
203
320
|
}
|
|
204
321
|
function toKeyScale(value) {
|
|
205
322
|
if (typeof value === "string") {
|
|
206
|
-
|
|
207
|
-
const rootPc = _chunkQ2WGKJNNcjs.noteToPitchClass.call(void 0, name.tonic);
|
|
208
|
-
return name.mode === "major" ? majorKey(rootPc) : minorKey(rootPc);
|
|
323
|
+
return resolveKeyName(value).scale;
|
|
209
324
|
}
|
|
210
325
|
if (typeof value === "object" && value !== null) {
|
|
211
|
-
const data = "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON().scale : value;
|
|
326
|
+
const data = "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON().scale : "scale" in value ? value.scale : value;
|
|
212
327
|
if (typeof data === "object" && data !== null) {
|
|
213
328
|
return normalizedKeyScale(data);
|
|
214
329
|
}
|
|
215
330
|
}
|
|
216
|
-
throw new (0,
|
|
331
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`key must be a key name or a key/scale; received ${typeof value}`);
|
|
217
332
|
}
|
|
218
333
|
|
|
219
334
|
// src/theory/scale/degrees.ts
|
|
220
335
|
function scaleOffset(pitch, key) {
|
|
221
|
-
return (
|
|
336
|
+
return (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch) - _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc) + 12) % 12;
|
|
222
337
|
}
|
|
223
338
|
function inScale(pitch, scale) {
|
|
224
339
|
return (scale.modeMask12 >> scaleOffset(pitch, scale) & 1) === 1;
|
|
225
340
|
}
|
|
226
341
|
function isScaleTone(pitch, key) {
|
|
227
|
-
return inScale(pitch, key);
|
|
342
|
+
return inScale(pitch, toKeyScale(key));
|
|
228
343
|
}
|
|
229
344
|
function nearestScaleTone(pitch, key) {
|
|
230
345
|
const scale = toKeyScale(key);
|
|
231
|
-
|
|
346
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, pitch, "pitch");
|
|
347
|
+
const base = _chunkS5BKZZGMcjs.clampToMidi.call(void 0, Math.round(pitch), "pitch");
|
|
232
348
|
for (let distance = 0; distance < 12; distance += 1) {
|
|
233
349
|
const lower = base - distance;
|
|
234
350
|
if (lower >= 0 && inScale(lower, scale)) {
|
|
@@ -251,12 +367,16 @@ function scaleOffsets(key) {
|
|
|
251
367
|
return offsets;
|
|
252
368
|
}
|
|
253
369
|
function scaleLadderPosition(pitch, key) {
|
|
370
|
+
return ladderPosition(pitch, toKeyScale(key));
|
|
371
|
+
}
|
|
372
|
+
function ladderPosition(pitch, key) {
|
|
373
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, pitch, "pitch");
|
|
254
374
|
const offsets = scaleOffsets(key);
|
|
255
375
|
const size = offsets.length;
|
|
256
376
|
if (size === 0) {
|
|
257
377
|
return { rung: 0, offset: 0 };
|
|
258
378
|
}
|
|
259
|
-
const relative = pitch -
|
|
379
|
+
const relative = pitch - _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
260
380
|
const octave = Math.floor(relative / 12);
|
|
261
381
|
const within = relative - octave * 12;
|
|
262
382
|
let degree = 0;
|
|
@@ -268,22 +388,27 @@ function scaleLadderPosition(pitch, key) {
|
|
|
268
388
|
return { rung: octave * size + degree, offset: within - (_nullishCoalesce(offsets[degree], () => ( 0))) };
|
|
269
389
|
}
|
|
270
390
|
function scaleLadderPitch(rung, key) {
|
|
391
|
+
return ladderPitch(rung, toKeyScale(key));
|
|
392
|
+
}
|
|
393
|
+
function ladderPitch(rung, key) {
|
|
394
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, rung, "rung");
|
|
271
395
|
const offsets = scaleOffsets(key);
|
|
272
396
|
const size = offsets.length;
|
|
273
397
|
if (size === 0) {
|
|
274
|
-
return
|
|
398
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
275
399
|
}
|
|
276
400
|
const octave = Math.floor(rung / size);
|
|
277
401
|
const degree = rung - octave * size;
|
|
278
|
-
return
|
|
402
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc) + octave * 12 + (_nullishCoalesce(offsets[degree], () => ( 0)));
|
|
279
403
|
}
|
|
280
404
|
function shiftByScaleDegrees(pitch, degrees, key) {
|
|
281
|
-
const
|
|
405
|
+
const scale = toKeyScale(key);
|
|
406
|
+
const steps = Math.trunc(_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, degrees, "degrees"));
|
|
282
407
|
if (steps === 0) {
|
|
283
408
|
return pitch;
|
|
284
409
|
}
|
|
285
|
-
const { rung, offset } =
|
|
286
|
-
return
|
|
410
|
+
const { rung, offset } = ladderPosition(pitch, scale);
|
|
411
|
+
return ladderPitch(rung + steps, scale) + offset;
|
|
287
412
|
}
|
|
288
413
|
function pitchToScaleDegree(pitch, key) {
|
|
289
414
|
const scale = toKeyScale(key);
|
|
@@ -300,19 +425,11 @@ function pitchToScaleDegree(pitch, key) {
|
|
|
300
425
|
return degree;
|
|
301
426
|
}
|
|
302
427
|
function diatonicPitchClasses(key) {
|
|
303
|
-
|
|
304
|
-
const root = _chunkQ2WGKJNNcjs.pitchClassOf.call(void 0, scale.rootPc);
|
|
305
|
-
const pcs = [];
|
|
306
|
-
for (let n = 0; n < 12; n += 1) {
|
|
307
|
-
if ((scale.modeMask12 >> n & 1) === 1) {
|
|
308
|
-
pcs.push((root + n) % 12);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return pcs.sort((a, b) => a - b);
|
|
428
|
+
return scaleTonesInDegreeOrder(key).sort((a, b) => a - b);
|
|
312
429
|
}
|
|
313
430
|
function scaleTonesInDegreeOrder(key) {
|
|
314
|
-
const scale = key;
|
|
315
|
-
const root =
|
|
431
|
+
const scale = toKeyScale(key);
|
|
432
|
+
const root = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, scale.rootPc);
|
|
316
433
|
const pcs = [];
|
|
317
434
|
for (let n = 0; n < 12; n += 1) {
|
|
318
435
|
if ((scale.modeMask12 >> n & 1) === 1) {
|
|
@@ -348,64 +465,57 @@ var DIATONIC_MODE_OFFSETS = /* @__PURE__ */ new Map([
|
|
|
348
465
|
[rotateMask(MAJOR_MASK, 11), -5]
|
|
349
466
|
// locrian
|
|
350
467
|
]);
|
|
351
|
-
function hasMinorThird(modeMask12) {
|
|
352
|
-
return (modeMask12 >> 3 & 1) === 1 && (modeMask12 >> 4 & 1) === 0;
|
|
353
|
-
}
|
|
354
468
|
function modeOffset(key) {
|
|
355
469
|
const diatonic = DIATONIC_MODE_OFFSETS.get(key.modeMask12);
|
|
356
470
|
if (diatonic !== void 0) {
|
|
357
471
|
return diatonic;
|
|
358
472
|
}
|
|
359
|
-
return
|
|
473
|
+
return isMinorMask(key.modeMask12) ? MINOR_MODE_OFFSET : 0;
|
|
360
474
|
}
|
|
361
475
|
function isSignatureKey(key) {
|
|
362
|
-
|
|
476
|
+
const mask = maskOf(key);
|
|
477
|
+
return DIATONIC_MODE_OFFSETS.has(mask) || mask === HARMONIC_MINOR_MASK || mask === MELODIC_MINOR_MASK;
|
|
363
478
|
}
|
|
364
479
|
function keySignatureFifths(tonic, key) {
|
|
365
|
-
const note =
|
|
366
|
-
const scale = key;
|
|
367
|
-
const letter =
|
|
368
|
-
|
|
369
|
-
|
|
480
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
481
|
+
const scale = toKeyScale(key);
|
|
482
|
+
const letter = _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, note.letter);
|
|
483
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, note.alter, "tonic.alter");
|
|
484
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, scale.modeMask12, "key.modeMask12", 1, 4095);
|
|
370
485
|
return (_nullishCoalesce(LETTER_FIFTHS[letter], () => ( 0))) + FIFTHS_PER_ALTERATION * note.alter + modeOffset(scale);
|
|
371
486
|
}
|
|
372
487
|
function keyFromFifths(fifths, mode = "major") {
|
|
373
|
-
|
|
374
|
-
const which =
|
|
488
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, fifths, "fifths", -MAX_FIFTHS, MAX_FIFTHS);
|
|
489
|
+
const which = _chunkS5BKZZGMcjs.assertOneOf.call(void 0, mode, ["major", "minor"], "mode");
|
|
375
490
|
const index = fifths + 1 + (which === "minor" ? -MINOR_MODE_OFFSET : 0);
|
|
376
491
|
const letter = _nullishCoalesce(FIFTHS_LETTERS[(index % 7 + 7) % 7], () => ( 0));
|
|
377
492
|
const alter = Math.floor(index / 7);
|
|
378
|
-
const rootPc =
|
|
493
|
+
const rootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, letter) + alter);
|
|
494
|
+
const scale = which === "minor" ? minorScale(rootPc) : majorScale(rootPc);
|
|
379
495
|
return {
|
|
380
496
|
tonic: { letter, alter },
|
|
381
|
-
|
|
497
|
+
scale,
|
|
498
|
+
variant: variantOfMask(scale.modeMask12)
|
|
382
499
|
};
|
|
383
500
|
}
|
|
384
501
|
|
|
385
502
|
// src/theory/scale/relations.ts
|
|
386
503
|
var ENHARMONIC_FIFTHS = 12;
|
|
387
504
|
var MAX_CONVENTIONAL_FIFTHS = 7;
|
|
388
|
-
var DOUBLE_ACCIDENTAL = 2;
|
|
389
505
|
var MINOR_TONIC_FIFTHS = 3;
|
|
390
506
|
var FLATTEST_TONIC_FIFTHS = -MAX_CONVENTIONAL_FIFTHS;
|
|
391
507
|
var SHARPEST_TONIC_FIFTHS = MAX_CONVENTIONAL_FIFTHS + MINOR_TONIC_FIFTHS;
|
|
392
|
-
function isMinorMode(modeMask12) {
|
|
393
|
-
return (modeMask12 >> 3 & 1) === 1 && (modeMask12 >> 4 & 1) === 0;
|
|
394
|
-
}
|
|
395
|
-
function assertModeMask(key, name = "key") {
|
|
396
|
-
return _chunkQ2WGKJNNcjs.assertInteger.call(void 0, key.modeMask12, `${name}.modeMask12`, 1, CHROMATIC_MASK);
|
|
397
|
-
}
|
|
398
508
|
function modeOf(key) {
|
|
399
|
-
return
|
|
509
|
+
return isMinorMask(maskOf(key)) ? "minor" : "major";
|
|
400
510
|
}
|
|
401
511
|
function oppositeMode(mode) {
|
|
402
512
|
return mode === "major" ? "minor" : "major";
|
|
403
513
|
}
|
|
404
514
|
function soundsLike(a, b) {
|
|
405
|
-
return
|
|
515
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, a.rootPc) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, b.rootPc) && isMinorMask(a.modeMask12) === isMinorMask(b.modeMask12);
|
|
406
516
|
}
|
|
407
517
|
function spelledLike(a, b) {
|
|
408
|
-
return
|
|
518
|
+
return _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, a.letter) === _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, b.letter) && a.alter === b.alter;
|
|
409
519
|
}
|
|
410
520
|
function tonicCost(tonic, key) {
|
|
411
521
|
let doubles = 0;
|
|
@@ -413,7 +523,7 @@ function tonicCost(tonic, key) {
|
|
|
413
523
|
for (const note of spellScale(tonic, key)) {
|
|
414
524
|
const alter = Math.abs(note.alter);
|
|
415
525
|
accidentals += alter;
|
|
416
|
-
if (alter >=
|
|
526
|
+
if (alter >= _chunkS5BKZZGMcjs.MAX_NAME_ACCIDENTALS) {
|
|
417
527
|
doubles += 1;
|
|
418
528
|
}
|
|
419
529
|
}
|
|
@@ -429,14 +539,14 @@ function spellsBetter(a, b, signatureKey) {
|
|
|
429
539
|
return false;
|
|
430
540
|
}
|
|
431
541
|
function spelledKeyOf(key) {
|
|
432
|
-
const scale = key;
|
|
433
|
-
const rootPc =
|
|
542
|
+
const scale = _chunkS5BKZZGMcjs.assertRecord.call(void 0, key, "key");
|
|
543
|
+
const rootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, scale.rootPc);
|
|
434
544
|
const signatureKey = isSignatureKey(scale);
|
|
435
545
|
let tonic = keyFromFifths(0).tonic;
|
|
436
546
|
let best;
|
|
437
547
|
for (let fifths = FLATTEST_TONIC_FIFTHS; fifths <= SHARPEST_TONIC_FIFTHS; fifths += 1) {
|
|
438
548
|
const candidate = keyFromFifths(fifths).tonic;
|
|
439
|
-
if (
|
|
549
|
+
if (_chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, candidate) !== rootPc) {
|
|
440
550
|
continue;
|
|
441
551
|
}
|
|
442
552
|
const cost = tonicCost(candidate, scale);
|
|
@@ -445,73 +555,76 @@ function spelledKeyOf(key) {
|
|
|
445
555
|
best = cost;
|
|
446
556
|
}
|
|
447
557
|
}
|
|
448
|
-
return { tonic, key };
|
|
558
|
+
return { tonic, scale: key, variant: variantOfMask(key.modeMask12) };
|
|
449
559
|
}
|
|
450
560
|
function relativeKeyOf(tonic, key) {
|
|
451
|
-
const
|
|
452
|
-
return keyFromFifths(
|
|
561
|
+
const mode = modeOf(toKeyScale(key));
|
|
562
|
+
return keyFromFifths(tonicFifths(_chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic), mode), oppositeMode(mode));
|
|
453
563
|
}
|
|
454
564
|
function parallelKeyOf(tonic, key) {
|
|
455
|
-
const note =
|
|
565
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
456
566
|
const mode = oppositeMode(modeOf(toKeyScale(key)));
|
|
457
|
-
const rootPc =
|
|
567
|
+
const rootPc = _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, note);
|
|
568
|
+
const scale = mode === "minor" ? minorScale(rootPc) : majorScale(rootPc);
|
|
458
569
|
return {
|
|
459
|
-
tonic: { letter:
|
|
460
|
-
|
|
570
|
+
tonic: { letter: _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, note.letter), alter: note.alter },
|
|
571
|
+
scale,
|
|
572
|
+
variant: variantOfMask(scale.modeMask12)
|
|
461
573
|
};
|
|
462
574
|
}
|
|
463
575
|
function tonicPosition(tonic) {
|
|
464
|
-
return keySignatureFifths(tonic,
|
|
576
|
+
return keySignatureFifths(tonic, majorScale(_chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, tonic)));
|
|
465
577
|
}
|
|
466
578
|
function tonicFifths(tonic, mode) {
|
|
467
579
|
return tonicPosition(tonic) - (mode === "minor" ? MINOR_TONIC_FIFTHS : 0);
|
|
468
580
|
}
|
|
469
581
|
function isWrittenTonic(tonic, key) {
|
|
470
582
|
const position = tonicPosition(tonic);
|
|
471
|
-
if (
|
|
472
|
-
return
|
|
583
|
+
if (isSignatureKey(key)) {
|
|
584
|
+
return Math.abs(position) <= MAX_FIFTHS && Math.abs(keySignatureFifths(tonic, key)) <= MAX_CONVENTIONAL_FIFTHS;
|
|
473
585
|
}
|
|
474
|
-
return
|
|
586
|
+
return position >= FLATTEST_TONIC_FIFTHS && position <= SHARPEST_TONIC_FIFTHS && tonicCost(tonic, { rootPc: _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, tonic), modeMask12: key.modeMask12 }).doubles === 0;
|
|
475
587
|
}
|
|
476
588
|
function dominantKeyOf(tonic, key) {
|
|
477
589
|
const mode = modeOf(toKeyScale(key));
|
|
478
|
-
return keyFromFifths(tonicFifths(
|
|
590
|
+
return keyFromFifths(tonicFifths(_chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic), mode) + 1, mode);
|
|
479
591
|
}
|
|
480
592
|
function subdominantKeyOf(tonic, key) {
|
|
481
593
|
const mode = modeOf(toKeyScale(key));
|
|
482
|
-
return keyFromFifths(tonicFifths(
|
|
594
|
+
return keyFromFifths(tonicFifths(_chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic), mode) - 1, mode);
|
|
483
595
|
}
|
|
484
596
|
function enharmonicKeyOf(tonic, key) {
|
|
485
|
-
const note =
|
|
597
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
486
598
|
const scale = toKeyScale(key);
|
|
487
|
-
|
|
599
|
+
maskOf(scale);
|
|
488
600
|
for (const position of [
|
|
489
601
|
tonicPosition(note) - ENHARMONIC_FIFTHS,
|
|
490
602
|
tonicPosition(note) + ENHARMONIC_FIFTHS
|
|
491
603
|
]) {
|
|
492
|
-
if (position
|
|
604
|
+
if (Math.abs(position) > MAX_FIFTHS) {
|
|
493
605
|
continue;
|
|
494
606
|
}
|
|
495
|
-
const
|
|
496
|
-
if (!isWrittenTonic(
|
|
607
|
+
const spelled2 = keyFromFifths(position).tonic;
|
|
608
|
+
if (!isWrittenTonic(spelled2, scale)) {
|
|
497
609
|
continue;
|
|
498
610
|
}
|
|
499
611
|
return {
|
|
500
|
-
tonic:
|
|
612
|
+
tonic: spelled2,
|
|
501
613
|
// The mask is the caller's; only the root is re-read, so a tonic that did
|
|
502
614
|
// not spell the mask's own root still comes back consistent.
|
|
503
|
-
|
|
615
|
+
scale: { rootPc: _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, spelled2), modeMask12: scale.modeMask12 },
|
|
616
|
+
variant: variantOfMask(scale.modeMask12)
|
|
504
617
|
};
|
|
505
618
|
}
|
|
506
619
|
return null;
|
|
507
620
|
}
|
|
508
621
|
function relativeOfDominantKeyOf(tonic, key) {
|
|
509
622
|
const dominant = dominantKeyOf(tonic, key);
|
|
510
|
-
return relativeKeyOf(dominant.tonic, dominant.
|
|
623
|
+
return relativeKeyOf(dominant.tonic, dominant.scale);
|
|
511
624
|
}
|
|
512
625
|
function relativeOfSubdominantKeyOf(tonic, key) {
|
|
513
626
|
const subdominant = subdominantKeyOf(tonic, key);
|
|
514
|
-
return relativeKeyOf(subdominant.tonic, subdominant.
|
|
627
|
+
return relativeKeyOf(subdominant.tonic, subdominant.scale);
|
|
515
628
|
}
|
|
516
629
|
var CLOSELY_RELATED = [
|
|
517
630
|
{ relation: "relative", of: relativeKeyOf },
|
|
@@ -522,24 +635,73 @@ var CLOSELY_RELATED = [
|
|
|
522
635
|
{ relation: "relativeOfSubdominant", of: relativeOfSubdominantKeyOf }
|
|
523
636
|
];
|
|
524
637
|
function relatedKeysOf(tonic, key) {
|
|
525
|
-
const note =
|
|
638
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
526
639
|
const scale = toKeyScale(key);
|
|
527
640
|
return CLOSELY_RELATED.map(({ relation, of }) => ({ ...of(note, scale), relation }));
|
|
528
641
|
}
|
|
529
642
|
function keyRelationBetween(a, b) {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
643
|
+
const from = _chunkS5BKZZGMcjs.assertRecord.call(void 0, a, "a");
|
|
644
|
+
const to = _chunkS5BKZZGMcjs.assertRecord.call(void 0, b, "b");
|
|
645
|
+
maskOf(from.scale, "a.scale");
|
|
646
|
+
maskOf(to.scale, "b.scale");
|
|
647
|
+
if (soundsLike(from.scale, to.scale)) {
|
|
648
|
+
return spelledLike(from.tonic, to.tonic) ? "same" : "enharmonic";
|
|
534
649
|
}
|
|
535
650
|
for (const { relation, of } of CLOSELY_RELATED) {
|
|
536
|
-
if (soundsLike(of(
|
|
651
|
+
if (soundsLike(of(from.tonic, from.scale).scale, to.scale)) {
|
|
537
652
|
return relation;
|
|
538
653
|
}
|
|
539
654
|
}
|
|
540
655
|
return null;
|
|
541
656
|
}
|
|
542
657
|
|
|
658
|
+
// src/theory/scale/identity.ts
|
|
659
|
+
function carriesIdentity(value) {
|
|
660
|
+
return typeof value === "object" && value !== null;
|
|
661
|
+
}
|
|
662
|
+
function carriedTonic(tonic, scale) {
|
|
663
|
+
if (_chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, tonic) !== scale.rootPc) {
|
|
664
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
665
|
+
`tonic ${_chunkS5BKZZGMcjs.formatNote.call(void 0, tonic)} does not match the scale root pitch class ${scale.rootPc}; pass a tonic that spells the scale root, or omit it to have one chosen`
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
return { letter: tonic.letter, alter: tonic.alter };
|
|
669
|
+
}
|
|
670
|
+
function carriedVariant(variant, scale) {
|
|
671
|
+
assertKeyVariant(variant, scale.modeMask12);
|
|
672
|
+
return variant;
|
|
673
|
+
}
|
|
674
|
+
function resolveKey(value) {
|
|
675
|
+
if (typeof value === "string") {
|
|
676
|
+
return resolveKeyName(value);
|
|
677
|
+
}
|
|
678
|
+
const scale = toKeyScale(value);
|
|
679
|
+
const carried = carriesIdentity(value) && "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON() : value;
|
|
680
|
+
const tonic = carriesIdentity(carried) && carried.tonic !== void 0 ? carriedTonic(carried.tonic, scale) : spelledKeyOf(scale).tonic;
|
|
681
|
+
const variant = carriesIdentity(carried) && carried.variant !== void 0 ? carriedVariant(carried.variant, scale) : variantOfMask(scale.modeMask12);
|
|
682
|
+
return { scale, tonic, variant };
|
|
683
|
+
}
|
|
684
|
+
function scaleOf(key) {
|
|
685
|
+
const scale = _chunkS5BKZZGMcjs.assertRecord.call(void 0, key, "key").scale;
|
|
686
|
+
maskOf(scale, "key.scale");
|
|
687
|
+
return scale;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// src/theory/scale/key.ts
|
|
691
|
+
function spelled(scale) {
|
|
692
|
+
const { tonic, variant } = spelledKeyOf(scale);
|
|
693
|
+
return { ...scale, tonic, variant };
|
|
694
|
+
}
|
|
695
|
+
function majorKey(rootPc) {
|
|
696
|
+
return spelled(majorScale(rootPc));
|
|
697
|
+
}
|
|
698
|
+
function minorKey(rootPc) {
|
|
699
|
+
return spelled(minorScale(rootPc));
|
|
700
|
+
}
|
|
701
|
+
function scaleByName(name, rootPc) {
|
|
702
|
+
return spelled(namedScale(name, rootPc));
|
|
703
|
+
}
|
|
704
|
+
|
|
543
705
|
// src/theory/scale/system.ts
|
|
544
706
|
var SCALE_SYSTEMS = Object.freeze({
|
|
545
707
|
major: "common-practice",
|
|
@@ -603,11 +765,11 @@ function scaleSystemOf(scale) {
|
|
|
603
765
|
if (typeof scale === "string") {
|
|
604
766
|
const canonical = resolveScaleName(scale);
|
|
605
767
|
if (canonical === void 0) {
|
|
606
|
-
throw new (0,
|
|
768
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unknown scale: ${scale}`);
|
|
607
769
|
}
|
|
608
770
|
return SCALE_SYSTEMS[canonical];
|
|
609
771
|
}
|
|
610
|
-
return SYSTEM_BY_MASK.get(scale
|
|
772
|
+
return SYSTEM_BY_MASK.get(maskOf(scale, "scale"));
|
|
611
773
|
}
|
|
612
774
|
function supportsFunctionalHarmony(scale) {
|
|
613
775
|
return scaleSystemOf(scale) !== "non-functional";
|
|
@@ -653,6 +815,7 @@ var BASE_TONES = {
|
|
|
653
815
|
var SEVENTH_SEMITONES = { maj7: 11, min7: 10, dim7: 9 };
|
|
654
816
|
var DEGREE_SEMITONES = { 6: 9, 9: 14, 11: 17, 13: 21 };
|
|
655
817
|
var PERFECT_FIFTH = 7;
|
|
818
|
+
var FIFTH_KEY = "5";
|
|
656
819
|
var OMITTABLE_DEGREES = [1, 3, 5];
|
|
657
820
|
var BASE_QUALITY = {
|
|
658
821
|
maj: "maj",
|
|
@@ -676,114 +839,149 @@ function parts(base, spec = {}) {
|
|
|
676
839
|
}
|
|
677
840
|
return built;
|
|
678
841
|
}
|
|
679
|
-
var QUALITY_SPECS =
|
|
680
|
-
maj
|
|
681
|
-
min
|
|
682
|
-
dim
|
|
683
|
-
aug
|
|
684
|
-
majb5
|
|
685
|
-
maj7
|
|
686
|
-
min7
|
|
687
|
-
dom7
|
|
688
|
-
dim7
|
|
689
|
-
m7b5
|
|
690
|
-
minMaj7
|
|
691
|
-
minMaj9
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
[
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
"
|
|
719
|
-
"
|
|
720
|
-
"
|
|
721
|
-
"
|
|
842
|
+
var QUALITY_SPECS = [
|
|
843
|
+
["maj", parts("maj")],
|
|
844
|
+
["min", parts("min")],
|
|
845
|
+
["dim", parts("dim")],
|
|
846
|
+
["aug", parts("aug")],
|
|
847
|
+
["majb5", parts("maj", { alt: [[5, -1]] })],
|
|
848
|
+
["maj7", parts("maj", { seventh: "maj7" })],
|
|
849
|
+
["min7", parts("min", { seventh: "min7" })],
|
|
850
|
+
["dom7", parts("maj", { seventh: "min7" })],
|
|
851
|
+
["dim7", parts("dim", { seventh: "dim7" })],
|
|
852
|
+
["m7b5", parts("dim", { seventh: "min7" })],
|
|
853
|
+
["minMaj7", parts("min", { seventh: "maj7" })],
|
|
854
|
+
["minMaj9", parts("min", { seventh: "maj7", alt: [[9, 0]] })],
|
|
855
|
+
[
|
|
856
|
+
"minMaj11",
|
|
857
|
+
parts("min", {
|
|
858
|
+
seventh: "maj7",
|
|
859
|
+
alt: [
|
|
860
|
+
[9, 0],
|
|
861
|
+
[11, 0]
|
|
862
|
+
]
|
|
863
|
+
})
|
|
864
|
+
],
|
|
865
|
+
[
|
|
866
|
+
"minMaj13",
|
|
867
|
+
parts("min", {
|
|
868
|
+
seventh: "maj7",
|
|
869
|
+
alt: [
|
|
870
|
+
[9, 0],
|
|
871
|
+
[13, 0]
|
|
872
|
+
]
|
|
873
|
+
})
|
|
874
|
+
],
|
|
875
|
+
["aug7", parts("aug", { seventh: "min7" })],
|
|
876
|
+
["augMaj7", parts("aug", { seventh: "maj7" })],
|
|
877
|
+
["6", parts("maj", { add: [6] })],
|
|
878
|
+
["min6", parts("min", { add: [6] })],
|
|
879
|
+
["6/9", parts("maj", { add: [6, 9] })],
|
|
880
|
+
["sus2", parts("sus2")],
|
|
881
|
+
["sus4", parts("sus4")],
|
|
882
|
+
["add9", parts("maj", { add: [9] })],
|
|
883
|
+
["add11", parts("maj", { add: [11] })],
|
|
884
|
+
["maj9", parts("maj", { seventh: "maj7", alt: [[9, 0]] })],
|
|
885
|
+
["min9", parts("min", { seventh: "min7", alt: [[9, 0]] })],
|
|
886
|
+
["dom9", parts("maj", { seventh: "min7", alt: [[9, 0]] })],
|
|
887
|
+
["7b9", parts("maj", { seventh: "min7", alt: [[9, -1]] })],
|
|
888
|
+
["7#9", parts("maj", { seventh: "min7", alt: [[9, 1]] })],
|
|
889
|
+
["7#11", parts("maj", { seventh: "min7", alt: [[11, 1]] })],
|
|
890
|
+
["7b13", parts("maj", { seventh: "min7", alt: [[13, -1]] })],
|
|
722
891
|
// The eleventh chord as a chart voices it: the third gives way to the
|
|
723
892
|
// eleventh a semitone above it rather than sounding against it.
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
[
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
893
|
+
[
|
|
894
|
+
"11",
|
|
895
|
+
parts("maj", {
|
|
896
|
+
seventh: "min7",
|
|
897
|
+
alt: [
|
|
898
|
+
[9, 0],
|
|
899
|
+
[11, 0]
|
|
900
|
+
],
|
|
901
|
+
omit: [3]
|
|
902
|
+
})
|
|
903
|
+
],
|
|
904
|
+
[
|
|
905
|
+
"13",
|
|
906
|
+
parts("maj", {
|
|
907
|
+
seventh: "min7",
|
|
908
|
+
alt: [
|
|
909
|
+
[9, 0],
|
|
910
|
+
[13, 0]
|
|
911
|
+
]
|
|
912
|
+
})
|
|
913
|
+
],
|
|
914
|
+
["5", parts("power")],
|
|
915
|
+
["7sus4", parts("sus4", { seventh: "min7" })],
|
|
916
|
+
["7b5", parts("maj", { seventh: "min7", alt: [[5, -1]] })],
|
|
742
917
|
// The altered dominant as it is voiced from a lead sheet: a dominant seventh
|
|
743
918
|
// with a raised fifth and a raised ninth. The full seven-note altered stack
|
|
744
919
|
// has no seven-letter spelling, so it is not what this symbol denotes.
|
|
745
|
-
"7alt"
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
[
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
[
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
920
|
+
["7alt", parts("aug", { seventh: "min7", alt: [[9, 1]] })],
|
|
921
|
+
[
|
|
922
|
+
"13b9",
|
|
923
|
+
parts("maj", {
|
|
924
|
+
seventh: "min7",
|
|
925
|
+
alt: [
|
|
926
|
+
[9, -1],
|
|
927
|
+
[13, 0]
|
|
928
|
+
]
|
|
929
|
+
})
|
|
930
|
+
],
|
|
931
|
+
[
|
|
932
|
+
"maj13",
|
|
933
|
+
parts("maj", {
|
|
934
|
+
seventh: "maj7",
|
|
935
|
+
alt: [
|
|
936
|
+
[9, 0],
|
|
937
|
+
[13, 0]
|
|
938
|
+
]
|
|
939
|
+
})
|
|
940
|
+
],
|
|
941
|
+
["maj7#11", parts("maj", { seventh: "maj7", alt: [[11, 1]] })],
|
|
942
|
+
[
|
|
943
|
+
"min11",
|
|
944
|
+
parts("min", {
|
|
945
|
+
seventh: "min7",
|
|
946
|
+
alt: [
|
|
947
|
+
[9, 0],
|
|
948
|
+
[11, 0]
|
|
949
|
+
]
|
|
950
|
+
})
|
|
951
|
+
],
|
|
952
|
+
[
|
|
953
|
+
"min13",
|
|
954
|
+
parts("min", {
|
|
955
|
+
seventh: "min7",
|
|
956
|
+
alt: [
|
|
957
|
+
[9, 0],
|
|
958
|
+
[13, 0]
|
|
959
|
+
]
|
|
960
|
+
})
|
|
961
|
+
],
|
|
962
|
+
["minAdd9", parts("min", { add: [9] })],
|
|
963
|
+
["min6/9", parts("min", { add: [6, 9] })]
|
|
964
|
+
];
|
|
965
|
+
var QUALITY_ORDER = QUALITY_SPECS.map(([quality]) => quality);
|
|
966
|
+
var SPEC_BY_QUALITY = new Map(QUALITY_SPECS);
|
|
778
967
|
function normalizeChordSpec(spec) {
|
|
779
968
|
let base = spec.base;
|
|
780
969
|
const alterations = /* @__PURE__ */ new Map();
|
|
781
970
|
for (const alteration of _nullishCoalesce(spec.alterations, () => ( []))) {
|
|
782
|
-
|
|
971
|
+
const { degree, alter } = alteration;
|
|
972
|
+
if (degree === 5) {
|
|
973
|
+
const current = alterations.get(FIFTH_KEY);
|
|
974
|
+
if (current !== void 0 && current.alter <= alter) {
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
alterations.set(FIFTH_KEY, { degree, alter });
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
alterations.set(`${degree}:${alter}`, { degree, alter });
|
|
783
981
|
}
|
|
784
982
|
const additions = new Set(_nullishCoalesce(spec.additions, () => ( [])));
|
|
785
983
|
const omissions = new Set(_nullishCoalesce(spec.omissions, () => ( [])));
|
|
786
|
-
const fifth = alterations.get(
|
|
984
|
+
const fifth = _optionalChain([alterations, 'access', _2 => _2.get, 'call', _3 => _3(FIFTH_KEY), 'optionalAccess', _4 => _4.alter]);
|
|
787
985
|
if (fifth !== void 0) {
|
|
788
986
|
if (base === "aug") {
|
|
789
987
|
base = "maj";
|
|
@@ -791,19 +989,19 @@ function normalizeChordSpec(spec) {
|
|
|
791
989
|
base = "min";
|
|
792
990
|
}
|
|
793
991
|
if (fifth === 0) {
|
|
794
|
-
alterations.delete(
|
|
992
|
+
alterations.delete(FIFTH_KEY);
|
|
795
993
|
} else if (base === "maj" && fifth === 1) {
|
|
796
994
|
base = "aug";
|
|
797
|
-
alterations.delete(
|
|
995
|
+
alterations.delete(FIFTH_KEY);
|
|
798
996
|
} else if (base === "min" && fifth === -1) {
|
|
799
997
|
base = "dim";
|
|
800
|
-
alterations.delete(
|
|
998
|
+
alterations.delete(FIFTH_KEY);
|
|
801
999
|
}
|
|
802
1000
|
}
|
|
803
1001
|
if (spec.seventh === void 0) {
|
|
804
|
-
for (const [degree, alter] of [...alterations]) {
|
|
1002
|
+
for (const [key, { degree, alter }] of [...alterations]) {
|
|
805
1003
|
if (degree !== 5 && alter === 0) {
|
|
806
|
-
alterations.delete(
|
|
1004
|
+
alterations.delete(key);
|
|
807
1005
|
additions.add(degree);
|
|
808
1006
|
}
|
|
809
1007
|
}
|
|
@@ -811,7 +1009,7 @@ function normalizeChordSpec(spec) {
|
|
|
811
1009
|
const normalized = {
|
|
812
1010
|
rootPc: spec.rootPc,
|
|
813
1011
|
base,
|
|
814
|
-
alterations: [...alterations].sort((a, b) => a
|
|
1012
|
+
alterations: [...alterations.values()].sort((a, b) => a.degree - b.degree || a.alter - b.alter),
|
|
815
1013
|
additions: [...additions].sort((a, b) => a - b),
|
|
816
1014
|
omissions: [...omissions].sort((a, b) => a - b)
|
|
817
1015
|
};
|
|
@@ -851,10 +1049,7 @@ function chordSpecIntervals(spec) {
|
|
|
851
1049
|
return specIntervals(assertChordSpec(spec));
|
|
852
1050
|
}
|
|
853
1051
|
var QUALITY_INTERVALS = Object.fromEntries(
|
|
854
|
-
|
|
855
|
-
quality,
|
|
856
|
-
specIntervals(normalizeChordSpec(QUALITY_SPECS[quality]))
|
|
857
|
-
])
|
|
1052
|
+
QUALITY_SPECS.map(([quality, spec]) => [quality, specIntervals(normalizeChordSpec(spec))])
|
|
858
1053
|
);
|
|
859
1054
|
function specKey(spec) {
|
|
860
1055
|
const normalized = normalizeChordSpec(spec);
|
|
@@ -867,16 +1062,14 @@ function specKey(spec) {
|
|
|
867
1062
|
].join("|");
|
|
868
1063
|
}
|
|
869
1064
|
var QUALITY_BY_KEY = new Map(
|
|
870
|
-
|
|
871
|
-
specKey(QUALITY_SPECS[quality]),
|
|
872
|
-
quality
|
|
873
|
-
])
|
|
1065
|
+
QUALITY_SPECS.map(([quality, spec]) => [specKey(spec), quality])
|
|
874
1066
|
);
|
|
875
1067
|
function chordSpecForQuality(quality, rootPc, bassPc) {
|
|
876
|
-
|
|
877
|
-
|
|
1068
|
+
const named = SPEC_BY_QUALITY.get(quality);
|
|
1069
|
+
if (named === void 0) {
|
|
1070
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unknown chord quality: ${String(quality)}`);
|
|
878
1071
|
}
|
|
879
|
-
const spec = normalizeChordSpec(
|
|
1072
|
+
const spec = normalizeChordSpec(named);
|
|
880
1073
|
spec.rootPc = rootPc;
|
|
881
1074
|
if (bassPc !== void 0) {
|
|
882
1075
|
spec.bassPc = bassPc;
|
|
@@ -892,10 +1085,10 @@ function chordSpecQuality(spec) {
|
|
|
892
1085
|
if (exact !== void 0) {
|
|
893
1086
|
return exact;
|
|
894
1087
|
}
|
|
895
|
-
const offsets = new Set(specIntervals(checked));
|
|
1088
|
+
const offsets = new Set(specIntervals({ ...checked, omissions: [] }));
|
|
896
1089
|
let nearest;
|
|
897
1090
|
let size = 0;
|
|
898
|
-
for (const quality of
|
|
1091
|
+
for (const quality of QUALITY_ORDER) {
|
|
899
1092
|
const template = QUALITY_INTERVALS[quality];
|
|
900
1093
|
if (template.length > size && template.every((offset) => offsets.has(offset))) {
|
|
901
1094
|
nearest = quality;
|
|
@@ -981,15 +1174,15 @@ function chordSpecFromIntervals(intervals) {
|
|
|
981
1174
|
}
|
|
982
1175
|
function assertPart(value, allowed, name) {
|
|
983
1176
|
if (!allowed.includes(value)) {
|
|
984
|
-
throw new (0,
|
|
985
|
-
`${name} must be one of ${allowed.join(", ")}; received ${
|
|
1177
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
1178
|
+
`${name} must be one of ${allowed.join(", ")}; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, value)}`
|
|
986
1179
|
);
|
|
987
1180
|
}
|
|
988
1181
|
return value;
|
|
989
1182
|
}
|
|
990
1183
|
function assertDegreeIn(value, allowed, name) {
|
|
991
1184
|
if (!allowed.includes(value)) {
|
|
992
|
-
throw new (0,
|
|
1185
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
993
1186
|
`${name} must be one of ${allowed.join(", ")}; received ${String(value)}`
|
|
994
1187
|
);
|
|
995
1188
|
}
|
|
@@ -997,7 +1190,7 @@ function assertDegreeIn(value, allowed, name) {
|
|
|
997
1190
|
}
|
|
998
1191
|
function assertDegreeList(value, allowed, name) {
|
|
999
1192
|
if (!Array.isArray(value)) {
|
|
1000
|
-
throw new (0,
|
|
1193
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be an array; received ${typeof value}`);
|
|
1001
1194
|
}
|
|
1002
1195
|
for (const degree of value) {
|
|
1003
1196
|
assertDegreeIn(degree, allowed, name);
|
|
@@ -1005,11 +1198,11 @@ function assertDegreeList(value, allowed, name) {
|
|
|
1005
1198
|
}
|
|
1006
1199
|
function assertChordSpec(spec) {
|
|
1007
1200
|
if (spec === null || typeof spec !== "object") {
|
|
1008
|
-
throw new (0,
|
|
1201
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`chord spec must be an object; received ${typeof spec}`);
|
|
1009
1202
|
}
|
|
1010
|
-
|
|
1203
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, spec.rootPc, "chord spec rootPc");
|
|
1011
1204
|
if (spec.bassPc !== void 0) {
|
|
1012
|
-
|
|
1205
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, spec.bassPc, "chord spec bassPc");
|
|
1013
1206
|
}
|
|
1014
1207
|
assertPart(spec.base, Object.keys(BASE_TONES), "chord spec base");
|
|
1015
1208
|
if (spec.seventh !== void 0) {
|
|
@@ -1020,10 +1213,10 @@ function assertChordSpec(spec) {
|
|
|
1020
1213
|
);
|
|
1021
1214
|
}
|
|
1022
1215
|
if (!Array.isArray(spec.alterations)) {
|
|
1023
|
-
throw new (0,
|
|
1216
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("chord spec alterations must be an array");
|
|
1024
1217
|
}
|
|
1025
1218
|
for (const alteration of spec.alterations) {
|
|
1026
|
-
assertDegreeIn(_optionalChain([alteration, 'optionalAccess',
|
|
1219
|
+
assertDegreeIn(_optionalChain([alteration, 'optionalAccess', _5 => _5.degree]), [5, 9, 11, 13], "chord spec alteration degree");
|
|
1027
1220
|
assertDegreeIn(alteration.alter, [-1, 0, 1], "chord spec alteration");
|
|
1028
1221
|
}
|
|
1029
1222
|
assertDegreeList(spec.additions, [6, 9, 11, 13], "chord spec additions");
|
|
@@ -1034,54 +1227,63 @@ function assertChordSpec(spec) {
|
|
|
1034
1227
|
// src/theory/chord/index.ts
|
|
1035
1228
|
var MAX_CHORD_INTERVAL = 127;
|
|
1036
1229
|
function chordQualities() {
|
|
1037
|
-
return
|
|
1230
|
+
return [...QUALITY_ORDER];
|
|
1038
1231
|
}
|
|
1039
|
-
function
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
throw new (0, _chunkQ2WGKJNNcjs.InvalidInputError)(`Unknown chord quality: ${String(ext)}`);
|
|
1232
|
+
function assertChordQuality(quality) {
|
|
1233
|
+
if (!Object.hasOwn(QUALITY_INTERVALS, quality)) {
|
|
1234
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unknown chord quality: ${String(quality)}`);
|
|
1043
1235
|
}
|
|
1236
|
+
return quality;
|
|
1237
|
+
}
|
|
1238
|
+
function assertChord(chord, name = "chord") {
|
|
1239
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, chord, name);
|
|
1240
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, read.rootPc, `${name}.rootPc`);
|
|
1241
|
+
assertChordQuality(read.quality);
|
|
1242
|
+
return read;
|
|
1243
|
+
}
|
|
1244
|
+
function chordFromDegree(degree, ext, key) {
|
|
1245
|
+
_chunkS5BKZZGMcjs.assertDegree.call(void 0, degree, "chord degree");
|
|
1246
|
+
assertChordQuality(ext);
|
|
1044
1247
|
const scale = toKeyScale(key);
|
|
1045
1248
|
const tones = scaleTonesInDegreeOrder(scale);
|
|
1046
1249
|
const length = tones.length;
|
|
1047
1250
|
const index = length > 0 ? (degree - 1) % length : 0;
|
|
1048
|
-
const rootPc = _nullishCoalesce(tones[index], () => (
|
|
1251
|
+
const rootPc = _nullishCoalesce(tones[index], () => ( _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, scale.rootPc)));
|
|
1049
1252
|
return { rootPc, quality: ext, intervals: [...QUALITY_INTERVALS[ext]] };
|
|
1050
1253
|
}
|
|
1051
1254
|
function makeChord(rootPc, quality, bassPc) {
|
|
1052
|
-
|
|
1255
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, rootPc, "chord rootPc");
|
|
1053
1256
|
if (bassPc !== void 0) {
|
|
1054
|
-
|
|
1055
|
-
}
|
|
1056
|
-
if (!Object.hasOwn(QUALITY_INTERVALS, quality)) {
|
|
1057
|
-
throw new (0, _chunkQ2WGKJNNcjs.InvalidInputError)(`Unknown chord quality: ${String(quality)}`);
|
|
1257
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, bassPc, "chord bassPc");
|
|
1058
1258
|
}
|
|
1259
|
+
assertChordQuality(quality);
|
|
1059
1260
|
const chord = {
|
|
1060
|
-
rootPc:
|
|
1261
|
+
rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc),
|
|
1061
1262
|
quality,
|
|
1062
1263
|
intervals: [..._nullishCoalesce(QUALITY_INTERVALS[quality], () => ( []))]
|
|
1063
1264
|
};
|
|
1064
1265
|
if (bassPc !== void 0) {
|
|
1065
|
-
chord.bassPc =
|
|
1266
|
+
chord.bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, bassPc);
|
|
1066
1267
|
}
|
|
1067
1268
|
return chord;
|
|
1068
1269
|
}
|
|
1069
1270
|
function chordFromSpec(spec) {
|
|
1070
1271
|
const checked = assertChordSpec(spec);
|
|
1071
1272
|
const chord = {
|
|
1072
|
-
rootPc:
|
|
1273
|
+
rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, checked.rootPc),
|
|
1073
1274
|
quality: chordSpecQuality(checked),
|
|
1074
1275
|
intervals: chordSpecIntervals(checked)
|
|
1075
1276
|
};
|
|
1076
1277
|
if (checked.bassPc !== void 0) {
|
|
1077
|
-
chord.bassPc =
|
|
1278
|
+
chord.bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, checked.bassPc);
|
|
1078
1279
|
}
|
|
1079
1280
|
return chord;
|
|
1080
1281
|
}
|
|
1081
1282
|
function chordSpecOf(chord) {
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
const
|
|
1283
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, chord, "chord");
|
|
1284
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, chord.rootPc, "chord rootPc");
|
|
1285
|
+
const rootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc);
|
|
1286
|
+
const bassPc = chord.bassPc === void 0 ? void 0 : _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.bassPc);
|
|
1085
1287
|
const intervals = _nullishCoalesce(chord.intervals, () => ( []));
|
|
1086
1288
|
const read = intervals.length === 0 ? void 0 : chordSpecFromIntervals(intervals);
|
|
1087
1289
|
if (read === void 0) {
|
|
@@ -1096,21 +1298,21 @@ function chordSpecOf(chord) {
|
|
|
1096
1298
|
function copySpanIntervals(intervals) {
|
|
1097
1299
|
const name = "chord span intervals";
|
|
1098
1300
|
if (!Array.isArray(intervals)) {
|
|
1099
|
-
throw new (0,
|
|
1301
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must be an array; received ${typeof intervals}`);
|
|
1100
1302
|
}
|
|
1101
1303
|
if (intervals.length === 0) {
|
|
1102
|
-
throw new (0,
|
|
1304
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`${name} must name at least one interval`);
|
|
1103
1305
|
}
|
|
1104
1306
|
const copy = [];
|
|
1105
1307
|
for (let index = 0; index < intervals.length; index += 1) {
|
|
1106
1308
|
const interval = intervals[index];
|
|
1107
1309
|
if (interval === void 0) {
|
|
1108
|
-
throw new (0,
|
|
1310
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
1109
1311
|
`${name}[${index}] must be a semitone offset; received undefined`
|
|
1110
1312
|
);
|
|
1111
1313
|
}
|
|
1112
1314
|
copy.push(
|
|
1113
|
-
|
|
1315
|
+
_chunkS5BKZZGMcjs.assertInteger.call(void 0, interval, `${name}[${index}]`, -MAX_CHORD_INTERVAL, MAX_CHORD_INTERVAL)
|
|
1114
1316
|
);
|
|
1115
1317
|
}
|
|
1116
1318
|
return copy;
|
|
@@ -1119,6 +1321,7 @@ function hasCustomIntervals(chord) {
|
|
|
1119
1321
|
return !matchesQualityIntervals(chord.quality, chord.intervals);
|
|
1120
1322
|
}
|
|
1121
1323
|
function chordFromSpan(span) {
|
|
1324
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, span, "chord span");
|
|
1122
1325
|
const chord = makeChord(span.rootPc, span.quality, span.bassPc);
|
|
1123
1326
|
if (span.intervals !== void 0) {
|
|
1124
1327
|
chord.intervals = copySpanIntervals(span.intervals);
|
|
@@ -1126,10 +1329,8 @@ function chordFromSpan(span) {
|
|
|
1126
1329
|
return chord;
|
|
1127
1330
|
}
|
|
1128
1331
|
function spanFromChord(chord, startBeat) {
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
throw new (0, _chunkQ2WGKJNNcjs.InvalidInputError)(`Unknown chord quality: ${String(chord.quality)}`);
|
|
1132
|
-
}
|
|
1332
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, startBeat, "chord span startBeat");
|
|
1333
|
+
assertChord(chord);
|
|
1133
1334
|
const span = { rootPc: chord.rootPc, quality: chord.quality, startBeat };
|
|
1134
1335
|
if (chord.bassPc !== void 0) {
|
|
1135
1336
|
span.bassPc = chord.bassPc;
|
|
@@ -1140,15 +1341,16 @@ function spanFromChord(chord, startBeat) {
|
|
|
1140
1341
|
return span;
|
|
1141
1342
|
}
|
|
1142
1343
|
function transposeChord(chord, semitones) {
|
|
1143
|
-
|
|
1344
|
+
assertChord(chord);
|
|
1345
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, semitones, "semitones");
|
|
1144
1346
|
const steps = Math.round(semitones);
|
|
1145
1347
|
const moved = {
|
|
1146
|
-
rootPc:
|
|
1348
|
+
rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + steps),
|
|
1147
1349
|
quality: chord.quality,
|
|
1148
1350
|
intervals: [...chord.intervals]
|
|
1149
1351
|
};
|
|
1150
1352
|
if (chord.bassPc !== void 0) {
|
|
1151
|
-
moved.bassPc =
|
|
1353
|
+
moved.bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.bassPc + steps);
|
|
1152
1354
|
}
|
|
1153
1355
|
return moved;
|
|
1154
1356
|
}
|
|
@@ -1164,66 +1366,152 @@ function chordToneSpellings(chord) {
|
|
|
1164
1366
|
if (hint === void 0 || interval === void 0) {
|
|
1165
1367
|
return void 0;
|
|
1166
1368
|
}
|
|
1167
|
-
if (
|
|
1369
|
+
if (_chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, hint) !== _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval)) {
|
|
1168
1370
|
return void 0;
|
|
1169
1371
|
}
|
|
1170
|
-
usable.push({ letter:
|
|
1372
|
+
usable.push({ letter: _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, hint.letter), alter: hint.alter });
|
|
1171
1373
|
}
|
|
1172
1374
|
return usable;
|
|
1173
1375
|
}
|
|
1174
|
-
function
|
|
1175
|
-
const
|
|
1376
|
+
function chordToneLetterOffsets(chord) {
|
|
1377
|
+
const hints = chordToneSpellings(chord);
|
|
1378
|
+
const rootHint = _optionalChain([hints, 'optionalAccess', _6 => _6[chord.intervals.findIndex((interval) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval) === 0)]]);
|
|
1379
|
+
if (hints === void 0 || rootHint === void 0) {
|
|
1380
|
+
return void 0;
|
|
1381
|
+
}
|
|
1382
|
+
return hints.map((hint) => _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, hint.letter - rootHint.letter));
|
|
1383
|
+
}
|
|
1384
|
+
var ROLE_BY_LETTER_OFFSET = {
|
|
1385
|
+
0: "root",
|
|
1386
|
+
2: "third",
|
|
1387
|
+
4: "fifth",
|
|
1388
|
+
5: "sixth",
|
|
1389
|
+
6: "seventh"
|
|
1390
|
+
};
|
|
1391
|
+
function spelledToneRole(pitch, chord) {
|
|
1392
|
+
const offsets = chordToneLetterOffsets(chord);
|
|
1393
|
+
if (offsets === void 0) {
|
|
1394
|
+
return void 0;
|
|
1395
|
+
}
|
|
1396
|
+
const index = chord.intervals.findIndex(
|
|
1397
|
+
(interval) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch)
|
|
1398
|
+
);
|
|
1399
|
+
const offset = offsets[index];
|
|
1400
|
+
return offset === void 0 ? void 0 : _nullishCoalesce(ROLE_BY_LETTER_OFFSET[offset], () => ( null));
|
|
1401
|
+
}
|
|
1402
|
+
function chordPcMask(chord, opts = {}) {
|
|
1403
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, chord, "chord");
|
|
1404
|
+
_chunkS5BKZZGMcjs.assertArray.call(void 0, chord.intervals, "chord intervals");
|
|
1405
|
+
let mask = 0;
|
|
1176
1406
|
for (const interval of chord.intervals) {
|
|
1177
|
-
|
|
1407
|
+
mask |= 1 << _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval);
|
|
1178
1408
|
}
|
|
1179
1409
|
if (opts.includeBass !== false && chord.bassPc !== void 0) {
|
|
1180
|
-
|
|
1410
|
+
mask |= 1 << _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.bassPc);
|
|
1411
|
+
}
|
|
1412
|
+
return mask;
|
|
1413
|
+
}
|
|
1414
|
+
function hasPitchClass(mask, pc) {
|
|
1415
|
+
return (mask >> pc & 1) === 1;
|
|
1416
|
+
}
|
|
1417
|
+
function chordIntervalMask(chord) {
|
|
1418
|
+
let mask = 0;
|
|
1419
|
+
for (const interval of chord.intervals) {
|
|
1420
|
+
mask |= 1 << (interval % 12 + 12) % 12;
|
|
1421
|
+
}
|
|
1422
|
+
return mask;
|
|
1423
|
+
}
|
|
1424
|
+
function chordPitchClasses(chord, opts = {}) {
|
|
1425
|
+
const mask = chordPcMask(assertChord(chord), _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts"));
|
|
1426
|
+
const pcs = [];
|
|
1427
|
+
for (let pc = 0; pc < 12; pc += 1) {
|
|
1428
|
+
if (hasPitchClass(mask, pc)) {
|
|
1429
|
+
pcs.push(pc);
|
|
1430
|
+
}
|
|
1181
1431
|
}
|
|
1182
|
-
return
|
|
1432
|
+
return pcs;
|
|
1183
1433
|
}
|
|
1184
1434
|
function intervalAboveRoot(pitch, chord) {
|
|
1185
|
-
return ((
|
|
1435
|
+
return ((_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch) - _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, assertChord(chord).rootPc)) % 12 + 12) % 12;
|
|
1186
1436
|
}
|
|
1187
1437
|
function isChordMember(pitch, chord) {
|
|
1188
|
-
return chord === null ? false :
|
|
1189
|
-
}
|
|
1190
|
-
function chordToneOffsets(chord) {
|
|
1191
|
-
return new Set(chord.intervals.map((i) => (i % 12 + 12) % 12));
|
|
1438
|
+
return chord === null ? false : hasPitchClass(chordPcMask(chord), _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch));
|
|
1192
1439
|
}
|
|
1193
1440
|
function chordToneRole(pitch, chord) {
|
|
1194
|
-
|
|
1195
|
-
const
|
|
1441
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, chord, "chord");
|
|
1442
|
+
const spelled2 = spelledToneRole(pitch, chord);
|
|
1443
|
+
if (spelled2 !== void 0) {
|
|
1444
|
+
return spelled2;
|
|
1445
|
+
}
|
|
1446
|
+
const interval = (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pitch) - _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc) + 12) % 12;
|
|
1447
|
+
const tones = chordIntervalMask(chord);
|
|
1448
|
+
const sounds = (ic) => hasPitchClass(tones, ic);
|
|
1196
1449
|
if (interval === 0) {
|
|
1197
|
-
return "root";
|
|
1450
|
+
return sounds(0) ? "root" : null;
|
|
1198
1451
|
}
|
|
1199
1452
|
if (interval === 3 || interval === 4) {
|
|
1200
|
-
return
|
|
1453
|
+
return sounds(interval) && (interval !== 3 || !sounds(4)) ? "third" : null;
|
|
1201
1454
|
}
|
|
1202
1455
|
if (interval === 7) {
|
|
1203
|
-
return
|
|
1456
|
+
return sounds(7) ? "fifth" : null;
|
|
1204
1457
|
}
|
|
1205
1458
|
if (interval === 6) {
|
|
1206
|
-
return
|
|
1459
|
+
return sounds(6) && !sounds(7) ? "fifth" : null;
|
|
1207
1460
|
}
|
|
1208
1461
|
if (interval === 8) {
|
|
1209
|
-
return
|
|
1462
|
+
return sounds(8) && !sounds(7) ? "fifth" : null;
|
|
1210
1463
|
}
|
|
1211
1464
|
if (interval === 9) {
|
|
1212
|
-
const hasHigherSeventh =
|
|
1213
|
-
const isDiminishedSeventh =
|
|
1214
|
-
if (
|
|
1465
|
+
const hasHigherSeventh = sounds(10) || sounds(11);
|
|
1466
|
+
const isDiminishedSeventh = sounds(3) && sounds(6) && !hasHigherSeventh;
|
|
1467
|
+
if (sounds(9) && isDiminishedSeventh) {
|
|
1215
1468
|
return "seventh";
|
|
1216
1469
|
}
|
|
1217
|
-
if (
|
|
1470
|
+
if (sounds(9) && !hasHigherSeventh) {
|
|
1218
1471
|
return "sixth";
|
|
1219
1472
|
}
|
|
1220
1473
|
return null;
|
|
1221
1474
|
}
|
|
1222
1475
|
if (interval === 10 || interval === 11) {
|
|
1223
|
-
return
|
|
1476
|
+
return sounds(interval) ? "seventh" : null;
|
|
1224
1477
|
}
|
|
1225
1478
|
return null;
|
|
1226
1479
|
}
|
|
1480
|
+
var DEGREE_BY_ROLE = {
|
|
1481
|
+
root: 1,
|
|
1482
|
+
third: 3,
|
|
1483
|
+
fifth: 5,
|
|
1484
|
+
sixth: 6,
|
|
1485
|
+
seventh: 7
|
|
1486
|
+
};
|
|
1487
|
+
var TENSION_DEGREE = [1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7];
|
|
1488
|
+
function degreeOfInterval(interval, chord) {
|
|
1489
|
+
const role = chordToneRole(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval), chord);
|
|
1490
|
+
if (role !== null) {
|
|
1491
|
+
return DEGREE_BY_ROLE[role];
|
|
1492
|
+
}
|
|
1493
|
+
return TENSION_DEGREE[(interval % 12 + 12) % 12];
|
|
1494
|
+
}
|
|
1495
|
+
function thirdSlotOf(chord) {
|
|
1496
|
+
const tones = chordIntervalMask(chord);
|
|
1497
|
+
if (hasPitchClass(tones, 4)) {
|
|
1498
|
+
return { kind: "third", interval: 4 };
|
|
1499
|
+
}
|
|
1500
|
+
if (hasPitchClass(tones, 3)) {
|
|
1501
|
+
return { kind: "third", interval: 3 };
|
|
1502
|
+
}
|
|
1503
|
+
const spec = chordSpecOf(chord);
|
|
1504
|
+
if (spec.base === "sus2") {
|
|
1505
|
+
return hasPitchClass(tones, 2) ? { kind: "suspension", interval: 2 } : { kind: "none" };
|
|
1506
|
+
}
|
|
1507
|
+
if (spec.base === "sus4" || spec.omissions.includes(3)) {
|
|
1508
|
+
return hasPitchClass(tones, 5) ? { kind: "suspension", interval: 5 } : { kind: "none" };
|
|
1509
|
+
}
|
|
1510
|
+
return { kind: "none" };
|
|
1511
|
+
}
|
|
1512
|
+
function displacedThirds(chord) {
|
|
1513
|
+
return thirdSlotOf(chord).kind === "suspension" ? [_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + 3), _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + 4)] : [];
|
|
1514
|
+
}
|
|
1227
1515
|
function classifyTriad(thirdIc, fifthIc) {
|
|
1228
1516
|
if (thirdIc === 4 && fifthIc === 8) {
|
|
1229
1517
|
return "aug";
|
|
@@ -1271,16 +1559,16 @@ function matchesQualityIntervals(quality, intervals) {
|
|
|
1271
1559
|
return template.length === intervals.length && template.every((interval, index) => interval === intervals[index]);
|
|
1272
1560
|
}
|
|
1273
1561
|
function stackThirds(degree, key, size) {
|
|
1274
|
-
|
|
1562
|
+
_chunkS5BKZZGMcjs.assertDegree.call(void 0, degree, "chord degree");
|
|
1275
1563
|
const tones = scaleTonesInDegreeOrder(key);
|
|
1276
1564
|
const length = tones.length;
|
|
1277
1565
|
if (length !== 7) {
|
|
1278
|
-
throw new (0,
|
|
1566
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
1279
1567
|
`diatonic chord stacking requires a heptatonic scale (received ${length} tones)`
|
|
1280
1568
|
);
|
|
1281
1569
|
}
|
|
1282
1570
|
const idx = (step) => (degree - 1 + step) % length;
|
|
1283
|
-
const rootPc = _nullishCoalesce(tones[idx(0)], () => (
|
|
1571
|
+
const rootPc = _nullishCoalesce(tones[idx(0)], () => ( _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc)));
|
|
1284
1572
|
const offsets = [0, 2, 4, 6].slice(0, size).map((step) => {
|
|
1285
1573
|
const pc = _nullishCoalesce(tones[idx(step)], () => ( rootPc));
|
|
1286
1574
|
return ((pc - rootPc) % 12 + 12) % 12;
|
|
@@ -1289,7 +1577,7 @@ function stackThirds(degree, key, size) {
|
|
|
1289
1577
|
const fifthIc = _nullishCoalesce(offsets[2], () => ( 7));
|
|
1290
1578
|
const quality = size === 3 ? classifyTriad(thirdIc, fifthIc) : classifySeventh(thirdIc, fifthIc, _nullishCoalesce(offsets[3], () => ( 11)));
|
|
1291
1579
|
if (!matchesQualityIntervals(quality, offsets)) {
|
|
1292
|
-
throw new (0,
|
|
1580
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
1293
1581
|
`scale thirds at degree ${degree} produce unsupported intervals [${offsets.join(", ")}]`
|
|
1294
1582
|
);
|
|
1295
1583
|
}
|
|
@@ -1357,20 +1645,20 @@ var CHROMATIC_SPELLING_SHARP = {
|
|
|
1357
1645
|
// M7
|
|
1358
1646
|
};
|
|
1359
1647
|
function notePitchClass(note) {
|
|
1360
|
-
return
|
|
1648
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, note.letter) + note.alter);
|
|
1361
1649
|
}
|
|
1362
1650
|
function assertTonicOf(tonic, key, source) {
|
|
1363
1651
|
const tonicPc = notePitchClass(tonic);
|
|
1364
|
-
const rootPc =
|
|
1652
|
+
const rootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
1365
1653
|
if (tonicPc !== rootPc) {
|
|
1366
|
-
const name =
|
|
1367
|
-
throw new (0,
|
|
1654
|
+
const name = _chunkS5BKZZGMcjs.formatNote.call(void 0, { letter: _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, tonic.letter), alter: tonic.alter });
|
|
1655
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
1368
1656
|
`${source}: tonic ${name} sounds pitch class ${tonicPc}, not the key root ${rootPc}; pass a tonic that spells the key root, or take one from spelledKeyOf`
|
|
1369
1657
|
);
|
|
1370
1658
|
}
|
|
1371
1659
|
}
|
|
1372
1660
|
function alterFor(letter, pc) {
|
|
1373
|
-
let d =
|
|
1661
|
+
let d = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, letter));
|
|
1374
1662
|
if (d > 6) {
|
|
1375
1663
|
d -= 12;
|
|
1376
1664
|
}
|
|
@@ -1380,7 +1668,7 @@ function letterFor(tonic, degreeOffset, pc) {
|
|
|
1380
1668
|
if (degreeOffset === void 0) {
|
|
1381
1669
|
return void 0;
|
|
1382
1670
|
}
|
|
1383
|
-
const letter =
|
|
1671
|
+
const letter = _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, tonic.letter + degreeOffset);
|
|
1384
1672
|
return { letter, alter: alterFor(letter, pc) };
|
|
1385
1673
|
}
|
|
1386
1674
|
function pickSpelling(flat, sharp, preferFlat) {
|
|
@@ -1396,16 +1684,32 @@ function capChromaticAccidentals(preferred, alternative) {
|
|
|
1396
1684
|
return alternative !== void 0 && Math.abs(preferred.alter) - Math.abs(alternative.alter) >= 2 ? alternative : preferred;
|
|
1397
1685
|
}
|
|
1398
1686
|
var DIATONIC_LETTER_COUNT = 7;
|
|
1687
|
+
var MAX_JOINT_TONE_COUNT = DIATONIC_LETTER_COUNT + 1;
|
|
1688
|
+
var MAJOR_SEMITONES = [0, 2, 4, 5, 7, 9, 11];
|
|
1689
|
+
var IMPERFECT_DEGREES = /* @__PURE__ */ new Set([1, 2, 5, 6]);
|
|
1690
|
+
var DIATONIC_MODE_OFFSETS2 = MAJOR_SEMITONES.map(
|
|
1691
|
+
(tonic, mode) => MAJOR_SEMITONES.map((_, degree) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, (_nullishCoalesce(MAJOR_SEMITONES[(mode + degree) % 7], () => ( 0))) - tonic))
|
|
1692
|
+
);
|
|
1693
|
+
function degreeStrain(tonic, note) {
|
|
1694
|
+
const letterOffset = _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, note.letter - tonic.letter);
|
|
1695
|
+
const offset = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, notePitchClass(note) - notePitchClass(tonic));
|
|
1696
|
+
let deviation = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, offset - (_nullishCoalesce(MAJOR_SEMITONES[letterOffset], () => ( 0))));
|
|
1697
|
+
if (deviation > 6) {
|
|
1698
|
+
deviation -= 12;
|
|
1699
|
+
}
|
|
1700
|
+
const strain = IMPERFECT_DEGREES.has(letterOffset) && deviation < 0 ? Math.abs(deviation + 1) : Math.abs(deviation);
|
|
1701
|
+
return Math.min(strain, 2);
|
|
1702
|
+
}
|
|
1399
1703
|
function isHeptatonic(key) {
|
|
1400
1704
|
return scaleTonesInDegreeOrder(key).length === DIATONIC_LETTER_COUNT;
|
|
1401
1705
|
}
|
|
1402
|
-
function
|
|
1706
|
+
function hasMinorThird(key) {
|
|
1403
1707
|
const tones = scaleTonesInDegreeOrder(key);
|
|
1404
|
-
const root =
|
|
1405
|
-
return tones.includes(
|
|
1708
|
+
const root = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc);
|
|
1709
|
+
return tones.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, root + 3)) && !tones.includes(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, root + 4));
|
|
1406
1710
|
}
|
|
1407
1711
|
function leansFlat(tonic, key) {
|
|
1408
|
-
return tonic.alter < 0 ||
|
|
1712
|
+
return tonic.alter < 0 || hasMinorThird(key);
|
|
1409
1713
|
}
|
|
1410
1714
|
function gappedCandidates(tonic, offset, pc, preferFlat) {
|
|
1411
1715
|
const flat = letterFor(tonic, CHROMATIC_SPELLING_FLAT[offset], pc);
|
|
@@ -1417,22 +1721,64 @@ function gappedCandidates(tonic, offset, pc, preferFlat) {
|
|
|
1417
1721
|
const alternative = preferred === flat ? sharp : flat;
|
|
1418
1722
|
return alternative === void 0 || alternative.letter === preferred.letter ? [preferred] : [preferred, alternative];
|
|
1419
1723
|
}
|
|
1420
|
-
function
|
|
1724
|
+
function spellByParentMode(tonic, pcs, preferFlat) {
|
|
1725
|
+
const tonicPc = notePitchClass(tonic);
|
|
1726
|
+
let best;
|
|
1727
|
+
let bestAlter = 0;
|
|
1728
|
+
let bestSigned = 0;
|
|
1729
|
+
for (const offsets of DIATONIC_MODE_OFFSETS2) {
|
|
1730
|
+
const notes = [];
|
|
1731
|
+
let alter = 0;
|
|
1732
|
+
let signed = 0;
|
|
1733
|
+
for (const pc of pcs) {
|
|
1734
|
+
const degree = offsets.indexOf(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - tonicPc));
|
|
1735
|
+
const note = letterFor(tonic, degree < 0 ? void 0 : degree, pc);
|
|
1736
|
+
if (note === void 0) {
|
|
1737
|
+
break;
|
|
1738
|
+
}
|
|
1739
|
+
notes.push(note);
|
|
1740
|
+
alter += Math.abs(note.alter);
|
|
1741
|
+
signed += note.alter;
|
|
1742
|
+
}
|
|
1743
|
+
if (notes.length !== pcs.length) {
|
|
1744
|
+
continue;
|
|
1745
|
+
}
|
|
1746
|
+
const evenlyLight = alter === bestAlter && (preferFlat ? signed < bestSigned : signed > bestSigned);
|
|
1747
|
+
const lighter = alter < bestAlter || evenlyLight;
|
|
1748
|
+
if (best === void 0 || lighter) {
|
|
1749
|
+
best = notes;
|
|
1750
|
+
bestAlter = alter;
|
|
1751
|
+
bestSigned = signed;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
return best;
|
|
1755
|
+
}
|
|
1756
|
+
function assignDistinctLetters(candidates, tonic, duplicates) {
|
|
1757
|
+
const reserved = 1 << _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, tonic.letter);
|
|
1421
1758
|
let best;
|
|
1759
|
+
let bestStrain = 0;
|
|
1422
1760
|
let bestAlter = 0;
|
|
1423
1761
|
let bestDeviations = 0;
|
|
1424
1762
|
for (let choice = 0; choice < 1 << candidates.length; choice += 1) {
|
|
1425
1763
|
const picked = [];
|
|
1426
1764
|
let letters = reserved;
|
|
1765
|
+
let spare = duplicates;
|
|
1766
|
+
let strain = 0;
|
|
1427
1767
|
let alter = 0;
|
|
1428
1768
|
let deviations = 0;
|
|
1429
1769
|
for (const [index, options] of candidates.entries()) {
|
|
1430
1770
|
const preferred = options[0];
|
|
1431
1771
|
const note = _nullishCoalesce(options[choice >> index & 1], () => ( preferred));
|
|
1432
|
-
if (note === void 0
|
|
1772
|
+
if (note === void 0) {
|
|
1433
1773
|
break;
|
|
1434
1774
|
}
|
|
1775
|
+
const taken = (letters & 1 << note.letter) !== 0;
|
|
1776
|
+
if (taken && (spare === 0 || (reserved & 1 << note.letter) !== 0)) {
|
|
1777
|
+
break;
|
|
1778
|
+
}
|
|
1779
|
+
spare -= taken ? 1 : 0;
|
|
1435
1780
|
letters |= 1 << note.letter;
|
|
1781
|
+
strain += degreeStrain(tonic, note);
|
|
1436
1782
|
alter += Math.abs(note.alter);
|
|
1437
1783
|
deviations += note === preferred ? 0 : 1;
|
|
1438
1784
|
picked.push(note);
|
|
@@ -1440,8 +1786,10 @@ function assignDistinctLetters(candidates, reserved) {
|
|
|
1440
1786
|
if (picked.length !== candidates.length) {
|
|
1441
1787
|
continue;
|
|
1442
1788
|
}
|
|
1443
|
-
|
|
1789
|
+
const better = duplicates > 0 && strain !== bestStrain ? strain < bestStrain : alter !== bestAlter ? alter < bestAlter : deviations < bestDeviations;
|
|
1790
|
+
if (best === void 0 || better) {
|
|
1444
1791
|
best = picked;
|
|
1792
|
+
bestStrain = strain;
|
|
1445
1793
|
bestAlter = alter;
|
|
1446
1794
|
bestDeviations = deviations;
|
|
1447
1795
|
}
|
|
@@ -1449,18 +1797,33 @@ function assignDistinctLetters(candidates, reserved) {
|
|
|
1449
1797
|
return best;
|
|
1450
1798
|
}
|
|
1451
1799
|
function spellGappedScale(tonic, key) {
|
|
1800
|
+
const cacheKey = `${_chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, tonic.letter)}:${tonic.alter}:${key.rootPc}:${key.modeMask12}`;
|
|
1801
|
+
const cached = JOINT_SPELLINGS.get(cacheKey);
|
|
1802
|
+
if (cached !== void 0) {
|
|
1803
|
+
return cached.spellings;
|
|
1804
|
+
}
|
|
1805
|
+
const answer = readGappedScale(tonic, key);
|
|
1806
|
+
if (JOINT_SPELLINGS.size >= MAX_REMEMBERED_SCALES) {
|
|
1807
|
+
JOINT_SPELLINGS.clear();
|
|
1808
|
+
}
|
|
1809
|
+
JOINT_SPELLINGS.set(cacheKey, { spellings: answer });
|
|
1810
|
+
return answer;
|
|
1811
|
+
}
|
|
1812
|
+
var MAX_REMEMBERED_SCALES = 512;
|
|
1813
|
+
var JOINT_SPELLINGS = /* @__PURE__ */ new Map();
|
|
1814
|
+
function readGappedScale(tonic, key) {
|
|
1452
1815
|
const tones = scaleTonesInDegreeOrder(key);
|
|
1453
|
-
if (tones.length >
|
|
1816
|
+
if (tones.length > MAX_JOINT_TONE_COUNT) {
|
|
1454
1817
|
return void 0;
|
|
1455
1818
|
}
|
|
1456
|
-
const tonicPc =
|
|
1457
|
-
const tonicNote = { letter:
|
|
1819
|
+
const tonicPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, tonic.letter) + tonic.alter);
|
|
1820
|
+
const tonicNote = { letter: _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, tonic.letter), alter: tonic.alter };
|
|
1458
1821
|
const preferFlat = leansFlat(tonic, key);
|
|
1459
|
-
const rest = tones.filter((pc) =>
|
|
1460
|
-
const
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
);
|
|
1822
|
+
const rest = tones.filter((pc) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - tonicPc) !== 0);
|
|
1823
|
+
const candidates = rest.map((pc) => gappedCandidates(tonic, _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - tonicPc), pc, preferFlat));
|
|
1824
|
+
const chosen = _nullishCoalesce(_nullishCoalesce(spellByParentMode(tonicNote, rest, preferFlat), () => ( // A scale that can hold a letter per tone does; only one that cannot writes
|
|
1825
|
+
// a letter twice, and then where the doubling falls is what is chosen.
|
|
1826
|
+
assignDistinctLetters(candidates, tonicNote, 0))), () => ( assignDistinctLetters(candidates, tonicNote, 1)));
|
|
1464
1827
|
if (chosen === void 0) {
|
|
1465
1828
|
return void 0;
|
|
1466
1829
|
}
|
|
@@ -1468,22 +1831,22 @@ function spellGappedScale(tonic, key) {
|
|
|
1468
1831
|
for (const [index, pc] of rest.entries()) {
|
|
1469
1832
|
const note = chosen[index];
|
|
1470
1833
|
if (note !== void 0) {
|
|
1471
|
-
spellings.set(
|
|
1834
|
+
spellings.set(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc), note);
|
|
1472
1835
|
}
|
|
1473
1836
|
}
|
|
1474
1837
|
return spellings;
|
|
1475
1838
|
}
|
|
1476
1839
|
function spellByKey(pc, tonic, key) {
|
|
1477
|
-
const tonicPc =
|
|
1478
|
-
const offset =
|
|
1840
|
+
const tonicPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, tonic.letter) + tonic.alter);
|
|
1841
|
+
const offset = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - tonicPc);
|
|
1479
1842
|
if (offset === 0) {
|
|
1480
|
-
return { letter:
|
|
1843
|
+
return { letter: _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, tonic.letter), alter: tonic.alter };
|
|
1481
1844
|
}
|
|
1482
1845
|
const heptatonic = isHeptatonic(key);
|
|
1483
1846
|
if (heptatonic) {
|
|
1484
|
-
const degree = scaleTonesInDegreeOrder(key).indexOf(
|
|
1847
|
+
const degree = scaleTonesInDegreeOrder(key).indexOf(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc));
|
|
1485
1848
|
if (degree >= 0) {
|
|
1486
|
-
const letter =
|
|
1849
|
+
const letter = _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, tonic.letter + degree);
|
|
1487
1850
|
return { letter, alter: alterFor(letter, pc) };
|
|
1488
1851
|
}
|
|
1489
1852
|
const degreeOffset = CHROMATIC_SPELLING[offset];
|
|
@@ -1491,14 +1854,14 @@ function spellByKey(pc, tonic, key) {
|
|
|
1491
1854
|
if (preferred !== void 0) {
|
|
1492
1855
|
const flat = letterFor(tonic, CHROMATIC_SPELLING_FLAT[offset], pc);
|
|
1493
1856
|
const sharp = letterFor(tonic, CHROMATIC_SPELLING_SHARP[offset], pc);
|
|
1494
|
-
const alternative = _optionalChain([flat, 'optionalAccess',
|
|
1857
|
+
const alternative = _optionalChain([flat, 'optionalAccess', _7 => _7.letter]) === preferred.letter ? sharp : _optionalChain([sharp, 'optionalAccess', _8 => _8.letter]) === preferred.letter ? flat : void 0;
|
|
1495
1858
|
return capChromaticAccidentals(preferred, alternative);
|
|
1496
1859
|
}
|
|
1497
1860
|
} else {
|
|
1498
1861
|
if (isScaleTone(pc, key)) {
|
|
1499
|
-
const assigned = _optionalChain([spellGappedScale, 'call',
|
|
1862
|
+
const assigned = _optionalChain([spellGappedScale, 'call', _9 => _9(tonic, key), 'optionalAccess', _10 => _10.get, 'call', _11 => _11(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc))]);
|
|
1500
1863
|
if (assigned !== void 0) {
|
|
1501
|
-
return assigned;
|
|
1864
|
+
return { letter: assigned.letter, alter: assigned.alter };
|
|
1502
1865
|
}
|
|
1503
1866
|
}
|
|
1504
1867
|
const [preferred] = gappedCandidates(tonic, offset, pc, leansFlat(tonic, key));
|
|
@@ -1506,7 +1869,7 @@ function spellByKey(pc, tonic, key) {
|
|
|
1506
1869
|
return preferred;
|
|
1507
1870
|
}
|
|
1508
1871
|
}
|
|
1509
|
-
const belowLetter =
|
|
1872
|
+
const belowLetter = _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, _nullishCoalesce([0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6][_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc)], () => ( 0)));
|
|
1510
1873
|
return { letter: belowLetter, alter: alterFor(belowLetter, pc) };
|
|
1511
1874
|
}
|
|
1512
1875
|
var CHORD_TONE_LETTER_STEPS = {
|
|
@@ -1523,29 +1886,55 @@ var CHORD_TONE_LETTER_STEPS = {
|
|
|
1523
1886
|
11: 6
|
|
1524
1887
|
// major seventh
|
|
1525
1888
|
};
|
|
1889
|
+
var LETTER_STEP_BY_ROLE = {
|
|
1890
|
+
root: 0,
|
|
1891
|
+
third: 2,
|
|
1892
|
+
fifth: 4,
|
|
1893
|
+
sixth: 5,
|
|
1894
|
+
seventh: 6
|
|
1895
|
+
};
|
|
1526
1896
|
var MAX_CONTEXT_ALTER = 2;
|
|
1527
|
-
function
|
|
1897
|
+
function chordToneLetterStep(pc, rootPc, chord) {
|
|
1898
|
+
if (chord !== void 0) {
|
|
1899
|
+
const offsets = chordToneLetterOffsets(chord);
|
|
1900
|
+
const index = chord.intervals.findIndex(
|
|
1901
|
+
(interval) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc)
|
|
1902
|
+
);
|
|
1903
|
+
const offset = _optionalChain([offsets, 'optionalAccess', _12 => _12[index]]);
|
|
1904
|
+
if (offset !== void 0) {
|
|
1905
|
+
return offset;
|
|
1906
|
+
}
|
|
1907
|
+
const role = chordToneRole(pc, chord);
|
|
1908
|
+
if (role !== null) {
|
|
1909
|
+
return LETTER_STEP_BY_ROLE[role];
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
return CHORD_TONE_LETTER_STEPS[_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc - rootPc)];
|
|
1913
|
+
}
|
|
1914
|
+
function spellChordTone(pc, context, tonic, key) {
|
|
1915
|
+
const { chord } = context;
|
|
1916
|
+
const chordRoot = _nullishCoalesce(_optionalChain([chord, 'optionalAccess', _13 => _13.rootPc]), () => ( context.chordRoot));
|
|
1528
1917
|
if (chordRoot === void 0) {
|
|
1529
1918
|
return void 0;
|
|
1530
1919
|
}
|
|
1531
|
-
const root = spellByKey(
|
|
1532
|
-
return letterFor(root,
|
|
1920
|
+
const root = chord === void 0 ? spellByKey(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chordRoot), tonic, key) : chordRootSpelling(chord, tonic, key);
|
|
1921
|
+
return letterFor(root, chordToneLetterStep(pc, chordRoot, chord), pc);
|
|
1533
1922
|
}
|
|
1534
1923
|
function neighbourSpelling(neighbour, gap, letterStep, pc, tonic, key) {
|
|
1535
|
-
if (neighbour === void 0 ||
|
|
1924
|
+
if (neighbour === void 0 || _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, neighbour - pc) !== _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, gap)) {
|
|
1536
1925
|
return void 0;
|
|
1537
1926
|
}
|
|
1538
|
-
return letterFor(spellByKey(
|
|
1927
|
+
return letterFor(spellByKey(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, neighbour), tonic, key), letterStep, pc);
|
|
1539
1928
|
}
|
|
1540
1929
|
function refineByContext(pc, tonic, key, context, keySpelling) {
|
|
1541
|
-
const tonicPc =
|
|
1542
|
-
if (
|
|
1930
|
+
const tonicPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, tonic.letter) + tonic.alter);
|
|
1931
|
+
if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, pc) === tonicPc || isScaleTone(pc, key)) {
|
|
1543
1932
|
return keySpelling;
|
|
1544
1933
|
}
|
|
1545
|
-
const {
|
|
1934
|
+
const { previous, next } = context;
|
|
1546
1935
|
const candidates = [
|
|
1547
|
-
// The sounding chord names the pitch by
|
|
1548
|
-
|
|
1936
|
+
// The sounding chord names the pitch by the degree it writes it as.
|
|
1937
|
+
spellChordTone(pc, context, tonic, key),
|
|
1549
1938
|
// A semitone below what follows: the pitch is its leading tone, a letter down.
|
|
1550
1939
|
neighbourSpelling(next, 1, -1, pc, tonic, key),
|
|
1551
1940
|
// A semitone above what preceded: the pitch is that note inflected upward,
|
|
@@ -1566,9 +1955,10 @@ function refineByContext(pc, tonic, key, context, keySpelling) {
|
|
|
1566
1955
|
return keySpelling;
|
|
1567
1956
|
}
|
|
1568
1957
|
function spellPitchClass(pc, tonic, key, context) {
|
|
1569
|
-
const note =
|
|
1958
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
1570
1959
|
const scale = toKeyScale(key);
|
|
1571
1960
|
assertTonicOf(note, scale, "spellPitchClass");
|
|
1961
|
+
_chunkS5BKZZGMcjs.assertOptions.call(void 0, context, "context");
|
|
1572
1962
|
return spelledPitchClass(pc, note, scale, context);
|
|
1573
1963
|
}
|
|
1574
1964
|
function spelledPitchClass(pc, tonic, key, context) {
|
|
@@ -1576,16 +1966,19 @@ function spelledPitchClass(pc, tonic, key, context) {
|
|
|
1576
1966
|
return context === void 0 ? keySpelling : refineByContext(pc, tonic, key, context, keySpelling);
|
|
1577
1967
|
}
|
|
1578
1968
|
function spellScale(tonic, key) {
|
|
1579
|
-
const note =
|
|
1580
|
-
const scale = key;
|
|
1969
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
1970
|
+
const scale = toKeyScale(key);
|
|
1581
1971
|
assertTonicOf(note, scale, "spellScale");
|
|
1582
1972
|
return scaleTonesInDegreeOrder(scale).map((pc) => spelledPitchClass(pc, note, scale));
|
|
1583
1973
|
}
|
|
1584
1974
|
function spellPitchClasses(pcs, tonic, key) {
|
|
1585
|
-
const
|
|
1975
|
+
const classes = _chunkS5BKZZGMcjs.assertArray.call(void 0, pcs, "pcs");
|
|
1976
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
1586
1977
|
const scale = toKeyScale(key);
|
|
1587
1978
|
assertTonicOf(note, scale, "spellPitchClasses");
|
|
1588
|
-
return
|
|
1979
|
+
return classes.map(
|
|
1980
|
+
(pc, index) => spelledPitchClass(_chunkS5BKZZGMcjs.assertPitchClass.call(void 0, pc, `pcs[${index}]`), note, scale)
|
|
1981
|
+
);
|
|
1589
1982
|
}
|
|
1590
1983
|
function chordLetterOffset(interval, chord) {
|
|
1591
1984
|
switch (interval) {
|
|
@@ -1599,11 +1992,11 @@ function chordLetterOffset(interval, chord) {
|
|
|
1599
1992
|
return 1;
|
|
1600
1993
|
case 3:
|
|
1601
1994
|
case 4:
|
|
1602
|
-
case 16:
|
|
1603
1995
|
return 2;
|
|
1604
1996
|
case 15:
|
|
1605
1997
|
return chord.intervals.some((i) => i === 3 || i === 4) ? 1 : 2;
|
|
1606
1998
|
case 5:
|
|
1999
|
+
case 16:
|
|
1607
2000
|
case 17:
|
|
1608
2001
|
case 18:
|
|
1609
2002
|
return 3;
|
|
@@ -1616,78 +2009,83 @@ function chordLetterOffset(interval, chord) {
|
|
|
1616
2009
|
return chord.quality === "dim7" ? 6 : 5;
|
|
1617
2010
|
case 20:
|
|
1618
2011
|
case 21:
|
|
2012
|
+
case 22:
|
|
1619
2013
|
return 5;
|
|
1620
2014
|
case 10:
|
|
1621
2015
|
case 11:
|
|
1622
|
-
case 22:
|
|
1623
2016
|
case 23:
|
|
1624
2017
|
return 6;
|
|
1625
2018
|
default: {
|
|
1626
2019
|
const octaves = Math.floor(Math.max(0, interval) / 12);
|
|
1627
|
-
const simple =
|
|
2020
|
+
const simple = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval);
|
|
1628
2021
|
const simpleOffset = _nullishCoalesce([0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6][simple], () => ( 0));
|
|
1629
2022
|
return octaves * 7 + simpleOffset;
|
|
1630
2023
|
}
|
|
1631
2024
|
}
|
|
1632
2025
|
}
|
|
1633
|
-
function hintedLetterOffsets(chord) {
|
|
1634
|
-
const hints = chordToneSpellings(chord);
|
|
1635
|
-
const rootHint = _optionalChain([hints, 'optionalAccess', _7 => _7[chord.intervals.findIndex((interval) => _chunkQ2WGKJNNcjs.pitchClassOf.call(void 0, interval) === 0)]]);
|
|
1636
|
-
if (hints === void 0 || rootHint === void 0) {
|
|
1637
|
-
return void 0;
|
|
1638
|
-
}
|
|
1639
|
-
return hints.map((hint) => _chunkQ2WGKJNNcjs.diatonicLetterOf.call(void 0, hint.letter - rootHint.letter));
|
|
1640
|
-
}
|
|
1641
2026
|
function spellChordFromRoot(chord, root) {
|
|
1642
|
-
return chordTonesFromRoot(chord,
|
|
2027
|
+
return chordTonesFromRoot(assertChord(chord), _chunkS5BKZZGMcjs.toNoteData.call(void 0, root));
|
|
1643
2028
|
}
|
|
1644
2029
|
function chordTonesFromRoot(chord, root) {
|
|
1645
|
-
if (
|
|
1646
|
-
throw new (0,
|
|
2030
|
+
if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, root.letter) + root.alter) !== _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc)) {
|
|
2031
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("chord root spelling must match chord.rootPc");
|
|
1647
2032
|
}
|
|
1648
|
-
const hinted =
|
|
2033
|
+
const hinted = chordToneLetterOffsets(chord);
|
|
1649
2034
|
return chord.intervals.map((interval, index) => {
|
|
1650
|
-
const letter =
|
|
1651
|
-
const pc =
|
|
2035
|
+
const letter = _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, root.letter + (_nullishCoalesce(_optionalChain([hinted, 'optionalAccess', _14 => _14[index]]), () => ( chordLetterOffset(interval, chord)))));
|
|
2036
|
+
const pc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval);
|
|
1652
2037
|
return { letter, alter: alterFor(letter, pc) };
|
|
1653
2038
|
});
|
|
1654
2039
|
}
|
|
1655
2040
|
function spellChord(chord, tonic, key) {
|
|
1656
|
-
|
|
2041
|
+
assertChord(chord);
|
|
2042
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
1657
2043
|
const scale = toKeyScale(key);
|
|
1658
2044
|
assertTonicOf(note, scale, "spellChord");
|
|
1659
2045
|
return chordTonesFromRoot(chord, chordRootSpelling(chord, note, scale));
|
|
1660
2046
|
}
|
|
1661
2047
|
function chordRootSpelling(chord, tonic, key) {
|
|
1662
2048
|
const hint = chord.rootSpelling;
|
|
1663
|
-
if (hint !== void 0 &&
|
|
1664
|
-
return { letter:
|
|
2049
|
+
if (hint !== void 0 && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, hint.letter) + hint.alter) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc)) {
|
|
2050
|
+
return { letter: _chunkS5BKZZGMcjs.diatonicLetterOf.call(void 0, hint.letter), alter: hint.alter };
|
|
1665
2051
|
}
|
|
1666
2052
|
return spelledPitchClass(chord.rootPc, tonic, key);
|
|
1667
2053
|
}
|
|
1668
2054
|
function spellPitch(pitch, tonic, key, context) {
|
|
1669
|
-
const note =
|
|
2055
|
+
const note = _chunkS5BKZZGMcjs.toNoteData.call(void 0, tonic);
|
|
1670
2056
|
const scale = toKeyScale(key);
|
|
1671
2057
|
assertTonicOf(note, scale, "spellPitch");
|
|
1672
|
-
|
|
1673
|
-
const
|
|
1674
|
-
const
|
|
1675
|
-
|
|
2058
|
+
_chunkS5BKZZGMcjs.assertOptions.call(void 0, context, "context");
|
|
2059
|
+
const rounded = Math.round(_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, pitch, "pitch"));
|
|
2060
|
+
const spelled2 = spelledPitchClass(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rounded), note, scale, context);
|
|
2061
|
+
const octave = (rounded - _chunkS5BKZZGMcjs.naturalPitchClassOf.call(void 0, spelled2.letter) - spelled2.alter) / 12 - 1;
|
|
2062
|
+
return { letter: spelled2.letter, alter: spelled2.alter, octave };
|
|
1676
2063
|
}
|
|
1677
2064
|
function noteNames(notes) {
|
|
1678
|
-
|
|
2065
|
+
_chunkS5BKZZGMcjs.assertArray.call(void 0, notes, "notes");
|
|
2066
|
+
return notes.map((note) => _chunkS5BKZZGMcjs.formatNote.call(void 0, _chunkS5BKZZGMcjs.toNoteData.call(void 0, note)));
|
|
1679
2067
|
}
|
|
1680
2068
|
|
|
1681
2069
|
// src/theory/counterpoint/internal.ts
|
|
2070
|
+
function assertQualityLabel(quality) {
|
|
2071
|
+
if (typeof quality !== "string" || !/^(P|M|m|A+|d+)$/.test(quality)) {
|
|
2072
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
2073
|
+
`interval.quality must be an interval quality; received ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, quality)}`
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
return quality;
|
|
2077
|
+
}
|
|
1682
2078
|
function pitchOf(value) {
|
|
1683
|
-
return typeof value === "number" ? value :
|
|
2079
|
+
return typeof value === "number" ? value : _chunkS5BKZZGMcjs.noteToMidi.call(void 0, value);
|
|
1684
2080
|
}
|
|
1685
2081
|
function simpleIntervalNumber(numberValue) {
|
|
1686
2082
|
return (Math.abs(numberValue) - 1) % 7 + 1;
|
|
1687
2083
|
}
|
|
1688
2084
|
function classifySpelledInterval(interval, twoVoice = true) {
|
|
1689
|
-
|
|
1690
|
-
const
|
|
2085
|
+
_chunkS5BKZZGMcjs.assertFlag.call(void 0, twoVoice, "twoVoice");
|
|
2086
|
+
const read = _chunkS5BKZZGMcjs.assertRecord.call(void 0, interval, "interval");
|
|
2087
|
+
const simple = simpleIntervalNumber(_chunkS5BKZZGMcjs.assertDegree.call(void 0, read.number, "interval.number"));
|
|
2088
|
+
const quality = assertQualityLabel(read.quality);
|
|
1691
2089
|
if (quality === "P") {
|
|
1692
2090
|
if (simple === 1 || simple === 5) {
|
|
1693
2091
|
return 0 /* PerfectConsonance */;
|
|
@@ -1733,28 +2131,31 @@ function motionBetween(from, to) {
|
|
|
1733
2131
|
if (leadMove > 0 !== counterMove > 0) {
|
|
1734
2132
|
return "contrary";
|
|
1735
2133
|
}
|
|
1736
|
-
const before = simpleIntervalNumber(
|
|
1737
|
-
const after = simpleIntervalNumber(
|
|
2134
|
+
const before = simpleIntervalNumber(_chunkS5BKZZGMcjs.spelledInterval.call(void 0, from.counter, from.lead).number);
|
|
2135
|
+
const after = simpleIntervalNumber(_chunkS5BKZZGMcjs.spelledInterval.call(void 0, to.counter, to.lead).number);
|
|
1738
2136
|
return before === after ? "parallel" : "similar";
|
|
1739
2137
|
}
|
|
1740
2138
|
function voiceIndependence(lead, counter, opts) {
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
2139
|
+
_chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
2140
|
+
const upper = _chunkS5BKZZGMcjs.assertArray.call(void 0, lead, "lead");
|
|
2141
|
+
const lower = _chunkS5BKZZGMcjs.assertArray.call(void 0, counter, "counter");
|
|
2142
|
+
if (upper.length !== lower.length) {
|
|
2143
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
2144
|
+
`voiceIndependence needs the two lines aligned slot for slot; received ${upper.length} and ${lower.length}`
|
|
1744
2145
|
);
|
|
1745
2146
|
}
|
|
1746
2147
|
for (const [name, flags] of [
|
|
1747
|
-
["leadAttacks", _optionalChain([opts, 'optionalAccess',
|
|
1748
|
-
["counterAttacks", _optionalChain([opts, 'optionalAccess',
|
|
2148
|
+
["leadAttacks", _optionalChain([opts, 'optionalAccess', _15 => _15.leadAttacks])],
|
|
2149
|
+
["counterAttacks", _optionalChain([opts, 'optionalAccess', _16 => _16.counterAttacks])]
|
|
1749
2150
|
]) {
|
|
1750
|
-
if (flags !== void 0 && flags.length !==
|
|
1751
|
-
throw new (0,
|
|
1752
|
-
`voiceIndependence needs ${name} aligned slot for slot with the lines; received ${flags.length} and ${
|
|
2151
|
+
if (flags !== void 0 && flags.length !== upper.length) {
|
|
2152
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
2153
|
+
`voiceIndependence needs ${name} aligned slot for slot with the lines; received ${flags.length} and ${upper.length}`
|
|
1753
2154
|
);
|
|
1754
2155
|
}
|
|
1755
2156
|
}
|
|
1756
|
-
const slots =
|
|
1757
|
-
const counterNote = _nullishCoalesce(
|
|
2157
|
+
const slots = upper.map((leadNote, index) => {
|
|
2158
|
+
const counterNote = _nullishCoalesce(lower[index], () => ( null));
|
|
1758
2159
|
return {
|
|
1759
2160
|
lead: leadNote,
|
|
1760
2161
|
counter: counterNote,
|
|
@@ -1780,12 +2181,12 @@ function voiceIndependence(lead, counter, opts) {
|
|
|
1780
2181
|
let filled = 0;
|
|
1781
2182
|
let gaps = 0;
|
|
1782
2183
|
for (let index = 0; index < slots.length; index += 1) {
|
|
1783
|
-
const leadHolds = !attacksAt(index, lead, _optionalChain([opts, 'optionalAccess',
|
|
2184
|
+
const leadHolds = !attacksAt(index, lead, _optionalChain([opts, 'optionalAccess', _17 => _17.leadAttacks]));
|
|
1784
2185
|
if (!leadHolds) {
|
|
1785
2186
|
continue;
|
|
1786
2187
|
}
|
|
1787
2188
|
gaps += 1;
|
|
1788
|
-
if (attacksAt(index, counter, _optionalChain([opts, 'optionalAccess',
|
|
2189
|
+
if (attacksAt(index, counter, _optionalChain([opts, 'optionalAccess', _18 => _18.counterAttacks]))) {
|
|
1789
2190
|
filled += 1;
|
|
1790
2191
|
}
|
|
1791
2192
|
}
|
|
@@ -1805,8 +2206,8 @@ function voiceIndependence(lead, counter, opts) {
|
|
|
1805
2206
|
totalGap += Math.abs(gap);
|
|
1806
2207
|
minGap = Math.min(minGap, Math.abs(gap));
|
|
1807
2208
|
orderSum += Math.sign(gap);
|
|
1808
|
-
const interval =
|
|
1809
|
-
const perfect = classifySpelledInterval(interval) === 0 /* PerfectConsonance */ || (_nullishCoalesce(_optionalChain([opts, 'optionalAccess',
|
|
2209
|
+
const interval = _chunkS5BKZZGMcjs.spelledInterval.call(void 0, slot.counter, slot.lead);
|
|
2210
|
+
const perfect = classifySpelledInterval(interval) === 0 /* PerfectConsonance */ || (_nullishCoalesce(_optionalChain([opts, 'optionalAccess', _19 => _19.countFourths]), () => ( false))) && interval.quality === "P" && simpleIntervalNumber(interval.number) === 4;
|
|
1810
2211
|
perfectRun = perfect ? perfectRun + 1 : 0;
|
|
1811
2212
|
longestPerfectRun = Math.max(longestPerfectRun, perfectRun);
|
|
1812
2213
|
}
|
|
@@ -1840,18 +2241,19 @@ function voiceIndependence(lead, counter, opts) {
|
|
|
1840
2241
|
}
|
|
1841
2242
|
|
|
1842
2243
|
// src/theory/counterpoint/index.ts
|
|
2244
|
+
var HIDDEN_PARALLEL_READINGS = Object.freeze(["fourPart", "twoVoice"]);
|
|
1843
2245
|
function createsVoiceCrossing(upper, lower) {
|
|
1844
2246
|
return pitchOf(upper) < pitchOf(lower);
|
|
1845
2247
|
}
|
|
1846
2248
|
function createsVerticalDissonance(a, b, twoVoice) {
|
|
1847
2249
|
if (typeof a !== "number" && typeof b !== "number") {
|
|
1848
|
-
return classifySpelledInterval(
|
|
2250
|
+
return classifySpelledInterval(_chunkS5BKZZGMcjs.spelledInterval.call(void 0, a, b), twoVoice) === 2 /* Dissonance */;
|
|
1849
2251
|
}
|
|
1850
|
-
return !
|
|
2252
|
+
return !_chunkS5BKZZGMcjs.isConsonantInterval.call(void 0, pitchOf(a) - pitchOf(b), twoVoice);
|
|
1851
2253
|
}
|
|
1852
2254
|
function isForbiddenMelodicLeap(prev, cur) {
|
|
1853
2255
|
if (typeof prev !== "number" && typeof cur !== "number") {
|
|
1854
|
-
const interval =
|
|
2256
|
+
const interval = _chunkS5BKZZGMcjs.spelledInterval.call(void 0, prev, cur);
|
|
1855
2257
|
if (Math.abs(interval.semitones) > 12 || interval.number > 8) {
|
|
1856
2258
|
return true;
|
|
1857
2259
|
}
|
|
@@ -1870,11 +2272,11 @@ function isAugmentedMelodicInterval(prev, cur) {
|
|
|
1870
2272
|
if (typeof prev === "number" || typeof cur === "number") {
|
|
1871
2273
|
return false;
|
|
1872
2274
|
}
|
|
1873
|
-
const interval =
|
|
2275
|
+
const interval = _chunkS5BKZZGMcjs.spelledInterval.call(void 0, prev, cur);
|
|
1874
2276
|
return interval.number >= 2 && interval.quality.startsWith("A");
|
|
1875
2277
|
}
|
|
1876
2278
|
function simpleClass(semitones) {
|
|
1877
|
-
return
|
|
2279
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, Math.abs(semitones));
|
|
1878
2280
|
}
|
|
1879
2281
|
function isPerfectClass(cls) {
|
|
1880
2282
|
return cls === 0 || cls === 7;
|
|
@@ -1917,7 +2319,8 @@ function createsParallelUnison(aPrev, aCur, bPrev, bCur) {
|
|
|
1917
2319
|
}
|
|
1918
2320
|
return a1 === b1 && a0 === b0;
|
|
1919
2321
|
}
|
|
1920
|
-
function createsHiddenParallelPerfect(aPrev, aCur, bPrev, bCur) {
|
|
2322
|
+
function createsHiddenParallelPerfect(aPrev, aCur, bPrev, bCur, strictness = "fourPart") {
|
|
2323
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, strictness, HIDDEN_PARALLEL_READINGS, "strictness");
|
|
1921
2324
|
const a0 = pitchOf(aPrev);
|
|
1922
2325
|
const a1 = pitchOf(aCur);
|
|
1923
2326
|
const b0 = pitchOf(bPrev);
|
|
@@ -1933,7 +2336,7 @@ function createsHiddenParallelPerfect(aPrev, aCur, bPrev, bCur) {
|
|
|
1933
2336
|
return false;
|
|
1934
2337
|
}
|
|
1935
2338
|
const upperMove = a1 >= b1 ? aMove : bMove;
|
|
1936
|
-
if (Math.abs(upperMove) <= 2) {
|
|
2339
|
+
if (strictness === "fourPart" && Math.abs(upperMove) <= 2) {
|
|
1937
2340
|
return false;
|
|
1938
2341
|
}
|
|
1939
2342
|
return true;
|
|
@@ -1948,7 +2351,12 @@ function createsBattuta(aPrev, aCur, bPrev, bCur) {
|
|
|
1948
2351
|
if (!bothVoicesMove(aMove, bMove) || similarMotion(aMove, bMove)) {
|
|
1949
2352
|
return false;
|
|
1950
2353
|
}
|
|
1951
|
-
|
|
2354
|
+
const nowClass = simpleClass(a1 - b1);
|
|
2355
|
+
if (nowClass !== 0) {
|
|
2356
|
+
return false;
|
|
2357
|
+
}
|
|
2358
|
+
const prevClass = simpleClass(a0 - b0);
|
|
2359
|
+
if (prevClass === nowClass) {
|
|
1952
2360
|
return false;
|
|
1953
2361
|
}
|
|
1954
2362
|
const upperMove = a1 >= b1 ? aMove : bMove;
|
|
@@ -1962,14 +2370,15 @@ function createsVoiceOverlap(upperPrev, upperCur, lowerPrev, lowerCur) {
|
|
|
1962
2370
|
return u1 < l0 || l1 > u0;
|
|
1963
2371
|
}
|
|
1964
2372
|
function exceedsSpacing(upper, lower, maxSemitones = 12) {
|
|
2373
|
+
_chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, maxSemitones, "maxSemitones");
|
|
1965
2374
|
return Math.abs(pitchOf(upper) - pitchOf(lower)) > maxSemitones;
|
|
1966
2375
|
}
|
|
1967
2376
|
function isLeadingToneResolution(prev, cur, key) {
|
|
1968
2377
|
const prevPitch = pitchOf(prev);
|
|
1969
2378
|
const curPitch = pitchOf(cur);
|
|
1970
|
-
const tonic =
|
|
2379
|
+
const tonic = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, toKeyScale(key).rootPc);
|
|
1971
2380
|
const leading = (tonic + 11) % 12;
|
|
1972
|
-
if (
|
|
2381
|
+
if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, prevPitch) !== leading || _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, curPitch) !== tonic) {
|
|
1973
2382
|
return false;
|
|
1974
2383
|
}
|
|
1975
2384
|
return curPitch > prevPitch && curPitch - prevPitch <= 2;
|
|
@@ -2008,8 +2417,19 @@ var PROFILE_WEIGHTS = Object.freeze({
|
|
|
2008
2417
|
});
|
|
2009
2418
|
var SAFETY_PROFILES = Object.keys(PROFILE_WEIGHTS);
|
|
2010
2419
|
function profileWeights(profile, overrides) {
|
|
2011
|
-
const base = PROFILE_WEIGHTS[
|
|
2012
|
-
|
|
2420
|
+
const base = PROFILE_WEIGHTS[_chunkS5BKZZGMcjs.assertOneOf.call(void 0, profile, SAFETY_PROFILES, "safety profile")];
|
|
2421
|
+
if (overrides === void 0) {
|
|
2422
|
+
return { ...base };
|
|
2423
|
+
}
|
|
2424
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, overrides, "overrides");
|
|
2425
|
+
const weights = { ...base };
|
|
2426
|
+
for (const [field, value] of Object.entries(overrides)) {
|
|
2427
|
+
if (value === void 0) {
|
|
2428
|
+
continue;
|
|
2429
|
+
}
|
|
2430
|
+
weights[field] = _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, value, `weight ${field}`);
|
|
2431
|
+
}
|
|
2432
|
+
return weights;
|
|
2013
2433
|
}
|
|
2014
2434
|
var NoteSafety = /* @__PURE__ */ ((NoteSafety2) => {
|
|
2015
2435
|
NoteSafety2[NoteSafety2["Safe"] = 0] = "Safe";
|
|
@@ -2017,6 +2437,7 @@ var NoteSafety = /* @__PURE__ */ ((NoteSafety2) => {
|
|
|
2017
2437
|
NoteSafety2[NoteSafety2["Dissonant"] = 2] = "Dissonant";
|
|
2018
2438
|
return NoteSafety2;
|
|
2019
2439
|
})(NoteSafety || {});
|
|
2440
|
+
Object.freeze(NoteSafety);
|
|
2020
2441
|
var ReasonFlag = /* @__PURE__ */ ((ReasonFlag2) => {
|
|
2021
2442
|
ReasonFlag2[ReasonFlag2["ChordTone"] = 1] = "ChordTone";
|
|
2022
2443
|
ReasonFlag2[ReasonFlag2["Tension"] = 2] = "Tension";
|
|
@@ -2037,6 +2458,7 @@ var ReasonFlag = /* @__PURE__ */ ((ReasonFlag2) => {
|
|
|
2037
2458
|
ReasonFlag2[ReasonFlag2["MelodicTritone"] = 65536] = "MelodicTritone";
|
|
2038
2459
|
return ReasonFlag2;
|
|
2039
2460
|
})(ReasonFlag || {});
|
|
2461
|
+
Object.freeze(ReasonFlag);
|
|
2040
2462
|
var SUGGESTION_WINDOW = 12;
|
|
2041
2463
|
var MAX_SUGGESTIONS = 3;
|
|
2042
2464
|
var REASON_SEVERITY = [
|
|
@@ -2072,7 +2494,7 @@ function avoidsMajorSeventh(chord) {
|
|
|
2072
2494
|
return chord.intervals.includes(4) && chord.intervals.includes(10);
|
|
2073
2495
|
}
|
|
2074
2496
|
function isStructuralChordDissonance(a, b, chord) {
|
|
2075
|
-
const rawClass =
|
|
2497
|
+
const rawClass = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, Math.abs(a - b));
|
|
2076
2498
|
const aOffset = intervalAboveRoot(a, chord);
|
|
2077
2499
|
const bOffset = intervalAboveRoot(b, chord);
|
|
2078
2500
|
const rootSeventh = aOffset === 0 && (bOffset === 10 || bOffset === 11) || bOffset === 0 && (aOffset === 10 || aOffset === 11);
|
|
@@ -2091,31 +2513,33 @@ function stepResolution(pitch, chord) {
|
|
|
2091
2513
|
}
|
|
2092
2514
|
function evaluateSafety(q, opts = {}) {
|
|
2093
2515
|
assertSafetyContext(q);
|
|
2094
|
-
|
|
2095
|
-
|
|
2516
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, q.candidatePitch, "candidatePitch");
|
|
2517
|
+
const options = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
2518
|
+
return evaluateInternal(q, _nullishCoalesce(options.suggestions, () => ( true)), _nullishCoalesce(options.partners, () => ( false)));
|
|
2096
2519
|
}
|
|
2097
2520
|
function assertSafetyContext(q) {
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
if (q.
|
|
2101
|
-
if (q.
|
|
2521
|
+
_chunkS5BKZZGMcjs.assertRecord.call(void 0, q, "safety query");
|
|
2522
|
+
_chunkS5BKZZGMcjs.assertOneOf.call(void 0, q.profile, SAFETY_PROFILES, "safety profile");
|
|
2523
|
+
if (q.prevPitch !== void 0) _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, q.prevPitch, "prevPitch");
|
|
2524
|
+
if (q.vocalLow !== void 0) _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, q.vocalLow, "vocalLow");
|
|
2525
|
+
if (q.vocalHigh !== void 0) _chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, q.vocalHigh, "vocalHigh");
|
|
2102
2526
|
if (q.vocalLow !== void 0 && q.vocalHigh !== void 0 && q.vocalLow > q.vocalHigh) {
|
|
2103
|
-
throw new (0,
|
|
2527
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("vocalLow must not exceed vocalHigh");
|
|
2104
2528
|
}
|
|
2105
2529
|
if (!Array.isArray(q.otherVoices)) {
|
|
2106
|
-
throw new (0,
|
|
2530
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`otherVoices must be an array; received ${typeof q.otherVoices}`);
|
|
2107
2531
|
}
|
|
2108
|
-
|
|
2532
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, q.otherVoices.length, "other voices");
|
|
2109
2533
|
for (let index = 0; index < q.otherVoices.length; index += 1) {
|
|
2110
2534
|
const voice = q.otherVoices[index];
|
|
2111
2535
|
if (!voice) continue;
|
|
2112
|
-
|
|
2536
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, voice.pitch, `otherVoices[${index}].pitch`);
|
|
2113
2537
|
if (voice.prevPitch !== void 0) {
|
|
2114
|
-
|
|
2538
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, voice.prevPitch, `otherVoices[${index}].prevPitch`);
|
|
2115
2539
|
}
|
|
2116
2540
|
}
|
|
2117
2541
|
}
|
|
2118
|
-
function evaluateInternal(q, collectSuggestions) {
|
|
2542
|
+
function evaluateInternal(q, collectSuggestions, collectPartners) {
|
|
2119
2543
|
let reasons = 0;
|
|
2120
2544
|
let level = 0 /* Safe */;
|
|
2121
2545
|
let resolveTo;
|
|
@@ -2186,41 +2610,58 @@ function evaluateInternal(q, collectSuggestions) {
|
|
|
2186
2610
|
reasons |= 512 /* MajorSeventh */;
|
|
2187
2611
|
}
|
|
2188
2612
|
}
|
|
2613
|
+
let bass = pitch;
|
|
2614
|
+
let top = pitch;
|
|
2615
|
+
for (const ov of q.otherVoices) {
|
|
2616
|
+
bass = Math.min(bass, ov.pitch);
|
|
2617
|
+
top = Math.max(top, ov.pitch);
|
|
2618
|
+
}
|
|
2619
|
+
const pairReasons = collectPartners ? new Array(q.otherVoices.length).fill(0) : void 0;
|
|
2620
|
+
const flagPair = (index, flag) => {
|
|
2621
|
+
reasons |= flag;
|
|
2622
|
+
if (pairReasons !== void 0) {
|
|
2623
|
+
pairReasons[index] = (_nullishCoalesce(pairReasons[index], () => ( 0))) | flag;
|
|
2624
|
+
}
|
|
2625
|
+
};
|
|
2189
2626
|
if (q.strongBeat) {
|
|
2190
|
-
const twoVoice = q.otherVoices.length === 1;
|
|
2191
2627
|
const prev = q.prevPitch;
|
|
2192
|
-
for (const ov of q.otherVoices) {
|
|
2193
|
-
|
|
2628
|
+
for (const [index, ov] of q.otherVoices.entries()) {
|
|
2629
|
+
const againstBass = pitch === bass || ov.pitch === bass;
|
|
2630
|
+
if (!createsVerticalDissonance(pitch, ov.pitch, againstBass)) {
|
|
2194
2631
|
continue;
|
|
2195
2632
|
}
|
|
2196
2633
|
if (chord && isStructuralChordDissonance(pitch, ov.pitch, chord)) {
|
|
2197
2634
|
continue;
|
|
2198
2635
|
}
|
|
2199
|
-
|
|
2636
|
+
if (chord && q.profile === "pop" && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, Math.abs(pitch - ov.pitch)) === 5 && isChordMember(pitch, chord) && isChordMember(ov.pitch, chord)) {
|
|
2637
|
+
continue;
|
|
2638
|
+
}
|
|
2639
|
+
flagPair(index, 1024 /* VerticalDissonance */);
|
|
2200
2640
|
raise(2 /* Dissonant */);
|
|
2201
|
-
if (prev !== void 0 && pitch === prev && ov.prevPitch !== void 0 && !createsVerticalDissonance(prev, ov.prevPitch,
|
|
2202
|
-
|
|
2641
|
+
if (prev !== void 0 && pitch === prev && ov.prevPitch !== void 0 && !createsVerticalDissonance(prev, ov.prevPitch, againstBass)) {
|
|
2642
|
+
flagPair(index, 16384 /* Suspension */);
|
|
2203
2643
|
}
|
|
2204
2644
|
}
|
|
2205
2645
|
}
|
|
2206
2646
|
if (q.prevPitch !== void 0) {
|
|
2207
2647
|
const prev = q.prevPitch;
|
|
2208
|
-
for (const ov of q.otherVoices) {
|
|
2648
|
+
for (const [index, ov] of q.otherVoices.entries()) {
|
|
2209
2649
|
if (ov.prevPitch === void 0) {
|
|
2210
2650
|
continue;
|
|
2211
2651
|
}
|
|
2212
2652
|
if (createsParallelPerfect(prev, pitch, ov.prevPitch, ov.pitch)) {
|
|
2213
|
-
|
|
2653
|
+
flagPair(index, 2048 /* ParallelPerfect */);
|
|
2214
2654
|
raise(parallelSeverity);
|
|
2215
2655
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2656
|
+
const outerPair = pitch === top && ov.pitch === bass || pitch === bass && ov.pitch === top;
|
|
2657
|
+
if (outerPair && createsHiddenParallelPerfect(prev, pitch, ov.prevPitch, ov.pitch)) {
|
|
2658
|
+
flagPair(index, 4096 /* HiddenParallel */);
|
|
2218
2659
|
raise(parallelSeverity);
|
|
2219
2660
|
}
|
|
2220
2661
|
const crossedNow = pitch - ov.pitch;
|
|
2221
2662
|
const crossedPrev = prev - ov.prevPitch;
|
|
2222
2663
|
if (crossedNow !== 0 && crossedPrev !== 0 && crossedNow > 0 !== crossedPrev > 0) {
|
|
2223
|
-
|
|
2664
|
+
flagPair(index, 8192 /* VoiceCrossing */);
|
|
2224
2665
|
raise(parallelSeverity);
|
|
2225
2666
|
}
|
|
2226
2667
|
}
|
|
@@ -2236,6 +2677,17 @@ function evaluateInternal(q, collectSuggestions) {
|
|
|
2236
2677
|
result.suggestions = suggestions;
|
|
2237
2678
|
}
|
|
2238
2679
|
}
|
|
2680
|
+
if (pairReasons !== void 0) {
|
|
2681
|
+
const partners = [];
|
|
2682
|
+
pairReasons.forEach((pair, index) => {
|
|
2683
|
+
if (pair !== 0) {
|
|
2684
|
+
partners.push({ index, reasons: pair });
|
|
2685
|
+
}
|
|
2686
|
+
});
|
|
2687
|
+
if (partners.length > 0) {
|
|
2688
|
+
result.partners = partners;
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2239
2691
|
return result;
|
|
2240
2692
|
}
|
|
2241
2693
|
function findSafeNearby(q, candidate) {
|
|
@@ -2245,7 +2697,7 @@ function findSafeNearby(q, candidate) {
|
|
|
2245
2697
|
if (p < 0 || p > 127) {
|
|
2246
2698
|
continue;
|
|
2247
2699
|
}
|
|
2248
|
-
if (evaluateInternal({ ...q, candidatePitch: p }, false).safety === 0 /* Safe */) {
|
|
2700
|
+
if (evaluateInternal({ ...q, candidatePitch: p }, false, false).safety === 0 /* Safe */) {
|
|
2249
2701
|
out.push(p);
|
|
2250
2702
|
if (out.length >= MAX_SUGGESTIONS) {
|
|
2251
2703
|
return out;
|
|
@@ -2269,7 +2721,7 @@ var REASON_TEXT = [
|
|
|
2269
2721
|
[2048 /* ParallelPerfect */, "Parallel perfect interval with another voice"],
|
|
2270
2722
|
[4096 /* HiddenParallel */, "Hidden perfect interval by similar motion"],
|
|
2271
2723
|
[8192 /* VoiceCrossing */, "Crosses another voice"],
|
|
2272
|
-
[128 /* LargeLeap */, "
|
|
2724
|
+
[128 /* LargeLeap */, "Forbidden melodic leap \u2014 a seventh or wider than an octave"],
|
|
2273
2725
|
[32768 /* NeedsResolution */, "Dissonance awaiting a stepwise resolution"],
|
|
2274
2726
|
[2 /* Tension */, "Chord tension"],
|
|
2275
2727
|
[8 /* ScaleTone */, "Scale tone, not in the chord"],
|
|
@@ -2303,18 +2755,18 @@ function enumerateSafePitches(q, pitchLow, pitchHigh) {
|
|
|
2303
2755
|
assertSafetyContext(q);
|
|
2304
2756
|
const chordTones = [];
|
|
2305
2757
|
const others = [];
|
|
2306
|
-
|
|
2307
|
-
|
|
2758
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, pitchLow, "pitchLow");
|
|
2759
|
+
_chunkS5BKZZGMcjs.assertMidiPitch.call(void 0, pitchHigh, "pitchHigh");
|
|
2308
2760
|
if (pitchLow > pitchHigh) {
|
|
2309
|
-
throw new (0,
|
|
2761
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
2310
2762
|
`pitchLow must not exceed pitchHigh; received ${pitchLow} > ${pitchHigh}`
|
|
2311
2763
|
);
|
|
2312
2764
|
}
|
|
2313
|
-
|
|
2765
|
+
_chunkS5BKZZGMcjs.assertGenerationBudget.call(void 0, pitchHigh - pitchLow + 1, "safe pitch candidates");
|
|
2314
2766
|
const low = Math.max(pitchLow, _nullishCoalesce(q.vocalLow, () => ( pitchLow)));
|
|
2315
2767
|
const high = Math.min(pitchHigh, _nullishCoalesce(q.vocalHigh, () => ( pitchHigh)));
|
|
2316
2768
|
for (let pitch = high; pitch >= low; pitch -= 1) {
|
|
2317
|
-
const result = evaluateInternal({ ...q, candidatePitch: pitch }, false);
|
|
2769
|
+
const result = evaluateInternal({ ...q, candidatePitch: pitch }, false, false);
|
|
2318
2770
|
if (result.safety === 2 /* Dissonant */) {
|
|
2319
2771
|
continue;
|
|
2320
2772
|
}
|
|
@@ -2327,7 +2779,7 @@ function enumerateSafePitches(q, pitchLow, pitchHigh) {
|
|
|
2327
2779
|
return [...chordTones, ...others];
|
|
2328
2780
|
}
|
|
2329
2781
|
|
|
2330
|
-
// src/theory/symbol/
|
|
2782
|
+
// src/theory/symbol/grammar.ts
|
|
2331
2783
|
var ROOT_RE = /^[A-Ga-g](?:#{1,2}|b{1,2}|x)?/;
|
|
2332
2784
|
var BASS_RE = /^[A-Ga-g](?:#{1,2}|b{1,2}|x)?$/;
|
|
2333
2785
|
var DEFAULT_SYSTEM = "english";
|
|
@@ -2430,51 +2882,6 @@ var QUALITY_MAP = {
|
|
|
2430
2882
|
h: "m7b5",
|
|
2431
2883
|
h7: "m7b5"
|
|
2432
2884
|
};
|
|
2433
|
-
var CANONICAL_SUFFIX = {
|
|
2434
|
-
maj: "",
|
|
2435
|
-
min: "m",
|
|
2436
|
-
dim: "dim",
|
|
2437
|
-
aug: "aug",
|
|
2438
|
-
maj7: "maj7",
|
|
2439
|
-
min7: "m7",
|
|
2440
|
-
dom7: "7",
|
|
2441
|
-
dim7: "dim7",
|
|
2442
|
-
m7b5: "m7b5",
|
|
2443
|
-
minMaj7: "mMaj7",
|
|
2444
|
-
minMaj9: "mMaj9",
|
|
2445
|
-
minMaj11: "mMaj11",
|
|
2446
|
-
minMaj13: "mMaj13",
|
|
2447
|
-
aug7: "aug7",
|
|
2448
|
-
augMaj7: "augMaj7",
|
|
2449
|
-
majb5: "maj(b5)",
|
|
2450
|
-
"6": "6",
|
|
2451
|
-
min6: "m6",
|
|
2452
|
-
"6/9": "6/9",
|
|
2453
|
-
sus2: "sus2",
|
|
2454
|
-
sus4: "sus4",
|
|
2455
|
-
add9: "add9",
|
|
2456
|
-
add11: "add11",
|
|
2457
|
-
maj9: "maj9",
|
|
2458
|
-
min9: "m9",
|
|
2459
|
-
dom9: "9",
|
|
2460
|
-
"7b9": "7b9",
|
|
2461
|
-
"7#9": "7#9",
|
|
2462
|
-
"7#11": "7#11",
|
|
2463
|
-
"7b13": "7b13",
|
|
2464
|
-
"11": "11",
|
|
2465
|
-
"13": "13",
|
|
2466
|
-
"5": "5",
|
|
2467
|
-
"7sus4": "7sus4",
|
|
2468
|
-
"7b5": "7b5",
|
|
2469
|
-
"7alt": "7alt",
|
|
2470
|
-
"13b9": "13b9",
|
|
2471
|
-
maj13: "maj13",
|
|
2472
|
-
"maj7#11": "maj7#11",
|
|
2473
|
-
min11: "m11",
|
|
2474
|
-
min13: "m13",
|
|
2475
|
-
minAdd9: "madd9",
|
|
2476
|
-
"min6/9": "m6/9"
|
|
2477
|
-
};
|
|
2478
2885
|
function knownQuality(suffix) {
|
|
2479
2886
|
return Object.hasOwn(QUALITY_MAP, suffix) ? QUALITY_MAP[suffix] : void 0;
|
|
2480
2887
|
}
|
|
@@ -2486,6 +2893,7 @@ var BASE_TOKENS = [
|
|
|
2486
2893
|
["dim", "dim"],
|
|
2487
2894
|
["aug", "aug"],
|
|
2488
2895
|
["maj", "major"],
|
|
2896
|
+
["Maj", "major"],
|
|
2489
2897
|
["m", "min"],
|
|
2490
2898
|
["-", "min"],
|
|
2491
2899
|
["o", "dim"],
|
|
@@ -2495,6 +2903,10 @@ var BASE_TOKENS = [
|
|
|
2495
2903
|
["\u0394", "major"],
|
|
2496
2904
|
["^", "major"]
|
|
2497
2905
|
];
|
|
2906
|
+
var COMPOUND_TOKENS = [
|
|
2907
|
+
["\xF8", { base: "dim", seventh: "min7" }],
|
|
2908
|
+
["h", { base: "dim", seventh: "min7" }]
|
|
2909
|
+
];
|
|
2498
2910
|
var MAJOR_MARKERS = [
|
|
2499
2911
|
["maj", "word"],
|
|
2500
2912
|
["Maj", "word"],
|
|
@@ -2513,6 +2925,27 @@ var ADDED_DEGREES = {
|
|
|
2513
2925
|
};
|
|
2514
2926
|
var ALTERABLE = { "5": 5, "9": 9, "11": 11, "13": 13 };
|
|
2515
2927
|
var OMITTABLE = { "1": 1, "3": 3, "5": 5 };
|
|
2928
|
+
function alterationKey(degree, alter) {
|
|
2929
|
+
return `${degree}:${alter}`;
|
|
2930
|
+
}
|
|
2931
|
+
function writeAlteration(draft, degree, alter) {
|
|
2932
|
+
if (draft.implied.delete(degree)) {
|
|
2933
|
+
draft.alterations.delete(alterationKey(degree, 0));
|
|
2934
|
+
}
|
|
2935
|
+
draft.alterations.set(alterationKey(degree, alter), { degree, alter });
|
|
2936
|
+
}
|
|
2937
|
+
function implyAlteration(draft, degree) {
|
|
2938
|
+
draft.implied.add(degree);
|
|
2939
|
+
draft.alterations.set(alterationKey(degree, 0), { degree, alter: 0 });
|
|
2940
|
+
}
|
|
2941
|
+
function altersDegree(draft, degree) {
|
|
2942
|
+
for (const alteration of draft.alterations.values()) {
|
|
2943
|
+
if (alteration.degree === degree) {
|
|
2944
|
+
return true;
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
return false;
|
|
2948
|
+
}
|
|
2516
2949
|
function matchToken(text, at, table) {
|
|
2517
2950
|
let found;
|
|
2518
2951
|
for (const [token, value] of table) {
|
|
@@ -2536,15 +2969,18 @@ function stackTo(draft, top) {
|
|
|
2536
2969
|
draft.additions.add(6);
|
|
2537
2970
|
return;
|
|
2538
2971
|
}
|
|
2539
|
-
draft.seventh = draft.major ? "maj7" : draft.base === "dim" ? "dim7" : "min7";
|
|
2972
|
+
draft.seventh = draft.major ? "maj7" : _nullishCoalesce(draft.seventhOverBase, () => ( (draft.base === "dim" ? "dim7" : "min7")));
|
|
2540
2973
|
if (top >= 9) {
|
|
2541
|
-
draft
|
|
2974
|
+
implyAlteration(draft, 9);
|
|
2542
2975
|
}
|
|
2543
2976
|
if (top === 11) {
|
|
2544
|
-
draft
|
|
2977
|
+
implyAlteration(draft, 11);
|
|
2978
|
+
if (!draft.major && draft.base === "maj") {
|
|
2979
|
+
draft.omissions.add(3);
|
|
2980
|
+
}
|
|
2545
2981
|
}
|
|
2546
2982
|
if (top === 13) {
|
|
2547
|
-
draft
|
|
2983
|
+
implyAlteration(draft, 13);
|
|
2548
2984
|
}
|
|
2549
2985
|
}
|
|
2550
2986
|
function applyFigure(draft, text, at) {
|
|
@@ -2560,7 +2996,7 @@ function applyFigure(draft, text, at) {
|
|
|
2560
2996
|
if (text.startsWith("alt", at)) {
|
|
2561
2997
|
draft.base = "aug";
|
|
2562
2998
|
draft.seventh = "min7";
|
|
2563
|
-
draft
|
|
2999
|
+
writeAlteration(draft, 9, 1);
|
|
2564
3000
|
return at + 3;
|
|
2565
3001
|
}
|
|
2566
3002
|
if (text.startsWith("add", at)) {
|
|
@@ -2587,18 +3023,42 @@ function applyFigure(draft, text, at) {
|
|
|
2587
3023
|
["b", -1],
|
|
2588
3024
|
["#", 1]
|
|
2589
3025
|
]);
|
|
2590
|
-
const from = _nullishCoalesce(_optionalChain([accidental, 'optionalAccess',
|
|
3026
|
+
const from = _nullishCoalesce(_optionalChain([accidental, 'optionalAccess', _20 => _20.next]), () => ( at));
|
|
2591
3027
|
const degree = matchNumberToken(text, from, ALTERABLE);
|
|
2592
3028
|
if (degree === void 0) {
|
|
2593
3029
|
return void 0;
|
|
2594
3030
|
}
|
|
2595
|
-
|
|
3031
|
+
if (degree.value === 5 && (accidental === void 0 || writesFifth(draft))) {
|
|
3032
|
+
return void 0;
|
|
3033
|
+
}
|
|
3034
|
+
writeAlteration(draft, degree.value, _nullishCoalesce(_optionalChain([accidental, 'optionalAccess', _21 => _21.value]), () => ( 0)));
|
|
2596
3035
|
return degree.next;
|
|
2597
3036
|
}
|
|
3037
|
+
function writesFifth(draft) {
|
|
3038
|
+
return draft.base === "dim" || draft.base === "aug" || altersDegree(draft, 5);
|
|
3039
|
+
}
|
|
2598
3040
|
function matchNumberToken(text, at, table) {
|
|
2599
3041
|
const entries = Object.entries(table).map(([token, value]) => [token, value]);
|
|
2600
3042
|
return matchToken(text, at, entries);
|
|
2601
3043
|
}
|
|
3044
|
+
function openings(core) {
|
|
3045
|
+
const found = [];
|
|
3046
|
+
for (const [token, value] of COMPOUND_TOKENS) {
|
|
3047
|
+
if (core.startsWith(token)) {
|
|
3048
|
+
found.push({ length: token.length, base: value.base, seventh: value.seventh });
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
for (const [token, value] of BASE_TOKENS) {
|
|
3052
|
+
if (!core.startsWith(token)) {
|
|
3053
|
+
continue;
|
|
3054
|
+
}
|
|
3055
|
+
found.push(
|
|
3056
|
+
value === "major" ? { length: token.length, major: true, glyph: token === "\u0394" || token === "^" } : { length: token.length, base: value }
|
|
3057
|
+
);
|
|
3058
|
+
}
|
|
3059
|
+
found.sort((a, b) => b.length - a.length);
|
|
3060
|
+
return [...found, void 0];
|
|
3061
|
+
}
|
|
2602
3062
|
function structuralSpec(text) {
|
|
2603
3063
|
let core = "";
|
|
2604
3064
|
const groups = [];
|
|
@@ -2626,24 +3086,37 @@ function structuralSpec(text) {
|
|
|
2626
3086
|
if (inside) {
|
|
2627
3087
|
return void 0;
|
|
2628
3088
|
}
|
|
3089
|
+
for (const opening of openings(core)) {
|
|
3090
|
+
const spec = readCore(core, groups, opening);
|
|
3091
|
+
if (spec !== void 0) {
|
|
3092
|
+
return spec;
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
return void 0;
|
|
3096
|
+
}
|
|
3097
|
+
function readCore(core, groups, opening) {
|
|
2629
3098
|
const draft = {
|
|
2630
3099
|
base: "maj",
|
|
2631
3100
|
alterations: /* @__PURE__ */ new Map(),
|
|
2632
3101
|
additions: /* @__PURE__ */ new Set(),
|
|
2633
3102
|
omissions: /* @__PURE__ */ new Set(),
|
|
3103
|
+
implied: /* @__PURE__ */ new Set(),
|
|
2634
3104
|
major: false
|
|
2635
3105
|
};
|
|
2636
3106
|
let at = 0;
|
|
2637
|
-
const opening = matchToken(core, at, BASE_TOKENS);
|
|
2638
3107
|
let markerGlyph = false;
|
|
2639
3108
|
let markerAfterBase = false;
|
|
2640
3109
|
if (opening !== void 0) {
|
|
2641
|
-
at = opening.
|
|
2642
|
-
if (opening.
|
|
3110
|
+
at = opening.length;
|
|
3111
|
+
if (opening.major === true) {
|
|
2643
3112
|
draft.major = true;
|
|
2644
|
-
markerGlyph =
|
|
2645
|
-
} else {
|
|
2646
|
-
draft.base = opening.
|
|
3113
|
+
markerGlyph = opening.glyph === true;
|
|
3114
|
+
} else if (opening.base !== void 0) {
|
|
3115
|
+
draft.base = opening.base;
|
|
3116
|
+
if (opening.seventh !== void 0) {
|
|
3117
|
+
draft.seventh = opening.seventh;
|
|
3118
|
+
draft.seventhOverBase = opening.seventh;
|
|
3119
|
+
}
|
|
2647
3120
|
}
|
|
2648
3121
|
}
|
|
2649
3122
|
if (!draft.major) {
|
|
@@ -2688,7 +3161,7 @@ function structuralSpec(text) {
|
|
|
2688
3161
|
rootPc: 0,
|
|
2689
3162
|
base: draft.base,
|
|
2690
3163
|
...draft.seventh === void 0 ? {} : { seventh: draft.seventh },
|
|
2691
|
-
alterations: [...draft.alterations
|
|
3164
|
+
alterations: [...draft.alterations.values()],
|
|
2692
3165
|
additions: [...draft.additions],
|
|
2693
3166
|
omissions: [...draft.omissions]
|
|
2694
3167
|
};
|
|
@@ -2698,10 +3171,10 @@ function suffixSpec(suffix) {
|
|
|
2698
3171
|
return quality === void 0 ? structuralSpec(suffix) : chordSpecForQuality(quality, 0);
|
|
2699
3172
|
}
|
|
2700
3173
|
function assertNamingSystem(system) {
|
|
2701
|
-
|
|
3174
|
+
_chunkS5BKZZGMcjs.formatNote.call(void 0, SYSTEM_PROBE, { system });
|
|
2702
3175
|
}
|
|
2703
3176
|
function bareNote(text, system) {
|
|
2704
|
-
const read =
|
|
3177
|
+
const read = _chunkS5BKZZGMcjs.tryParseNote.call(void 0, text, { system });
|
|
2705
3178
|
if (!read.ok) {
|
|
2706
3179
|
return void 0;
|
|
2707
3180
|
}
|
|
@@ -2710,12 +3183,13 @@ function bareNote(text, system) {
|
|
|
2710
3183
|
function rootSplits(text, system) {
|
|
2711
3184
|
if (system === "english") {
|
|
2712
3185
|
const match = text.match(ROOT_RE);
|
|
2713
|
-
const token = _optionalChain([match, 'optionalAccess',
|
|
2714
|
-
return token === void 0 ? [] : [{ root:
|
|
3186
|
+
const token = _optionalChain([match, 'optionalAccess', _22 => _22[0]]);
|
|
3187
|
+
return token === void 0 ? [] : [{ root: _chunkS5BKZZGMcjs.parseNote.call(void 0, token, { system }), rest: text.slice(token.length) }];
|
|
2715
3188
|
}
|
|
2716
3189
|
assertNamingSystem(system);
|
|
2717
3190
|
const splits = [];
|
|
2718
|
-
|
|
3191
|
+
const longest = Math.min(text.length, _chunkS5BKZZGMcjs.maxNoteNameLength.call(void 0, system));
|
|
3192
|
+
for (let end = longest; end > 0; end -= 1) {
|
|
2719
3193
|
const root = bareNote(text.slice(0, end), system);
|
|
2720
3194
|
if (root !== void 0) {
|
|
2721
3195
|
splits.push({ root, rest: text.slice(end) });
|
|
@@ -2725,14 +3199,14 @@ function rootSplits(text, system) {
|
|
|
2725
3199
|
}
|
|
2726
3200
|
function bassNote(text, system) {
|
|
2727
3201
|
if (system === "english") {
|
|
2728
|
-
return BASS_RE.test(text) ?
|
|
3202
|
+
return BASS_RE.test(text) ? _chunkS5BKZZGMcjs.parseNote.call(void 0, text, { system }) : void 0;
|
|
2729
3203
|
}
|
|
2730
3204
|
return bareNote(text, system);
|
|
2731
3205
|
}
|
|
2732
3206
|
function makeSpelledChord(root, spec, bass) {
|
|
2733
|
-
const rooted = { ...spec, rootPc:
|
|
3207
|
+
const rooted = { ...spec, rootPc: _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, root) };
|
|
2734
3208
|
if (bass !== void 0) {
|
|
2735
|
-
rooted.bassPc =
|
|
3209
|
+
rooted.bassPc = _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, bass);
|
|
2736
3210
|
}
|
|
2737
3211
|
const chord = chordFromSpec(rooted);
|
|
2738
3212
|
chord.rootSpelling = { letter: root.letter, alter: root.alter };
|
|
@@ -2753,82 +3227,53 @@ function chordAfterRoot(root, rest, system) {
|
|
|
2753
3227
|
const spec = suffixSpec(rest);
|
|
2754
3228
|
return spec === void 0 ? void 0 : makeSpelledChord(root, spec);
|
|
2755
3229
|
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
}
|
|
2804
|
-
if (data.toneSpellings !== void 0) {
|
|
2805
|
-
copy.toneSpellings = data.toneSpellings;
|
|
2806
|
-
}
|
|
2807
|
-
return copy;
|
|
2808
|
-
}
|
|
2809
|
-
function toChordData(value) {
|
|
2810
|
-
if (typeof value === "string") {
|
|
2811
|
-
return parseChordSymbol(value);
|
|
2812
|
-
}
|
|
2813
|
-
if (typeof value === "object" && value !== null) {
|
|
2814
|
-
const data = "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON() : value;
|
|
2815
|
-
return normalizedChord(data);
|
|
2816
|
-
}
|
|
2817
|
-
throw new (0, _chunkQ2WGKJNNcjs.InvalidInputError)(
|
|
2818
|
-
`chord must be a chord symbol or chord data; received ${typeof value}`
|
|
2819
|
-
);
|
|
2820
|
-
}
|
|
2821
|
-
function symbolName(note, system) {
|
|
2822
|
-
const name = _chunkQ2WGKJNNcjs.formatNote.call(void 0, note, { system });
|
|
2823
|
-
return system === "german" ? `${name.slice(0, 1).toUpperCase()}${name.slice(1)}` : name;
|
|
2824
|
-
}
|
|
2825
|
-
function pitchClassName(pc, hint, system, flats, inheritFlats) {
|
|
2826
|
-
if (flats === void 0 && hint !== void 0 && _chunkQ2WGKJNNcjs.noteToPitchClass.call(void 0, hint) === pc) {
|
|
2827
|
-
return symbolName(hint, system);
|
|
2828
|
-
}
|
|
2829
|
-
const note = _chunkQ2WGKJNNcjs.midiToNote.call(void 0, 60 + pc, _nullishCoalesce(flats, () => ( inheritFlats)) ? "flat" : "sharp");
|
|
2830
|
-
return symbolName({ letter: note.letter, alter: note.alter }, system);
|
|
2831
|
-
}
|
|
3230
|
+
|
|
3231
|
+
// src/theory/symbol/suffix.ts
|
|
3232
|
+
var CANONICAL_SUFFIX = {
|
|
3233
|
+
maj: "",
|
|
3234
|
+
min: "m",
|
|
3235
|
+
dim: "dim",
|
|
3236
|
+
aug: "aug",
|
|
3237
|
+
maj7: "maj7",
|
|
3238
|
+
min7: "m7",
|
|
3239
|
+
dom7: "7",
|
|
3240
|
+
dim7: "dim7",
|
|
3241
|
+
m7b5: "m7b5",
|
|
3242
|
+
minMaj7: "mMaj7",
|
|
3243
|
+
minMaj9: "mMaj9",
|
|
3244
|
+
minMaj11: "mMaj11",
|
|
3245
|
+
minMaj13: "mMaj13",
|
|
3246
|
+
aug7: "aug7",
|
|
3247
|
+
augMaj7: "augMaj7",
|
|
3248
|
+
majb5: "maj(b5)",
|
|
3249
|
+
"6": "6",
|
|
3250
|
+
min6: "m6",
|
|
3251
|
+
"6/9": "6/9",
|
|
3252
|
+
sus2: "sus2",
|
|
3253
|
+
sus4: "sus4",
|
|
3254
|
+
add9: "add9",
|
|
3255
|
+
add11: "add11",
|
|
3256
|
+
maj9: "maj9",
|
|
3257
|
+
min9: "m9",
|
|
3258
|
+
dom9: "9",
|
|
3259
|
+
"7b9": "7b9",
|
|
3260
|
+
"7#9": "7#9",
|
|
3261
|
+
"7#11": "7#11",
|
|
3262
|
+
"7b13": "7b13",
|
|
3263
|
+
"11": "11",
|
|
3264
|
+
"13": "13",
|
|
3265
|
+
"5": "5",
|
|
3266
|
+
"7sus4": "7sus4",
|
|
3267
|
+
"7b5": "7b5",
|
|
3268
|
+
"7alt": "7alt",
|
|
3269
|
+
"13b9": "13b9",
|
|
3270
|
+
maj13: "maj13",
|
|
3271
|
+
"maj7#11": "maj7#11",
|
|
3272
|
+
min11: "m11",
|
|
3273
|
+
min13: "m13",
|
|
3274
|
+
minAdd9: "madd9",
|
|
3275
|
+
"min6/9": "m6/9"
|
|
3276
|
+
};
|
|
2832
3277
|
var CORE_CANDIDATES = chordQualities().map((quality) => [quality, chordSpecForQuality(quality, 0)]).filter(([, spec]) => spec.alterations.every(({ degree, alter }) => degree === 5 || alter === 0));
|
|
2833
3278
|
function carriesAlteration(spec, part) {
|
|
2834
3279
|
return spec.alterations.some(
|
|
@@ -2883,7 +3328,7 @@ function figureText(spec, core) {
|
|
|
2883
3328
|
figures.push({ degree, text: `${alter < 0 ? "b" : alter > 0 ? "#" : ""}${degree}` });
|
|
2884
3329
|
}
|
|
2885
3330
|
for (const degree of spec.additions) {
|
|
2886
|
-
if (_optionalChain([core, 'optionalAccess',
|
|
3331
|
+
if (_optionalChain([core, 'optionalAccess', _23 => _23.additions, 'access', _24 => _24.includes, 'call', _25 => _25(degree)]) !== true) {
|
|
2887
3332
|
figures.push({ degree, text: `add${degree}` });
|
|
2888
3333
|
}
|
|
2889
3334
|
}
|
|
@@ -2900,42 +3345,370 @@ function specSuffix(spec) {
|
|
|
2900
3345
|
const figures = figureText(spec, coreSpec);
|
|
2901
3346
|
return figures.length === 0 ? text : `${text}(${figures.join(",")})`;
|
|
2902
3347
|
}
|
|
3348
|
+
|
|
3349
|
+
// src/theory/symbol/spelling.ts
|
|
3350
|
+
function bareSpelling(note) {
|
|
3351
|
+
return { letter: note.letter, alter: note.alter };
|
|
3352
|
+
}
|
|
3353
|
+
function plainSpelling(pc, asFlat) {
|
|
3354
|
+
return bareSpelling(_chunkS5BKZZGMcjs.midiToNote.call(void 0, 60 + pc, asFlat ? "flat" : "sharp"));
|
|
3355
|
+
}
|
|
3356
|
+
function symbolName(note, system) {
|
|
3357
|
+
const name = _chunkS5BKZZGMcjs.formatNote.call(void 0, note, { system });
|
|
3358
|
+
return system === "german" ? `${name.slice(0, 1).toUpperCase()}${name.slice(1)}` : name;
|
|
3359
|
+
}
|
|
3360
|
+
function isWrittenSpelling(spelling) {
|
|
3361
|
+
const written = _chunkS5BKZZGMcjs.midiToNote.call(void 0,
|
|
3362
|
+
60 + _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, spelling),
|
|
3363
|
+
spelling.alter < 0 ? "flat" : "sharp"
|
|
3364
|
+
);
|
|
3365
|
+
return written.letter === spelling.letter && written.alter === spelling.alter;
|
|
3366
|
+
}
|
|
3367
|
+
function pitchClassName(pc, hint, system, flats, inheritFlats) {
|
|
3368
|
+
if (flats === void 0 && hint !== void 0 && _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, hint) === pc) {
|
|
3369
|
+
return symbolName(hint, system);
|
|
3370
|
+
}
|
|
3371
|
+
return symbolName(plainSpelling(pc, _nullishCoalesce(_nullishCoalesce(flats, () => ( inheritFlats)), () => ( false))), system);
|
|
3372
|
+
}
|
|
3373
|
+
function onAccidentalSide(spelling, flats) {
|
|
3374
|
+
return flats === void 0 || spelling.alter === 0 || spelling.alter < 0 === flats;
|
|
3375
|
+
}
|
|
3376
|
+
function bySameStep(spelling, from, to) {
|
|
3377
|
+
return bareSpelling(_chunkS5BKZZGMcjs.transposeByInterval.call(void 0, spelling, _chunkS5BKZZGMcjs.spelledInterval.call(void 0, from, to)));
|
|
3378
|
+
}
|
|
3379
|
+
function spellingAbove(root, letters, pc) {
|
|
3380
|
+
const letter = ((root.letter + letters) % 7 + 7) % 7;
|
|
3381
|
+
const natural = _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, { letter, alter: 0 });
|
|
3382
|
+
return { letter, alter: ((pc - natural) % 12 + 18) % 12 - 6 };
|
|
3383
|
+
}
|
|
3384
|
+
function carriedBass(spelling, from, to, asFlat, isOwnSpelling) {
|
|
3385
|
+
const carried = bySameStep(spelling, from, to);
|
|
3386
|
+
return isOwnSpelling(carried) || isWrittenSpelling(carried) ? carried : plainSpelling(_chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, carried), asFlat);
|
|
3387
|
+
}
|
|
3388
|
+
function hintFor(hint, pc) {
|
|
3389
|
+
return hint !== void 0 && _chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, hint) === pc ? hint : void 0;
|
|
3390
|
+
}
|
|
3391
|
+
function rootSpellingFor(pc, hint, flats) {
|
|
3392
|
+
return hint !== void 0 && onAccidentalSide(hint, flats) ? hint : plainSpelling(pc, _nullishCoalesce(flats, () => ( false)));
|
|
3393
|
+
}
|
|
3394
|
+
|
|
3395
|
+
// src/theory/symbol/index.ts
|
|
3396
|
+
function parseChordSymbol(text, opts) {
|
|
3397
|
+
return _chunkS5BKZZGMcjs.unwrapParse.call(void 0, tryParseChordSymbol(text, opts));
|
|
3398
|
+
}
|
|
3399
|
+
function tryParseChordSymbol(text, opts) {
|
|
3400
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
3401
|
+
try {
|
|
3402
|
+
if (typeof text !== "string") {
|
|
3403
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`chord symbol must be a string; received ${typeof text}`);
|
|
3404
|
+
}
|
|
3405
|
+
const system = _nullishCoalesce(asked.system, () => ( DEFAULT_SYSTEM));
|
|
3406
|
+
const trimmed = text.trim().replaceAll("\u266F", "#").replaceAll("\u266D", "b").replaceAll("\u{1D12A}", "x").replaceAll("\u{1D12B}", "bb").replaceAll("\u2206", "\u0394");
|
|
3407
|
+
const splits = rootSplits(trimmed, system);
|
|
3408
|
+
if (splits.length === 0) {
|
|
3409
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Invalid chord symbol: ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, text)}`);
|
|
3410
|
+
}
|
|
3411
|
+
for (const { root, rest } of splits) {
|
|
3412
|
+
const chord = chordAfterRoot(root, rest, system);
|
|
3413
|
+
if (chord !== void 0) {
|
|
3414
|
+
return { ok: true, value: chord };
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unrecognized chord quality: ${_chunkS5BKZZGMcjs.describeRejected.call(void 0, text)}`);
|
|
3418
|
+
} catch (error) {
|
|
3419
|
+
return _chunkS5BKZZGMcjs.parseFailure.call(void 0, error);
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
2903
3422
|
function formatChordSymbol(chord, opts) {
|
|
2904
3423
|
const data = toChordData(chord);
|
|
2905
3424
|
if (!Object.hasOwn(CANONICAL_SUFFIX, data.quality)) {
|
|
2906
|
-
throw new (0,
|
|
2907
|
-
}
|
|
2908
|
-
const
|
|
2909
|
-
const
|
|
2910
|
-
const
|
|
2911
|
-
const
|
|
3425
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(`Unknown chord quality: ${String(data.quality)}`);
|
|
3426
|
+
}
|
|
3427
|
+
const asked = _chunkS5BKZZGMcjs.assertOptions.call(void 0, opts, "opts");
|
|
3428
|
+
const system = _nullishCoalesce(asked.system, () => ( DEFAULT_SYSTEM));
|
|
3429
|
+
const flats = asked.flats;
|
|
3430
|
+
const rootPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, data.rootPc);
|
|
3431
|
+
const rootHint = hintFor(data.rootSpelling, rootPc);
|
|
3432
|
+
const rootSpelling = rootSpellingFor(rootPc, rootHint, flats);
|
|
2912
3433
|
const suffix = specSuffix(chordSpecOf(data));
|
|
2913
|
-
let symbol = `${
|
|
2914
|
-
if (data.bassPc !== void 0 &&
|
|
2915
|
-
const
|
|
2916
|
-
const
|
|
2917
|
-
|
|
3434
|
+
let symbol = `${symbolName(rootSpelling, system)}${suffix}`;
|
|
3435
|
+
if (data.bassPc !== void 0 && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, data.bassPc) !== rootPc) {
|
|
3436
|
+
const bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, data.bassPc);
|
|
3437
|
+
const bassHint = hintFor(data.bassSpelling, bassPc);
|
|
3438
|
+
const tonePcs = new Set(chordPitchClasses(data, { includeBass: false }));
|
|
3439
|
+
const ownSpelling = tonePcs.has(bassPc) ? spellingAbove(
|
|
3440
|
+
rootSpelling,
|
|
3441
|
+
(_nullishCoalesce(degreeOfInterval(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, bassPc - rootPc), data), () => ( 1))) - 1,
|
|
3442
|
+
bassPc
|
|
3443
|
+
) : void 0;
|
|
3444
|
+
const bassName = rootHint !== void 0 && bassHint !== void 0 ? symbolName(
|
|
3445
|
+
carriedBass(
|
|
3446
|
+
bassHint,
|
|
3447
|
+
rootHint,
|
|
3448
|
+
rootSpelling,
|
|
3449
|
+
_nullishCoalesce(flats, () => ( rootSpelling.alter < 0)),
|
|
3450
|
+
(spelling) => ownSpelling !== void 0 && spelling.letter === ownSpelling.letter && spelling.alter === ownSpelling.alter
|
|
3451
|
+
),
|
|
3452
|
+
system
|
|
3453
|
+
) : pitchClassName(bassPc, bassHint, system, flats, rootSpelling.alter < 0);
|
|
3454
|
+
symbol += `/${bassName}`;
|
|
2918
3455
|
}
|
|
2919
3456
|
return symbol;
|
|
2920
3457
|
}
|
|
3458
|
+
function transposeChordSpellings(spellings, semitones, flats) {
|
|
3459
|
+
const byLetter = (spelling) => spelling === void 0 ? void 0 : bareSpelling(_chunkS5BKZZGMcjs.transposeNote.call(void 0, spelling, semitones));
|
|
3460
|
+
const movedRoot = byLetter(spellings.rootSpelling);
|
|
3461
|
+
const movedBass = byLetter(spellings.bassSpelling);
|
|
3462
|
+
const side = [movedRoot, spellings.rootSpelling, movedBass, spellings.bassSpelling].find(
|
|
3463
|
+
(spelling) => spelling !== void 0 && spelling.alter !== 0
|
|
3464
|
+
);
|
|
3465
|
+
const preferFlats = _nullishCoalesce(flats, () => ( (side !== void 0 && side.alter < 0)));
|
|
3466
|
+
const octaveOnly = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, semitones) === 0;
|
|
3467
|
+
const plainName = (spelling, asFlat) => plainSpelling(_chunkS5BKZZGMcjs.noteToPitchClass.call(void 0, spelling), asFlat);
|
|
3468
|
+
const writable = (spelling) => octaveOnly || isWrittenSpelling(spelling) ? spelling : plainName(spelling, preferFlats);
|
|
3469
|
+
const root = spellings.rootSpelling;
|
|
3470
|
+
const bass = spellings.bassSpelling;
|
|
3471
|
+
const carriesBass = (candidate) => {
|
|
3472
|
+
if (root === void 0 || bass === void 0 || octaveOnly || !isWrittenSpelling(bass)) {
|
|
3473
|
+
return true;
|
|
3474
|
+
}
|
|
3475
|
+
const carried = bySameStep(bass, root, candidate);
|
|
3476
|
+
return isWrittenSpelling(carried) && onAccidentalSide(carried, flats);
|
|
3477
|
+
};
|
|
3478
|
+
const moved = {};
|
|
3479
|
+
if (movedRoot !== void 0) {
|
|
3480
|
+
const asked = flats !== void 0 && !octaveOnly && !isWrittenSpelling(movedRoot);
|
|
3481
|
+
const candidates = [
|
|
3482
|
+
...octaveOnly || isWrittenSpelling(movedRoot) ? [movedRoot] : [],
|
|
3483
|
+
plainName(movedRoot, preferFlats),
|
|
3484
|
+
...asked ? [movedRoot] : [],
|
|
3485
|
+
plainName(movedRoot, !preferFlats)
|
|
3486
|
+
];
|
|
3487
|
+
moved.rootSpelling = _nullishCoalesce(candidates.find(carriesBass), () => ( plainName(movedRoot, preferFlats)));
|
|
3488
|
+
}
|
|
3489
|
+
const step = root !== void 0 && moved.rootSpelling !== void 0 ? _chunkS5BKZZGMcjs.spelledInterval.call(void 0, root, moved.rootSpelling) : void 0;
|
|
3490
|
+
const byStep = (spelling) => bareSpelling(
|
|
3491
|
+
step === void 0 ? _chunkS5BKZZGMcjs.transposeNote.call(void 0, spelling, semitones) : _chunkS5BKZZGMcjs.transposeByInterval.call(void 0, spelling, step)
|
|
3492
|
+
);
|
|
3493
|
+
if (bass !== void 0) {
|
|
3494
|
+
moved.bassSpelling = writable(byStep(bass));
|
|
3495
|
+
}
|
|
3496
|
+
if (spellings.toneSpellings !== void 0) {
|
|
3497
|
+
moved.toneSpellings = spellings.toneSpellings.map(byStep);
|
|
3498
|
+
}
|
|
3499
|
+
return moved;
|
|
3500
|
+
}
|
|
2921
3501
|
function transposeChordSymbol(text, semitones, opts) {
|
|
2922
|
-
|
|
3502
|
+
_chunkS5BKZZGMcjs.assertFiniteSemitones.call(void 0, semitones);
|
|
2923
3503
|
const chord = parseChordSymbol(text, opts);
|
|
2924
|
-
const transposed = { ...chord, rootPc:
|
|
2925
|
-
if (chord.rootSpelling !== void 0) {
|
|
2926
|
-
const hint = _chunkQ2WGKJNNcjs.transposeNote.call(void 0, chord.rootSpelling, semitones);
|
|
2927
|
-
transposed.rootSpelling = { letter: hint.letter, alter: hint.alter };
|
|
2928
|
-
}
|
|
3504
|
+
const transposed = { ...chord, rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + semitones) };
|
|
2929
3505
|
if (chord.bassPc !== void 0) {
|
|
2930
|
-
transposed.bassPc =
|
|
3506
|
+
transposed.bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.bassPc + semitones);
|
|
2931
3507
|
}
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
transposed.
|
|
3508
|
+
const spellings = transposeChordSpellings(chord, semitones, _optionalChain([opts, 'optionalAccess', _26 => _26.flats]));
|
|
3509
|
+
if (spellings.rootSpelling !== void 0) {
|
|
3510
|
+
transposed.rootSpelling = spellings.rootSpelling;
|
|
3511
|
+
}
|
|
3512
|
+
if (spellings.bassSpelling !== void 0) {
|
|
3513
|
+
transposed.bassSpelling = spellings.bassSpelling;
|
|
3514
|
+
}
|
|
3515
|
+
if (spellings.toneSpellings !== void 0) {
|
|
3516
|
+
transposed.toneSpellings = spellings.toneSpellings;
|
|
2935
3517
|
}
|
|
2936
3518
|
return formatChordSymbol(transposed, opts);
|
|
2937
3519
|
}
|
|
2938
3520
|
|
|
3521
|
+
// src/theory/symbol/coerce.ts
|
|
3522
|
+
function normalizedChord(data) {
|
|
3523
|
+
if (!Array.isArray(data.intervals)) {
|
|
3524
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)("chord.intervals must be an array of semitone offsets");
|
|
3525
|
+
}
|
|
3526
|
+
const copy = {
|
|
3527
|
+
rootPc: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, data.rootPc, "chord.rootPc")),
|
|
3528
|
+
quality: data.quality,
|
|
3529
|
+
// Each offset is checked rather than copied blind: a chord holding a NaN
|
|
3530
|
+
// interval voices, spells and formats as a chord that looks real, and the
|
|
3531
|
+
// failure surfaces wherever the number is finally used.
|
|
3532
|
+
intervals: data.intervals.map(
|
|
3533
|
+
(interval, index) => _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, interval, `chord.intervals[${index}]`)
|
|
3534
|
+
)
|
|
3535
|
+
};
|
|
3536
|
+
if (data.bassPc !== void 0) {
|
|
3537
|
+
copy.bassPc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, _chunkS5BKZZGMcjs.assertFiniteNumber.call(void 0, data.bassPc, "chord.bassPc"));
|
|
3538
|
+
}
|
|
3539
|
+
if (data.rootSpelling !== void 0) {
|
|
3540
|
+
copy.rootSpelling = data.rootSpelling;
|
|
3541
|
+
}
|
|
3542
|
+
if (data.bassSpelling !== void 0) {
|
|
3543
|
+
copy.bassSpelling = data.bassSpelling;
|
|
3544
|
+
}
|
|
3545
|
+
if (data.toneSpellings !== void 0) {
|
|
3546
|
+
copy.toneSpellings = data.toneSpellings;
|
|
3547
|
+
}
|
|
3548
|
+
return copy;
|
|
3549
|
+
}
|
|
3550
|
+
function toChordData(value) {
|
|
3551
|
+
if (typeof value === "string") {
|
|
3552
|
+
return parseChordSymbol(value);
|
|
3553
|
+
}
|
|
3554
|
+
if (typeof value === "object" && value !== null) {
|
|
3555
|
+
const data = "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON() : value;
|
|
3556
|
+
return normalizedChord(data);
|
|
3557
|
+
}
|
|
3558
|
+
throw new (0, _chunkS5BKZZGMcjs.InvalidInputError)(
|
|
3559
|
+
`chord must be a chord symbol or chord data; received ${typeof value}`
|
|
3560
|
+
);
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
// src/theory/tendency/index.ts
|
|
3564
|
+
function hasInterval(chord, semitones) {
|
|
3565
|
+
return chord.intervals.some((interval) => _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, interval) === semitones);
|
|
3566
|
+
}
|
|
3567
|
+
function isDiatonicChord(chord, key) {
|
|
3568
|
+
return chordPitchClasses(chord).every((pc) => isScaleTone(pc, key));
|
|
3569
|
+
}
|
|
3570
|
+
function hasMajorThird(chord) {
|
|
3571
|
+
return hasInterval(chord, 4);
|
|
3572
|
+
}
|
|
3573
|
+
function soundsDominantSeventh(chord) {
|
|
3574
|
+
return hasMajorThird(chord) && hasInterval(chord, 10);
|
|
3575
|
+
}
|
|
3576
|
+
function soundsMajorTriad(chord) {
|
|
3577
|
+
return hasMajorThird(chord) && !hasInterval(chord, 10) && !hasInterval(chord, 11);
|
|
3578
|
+
}
|
|
3579
|
+
function hasDominantSonority(chord) {
|
|
3580
|
+
return soundsMajorTriad(chord) || soundsDominantSeventh(chord);
|
|
3581
|
+
}
|
|
3582
|
+
function isDominantChordOf(chord, key) {
|
|
3583
|
+
if (_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) !== 7) {
|
|
3584
|
+
return false;
|
|
3585
|
+
}
|
|
3586
|
+
if (hasMajorThird(chord)) {
|
|
3587
|
+
return true;
|
|
3588
|
+
}
|
|
3589
|
+
const suspended = !hasInterval(chord, 3) && (hasInterval(chord, 5) || hasInterval(chord, 2));
|
|
3590
|
+
return suspended && hasInterval(chord, 10);
|
|
3591
|
+
}
|
|
3592
|
+
function isNeapolitanChordOf(chord, key) {
|
|
3593
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) === 1 && soundsMajorTriad(chord) && !isDiatonicChord(chord, key);
|
|
3594
|
+
}
|
|
3595
|
+
var DOMINANT_DEGREE = 5;
|
|
3596
|
+
function heptatonicFrameOf(key) {
|
|
3597
|
+
return scaleTonesInDegreeOrder(key).length === 7 ? key : majorKey(_chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc));
|
|
3598
|
+
}
|
|
3599
|
+
function degreeTriad(tones, index) {
|
|
3600
|
+
const root = _nullishCoalesce(tones[index], () => ( 0));
|
|
3601
|
+
return {
|
|
3602
|
+
third: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[(index + 2) % tones.length], () => ( 0))) - root),
|
|
3603
|
+
fifth: _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[(index + 4) % tones.length], () => ( 0))) - root)
|
|
3604
|
+
};
|
|
3605
|
+
}
|
|
3606
|
+
function tonicizableDegrees(key) {
|
|
3607
|
+
const tones = scaleTonesInDegreeOrder(heptatonicFrameOf(key));
|
|
3608
|
+
const minor = isMinorMask(key.modeMask12);
|
|
3609
|
+
const out = [];
|
|
3610
|
+
for (let index = 0; index < tones.length; index += 1) {
|
|
3611
|
+
const rootPc = tones[index];
|
|
3612
|
+
if (rootPc === void 0) {
|
|
3613
|
+
continue;
|
|
3614
|
+
}
|
|
3615
|
+
const triad = degreeTriad(tones, index);
|
|
3616
|
+
if (triad.fifth !== 7) {
|
|
3617
|
+
continue;
|
|
3618
|
+
}
|
|
3619
|
+
const dominantDegree = minor && index + 1 === DOMINANT_DEGREE;
|
|
3620
|
+
out.push({ degreeNumber: index + 1, rootPc, lower: triad.third === 3 && !dominantDegree });
|
|
3621
|
+
}
|
|
3622
|
+
return out;
|
|
3623
|
+
}
|
|
3624
|
+
function appliedDominantTarget(rootPc, key) {
|
|
3625
|
+
const target = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, rootPc);
|
|
3626
|
+
return _nullishCoalesce(tonicizableDegrees(key).find(
|
|
3627
|
+
(degree) => degree.degreeNumber !== 1 && degree.rootPc === target
|
|
3628
|
+
), () => ( null));
|
|
3629
|
+
}
|
|
3630
|
+
function leadingTonePcOf(key) {
|
|
3631
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc - 1);
|
|
3632
|
+
}
|
|
3633
|
+
var LEADING_TONE_QUALITIES = /* @__PURE__ */ new Set(["dim", "dim7", "m7b5"]);
|
|
3634
|
+
function soundsDiminishedTriad(chord) {
|
|
3635
|
+
return hasInterval(chord, 3) && hasInterval(chord, 6) && !hasInterval(chord, 7);
|
|
3636
|
+
}
|
|
3637
|
+
function isLeadingToneChordOf(chord, key) {
|
|
3638
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc) === leadingTonePcOf(key) && soundsDiminishedTriad(chord);
|
|
3639
|
+
}
|
|
3640
|
+
function isFunctioningLeadingTone(chord, key) {
|
|
3641
|
+
const role = chordToneRole(leadingTonePcOf(key), chord);
|
|
3642
|
+
if (role === "third") {
|
|
3643
|
+
return _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc) === _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, key.rootPc + 7);
|
|
3644
|
+
}
|
|
3645
|
+
if (role === "root") {
|
|
3646
|
+
return soundsDiminishedTriad(chord);
|
|
3647
|
+
}
|
|
3648
|
+
return false;
|
|
3649
|
+
}
|
|
3650
|
+
function seventhPcOf(chord) {
|
|
3651
|
+
for (const interval of chord.intervals) {
|
|
3652
|
+
const pc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval);
|
|
3653
|
+
if (chordToneRole(pc, chord) === "seventh") {
|
|
3654
|
+
return pc;
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
return void 0;
|
|
3658
|
+
}
|
|
3659
|
+
function fifthPcOf(chord) {
|
|
3660
|
+
for (const interval of chord.intervals) {
|
|
3661
|
+
const pc = _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, chord.rootPc + interval);
|
|
3662
|
+
if (chordToneRole(pc, chord) === "fifth") {
|
|
3663
|
+
return pc;
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
return void 0;
|
|
3667
|
+
}
|
|
3668
|
+
function isDescendingStep(interval) {
|
|
3669
|
+
return interval.number === 2 && (interval.semitones === -1 || interval.semitones === -2);
|
|
3670
|
+
}
|
|
3671
|
+
var THIRD_SEMITONES = [3, 4];
|
|
3672
|
+
function isFrustratedLeadingTone(fromPitch, toPitch, nextChord) {
|
|
3673
|
+
if (!THIRD_SEMITONES.includes(fromPitch - toPitch)) {
|
|
3674
|
+
return false;
|
|
3675
|
+
}
|
|
3676
|
+
const fifthPc = fifthPcOf(nextChord);
|
|
3677
|
+
return fifthPc !== void 0 && _chunkS5BKZZGMcjs.pitchClassOf.call(void 0, toPitch) === fifthPc;
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3680
|
+
|
|
3681
|
+
|
|
3682
|
+
|
|
3683
|
+
|
|
3684
|
+
|
|
3685
|
+
|
|
3686
|
+
|
|
3687
|
+
|
|
3688
|
+
|
|
3689
|
+
|
|
3690
|
+
|
|
3691
|
+
|
|
3692
|
+
|
|
3693
|
+
|
|
3694
|
+
|
|
3695
|
+
|
|
3696
|
+
|
|
3697
|
+
|
|
3698
|
+
|
|
3699
|
+
|
|
3700
|
+
|
|
3701
|
+
|
|
3702
|
+
|
|
3703
|
+
|
|
3704
|
+
|
|
3705
|
+
|
|
3706
|
+
|
|
3707
|
+
|
|
3708
|
+
|
|
3709
|
+
|
|
3710
|
+
|
|
3711
|
+
|
|
2939
3712
|
|
|
2940
3713
|
|
|
2941
3714
|
|
|
@@ -3049,5 +3822,5 @@ function transposeChordSymbol(text, semitones, opts) {
|
|
|
3049
3822
|
|
|
3050
3823
|
|
|
3051
3824
|
|
|
3052
|
-
exports.maskFromOffsets = maskFromOffsets; exports.MAJOR_MASK = MAJOR_MASK; exports.NATURAL_MINOR_MASK = NATURAL_MINOR_MASK; exports.HARMONIC_MINOR_MASK = HARMONIC_MINOR_MASK; exports.MELODIC_MINOR_MASK = MELODIC_MINOR_MASK; exports.DORIAN_MASK = DORIAN_MASK; exports.PHRYGIAN_MASK = PHRYGIAN_MASK; exports.LYDIAN_MASK = LYDIAN_MASK; exports.MIXOLYDIAN_MASK = MIXOLYDIAN_MASK; exports.LOCRIAN_MASK = LOCRIAN_MASK; exports.MAJOR_PENTATONIC_MASK = MAJOR_PENTATONIC_MASK; exports.MINOR_PENTATONIC_MASK = MINOR_PENTATONIC_MASK; exports.BLUES_MASK = BLUES_MASK; exports.WHOLE_TONE_MASK = WHOLE_TONE_MASK; exports.OCTATONIC_HALF_WHOLE_MASK = OCTATONIC_HALF_WHOLE_MASK; exports.OCTATONIC_WHOLE_HALF_MASK = OCTATONIC_WHOLE_HALF_MASK; exports.CHROMATIC_MASK = CHROMATIC_MASK; exports.LYDIAN_DOMINANT_MASK = LYDIAN_DOMINANT_MASK; exports.MIXOLYDIAN_B13_MASK = MIXOLYDIAN_B13_MASK; exports.LOCRIAN_NATURAL2_MASK = LOCRIAN_NATURAL2_MASK; exports.ALTERED_MASK = ALTERED_MASK; exports.PHRYGIAN_DOMINANT_MASK = PHRYGIAN_DOMINANT_MASK; exports.MIYAKO_BUSHI_MASK = MIYAKO_BUSHI_MASK; exports.RITSU_MASK = RITSU_MASK; exports.RYUKYU_MASK = RYUKYU_MASK; exports.DOUBLE_HARMONIC_MASK = DOUBLE_HARMONIC_MASK; exports.TODI_MASK = TODI_MASK; exports.MARWA_MASK = MARWA_MASK; exports.PURVI_MASK = PURVI_MASK; exports.NAMED_SCALES = NAMED_SCALES; exports.WORLD_SCALES = WORLD_SCALES; exports.SCALE_ALIASES = SCALE_ALIASES; exports.resolveScaleName = resolveScaleName; exports.namedScaleMask = namedScaleMask; exports.requireScaleMask = requireScaleMask; exports.
|
|
3053
|
-
//# sourceMappingURL=chunk-
|
|
3825
|
+
exports.maskFromOffsets = maskFromOffsets; exports.MAJOR_MASK = MAJOR_MASK; exports.NATURAL_MINOR_MASK = NATURAL_MINOR_MASK; exports.HARMONIC_MINOR_MASK = HARMONIC_MINOR_MASK; exports.MELODIC_MINOR_MASK = MELODIC_MINOR_MASK; exports.DORIAN_MASK = DORIAN_MASK; exports.PHRYGIAN_MASK = PHRYGIAN_MASK; exports.LYDIAN_MASK = LYDIAN_MASK; exports.MIXOLYDIAN_MASK = MIXOLYDIAN_MASK; exports.LOCRIAN_MASK = LOCRIAN_MASK; exports.MAJOR_PENTATONIC_MASK = MAJOR_PENTATONIC_MASK; exports.MINOR_PENTATONIC_MASK = MINOR_PENTATONIC_MASK; exports.BLUES_MASK = BLUES_MASK; exports.WHOLE_TONE_MASK = WHOLE_TONE_MASK; exports.OCTATONIC_HALF_WHOLE_MASK = OCTATONIC_HALF_WHOLE_MASK; exports.OCTATONIC_WHOLE_HALF_MASK = OCTATONIC_WHOLE_HALF_MASK; exports.CHROMATIC_MASK = CHROMATIC_MASK; exports.assertModeMask = assertModeMask; exports.LYDIAN_DOMINANT_MASK = LYDIAN_DOMINANT_MASK; exports.MIXOLYDIAN_B13_MASK = MIXOLYDIAN_B13_MASK; exports.LOCRIAN_NATURAL2_MASK = LOCRIAN_NATURAL2_MASK; exports.ALTERED_MASK = ALTERED_MASK; exports.PHRYGIAN_DOMINANT_MASK = PHRYGIAN_DOMINANT_MASK; exports.MIYAKO_BUSHI_MASK = MIYAKO_BUSHI_MASK; exports.RITSU_MASK = RITSU_MASK; exports.RYUKYU_MASK = RYUKYU_MASK; exports.DOUBLE_HARMONIC_MASK = DOUBLE_HARMONIC_MASK; exports.TODI_MASK = TODI_MASK; exports.MARWA_MASK = MARWA_MASK; exports.PURVI_MASK = PURVI_MASK; exports.NAMED_SCALES = NAMED_SCALES; exports.WORLD_SCALES = WORLD_SCALES; exports.SCALE_ALIASES = SCALE_ALIASES; exports.resolveScaleName = resolveScaleName; exports.namedScaleMask = namedScaleMask; exports.requireScaleMask = requireScaleMask; exports.isMinorMask = isMinorMask; exports.variantOfMask = variantOfMask; exports.assertKeyVariant = assertKeyVariant; exports.scaleNameOfMask = scaleNameOfMask; exports.tryResolveKeyName = tryResolveKeyName; exports.toKeyScale = toKeyScale; exports.isScaleTone = isScaleTone; exports.nearestScaleTone = nearestScaleTone; exports.scaleLadderPosition = scaleLadderPosition; exports.scaleLadderPitch = scaleLadderPitch; exports.shiftByScaleDegrees = shiftByScaleDegrees; exports.pitchToScaleDegree = pitchToScaleDegree; exports.diatonicPitchClasses = diatonicPitchClasses; exports.scaleTonesInDegreeOrder = scaleTonesInDegreeOrder; exports.assertTonicOf = assertTonicOf; exports.spellPitchClass = spellPitchClass; exports.spellScale = spellScale; exports.spellPitchClasses = spellPitchClasses; exports.spellChordFromRoot = spellChordFromRoot; exports.spellChord = spellChord; exports.spellPitch = spellPitch; exports.noteNames = noteNames; exports.isSignatureKey = isSignatureKey; exports.keySignatureFifths = keySignatureFifths; exports.keyFromFifths = keyFromFifths; exports.spelledKeyOf = spelledKeyOf; exports.relativeKeyOf = relativeKeyOf; exports.parallelKeyOf = parallelKeyOf; exports.isWrittenTonic = isWrittenTonic; exports.dominantKeyOf = dominantKeyOf; exports.subdominantKeyOf = subdominantKeyOf; exports.enharmonicKeyOf = enharmonicKeyOf; exports.relatedKeysOf = relatedKeysOf; exports.keyRelationBetween = keyRelationBetween; exports.resolveKey = resolveKey; exports.scaleOf = scaleOf; exports.majorKey = majorKey; exports.minorKey = minorKey; exports.scaleByName = scaleByName; exports.SCALE_SYSTEMS = SCALE_SYSTEMS; exports.scaleSystemOf = scaleSystemOf; exports.supportsFunctionalHarmony = supportsFunctionalHarmony; exports.chordSpecIntervals = chordSpecIntervals; exports.chordSpecQuality = chordSpecQuality; exports.chordQualities = chordQualities; exports.assertChordQuality = assertChordQuality; exports.assertChord = assertChord; exports.chordFromDegree = chordFromDegree; exports.makeChord = makeChord; exports.chordFromSpec = chordFromSpec; exports.chordSpecOf = chordSpecOf; exports.chordFromSpan = chordFromSpan; exports.spanFromChord = spanFromChord; exports.transposeChord = transposeChord; exports.chordToneSpellings = chordToneSpellings; exports.chordPitchClasses = chordPitchClasses; exports.intervalAboveRoot = intervalAboveRoot; exports.isChordMember = isChordMember; exports.chordToneRole = chordToneRole; exports.degreeOfInterval = degreeOfInterval; exports.thirdSlotOf = thirdSlotOf; exports.displacedThirds = displacedThirds; exports.diatonicTriad = diatonicTriad; exports.diatonicSeventh = diatonicSeventh; exports.simpleIntervalNumber = simpleIntervalNumber; exports.classifySpelledInterval = classifySpelledInterval; exports.voiceIndependence = voiceIndependence; exports.createsVoiceCrossing = createsVoiceCrossing; exports.createsVerticalDissonance = createsVerticalDissonance; exports.isForbiddenMelodicLeap = isForbiddenMelodicLeap; exports.isAugmentedMelodicInterval = isAugmentedMelodicInterval; exports.createsParallelPerfect = createsParallelPerfect; exports.createsParallelOctave = createsParallelOctave; exports.createsParallelUnison = createsParallelUnison; exports.createsHiddenParallelPerfect = createsHiddenParallelPerfect; exports.createsBattuta = createsBattuta; exports.createsVoiceOverlap = createsVoiceOverlap; exports.exceedsSpacing = exceedsSpacing; exports.isLeadingToneResolution = isLeadingToneResolution; exports.PROFILE_WEIGHTS = PROFILE_WEIGHTS; exports.profileWeights = profileWeights; exports.NoteSafety = NoteSafety; exports.ReasonFlag = ReasonFlag; exports.evaluateSafety = evaluateSafety; exports.enumerateSafePitches = enumerateSafePitches; exports.toChordData = toChordData; exports.parseChordSymbol = parseChordSymbol; exports.tryParseChordSymbol = tryParseChordSymbol; exports.formatChordSymbol = formatChordSymbol; exports.transposeChordSpellings = transposeChordSpellings; exports.transposeChordSymbol = transposeChordSymbol; exports.isDiatonicChord = isDiatonicChord; exports.hasMajorThird = hasMajorThird; exports.soundsDominantSeventh = soundsDominantSeventh; exports.hasDominantSonority = hasDominantSonority; exports.isDominantChordOf = isDominantChordOf; exports.isNeapolitanChordOf = isNeapolitanChordOf; exports.heptatonicFrameOf = heptatonicFrameOf; exports.tonicizableDegrees = tonicizableDegrees; exports.appliedDominantTarget = appliedDominantTarget; exports.leadingTonePcOf = leadingTonePcOf; exports.LEADING_TONE_QUALITIES = LEADING_TONE_QUALITIES; exports.isLeadingToneChordOf = isLeadingToneChordOf; exports.isFunctioningLeadingTone = isFunctioningLeadingTone; exports.seventhPcOf = seventhPcOf; exports.fifthPcOf = fifthPcOf; exports.isDescendingStep = isDescendingStep; exports.isFrustratedLeadingTone = isFrustratedLeadingTone;
|
|
3826
|
+
//# sourceMappingURL=chunk-3R3QVKY5.cjs.map
|