@libraz/libcantus 0.9.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -261
- package/README_ja.md +115 -0
- package/dist/analyze/index.cjs +54 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +213 -456
- package/dist/analyze/index.d.ts +213 -456
- package/dist/analyze/index.js +56 -9
- package/dist/chunk-3JXCW6DX.cjs +3220 -0
- package/dist/chunk-3JXCW6DX.cjs.map +1 -0
- package/dist/chunk-4A2RMUCC.js +7647 -0
- package/dist/chunk-4A2RMUCC.js.map +1 -0
- package/dist/chunk-6XPTBE7Y.cjs +49 -0
- package/dist/chunk-6XPTBE7Y.cjs.map +1 -0
- package/dist/chunk-AFM2ULJH.cjs +5121 -0
- package/dist/chunk-AFM2ULJH.cjs.map +1 -0
- package/dist/chunk-E3F4AHAH.cjs +690 -0
- package/dist/chunk-E3F4AHAH.cjs.map +1 -0
- package/dist/chunk-ELCTZUJJ.js +379 -0
- package/dist/chunk-ELCTZUJJ.js.map +1 -0
- package/dist/chunk-FVSI36UV.js +690 -0
- package/dist/chunk-FVSI36UV.js.map +1 -0
- package/dist/chunk-GEDTJHAC.cjs +1 -0
- package/dist/chunk-GEDTJHAC.cjs.map +1 -0
- package/dist/chunk-GOZG57ER.js +3220 -0
- package/dist/chunk-GOZG57ER.js.map +1 -0
- package/dist/chunk-H3VORETI.js +2243 -0
- package/dist/chunk-H3VORETI.js.map +1 -0
- package/dist/chunk-H42UHPYW.js +1577 -0
- package/dist/chunk-H42UHPYW.js.map +1 -0
- package/dist/chunk-HFPS7JFD.js +1 -0
- package/dist/chunk-INHVXP6Z.js +3053 -0
- package/dist/chunk-INHVXP6Z.js.map +1 -0
- package/dist/chunk-K4ZJUGF4.cjs +379 -0
- package/dist/chunk-K4ZJUGF4.cjs.map +1 -0
- package/dist/chunk-KNJEKLKV.js +49 -0
- package/dist/chunk-KNJEKLKV.js.map +1 -0
- package/dist/chunk-M4CWTJWJ.cjs +7647 -0
- package/dist/chunk-M4CWTJWJ.cjs.map +1 -0
- package/dist/chunk-MXO72PLY.cjs +211 -0
- package/dist/chunk-MXO72PLY.cjs.map +1 -0
- package/dist/chunk-NLEU4QSE.cjs +360 -0
- package/dist/chunk-NLEU4QSE.cjs.map +1 -0
- package/dist/chunk-OE6WK2Y2.cjs +1577 -0
- package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
- package/dist/chunk-Q2WGKJNN.cjs +1064 -0
- package/dist/chunk-Q2WGKJNN.cjs.map +1 -0
- package/dist/chunk-QYQQ5J6E.js +1 -0
- package/dist/chunk-QYQQ5J6E.js.map +1 -0
- package/dist/chunk-RHIJ3S4I.cjs +1 -0
- package/dist/chunk-RHIJ3S4I.cjs.map +1 -0
- package/dist/chunk-TTCLJX6D.js +211 -0
- package/dist/chunk-TTCLJX6D.js.map +1 -0
- package/dist/chunk-UADYAYAT.cjs +3053 -0
- package/dist/chunk-UADYAYAT.cjs.map +1 -0
- package/dist/chunk-VOHZB45S.js +5121 -0
- package/dist/chunk-VOHZB45S.js.map +1 -0
- package/dist/chunk-VTI6FOLB.js +1064 -0
- package/dist/chunk-VTI6FOLB.js.map +1 -0
- package/dist/chunk-WWURE4XT.cjs +2243 -0
- package/dist/chunk-WWURE4XT.cjs.map +1 -0
- package/dist/chunk-YH3BIKHH.js +360 -0
- package/dist/chunk-YH3BIKHH.js.map +1 -0
- package/dist/core/index.cjs +103 -6
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +96 -345
- package/dist/core/index.d.ts +96 -345
- package/dist/core/index.js +104 -7
- package/dist/generate/index.cjs +89 -10
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +437 -1095
- package/dist/generate/index.d.ts +437 -1095
- package/dist/generate/index.js +94 -15
- package/dist/index-9wcMhG73.d.ts +1095 -0
- package/dist/{index-D6b6na69.d.cts → index-B4o55NDr.d.cts} +13 -9
- package/dist/index-B9MNZboQ.d.cts +770 -0
- package/dist/index-B9MNZboQ.d.ts +770 -0
- package/dist/index-BGFW-8P2.d.cts +2307 -0
- package/dist/index-BO6xE9YU.d.cts +1804 -0
- package/dist/index-BkGmlyI3.d.cts +470 -0
- package/dist/index-CCNJRG-P.d.cts +1095 -0
- package/dist/index-CGpRv5sl.d.cts +643 -0
- package/dist/index-C_8o--VE.d.cts +1242 -0
- package/dist/index-CgHqxdps.d.ts +2307 -0
- package/dist/index-Chbst3Jx.d.ts +1343 -0
- package/dist/index-Cj49F892.d.ts +470 -0
- package/dist/{index-tSQh-xwY.d.ts → index-CunYKLiu.d.ts} +13 -9
- package/dist/index-D57QRbVn.d.ts +1804 -0
- package/dist/index-DInQqT8Q.d.cts +66 -0
- package/dist/index-DInQqT8Q.d.ts +66 -0
- package/dist/index-Dzr13q3d.d.cts +1343 -0
- package/dist/index-G1uwGGWQ.d.ts +643 -0
- package/dist/index-szBv3496.d.ts +1242 -0
- package/dist/index.cjs +358 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -15
- package/dist/index.d.ts +17 -15
- package/dist/index.js +407 -64
- package/dist/masks-DYbE485J.d.cts +445 -0
- package/dist/masks-DYbE485J.d.ts +445 -0
- package/dist/model/index.cjs +39 -7
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +4685 -243
- package/dist/model/index.d.ts +4685 -243
- package/dist/model/index.js +40 -8
- package/dist/positional-Cptlj-xs.d.ts +287 -0
- package/dist/positional-DvH_sd8u.d.cts +287 -0
- package/dist/theory/index.cjs +101 -7
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +513 -173
- package/dist/theory/index.d.ts +513 -173
- package/dist/theory/index.js +118 -24
- package/package.json +16 -11
- package/dist/chunk-36N73KZ3.cjs +0 -246
- package/dist/chunk-36N73KZ3.cjs.map +0 -1
- package/dist/chunk-4HLLZPXT.cjs +0 -3077
- package/dist/chunk-4HLLZPXT.cjs.map +0 -1
- package/dist/chunk-7MGZ7D62.cjs +0 -498
- package/dist/chunk-7MGZ7D62.cjs.map +0 -1
- package/dist/chunk-7NKDPF74.js +0 -3077
- package/dist/chunk-7NKDPF74.js.map +0 -1
- package/dist/chunk-CAN76NCU.cjs +0 -679
- package/dist/chunk-CAN76NCU.cjs.map +0 -1
- package/dist/chunk-D2FAJBYL.js +0 -479
- package/dist/chunk-D2FAJBYL.js.map +0 -1
- package/dist/chunk-EHVEBWM5.js +0 -1449
- package/dist/chunk-EHVEBWM5.js.map +0 -1
- package/dist/chunk-FCANXBAT.cjs +0 -30
- package/dist/chunk-FCANXBAT.cjs.map +0 -1
- package/dist/chunk-FNDWXRRI.cjs +0 -479
- package/dist/chunk-FNDWXRRI.cjs.map +0 -1
- package/dist/chunk-GQSGS2N4.js +0 -173
- package/dist/chunk-GQSGS2N4.js.map +0 -1
- package/dist/chunk-HKGYCQ34.js +0 -53
- package/dist/chunk-HKGYCQ34.js.map +0 -1
- package/dist/chunk-I24MV65U.js +0 -106
- package/dist/chunk-I24MV65U.js.map +0 -1
- package/dist/chunk-KMHOICIY.js +0 -679
- package/dist/chunk-KMHOICIY.js.map +0 -1
- package/dist/chunk-LW53AHQU.cjs +0 -1117
- package/dist/chunk-LW53AHQU.cjs.map +0 -1
- package/dist/chunk-N6IHQUOX.js +0 -1
- package/dist/chunk-NKIBQ6PT.js +0 -30
- package/dist/chunk-NKIBQ6PT.js.map +0 -1
- package/dist/chunk-NP4NA2FB.cjs +0 -106
- package/dist/chunk-NP4NA2FB.cjs.map +0 -1
- package/dist/chunk-NVE34YGZ.cjs +0 -1449
- package/dist/chunk-NVE34YGZ.cjs.map +0 -1
- package/dist/chunk-NYYWMV2C.js +0 -327
- package/dist/chunk-NYYWMV2C.js.map +0 -1
- package/dist/chunk-Q2XUP227.js +0 -845
- package/dist/chunk-Q2XUP227.js.map +0 -1
- package/dist/chunk-Q6OP4U43.cjs +0 -327
- package/dist/chunk-Q6OP4U43.cjs.map +0 -1
- package/dist/chunk-RC6GBMCD.cjs +0 -845
- package/dist/chunk-RC6GBMCD.cjs.map +0 -1
- package/dist/chunk-RK35RIN7.js +0 -1117
- package/dist/chunk-RK35RIN7.js.map +0 -1
- package/dist/chunk-RUMU3UA6.cjs +0 -53
- package/dist/chunk-RUMU3UA6.cjs.map +0 -1
- package/dist/chunk-T64C7ZD7.cjs +0 -1
- package/dist/chunk-T64C7ZD7.cjs.map +0 -1
- package/dist/chunk-XEBG3G53.js +0 -498
- package/dist/chunk-XEBG3G53.js.map +0 -1
- package/dist/chunk-YLEMGEFH.js +0 -246
- package/dist/chunk-YLEMGEFH.js.map +0 -1
- package/dist/chunk-ZEJR4TKL.cjs +0 -173
- package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
- package/dist/function-BtiZb9i9.d.ts +0 -208
- package/dist/function-DNugAOrt.d.cts +0 -208
- package/dist/index-6VR8-kit.d.ts +0 -143
- package/dist/index-70p168VM.d.ts +0 -192
- package/dist/index-Be74mcon.d.cts +0 -152
- package/dist/index-BtXT6UQ0.d.cts +0 -192
- package/dist/index-C5UBbQ4G.d.ts +0 -152
- package/dist/index-C83mZI1P.d.ts +0 -242
- package/dist/index-DXd9JikN.d.cts +0 -246
- package/dist/index-DXd9JikN.d.ts +0 -246
- package/dist/index-OG65ocOr.d.cts +0 -272
- package/dist/index-OG65ocOr.d.ts +0 -272
- package/dist/index-tJhkmQgE.d.cts +0 -143
- package/dist/index-y_ak9_Hi.d.cts +0 -242
- package/dist/styled-DIRkk9Uz.d.ts +0 -506
- package/dist/styled-DJbkJQfj.d.cts +0 -506
- package/dist/types-BN6_Q9Kl.d.cts +0 -39
- package/dist/types-BN6_Q9Kl.d.ts +0 -39
- /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/libcantus/libcantus/dist/chunk-CAN76NCU.cjs","../src/analyze/detect/index.ts","../src/analyze/functional/internal.ts","../src/analyze/functional/roman.ts","../src/analyze/functional/borrowed.ts","../src/analyze/functional/function.ts","../src/analyze/functional/cadence.ts"],"names":[],"mappings":"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AAC5B;AAgB2B;AACA,EAAA;AAChB,IAAA;AACT,EAAA;AACmB,EAAA;AACC,EAAA;AACG,EAAA;AACG,IAAA;AAC1B,EAAA;AACO,EAAA;AACT;AA2ByC;AACd,EAAA;AAC3B;AAYqD;AAC5C,EAAA;AACS,IAAA;AACS,IAAA;AACzB,EAAA;AACF;AAGS;AACY,EAAA;AACrB;AAGuB;AACE,EAAA;AACzB;AAsB6B;AACZ,EAAA;AACR,EAAA;AACgB,IAAA;AACA,IAAA;AACrB,IAAA;AACoB,IAAA;AACtB,EAAA;AACF;AAWkC;AAGlB,EAAA;AACK,EAAA;AACF,EAAA;AACnB;AL+Z4B;AACA;AMrlBE;AACd,EAAA;AACK,EAAA;AACF,EAAA;AAIQ,EAAA;AACD,EAAA;AACf,IAAA;AACT,EAAA;AACwB,EAAA;AACf,IAAA;AACT,EAAA;AACwB,EAAA;AACf,IAAA;AACT,EAAA;AAGsB,EAAA;AACb,IAAA;AACT,EAAA;AACO,EAAA;AACT;ANklB4B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/libcantus/libcantus/dist/chunk-CAN76NCU.cjs","sourcesContent":[null,"/**\n * Recognition: infer a chord name from a set of pitches, or a key from a set of\n * pitch classes. This is the inverse direction of the chord/scale builders,\n * which only go name -> notes.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\nimport type { KeyScale, NoteEvent } from '../../core/types.js';\nimport { assertFiniteNumber, assertGenerationBudget } from '../../core/validation/index.js';\nimport type { Chord, ChordQuality } from '../../theory/chord/index.js';\nimport { chordPitchClasses, chordQualities, makeChord } from '../../theory/chord/index.js';\nimport {\n HARMONIC_MINOR_MASK,\n MAJOR_MASK,\n MELODIC_MINOR_MASK,\n NATURAL_MINOR_MASK,\n} from '../../theory/scale/index.js';\n\n/**\n * A candidate chord interpretation of a pitch set.\n *\n * @category Recognition\n */\nexport type ChordMatch = {\n rootPc: number;\n quality: ChordQuality;\n /** Chord tones absent from the input (an incomplete voicing). */\n missingPcs: number[];\n /** Input pitch classes not belonging to the chord. */\n extraPcs: number[];\n /** True when the input pitch-class set equals the chord exactly. */\n exact: boolean;\n /**\n * Inversion implied by a known bass: 0 for root position, 1..n for an\n * inversion. Null when no inversion can be named — either the input is an\n * unordered pitch-class set with no bass, or the bass is not a chord tone (a\n * pedal or passing bass), in which case `bassPc` still reports it.\n */\n inversion: number | null;\n /** Bass pitch class when the lowest note is not the root. */\n bassPc?: number;\n};\n\n/**\n * Input interpretation for {@link detectChord} and {@link detectChordBest}.\n *\n * @category Recognition\n */\nexport type DetectChordOptions = {\n /**\n * `midi` uses the numerically lowest pitch as bass; `pitchClass` treats the\n * input as unordered. `auto` (default) selects pitch-class mode only when all\n * values lie in 0..11.\n */\n input?: 'auto' | 'midi' | 'pitchClass';\n /** Explicit bass pitch class, including for an unordered pitch-class set. */\n bassPc?: number;\n};\n\n/**\n * A candidate key interpretation of a pitch-class set.\n *\n * @category Recognition\n */\nexport type KeyMatch = {\n /** The scale that scored best for this tonic and mode, `variant` included. */\n key: KeyScale;\n mode: 'major' | 'minor';\n /** Which scale form `key` uses; minor keys pick the best-scoring of the three. */\n variant: KeyVariant;\n /**\n * Fraction of the distinct input pitch classes that belong to `key`, in\n * [0, 1]. Measured against the returned scale, so it always agrees with\n * `isScaleTone(pc, match.key)`. This is a coverage figure, not the ranking:\n * see `score`.\n */\n fit: number;\n /**\n * The value the results are ranked by, in [0, 1.5]. Unlike `fit` it counts\n * every occurrence rather than every distinct pitch class, so a repeated tone\n * weighs more, and it adds half a count per sounding of the tonic itself to\n * break ties between keys that contain the same notes.\n */\n score: number;\n};\n\n/**\n * Which form of a scale a {@link KeyMatch} settled on.\n *\n * @category Recognition\n */\nexport type KeyVariant = 'major' | 'natural' | 'harmonic' | 'melodic';\n\n/**\n * Input weighting for {@link detectKey}.\n *\n * @category Recognition\n */\nexport type DetectKeyOptions = {\n /**\n * How much each pitch counts toward the histogram, one entry per pitch.\n * Defaults to one per pitch, which weighs a thirty-second-note ornament as\n * heavily as the whole note under it. {@link detectKeyFromNotes} supplies\n * duration times velocity, matching how chord inference weighs its own\n * histogram.\n */\n weights?: readonly number[];\n};\n\n/** Unique pitch classes of the input, sorted ascending. */\nfunction uniquePitchClasses(pitches: readonly number[]): number[] {\n return [...new Set(pitches.map(pitchClass))].sort((a, b) => a - b);\n}\n\nfunction assertPitches(pitches: readonly number[]): void {\n assertGenerationBudget(pitches.length, 'detection pitches');\n for (let index = 0; index < pitches.length; index += 1) {\n assertFiniteNumber(pitches[index] ?? Number.NaN, `pitches[${index}]`);\n }\n}\n\n/**\n * Identify chords matching a set of pitches.\n *\n * Every input pitch class is tried as a root against every known chord quality.\n * A match is reported when all of the chord's tones are present in the input, or\n * when the only absent tone is the perfect fifth (a common omission in shell\n * voicings); matches are ranked best-first by fewest extra notes, then fewest\n * missing notes, then most specific (largest) chord. An exact match (no extras,\n * no missing) is flagged and ranked first.\n *\n * @param pitches MIDI pitches or bare pitch classes (octave-agnostic).\n * @returns Ranked chord interpretations (may be empty).\n * @example\n * ```ts\n * import { detectChord } from '@libraz/libcantus';\n * const matches = detectChord([60, 64, 67]); // C E G\n * matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }\n * ```\n * @category Recognition\n */\nexport function detectChord(\n pitches: readonly number[],\n opts: DetectChordOptions = {},\n): ChordMatch[] {\n assertPitches(pitches);\n if (opts.bassPc !== undefined) assertFiniteNumber(opts.bassPc, 'bassPc');\n const input = uniquePitchClasses(pitches);\n if (input.length === 0) {\n return [];\n }\n const inputKind =\n opts.input === undefined || opts.input === 'auto'\n ? pitches.every((pitch) => Number.isInteger(pitch) && pitch >= 0 && pitch <= 11)\n ? 'pitchClass'\n : 'midi'\n : opts.input;\n const bassPc =\n opts.bassPc !== undefined\n ? pitchClass(opts.bassPc)\n : inputKind === 'midi'\n ? pitchClass(pitches.reduce((lowest, pitch) => Math.min(lowest, pitch), Infinity))\n : undefined;\n const inputSet = new Set(input);\n const matches: ChordMatch[] = [];\n const qualities = chordQualities();\n for (const rootPc of input) {\n for (const quality of qualities) {\n const chord = makeChord(rootPc, quality);\n const tones = chordPitchClasses(chord);\n const toneSet = new Set(tones);\n const missingPcs = tones.filter((pc) => !inputSet.has(pc));\n // Accept an exact-tone match, or one whose only absent tone is the perfect\n // fifth; any other missing tone (third, sus tone, seventh, ...) rejects.\n const fifthPc = pitchClass(rootPc + 7);\n if (missingPcs.length > 1 || (missingPcs.length === 1 && missingPcs[0] !== fifthPc)) {\n continue;\n }\n const extraPcs = input.filter((pc) => !toneSet.has(pc));\n const bassIndex =\n bassPc === undefined\n ? -1\n : chord.intervals.findIndex((iv) => pitchClass(rootPc + iv) === bassPc);\n // A bass that is not a chord tone names no inversion; reporting it as 0\n // would be indistinguishable from root position for a caller that reads\n // `inversion === 0` as \"no slash needed\".\n const inversion = bassPc === undefined || bassIndex < 0 ? null : bassIndex;\n const match: ChordMatch = {\n rootPc,\n quality,\n missingPcs,\n extraPcs,\n exact: extraPcs.length === 0 && missingPcs.length === 0,\n inversion,\n };\n if (bassPc !== undefined && bassPc !== rootPc) {\n match.bassPc = bassPc;\n }\n matches.push(match);\n }\n }\n matches.sort((a, b) => {\n if (a.extraPcs.length !== b.extraPcs.length) {\n return a.extraPcs.length - b.extraPcs.length;\n }\n if (a.missingPcs.length !== b.missingPcs.length) {\n return a.missingPcs.length - b.missingPcs.length;\n }\n // Prefer root position (the bass is the chord root) on a tie.\n if ((a.inversion === 0) !== (b.inversion === 0)) {\n return a.inversion === 0 ? -1 : 1;\n }\n const aSize = chordPitchClasses(makeChord(a.rootPc, a.quality)).length;\n const bSize = chordPitchClasses(makeChord(b.rootPc, b.quality)).length;\n return bSize - aSize;\n });\n return matches;\n}\n\n/**\n * The single best chord interpretation of a pitch set, or null if none.\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @returns The top-ranked chord, or null when nothing matches.\n * @example\n * ```ts\n * import { detectChordBest } from '@libraz/libcantus';\n * detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }\n * ```\n * @category Recognition\n */\nexport function detectChordBest(\n pitches: readonly number[],\n opts: DetectChordOptions = {},\n): Chord | null {\n const best = detectChord(pitches, opts)[0];\n if (!best) {\n return null;\n }\n return makeChord(best.rootPc, best.quality, best.bassPc);\n}\n\n/**\n * Minor-scale variants scored for each minor-key candidate. Scoring against all\n * three lets the raised sixth and seventh (e.g. the leading tone G# in A minor)\n * count toward their own tonic instead of only penalizing it. Natural minor\n * comes first so it wins a tie as the most diatonic reading.\n */\nconst MINOR_VARIANTS = [\n { variant: 'natural', mask: NATURAL_MINOR_MASK },\n { variant: 'harmonic', mask: HARMONIC_MINOR_MASK },\n { variant: 'melodic', mask: MELODIC_MINOR_MASK },\n] as const satisfies readonly { variant: KeyVariant; mask: number }[];\n\n/** The single major form, kept in the same shape as the minor variants. */\nconst MAJOR_VARIANTS = [{ variant: 'major', mask: MAJOR_MASK }] as const satisfies readonly {\n variant: KeyVariant;\n mask: number;\n}[];\n\n/**\n * Rank major and minor keys by how well they contain a set of pitch classes.\n *\n * Ranking is by `score`, which counts repetitions and adds a tonic weight so\n * that, among equally-fitting keys, the one whose root is actually sounded is\n * preferred. Minor candidates are scored against the natural, harmonic, and\n * melodic minor variants and keep the best of the three, so a minor cadence\n * containing the leading tone still resolves to its own tonic; the winning\n * variant is what `key` and `variant` report, so `fit` describes the scale the\n * caller receives. Returns all 24 keys ranked best-first, or an empty array for\n * an empty input (mirroring {@link detectChord}).\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @returns Ranked key interpretations (empty for an empty input).\n * @example\n * ```ts\n * import { detectKey } from '@libraz/libcantus';\n * const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale\n * keys[0].mode; // 'major', with keys[0].key.rootPc === 0\n * ```\n * @category Recognition\n */\nexport function detectKey(pitches: readonly number[], opts: DetectKeyOptions = {}): KeyMatch[] {\n assertPitches(pitches);\n const input = uniquePitchClasses(pitches);\n if (input.length === 0) {\n return [];\n }\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== pitches.length) {\n throw new InvalidInputError('weights must have one entry per pitch');\n }\n const counts = new Map<number, number>();\n let total = 0;\n for (let index = 0; index < pitches.length; index += 1) {\n const weight = weights === undefined ? 1 : (weights[index] ?? 0);\n assertFiniteNumber(weight, `weights[${index}]`);\n if (weight <= 0) {\n continue;\n }\n const pc = pitchClass(pitches[index] ?? 0);\n counts.set(pc, (counts.get(pc) ?? 0) + weight);\n total += weight;\n }\n if (total === 0) {\n return [];\n }\n const results: KeyMatch[] = [];\n for (let tonic = 0; tonic < 12; tonic += 1) {\n for (const mode of ['major', 'minor'] as const) {\n const variants = mode === 'major' ? MAJOR_VARIANTS : MINOR_VARIANTS;\n // Score each scale variant and keep the best; ties keep the earlier\n // (more diatonic) variant. The winner is what the match reports, so its\n // fit is measured against the very scale the caller receives.\n let inScale = 0;\n let weighted = Number.NEGATIVE_INFINITY;\n let best: { variant: KeyVariant; mask: number } = variants[0];\n for (const candidate of variants) {\n let variantInScale = 0;\n let variantWeighted = 0;\n for (const pc of input) {\n const offset = (pc - tonic + 12) % 12;\n if ((candidate.mask >> offset) & 1) {\n variantInScale += 1;\n }\n }\n for (const [pc, count] of counts) {\n const offset = (pc - tonic + 12) % 12;\n if ((candidate.mask >> offset) & 1) {\n variantWeighted += count;\n }\n }\n if (variantWeighted > weighted) {\n weighted = variantWeighted;\n inScale = variantInScale;\n best = candidate;\n }\n }\n weighted += (counts.get(tonic) ?? 0) * 0.5;\n results.push({\n key: { rootPc: tonic, modeMask12: best.mask },\n mode,\n variant: best.variant,\n fit: inScale / input.length,\n score: weighted / total,\n });\n }\n }\n results.sort((a, b) => b.score - a.score);\n return results;\n}\n\n/** Default MIDI velocity assumed when a note event does not carry one. */\nconst DEFAULT_VELOCITY = 100;\n\n/**\n * Rank keys by how well they contain a set of note events, weighting each note\n * by how much of the music it actually occupies.\n *\n * {@link detectKey} counts every pitch once, which lets a run of fast ornamental\n * notes outvote the sustained harmony that establishes the key. This weighs\n * each note by duration times velocity, the same measure chord inference uses,\n * so the two agree on what the music emphasises. Notes that never sound (zero\n * or negative duration) are ignored.\n *\n * @param notes The note events to weigh.\n * @returns Ranked key interpretations (empty when nothing sounds).\n * @example\n * ```ts\n * import { detectKeyFromNotes } from '@libraz/libcantus';\n * detectKeyFromNotes([{ pitch: 60, startBeat: 0, durationBeat: 4 }])[0]?.key.rootPc; // 0\n * ```\n * @category Recognition\n */\nexport function detectKeyFromNotes(notes: readonly NoteEvent[]): KeyMatch[] {\n const sounding = notes.filter((note) => note.durationBeat > 0);\n return detectKey(\n sounding.map((note) => note.pitch),\n { weights: sounding.map((note) => note.durationBeat * (note.velocity ?? DEFAULT_VELOCITY)) },\n );\n}\n\n/**\n * The single best key interpretation of a pitch set.\n *\n * The counterpart of {@link detectChordBest}: the ranked list is the general\n * answer, but a caller that just wants \"what key is this\" should not have to\n * index into it and assert the result is there.\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @param opts How to weigh the input; see {@link DetectKeyOptions}.\n * @returns The top-ranked key, or null when nothing sounds.\n * @example\n * ```ts\n * import { detectKeyBest } from '@libraz/libcantus';\n * detectKeyBest([0, 2, 4, 5, 7, 9, 11])?.mode; // 'major'\n * ```\n * @category Recognition\n */\nexport function detectKeyBest(\n pitches: readonly number[],\n opts: DetectKeyOptions = {},\n): KeyMatch | null {\n return detectKey(pitches, opts)[0] ?? null;\n}\n","/**\n * Shared helpers for the functional-harmony modules.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport { pitchClassOf as mod12 } from '../../core/pitch/index.js';\n\nexport { pitchClassOf as mod12 } from '../../core/pitch/index.js';\n\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../../theory/chord/index.js';\nimport { MAJOR_MASK, majorKey, scaleTonesInDegreeOrder } from '../../theory/scale/index.js';\n\n/** Diatonic pitch class of a 1-based scale degree in a key. */\nexport function degreeRootPc(degreeNumber: number, key: KeyScale): number {\n const tones = scaleTonesInDegreeOrder(key);\n if (tones.length === 0) {\n return mod12(key.rootPc);\n }\n // A plain `%` yields a negative index for a degree below the first, which\n // reads as undefined and collapses to the tonic; wrap into range instead.\n const index = (((degreeNumber - 1) % tones.length) + tones.length) % tones.length;\n return tones[index] ?? mod12(key.rootPc);\n}\n\n/**\n * The 1-based scale degrees that already sit a semitone below their parallel\n * major counterpart — the third, sixth and seventh of a natural minor key, the\n * third and seventh of dorian, and so on.\n *\n * Roman-numeral spelling and parsing both need this: a flat sign on such a\n * degree is the degree itself rather than a further lowering, and a chromatic\n * root a semitone above one of them is that degree raised (`#III` in a minor\n * key), not a flattened version of the degree above it.\n *\n * Only heptatonic keys have a degree-for-degree correspondence with a major\n * scale, so anything else reports no lowered degrees.\n */\nexport function loweredDegrees(key: KeyScale): Set<number> {\n const tones = scaleTonesInDegreeOrder(key);\n const out = new Set<number>();\n if (tones.length !== 7) {\n return out;\n }\n const major = scaleTonesInDegreeOrder({ rootPc: mod12(key.rootPc), modeMask12: MAJOR_MASK });\n for (let index = 0; index < 7; index += 1) {\n const tone = tones[index];\n const majorTone = major[index];\n if (tone !== undefined && majorTone !== undefined && mod12(majorTone - tone) === 1) {\n out.add(index + 1);\n }\n }\n return out;\n}\n\n/**\n * The heptatonic frame a Roman numeral is measured against for a key.\n *\n * Roman numerals only have seven glyphs, so a scale with any other number of\n * tones has no degree-for-degree numeral of its own: a pentatonic key would\n * make `VI` wrap around to the tonic and an octatonic or chromatic key would\n * have degrees no numeral can name. Such keys are read against their parallel\n * major instead — the same frame the chromatic fallback spelling already uses —\n * so `chordToRoman` and `romanToChord` stay mutual inverses for every key.\n */\nexport function romanReference(key: KeyScale): KeyScale {\n return scaleTonesInDegreeOrder(key).length === 7 ? key : majorKey(mod12(key.rootPc));\n}\n\n/** Whether a chord is the Neapolitan: a major triad on the flat second degree. */\nexport function isNeapolitan(chord: Chord, key: KeyScale): boolean {\n return mod12(chord.rootPc - key.rootPc) === 1 && chord.quality === 'maj';\n}\n","/**\n * Roman-numeral parsing and formatting.\n *\n * The {@link ROMAN_STYLE} table is the single source of truth for both\n * directions, so {@link chordToRoman} and {@link romanToChord} stay mutual\n * inverses by construction.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord, ChordQuality } from '../../theory/chord/index.js';\nimport { chordPitchClasses, makeChord } from '../../theory/chord/index.js';\nimport { isScaleTone, majorKey, scaleTonesInDegreeOrder } from '../../theory/scale/index.js';\nimport { degreeRootPc, loweredDegrees, mod12, romanReference } from './internal.js';\n\n/** Roman numeral glyphs indexed by degree number - 1. */\nconst ROMAN = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII'] as const;\n\n/** Roman glyph -> degree number (1..7). */\nconst ROMAN_TO_DEGREE: Record<string, number> = {\n I: 1,\n II: 2,\n III: 3,\n IV: 4,\n V: 5,\n VI: 6,\n VII: 7,\n};\n\n/** Major-key Roman spelling for each semitone offset above the tonic. */\nconst OFFSET_SPELLING: readonly [number, string][] = [\n [1, ''],\n [2, 'b'],\n [2, ''],\n [3, 'b'],\n [3, ''],\n [4, ''],\n [4, '#'],\n [5, ''],\n [6, 'b'],\n [6, ''],\n [7, 'b'],\n [7, ''],\n];\n\n/** Choose a seventh-chord quality from a triad label and the numeral case. */\nfunction seventhQuality(base: 'maj' | 'min' | 'dim' | 'aug', halfDim: boolean): ChordQuality {\n if (halfDim) {\n return 'm7b5';\n }\n if (base === 'dim') {\n return 'dim7';\n }\n if (base === 'aug') {\n return 'aug7';\n }\n return base === 'maj' ? 'dom7' : 'min7';\n}\n\n/** Figure strings that denote a recognized figured-bass inversion. */\nconst INVERSION_FIGURES = new Set(['6', '64', '65', '43', '42', '2', '7']);\n\n/**\n * Canonical Roman-numeral rendering (numeral case and quality suffix) for every\n * supported chord quality. The table is the single source of truth for both\n * directions: {@link chordToRoman} renders from it and {@link romanToChord}\n * recognizes its exact case-sensitive suffixes, so the two stay mutual\n * inverses by construction. Suffixes are chosen to never collide with\n * figured-bass inversion digits (`6`, `64`, `65`, `43`, `42`, `2`) — the added\n * sixth is `add6`, the six-nine chord is `69` — and each (case, suffix) pair is\n * unique.\n */\nconst ROMAN_STYLE: Record<ChordQuality, { lower: boolean; suffix: string }> = {\n maj: { lower: false, suffix: '' },\n min: { lower: true, suffix: '' },\n dim: { lower: true, suffix: 'o' },\n aug: { lower: false, suffix: '+' },\n maj7: { lower: false, suffix: 'maj7' },\n min7: { lower: true, suffix: '7' },\n dom7: { lower: false, suffix: '7' },\n dim7: { lower: true, suffix: 'o7' },\n m7b5: { lower: true, suffix: 'ø7' },\n minMaj7: { lower: true, suffix: 'maj7' },\n aug7: { lower: false, suffix: '+7' },\n augMaj7: { lower: false, suffix: '+maj7' },\n majb5: { lower: false, suffix: 'b5' },\n '6': { lower: false, suffix: 'add6' },\n min6: { lower: true, suffix: 'add6' },\n '6/9': { lower: false, suffix: '69' },\n sus2: { lower: false, suffix: 'sus2' },\n sus4: { lower: false, suffix: 'sus4' },\n add9: { lower: false, suffix: 'add9' },\n add11: { lower: false, suffix: 'add11' },\n maj9: { lower: false, suffix: 'maj9' },\n min9: { lower: true, suffix: '9' },\n dom9: { lower: false, suffix: '9' },\n '7b9': { lower: false, suffix: '7b9' },\n '7#9': { lower: false, suffix: '7#9' },\n '7#11': { lower: false, suffix: '7#11' },\n '7b13': { lower: false, suffix: '7b13' },\n '11': { lower: false, suffix: '11' },\n '13': { lower: false, suffix: '13' },\n '5': { lower: false, suffix: '5' },\n '7sus4': { lower: false, suffix: '7sus4' },\n '7b5': { lower: false, suffix: '7b5' },\n '7alt': { lower: false, suffix: '7alt' },\n '13b9': { lower: false, suffix: '13b9' },\n maj13: { lower: false, suffix: 'maj13' },\n 'maj7#11': { lower: false, suffix: 'maj7#11' },\n min11: { lower: true, suffix: '11' },\n min13: { lower: true, suffix: '13' },\n minAdd9: { lower: true, suffix: 'add9' },\n 'min6/9': { lower: true, suffix: '69' },\n};\n\n/** Reverse lookup of {@link ROMAN_STYLE}: `(case, exact suffix) -> quality`. */\nconst SUFFIX_QUALITY: ReadonlyMap<string, ChordQuality> = new Map(\n (Object.entries(ROMAN_STYLE) as [ChordQuality, { lower: boolean; suffix: string }][]).map(\n ([quality, style]) => [`${style.lower ? 'l' : 'u'}:${style.suffix}`, quality],\n ),\n);\n\n/** Read figured-bass digits into a chord inversion and whether a seventh is implied. */\nfunction parseInversion(figures: string): { inversion: number; seventh: boolean } {\n if (figures === '65') {\n return { inversion: 1, seventh: true };\n }\n if (figures === '43') {\n return { inversion: 2, seventh: true };\n }\n if (figures === '42' || figures === '2') {\n return { inversion: 3, seventh: true };\n }\n if (figures === '7') {\n return { inversion: 0, seventh: true };\n }\n if (figures === '64') {\n return { inversion: 2, seventh: false };\n }\n if (figures === '6') {\n return { inversion: 1, seventh: false };\n }\n return { inversion: 0, seventh: false };\n}\n\n/** Parse a Roman numeral (no secondary '/') into a root, quality, and inversion. */\nfunction parseSimpleRoman(\n text: string,\n key: KeyScale,\n): { rootPc: number; quality: ChordQuality; inversion: number } {\n const match = /^([b#]?)([iIvV]+)(.*)$/.exec(text.trim());\n if (!match) {\n throw new InvalidInputError(`Invalid Roman numeral: ${text}`);\n }\n const accidental = match[1] === 'b' ? -1 : match[1] === '#' ? 1 : 0;\n const glyph = (match[2] ?? '').toUpperCase();\n const degreeNumber = ROMAN_TO_DEGREE[glyph];\n if (degreeNumber === undefined) {\n throw new InvalidInputError(`Invalid Roman numeral: ${text}`);\n }\n const isUpper = (match[2] ?? '')[0] === (match[2] ?? '')[0]?.toUpperCase();\n const suffix = match[3] ?? '';\n // Degrees are read in the key's heptatonic frame, so a numeral means the same\n // root in both directions even when the key itself is not heptatonic.\n const frame = romanReference(key);\n // A flat on a degree the mode already lowers is that degree, not a further\n // lowering: `bVII` in A minor is G, the pop reading, rather than F#.\n const redundantFlat = accidental === -1 && loweredDegrees(frame).has(degreeNumber);\n const rootPc = mod12(degreeRootPc(degreeNumber, frame) + (redundantFlat ? 0 : accidental));\n\n // Canonical quality suffixes (exact match, case-sensitive on the numeral)\n // come first so every chordToRoman rendering re-parses to the same quality:\n // `V9` -> dom9 but `ii9` -> min9 and `Imaj9` -> maj9, and added-tone suffixes\n // whose digits would otherwise be misread as figured bass (`Iadd6`, `I69`,\n // `Isus2`, `Iadd11`) resolve to their qualities in root position.\n const canonical = SUFFIX_QUALITY.get(`${isUpper ? 'u' : 'l'}:${suffix}`);\n if (canonical !== undefined) {\n return { rootPc, quality: canonical, inversion: 0 };\n }\n\n // Non-canonical spellings are limited to a complete quality marker followed\n // by an optional major-seventh marker and a recognized figured bass. Never\n // search substrings: `Vfoo` must not become diminished merely because it\n // contains an \"o\", and unknown trailing text must be rejected in full.\n const parsedSuffix = /^(o|°|dim|ø|\\+|aug)?(maj7|M7)?(65|64|43|42|7|6|2)?$/.exec(suffix);\n if (!parsedSuffix) {\n throw new InvalidInputError(`Unsupported suffix \"${suffix}\" in Roman numeral: ${text}`);\n }\n const qualityMarker = parsedSuffix[1] ?? '';\n const isDim = qualityMarker === 'o' || qualityMarker === '°' || qualityMarker === 'dim';\n const isAug = qualityMarker === '+' || qualityMarker === 'aug';\n const isHalfDim = qualityMarker === 'ø';\n const explicitMaj7 = parsedSuffix[2] !== undefined;\n const figures = parsedSuffix[3] ?? '';\n\n // Reject figure strings that are neither a known figured-bass inversion nor a\n // canonical quality suffix rather than silently degrading to a root triad.\n if (figures !== '' && !INVERSION_FIGURES.has(figures)) {\n throw new InvalidInputError(\n `Unsupported figured-bass or extension \"${figures}\" in Roman numeral: ${text}`,\n );\n }\n\n const { inversion, seventh } = parseInversion(figures);\n // The ø glyph is the half-diminished seventh by definition (there is no\n // half-diminished triad), so it always implies a seventh.\n const hasSeventh = explicitMaj7 || seventh || isHalfDim;\n\n let base: 'maj' | 'min' | 'dim' | 'aug';\n if (isDim || isHalfDim) {\n base = 'dim';\n } else if (isAug) {\n base = 'aug';\n } else {\n base = isUpper ? 'maj' : 'min';\n }\n\n let quality: ChordQuality;\n if (explicitMaj7) {\n quality = base === 'min' ? 'minMaj7' : base === 'aug' ? 'augMaj7' : 'maj7';\n } else if (hasSeventh) {\n quality = seventhQuality(base, isHalfDim);\n } else if (base === 'dim') {\n quality = 'dim';\n } else if (base === 'aug') {\n quality = 'aug';\n } else {\n quality = base;\n }\n return { rootPc, quality, inversion };\n}\n\n/** Build a chord from a parsed Roman numeral, attaching a bass for inversions. */\nfunction chordFromParsed(parsed: {\n rootPc: number;\n quality: ChordQuality;\n inversion: number;\n}): Chord {\n const chord = makeChord(parsed.rootPc, parsed.quality);\n if (parsed.inversion > 0 && parsed.inversion < chord.intervals.length) {\n chord.bassPc = mod12(parsed.rootPc + (chord.intervals[parsed.inversion] ?? 0));\n }\n return chord;\n}\n\n/**\n * Build the chord denoted by a Roman numeral in a key.\n *\n * Supports accidentals (`bVII`, `#iv`), case-based triad quality, the `o`/`ø`/`+`\n * suffixes, sevenths (`V7`, `viio7`, `Imaj7`), figured-bass inversions\n * (`V6`, `V64`, `V65`, `V43`, `V42`), and applied/secondary chords via a slash\n * (`V7/V`, `viio/ii`). The target after the slash is read as a scale degree\n * whose root becomes a local major tonic for the applied chord. Inverted chords\n * carry a `bassPc`.\n *\n * The `ø` glyph always denotes the half-diminished seventh (`iiø` == `iiø7` ==\n * `m7b5`), since no half-diminished triad exists. Extension and added-tone\n * suffixes are the canonical case-sensitive forms emitted by\n * {@link chordToRoman} and honor the numeral case: `V9` -> `dom9`, `ii9` ->\n * `min9`, `Imaj9` -> `maj9`, `V11` -> `11`, `V13` -> `13`, `Iadd6`/`iadd6` ->\n * `6`/`min6`, `I69` -> `6/9`, `Isus2`/`Isus4`, `Iadd9`/`Iadd11`, `Ib5` ->\n * `majb5`, `I5` -> `5`, and the altered dominants `V7b9`/`V7#9`/`V7#11`/`V7b13`.\n * A figure string that is neither a recognized inversion nor a supported\n * quality suffix throws rather than silently degrading to a triad.\n *\n * @param text The Roman numeral.\n * @param key The prevailing key.\n * @returns The chord.\n * @example\n * ```ts\n * import { romanToChord, majorKey } from '@libraz/libcantus';\n * romanToChord('V7', majorKey(0)); // G7 in C major: { rootPc: 7, quality: 'dom7', ... }\n * ```\n * @category Functional Harmony\n */\nexport function romanToChord(text: string, key: KeyScale): Chord {\n const trimmed = text.trim();\n const slash = trimmed.indexOf('/');\n if (slash >= 0) {\n const applied = trimmed.slice(0, slash);\n const target = trimmed.slice(slash + 1);\n const targetRoot = parseSimpleRoman(target, key).rootPc;\n const localKey = majorKey(targetRoot);\n return chordFromParsed(parseSimpleRoman(applied, localKey));\n }\n return chordFromParsed(parseSimpleRoman(trimmed, key));\n}\n\n/** Case and suffix for rendering a chord quality as a Roman numeral. */\nfunction romanStyle(quality: ChordQuality): { lower: boolean; suffix: string } {\n return ROMAN_STYLE[quality];\n}\n\n/** Choose the degree number and accidental to spell a root as a Roman numeral. */\nfunction romanSpelling(\n rootPc: number,\n key: KeyScale,\n): { degreeNumber: number; accidental: string } {\n const tones = scaleTonesInDegreeOrder(romanReference(key));\n const diatonic = tones.indexOf(mod12(rootPc));\n if (diatonic >= 0) {\n return { degreeNumber: diatonic + 1, accidental: '' };\n }\n // A chromatic root a semitone above a degree the mode already lowers is that\n // degree raised: C# in A minor is `#III`, not `bIV`.\n const lowered = loweredDegrees(romanReference(key));\n for (let i = 0; i < tones.length; i += 1) {\n if (lowered.has(i + 1) && mod12((tones[i] ?? 0) + 1) === mod12(rootPc)) {\n return { degreeNumber: i + 1, accidental: '#' };\n }\n }\n // Otherwise prefer a flat of the diatonic degree a semitone above it,\n // then a sharp of the degree a semitone below. Degree 1 (the tonic) and\n // degree 5 (the dominant) are skipped in the flat pass, so a raised leading\n // tone spells as `#vii` rather than a flat tonic `bI`, and the tritone above\n // the tonic spells as `#iv` rather than a flat fifth `bV` (matching the\n // conventional `OFFSET_SPELLING` for offset 6).\n for (let i = 0; i < tones.length; i += 1) {\n const degreeNumber = i + 1;\n if (degreeNumber === 1 || degreeNumber === 5) {\n continue;\n }\n if (mod12((tones[i] ?? 0) - 1) === mod12(rootPc)) {\n return { degreeNumber, accidental: 'b' };\n }\n }\n for (let i = 0; i < tones.length; i += 1) {\n if (mod12((tones[i] ?? 0) + 1) === mod12(rootPc)) {\n return { degreeNumber: i + 1, accidental: '#' };\n }\n }\n const [degreeNumber, accidental] = OFFSET_SPELLING[mod12(rootPc - key.rootPc)] ?? [1, ''];\n return { degreeNumber, accidental };\n}\n\n/** Quality marker (without the seventh digit) used when a figure carries the 7. */\nfunction baseMarker(quality: ChordQuality): string {\n if (quality === 'dim' || quality === 'dim7') {\n return 'o';\n }\n if (quality === 'm7b5') {\n return 'ø';\n }\n if (quality === 'aug' || quality === 'aug7') {\n return '+';\n }\n if (quality === 'augMaj7') {\n return '+maj7';\n }\n if (quality === 'maj7' || quality === 'minMaj7') {\n return 'maj7';\n }\n return '';\n}\n\nconst TRIAD_FIGURES: Record<number, string> = { 1: '6', 2: '64' };\nconst SEVENTH_FIGURES: Record<number, string> = { 1: '65', 2: '43', 3: '42' };\n\n/** Qualities whose inversions render as lossless triad figures (6, 64). */\nconst TRIAD_FIGURE_QUALITIES: ReadonlySet<ChordQuality> = new Set(['maj', 'min', 'dim', 'aug']);\n\n/**\n * Qualities carrying a chordal seventh, whose inversions render as seventh\n * figures (65, 43, 42). Membership is decided by the quality itself — a 7th\n * above the root (10 or 11 semitones, or the diminished 7th of `dim7`) — never\n * by interval count, which would turn added-tone chords into false sevenths.\n */\nconst SEVENTH_FIGURE_QUALITIES: ReadonlySet<ChordQuality> = new Set([\n 'maj7',\n 'min7',\n 'dom7',\n 'dim7',\n 'm7b5',\n 'minMaj7',\n 'aug7',\n 'augMaj7',\n]);\n\n/**\n * The numeral glyph for a degree number, cased for the chord quality.\n *\n * Only the seven glyphs exist, so a degree outside 1..7 is a contract violation\n * rather than something to paper over with a default numeral.\n */\nfunction numeralFor(degreeNumber: number, lower: boolean): string {\n const glyph = ROMAN[degreeNumber - 1];\n if (glyph === undefined) {\n throw new InvalidInputError(`no Roman numeral for scale degree ${degreeNumber}`);\n }\n return lower ? glyph.toLowerCase() : glyph;\n}\n\n/** Whether every pitch class of a chord belongs to the key's scale. */\nfunction isDiatonicChord(chord: Chord, key: KeyScale): boolean {\n return chordPitchClasses(chord).every((pc) => isScaleTone(pc, key));\n}\n\n/**\n * Whether the chord sounds like an applied dominant: a major triad, or any\n * chord stacking a major third and a minor seventh above its root. The\n * diminished family is handled separately, as the leading-tone chord.\n */\nfunction isAppliedDominantSonority(chord: Chord): boolean {\n const has = (semitones: number): boolean => chord.intervals.some((i) => mod12(i) === semitones);\n return chord.quality === 'maj' || (has(4) && has(10));\n}\n\n/** Diminished-family qualities, which tonicize from a semitone below. */\nconst LEADING_TONE_QUALITIES: ReadonlySet<ChordQuality> = new Set(['dim', 'dim7', 'm7b5']);\n\n/** The third and fifth above a scale degree, measured within its own scale. */\nfunction degreeTriad(tones: readonly number[], index: number): { third: number; fifth: number } {\n const root = tones[index] ?? 0;\n return {\n third: mod12((tones[(index + 2) % tones.length] ?? 0) - root),\n fifth: mod12((tones[(index + 4) % tones.length] ?? 0) - root),\n };\n}\n\n/**\n * The scale degree a chromatic chord tonicizes, or null when it tonicizes\n * nothing. A dominant sonority points a fifth below itself, a diminished one a\n * semitone above itself; the tonic is never a target (that chord is the key's own\n * dominant) and neither is a degree carrying a diminished triad, which has no\n * fifth to be tonicized.\n */\nfunction appliedTarget(\n chord: Chord,\n key: KeyScale,\n): { degreeNumber: number; rootPc: number; lower: boolean } | null {\n const dominant = isAppliedDominantSonority(chord);\n const leadingTone = LEADING_TONE_QUALITIES.has(chord.quality);\n if (!dominant && !leadingTone) {\n return null;\n }\n const tones = scaleTonesInDegreeOrder(romanReference(key));\n for (let index = 1; index < tones.length; index += 1) {\n const targetRoot = tones[index];\n if (targetRoot === undefined) {\n continue;\n }\n const triad = degreeTriad(tones, index);\n if (triad.fifth === 6) {\n continue;\n }\n const expectedRoot = mod12(targetRoot + (dominant ? 7 : -1));\n if (expectedRoot === mod12(chord.rootPc)) {\n return { degreeNumber: index + 1, rootPc: targetRoot, lower: triad.third === 3 };\n }\n }\n return null;\n}\n\n/**\n * Options for {@link chordToRoman}.\n *\n * @category Functional Harmony\n */\nexport type ChordToRomanOptions = {\n /**\n * Render a tonicizing chord as an applied numeral (`V7/V`, `viio7/ii`)\n * instead of naming its root against the home key (`II7`, `#ivo7`).\n *\n * Off by default: naming the root is always a correct spelling, whereas\n * whether a chromatic dominant is genuinely applied is a reading only the\n * caller can make. Turning it on makes {@link chordToRoman} the exact inverse\n * of {@link romanToChord} for the chords {@link secondaryDominant} builds.\n */\n applied?: boolean;\n};\n\n/**\n * Render a chord as a Roman numeral relative to a key.\n *\n * Diatonic roots take their scale-degree numeral directly, so numerals are\n * correct in both major and minor keys (and any custom scale). The quality\n * selects the case and suffix; chromatic roots receive a flat/sharp spelling by\n * convention. A key that is not heptatonic has no numeral of its own for every\n * degree, so its roots are named against its parallel major.\n *\n * When the chord carries a `bassPc` on a chord tone, a figured-bass inversion\n * (`6`, `64`, `65`, `43`, `42`) is emitted for plain triads and true seventh\n * chords; added-tone and extended qualities have no lossless figure and render\n * in root position instead (the bass is dropped, pitch classes are preserved).\n *\n * A `bassPc` that is *not* a chord tone — a pedal or passing bass such as\n * `C/D` — is likewise dropped, and the numeral names the upper chord alone.\n * Roman-numeral notation spends its slash on applied chords (`V7/V`), so there\n * is no unambiguous way to write such a bass; a caller that must keep it should\n * read `chord.bassPc` alongside the numeral.\n *\n * @param chord The chord to name.\n * @param key The prevailing key.\n * @param opts `applied` renders tonicizing chords as `V7/V`-style numerals.\n * @returns The Roman numeral string.\n * @example\n * ```ts\n * import { chordToRoman, makeChord, majorKey } from '@libraz/libcantus';\n * chordToRoman(makeChord(7, 'dom7'), majorKey(0)); // => 'V7' (G7 in C major)\n * chordToRoman(makeChord(2, 'dom7'), majorKey(0), { applied: true }); // => 'V7/V'\n * ```\n * @category Functional Harmony\n */\nexport function chordToRoman(chord: Chord, key: KeyScale, opts: ChordToRomanOptions = {}): string {\n if (opts.applied === true && !isDiatonicChord(chord, key)) {\n const target = appliedTarget(chord, key);\n if (target !== null) {\n const local = chordToRoman(chord, majorKey(target.rootPc));\n return `${local}/${numeralFor(target.degreeNumber, target.lower)}`;\n }\n }\n const { degreeNumber, accidental } = romanSpelling(chord.rootPc, key);\n const { lower, suffix } = romanStyle(chord.quality);\n const cased = numeralFor(degreeNumber, lower);\n\n let inversion = 0;\n if (chord.bassPc !== undefined) {\n const idx = chord.intervals.findIndex((iv) => mod12(chord.rootPc + iv) === chord.bassPc);\n if (idx > 0) {\n inversion = idx;\n }\n }\n if (inversion > 0) {\n const figure = SEVENTH_FIGURE_QUALITIES.has(chord.quality)\n ? SEVENTH_FIGURES[inversion]\n : TRIAD_FIGURE_QUALITIES.has(chord.quality)\n ? TRIAD_FIGURES[inversion]\n : undefined;\n if (figure !== undefined) {\n return `${accidental}${cased}${baseMarker(chord.quality)}${figure}`;\n }\n // No lossless figured-bass symbol exists — the quality is an added-tone or\n // extended chord, or the bass falls on a tension beyond the seventh — so\n // fall back to root-position rendering with the quality suffix rather than\n // emitting a figure that would re-parse as a different chord.\n }\n return `${accidental}${cased}${suffix}`;\n}\n","/**\n * Borrowed chords (modal interchange) and the Neapolitan.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../../theory/chord/index.js';\nimport { HARMONIC_MINOR_MASK } from '../../theory/scale/index.js';\nimport { isDiatonic, isMinorKey, parallelKey } from './function.js';\nimport { isNeapolitan, mod12 } from './internal.js';\n\n/**\n * The origin of a recognized non-diatonic chord, or null when none applies.\n *\n * @category Functional Harmony\n */\nexport type BorrowedSource = 'parallelMinor' | 'parallelMajor' | 'neapolitan' | null;\n\n/**\n * In a minor key, whether a non-diatonic chord is explained by the harmonic\n * minor scale on the same tonic (major V, V7, the raised-leading-tone viio).\n * Such chords are in-key chromatic alterations, not modal interchange.\n */\nfunction isHarmonicMinorAlteration(chord: Chord, key: KeyScale): boolean {\n return (\n isMinorKey(key) &&\n isDiatonic(chord, { rootPc: mod12(key.rootPc), modeMask12: HARMONIC_MINOR_MASK })\n );\n}\n\n/**\n * Whether a chord is borrowed from the parallel mode (modal interchange).\n *\n * True when the chord is not diatonic to `key` but is diatonic to its\n * {@link parallelKey} — e.g. iv, bVI, or bVII in a major key, or the Picardy\n * tonic and major IV in a minor key. Two non-diatonic families are excluded:\n * chords diatonic to neither mode (they are chromatic, not borrowed), and, in\n * a minor key, chords explained by the harmonic minor scale (the major\n * dominant and raised-leading-tone chords), which are in-key alterations\n * rather than interchange even though they happen to fit the parallel major.\n *\n * @param chord The chord to test.\n * @param key The prevailing key.\n * @returns True if the chord is borrowed from the parallel mode.\n * @category Functional Harmony\n */\nexport function isBorrowedChord(chord: Chord, key: KeyScale): boolean {\n if (isDiatonic(chord, key)) {\n return false;\n }\n if (isHarmonicMinorAlteration(chord, key)) {\n return false;\n }\n return isDiatonic(chord, parallelKey(key));\n}\n\n/**\n * Identify where a non-diatonic chord comes from.\n *\n * The Neapolitan (major triad on b2) is recognized first, since it sits\n * outside both parallel modes; parallel-mode borrowing follows the\n * {@link isBorrowedChord} rules. Diatonic chords, harmonic-minor alterations,\n * and unrecognized chromatic chords all yield null.\n *\n * @param chord The chord to classify.\n * @param key The prevailing key.\n * @returns The borrowing source, or null.\n * @category Functional Harmony\n */\nexport function borrowedSource(chord: Chord, key: KeyScale): BorrowedSource {\n if (isDiatonic(chord, key)) {\n return null;\n }\n if (isNeapolitan(chord, key)) {\n return 'neapolitan';\n }\n if (isBorrowedChord(chord, key)) {\n return isMinorKey(key) ? 'parallelMajor' : 'parallelMinor';\n }\n return null;\n}\n","/**\n * Harmonic function (tonic / subdominant / dominant), diatonicity, parallel-key\n * mirroring, and full chord analysis.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport type { KeyScale } from '../../core/types.js';\nimport { assertInteger } from '../../core/validation/index.js';\nimport type { Chord, ChordQuality } from '../../theory/chord/index.js';\nimport { chordPitchClasses, makeChord } from '../../theory/chord/index.js';\nimport { isScaleTone, MAJOR_MASK, NATURAL_MINOR_MASK } from '../../theory/scale/index.js';\nimport { type BorrowedSource, borrowedSource } from './borrowed.js';\nimport { degreeRootPc, isNeapolitan, mod12 } from './internal.js';\nimport { chordToRoman } from './roman.js';\n\n/**\n * The three broad harmonic functions of tonal music.\n *\n * @category Functional Harmony\n */\nexport type HarmonicFunction = 'tonic' | 'subdominant' | 'dominant';\n\n/** Harmonic function of each semitone offset above the tonic (major context). */\nconst FUNCTION_BY_OFFSET: readonly HarmonicFunction[] = [\n 'tonic', // 0 I\n 'subdominant', // 1 bII (Neapolitan)\n 'subdominant', // 2 ii\n 'tonic', // 3 bIII\n 'tonic', // 4 iii\n 'subdominant', // 5 IV\n 'dominant', // 6 #IV / bV\n 'dominant', // 7 V\n 'subdominant', // 8 bVI\n 'tonic', // 9 vi\n 'subdominant', // 10 bVII\n 'dominant', // 11 vii\n];\n\n/**\n * Whether a key's scale has a minor third and no major third (a minor key).\n *\n * @category Functional Harmony\n */\nexport function isMinorKey(key: KeyScale): boolean {\n const hasMinorThird = (key.modeMask12 >> 3) & 1;\n const hasMajorThird = (key.modeMask12 >> 4) & 1;\n return Boolean(hasMinorThird) && !hasMajorThird;\n}\n\n/**\n * The harmonic function of a chord in a key.\n *\n * The root's offset above the tonic gives the baseline mapping, which follows\n * common-practice major-key function and is a useful approximation in minor and\n * for borrowed chords. Chord quality then refines it where the sonority settles\n * an ambiguity the root offset cannot:\n *\n * - A chord that *sounds* like a dominant — a major third with a minor seventh,\n * or a diminished-family chord — and is not diatonic to the key has dominant\n * function when its root resolves down a fifth or by a semitone onto a\n * diatonic degree. This is what makes an applied dominant (`A7` in C, which\n * tonicizes ii) and its tritone substitute (`Db7`) read as dominant rather\n * than inheriting the function of the degree they happen to sit on.\n * - The Neapolitan is subdominant.\n * - A major triad on bVI or bVII of a major key is subdominant — the borrowed\n * pop cadence chord, distinct from the bVII7 above, which has a seventh and\n * is a dominant sonority.\n *\n * @param chord The chord.\n * @param key The prevailing key.\n * @returns The harmonic function.\n * @example\n * ```ts\n * import { functionOf, makeChord, majorKey } from '@libraz/libcantus';\n * functionOf(makeChord(9, 'dom7'), majorKey(0)); // 'dominant' — A7 tonicizes ii\n * functionOf(makeChord(10, 'maj'), majorKey(0)); // 'subdominant' — borrowed bVII\n * ```\n * @category Functional Harmony\n */\nexport function functionOf(chord: Chord, key: KeyScale): HarmonicFunction {\n const offset = mod12(chord.rootPc - key.rootPc);\n if (isNeapolitan(chord, key)) {\n return 'subdominant';\n }\n if (isAppliedDominant(chord, key)) {\n return 'dominant';\n }\n if (!isMinorKey(key) && hasMajorThird(chord) && (offset === 8 || offset === 10)) {\n return 'subdominant';\n }\n return FUNCTION_BY_OFFSET[offset] ?? 'tonic';\n}\n\n/**\n * Whether the chord is a dominant sonority pointing at a diatonic degree.\n *\n * A chord already diatonic to the key keeps the offset table's reading; what is\n * classified here is the chromatic chord whose sonority and resolution give it\n * dominant function regardless of the degree it sits on.\n *\n * The resolution required depends on the sonority. A dominant seventh (major\n * third plus minor seventh) must fall a perfect fifth — the applied dominants —\n * or a semitone, which is the same motion its tritone substitute makes. A\n * diminished-family chord must rise a semitone, the leading-tone resolution;\n * requiring that is what keeps a borrowed `iiø7`, which falls a fifth like any\n * other supertonic chord, reading as a predominant rather than a dominant.\n */\nfunction isAppliedDominant(chord: Chord, key: KeyScale): boolean {\n if (isDiatonic(chord, key)) {\n return false;\n }\n const root = mod12(chord.rootPc);\n const resolvesTo = (step: number) => isScaleTone(mod12(root + step), key);\n if (hasMajorThird(chord) && chord.intervals.some((i) => mod12(i) === 10)) {\n return resolvesTo(5) || resolvesTo(11);\n }\n return isDiminishedQuality(chord.quality) && resolvesTo(1);\n}\n\n/**\n * The result of {@link analyzeChord}: function, borrowing, and Roman numeral.\n *\n * @category Functional Harmony\n */\nexport type ChordAnalysis = {\n function: HarmonicFunction;\n borrowed: boolean;\n source: BorrowedSource;\n roman: string;\n};\n\n/**\n * Whether every pitch class of a chord belongs to the key's scale.\n *\n * The test is strict against the key's own mode mask: in a natural-minor key\n * the harmonic-minor dominant (major V) is *not* diatonic, since the raised\n * leading tone lies outside the mask. Borrowing predicates treat that case as\n * an in-key alteration separately (see {@link isBorrowedChord}).\n *\n * @param chord The chord to test.\n * @param key The prevailing key.\n * @returns True if all chord pitch classes are scale tones.\n * @category Functional Harmony\n */\nexport function isDiatonic(chord: Chord, key: KeyScale): boolean {\n return chordPitchClasses(chord).every((pc) => isScaleTone(pc, key));\n}\n\n/**\n * The parallel key: same tonic, opposite mode.\n *\n * A key with a minor third (natural/harmonic/melodic minor, dorian, phrygian)\n * maps to the parallel major; any other key maps to the parallel natural minor.\n *\n * @param key The key to mirror.\n * @returns The parallel major or natural-minor key on the same tonic.\n * @category Functional Harmony\n */\nexport function parallelKey(key: KeyScale): KeyScale {\n return {\n rootPc: mod12(key.rootPc),\n modeMask12: isMinorKey(key) ? MAJOR_MASK : NATURAL_MINOR_MASK,\n };\n}\n\n/** Diminished-family qualities: diminished triad, dim7, half-diminished. */\nfunction isDiminishedQuality(quality: ChordQuality): boolean {\n return quality === 'dim' || quality === 'dim7' || quality === 'm7b5';\n}\n\n/** Whether the chord's interval template carries a major third above the root. */\nfunction hasMajorThird(chord: Chord): boolean {\n return chord.intervals.some((interval) => mod12(interval) === 4);\n}\n\n/**\n * Analyze a chord in a key: harmonic function, borrowing, and Roman numeral.\n *\n * The function is quality-aware (see the predicates behind it), the source\n * follows {@link borrowedSource}, and the numeral comes from\n * {@link chordToRoman}. `borrowed` is true whenever a source is identified —\n * including the Neapolitan, which the stricter parallel-mode predicate\n * {@link isBorrowedChord} does not count.\n *\n * @param chord The chord to analyze.\n * @param key The prevailing key.\n * @returns The chord analysis.\n * @example\n * ```ts\n * import { analyzeChord, makeChord, majorKey } from '@libraz/libcantus';\n * analyzeChord(makeChord(7, 'dom7'), majorKey(0));\n * // { function: 'dominant', borrowed: false, source: null, roman: 'V7' }\n * ```\n * @category Functional Harmony\n */\nexport function analyzeChord(chord: Chord, key: KeyScale): ChordAnalysis {\n const source = borrowedSource(chord, key);\n return {\n function: functionOf(chord, key),\n borrowed: source !== null,\n source,\n roman: chordToRoman(chord, key),\n };\n}\n\n/**\n * The secondary dominant (V7) that tonicizes a scale degree.\n *\n * @param targetDegree 0-based scale degree to tonicize, in 0..6.\n * @param key The prevailing key.\n * @returns A dominant-seventh chord a fifth above the target's root.\n * @throws If `targetDegree` is not an integer in 0..6.\n * @category Functional Harmony\n */\nexport function secondaryDominant(targetDegree: number, key: KeyScale): Chord {\n // A degree outside the scale is a caller error, not a wrap-around: silently\n // tonicizing some other degree produces a chord that reads as intentional.\n assertInteger(targetDegree, 'targetDegree', 0, 6);\n const targetRoot = degreeRootPc(targetDegree + 1, key);\n return makeChord(mod12(targetRoot + 7), 'dom7');\n}\n","/**\n * Cadence detection between two successive chords.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../../theory/chord/index.js';\nimport { isMinorKey } from './function.js';\nimport { mod12 } from './internal.js';\n\n/**\n * A recognized cadence type, or null when a chord pair forms none.\n *\n * @category Functional Harmony\n */\nexport type Cadence = 'authentic' | 'plagal' | 'half' | 'deceptive' | null;\n\n/**\n * Classify the cadence formed by moving from one chord to the next.\n *\n * - authentic: V (dominant a fifth above the tonic) to I\n * - plagal: IV (a fourth above the tonic) to I\n * - deceptive: V to the submediant (diatonic vi or borrowed bVI in major, VI in\n * minor)\n * - half: any chord other than the dominant itself to V\n *\n * A static V-to-V repeat with no root motion is not a cadence and yields null.\n *\n * @param from The penultimate chord.\n * @param to The final chord.\n * @param key The prevailing key.\n * @returns The cadence type, or null.\n * @example\n * ```ts\n * import { detectCadence, makeChord, majorKey } from '@libraz/libcantus';\n * detectCadence(makeChord(7, 'maj'), makeChord(0, 'maj'), majorKey(0)); // => 'authentic'\n * ```\n * @category Functional Harmony\n */\nexport function detectCadence(from: Chord, to: Chord, key: KeyScale): Cadence {\n const tonic = mod12(key.rootPc);\n const fromOffset = mod12(from.rootPc - tonic);\n const toOffset = mod12(to.rootPc - tonic);\n // Deceptive targets: the diatonic submediant (vi at offset 9 in major, VI at\n // offset 8 in minor) plus, in a major key, the borrowed flat-submediant bVI\n // at offset 8.\n const deceptiveTargets = isMinorKey(key) ? [8] : [8, 9];\n if (fromOffset === 7 && toOffset === 0) {\n return 'authentic';\n }\n if (fromOffset === 5 && toOffset === 0) {\n return 'plagal';\n }\n if (fromOffset === 7 && deceptiveTargets.includes(toOffset)) {\n return 'deceptive';\n }\n // A move to the dominant is a half cadence, but a no-root-motion V-to-V repeat\n // is not a cadence at all.\n if (toOffset === 7 && fromOffset !== 7) {\n return 'half';\n }\n return null;\n}\n"]}
|
package/dist/chunk-D2FAJBYL.js
DELETED
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
InvalidInputError,
|
|
3
|
-
assertFiniteNumber,
|
|
4
|
-
assertInteger,
|
|
5
|
-
isConsonantInterval,
|
|
6
|
-
pitchClassOf
|
|
7
|
-
} from "./chunk-XEBG3G53.js";
|
|
8
|
-
|
|
9
|
-
// src/theory/scale/degrees.ts
|
|
10
|
-
function scaleOffset(pitch, key) {
|
|
11
|
-
return (pitchClassOf(pitch) - pitchClassOf(key.rootPc) + 12) % 12;
|
|
12
|
-
}
|
|
13
|
-
function isScaleTone(pitch, key) {
|
|
14
|
-
return (key.modeMask12 >> scaleOffset(pitch, key) & 1) === 1;
|
|
15
|
-
}
|
|
16
|
-
function nearestScaleTone(pitch, key) {
|
|
17
|
-
const base = Math.round(pitch);
|
|
18
|
-
for (let distance = 0; distance < 12; distance += 1) {
|
|
19
|
-
const lower = base - distance;
|
|
20
|
-
if (isScaleTone(lower, key)) {
|
|
21
|
-
return lower;
|
|
22
|
-
}
|
|
23
|
-
const higher = base + distance;
|
|
24
|
-
if (isScaleTone(higher, key)) {
|
|
25
|
-
return higher;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return base;
|
|
29
|
-
}
|
|
30
|
-
function pitchToScaleDegree(pitch, key) {
|
|
31
|
-
const offset = scaleOffset(pitch, key);
|
|
32
|
-
if ((key.modeMask12 >> offset & 1) === 0) {
|
|
33
|
-
return -1;
|
|
34
|
-
}
|
|
35
|
-
let degree = 0;
|
|
36
|
-
for (let n = 0; n < offset; n += 1) {
|
|
37
|
-
if ((key.modeMask12 >> n & 1) === 1) {
|
|
38
|
-
degree += 1;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return degree;
|
|
42
|
-
}
|
|
43
|
-
function diatonicPitchClasses(key) {
|
|
44
|
-
const root = pitchClassOf(key.rootPc);
|
|
45
|
-
const pcs = [];
|
|
46
|
-
for (let n = 0; n < 12; n += 1) {
|
|
47
|
-
if ((key.modeMask12 >> n & 1) === 1) {
|
|
48
|
-
pcs.push((root + n) % 12);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return pcs.sort((a, b) => a - b);
|
|
52
|
-
}
|
|
53
|
-
function scaleTonesInDegreeOrder(key) {
|
|
54
|
-
const root = pitchClassOf(key.rootPc);
|
|
55
|
-
const pcs = [];
|
|
56
|
-
for (let n = 0; n < 12; n += 1) {
|
|
57
|
-
if ((key.modeMask12 >> n & 1) === 1) {
|
|
58
|
-
pcs.push((root + n) % 12);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return pcs;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// src/theory/scale/masks.ts
|
|
65
|
-
function maskFromOffsets(offsets) {
|
|
66
|
-
let mask = 1;
|
|
67
|
-
for (const offset of offsets) {
|
|
68
|
-
mask |= 1 << (offset % 12 + 12) % 12;
|
|
69
|
-
}
|
|
70
|
-
return mask;
|
|
71
|
-
}
|
|
72
|
-
var MAJOR_MASK = 2741;
|
|
73
|
-
var NATURAL_MINOR_MASK = 1453;
|
|
74
|
-
var HARMONIC_MINOR_MASK = maskFromOffsets([0, 2, 3, 5, 7, 8, 11]);
|
|
75
|
-
var MELODIC_MINOR_MASK = maskFromOffsets([0, 2, 3, 5, 7, 9, 11]);
|
|
76
|
-
var DORIAN_MASK = maskFromOffsets([0, 2, 3, 5, 7, 9, 10]);
|
|
77
|
-
var PHRYGIAN_MASK = maskFromOffsets([0, 1, 3, 5, 7, 8, 10]);
|
|
78
|
-
var LYDIAN_MASK = maskFromOffsets([0, 2, 4, 6, 7, 9, 11]);
|
|
79
|
-
var MIXOLYDIAN_MASK = maskFromOffsets([0, 2, 4, 5, 7, 9, 10]);
|
|
80
|
-
var LOCRIAN_MASK = maskFromOffsets([0, 1, 3, 5, 6, 8, 10]);
|
|
81
|
-
var MAJOR_PENTATONIC_MASK = maskFromOffsets([0, 2, 4, 7, 9]);
|
|
82
|
-
var MINOR_PENTATONIC_MASK = maskFromOffsets([0, 3, 5, 7, 10]);
|
|
83
|
-
var BLUES_MASK = maskFromOffsets([0, 3, 5, 6, 7, 10]);
|
|
84
|
-
var WHOLE_TONE_MASK = maskFromOffsets([0, 2, 4, 6, 8, 10]);
|
|
85
|
-
var OCTATONIC_HALF_WHOLE_MASK = maskFromOffsets([0, 1, 3, 4, 6, 7, 9, 10]);
|
|
86
|
-
var OCTATONIC_WHOLE_HALF_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 9, 11]);
|
|
87
|
-
var CHROMATIC_MASK = 4095;
|
|
88
|
-
var LYDIAN_DOMINANT_MASK = maskFromOffsets([0, 2, 4, 6, 7, 9, 10]);
|
|
89
|
-
var MIXOLYDIAN_B13_MASK = maskFromOffsets([0, 2, 4, 5, 7, 8, 10]);
|
|
90
|
-
var LOCRIAN_NATURAL2_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 10]);
|
|
91
|
-
var ALTERED_MASK = maskFromOffsets([0, 1, 3, 4, 6, 8, 10]);
|
|
92
|
-
var PHRYGIAN_DOMINANT_MASK = maskFromOffsets([0, 1, 4, 5, 7, 8, 10]);
|
|
93
|
-
var NAMED_SCALES = Object.freeze({
|
|
94
|
-
major: MAJOR_MASK,
|
|
95
|
-
ionian: MAJOR_MASK,
|
|
96
|
-
naturalMinor: NATURAL_MINOR_MASK,
|
|
97
|
-
aeolian: NATURAL_MINOR_MASK,
|
|
98
|
-
harmonicMinor: HARMONIC_MINOR_MASK,
|
|
99
|
-
melodicMinor: MELODIC_MINOR_MASK,
|
|
100
|
-
dorian: DORIAN_MASK,
|
|
101
|
-
phrygian: PHRYGIAN_MASK,
|
|
102
|
-
lydian: LYDIAN_MASK,
|
|
103
|
-
mixolydian: MIXOLYDIAN_MASK,
|
|
104
|
-
locrian: LOCRIAN_MASK,
|
|
105
|
-
lydianDominant: LYDIAN_DOMINANT_MASK,
|
|
106
|
-
mixolydianB13: MIXOLYDIAN_B13_MASK,
|
|
107
|
-
locrianNatural2: LOCRIAN_NATURAL2_MASK,
|
|
108
|
-
altered: ALTERED_MASK,
|
|
109
|
-
phrygianDominant: PHRYGIAN_DOMINANT_MASK,
|
|
110
|
-
majorPentatonic: MAJOR_PENTATONIC_MASK,
|
|
111
|
-
minorPentatonic: MINOR_PENTATONIC_MASK,
|
|
112
|
-
blues: BLUES_MASK,
|
|
113
|
-
wholeTone: WHOLE_TONE_MASK,
|
|
114
|
-
octatonicHalfWhole: OCTATONIC_HALF_WHOLE_MASK,
|
|
115
|
-
octatonicWholeHalf: OCTATONIC_WHOLE_HALF_MASK,
|
|
116
|
-
chromatic: CHROMATIC_MASK
|
|
117
|
-
});
|
|
118
|
-
function namedScaleMask(name) {
|
|
119
|
-
return Object.hasOwn(NAMED_SCALES, name) ? NAMED_SCALES[name] : void 0;
|
|
120
|
-
}
|
|
121
|
-
function requireScaleMask(name, label = "scale") {
|
|
122
|
-
const mask = namedScaleMask(name);
|
|
123
|
-
if (mask === void 0) {
|
|
124
|
-
throw new InvalidInputError(`Unknown ${label}: ${String(name)}`);
|
|
125
|
-
}
|
|
126
|
-
return mask;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// src/theory/scale/key.ts
|
|
130
|
-
function majorKey(rootPc) {
|
|
131
|
-
return { rootPc: (rootPc % 12 + 12) % 12, modeMask12: MAJOR_MASK };
|
|
132
|
-
}
|
|
133
|
-
function minorKey(rootPc) {
|
|
134
|
-
return { rootPc: (rootPc % 12 + 12) % 12, modeMask12: NATURAL_MINOR_MASK };
|
|
135
|
-
}
|
|
136
|
-
function scaleByName(name, rootPc) {
|
|
137
|
-
return { rootPc: (rootPc % 12 + 12) % 12, modeMask12: requireScaleMask(name) };
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// src/theory/chord/index.ts
|
|
141
|
-
var QUALITY_INTERVALS = {
|
|
142
|
-
maj: [0, 4, 7],
|
|
143
|
-
min: [0, 3, 7],
|
|
144
|
-
dim: [0, 3, 6],
|
|
145
|
-
aug: [0, 4, 8],
|
|
146
|
-
majb5: [0, 4, 6],
|
|
147
|
-
maj7: [0, 4, 7, 11],
|
|
148
|
-
min7: [0, 3, 7, 10],
|
|
149
|
-
dom7: [0, 4, 7, 10],
|
|
150
|
-
dim7: [0, 3, 6, 9],
|
|
151
|
-
m7b5: [0, 3, 6, 10],
|
|
152
|
-
minMaj7: [0, 3, 7, 11],
|
|
153
|
-
aug7: [0, 4, 8, 10],
|
|
154
|
-
augMaj7: [0, 4, 8, 11],
|
|
155
|
-
"6": [0, 4, 7, 9],
|
|
156
|
-
min6: [0, 3, 7, 9],
|
|
157
|
-
"6/9": [0, 4, 7, 9, 14],
|
|
158
|
-
sus2: [0, 2, 7],
|
|
159
|
-
sus4: [0, 5, 7],
|
|
160
|
-
add9: [0, 4, 7, 14],
|
|
161
|
-
add11: [0, 4, 7, 17],
|
|
162
|
-
maj9: [0, 4, 7, 11, 14],
|
|
163
|
-
min9: [0, 3, 7, 10, 14],
|
|
164
|
-
dom9: [0, 4, 7, 10, 14],
|
|
165
|
-
"7b9": [0, 4, 7, 10, 13],
|
|
166
|
-
"7#9": [0, 4, 7, 10, 15],
|
|
167
|
-
"7#11": [0, 4, 7, 10, 18],
|
|
168
|
-
"7b13": [0, 4, 7, 10, 20],
|
|
169
|
-
"11": [0, 7, 10, 14, 17],
|
|
170
|
-
"13": [0, 4, 7, 10, 14, 21],
|
|
171
|
-
"5": [0, 7],
|
|
172
|
-
"7sus4": [0, 5, 7, 10],
|
|
173
|
-
"7b5": [0, 4, 6, 10],
|
|
174
|
-
// The altered dominant as it is voiced from a lead sheet: a dominant seventh
|
|
175
|
-
// with a raised fifth and a raised ninth. The full seven-note altered stack
|
|
176
|
-
// has no seven-letter spelling, so it is not what this symbol denotes.
|
|
177
|
-
"7alt": [0, 4, 8, 10, 15],
|
|
178
|
-
"13b9": [0, 4, 7, 10, 13, 21],
|
|
179
|
-
maj13: [0, 4, 7, 11, 14, 21],
|
|
180
|
-
"maj7#11": [0, 4, 7, 11, 18],
|
|
181
|
-
min11: [0, 3, 7, 10, 14, 17],
|
|
182
|
-
min13: [0, 3, 7, 10, 14, 21],
|
|
183
|
-
minAdd9: [0, 3, 7, 14],
|
|
184
|
-
"min6/9": [0, 3, 7, 9, 14]
|
|
185
|
-
};
|
|
186
|
-
function chordQualities() {
|
|
187
|
-
return Object.keys(QUALITY_INTERVALS);
|
|
188
|
-
}
|
|
189
|
-
function chordFromDegree(degree, ext, key) {
|
|
190
|
-
assertInteger(degree, "chord degree", -1e3, 1e3);
|
|
191
|
-
if (!Object.hasOwn(QUALITY_INTERVALS, ext)) {
|
|
192
|
-
throw new InvalidInputError(`Unknown chord quality: ${String(ext)}`);
|
|
193
|
-
}
|
|
194
|
-
const tones = scaleTonesInDegreeOrder(key);
|
|
195
|
-
const length = tones.length;
|
|
196
|
-
const index = length > 0 ? (degree % length + length) % length : 0;
|
|
197
|
-
const rootPc = tones[index] ?? pitchClassOf(key.rootPc);
|
|
198
|
-
return { rootPc, quality: ext, intervals: [...QUALITY_INTERVALS[ext]] };
|
|
199
|
-
}
|
|
200
|
-
function makeChord(rootPc, quality, bassPc) {
|
|
201
|
-
assertFiniteNumber(rootPc, "chord rootPc");
|
|
202
|
-
if (bassPc !== void 0) {
|
|
203
|
-
assertFiniteNumber(bassPc, "chord bassPc");
|
|
204
|
-
}
|
|
205
|
-
if (!Object.hasOwn(QUALITY_INTERVALS, quality)) {
|
|
206
|
-
throw new InvalidInputError(`Unknown chord quality: ${String(quality)}`);
|
|
207
|
-
}
|
|
208
|
-
const chord = {
|
|
209
|
-
rootPc: pitchClassOf(rootPc),
|
|
210
|
-
quality,
|
|
211
|
-
intervals: [...QUALITY_INTERVALS[quality] ?? []]
|
|
212
|
-
};
|
|
213
|
-
if (bassPc !== void 0) {
|
|
214
|
-
chord.bassPc = pitchClassOf(bassPc);
|
|
215
|
-
}
|
|
216
|
-
return chord;
|
|
217
|
-
}
|
|
218
|
-
function transposeChord(chord, semitones) {
|
|
219
|
-
assertFiniteNumber(semitones, "semitones");
|
|
220
|
-
const steps = Math.round(semitones);
|
|
221
|
-
const moved = {
|
|
222
|
-
rootPc: pitchClassOf(chord.rootPc + steps),
|
|
223
|
-
quality: chord.quality,
|
|
224
|
-
intervals: [...chord.intervals]
|
|
225
|
-
};
|
|
226
|
-
if (chord.bassPc !== void 0) {
|
|
227
|
-
moved.bassPc = pitchClassOf(chord.bassPc + steps);
|
|
228
|
-
}
|
|
229
|
-
return moved;
|
|
230
|
-
}
|
|
231
|
-
function chordPitchClasses(chord, opts = {}) {
|
|
232
|
-
const set = /* @__PURE__ */ new Set();
|
|
233
|
-
for (const interval of chord.intervals) {
|
|
234
|
-
set.add(pitchClassOf(chord.rootPc + interval));
|
|
235
|
-
}
|
|
236
|
-
if (opts.includeBass !== false && chord.bassPc !== void 0) {
|
|
237
|
-
set.add(pitchClassOf(chord.bassPc));
|
|
238
|
-
}
|
|
239
|
-
return [...set].sort((a, b) => a - b);
|
|
240
|
-
}
|
|
241
|
-
function intervalAboveRoot(pitch, chord) {
|
|
242
|
-
return ((pitchClassOf(pitch) - pitchClassOf(chord.rootPc)) % 12 + 12) % 12;
|
|
243
|
-
}
|
|
244
|
-
function isChordMember(pitch, chord) {
|
|
245
|
-
return chord === null ? false : chordPitchClasses(chord).includes(pitchClassOf(pitch));
|
|
246
|
-
}
|
|
247
|
-
function chordToneOffsets(chord) {
|
|
248
|
-
return new Set(chord.intervals.map((i) => (i % 12 + 12) % 12));
|
|
249
|
-
}
|
|
250
|
-
function chordToneRole(pitch, chord) {
|
|
251
|
-
const interval = (pitchClassOf(pitch) - pitchClassOf(chord.rootPc) + 12) % 12;
|
|
252
|
-
const tones = chordToneOffsets(chord);
|
|
253
|
-
if (interval === 0) {
|
|
254
|
-
return "root";
|
|
255
|
-
}
|
|
256
|
-
if (interval === 3 || interval === 4) {
|
|
257
|
-
return tones.has(interval) ? "third" : null;
|
|
258
|
-
}
|
|
259
|
-
if (interval === 7) {
|
|
260
|
-
return tones.has(7) ? "fifth" : null;
|
|
261
|
-
}
|
|
262
|
-
if (interval === 6) {
|
|
263
|
-
return tones.has(6) && !tones.has(7) ? "fifth" : null;
|
|
264
|
-
}
|
|
265
|
-
if (interval === 8) {
|
|
266
|
-
return tones.has(8) && !tones.has(7) ? "fifth" : null;
|
|
267
|
-
}
|
|
268
|
-
if (interval === 9) {
|
|
269
|
-
const hasHigherSeventh = tones.has(10) || tones.has(11);
|
|
270
|
-
const isDiminishedSeventh = tones.has(3) && tones.has(6) && !hasHigherSeventh;
|
|
271
|
-
if (isDiminishedSeventh) {
|
|
272
|
-
return "seventh";
|
|
273
|
-
}
|
|
274
|
-
if (tones.has(9) && !hasHigherSeventh) {
|
|
275
|
-
return "sixth";
|
|
276
|
-
}
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
if (interval === 10 || interval === 11) {
|
|
280
|
-
return tones.has(interval) ? "seventh" : null;
|
|
281
|
-
}
|
|
282
|
-
return null;
|
|
283
|
-
}
|
|
284
|
-
function classifyTriad(thirdIc, fifthIc) {
|
|
285
|
-
if (thirdIc === 4 && fifthIc === 8) {
|
|
286
|
-
return "aug";
|
|
287
|
-
}
|
|
288
|
-
if (thirdIc === 4 && fifthIc === 6) {
|
|
289
|
-
return "majb5";
|
|
290
|
-
}
|
|
291
|
-
if (thirdIc === 3 && fifthIc === 6) {
|
|
292
|
-
return "dim";
|
|
293
|
-
}
|
|
294
|
-
if (thirdIc === 3) {
|
|
295
|
-
return "min";
|
|
296
|
-
}
|
|
297
|
-
return "maj";
|
|
298
|
-
}
|
|
299
|
-
function classifySeventh(thirdIc, fifthIc, seventhIc) {
|
|
300
|
-
if (thirdIc === 3 && fifthIc === 6 && seventhIc === 9) {
|
|
301
|
-
return "dim7";
|
|
302
|
-
}
|
|
303
|
-
if (thirdIc === 3 && fifthIc === 6 && seventhIc === 10) {
|
|
304
|
-
return "m7b5";
|
|
305
|
-
}
|
|
306
|
-
if (thirdIc === 3 && seventhIc === 11) {
|
|
307
|
-
return "minMaj7";
|
|
308
|
-
}
|
|
309
|
-
if (thirdIc === 3) {
|
|
310
|
-
return "min7";
|
|
311
|
-
}
|
|
312
|
-
if (fifthIc === 8 && seventhIc === 10) {
|
|
313
|
-
return "aug7";
|
|
314
|
-
}
|
|
315
|
-
if (fifthIc === 8 && seventhIc === 11) {
|
|
316
|
-
return "augMaj7";
|
|
317
|
-
}
|
|
318
|
-
if (seventhIc === 11) {
|
|
319
|
-
return "maj7";
|
|
320
|
-
}
|
|
321
|
-
return "dom7";
|
|
322
|
-
}
|
|
323
|
-
function stackThirds(degree, key, size) {
|
|
324
|
-
const tones = scaleTonesInDegreeOrder(key);
|
|
325
|
-
const length = tones.length;
|
|
326
|
-
if (length !== 7) {
|
|
327
|
-
throw new InvalidInputError(
|
|
328
|
-
`diatonic chord stacking requires a heptatonic scale (received ${length} tones)`
|
|
329
|
-
);
|
|
330
|
-
}
|
|
331
|
-
const idx = (step) => ((degree + step) % length + length) % length;
|
|
332
|
-
const rootPc = tones[idx(0)] ?? pitchClassOf(key.rootPc);
|
|
333
|
-
const offsets = [0, 2, 4, 6].slice(0, size).map((step) => {
|
|
334
|
-
const pc = tones[idx(step)] ?? rootPc;
|
|
335
|
-
return ((pc - rootPc) % 12 + 12) % 12;
|
|
336
|
-
});
|
|
337
|
-
const thirdIc = offsets[1] ?? 4;
|
|
338
|
-
const fifthIc = offsets[2] ?? 7;
|
|
339
|
-
const quality = size === 3 ? classifyTriad(thirdIc, fifthIc) : classifySeventh(thirdIc, fifthIc, offsets[3] ?? 11);
|
|
340
|
-
return { rootPc, quality, intervals: offsets };
|
|
341
|
-
}
|
|
342
|
-
function diatonicTriad(degree, key) {
|
|
343
|
-
return stackThirds(degree, key, 3);
|
|
344
|
-
}
|
|
345
|
-
function diatonicSeventh(degree, key) {
|
|
346
|
-
return stackThirds(degree, key, 4);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// src/theory/counterpoint/index.ts
|
|
350
|
-
function createsVoiceCrossing(upperPitch, lowerPitch) {
|
|
351
|
-
return upperPitch < lowerPitch;
|
|
352
|
-
}
|
|
353
|
-
function createsVerticalDissonance(a, b, twoVoice) {
|
|
354
|
-
return !isConsonantInterval(a - b, twoVoice);
|
|
355
|
-
}
|
|
356
|
-
function isForbiddenMelodicLeap(prev, cur) {
|
|
357
|
-
const semis = Math.abs(cur - prev);
|
|
358
|
-
return semis === 6 || semis === 10 || semis === 11 || semis > 12;
|
|
359
|
-
}
|
|
360
|
-
function simpleClass(semitones) {
|
|
361
|
-
return Math.abs(semitones) % 12;
|
|
362
|
-
}
|
|
363
|
-
function isPerfectClass(cls) {
|
|
364
|
-
return cls === 0 || cls === 7;
|
|
365
|
-
}
|
|
366
|
-
function similarMotion(aMove, bMove) {
|
|
367
|
-
return aMove !== 0 && bMove !== 0 && aMove > 0 === bMove > 0;
|
|
368
|
-
}
|
|
369
|
-
function bothVoicesMove(aMove, bMove) {
|
|
370
|
-
return aMove !== 0 && bMove !== 0;
|
|
371
|
-
}
|
|
372
|
-
function createsParallelPerfect(aPrev, aCur, bPrev, bCur) {
|
|
373
|
-
if (!bothVoicesMove(aCur - aPrev, bCur - bPrev)) {
|
|
374
|
-
return false;
|
|
375
|
-
}
|
|
376
|
-
const nowClass = simpleClass(aCur - bCur);
|
|
377
|
-
const prevClass = simpleClass(aPrev - bPrev);
|
|
378
|
-
return isPerfectClass(nowClass) && nowClass === prevClass;
|
|
379
|
-
}
|
|
380
|
-
function createsParallelOctave(aPrev, aCur, bPrev, bCur) {
|
|
381
|
-
if (!similarMotion(aCur - aPrev, bCur - bPrev)) {
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
return simpleClass(aCur - bCur) === 0 && simpleClass(aPrev - bPrev) === 0;
|
|
385
|
-
}
|
|
386
|
-
function createsParallelUnison(aPrev, aCur, bPrev, bCur) {
|
|
387
|
-
if (aCur === aPrev || bCur === bPrev) {
|
|
388
|
-
return false;
|
|
389
|
-
}
|
|
390
|
-
return aCur === bCur && aPrev === bPrev;
|
|
391
|
-
}
|
|
392
|
-
function createsHiddenParallelPerfect(aPrev, aCur, bPrev, bCur) {
|
|
393
|
-
const aMove = aCur - aPrev;
|
|
394
|
-
const bMove = bCur - bPrev;
|
|
395
|
-
if (!similarMotion(aMove, bMove)) {
|
|
396
|
-
return false;
|
|
397
|
-
}
|
|
398
|
-
const nowClass = simpleClass(aCur - bCur);
|
|
399
|
-
const prevClass = simpleClass(aPrev - bPrev);
|
|
400
|
-
if (!isPerfectClass(nowClass) || prevClass === nowClass) {
|
|
401
|
-
return false;
|
|
402
|
-
}
|
|
403
|
-
const upperMove = aCur >= bCur ? aMove : bMove;
|
|
404
|
-
if (Math.abs(upperMove) <= 2) {
|
|
405
|
-
return false;
|
|
406
|
-
}
|
|
407
|
-
return true;
|
|
408
|
-
}
|
|
409
|
-
function createsVoiceOverlap(upperPrev, upperCur, lowerPrev, lowerCur) {
|
|
410
|
-
return upperCur < lowerPrev || lowerCur > upperPrev;
|
|
411
|
-
}
|
|
412
|
-
function exceedsSpacing(upperPitch, lowerPitch, maxSemitones = 12) {
|
|
413
|
-
return Math.abs(upperPitch - lowerPitch) > maxSemitones;
|
|
414
|
-
}
|
|
415
|
-
function isLeadingToneResolution(prev, cur, key) {
|
|
416
|
-
const tonic = pitchClassOf(key.rootPc);
|
|
417
|
-
const leading = (tonic + 11) % 12;
|
|
418
|
-
if (pitchClassOf(prev) !== leading || pitchClassOf(cur) !== tonic) {
|
|
419
|
-
return false;
|
|
420
|
-
}
|
|
421
|
-
return cur > prev && cur - prev <= 2;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
export {
|
|
425
|
-
isScaleTone,
|
|
426
|
-
nearestScaleTone,
|
|
427
|
-
pitchToScaleDegree,
|
|
428
|
-
diatonicPitchClasses,
|
|
429
|
-
scaleTonesInDegreeOrder,
|
|
430
|
-
maskFromOffsets,
|
|
431
|
-
MAJOR_MASK,
|
|
432
|
-
NATURAL_MINOR_MASK,
|
|
433
|
-
HARMONIC_MINOR_MASK,
|
|
434
|
-
MELODIC_MINOR_MASK,
|
|
435
|
-
DORIAN_MASK,
|
|
436
|
-
PHRYGIAN_MASK,
|
|
437
|
-
LYDIAN_MASK,
|
|
438
|
-
MIXOLYDIAN_MASK,
|
|
439
|
-
LOCRIAN_MASK,
|
|
440
|
-
MAJOR_PENTATONIC_MASK,
|
|
441
|
-
MINOR_PENTATONIC_MASK,
|
|
442
|
-
BLUES_MASK,
|
|
443
|
-
WHOLE_TONE_MASK,
|
|
444
|
-
OCTATONIC_HALF_WHOLE_MASK,
|
|
445
|
-
OCTATONIC_WHOLE_HALF_MASK,
|
|
446
|
-
CHROMATIC_MASK,
|
|
447
|
-
LYDIAN_DOMINANT_MASK,
|
|
448
|
-
MIXOLYDIAN_B13_MASK,
|
|
449
|
-
LOCRIAN_NATURAL2_MASK,
|
|
450
|
-
ALTERED_MASK,
|
|
451
|
-
PHRYGIAN_DOMINANT_MASK,
|
|
452
|
-
NAMED_SCALES,
|
|
453
|
-
namedScaleMask,
|
|
454
|
-
requireScaleMask,
|
|
455
|
-
majorKey,
|
|
456
|
-
minorKey,
|
|
457
|
-
scaleByName,
|
|
458
|
-
chordQualities,
|
|
459
|
-
chordFromDegree,
|
|
460
|
-
makeChord,
|
|
461
|
-
transposeChord,
|
|
462
|
-
chordPitchClasses,
|
|
463
|
-
intervalAboveRoot,
|
|
464
|
-
isChordMember,
|
|
465
|
-
chordToneRole,
|
|
466
|
-
diatonicTriad,
|
|
467
|
-
diatonicSeventh,
|
|
468
|
-
createsVoiceCrossing,
|
|
469
|
-
createsVerticalDissonance,
|
|
470
|
-
isForbiddenMelodicLeap,
|
|
471
|
-
createsParallelPerfect,
|
|
472
|
-
createsParallelOctave,
|
|
473
|
-
createsParallelUnison,
|
|
474
|
-
createsHiddenParallelPerfect,
|
|
475
|
-
createsVoiceOverlap,
|
|
476
|
-
exceedsSpacing,
|
|
477
|
-
isLeadingToneResolution
|
|
478
|
-
};
|
|
479
|
-
//# sourceMappingURL=chunk-D2FAJBYL.js.map
|