@libraz/libcantus 1.2.0 → 1.4.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/NOTICE +63 -0
- package/README.md +7 -1
- package/README_ja.md +17 -11
- package/dist/analyze/index.cjs +31 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +161 -13
- package/dist/analyze/index.d.ts +161 -13
- package/dist/analyze/index.js +37 -13
- package/dist/{chunk-NB25P3EH.js → chunk-2G5MCGYU.js} +33 -11
- package/dist/chunk-2G5MCGYU.js.map +1 -0
- package/dist/{chunk-NM7UAMC3.cjs → chunk-3FDBMIPR.cjs} +64 -64
- package/dist/chunk-3FDBMIPR.cjs.map +1 -0
- package/dist/{chunk-HPVSH7SF.cjs → chunk-3MDOEFIQ.cjs} +618 -954
- package/dist/chunk-3MDOEFIQ.cjs.map +1 -0
- package/dist/{chunk-FBH75DAY.js → chunk-5MWRBYAT.js} +560 -159
- package/dist/chunk-5MWRBYAT.js.map +1 -0
- package/dist/{chunk-J7FHVZII.cjs → chunk-6TTBEON3.cjs} +3074 -740
- package/dist/chunk-6TTBEON3.cjs.map +1 -0
- package/dist/{chunk-UMWZ4ZET.js → chunk-7NQ6AL3H.js} +4 -4
- package/dist/chunk-7NQ6AL3H.js.map +1 -0
- package/dist/{chunk-HWHGOVO6.cjs → chunk-E3QO3UET.cjs} +31 -23
- package/dist/chunk-E3QO3UET.cjs.map +1 -0
- package/dist/{chunk-H2KJHBW4.js → chunk-FJFULJZE.js} +2375 -191
- package/dist/chunk-FJFULJZE.js.map +1 -0
- package/dist/{chunk-Q6LFSAKV.js → chunk-FK3DGAIZ.js} +2657 -323
- package/dist/chunk-FK3DGAIZ.js.map +1 -0
- package/dist/chunk-GEDTJHAC.cjs.map +1 -1
- package/dist/{chunk-RFIBF2RR.js → chunk-H7FVMBUC.js} +138 -65
- package/dist/chunk-H7FVMBUC.js.map +1 -0
- package/dist/{chunk-DSMJRXCZ.cjs → chunk-HYSVSFNI.cjs} +931 -530
- package/dist/chunk-HYSVSFNI.cjs.map +1 -0
- package/dist/{chunk-35NBV2FT.cjs → chunk-KMYGRFZ6.cjs} +47 -24
- package/dist/chunk-KMYGRFZ6.cjs.map +1 -0
- package/dist/chunk-LQZQDBCD.cjs +5513 -0
- package/dist/chunk-LQZQDBCD.cjs.map +1 -0
- package/dist/{chunk-PM4XJE2Y.cjs → chunk-P3CPXAJ5.cjs} +76 -54
- package/dist/chunk-P3CPXAJ5.cjs.map +1 -0
- package/dist/{chunk-S5BKZZGM.cjs → chunk-S3QELJUE.cjs} +72 -56
- package/dist/chunk-S3QELJUE.cjs.map +1 -0
- package/dist/{chunk-PUKJP2Z5.js → chunk-TXFWSU5D.js} +31 -8
- package/dist/chunk-TXFWSU5D.js.map +1 -0
- package/dist/{chunk-76ZBTRG2.cjs → chunk-U4EQTDGN.cjs} +258 -218
- package/dist/chunk-U4EQTDGN.cjs.map +1 -0
- package/dist/chunk-UGLFDG7L.cjs.map +1 -1
- package/dist/{chunk-HYJJ2V2I.js → chunk-UTE5A36R.js} +483 -819
- package/dist/chunk-UTE5A36R.js.map +1 -0
- package/dist/{chunk-NFJ4P6ZZ.js → chunk-UZKQISRF.js} +17 -9
- package/dist/chunk-UZKQISRF.js.map +1 -0
- package/dist/{chunk-7KG3RTYS.js → chunk-VL5NXVCN.js} +281 -155
- package/dist/chunk-VL5NXVCN.js.map +1 -0
- package/dist/{chunk-CGBADIO5.cjs → chunk-WOMCXN2W.cjs} +328 -202
- package/dist/chunk-WOMCXN2W.cjs.map +1 -0
- package/dist/{chunk-3R3QVKY5.cjs → chunk-YDGMWH43.cjs} +397 -324
- package/dist/chunk-YDGMWH43.cjs.map +1 -0
- package/dist/{chunk-AGOVW7U6.js → chunk-YYVXRV3V.js} +72 -56
- package/dist/chunk-YYVXRV3V.js.map +1 -0
- package/dist/{chunk-M5RYMAFI.js → chunk-ZLNSH4UL.js} +71 -31
- package/dist/chunk-ZLNSH4UL.js.map +1 -0
- package/dist/{coerce-DRERzdve.d.cts → coerce-CUhHc3Tu.d.ts} +16 -8
- package/dist/{coerce-DP0vYu-x.d.ts → coerce-Ytt2Eiq9.d.cts} +16 -8
- package/dist/core/index.cjs +5 -5
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +9 -8
- package/dist/core/index.d.ts +9 -8
- package/dist/core/index.js +4 -4
- package/dist/generate/index.cjs +20 -8
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +105 -17
- package/dist/generate/index.d.ts +105 -17
- package/dist/generate/index.js +19 -7
- package/dist/{index-CL4b4gUQ.d.ts → index-5VJgKz_Q.d.cts} +6 -2
- package/dist/{index-B9QLziDe.d.cts → index-BLuDesVG.d.ts} +20 -13
- package/dist/{index-BHIUyjhZ.d.ts → index-BV6APVa6.d.cts} +20 -13
- package/dist/{index-BMweUlm5.d.cts → index-Bf0Sv8a9.d.ts} +6 -2
- package/dist/{index-Dw2DP7vm.d.ts → index-BkT21EMv.d.cts} +3 -2
- package/dist/{index-BL5N2Oyz.d.cts → index-C7KCaTRz.d.ts} +3 -2
- package/dist/{index-Cy15oTvh.d.ts → index-C9MYbuKS.d.cts} +7 -3
- package/dist/{index-Cy15oTvh.d.cts → index-C9MYbuKS.d.ts} +7 -3
- package/dist/{index-BNSM-DSk.d.cts → index-DVInzCDS.d.cts} +533 -28
- package/dist/{index-9eoQs2C1.d.ts → index-Dg-SAfhz.d.ts} +6 -4
- package/dist/{index-BJgP97N1.d.ts → index-jgeug9EA.d.ts} +533 -28
- package/dist/{index-cHvbYgJI.d.cts → index-pQihL4z7.d.cts} +6 -4
- package/dist/index.cjs +49 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -13
- package/dist/index.d.ts +13 -13
- package/dist/index.js +55 -19
- package/dist/{masks-Cc7-MzzY.d.ts → masks-BnzXnBj0.d.cts} +3 -2
- package/dist/{masks-pADfTOiD.d.cts → masks-tycmkrgs.d.ts} +3 -2
- package/dist/model/index.cjs +12 -12
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +259 -48
- package/dist/model/index.d.ts +259 -48
- package/dist/model/index.js +11 -11
- package/dist/{positional-DJgs6ltD.d.ts → positional-CscpxtlE.d.cts} +3 -2
- package/dist/{positional-DMZer-FM.d.cts → positional-DLnfUgqG.d.ts} +3 -2
- package/dist/{index-BRMbPkHE.d.ts → profile-B4WqcM4H.d.ts} +85 -610
- package/dist/{index-DGCNKAUr.d.cts → profile-BJd1XkPB.d.cts} +85 -610
- package/dist/theory/index.cjs +5 -5
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +18 -14
- package/dist/theory/index.d.ts +18 -14
- package/dist/theory/index.js +4 -4
- package/dist/{index-CJBBiAmU.d.ts → types-7mGFwvMm.d.ts} +1210 -31
- package/dist/{index-BBWNZS0f.d.cts → types-_ofpb2be.d.cts} +1210 -31
- package/package.json +13 -13
- package/dist/chunk-35NBV2FT.cjs.map +0 -1
- package/dist/chunk-3R3QVKY5.cjs.map +0 -1
- package/dist/chunk-76ZBTRG2.cjs.map +0 -1
- package/dist/chunk-7KG3RTYS.js.map +0 -1
- package/dist/chunk-AGOVW7U6.js.map +0 -1
- package/dist/chunk-CGBADIO5.cjs.map +0 -1
- package/dist/chunk-DSMJRXCZ.cjs.map +0 -1
- package/dist/chunk-FBH75DAY.js.map +0 -1
- package/dist/chunk-H2KJHBW4.js.map +0 -1
- package/dist/chunk-HPVSH7SF.cjs.map +0 -1
- package/dist/chunk-HWHGOVO6.cjs.map +0 -1
- package/dist/chunk-HYJJ2V2I.js.map +0 -1
- package/dist/chunk-J7FHVZII.cjs.map +0 -1
- package/dist/chunk-M5RYMAFI.js.map +0 -1
- package/dist/chunk-NB25P3EH.js.map +0 -1
- package/dist/chunk-NFJ4P6ZZ.js.map +0 -1
- package/dist/chunk-NM7UAMC3.cjs.map +0 -1
- package/dist/chunk-PM4XJE2Y.cjs.map +0 -1
- package/dist/chunk-PUKJP2Z5.js.map +0 -1
- package/dist/chunk-Q6LFSAKV.js.map +0 -1
- package/dist/chunk-RFIBF2RR.js.map +0 -1
- package/dist/chunk-S5BKZZGM.cjs.map +0 -1
- package/dist/chunk-SGLEQVJH.cjs +0 -3329
- package/dist/chunk-SGLEQVJH.cjs.map +0 -1
- package/dist/chunk-UMWZ4ZET.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/libcantus/libcantus/dist/chunk-GEDTJHAC.cjs"],"names":[],"mappings":"AAAA","file":"/home/runner/work/libcantus/libcantus/dist/chunk-GEDTJHAC.cjs"}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/libcantus/libcantus/ts/dist/chunk-GEDTJHAC.cjs"],"names":[],"mappings":"AAAA","file":"/home/runner/work/libcantus/libcantus/ts/dist/chunk-GEDTJHAC.cjs"}
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
tryParseKeyName,
|
|
34
34
|
tryParseNote,
|
|
35
35
|
unwrapParse
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-YYVXRV3V.js";
|
|
37
37
|
|
|
38
38
|
// src/theory/scale/masks.ts
|
|
39
39
|
function maskFromOffsets(offsets) {
|
|
@@ -328,7 +328,9 @@ function toKeyScale(value) {
|
|
|
328
328
|
return normalizedKeyScale(data);
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
|
-
throw new InvalidInputError(
|
|
331
|
+
throw new InvalidInputError(
|
|
332
|
+
`key must be a key name or a key/scale; received ${describeRejected(value)}`
|
|
333
|
+
);
|
|
332
334
|
}
|
|
333
335
|
|
|
334
336
|
// src/theory/scale/degrees.ts
|
|
@@ -449,7 +451,7 @@ function rotateMask(mask, semitones) {
|
|
|
449
451
|
const steps = (semitones % 12 + 12) % 12;
|
|
450
452
|
return (mask >> steps | mask << 12 - steps) & 4095;
|
|
451
453
|
}
|
|
452
|
-
var
|
|
454
|
+
var DIATONIC_MODE_OFFSET_ENTRIES = [
|
|
453
455
|
[rotateMask(MAJOR_MASK, 5), 1],
|
|
454
456
|
// lydian
|
|
455
457
|
[MAJOR_MASK, 0],
|
|
@@ -464,7 +466,8 @@ var DIATONIC_MODE_OFFSETS = /* @__PURE__ */ new Map([
|
|
|
464
466
|
// phrygian
|
|
465
467
|
[rotateMask(MAJOR_MASK, 11), -5]
|
|
466
468
|
// locrian
|
|
467
|
-
]
|
|
469
|
+
];
|
|
470
|
+
var DIATONIC_MODE_OFFSETS = new Map(DIATONIC_MODE_OFFSET_ENTRIES);
|
|
468
471
|
function modeOffset(key) {
|
|
469
472
|
const diatonic = DIATONIC_MODE_OFFSETS.get(key.modeMask12);
|
|
470
473
|
if (diatonic !== void 0) {
|
|
@@ -1097,7 +1100,7 @@ function chordSpecQuality(spec) {
|
|
|
1097
1100
|
}
|
|
1098
1101
|
return nearest ?? BASE_QUALITY[checked.base];
|
|
1099
1102
|
}
|
|
1100
|
-
var
|
|
1103
|
+
var EXTENSION_ENTRIES = [
|
|
1101
1104
|
[13, { degree: 9, alter: -1 }],
|
|
1102
1105
|
[14, { degree: 9, alter: 0 }],
|
|
1103
1106
|
[15, { degree: 9, alter: 1 }],
|
|
@@ -1107,7 +1110,8 @@ var EXTENSION_BY_SEMITONE = /* @__PURE__ */ new Map([
|
|
|
1107
1110
|
[20, { degree: 13, alter: -1 }],
|
|
1108
1111
|
[21, { degree: 13, alter: 0 }],
|
|
1109
1112
|
[22, { degree: 13, alter: 1 }]
|
|
1110
|
-
]
|
|
1113
|
+
];
|
|
1114
|
+
var EXTENSION_BY_SEMITONE = new Map(EXTENSION_ENTRIES);
|
|
1111
1115
|
function sameOffsets(a, b) {
|
|
1112
1116
|
return a.length === b.length && a.every((offset, index) => offset === b[index]);
|
|
1113
1117
|
}
|
|
@@ -1172,6 +1176,9 @@ function chordSpecFromIntervals(intervals) {
|
|
|
1172
1176
|
const normalized = normalizeChordSpec(spec);
|
|
1173
1177
|
return sameOffsets(specIntervals(normalized), offsets) ? normalized : void 0;
|
|
1174
1178
|
}
|
|
1179
|
+
var ALTERABLE_DEGREES = [5, 9, 11, 13];
|
|
1180
|
+
var ALTERATION_STEPS = [-1, 0, 1];
|
|
1181
|
+
var ADDABLE_DEGREES = [6, 9, 11, 13];
|
|
1175
1182
|
function assertPart(value, allowed, name) {
|
|
1176
1183
|
if (!allowed.includes(value)) {
|
|
1177
1184
|
throw new InvalidInputError(
|
|
@@ -1190,7 +1197,7 @@ function assertDegreeIn(value, allowed, name) {
|
|
|
1190
1197
|
}
|
|
1191
1198
|
function assertDegreeList(value, allowed, name) {
|
|
1192
1199
|
if (!Array.isArray(value)) {
|
|
1193
|
-
throw new InvalidInputError(`${name} must be an array; received ${
|
|
1200
|
+
throw new InvalidInputError(`${name} must be an array; received ${describeRejected(value)}`);
|
|
1194
1201
|
}
|
|
1195
1202
|
for (const degree of value) {
|
|
1196
1203
|
assertDegreeIn(degree, allowed, name);
|
|
@@ -1198,7 +1205,7 @@ function assertDegreeList(value, allowed, name) {
|
|
|
1198
1205
|
}
|
|
1199
1206
|
function assertChordSpec(spec) {
|
|
1200
1207
|
if (spec === null || typeof spec !== "object") {
|
|
1201
|
-
throw new InvalidInputError(`chord spec must be an object; received ${
|
|
1208
|
+
throw new InvalidInputError(`chord spec must be an object; received ${describeRejected(spec)}`);
|
|
1202
1209
|
}
|
|
1203
1210
|
assertFiniteNumber(spec.rootPc, "chord spec rootPc");
|
|
1204
1211
|
if (spec.bassPc !== void 0) {
|
|
@@ -1216,10 +1223,10 @@ function assertChordSpec(spec) {
|
|
|
1216
1223
|
throw new InvalidInputError("chord spec alterations must be an array");
|
|
1217
1224
|
}
|
|
1218
1225
|
for (const alteration of spec.alterations) {
|
|
1219
|
-
assertDegreeIn(alteration?.degree,
|
|
1220
|
-
assertDegreeIn(alteration.alter,
|
|
1226
|
+
assertDegreeIn(alteration?.degree, ALTERABLE_DEGREES, "chord spec alteration degree");
|
|
1227
|
+
assertDegreeIn(alteration.alter, ALTERATION_STEPS, "chord spec alteration");
|
|
1221
1228
|
}
|
|
1222
|
-
assertDegreeList(spec.additions,
|
|
1229
|
+
assertDegreeList(spec.additions, ADDABLE_DEGREES, "chord spec additions");
|
|
1223
1230
|
assertDegreeList(spec.omissions, OMITTABLE_DEGREES, "chord spec omissions");
|
|
1224
1231
|
return normalizeChordSpec(spec);
|
|
1225
1232
|
}
|
|
@@ -1230,7 +1237,7 @@ function chordQualities() {
|
|
|
1230
1237
|
return [...QUALITY_ORDER];
|
|
1231
1238
|
}
|
|
1232
1239
|
function assertChordQuality(quality) {
|
|
1233
|
-
if (!Object.hasOwn(QUALITY_INTERVALS, quality)) {
|
|
1240
|
+
if (typeof quality !== "string" || !Object.hasOwn(QUALITY_INTERVALS, quality)) {
|
|
1234
1241
|
throw new InvalidInputError(`Unknown chord quality: ${String(quality)}`);
|
|
1235
1242
|
}
|
|
1236
1243
|
return quality;
|
|
@@ -1244,17 +1251,20 @@ function assertChord(chord, name = "chord") {
|
|
|
1244
1251
|
function chordFromDegree(degree, ext, key) {
|
|
1245
1252
|
assertDegree(degree, "chord degree");
|
|
1246
1253
|
assertChordQuality(ext);
|
|
1247
|
-
const
|
|
1248
|
-
const tones = scaleTonesInDegreeOrder(scale);
|
|
1254
|
+
const resolved = resolveKey(key);
|
|
1255
|
+
const tones = scaleTonesInDegreeOrder(resolved.scale);
|
|
1249
1256
|
const length = tones.length;
|
|
1250
1257
|
const index = length > 0 ? (degree - 1) % length : 0;
|
|
1251
|
-
const rootPc = tones[index] ?? pitchClassOf(scale.rootPc);
|
|
1252
|
-
return
|
|
1258
|
+
const rootPc = tones[index] ?? pitchClassOf(resolved.scale.rootPc);
|
|
1259
|
+
return makeSpelledChord(rootPc, ext, { rootSpelling: keySpelling(rootPc, resolved) });
|
|
1253
1260
|
}
|
|
1254
1261
|
function makeChord(rootPc, quality, bassPc) {
|
|
1262
|
+
return makeSpelledChord(rootPc, quality, { bassPc });
|
|
1263
|
+
}
|
|
1264
|
+
function makeSpelledChord(rootPc, quality, parts2 = {}) {
|
|
1255
1265
|
assertFiniteNumber(rootPc, "chord rootPc");
|
|
1256
|
-
if (bassPc !== void 0) {
|
|
1257
|
-
assertFiniteNumber(bassPc, "chord bassPc");
|
|
1266
|
+
if (parts2.bassPc !== void 0) {
|
|
1267
|
+
assertFiniteNumber(parts2.bassPc, "chord bassPc");
|
|
1258
1268
|
}
|
|
1259
1269
|
assertChordQuality(quality);
|
|
1260
1270
|
const chord = {
|
|
@@ -1262,11 +1272,32 @@ function makeChord(rootPc, quality, bassPc) {
|
|
|
1262
1272
|
quality,
|
|
1263
1273
|
intervals: [...QUALITY_INTERVALS[quality] ?? []]
|
|
1264
1274
|
};
|
|
1265
|
-
if (bassPc !== void 0) {
|
|
1266
|
-
chord.bassPc = pitchClassOf(bassPc);
|
|
1275
|
+
if (parts2.bassPc !== void 0) {
|
|
1276
|
+
chord.bassPc = pitchClassOf(parts2.bassPc);
|
|
1277
|
+
}
|
|
1278
|
+
if (parts2.rootSpelling !== void 0) {
|
|
1279
|
+
chord.rootSpelling = { letter: parts2.rootSpelling.letter, alter: parts2.rootSpelling.alter };
|
|
1280
|
+
}
|
|
1281
|
+
if (parts2.bassSpelling !== void 0) {
|
|
1282
|
+
chord.bassSpelling = { letter: parts2.bassSpelling.letter, alter: parts2.bassSpelling.alter };
|
|
1283
|
+
} else if (chord.rootSpelling !== void 0 && chord.bassPc !== void 0) {
|
|
1284
|
+
const index = chord.intervals.findIndex(
|
|
1285
|
+
(interval) => pitchClassOf(chord.rootPc + interval) === chord.bassPc
|
|
1286
|
+
);
|
|
1287
|
+
const tone = index >= 0 ? spellChordFromRoot(chord, chord.rootSpelling)[index] : void 0;
|
|
1288
|
+
if (tone !== void 0) {
|
|
1289
|
+
chord.bassSpelling = { letter: tone.letter, alter: tone.alter };
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
if (parts2.toneSpellings !== void 0) {
|
|
1293
|
+
chord.toneSpellings = parts2.toneSpellings.map(({ letter, alter }) => ({ letter, alter }));
|
|
1267
1294
|
}
|
|
1268
1295
|
return chord;
|
|
1269
1296
|
}
|
|
1297
|
+
function keySpelling(pc, key) {
|
|
1298
|
+
const { letter, alter } = spellPitchClass(pc, key.tonic, key.scale);
|
|
1299
|
+
return { letter, alter };
|
|
1300
|
+
}
|
|
1270
1301
|
function chordFromSpec(spec) {
|
|
1271
1302
|
const checked = assertChordSpec(spec);
|
|
1272
1303
|
const chord = {
|
|
@@ -1298,7 +1329,9 @@ function chordSpecOf(chord) {
|
|
|
1298
1329
|
function copySpanIntervals(intervals) {
|
|
1299
1330
|
const name = "chord span intervals";
|
|
1300
1331
|
if (!Array.isArray(intervals)) {
|
|
1301
|
-
throw new InvalidInputError(
|
|
1332
|
+
throw new InvalidInputError(
|
|
1333
|
+
`${name} must be an array; received ${describeRejected(intervals)}`
|
|
1334
|
+
);
|
|
1302
1335
|
}
|
|
1303
1336
|
if (intervals.length === 0) {
|
|
1304
1337
|
throw new InvalidInputError(`${name} must name at least one interval`);
|
|
@@ -1322,7 +1355,7 @@ function hasCustomIntervals(chord) {
|
|
|
1322
1355
|
}
|
|
1323
1356
|
function chordFromSpan(span) {
|
|
1324
1357
|
assertRecord(span, "chord span");
|
|
1325
|
-
const chord =
|
|
1358
|
+
const chord = makeSpelledChord(span.rootPc, span.quality, { bassPc: span.bassPc });
|
|
1326
1359
|
if (span.intervals !== void 0) {
|
|
1327
1360
|
chord.intervals = copySpanIntervals(span.intervals);
|
|
1328
1361
|
}
|
|
@@ -1558,8 +1591,9 @@ function matchesQualityIntervals(quality, intervals) {
|
|
|
1558
1591
|
const template = QUALITY_INTERVALS[quality];
|
|
1559
1592
|
return template.length === intervals.length && template.every((interval, index) => interval === intervals[index]);
|
|
1560
1593
|
}
|
|
1561
|
-
function stackThirds(degree,
|
|
1594
|
+
function stackThirds(degree, resolved, size) {
|
|
1562
1595
|
assertDegree(degree, "chord degree");
|
|
1596
|
+
const key = resolved.scale;
|
|
1563
1597
|
const tones = scaleTonesInDegreeOrder(key);
|
|
1564
1598
|
const length = tones.length;
|
|
1565
1599
|
if (length !== 7) {
|
|
@@ -1581,13 +1615,13 @@ function stackThirds(degree, key, size) {
|
|
|
1581
1615
|
`scale thirds at degree ${degree} produce unsupported intervals [${offsets.join(", ")}]`
|
|
1582
1616
|
);
|
|
1583
1617
|
}
|
|
1584
|
-
return
|
|
1618
|
+
return makeSpelledChord(rootPc, quality, { rootSpelling: keySpelling(rootPc, resolved) });
|
|
1585
1619
|
}
|
|
1586
1620
|
function diatonicTriad(degree, key) {
|
|
1587
|
-
return stackThirds(degree,
|
|
1621
|
+
return stackThirds(degree, resolveKey(key), 3);
|
|
1588
1622
|
}
|
|
1589
1623
|
function diatonicSeventh(degree, key) {
|
|
1590
|
-
return stackThirds(degree,
|
|
1624
|
+
return stackThirds(degree, resolveKey(key), 4);
|
|
1591
1625
|
}
|
|
1592
1626
|
|
|
1593
1627
|
// src/theory/spelling/index.ts
|
|
@@ -1686,7 +1720,8 @@ function capChromaticAccidentals(preferred, alternative) {
|
|
|
1686
1720
|
var DIATONIC_LETTER_COUNT = 7;
|
|
1687
1721
|
var MAX_JOINT_TONE_COUNT = DIATONIC_LETTER_COUNT + 1;
|
|
1688
1722
|
var MAJOR_SEMITONES = [0, 2, 4, 5, 7, 9, 11];
|
|
1689
|
-
var
|
|
1723
|
+
var IMPERFECT_DEGREE_LIST = [1, 2, 5, 6];
|
|
1724
|
+
var IMPERFECT_DEGREES = new Set(IMPERFECT_DEGREE_LIST);
|
|
1690
1725
|
var DIATONIC_MODE_OFFSETS2 = MAJOR_SEMITONES.map(
|
|
1691
1726
|
(tonic, mode) => MAJOR_SEMITONES.map((_, degree) => pitchClassOf((MAJOR_SEMITONES[(mode + degree) % 7] ?? 0) - tonic))
|
|
1692
1727
|
);
|
|
@@ -1869,9 +1904,10 @@ function spellByKey(pc, tonic, key) {
|
|
|
1869
1904
|
return preferred;
|
|
1870
1905
|
}
|
|
1871
1906
|
}
|
|
1872
|
-
const belowLetter = diatonicLetterOf([
|
|
1907
|
+
const belowLetter = diatonicLetterOf(LETTER_BELOW_PITCH_CLASS[pitchClassOf(pc)] ?? 0);
|
|
1873
1908
|
return { letter: belowLetter, alter: alterFor(belowLetter, pc) };
|
|
1874
1909
|
}
|
|
1910
|
+
var LETTER_BELOW_PITCH_CLASS = [0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6];
|
|
1875
1911
|
var CHORD_TONE_LETTER_STEPS = {
|
|
1876
1912
|
0: 0,
|
|
1877
1913
|
// root
|
|
@@ -1926,10 +1962,10 @@ function neighbourSpelling(neighbour, gap, letterStep, pc, tonic, key) {
|
|
|
1926
1962
|
}
|
|
1927
1963
|
return letterFor(spellByKey(pitchClassOf(neighbour), tonic, key), letterStep, pc);
|
|
1928
1964
|
}
|
|
1929
|
-
function refineByContext(pc, tonic, key, context,
|
|
1965
|
+
function refineByContext(pc, tonic, key, context, keySpelling2) {
|
|
1930
1966
|
const tonicPc = pitchClassOf(naturalPitchClassOf(tonic.letter) + tonic.alter);
|
|
1931
1967
|
if (pitchClassOf(pc) === tonicPc || isScaleTone(pc, key)) {
|
|
1932
|
-
return
|
|
1968
|
+
return keySpelling2;
|
|
1933
1969
|
}
|
|
1934
1970
|
const { previous, next } = context;
|
|
1935
1971
|
const candidates = [
|
|
@@ -1952,7 +1988,7 @@ function refineByContext(pc, tonic, key, context, keySpelling) {
|
|
|
1952
1988
|
return candidate;
|
|
1953
1989
|
}
|
|
1954
1990
|
}
|
|
1955
|
-
return
|
|
1991
|
+
return keySpelling2;
|
|
1956
1992
|
}
|
|
1957
1993
|
function spellPitchClass(pc, tonic, key, context) {
|
|
1958
1994
|
const note = toNoteData(tonic);
|
|
@@ -1962,8 +1998,8 @@ function spellPitchClass(pc, tonic, key, context) {
|
|
|
1962
1998
|
return spelledPitchClass(pc, note, scale, context);
|
|
1963
1999
|
}
|
|
1964
2000
|
function spelledPitchClass(pc, tonic, key, context) {
|
|
1965
|
-
const
|
|
1966
|
-
return context === void 0 ?
|
|
2001
|
+
const keySpelling2 = spellByKey(pc, tonic, key);
|
|
2002
|
+
return context === void 0 ? keySpelling2 : refineByContext(pc, tonic, key, context, keySpelling2);
|
|
1967
2003
|
}
|
|
1968
2004
|
function spellScale(tonic, key) {
|
|
1969
2005
|
const note = toNoteData(tonic);
|
|
@@ -1980,6 +2016,7 @@ function spellPitchClasses(pcs, tonic, key) {
|
|
|
1980
2016
|
(pc, index) => spelledPitchClass(assertPitchClass(pc, `pcs[${index}]`), note, scale)
|
|
1981
2017
|
);
|
|
1982
2018
|
}
|
|
2019
|
+
var SIMPLE_LETTER_OFFSETS = [0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6];
|
|
1983
2020
|
function chordLetterOffset(interval, chord) {
|
|
1984
2021
|
switch (interval) {
|
|
1985
2022
|
case 0:
|
|
@@ -1994,7 +2031,7 @@ function chordLetterOffset(interval, chord) {
|
|
|
1994
2031
|
case 4:
|
|
1995
2032
|
return 2;
|
|
1996
2033
|
case 15:
|
|
1997
|
-
return
|
|
2034
|
+
return 1;
|
|
1998
2035
|
case 5:
|
|
1999
2036
|
case 16:
|
|
2000
2037
|
case 17:
|
|
@@ -2018,7 +2055,7 @@ function chordLetterOffset(interval, chord) {
|
|
|
2018
2055
|
default: {
|
|
2019
2056
|
const octaves = Math.floor(Math.max(0, interval) / 12);
|
|
2020
2057
|
const simple = pitchClassOf(interval);
|
|
2021
|
-
const simpleOffset = [
|
|
2058
|
+
const simpleOffset = SIMPLE_LETTER_OFFSETS[simple] ?? 0;
|
|
2022
2059
|
return octaves * 7 + simpleOffset;
|
|
2023
2060
|
}
|
|
2024
2061
|
}
|
|
@@ -2527,17 +2564,21 @@ function assertSafetyContext(q) {
|
|
|
2527
2564
|
throw new InvalidInputError("vocalLow must not exceed vocalHigh");
|
|
2528
2565
|
}
|
|
2529
2566
|
if (!Array.isArray(q.otherVoices)) {
|
|
2530
|
-
throw new InvalidInputError(
|
|
2567
|
+
throw new InvalidInputError(
|
|
2568
|
+
`otherVoices must be an array; received ${describeRejected(q.otherVoices)}`
|
|
2569
|
+
);
|
|
2531
2570
|
}
|
|
2532
2571
|
assertGenerationBudget(q.otherVoices.length, "other voices");
|
|
2533
2572
|
for (let index = 0; index < q.otherVoices.length; index += 1) {
|
|
2534
|
-
const voice = q.otherVoices[index];
|
|
2535
|
-
if (!voice) continue;
|
|
2573
|
+
const voice = assertRecord(q.otherVoices[index], `otherVoices[${index}]`);
|
|
2536
2574
|
assertMidiPitch(voice.pitch, `otherVoices[${index}].pitch`);
|
|
2537
2575
|
if (voice.prevPitch !== void 0) {
|
|
2538
2576
|
assertMidiPitch(voice.prevPitch, `otherVoices[${index}].prevPitch`);
|
|
2539
2577
|
}
|
|
2540
2578
|
}
|
|
2579
|
+
if (q.chord !== null) {
|
|
2580
|
+
assertRecord(q.chord, "chord");
|
|
2581
|
+
}
|
|
2541
2582
|
}
|
|
2542
2583
|
function evaluateInternal(q, collectSuggestions, collectPartners) {
|
|
2543
2584
|
let reasons = 0;
|
|
@@ -2925,6 +2966,19 @@ var ADDED_DEGREES = {
|
|
|
2925
2966
|
};
|
|
2926
2967
|
var ALTERABLE = { "5": 5, "9": 9, "11": 11, "13": 13 };
|
|
2927
2968
|
var OMITTABLE = { "1": 1, "3": 3, "5": 5 };
|
|
2969
|
+
var SUSPENSION_TOKENS = [
|
|
2970
|
+
["sus2", "sus2"],
|
|
2971
|
+
["sus4", "sus4"],
|
|
2972
|
+
["sus", "sus4"]
|
|
2973
|
+
];
|
|
2974
|
+
var OMISSION_TOKENS = [
|
|
2975
|
+
["omit", 4],
|
|
2976
|
+
["no", 2]
|
|
2977
|
+
];
|
|
2978
|
+
var ACCIDENTAL_TOKENS = [
|
|
2979
|
+
["b", -1],
|
|
2980
|
+
["#", 1]
|
|
2981
|
+
];
|
|
2928
2982
|
function alterationKey(degree, alter) {
|
|
2929
2983
|
return `${degree}:${alter}`;
|
|
2930
2984
|
}
|
|
@@ -2984,11 +3038,7 @@ function stackTo(draft, top) {
|
|
|
2984
3038
|
}
|
|
2985
3039
|
}
|
|
2986
3040
|
function applyFigure(draft, text, at) {
|
|
2987
|
-
const base = matchToken(text, at,
|
|
2988
|
-
["sus2", "sus2"],
|
|
2989
|
-
["sus4", "sus4"],
|
|
2990
|
-
["sus", "sus4"]
|
|
2991
|
-
]);
|
|
3041
|
+
const base = matchToken(text, at, SUSPENSION_TOKENS);
|
|
2992
3042
|
if (base !== void 0) {
|
|
2993
3043
|
draft.base = base.value;
|
|
2994
3044
|
return base.next;
|
|
@@ -3007,10 +3057,7 @@ function applyFigure(draft, text, at) {
|
|
|
3007
3057
|
draft.additions.add(degree2.value);
|
|
3008
3058
|
return degree2.next;
|
|
3009
3059
|
}
|
|
3010
|
-
const omitted = matchToken(text, at,
|
|
3011
|
-
["omit", 4],
|
|
3012
|
-
["no", 2]
|
|
3013
|
-
]);
|
|
3060
|
+
const omitted = matchToken(text, at, OMISSION_TOKENS);
|
|
3014
3061
|
if (omitted !== void 0) {
|
|
3015
3062
|
const degree2 = matchNumberToken(text, omitted.next, OMITTABLE);
|
|
3016
3063
|
if (degree2 === void 0) {
|
|
@@ -3019,10 +3066,7 @@ function applyFigure(draft, text, at) {
|
|
|
3019
3066
|
draft.omissions.add(degree2.value);
|
|
3020
3067
|
return degree2.next;
|
|
3021
3068
|
}
|
|
3022
|
-
const accidental = matchToken(text, at,
|
|
3023
|
-
["b", -1],
|
|
3024
|
-
["#", 1]
|
|
3025
|
-
]);
|
|
3069
|
+
const accidental = matchToken(text, at, ACCIDENTAL_TOKENS);
|
|
3026
3070
|
const from = accidental?.next ?? at;
|
|
3027
3071
|
const degree = matchNumberToken(text, from, ALTERABLE);
|
|
3028
3072
|
if (degree === void 0) {
|
|
@@ -3203,7 +3247,7 @@ function bassNote(text, system) {
|
|
|
3203
3247
|
}
|
|
3204
3248
|
return bareNote(text, system);
|
|
3205
3249
|
}
|
|
3206
|
-
function
|
|
3250
|
+
function chordFromSymbolParts(root, spec, bass) {
|
|
3207
3251
|
const rooted = { ...spec, rootPc: noteToPitchClass(root) };
|
|
3208
3252
|
if (bass !== void 0) {
|
|
3209
3253
|
rooted.bassPc = noteToPitchClass(bass);
|
|
@@ -3221,11 +3265,11 @@ function chordAfterRoot(root, rest, system) {
|
|
|
3221
3265
|
const slashSpec = suffixSpec(rest.slice(0, slashIndex));
|
|
3222
3266
|
const bass = slashSpec === void 0 ? void 0 : bassNote(rest.slice(slashIndex + 1), system);
|
|
3223
3267
|
if (slashSpec !== void 0 && bass !== void 0) {
|
|
3224
|
-
return
|
|
3268
|
+
return chordFromSymbolParts(root, slashSpec, bass);
|
|
3225
3269
|
}
|
|
3226
3270
|
}
|
|
3227
3271
|
const spec = suffixSpec(rest);
|
|
3228
|
-
return spec === void 0 ? void 0 :
|
|
3272
|
+
return spec === void 0 ? void 0 : chordFromSymbolParts(root, spec);
|
|
3229
3273
|
}
|
|
3230
3274
|
|
|
3231
3275
|
// src/theory/symbol/suffix.ts
|
|
@@ -3302,7 +3346,11 @@ var BASE_SUFFIX = {
|
|
|
3302
3346
|
sus4: "sus4",
|
|
3303
3347
|
power: "5"
|
|
3304
3348
|
};
|
|
3305
|
-
var SEVENTH_SUFFIX = {
|
|
3349
|
+
var SEVENTH_SUFFIX = {
|
|
3350
|
+
maj7: "maj7",
|
|
3351
|
+
min7: "7",
|
|
3352
|
+
dim7: "dim7"
|
|
3353
|
+
};
|
|
3306
3354
|
var MAJOR_SEVENTH_AFTER_BASE = "Maj7";
|
|
3307
3355
|
function builtCoreSuffix(spec) {
|
|
3308
3356
|
const base = BASE_SUFFIX[spec.base];
|
|
@@ -3421,12 +3469,12 @@ function tryParseChordSymbol(text, opts) {
|
|
|
3421
3469
|
}
|
|
3422
3470
|
function formatChordSymbol(chord, opts) {
|
|
3423
3471
|
const data = toChordData(chord);
|
|
3424
|
-
if (!Object.hasOwn(CANONICAL_SUFFIX, data.quality)) {
|
|
3472
|
+
if (typeof data.quality !== "string" || !Object.hasOwn(CANONICAL_SUFFIX, data.quality)) {
|
|
3425
3473
|
throw new InvalidInputError(`Unknown chord quality: ${String(data.quality)}`);
|
|
3426
3474
|
}
|
|
3427
3475
|
const asked = assertOptions(opts, "opts");
|
|
3428
3476
|
const system = asked.system ?? DEFAULT_SYSTEM;
|
|
3429
|
-
const flats = asked.flats;
|
|
3477
|
+
const flats = symbolFlats(asked.flats);
|
|
3430
3478
|
const rootPc = pitchClassOf(data.rootPc);
|
|
3431
3479
|
const rootHint = hintFor(data.rootSpelling, rootPc);
|
|
3432
3480
|
const rootSpelling = rootSpellingFor(rootPc, rootHint, flats);
|
|
@@ -3441,7 +3489,7 @@ function formatChordSymbol(chord, opts) {
|
|
|
3441
3489
|
(degreeOfInterval(pitchClassOf(bassPc - rootPc), data) ?? 1) - 1,
|
|
3442
3490
|
bassPc
|
|
3443
3491
|
) : void 0;
|
|
3444
|
-
const bassName = rootHint !== void 0 && bassHint !== void 0 ? symbolName(
|
|
3492
|
+
const bassName = flats !== void 0 && rootHint !== void 0 && bassHint !== void 0 ? symbolName(
|
|
3445
3493
|
carriedBass(
|
|
3446
3494
|
bassHint,
|
|
3447
3495
|
rootHint,
|
|
@@ -3455,6 +3503,9 @@ function formatChordSymbol(chord, opts) {
|
|
|
3455
3503
|
}
|
|
3456
3504
|
return symbol;
|
|
3457
3505
|
}
|
|
3506
|
+
function symbolFlats(flats) {
|
|
3507
|
+
return flats === void 0 ? void 0 : assertFlag(flats, "flats");
|
|
3508
|
+
}
|
|
3458
3509
|
function transposeChordSpellings(spellings, semitones, flats) {
|
|
3459
3510
|
const byLetter = (spelling) => spelling === void 0 ? void 0 : bareSpelling(transposeNote(spelling, semitones));
|
|
3460
3511
|
const movedRoot = byLetter(spellings.rootSpelling);
|
|
@@ -3505,7 +3556,7 @@ function transposeChordSymbol(text, semitones, opts) {
|
|
|
3505
3556
|
if (chord.bassPc !== void 0) {
|
|
3506
3557
|
transposed.bassPc = pitchClassOf(chord.bassPc + semitones);
|
|
3507
3558
|
}
|
|
3508
|
-
const spellings = transposeChordSpellings(chord, semitones, opts?.flats);
|
|
3559
|
+
const spellings = transposeChordSpellings(chord, semitones, symbolFlats(opts?.flats));
|
|
3509
3560
|
if (spellings.rootSpelling !== void 0) {
|
|
3510
3561
|
transposed.rootSpelling = spellings.rootSpelling;
|
|
3511
3562
|
}
|
|
@@ -3552,11 +3603,11 @@ function toChordData(value) {
|
|
|
3552
3603
|
return parseChordSymbol(value);
|
|
3553
3604
|
}
|
|
3554
3605
|
if (typeof value === "object" && value !== null) {
|
|
3555
|
-
const data = "toJSON" in value && typeof value.toJSON === "function" ? value.toJSON() : value;
|
|
3606
|
+
const data = "toJSON" in value && typeof value.toJSON === "function" ? "data" in value && typeof value.data === "object" && value.data !== null ? value.data : value.toJSON() : value;
|
|
3556
3607
|
return normalizedChord(data);
|
|
3557
3608
|
}
|
|
3558
3609
|
throw new InvalidInputError(
|
|
3559
|
-
`chord must be a chord symbol or chord data; received ${
|
|
3610
|
+
`chord must be a chord symbol or chord data; received ${describeRejected(value)}`
|
|
3560
3611
|
);
|
|
3561
3612
|
}
|
|
3562
3613
|
|
|
@@ -3567,6 +3618,9 @@ function hasInterval(chord, semitones) {
|
|
|
3567
3618
|
function isDiatonicChord(chord, key) {
|
|
3568
3619
|
return chordPitchClasses(chord).every((pc) => isScaleTone(pc, key));
|
|
3569
3620
|
}
|
|
3621
|
+
function isNativeDominantSeventh(rootPc, key) {
|
|
3622
|
+
return isDiatonicChord(makeChord(rootPc, "dom7"), key);
|
|
3623
|
+
}
|
|
3570
3624
|
function hasMajorThird(chord) {
|
|
3571
3625
|
return hasInterval(chord, 4);
|
|
3572
3626
|
}
|
|
@@ -3627,10 +3681,23 @@ function appliedDominantTarget(rootPc, key) {
|
|
|
3627
3681
|
(degree) => degree.degreeNumber !== 1 && degree.rootPc === target
|
|
3628
3682
|
) ?? null;
|
|
3629
3683
|
}
|
|
3684
|
+
function cadencesThroughRaisedSeventh(key) {
|
|
3685
|
+
return isMinorMask(key.modeMask12) && scaleSystemOf(key) === "common-practice";
|
|
3686
|
+
}
|
|
3630
3687
|
function leadingTonePcOf(key) {
|
|
3631
3688
|
return pitchClassOf(key.rootPc - 1);
|
|
3632
3689
|
}
|
|
3633
|
-
var
|
|
3690
|
+
var LEADING_TONE_QUALITY_NAMES = ["dim", "dim7", "m7b5"];
|
|
3691
|
+
var LEADING_TONE_QUALITIES = new Set(
|
|
3692
|
+
LEADING_TONE_QUALITY_NAMES
|
|
3693
|
+
);
|
|
3694
|
+
function appliedChordTarget(chord, key) {
|
|
3695
|
+
const dominant = hasDominantSonority(chord);
|
|
3696
|
+
if (!dominant && !LEADING_TONE_QUALITIES.has(chord.quality)) {
|
|
3697
|
+
return null;
|
|
3698
|
+
}
|
|
3699
|
+
return appliedDominantTarget(chord.rootPc + (dominant ? 5 : 1), key);
|
|
3700
|
+
}
|
|
3634
3701
|
function soundsDiminishedTriad(chord) {
|
|
3635
3702
|
return hasInterval(chord, 3) && hasInterval(chord, 6) && !hasInterval(chord, 7);
|
|
3636
3703
|
}
|
|
@@ -3757,12 +3824,16 @@ export {
|
|
|
3757
3824
|
scaleSystemOf,
|
|
3758
3825
|
supportsFunctionalHarmony,
|
|
3759
3826
|
chordSpecIntervals,
|
|
3827
|
+
QUALITY_INTERVALS,
|
|
3828
|
+
chordSpecForQuality,
|
|
3760
3829
|
chordSpecQuality,
|
|
3761
3830
|
chordQualities,
|
|
3762
3831
|
assertChordQuality,
|
|
3763
3832
|
assertChord,
|
|
3764
3833
|
chordFromDegree,
|
|
3765
3834
|
makeChord,
|
|
3835
|
+
makeSpelledChord,
|
|
3836
|
+
keySpelling,
|
|
3766
3837
|
chordFromSpec,
|
|
3767
3838
|
chordSpecOf,
|
|
3768
3839
|
chordFromSpan,
|
|
@@ -3800,22 +3871,24 @@ export {
|
|
|
3800
3871
|
evaluateSafety,
|
|
3801
3872
|
enumerateSafePitches,
|
|
3802
3873
|
toChordData,
|
|
3874
|
+
spellingAbove,
|
|
3803
3875
|
parseChordSymbol,
|
|
3804
3876
|
tryParseChordSymbol,
|
|
3805
3877
|
formatChordSymbol,
|
|
3806
3878
|
transposeChordSpellings,
|
|
3807
3879
|
transposeChordSymbol,
|
|
3808
3880
|
isDiatonicChord,
|
|
3881
|
+
isNativeDominantSeventh,
|
|
3809
3882
|
hasMajorThird,
|
|
3810
3883
|
soundsDominantSeventh,
|
|
3811
|
-
hasDominantSonority,
|
|
3812
3884
|
isDominantChordOf,
|
|
3813
3885
|
isNeapolitanChordOf,
|
|
3814
3886
|
heptatonicFrameOf,
|
|
3815
3887
|
tonicizableDegrees,
|
|
3816
|
-
|
|
3888
|
+
cadencesThroughRaisedSeventh,
|
|
3817
3889
|
leadingTonePcOf,
|
|
3818
3890
|
LEADING_TONE_QUALITIES,
|
|
3891
|
+
appliedChordTarget,
|
|
3819
3892
|
isLeadingToneChordOf,
|
|
3820
3893
|
isFunctioningLeadingTone,
|
|
3821
3894
|
seventhPcOf,
|
|
@@ -3823,4 +3896,4 @@ export {
|
|
|
3823
3896
|
isDescendingStep,
|
|
3824
3897
|
isFrustratedLeadingTone
|
|
3825
3898
|
};
|
|
3826
|
-
//# sourceMappingURL=chunk-
|
|
3899
|
+
//# sourceMappingURL=chunk-H7FVMBUC.js.map
|