@libraz/libcantus 0.9.4 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +27 -18
  2. package/README_ja.md +268 -0
  3. package/dist/analyze/index.cjs +7 -7
  4. package/dist/analyze/index.d.cts +9 -99
  5. package/dist/analyze/index.d.ts +9 -99
  6. package/dist/analyze/index.js +6 -6
  7. package/dist/{chunk-36N73KZ3.cjs → chunk-2A2QMA74.cjs} +80 -65
  8. package/dist/chunk-2A2QMA74.cjs.map +1 -0
  9. package/dist/{chunk-YLEMGEFH.js → chunk-2PTFGVD7.js} +50 -35
  10. package/dist/chunk-2PTFGVD7.js.map +1 -0
  11. package/dist/{chunk-ZEJR4TKL.cjs → chunk-357ZDPVU.cjs} +36 -47
  12. package/dist/chunk-357ZDPVU.cjs.map +1 -0
  13. package/dist/{chunk-EHVEBWM5.js → chunk-3KX76RLG.js} +136 -37
  14. package/dist/chunk-3KX76RLG.js.map +1 -0
  15. package/dist/{chunk-RC6GBMCD.cjs → chunk-4VZ5MZAM.cjs} +155 -111
  16. package/dist/chunk-4VZ5MZAM.cjs.map +1 -0
  17. package/dist/{chunk-RK35RIN7.js → chunk-7EONYVI5.js} +115 -28
  18. package/dist/chunk-7EONYVI5.js.map +1 -0
  19. package/dist/{chunk-GQSGS2N4.js → chunk-7JEP3MFY.js} +5 -16
  20. package/dist/chunk-7JEP3MFY.js.map +1 -0
  21. package/dist/{chunk-7NKDPF74.js → chunk-AID75RN3.js} +203 -104
  22. package/dist/chunk-AID75RN3.js.map +1 -0
  23. package/dist/{chunk-FNDWXRRI.cjs → chunk-BSLTLGM3.cjs} +55 -37
  24. package/dist/chunk-BSLTLGM3.cjs.map +1 -0
  25. package/dist/{chunk-NP4NA2FB.cjs → chunk-CU6VG2YM.cjs} +39 -36
  26. package/dist/chunk-CU6VG2YM.cjs.map +1 -0
  27. package/dist/{chunk-NYYWMV2C.js → chunk-DZMHIGI4.js} +27 -17
  28. package/dist/chunk-DZMHIGI4.js.map +1 -0
  29. package/dist/{chunk-I24MV65U.js → chunk-EDOTEABK.js} +18 -15
  30. package/dist/{chunk-I24MV65U.js.map → chunk-EDOTEABK.js.map} +1 -1
  31. package/dist/{chunk-NKIBQ6PT.js → chunk-HN2OEUN2.js} +7 -4
  32. package/dist/chunk-HN2OEUN2.js.map +1 -0
  33. package/dist/{chunk-D2FAJBYL.js → chunk-KBTTEX7Q.js} +30 -12
  34. package/dist/chunk-KBTTEX7Q.js.map +1 -0
  35. package/dist/{chunk-CAN76NCU.cjs → chunk-KQN2ZYND.cjs} +147 -102
  36. package/dist/chunk-KQN2ZYND.cjs.map +1 -0
  37. package/dist/{chunk-4HLLZPXT.cjs → chunk-MPTVJIVG.cjs} +350 -251
  38. package/dist/chunk-MPTVJIVG.cjs.map +1 -0
  39. package/dist/{chunk-RUMU3UA6.cjs → chunk-MTMZTMWM.cjs} +12 -12
  40. package/dist/{chunk-RUMU3UA6.cjs.map → chunk-MTMZTMWM.cjs.map} +1 -1
  41. package/dist/{chunk-KMHOICIY.js → chunk-NNB67XA2.js} +90 -45
  42. package/dist/chunk-NNB67XA2.js.map +1 -0
  43. package/dist/{chunk-LW53AHQU.cjs → chunk-OL3IHHSJ.cjs} +228 -141
  44. package/dist/chunk-OL3IHHSJ.cjs.map +1 -0
  45. package/dist/{chunk-7MGZ7D62.cjs → chunk-PI3UXRWK.cjs} +43 -13
  46. package/dist/chunk-PI3UXRWK.cjs.map +1 -0
  47. package/dist/{chunk-XEBG3G53.js → chunk-R2VVFAIN.js} +42 -12
  48. package/dist/chunk-R2VVFAIN.js.map +1 -0
  49. package/dist/{chunk-Q6OP4U43.cjs → chunk-WFDXOLUB.cjs} +50 -40
  50. package/dist/chunk-WFDXOLUB.cjs.map +1 -0
  51. package/dist/{chunk-NVE34YGZ.cjs → chunk-WTAN4ACG.cjs} +212 -113
  52. package/dist/chunk-WTAN4ACG.cjs.map +1 -0
  53. package/dist/{chunk-FCANXBAT.cjs → chunk-YFJXS3AU.cjs} +8 -5
  54. package/dist/chunk-YFJXS3AU.cjs.map +1 -0
  55. package/dist/{chunk-Q2XUP227.js → chunk-YUE6TJ4M.js} +89 -45
  56. package/dist/chunk-YUE6TJ4M.js.map +1 -0
  57. package/dist/{chunk-HKGYCQ34.js → chunk-ZGLJM4A4.js} +2 -2
  58. package/dist/core/index.cjs +15 -5
  59. package/dist/core/index.cjs.map +1 -1
  60. package/dist/core/index.d.cts +14 -4
  61. package/dist/core/index.d.ts +14 -4
  62. package/dist/core/index.js +14 -4
  63. package/dist/{function-DNugAOrt.d.cts → function-CxixTB02.d.cts} +98 -7
  64. package/dist/{function-BtiZb9i9.d.ts → function-DTCt675z.d.ts} +98 -7
  65. package/dist/generate/index.cjs +10 -10
  66. package/dist/generate/index.d.cts +21 -21
  67. package/dist/generate/index.d.ts +21 -21
  68. package/dist/generate/index.js +9 -9
  69. package/dist/{index-tJhkmQgE.d.cts → index-B2Ulxxpo.d.cts} +3 -2
  70. package/dist/{index-Be74mcon.d.cts → index-BkYJ0xMq.d.cts} +2 -2
  71. package/dist/{index-6VR8-kit.d.ts → index-BuaB-ypt.d.ts} +3 -2
  72. package/dist/{index-70p168VM.d.ts → index-CAN7v-kw.d.ts} +9 -2
  73. package/dist/{index-C83mZI1P.d.ts → index-COw1Ky9g.d.ts} +1 -1
  74. package/dist/{index-tSQh-xwY.d.ts → index-Cfx8xgH0.d.ts} +1 -1
  75. package/dist/{index-C5UBbQ4G.d.ts → index-DRtIhlJj.d.ts} +2 -2
  76. package/dist/{index-BtXT6UQ0.d.cts → index-alrRninU.d.cts} +9 -2
  77. package/dist/{index-y_ak9_Hi.d.cts → index-oTQbYYIs.d.cts} +1 -1
  78. package/dist/{index-OG65ocOr.d.ts → index-tR9jTn26.d.cts} +4 -1
  79. package/dist/{index-OG65ocOr.d.cts → index-tR9jTn26.d.ts} +4 -1
  80. package/dist/{index-D6b6na69.d.cts → index-x2vcsduE.d.cts} +1 -1
  81. package/dist/index.cjs +24 -14
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.cts +11 -11
  84. package/dist/index.d.ts +11 -11
  85. package/dist/index.js +23 -13
  86. package/dist/model/index.cjs +7 -7
  87. package/dist/model/index.d.cts +48 -16
  88. package/dist/model/index.d.ts +48 -16
  89. package/dist/model/index.js +6 -6
  90. package/dist/{styled-DIRkk9Uz.d.ts → styled-Bl0ZK28h.d.ts} +40 -3
  91. package/dist/{styled-DJbkJQfj.d.cts → styled-Crv6SA4S.d.cts} +40 -3
  92. package/dist/theory/index.cjs +6 -6
  93. package/dist/theory/index.d.cts +9 -9
  94. package/dist/theory/index.d.ts +9 -9
  95. package/dist/theory/index.js +5 -5
  96. package/package.json +12 -9
  97. package/dist/chunk-36N73KZ3.cjs.map +0 -1
  98. package/dist/chunk-4HLLZPXT.cjs.map +0 -1
  99. package/dist/chunk-7MGZ7D62.cjs.map +0 -1
  100. package/dist/chunk-7NKDPF74.js.map +0 -1
  101. package/dist/chunk-CAN76NCU.cjs.map +0 -1
  102. package/dist/chunk-D2FAJBYL.js.map +0 -1
  103. package/dist/chunk-EHVEBWM5.js.map +0 -1
  104. package/dist/chunk-FCANXBAT.cjs.map +0 -1
  105. package/dist/chunk-FNDWXRRI.cjs.map +0 -1
  106. package/dist/chunk-GQSGS2N4.js.map +0 -1
  107. package/dist/chunk-KMHOICIY.js.map +0 -1
  108. package/dist/chunk-LW53AHQU.cjs.map +0 -1
  109. package/dist/chunk-NKIBQ6PT.js.map +0 -1
  110. package/dist/chunk-NP4NA2FB.cjs.map +0 -1
  111. package/dist/chunk-NVE34YGZ.cjs.map +0 -1
  112. package/dist/chunk-NYYWMV2C.js.map +0 -1
  113. package/dist/chunk-Q2XUP227.js.map +0 -1
  114. package/dist/chunk-Q6OP4U43.cjs.map +0 -1
  115. package/dist/chunk-RC6GBMCD.cjs.map +0 -1
  116. package/dist/chunk-RK35RIN7.js.map +0 -1
  117. package/dist/chunk-XEBG3G53.js.map +0 -1
  118. package/dist/chunk-YLEMGEFH.js.map +0 -1
  119. package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
  120. /package/dist/{chunk-HKGYCQ34.js.map → chunk-ZGLJM4A4.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theory/chordscale/index.ts","../src/theory/spelling/index.ts","../src/theory/symbol/index.ts","../src/theory/voicing/internal.ts","../src/theory/voicing/leading.ts","../src/theory/voicing/satb.ts","../src/theory/voicing/styled.ts"],"sourcesContent":["import { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\nimport { assertGenerationBudget, assertPositiveInt } from '../../core/validation/index.js';\nimport type { Chord } from '../chord/index.js';\nimport { chordPitchClasses } from '../chord/index.js';\nimport type { ScaleNameInput } from '../scale/index.js';\nimport { NAMED_SCALES, namedScaleMask, requireScaleMask } from '../scale/index.js';\n\n/** Count the set bits (scale tones) in a 12-bit mode mask. */\nfunction popcount12(mask: number): number {\n let count = 0;\n for (let n = 0; n < 12; n += 1) {\n count += (mask >> n) & 1;\n }\n return count;\n}\n\n/** Test whether a pitch class belongs to a mode mask rooted on `scaleRootPc`. */\nfunction maskHasPitchClass(mask: number, scaleRootPc: number, pc: number): boolean {\n const offset = pitchClass(pc - scaleRootPc);\n return ((mask >> offset) & 1) === 1;\n}\n\n/**\n * Test whether every chord pitch class is contained in a scale.\n *\n * @param chordPcs The chord's pitch classes (0..11).\n * @param scaleMask The scale's 12-bit mode mask.\n * @param scaleRootPc The pitch class the mask is rooted on.\n * @returns True if the scale is a superset of the chord.\n *\n * @category Scales\n */\nexport function scaleMatchesChord(\n chordPcs: number[],\n scaleMask: number,\n scaleRootPc: number,\n): boolean {\n for (const pc of chordPcs) {\n if (!maskHasPitchClass(scaleMask, scaleRootPc, pc)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * A named scale rooted on a pitch class that fits over a chord.\n *\n * @category Scales\n */\nexport type ChordScaleMatch = {\n name: string;\n rootPc: number;\n};\n\n/**\n * Scale names whose mask duplicates another {@link NAMED_SCALES} entry\n * (major/ionian, naturalMinor/aeolian). Chord-scale analysis conventionally\n * speaks in mode names, so these aliases are skipped and only the modal name\n * is reported.\n */\nconst ALIASED_SCALE_NAMES = new Set(['major', 'naturalMinor']);\n\n/** Number of tones in a heptatonic (seven-note) scale. */\nconst HEPTATONIC_SIZE = 7;\n\n/**\n * Conventional preference among equally-fitting scales, brightest first.\n *\n * Several modes fit a chord that states no third or sixth — a power chord, a\n * suspension — equally well. Alphabetical order made `aeolian` the answer for\n * those, naming a minor mode as the best fit for a mode-neutral chord.\n */\nconst SCALE_PREFERENCE = [\n 'ionian',\n 'major',\n 'mixolydian',\n 'dorian',\n 'lydian',\n 'aeolian',\n 'naturalMinor',\n 'phrygian',\n 'locrian',\n] as const;\n\n/** Conventional first choices that pure set-fit ranking cannot express. */\nconst IDIOMATIC_SCALES: Partial<Record<Chord['quality'], readonly string[]>> = {\n aug: ['wholeTone'],\n m7b5: ['locrian'],\n};\n\n/** Position of a scale in {@link SCALE_PREFERENCE}, or last when unlisted. */\nfunction conventionalRank(name: string): number {\n const index = (SCALE_PREFERENCE as readonly string[]).indexOf(name);\n return index < 0 ? SCALE_PREFERENCE.length : index;\n}\n\n/** Whether this scale is an idiomatic color choice for the chord quality. */\nfunction idiomaticRank(chord: Chord, name: string): number {\n const choices = IDIOMATIC_SCALES[chord.quality];\n if (choices === undefined) {\n return 0;\n }\n const index = choices.indexOf(name);\n return index < 0 ? choices.length + 1 : index;\n}\n\n/**\n * An ordinary dominant seventh may use altered colors while retaining its\n * perfect fifth in the voicing; the `7alt` quality makes that alteration\n * explicit, but lead sheets commonly write the shorter `7` here.\n */\nfunction isAlteredDominant(chord: Chord, scaleName: string): boolean {\n return chord.quality === 'dom7' && scaleName === 'altered';\n}\n\n/**\n * List the scales that fit over a chord, best fit first.\n *\n * Only the chord root is considered as the scale root, matching the\n * conventional chord-scale relationship. Every entry of {@link NAMED_SCALES}\n * whose pitch-class set is a superset of the chord's is returned once per\n * distinct pitch-class set (aliased masks such as major/ionian report only the\n * modal name), ranked by fewest extra scale tones beyond the chord and then by\n * conventional\n * preference. For bare triads and smaller chords, heptatonic scales rank before\n * pentatonics and other sizes: a pentatonic adds no modal color over a triad,\n * so the seven-note modes are the more useful answer. The chromatic scale is\n * only returned as a fallback when no other scale contains the chord.\n *\n * The ranking is by fit, so the first entry is the tightest-fitting scale\n * rather than the idiomatic choice: a four-note chord that a pentatonic covers\n * exactly puts that pentatonic ahead of the mode a player would name. Read the\n * whole list, or pick by name, when the idiomatic scale is what is wanted;\n * {@link scalesForChanges} makes that choice for a progression.\n *\n * @param chord The chord to fit scales over.\n * @returns The matching scales rooted on the chord root, best fit first.\n *\n * @example\n * ```ts\n * import { makeChord, chordScales } from '@libraz/libcantus';\n * const scales = chordScales(makeChord(0, 'maj7'));\n * // scales for Cmaj7, best fit first; each is { name, rootPc: 0 }\n * ```\n *\n * @category Scales\n */\nexport function chordScales(chord: Chord): ChordScaleMatch[] {\n const chordPcs = chordPitchClasses(chord);\n const rootPc = pitchClass(chord.rootPc);\n const ranked: { name: string; extra: number; size: number }[] = [];\n const seenMasks = new Set<number>();\n for (const name of Object.keys(NAMED_SCALES)) {\n if (name === 'chromatic' || ALIASED_SCALE_NAMES.has(name)) {\n continue;\n }\n const mask = namedScaleMask(name);\n if (mask === undefined || seenMasks.has(mask)) {\n continue;\n }\n seenMasks.add(mask);\n if (scaleMatchesChord(chordPcs, mask, rootPc) || isAlteredDominant(chord, name)) {\n const size = popcount12(mask);\n ranked.push({ name, extra: size - chordPcs.length, size });\n }\n }\n if (ranked.length === 0) {\n // No diatonic-style scale contains the chord; fall back to the chromatic\n // scale, which trivially contains every pitch class.\n if (NAMED_SCALES.chromatic !== undefined) {\n return [{ name: 'chromatic', rootPc }];\n }\n return [];\n }\n const preferHeptatonic = chordPcs.length <= 3;\n ranked.sort((a, b) => {\n const idiomaticA = idiomaticRank(chord, a.name);\n const idiomaticB = idiomaticRank(chord, b.name);\n if (idiomaticA !== idiomaticB) {\n return idiomaticA - idiomaticB;\n }\n if (preferHeptatonic && (a.size === HEPTATONIC_SIZE) !== (b.size === HEPTATONIC_SIZE)) {\n return a.size === HEPTATONIC_SIZE ? -1 : 1;\n }\n if (a.extra !== b.extra) {\n return a.extra - b.extra;\n }\n const rankA = conventionalRank(a.name);\n const rankB = conventionalRank(b.name);\n if (rankA !== rankB) {\n return rankA - rankB;\n }\n return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;\n });\n return ranked.map((entry) => ({ name: entry.name, rootPc }));\n}\n\n/**\n * List a scale's avoid notes over a chord.\n *\n * An avoid note is a non-chord scale tone that lies a semitone directly above a\n * chord tone; sounding it against the chord clashes. The scale is rooted on the\n * chord root. If the scale does not contain the chord, no avoid notes exist.\n *\n * @param chord The chord providing the chord tones.\n * @param scaleName A key of {@link NAMED_SCALES}.\n * @returns The avoid-note pitch classes, sorted ascending in [0, 11].\n * @throws If `scaleName` is not a built-in scale. An empty result already\n * means \"this scale has no avoid notes over this chord\"; answering a typo\n * the same way would make the two indistinguishable.\n *\n * @category Scales\n */\nexport function avoidNotes(chord: Chord, scaleName: ScaleNameInput): number[] {\n const mask = requireScaleMask(scaleName);\n const rootPc = pitchClass(chord.rootPc);\n const chordPcs = chordPitchClasses(chord);\n const alteredDominant = isAlteredDominant(chord, scaleName);\n if (!scaleMatchesChord(chordPcs, mask, rootPc) && !alteredDominant) {\n return [];\n }\n const chordSet = new Set(chordPcs);\n const avoid: number[] = [];\n for (let pc = 0; pc < 12; pc += 1) {\n if (!maskHasPitchClass(mask, rootPc, pc) || chordSet.has(pc)) {\n continue;\n }\n const suspendedThird =\n chord.quality === 'sus4' || chord.quality === '7sus4' ? pc === pitchClass(rootPc + 4) : false;\n if (!alteredDominant && (chordSet.has(pitchClass(pc - 1)) || suspendedThird)) {\n avoid.push(pc);\n }\n }\n return avoid.sort((a, b) => a - b);\n}\n\n/**\n * List a scale's available tensions over a chord.\n *\n * Available tensions are scale tones that are neither chord tones nor avoid\n * notes, i.e. the usable color tones (typically the 9/11/13 region). The scale\n * is rooted on the chord root. If the scale does not contain the chord, there\n * are no available tensions.\n *\n * @param chord The chord providing the chord tones.\n * @param scaleName A key of {@link NAMED_SCALES}.\n * @returns The available-tension pitch classes, sorted ascending in [0, 11].\n * @throws If `scaleName` is not a built-in scale, as {@link avoidNotes} does.\n *\n * @example\n * ```ts\n * import { makeChord, availableTensions } from '@libraz/libcantus';\n * availableTensions(makeChord(0, 'maj7'), 'ionian'); // [2, 9] — color tones over Cmaj7\n * ```\n *\n * @category Scales\n */\nexport function availableTensions(chord: Chord, scaleName: ScaleNameInput): number[] {\n const mask = requireScaleMask(scaleName);\n const rootPc = pitchClass(chord.rootPc);\n const chordPcs = chordPitchClasses(chord);\n const alteredDominant = isAlteredDominant(chord, scaleName);\n if (!scaleMatchesChord(chordPcs, mask, rootPc) && !alteredDominant) {\n return [];\n }\n const chordSet = new Set(chordPcs);\n const avoidSet = alteredDominant ? new Set<number>() : new Set(avoidNotes(chord, scaleName));\n const tensions: number[] = [];\n for (let pc = 0; pc < 12; pc += 1) {\n if (!maskHasPitchClass(mask, rootPc, pc) || chordSet.has(pc) || avoidSet.has(pc)) {\n continue;\n }\n tensions.push(pc);\n }\n return tensions.sort((a, b) => a - b);\n}\n\n/**\n * A scale fit over a chord together with its avoid notes and tensions.\n *\n * @category Scales\n */\nexport type ChordScaleReportEntry = {\n name: string;\n rootPc: number;\n avoid: number[];\n tensions: number[];\n};\n\n/**\n * Report the best-fitting scales for a chord with their avoid notes and tensions.\n *\n * Combines {@link chordScales}, {@link avoidNotes}, and {@link availableTensions}\n * into a single ergonomic result, ordered best fit first.\n *\n * @param chord The chord to analyze.\n * @param limit Optional maximum number of scales to report; all by default.\n * @returns One entry per reported scale, best fit first.\n *\n * @category Scales\n */\nexport function chordScaleReport(chord: Chord, limit?: number): ChordScaleReportEntry[] {\n if (limit !== undefined) {\n assertPositiveInt(limit, 'chord-scale report limit');\n }\n const matches = chordScales(chord);\n const chosen = limit === undefined ? matches : matches.slice(0, limit);\n return chosen.map((match) => ({\n name: match.name,\n rootPc: match.rootPc,\n avoid: avoidNotes(chord, match.name),\n tensions: availableTensions(chord, match.name),\n }));\n}\n\n/**\n * A chord paired with the scale chosen for it by {@link scalesForChanges}.\n *\n * @category Scales\n */\nexport type ScaleChoice = {\n chord: Chord;\n scale: ChordScaleMatch;\n};\n\n/**\n * Small per-candidate penalty added in {@link scalesForChanges} so that, among\n * choices of otherwise-equal transition cost, the tighter best-fit scale wins.\n */\nconst RANK_PENALTY = 0.01;\n\n/** Build the pitch-class set of a named scale rooted on `rootPc`. */\nfunction scalePitchClassSet(name: string, rootPc: number): Set<number> {\n const mask = namedScaleMask(name);\n const pcs = new Set<number>();\n if (mask === undefined) {\n return pcs;\n }\n for (let n = 0; n < 12; n += 1) {\n if (((mask >> n) & 1) === 1) {\n pcs.add(pitchClass(rootPc + n));\n }\n }\n return pcs;\n}\n\n/** Count pitch classes that belong to exactly one of two sets. */\nfunction symmetricDifferenceSize(a: Set<number>, b: Set<number>): number {\n let count = 0;\n for (const pc of a) {\n if (!b.has(pc)) {\n count += 1;\n }\n }\n for (const pc of b) {\n if (!a.has(pc)) {\n count += 1;\n }\n }\n return count;\n}\n\n/**\n * Choose one scale per chord across a progression, favoring continuity.\n *\n * Each chord's {@link chordScales} candidates form a stage in a Viterbi-style\n * dynamic program. The transition cost between adjacent choices is the number\n * of pitch classes that differ between their pitch-class sets (the symmetric\n * difference), plus a small penalty for straying from a chord's best-fit scale\n * so that ties break toward the tighter fit. The minimum-total-cost path is\n * returned, one {@link ScaleChoice} per input chord in the original order.\n *\n * @param chords The chord sequence to choose scales for.\n * @returns One scale choice per chord, in input order.\n *\n * @category Scales\n */\nexport function scalesForChanges(chords: Chord[]): ScaleChoice[] {\n assertGenerationBudget(chords.length, 'chord-scale changes');\n if (chords.length === 0) {\n return [];\n }\n const candidateLists = chords.map((chord) => chordScales(chord));\n const pcSets = candidateLists.map((candidates) =>\n candidates.map((match) => scalePitchClassSet(match.name, match.rootPc)),\n );\n\n const first = candidateLists[0] ?? [];\n const dp: number[][] = [first.map((_, j) => j * RANK_PENALTY)];\n const back: number[][] = [first.map(() => -1)];\n\n for (let i = 1; i < candidateLists.length; i += 1) {\n const candidates = candidateLists[i] ?? [];\n const prevCosts = dp[i - 1] ?? [];\n const prevSets = pcSets[i - 1] ?? [];\n const curSets = pcSets[i] ?? [];\n const stageCosts: number[] = [];\n const stageBack: number[] = [];\n for (let j = 0; j < candidates.length; j += 1) {\n let bestCost = Number.POSITIVE_INFINITY;\n let bestPrev = -1;\n for (let k = 0; k < prevCosts.length; k += 1) {\n const transition = symmetricDifferenceSize(\n prevSets[k] ?? new Set(),\n curSets[j] ?? new Set(),\n );\n const cost = (prevCosts[k] ?? 0) + transition;\n if (cost < bestCost) {\n bestCost = cost;\n bestPrev = k;\n }\n }\n stageCosts.push(bestCost + j * RANK_PENALTY);\n stageBack.push(bestPrev);\n }\n dp.push(stageCosts);\n back.push(stageBack);\n }\n\n const lastCosts = dp[dp.length - 1] ?? [];\n let bestFinal = 0;\n for (let j = 1; j < lastCosts.length; j += 1) {\n if ((lastCosts[j] ?? Number.POSITIVE_INFINITY) < (lastCosts[bestFinal] ?? 0)) {\n bestFinal = j;\n }\n }\n\n const chosenIndices: number[] = new Array(candidateLists.length);\n let current = bestFinal;\n for (let i = candidateLists.length - 1; i >= 0; i -= 1) {\n chosenIndices[i] = current;\n current = back[i]?.[current] ?? -1;\n }\n\n return chords.map((chord, i) => {\n const candidates = candidateLists[i] ?? [];\n const scale = candidates[chosenIndices[i] ?? 0] ?? { name: 'chromatic', rootPc: chord.rootPc };\n return { chord, scale };\n });\n}\n","/**\n * Spelling: derive letter-name notes for scales and chords from a spelled tonic.\n *\n * The theory core works in pitch classes, which cannot choose between (say) a\n * G# and an Ab. Given a spelled tonic, this module assigns diatonic letters to\n * scale degrees and chord tones so a C major scale spells as C D E F G A B and\n * A harmonic minor spells its seventh as G#.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport type { Note } from '../../core/pitch/index.js';\nimport {\n formatNote,\n diatonicLetterOf as mod7,\n pitchClassOf as mod12,\n naturalPitchClassOf as naturalPc,\n} from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../chord/index.js';\nimport { scaleTonesInDegreeOrder } from '../scale/index.js';\n\n/**\n * Conventional degree assignment for each chromatic offset above the tonic.\n *\n * The letter is derived from the tonic's letter plus `degreeOffset` (so the\n * spelling follows the key's diatonic letters), and the accidental is recomputed\n * for that letter. The table covers the whole octave, so a pitch class that is\n * not a degree of the scale — a chromatic tone in a heptatonic key, or any tone\n * outside a pentatonic or blues scale — still spells from the tonic's letter\n * rather than falling back to a fixed sharp table.\n *\n * Offsets follow the conventional ascending chromatic spelling: b2, M2, b3, M3,\n * P4, #4, P5, b6, #6, b7, #7. The raised sixth and leading tone keep sharp-side\n * minor keys spelling their raised degrees with the key-correct letter (e.g. F#\n * minor spells its leading tone E#, not F).\n */\nconst CHROMATIC_SPELLING: Record<number, number> = {\n 1: 1, // b2\n 2: 1, // M2\n 3: 2, // b3\n 4: 2, // M3\n 5: 3, // P4\n 6: 3, // #4\n 7: 4, // P5\n 8: 5, // b6\n 9: 5, // #6 (raised sixth of a minor key)\n 10: 6, // b7\n 11: 6, // #7 (raised leading tone of a minor key)\n};\n\n/**\n * Flat-side table for scales that are not heptatonic.\n *\n * Identical to {@link CHROMATIC_SPELLING} except at the tritone, which a\n * flat-side scale spells as a diminished fifth rather than the augmented fourth\n * a lydian mode wants: C blues spells C Eb F Gb G Bb.\n */\nconst CHROMATIC_SPELLING_FLAT: Record<number, number> = {\n ...CHROMATIC_SPELLING,\n 6: 4, // b5\n};\n\n/**\n * Sharp-side counterpart, used for scales that are not heptatonic and lean\n * sharp: C whole-tone spells C D E F# G# A#.\n */\nconst CHROMATIC_SPELLING_SHARP: Record<number, number> = {\n 1: 0, // #1\n 2: 1, // M2\n 3: 1, // #2\n 4: 2, // M3\n 5: 3, // P4\n 6: 3, // #4\n 7: 4, // P5\n 8: 4, // #5\n 9: 5, // M6\n 10: 5, // #6\n 11: 6, // M7\n};\n\n/** Shortest signed alteration (in [-6, 6]) taking a letter's natural pc to `pc`. */\nfunction alterFor(letter: number, pc: number): number {\n let d = mod12(pc - naturalPc(letter));\n if (d > 6) {\n d -= 12;\n }\n return d;\n}\n\n/** Spell `pc` on the letter `degreeOffset` steps above the tonic's letter. */\nfunction letterFor(tonic: Note, degreeOffset: number | undefined, pc: number): Note | undefined {\n if (degreeOffset === undefined) {\n return undefined;\n }\n const letter = mod7(tonic.letter + degreeOffset);\n return { letter, alter: alterFor(letter, pc) };\n}\n\n/** The lighter-accidental of two candidate spellings; ties go to `preferFlat`. */\nfunction pickSpelling(\n flat: Note | undefined,\n sharp: Note | undefined,\n preferFlat: boolean,\n): Note | undefined {\n if (flat === undefined || sharp === undefined) {\n return flat ?? sharp;\n }\n if (Math.abs(flat.alter) !== Math.abs(sharp.alter)) {\n return Math.abs(flat.alter) < Math.abs(sharp.alter) ? flat : sharp;\n }\n return preferFlat ? flat : sharp;\n}\n\n/**\n * Keep a conventional chromatic degree unless its key-letter spelling costs\n * two or more accidentals than the enharmonic alternative. This preserves Db\n * for C-major bII while avoiding Bbb in Ab major, where A is more readable.\n */\nfunction capChromaticAccidentals(preferred: Note, alternative: Note | undefined): Note {\n return alternative !== undefined && Math.abs(preferred.alter) - Math.abs(alternative.alter) >= 2\n ? alternative\n : preferred;\n}\n\n/** Whether the key's scale is a seven-note (heptatonic) scale. */\nfunction isHeptatonic(key: KeyScale): boolean {\n return scaleTonesInDegreeOrder(key).length === 7;\n}\n\n/** Whether the scale has a minor third and no major third — it leans flat. */\nfunction hasMinorThird(key: KeyScale): boolean {\n const tones = scaleTonesInDegreeOrder(key);\n const root = mod12(key.rootPc);\n return tones.includes(mod12(root + 3)) && !tones.includes(mod12(root + 4));\n}\n\n/**\n * Spell a single pitch class relative to a spelled tonic and key.\n *\n * The tonic always spells as itself. In a heptatonic key each scale degree takes\n * the next letter above the tonic, so the scale spells with one letter per\n * degree. Every other pitch class — a chromatic tone in a heptatonic key, or any\n * tone of a scale that is not heptatonic (pentatonic, blues, octatonic) — takes\n * the conventional interval spelling above the tonic's letter, so a flat-side\n * key keeps flat-side names.\n *\n * @param pc The pitch class to spell.\n * @param tonic The spelled tonic (its letter anchors the spelling).\n * @param key The key/scale.\n * @returns The spelled note (without octave).\n * @category Pitch & Intervals\n */\nexport function spellPitchClass(pc: number, tonic: Note, key: KeyScale): Note {\n const tonicPc = mod12(naturalPc(tonic.letter) + tonic.alter);\n const offset = mod12(pc - tonicPc);\n\n // The tonic spells as itself, whatever the scale: a caller that asked for Eb\n // major pentatonic must not be handed back a D#.\n if (offset === 0) {\n return { letter: mod7(tonic.letter), alter: tonic.alter };\n }\n\n const heptatonic = isHeptatonic(key);\n if (heptatonic) {\n const degree = scaleTonesInDegreeOrder(key).indexOf(mod12(pc));\n if (degree >= 0) {\n const letter = mod7(tonic.letter + degree);\n return { letter, alter: alterFor(letter, pc) };\n }\n const degreeOffset = CHROMATIC_SPELLING[offset];\n const preferred = letterFor(tonic, degreeOffset, pc);\n if (preferred !== undefined) {\n const flat = letterFor(tonic, CHROMATIC_SPELLING_FLAT[offset], pc);\n const sharp = letterFor(tonic, CHROMATIC_SPELLING_SHARP[offset], pc);\n // The conventional heptatonic degree is usually the flat-side candidate;\n // use the other side only when it avoids a double (or worse) accidental.\n const alternative =\n flat?.letter === preferred.letter\n ? sharp\n : sharp?.letter === preferred.letter\n ? flat\n : undefined;\n return capChromaticAccidentals(preferred, alternative);\n }\n } else {\n // A scale that is not heptatonic has no letter-per-degree spelling to\n // follow, so take whichever conventional letter needs the smaller\n // accidental. Ties go to the side the scale itself leans: a flat tonic or a\n // minor third both mean flats (C blues spells Gb and Bb, not F# and A#).\n const flat = letterFor(tonic, CHROMATIC_SPELLING_FLAT[offset], pc);\n const sharp = letterFor(tonic, CHROMATIC_SPELLING_SHARP[offset], pc);\n const best = pickSpelling(flat, sharp, tonic.alter < 0 || hasMinorThird(key));\n if (best !== undefined) {\n return best;\n }\n }\n\n // Unreachable for a pitch class, since both tables cover offsets 1..11 and\n // offset 0 returns above; kept so a non-integral input still names something.\n const belowLetter = mod7([0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6][mod12(pc)] ?? 0);\n return { letter: belowLetter, alter: alterFor(belowLetter, pc) };\n}\n\n/**\n * Spell every pitch class of a scale, in ascending scale-degree order.\n *\n * Correct for heptatonic scales (each degree gets the next letter). A scale that\n * is not heptatonic is spelled tone by tone, on the accidental side the scale\n * leans towards.\n *\n * @param tonic The spelled tonic.\n * @param key The key/scale.\n * @returns Spelled notes, one per scale degree.\n * @example\n * ```ts\n * import { spellScale, noteNames, parseNote, majorKey } from '@libraz/libcantus';\n * noteNames(spellScale(parseNote('C'), majorKey(0)));\n * // ['C', 'D', 'E', 'F', 'G', 'A', 'B']\n * ```\n * @category Pitch & Intervals\n */\nexport function spellScale(tonic: Note, key: KeyScale): Note[] {\n return scaleTonesInDegreeOrder(key).map((pc) => spellPitchClass(pc, tonic, key));\n}\n\n/**\n * Spell an arbitrary list of pitch classes relative to a key.\n *\n * @param pcs The pitch classes.\n * @param tonic The spelled tonic.\n * @param key The key/scale.\n * @returns Spelled notes, in input order.\n * @category Pitch & Intervals\n */\nexport function spellPitchClasses(pcs: number[], tonic: Note, key: KeyScale): Note[] {\n return pcs.map((pc) => spellPitchClass(pc, tonic, key));\n}\n\n/**\n * Diatonic letter distance implied by a chord interval.\n *\n * Chord intervals are not merely pitch-class distances: 6 is a diminished\n * fifth in the basic chord templates while 18 is an augmented eleventh, and 9\n * is a diminished seventh in `dim7` but a sixth elsewhere. Keeping that\n * distinction is what prevents functional chord tones from being respelled by\n * their nearest key pitch (for example G# becoming Ab in E7).\n */\nfunction chordLetterOffset(interval: number, chord: Chord): number {\n switch (interval) {\n case 0:\n case 12:\n return 0;\n case 1:\n case 2:\n case 13:\n case 14:\n return 1;\n case 3:\n case 4:\n case 16:\n return 2;\n case 15:\n // A raised ninth over a chord that already has a third is a ninth, not a\n // second third: C7#9 spells D#, not a duplicate E.\n return chord.intervals.some((i) => i === 3 || i === 4) ? 1 : 2;\n case 5:\n case 17:\n case 18:\n return 3;\n case 6:\n case 7:\n case 8:\n case 19:\n return 4;\n case 9:\n return chord.quality === 'dim7' ? 6 : 5;\n case 20:\n case 21:\n return 5;\n case 10:\n case 11:\n case 22:\n case 23:\n return 6;\n default: {\n // Unknown/custom interval data gets the nearest conventional diatonic\n // distance. Public builders use the explicit cases above.\n const octaves = Math.floor(Math.max(0, interval) / 12);\n const simple = mod12(interval);\n const simpleOffset = [0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6][simple] ?? 0;\n return octaves * 7 + simpleOffset;\n }\n }\n}\n\n/**\n * Spell chord tones from an already chosen root spelling.\n *\n * This is public for callers that already know the desired root spelling;\n * {@link spellChord} instead derives that spelling from the chord and key.\n */\nexport function spellChordFromRoot(chord: Chord, root: Note): Note[] {\n if (mod12(naturalPc(root.letter) + root.alter) !== mod12(chord.rootPc)) {\n throw new InvalidInputError('chord root spelling must match chord.rootPc');\n }\n return chord.intervals.map((interval) => {\n const letter = mod7(root.letter + chordLetterOffset(interval, chord));\n const pc = mod12(chord.rootPc + interval);\n return { letter, alter: alterFor(letter, pc) };\n });\n}\n\n/**\n * Spell a chord's tones, in the chord's own (tertian) order, relative to a key.\n *\n * Diatonic chords spell exactly (e.g. G7 in C major -> G B D F). Chromatic chord\n * tones take their conventional spelling; enharmonically ambiguous altered\n * tensions may be spelled by the general convention rather than by chord\n * function.\n *\n * @param chord The chord.\n * @param tonic The spelled tonic of the key.\n * @param key The key/scale.\n * @returns Spelled chord tones, root first.\n * @example\n * ```ts\n * import { spellChord, noteNames, parseNote, majorKey, makeChord } from '@libraz/libcantus';\n * // G7 in C major\n * noteNames(spellChord(makeChord(7, 'dom7'), parseNote('C'), majorKey(0)));\n * // ['G', 'B', 'D', 'F']\n * ```\n * @category Pitch & Intervals\n */\nexport function spellChord(chord: Chord, tonic: Note, key: KeyScale): Note[] {\n return spellChordFromRoot(chord, chordRootSpelling(chord, tonic, key));\n}\n\n/**\n * The root spelling to use for a chord: the chord's own hint when it still\n * matches the root pitch class, otherwise the key's spelling of that pitch\n * class.\n *\n * Honouring the hint is what keeps a chord's spelled tones agreeing with the\n * symbol it renders as — `parseChordSymbol('C#7')` must spell C# E# G# B even\n * when analysed in a flat-side key.\n */\nfunction chordRootSpelling(chord: Chord, tonic: Note, key: KeyScale): Note {\n const hint = chord.rootSpelling;\n if (hint !== undefined && mod12(naturalPc(hint.letter) + hint.alter) === mod12(chord.rootPc)) {\n return { letter: mod7(hint.letter), alter: hint.alter };\n }\n return spellPitchClass(chord.rootPc, tonic, key);\n}\n\n/**\n * Spell a MIDI pitch relative to a key, keeping its octave.\n *\n * The octave-less sibling of this function, {@link spellPitchClass}, is enough\n * for chord and scale spelling; this one is for naming actual sounding pitches\n * (a generated line, an imported track) without losing the register.\n *\n * @param pitch The MIDI pitch; rounded to the nearest integer.\n * @param tonic The spelled tonic of the key.\n * @param key The key/scale.\n * @returns The spelled note, carrying the octave that reproduces `pitch`.\n * @example\n * ```ts\n * import { spellPitch, formatNote, parseNote, majorKey } from '@libraz/libcantus';\n * formatNote(spellPitch(70, parseNote('Eb'), majorKey(3))); // 'Bb4'\n * ```\n * @category Pitch & Intervals\n */\nexport function spellPitch(pitch: number, tonic: Note, key: KeyScale): Note {\n const rounded = Math.round(pitch);\n const spelled = spellPitchClass(mod12(rounded), tonic, key);\n const octave = (rounded - naturalPc(spelled.letter) - spelled.alter) / 12 - 1;\n return { letter: spelled.letter, alter: spelled.alter, octave };\n}\n\n/**\n * Convenience: render spelled notes as letter-name strings.\n *\n * @param notes The notes.\n * @returns Their formatted names.\n * @category Pitch & Intervals\n */\nexport function noteNames(notes: Note[]): string[] {\n return notes.map(formatNote);\n}\n","/**\n * Lead-sheet chord symbol parsing and formatting.\n *\n * Bridges the informal `<root><quality>[/<bass>]` notation musicians write\n * (`Cmaj7`, `F#m7b5`, `Bb7`, `C/G`) and the library's structured {@link Chord}\n * type, so callers can accept/emit plain text at the edges of the API.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport {\n formatNote,\n midiToNote,\n type Note,\n noteToPitchClass,\n parseNote,\n pitchClassOf as pitchClass,\n transposeNote,\n} from '../../core/pitch/index.js';\nimport { assertFiniteNumber, assertFiniteSemitones } from '../../core/validation/index.js';\nimport { type Chord, type ChordQuality, makeChord, type PitchSpelling } from '../chord/index.js';\n\n/**\n * Matches a chord root: a letter A-G (case-insensitive, like {@link parseNote})\n * with an optional single-direction accidental.\n */\nconst ROOT_RE = /^[A-Ga-g](?:#{1,2}|b{1,2}|x)?/;\n\n/** Matches a bare note usable as a slash-chord bass (no octave). */\nconst BASS_RE = /^[A-Ga-g](?:#{1,2}|b{1,2}|x)?$/;\n\n/** Recognized quality suffixes, keyed by their exact lead-sheet spelling. */\nconst QUALITY_MAP: Record<string, ChordQuality> = {\n '': 'maj',\n maj: 'maj',\n m: 'min',\n min: 'min',\n '-': 'min',\n dim: 'dim',\n '°': 'dim',\n aug: 'aug',\n '+': 'aug',\n maj7: 'maj7',\n M7: 'maj7',\n Δ: 'maj7',\n Δ7: 'maj7',\n m7: 'min7',\n min7: 'min7',\n '-7': 'min7',\n '7': 'dom7',\n dim7: 'dim7',\n '°7': 'dim7',\n m7b5: 'm7b5',\n ø: 'm7b5',\n ø7: 'm7b5',\n min7b5: 'm7b5',\n mMaj7: 'minMaj7',\n mM7: 'minMaj7',\n minMaj7: 'minMaj7',\n mMaj9: 'minMaj9',\n mM9: 'minMaj9',\n minMaj9: 'minMaj9',\n mMaj11: 'minMaj11',\n mM11: 'minMaj11',\n minMaj11: 'minMaj11',\n mMaj13: 'minMaj13',\n mM13: 'minMaj13',\n minMaj13: 'minMaj13',\n aug7: 'aug7',\n '+7': 'aug7',\n '7#5': 'aug7',\n augMaj7: 'augMaj7',\n augM7: 'augMaj7',\n '+maj7': 'augMaj7',\n '+M7': 'augMaj7',\n majb5: 'majb5',\n 'maj(b5)': 'majb5',\n '(b5)': 'majb5',\n '6': '6',\n m6: 'min6',\n min6: 'min6',\n '6/9': '6/9',\n '69': '6/9',\n sus2: 'sus2',\n sus: 'sus4',\n sus4: 'sus4',\n add9: 'add9',\n add11: 'add11',\n maj9: 'maj9',\n M9: 'maj9',\n m9: 'min9',\n min9: 'min9',\n '9': 'dom9',\n '7b9': '7b9',\n '7#9': '7#9',\n '7#11': '7#11',\n '7b13': '7b13',\n '11': '11',\n '13': '13',\n '5': '5',\n '7sus4': '7sus4',\n '7sus': '7sus4',\n '9sus4': '11',\n '9sus': '11',\n '7b5': '7b5',\n '7alt': '7alt',\n alt: '7alt',\n '13b9': '13b9',\n maj13: 'maj13',\n M13: 'maj13',\n 'maj7#11': 'maj7#11',\n 'M7#11': 'maj7#11',\n m11: 'min11',\n min11: 'min11',\n m13: 'min13',\n min13: 'min13',\n madd9: 'minAdd9',\n 'min(add9)': 'minAdd9',\n 'm(add9)': 'minAdd9',\n '6add9': '6/9',\n 'm6/9': 'min6/9',\n m69: 'min6/9',\n 'min6/9': 'min6/9',\n // ASCII stand-ins for the degree and half-diminished glyphs, which most\n // lead sheets and chord-chart text files use instead of the typographic ones.\n o: 'dim',\n o7: 'dim7',\n h: 'm7b5',\n h7: 'm7b5',\n};\n\n/** Canonical lead-sheet suffix emitted for each chord quality when formatting. */\nconst CANONICAL_SUFFIX: Record<ChordQuality, string> = {\n maj: '',\n min: 'm',\n dim: 'dim',\n aug: 'aug',\n maj7: 'maj7',\n min7: 'm7',\n dom7: '7',\n dim7: 'dim7',\n m7b5: 'm7b5',\n minMaj7: 'mMaj7',\n minMaj9: 'mMaj9',\n minMaj11: 'mMaj11',\n minMaj13: 'mMaj13',\n aug7: 'aug7',\n augMaj7: 'augMaj7',\n majb5: 'maj(b5)',\n '6': '6',\n min6: 'm6',\n '6/9': '6/9',\n sus2: 'sus2',\n sus4: 'sus4',\n add9: 'add9',\n add11: 'add11',\n maj9: 'maj9',\n min9: 'm9',\n dom9: '9',\n '7b9': '7b9',\n '7#9': '7#9',\n '7#11': '7#11',\n '7b13': '7b13',\n '11': '11',\n '13': '13',\n '5': '5',\n '7sus4': '7sus4',\n '7b5': '7b5',\n '7alt': '7alt',\n '13b9': '13b9',\n maj13: 'maj13',\n 'maj7#11': 'maj7#11',\n min11: 'm11',\n min13: 'm13',\n minAdd9: 'madd9',\n 'min6/9': 'm6/9',\n};\n\n/**\n * The quality a suffix names, or undefined when it names none.\n *\n * The own-property check is what stops `'constructor'` and `'toString'` from\n * resolving through `Object.prototype` and reaching the chord builder with a\n * quality it has no interval template for.\n */\nfunction knownQuality(suffix: string): ChordQuality | undefined {\n return Object.hasOwn(QUALITY_MAP, suffix) ? QUALITY_MAP[suffix] : undefined;\n}\n\n/** Build a chord and record the parsed spellings as enharmonic hints. */\nfunction makeSpelledChord(root: Note, quality: ChordQuality, bass?: Note): Chord {\n const chord = makeChord(\n noteToPitchClass(root),\n quality,\n bass === undefined ? undefined : noteToPitchClass(bass),\n );\n chord.rootSpelling = { letter: root.letter, alter: root.alter };\n if (bass !== undefined) {\n chord.bassSpelling = { letter: bass.letter, alter: bass.alter };\n }\n return chord;\n}\n\n/**\n * Parse a lead-sheet chord symbol into a {@link Chord}.\n *\n * Accepts `<root><quality>[/<bass>]`, e.g. `Cmaj7`, `F#m7b5`, `Bb7`, `C/G`,\n * `C6/9`, `C6/9/E`. Root and bass letters are case-insensitive, matching\n * {@link parseNote}. A `/` is ambiguous between a slash bass and the `6/9`\n * quality; the text splits at the last `/` whose right-hand side is a valid\n * bare note preceded by a recognized quality, so `6/9` (with or without a\n * further slash bass) parses as a quality.\n *\n * The parsed chord carries the root/bass spellings as enharmonic hints\n * (`rootSpelling`/`bassSpelling`) so {@link formatChordSymbol} can reproduce\n * flat spellings such as `Bbmaj7` instead of respelling them with sharps.\n *\n * @param text The chord symbol text.\n * @returns The parsed chord.\n * @throws If the root or quality is not recognized.\n * @example\n * ```ts\n * import { parseChordSymbol, formatChordSymbol } from '@libraz/libcantus';\n * const c = parseChordSymbol('Bbmaj7');\n * formatChordSymbol(c); // 'Bbmaj7' — flat spelling is preserved on round-trip\n * ```\n * @category Chords\n */\nexport function parseChordSymbol(text: string): Chord {\n const trimmed = text\n .trim()\n .replaceAll('♯', '#')\n .replaceAll('♭', 'b')\n .replaceAll('𝄪', 'x')\n .replaceAll('𝄫', 'bb');\n const rootMatch = ROOT_RE.exec(trimmed);\n if (!rootMatch) {\n throw new InvalidInputError(`Invalid chord symbol: ${text}`);\n }\n const rootToken = rootMatch[0];\n const rootNote = parseNote(rootToken);\n const rest = trimmed.slice(rootToken.length);\n\n // Split at the last '/' so the '6/9' quality's own slash never masks a\n // trailing slash bass (e.g. 'C6/9/E').\n const slashIndex = rest.lastIndexOf('/');\n if (slashIndex !== -1) {\n const before = rest.slice(0, slashIndex);\n const after = rest.slice(slashIndex + 1);\n const beforeQuality = knownQuality(before);\n if (beforeQuality !== undefined && BASS_RE.test(after)) {\n return makeSpelledChord(rootNote, beforeQuality, parseNote(after));\n }\n }\n\n const quality = knownQuality(rest);\n if (quality === undefined) {\n throw new InvalidInputError(`Unrecognized chord quality: ${text}`);\n }\n return makeSpelledChord(rootNote, quality);\n}\n\n/**\n * Name a pitch class, preferring a spelling hint when it is still valid.\n *\n * A hint is used only when no explicit sharp/flat preference was given and the\n * hint still resolves to `pc` (a stale hint left over after transposition is\n * ignored). Otherwise the pitch class is respelled from the requested table,\n * falling back to `inheritFlats` so an unhinted slash bass follows the side its\n * root was spelled on rather than flipping to sharps inside one symbol.\n */\nfunction pitchClassName(\n pc: number,\n hint: PitchSpelling | undefined,\n flats?: boolean,\n inheritFlats?: boolean,\n): string {\n if (flats === undefined && hint !== undefined && noteToPitchClass(hint) === pc) {\n return formatNote(hint);\n }\n const note = midiToNote(60 + pc, (flats ?? inheritFlats) ? 'flat' : 'sharp');\n return formatNote({ letter: note.letter, alter: note.alter });\n}\n\n/**\n * Format a {@link Chord} as a lead-sheet chord symbol.\n *\n * The inverse of {@link parseChordSymbol}: each quality maps to one canonical\n * suffix spelling, and a slash bass is appended only when it differs from the\n * root. When the chord carries `rootSpelling`/`bassSpelling` hints (as chords\n * from {@link parseChordSymbol} do) and no explicit `flats` preference is\n * given, the hints are reused so flat symbols round-trip unchanged.\n *\n * @param chord The chord to format.\n * @param opts Formatting options.\n * @param opts.flats Prefer flat spellings over sharps for altered roots/basses;\n * passing either `true` or `false` overrides any spelling hints.\n * @returns The chord symbol text.\n * @example\n * ```ts\n * import { makeChord, formatChordSymbol } from '@libraz/libcantus';\n * formatChordSymbol(makeChord(0, 'min7')); // 'Cm7'\n * ```\n * @category Chords\n */\nexport function formatChordSymbol(chord: Chord, opts?: { flats?: boolean }): string {\n // A chord rebuilt from JSON or arrived at through arithmetic can carry a\n // non-finite root or a quality this module has no suffix for; formatting\n // those produces 'C' and 'Cundefined', which read as real symbols.\n assertFiniteNumber(chord.rootPc, 'chord rootPc');\n if (chord.bassPc !== undefined) {\n assertFiniteNumber(chord.bassPc, 'chord bassPc');\n }\n if (!Object.hasOwn(CANONICAL_SUFFIX, chord.quality)) {\n throw new InvalidInputError(`Unknown chord quality: ${String(chord.quality)}`);\n }\n const rootPc = pitchClass(chord.rootPc);\n const rootHint = chord.rootSpelling;\n const rootName = pitchClassName(rootPc, rootHint, opts?.flats);\n const suffix = CANONICAL_SUFFIX[chord.quality];\n let symbol = `${rootName}${suffix}`;\n if (chord.bassPc !== undefined && pitchClass(chord.bassPc) !== rootPc) {\n const inheritFlats =\n rootHint !== undefined && noteToPitchClass(rootHint) === rootPc\n ? rootHint.alter < 0\n : undefined;\n symbol += `/${pitchClassName(pitchClass(chord.bassPc), chord.bassSpelling, opts?.flats, inheritFlats)}`;\n }\n return symbol;\n}\n\n/**\n * Transpose a chord symbol by a number of semitones.\n *\n * @param text The chord symbol text.\n * @param semitones Signed semitone offset to apply to the root and bass.\n * @param opts Formatting options for the result; see {@link formatChordSymbol}.\n * @returns The transposed chord symbol text.\n * @throws If `text` does not parse as a chord symbol.\n * @example\n * ```ts\n * import { transposeChordSymbol } from '@libraz/libcantus';\n * transposeChordSymbol('C/G', 2); // 'D/A'\n * ```\n * @category Chords\n */\nexport function transposeChordSymbol(\n text: string,\n semitones: number,\n opts?: { flats?: boolean },\n): string {\n assertFiniteSemitones(semitones);\n const chord = parseChordSymbol(text);\n const transposed: Chord = { ...chord, rootPc: pitchClass(chord.rootPc + semitones) };\n if (chord.rootSpelling !== undefined) {\n const hint = transposeNote(chord.rootSpelling, semitones);\n transposed.rootSpelling = { letter: hint.letter, alter: hint.alter };\n }\n if (chord.bassPc !== undefined) {\n transposed.bassPc = pitchClass(chord.bassPc + semitones);\n }\n if (chord.bassSpelling !== undefined) {\n const hint = transposeNote(chord.bassSpelling, semitones);\n transposed.bassSpelling = { letter: hint.letter, alter: hint.alter };\n }\n return formatChordSymbol(transposed, opts);\n}\n","import { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\n\nexport { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\n\nimport { NoSolutionError } from '../../core/errors/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../chord/index.js';\nimport { chordPitchClasses, chordToneRole } from '../chord/index.js';\nimport { createsParallelPerfect, createsVoiceOverlap } from '../counterpoint/index.js';\nimport type { VoiceRange } from './satb.js';\n\n/** Default maximum spacing between adjacent upper voices (one octave). */\nexport const DEFAULT_MAX_SPACING = 12;\n\n/** Score penalty per counterpoint violation between consecutive voicings. */\nexport const VIOLATION_PENALTY = 1000;\n/** Score penalty per chord tone absent from a voicing. */\nconst MISSING_TONE_PENALTY = 500;\n/**\n * Score penalty for omitting the chord's fifth. Far milder than any other\n * missing tone: the fifth carries no identity, and the textbook resolution of a\n * complete dominant seventh onto a tonic triad — every tendency tone resolving\n * inward — leaves the tonic without its fifth. Weighted below\n * {@link RESOLUTION_PENALTY} so a resolution can buy the omission, and above\n * {@link POOR_DOUBLING_PENALTY} so nothing else can.\n */\nconst MISSING_FIFTH_PENALTY = 20;\n/** Score penalty per doubled tone that is neither the root nor the fifth. */\nconst POOR_DOUBLING_PENALTY = 4;\n/** Penalty for adjacent voices sharing exactly the same MIDI pitch. */\nconst UNISON_PENALTY = 100;\n/**\n * Score penalty for doubling the key's leading tone. Doubling it guarantees\n * parallel octaves on its resolution, so it is a rule violation rather than a\n * matter of taste — weighted far above {@link POOR_DOUBLING_PENALTY}, but below\n * a missing chord tone, which damages the chord itself.\n */\nconst LEADING_TONE_DOUBLING_PENALTY = 200;\n/**\n * Score penalty per tendency tone that fails to resolve. Well above the few\n * semitones of extra motion a correct resolution usually costs, so smoothness\n * can never buy an unresolved seventh, and well below\n * {@link VIOLATION_PENALTY}, so avoiding parallels still comes first.\n */\nexport const RESOLUTION_PENALTY = 200;\n/** Hard cap on candidate voicings evaluated per chord, keeping the search bounded. */\nconst DEFAULT_MAX_CANDIDATES = 4000;\n/**\n * Hard cap on search-tree nodes visited per chord. The candidate cap alone only\n * counts completed voicings, so a search whose upper voices admit no chord tone\n * would expand the whole cartesian product without ever reaching a leaf.\n */\nconst SEARCH_NODES_PER_CANDIDATE = 16;\n\n/**\n * All MIDI pitches of a pitch class inside an inclusive range, ordered from the\n * centre of the range outward (ties break toward the lower pitch). Enumerating\n * centre-outward keeps the candidate set balanced around the register when it\n * is truncated at {@link MAX_CANDIDATES}, instead of skewing to the low octaves\n * that a plain ascending scan would visit first.\n */\nfunction pitchesForPc(pc: number, range: VoiceRange): number[] {\n const result: number[] = [];\n for (let midi = Math.ceil(range.min); midi <= range.max; midi += 1) {\n if (pitchClass(midi) === pc) {\n result.push(midi);\n }\n }\n const center = (range.min + range.max) / 2;\n return result.sort((a, b) => {\n const da = Math.abs(a - center);\n const db = Math.abs(b - center);\n return da === db ? a - b : da - db;\n });\n}\n\n/**\n * Enumerate candidate voicings for a chord: the bass takes the chord's bass\n * (or root) pitch class at each available octave, and each upper voice takes\n * any chord pitch class within its range. Candidates are built in ascending\n * voice order and pruned to exclude voice crossings and over-wide adjacent\n * spacing (the bass–tenor pair is allowed an extra octave, per convention).\n * Enumeration is deterministic and capped at `maxCandidates` completed\n * voicings and a proportional number of visited nodes.\n *\n * Each voice's admissible pitches are resolved once up front rather than\n * recomputed at every node, and a voice that admits no chord tone at all fails\n * immediately: continuing would explore every combination of the voices below\n * it only to reach no leaf.\n *\n * @throws If any voice's range contains no pitch of any chord tone.\n */\nexport function enumerateVoicings(\n chord: Chord,\n ranges: VoiceRange[],\n maxSpacing: number,\n maxCandidates = DEFAULT_MAX_CANDIDATES,\n): number[][] {\n const chordPcs = chordPitchClasses(chord);\n const bassPc = pitchClass(chord.bassPc ?? chord.rootPc);\n // Pitch-class-major order, matching the enumeration order of the search.\n const byVoice = ranges.map((range, voice) =>\n (voice === 0 ? [bassPc] : chordPcs).flatMap((pc) => pitchesForPc(pc, range)),\n );\n for (let voice = 0; voice < byVoice.length; voice += 1) {\n if ((byVoice[voice] ?? []).length === 0) {\n throw new NoSolutionError('no voicing satisfies the given ranges');\n }\n }\n const results: number[][] = [];\n const current: number[] = [];\n let nodes = 0;\n const maxSearchNodes = maxCandidates * SEARCH_NODES_PER_CANDIDATE;\n const build = (voice: number): void => {\n nodes += 1;\n if (results.length >= maxCandidates || nodes > maxSearchNodes) {\n return;\n }\n if (voice === ranges.length) {\n results.push([...current]);\n return;\n }\n const prev = current[voice - 1];\n for (const pitch of byVoice[voice] ?? []) {\n if (prev !== undefined) {\n if (pitch < prev) {\n continue; // would cross below the next lower voice\n }\n const spacingLimit = voice === 1 ? maxSpacing + 12 : maxSpacing;\n if (pitch - prev > spacingLimit) {\n continue;\n }\n }\n current.push(pitch);\n build(voice + 1);\n current.pop();\n }\n };\n build(0);\n return results;\n}\n\n/**\n * Structural quality penalty of a single voicing: heavily penalize missing\n * chord tones (mildly for the fifth, which carries no identity), mildly\n * penalize doubling anything other than the root or fifth, and — when a key is\n * known — heavily penalize doubling its leading tone.\n *\n * The exempt fifth is the chord's own fifth, whatever its size: a diminished,\n * augmented, or absent fifth would leave the root as the only freely doubled\n * tone, which is what forces a doubled leading tone in a `viio` chord.\n */\nexport function structuralPenalty(pitches: number[], chord: Chord, key?: KeyScale): number {\n const counts = new Map<number, number>();\n for (const pitch of pitches) {\n const pc = pitchClass(pitch);\n counts.set(pc, (counts.get(pc) ?? 0) + 1);\n }\n let penalty = 0;\n for (let index = 1; index < pitches.length; index += 1) {\n if (pitches[index] === pitches[index - 1]) {\n penalty += UNISON_PENALTY;\n }\n }\n for (const pc of chordPitchClasses(chord)) {\n if (!counts.has(pc)) {\n penalty +=\n chordToneRole(pc, chord) === 'fifth' ? MISSING_FIFTH_PENALTY : MISSING_TONE_PENALTY;\n }\n }\n const rootPc = pitchClass(chord.rootPc);\n const leadingTonePc = key === undefined ? undefined : pitchClass(key.rootPc - 1);\n for (const [pc, count] of counts) {\n if (count <= 1) {\n continue;\n }\n if (pc === leadingTonePc) {\n penalty += (count - 1) * LEADING_TONE_DOUBLING_PENALTY;\n continue;\n }\n if (pc !== rootPc && chordToneRole(pc, chord) !== 'fifth') {\n penalty += (count - 1) * POOR_DOUBLING_PENALTY;\n }\n }\n return penalty;\n}\n\n/** The chord's own seventh as a pitch class, or undefined when it has none. */\nfunction seventhPcOf(chord: Chord): number | undefined {\n for (const interval of chord.intervals) {\n const pc = pitchClass(chord.rootPc + interval);\n if (chordToneRole(pc, chord) === 'seventh') {\n return pc;\n }\n }\n return undefined;\n}\n\n/**\n * Count the tendency tones that fail to resolve between two consecutive\n * voicings of the same progression.\n *\n * A chordal seventh is a dissonance: unless the next chord holds it as a common\n * tone, the voice carrying it must fall by step. A leading tone must rise to\n * the tonic whenever the next chord contains one; without a key there is no\n * leading tone to speak of, so that half of the rule is skipped.\n */\nexport function resolutionViolations(\n prev: number[],\n cur: number[],\n prevChord: Chord,\n nextChord: Chord,\n key?: KeyScale,\n): number {\n const seventhPc = seventhPcOf(prevChord);\n const leadingTonePc = key === undefined ? undefined : pitchClass(key.rootPc - 1);\n const tonicPc = key === undefined ? undefined : pitchClass(key.rootPc);\n const nextPcs = new Set(chordPitchClasses(nextChord));\n let count = 0;\n for (let voice = 0; voice < prev.length && voice < cur.length; voice += 1) {\n const from = prev[voice];\n const to = cur[voice];\n if (from === undefined || to === undefined) {\n continue;\n }\n const fromPc = pitchClass(from);\n const motion = to - from;\n if (fromPc === seventhPc && !nextPcs.has(fromPc) && motion !== -1 && motion !== -2) {\n count += 1;\n }\n if (\n fromPc === leadingTonePc &&\n tonicPc !== undefined &&\n nextPcs.has(tonicPc) &&\n !nextPcs.has(fromPc) &&\n motion !== 1\n ) {\n count += 1;\n }\n }\n return count;\n}\n\n/**\n * Count counterpoint violations between two consecutive voicings of equal\n * length: parallel perfects (fifths and octaves alike, since octaves are the\n * perfect-class-zero case of {@link createsParallelPerfect}) on every voice\n * pair, and voice overlaps on adjacent pairs.\n *\n * Voice crossing and over-wide spacing are not counted: {@link\n * enumerateVoicings} rejects both while building a candidate, so a candidate\n * that reaches here cannot exhibit either. Overlap involves the previous\n * voicing and so is still live.\n */\nexport function violationCount(prev: number[], cur: number[]): number {\n let count = 0;\n for (let lower = 0; lower < cur.length; lower += 1) {\n for (let upper = lower + 1; upper < cur.length; upper += 1) {\n const prevLower = prev[lower];\n const prevUpper = prev[upper];\n const curLower = cur[lower];\n const curUpper = cur[upper];\n if (\n prevLower === undefined ||\n prevUpper === undefined ||\n curLower === undefined ||\n curUpper === undefined\n ) {\n continue;\n }\n if (createsParallelPerfect(prevUpper, curUpper, prevLower, curLower)) {\n count += 1;\n }\n if (upper === lower + 1) {\n if (createsVoiceOverlap(prevUpper, curUpper, prevLower, curLower)) {\n count += 1;\n }\n }\n }\n }\n return count;\n}\n","import { InvalidInputError, NoSolutionError } from '../../core/errors/index.js';\nimport { assertFiniteNumber } from '../../core/validation/index.js';\nimport type { Chord } from '../chord/index.js';\nimport { createsHiddenParallelPerfect } from '../counterpoint/index.js';\nimport {\n enumerateVoicings,\n RESOLUTION_PENALTY,\n resolutionViolations,\n structuralPenalty,\n VIOLATION_PENALTY,\n violationCount,\n} from './internal.js';\nimport type { VoicingOptions } from './satb.js';\nimport { resolveMaxCandidates, resolveMaxSpacing, resolveRanges } from './satb.js';\n\n/**\n * Moderate penalty for a hidden/direct perfect fifth or octave reached on the\n * outer-voice (bass–soprano) pair. Unlike a true parallel perfect it is\n * discouraged rather than forbidden, so the weight sits alongside voice-leading\n * motion rather than the hard {@link VIOLATION_PENALTY}.\n */\nconst HIDDEN_PERFECT_PENALTY = 6;\n\n/**\n * Total voice-leading cost between two voicings: the sum of absolute semitone\n * motion across voices, plus a moderate `HIDDEN_PERFECT_PENALTY` when the\n * outer-voice (bass–soprano) pair reaches a hidden/direct perfect fifth or\n * octave by similar motion. The arrays must be the same length; when they\n * differ the voicings are not comparable and the cost is `Infinity`.\n *\n * @param from The previous voicing, one MIDI pitch per voice.\n * @param to The next voicing, one MIDI pitch per voice.\n * @returns The summed absolute motion (plus any hidden-perfect penalty), or\n * `Infinity` when lengths differ.\n * @category Voicing & Counterpoint\n */\nexport function voiceLeadingCost(from: number[], to: number[]): number {\n if (from.length !== to.length) {\n return Number.POSITIVE_INFINITY;\n }\n let total = 0;\n for (let i = 0; i < from.length; i += 1) {\n const a = from[i];\n const b = to[i];\n if (a === undefined || b === undefined) {\n continue;\n }\n total += Math.abs(b - a);\n }\n // Discourage hidden/direct perfects between the outermost voices, where they\n // are most audible. True parallels are handled (and forbidden) elsewhere.\n if (from.length >= 2) {\n const bassPrev = from[0];\n const bassCur = to[0];\n const sopPrev = from[from.length - 1];\n const sopCur = to[to.length - 1];\n if (\n bassPrev !== undefined &&\n bassCur !== undefined &&\n sopPrev !== undefined &&\n sopCur !== undefined &&\n createsHiddenParallelPerfect(bassPrev, bassCur, sopPrev, sopCur)\n ) {\n total += HIDDEN_PERFECT_PENALTY;\n }\n }\n return total;\n}\n\n/**\n * Voice a single chord to follow smoothly from an arbitrary current voicing.\n *\n * Candidate voicings of `chord` are enumerated within ranges taken from `opts`,\n * or — when neither `voices` nor `ranges` is given — from a one-octave window\n * around each pitch of `current` (so the result matches `current`'s voice\n * count). Each candidate is scored by structural quality, voice-leading motion\n * from `current`, and a large penalty per counterpoint violation; the lowest\n * scoring candidate is returned, ascending.\n *\n * @param current The current voicing to lead from, ascending (index 0 = lowest).\n * @param chord The next chord to voice.\n * @param opts Voicing options; when omitted, ranges follow `current`'s span.\n * @returns The chosen voicing, ascending with one MIDI pitch per voice.\n * @throws If `current` is empty or holds a non-finite pitch while the ranges\n * are derived from it, or if no voicing fits the ranges.\n * @category Voicing & Counterpoint\n */\nexport function nextVoicing(current: number[], chord: Chord, opts?: VoicingOptions): number[] {\n const derived = opts?.ranges === undefined && opts?.voices === undefined;\n if (derived) {\n // The ranges are read off `current`, so an empty voicing would describe a\n // zero-voice chord and return an empty result — the same input that throws\n // when written as an explicit `{ ranges: [] }`.\n if (current.length === 0) {\n throw new InvalidInputError('current must contain at least one pitch');\n }\n for (let index = 0; index < current.length; index += 1) {\n assertFiniteNumber(current[index] ?? Number.NaN, `current[${index}]`);\n }\n }\n const ranges = derived\n ? current.map((pitch) => {\n // Window one octave around each current pitch, clamped so extreme-low\n // or extreme-high input can never yield MIDI outside [0, 127].\n const centre = Math.min(127, Math.max(0, pitch));\n return { min: Math.max(0, centre - 12), max: Math.min(127, centre + 12) };\n })\n : resolveRanges(opts);\n for (let index = 0; index < current.length; index += 1) {\n assertFiniteNumber(current[index] ?? Number.NaN, `current[${index}]`);\n }\n if (current.length < ranges.length) {\n throw new InvalidInputError(\n `current has ${current.length} voices but the requested ranges require ${ranges.length}`,\n );\n }\n // Thinning an existing texture is a normal use case (SATB to three voices,\n // for example). Keep the outer voices and select evenly spaced inner voices\n // so motion is still measured between like voice roles.\n const source =\n current.length === ranges.length\n ? current\n : ranges.length === 1\n ? [current[0] ?? Number.NaN]\n : ranges.map((_, index) => {\n const sourceIndex = Math.round((index * (current.length - 1)) / (ranges.length - 1));\n return current[sourceIndex] ?? Number.NaN;\n });\n const maxSpacing = resolveMaxSpacing(opts);\n const candidates = enumerateVoicings(chord, ranges, maxSpacing, resolveMaxCandidates(opts));\n const previousChord = opts?.previousChord;\n let best: number[] | undefined;\n let bestScore = Number.POSITIVE_INFINITY;\n for (const candidate of candidates) {\n const score =\n structuralPenalty(candidate, chord, opts?.key) +\n voiceLeadingCost(source, candidate) +\n VIOLATION_PENALTY * violationCount(source, candidate) +\n RESOLUTION_PENALTY *\n (previousChord === undefined\n ? 0\n : resolutionViolations(source, candidate, previousChord, chord, opts?.key));\n if (score < bestScore) {\n bestScore = score;\n best = candidate;\n }\n }\n if (best === undefined) {\n throw new NoSolutionError('no voicing satisfies the given ranges');\n }\n return best;\n}\n","import { InvalidInputError, NoSolutionError } from '../../core/errors/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport {\n assertFiniteNumber,\n assertGenerationBudget,\n assertPositiveInt,\n} from '../../core/validation/index.js';\nimport type { Chord } from '../chord/index.js';\nimport { formatChordSymbol } from '../symbol/index.js';\nimport {\n DEFAULT_MAX_SPACING,\n enumerateVoicings,\n RESOLUTION_PENALTY,\n resolutionViolations,\n structuralPenalty,\n VIOLATION_PENALTY,\n violationCount,\n} from './internal.js';\nimport { voiceLeadingCost } from './leading.js';\n\n/**\n * An inclusive MIDI pitch range for a single voice.\n *\n * @category Voicing & Counterpoint\n */\nexport type VoiceRange = {\n readonly min: number;\n readonly max: number;\n};\n\n/**\n * Default four-voice SATB ranges, ascending (index 0 = lowest):\n * bass E2–C4 (40–60), tenor C3–G4 (48–67), alto G3–D5 (55–74),\n * soprano C4–G5 (60–79).\n *\n * @category Voicing & Counterpoint\n */\nexport const SATB_RANGES: readonly Readonly<VoiceRange>[] = Object.freeze([\n Object.freeze({ min: 40, max: 60 }),\n Object.freeze({ min: 48, max: 67 }),\n Object.freeze({ min: 55, max: 74 }),\n Object.freeze({ min: 60, max: 79 }),\n]);\n\n/**\n * Options controlling {@link voiceChord} and {@link voiceProgression}.\n *\n * @category Voicing & Counterpoint\n */\nexport type VoicingOptions = {\n /**\n * Number of voices to realize. Ignored when `ranges` is given.\n *\n * @defaultValue 4\n */\n voices?: number;\n /** Explicit per-voice ranges, ascending (index 0 = lowest). Takes precedence over `voices`. */\n ranges?: VoiceRange[];\n /**\n * Maximum spacing in semitones between adjacent upper voices.\n *\n * @defaultValue 12\n */\n maxSpacing?: number;\n /**\n * Maximum candidate voicings evaluated for one chord.\n *\n * Raise this for large voicings when exact optimum matters more than bounded\n * search time.\n *\n * @defaultValue 4000\n */\n maxCandidates?: number;\n /**\n * Maximum number of chords {@link voiceProgression} will voice. The search\n * per chord is bounded internally, so the cost of a progression is linear in\n * its length; this is the guard against an unbounded caller, not a limit on\n * the search.\n *\n * @defaultValue 1000000\n */\n budget?: number;\n /**\n * The prevailing key. Supplying it enables the rules that only make sense\n * relative to a tonic: the leading tone is neither doubled nor left\n * unresolved. Without it, voicings are chosen from chord structure and\n * voice-leading distance alone.\n */\n key?: KeyScale;\n /**\n * The chord that produced the current voicing passed to {@link nextVoicing}.\n * When supplied, chordal-seventh resolution is scored exactly as it is by\n * {@link voiceProgression}.\n */\n previousChord?: Chord;\n};\n\n/** Overall pitch floor/ceiling used when deriving ranges for arbitrary voice counts. */\nconst DERIVED_LOW = 40;\nconst DERIVED_HIGH = 79;\n/** Span of each derived per-voice range in semitones. */\nconst DERIVED_SPAN = 19;\n\n/**\n * Resolve the per-voice ranges implied by the options: explicit `ranges` win,\n * four voices use {@link SATB_RANGES}, and other counts get evenly spaced\n * ranges spanning roughly the bass-to-soprano compass.\n */\nexport function resolveRanges(opts?: VoicingOptions): VoiceRange[] {\n if (opts?.ranges !== undefined) {\n if (opts.ranges.length === 0) {\n throw new InvalidInputError('ranges must contain at least one voice range');\n }\n assertGenerationBudget(opts.ranges.length, 'voice ranges', 128);\n return opts.ranges.map((range, index) => {\n assertFiniteNumber(range.min, `ranges[${index}].min`);\n assertFiniteNumber(range.max, `ranges[${index}].max`);\n if (range.min > range.max) {\n throw new InvalidInputError(`ranges[${index}].min must not exceed max`);\n }\n assertGenerationBudget(\n Math.floor(range.max) - Math.ceil(range.min) + 1,\n `ranges[${index}] span`,\n 4096,\n );\n return { ...range };\n });\n }\n const voices = opts?.voices ?? 4;\n assertPositiveInt(voices, 'voices', 128);\n if (voices === 4) {\n return SATB_RANGES.map((range) => ({ ...range }));\n }\n if (voices === 1) {\n return [{ min: DERIVED_LOW, max: DERIVED_HIGH }];\n }\n const ranges: VoiceRange[] = [];\n for (let i = 0; i < voices; i += 1) {\n const min = Math.round(\n DERIVED_LOW + (i * (DERIVED_HIGH - DERIVED_SPAN - DERIVED_LOW)) / (voices - 1),\n );\n ranges.push({ min, max: min + DERIVED_SPAN });\n }\n return ranges;\n}\n\n/**\n * Resolve and validate the adjacent-voice spacing limit. Shared by every entry\n * point so `nextVoicing` cannot accept a NaN that silently disables the spacing\n * constraint, nor a negative value that reports itself as an impossible range.\n */\nexport function resolveMaxSpacing(opts?: VoicingOptions): number {\n const maxSpacing = opts?.maxSpacing ?? DEFAULT_MAX_SPACING;\n assertFiniteNumber(maxSpacing, 'maxSpacing');\n if (maxSpacing < 0) {\n throw new InvalidInputError('maxSpacing must be non-negative');\n }\n return maxSpacing;\n}\n\n/** Resolve and validate the per-chord candidate-search cap. */\nexport function resolveMaxCandidates(opts?: VoicingOptions): number | undefined {\n if (opts?.maxCandidates === undefined) return undefined;\n assertPositiveInt(opts.maxCandidates, 'maxCandidates', 1_000_000);\n return opts.maxCandidates;\n}\n\n/**\n * Realize a single chord as one MIDI pitch per voice, ascending (index 0 =\n * lowest). The bass voice takes the chord's `bassPc` when set, otherwise the\n * root; upper voices take chord pitch classes, doubling the root or fifth as\n * needed to fill all voices. The result stays inside each voice's range, keeps\n * adjacent upper voices within `maxSpacing`, avoids voice crossing, and is\n * deterministic: a compact close-position voicing centered in the ranges.\n *\n * @param chord The chord to voice.\n * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.\n * @returns MIDI pitches, ascending, one per voice.\n * @throws If no voicing fits the given ranges.\n * @example\n * ```ts\n * import { parseChordSymbol, voiceChord } from '@libraz/libcantus';\n * const chord = parseChordSymbol('Cmaj7');\n * voiceChord(chord); // four ascending MIDI pitches within the SATB ranges\n * ```\n * @category Voicing & Counterpoint\n */\nexport function voiceChord(chord: Chord, opts?: VoicingOptions): number[] {\n const ranges = resolveRanges(opts);\n const maxSpacing = resolveMaxSpacing(opts);\n const candidates = enumerateVoicings(chord, ranges, maxSpacing, resolveMaxCandidates(opts));\n let best: number[] | undefined;\n let bestScore = Number.POSITIVE_INFINITY;\n for (const candidate of candidates) {\n let score = structuralPenalty(candidate, chord, opts?.key);\n for (let i = 0; i < candidate.length; i += 1) {\n const pitch = candidate[i];\n const range = ranges[i];\n if (pitch === undefined || range === undefined) {\n continue;\n }\n // Prefer pitches near the middle of each voice's range for a centered,\n // compact default voicing.\n score += Math.abs(pitch - (range.min + range.max) / 2);\n }\n if (score < bestScore) {\n bestScore = score;\n best = candidate;\n }\n }\n if (best === undefined) {\n throw new NoSolutionError(\n `no voicing satisfies the given ranges for ${formatChordSymbol(chord)}`,\n );\n }\n return best;\n}\n\n/**\n * Voice a chord progression with smooth voice leading. The first chord is\n * voiced with {@link voiceChord}; each subsequent chord picks, from a bounded\n * deterministic candidate set, the voicing minimizing the voice-leading cost\n * from the previous voicing plus a large penalty per counterpoint violation\n * (parallel perfects/octaves, voice crossing, voice overlap, and over-wide\n * upper-voice spacing).\n *\n * Tendency tones are resolved rather than merely moved economically: the voice\n * holding a chordal seventh falls by step unless the next chord keeps that tone,\n * and — when `opts.key` is given — the leading tone rises to the tonic and is\n * never doubled. Without a key the leading-tone rules cannot apply, since\n * nothing identifies which pitch class is the leading tone.\n *\n * @param chords The chords to voice in order.\n * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.\n * @returns One voicing per chord, each ascending with one MIDI pitch per voice.\n * @throws If any chord admits no voicing within the given ranges, or if the\n * progression is longer than `opts.budget` chords.\n * @example\n * ```ts\n * import { parseChordSymbol, voiceProgression } from '@libraz/libcantus';\n * const chords = ['C', 'Am', 'F', 'G'].map((s) => parseChordSymbol(s));\n * voiceProgression(chords); // one four-voice voicing per chord, smoothly led\n * ```\n * @category Voicing & Counterpoint\n */\n/** The unsatisfiable-constraints error for one chord of a progression. */\nfunction noSolutionAt(index: number, chord: Chord): NoSolutionError {\n return new NoSolutionError(\n `no voicing satisfies the given ranges for ${formatChordSymbol(chord)} at index ${index}`,\n { at: index },\n );\n}\n\n/**\n * Run one chord's work, re-raising an unsatisfiable-constraints failure with\n * the chord it happened on. Voicing a whole lead sheet is otherwise told only\n * that some chord did not fit.\n */\nfunction locate<T>(index: number, chord: Chord, work: () => T): T {\n try {\n return work();\n } catch (error) {\n if (error instanceof NoSolutionError) {\n throw noSolutionAt(index, chord);\n }\n throw error;\n }\n}\n\n/**\n * Voice a chord progression with smooth, bounded SATB-style leading.\n *\n * Each chord is chosen from a deterministic candidate set, minimizing motion\n * while penalizing counterpoint violations. A supplied key additionally\n * resolves leading tones and chordal sevenths.\n *\n * @param chords The chords to voice in order.\n * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.\n * @returns One ascending MIDI voicing per chord.\n * @throws {@link NoSolutionError} with the failing chord index when a chord\n * cannot fit the requested ranges.\n * @category Voicing & Counterpoint\n */\nexport function voiceProgression(chords: readonly Chord[], opts?: VoicingOptions): number[][] {\n assertGenerationBudget(chords.length, 'voiced progression chords', opts?.budget);\n const ranges = resolveRanges(opts);\n const maxSpacing = resolveMaxSpacing(opts);\n const maxCandidates = resolveMaxCandidates(opts);\n const result: number[][] = [];\n let prev: number[] | undefined;\n let prevChord: Chord | undefined;\n for (let index = 0; index < chords.length; index += 1) {\n const chord = chords[index];\n if (chord === undefined) {\n continue;\n }\n if (prev === undefined) {\n prev = locate(index, chord, () => voiceChord(chord, opts));\n prevChord = chord;\n result.push(prev);\n continue;\n }\n const candidates = locate(index, chord, () =>\n enumerateVoicings(chord, ranges, maxSpacing, maxCandidates),\n );\n let best: number[] | undefined;\n let bestScore = Number.POSITIVE_INFINITY;\n for (const candidate of candidates) {\n const unresolved =\n prevChord === undefined\n ? 0\n : resolutionViolations(prev, candidate, prevChord, chord, opts?.key);\n const score =\n structuralPenalty(candidate, chord, opts?.key) +\n voiceLeadingCost(prev, candidate) +\n VIOLATION_PENALTY * violationCount(prev, candidate) +\n RESOLUTION_PENALTY * unresolved;\n if (score < bestScore) {\n bestScore = score;\n best = candidate;\n }\n }\n if (best === undefined) {\n throw noSolutionAt(index, chord);\n }\n result.push(best);\n prev = best;\n prevChord = chord;\n }\n return result;\n}\n","import { InvalidInputError } from '../../core/errors/index.js';\nimport { assertFiniteNumber, assertInteger } from '../../core/validation/index.js';\nimport type { Chord } from '../chord/index.js';\nimport { chordToneRole } from '../chord/index.js';\nimport { pitchClass } from './internal.js';\n\n/**\n * A tertian voicing style for {@link voiceChordStyled}.\n *\n * - `close`: the plain close-position tertian stack.\n * - `drop2`: the second voice from the top dropped an octave (drop-2 voicing).\n * - `drop3`: the third voice from the top dropped an octave (drop-3 voicing).\n * - `shell`: root plus guide tones (third and seventh) for seventh chords, or\n * root/third/fifth for triads; the fifth and tensions are omitted.\n * - `rootless`: the root omitted, keeping third/fifth/seventh and tensions\n * (a typical left-hand jazz voicing).\n *\n * @category Voicing & Counterpoint\n */\nexport type VoicingStyle = 'close' | 'drop2' | 'drop3' | 'shell' | 'rootless';\n\n/**\n * Options controlling {@link voiceChordStyled}.\n *\n * @category Voicing & Counterpoint\n */\nexport type StyledVoicingOptions = {\n /**\n * Voicing style to build.\n *\n * @defaultValue 'close'\n */\n style?: VoicingStyle;\n /** Constrain the highest voice to this pitch class (0..11) when given. */\n topNote?: number;\n /**\n * Base octave in scientific pitch notation: octave 4 starts the stack near\n * middle C (MIDI 60), i.e. near `12 * (octave + 1)`.\n *\n * @defaultValue 4\n */\n octave?: number;\n /**\n * Omit the root regardless of style (relevant for jazz voicings).\n *\n * @defaultValue false\n */\n rootless?: boolean;\n};\n\n/** Default base octave for a styled close-position stack. */\nconst DEFAULT_STYLE_OCTAVE = 4;\n\n/** Return the pitch classes of a list in order, without duplicates. */\nfunction dedupePcs(pcs: number[]): number[] {\n const seen = new Set<number>();\n const result: number[] = [];\n for (const pc of pcs) {\n if (!seen.has(pc)) {\n seen.add(pc);\n result.push(pc);\n }\n }\n return result;\n}\n\n/** The lowest MIDI pitch of a pitch class at or above a floor. */\nfunction lowestPitchAtOrAbove(pc: number, floor: number): number {\n return floor + ((((pc - pitchClass(floor)) % 12) + 12) % 12);\n}\n\n/** The pitch class in `pcs` whose circular distance to `target` is smallest. */\nfunction nearestPc(target: number, pcs: number[]): number {\n let best = pcs[0] ?? target;\n let bestDist = 12;\n for (const pc of pcs) {\n const dist = Math.min((((pc - target) % 12) + 12) % 12, (((target - pc) % 12) + 12) % 12);\n if (dist < bestDist) {\n bestDist = dist;\n best = pc;\n }\n }\n return best;\n}\n\n/**\n * Realize a single chord as an explicit tertian voicing in a chosen style,\n * independent of the SATB range search used by {@link voiceChord}.\n *\n * The chord tones are stacked in close position from the bass (`bassPc`, else\n * `rootPc`) in the given scientific-pitch `octave` upward (octave 4 starts the\n * bass near C4 = MIDI 60, matching {@link midiToNote} and the bass module).\n * When `topNote` is given the stack is rotated so the highest voice's pitch\n * class equals that note (or the nearest chord tone). The chosen\n * {@link VoicingStyle} then transforms the stack, and the result is returned as\n * ascending MIDI pitches (index 0 = lowest).\n *\n * Every returned pitch is a valid MIDI number: an octave whose stack would run\n * off either end of the 0..127 range is rejected rather than voiced out of\n * range, matching {@link nextVoicing}, which clamps its derived ranges.\n *\n * @param chord The chord to voice.\n * @param opts Styled voicing options; defaults to a close voicing at octave 4.\n * @returns MIDI pitches, ascending, one per retained voice.\n * @throws If the voicing would not fit inside MIDI 0..127 at the given octave.\n * @example\n * ```ts\n * import { parseChordSymbol, voiceChordStyled } from '@libraz/libcantus';\n * const chord = parseChordSymbol('Dm7');\n * voiceChordStyled(chord, { style: 'drop2' }); // ascending MIDI pitches, drop-2 voicing\n * ```\n * @category Voicing & Counterpoint\n */\nexport function voiceChordStyled(chord: Chord, opts?: StyledVoicingOptions): number[] {\n const style = opts?.style ?? 'close';\n const octave = opts?.octave ?? DEFAULT_STYLE_OCTAVE;\n assertInteger(octave, 'styled voicing octave', -10, 10);\n if (opts?.topNote !== undefined) {\n assertFiniteNumber(opts.topNote, 'styled voicing topNote');\n }\n const base = 12 * (octave + 1);\n const rootPc = pitchClass(chord.rootPc);\n const bassPc = pitchClass(chord.bassPc ?? chord.rootPc);\n const omitRoot = style === 'rootless' || opts?.rootless === true;\n\n // Tertian chord tones in order, with the bass tone rotated to the bottom.\n let order = dedupePcs(chord.intervals.map((interval) => pitchClass(chord.rootPc + interval)));\n const bassIndex = order.indexOf(bassPc);\n if (bassIndex > 0) {\n order = [...order.slice(bassIndex), ...order.slice(0, bassIndex)];\n } else if (bassIndex < 0) {\n order = [bassPc, ...order];\n }\n\n if (style === 'shell') {\n const roles = order.map((pc) => chordToneRole(pc, chord));\n // The guide tone is the seventh when present; on a sixth chord the sixth\n // stands in for it, and otherwise the voicing falls back to the fifth.\n const guide = roles.includes('seventh')\n ? 'seventh'\n : roles.includes('sixth')\n ? 'sixth'\n : 'fifth';\n order = order.filter((_pc, i) => {\n const role = roles[i];\n return _pc === bassPc || role === 'root' || role === 'third' || role === guide;\n });\n }\n\n if (omitRoot) {\n order = order.filter((pc) => pc !== rootPc || (chord.bassPc !== undefined && pc === bassPc));\n }\n\n if (order.length === 0) {\n return [];\n }\n\n if (opts?.topNote !== undefined) {\n const target = order.includes(pitchClass(opts.topNote))\n ? pitchClass(opts.topNote)\n : nearestPc(pitchClass(opts.topNote), order);\n const targetIndex = order.indexOf(target);\n order = [...order.slice(targetIndex + 1), ...order.slice(0, targetIndex + 1)];\n }\n\n // Stack the ordered pitch classes upward in close position.\n const stack: number[] = [];\n let prev: number | undefined;\n for (const pc of order) {\n if (prev === undefined) {\n prev = lowestPitchAtOrAbove(pc, base);\n } else {\n let delta = (((pc - pitchClass(prev)) % 12) + 12) % 12;\n if (delta === 0) {\n delta = 12;\n }\n prev += delta;\n }\n stack.push(prev);\n }\n\n if (style === 'drop2' && stack.length >= 2) {\n stack[stack.length - 2] = (stack[stack.length - 2] ?? 0) - 12;\n } else if (style === 'drop3' && stack.length >= 3) {\n stack[stack.length - 3] = (stack[stack.length - 3] ?? 0) - 12;\n }\n\n // An explicit slash bass is a structural requirement, including when it is\n // not a chord member. Drop voicings and top-note rotation may have moved a\n // different tone below it, so lower the retained bass by octaves before the\n // final sort. This gives the bass priority over a conflicting top-note hint.\n if (chord.bassPc !== undefined) {\n const bassIndexInStack = stack.findIndex((pitch) => pitchClass(pitch) === bassPc);\n if (bassIndexInStack >= 0) {\n const otherLowest = Math.min(\n ...stack.filter((_pitch, index) => index !== bassIndexInStack),\n Number.POSITIVE_INFINITY,\n );\n while ((stack[bassIndexInStack] ?? 0) >= otherLowest) {\n stack[bassIndexInStack] = (stack[bassIndexInStack] ?? 0) - 12;\n }\n }\n }\n\n const voicing = stack.sort((a, b) => a - b);\n const lowest = voicing[0] ?? 0;\n const highest = voicing[voicing.length - 1] ?? 0;\n if (lowest < 0 || highest > 127) {\n throw new InvalidInputError(\n `styled voicing at octave ${octave} spans MIDI ${lowest}..${highest}, outside 0..127`,\n );\n }\n return voicing;\n}\n"],"mappings":"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","names":[]}
@@ -5,16 +5,16 @@ import {
5
5
  functionOf,
6
6
  isDiatonic,
7
7
  parallelKey
8
- } from "./chunk-KMHOICIY.js";
8
+ } from "./chunk-NNB67XA2.js";
9
9
  import {
10
10
  chordPitchClasses,
11
11
  diatonicTriad,
12
12
  makeChord,
13
13
  scaleTonesInDegreeOrder
14
- } from "./chunk-D2FAJBYL.js";
14
+ } from "./chunk-KBTTEX7Q.js";
15
15
  import {
16
16
  pitchClassOf
17
- } from "./chunk-XEBG3G53.js";
17
+ } from "./chunk-R2VVFAIN.js";
18
18
 
19
19
  // src/generate/reharmony/index.ts
20
20
  function hasInterval(chord, semitone) {
@@ -23,11 +23,6 @@ function hasInterval(chord, semitone) {
23
23
  function isDominantType(chord) {
24
24
  return hasInterval(chord, 4) && hasInterval(chord, 10);
25
25
  }
26
- function isStableTarget(chord) {
27
- const hasFifth = hasInterval(chord, 7);
28
- const hasThird = hasInterval(chord, 3) || hasInterval(chord, 4);
29
- return hasFifth && hasThird && !isDominantType(chord);
30
- }
31
26
  function commonToneCount(a, b) {
32
27
  const set = new Set(b);
33
28
  return a.filter((pc) => set.has(pc)).length;
@@ -64,12 +59,6 @@ function substituteChord(chord, key, opts) {
64
59
  if (isDominantType(chord)) {
65
60
  candidates.push({ chord: makeChord(pitchClassOf(chord.rootPc + 6), "dom7"), type: "tritone" });
66
61
  }
67
- if (isStableTarget(chord)) {
68
- candidates.push({
69
- chord: makeChord(pitchClassOf(chord.rootPc + 7), "dom7"),
70
- type: "secondaryDominant"
71
- });
72
- }
73
62
  for (const triad of diatonicTriadsOf(key)) {
74
63
  const offset = pitchClassOf(triad.rootPc - chord.rootPc);
75
64
  if (THIRD_OFFSETS.includes(offset) && commonToneCount(originalTriad, chordPitchClasses(triad)) === 2) {
@@ -138,7 +127,7 @@ function modalInterchangePalette(key) {
138
127
  });
139
128
  };
140
129
  for (const triad of diatonicTriadsOf(parallelKey(key))) {
141
- if (!isDiatonic(triad, key)) {
130
+ if (!isDiatonic(triad, key) && borrowedSource(triad, key) !== null) {
142
131
  add(triad);
143
132
  }
144
133
  }
@@ -170,4 +159,4 @@ export {
170
159
  modalInterchangePalette,
171
160
  negativeHarmonyMirror
172
161
  };
173
- //# sourceMappingURL=chunk-GQSGS2N4.js.map
162
+ //# sourceMappingURL=chunk-7JEP3MFY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/generate/reharmony/index.ts"],"sourcesContent":["/**\n * Reharmonization: chord substitution, modal-interchange palettes, and negative\n * harmony. These transforms take an existing chord (or a key) and propose\n * alternative harmonies that preserve a chosen relationship — a shared function,\n * a common tone, a tonicizing dominant, or a reflection across the key axis.\n *\n * Roots are pitch classes (0..11); no spelled key signature is required.\n */\n\nimport { detectChordBest } from '../../analyze/detect/index.js';\nimport {\n type BorrowedSource,\n borrowedSource,\n chordToRoman,\n functionOf,\n type HarmonicFunction,\n isDiatonic,\n parallelKey,\n} from '../../analyze/functional/index.js';\nimport { pitchClassOf as mod12 } from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport {\n type Chord,\n type ChordQuality,\n chordPitchClasses,\n diatonicTriad,\n makeChord,\n} from '../../theory/chord/index.js';\nimport { scaleTonesInDegreeOrder } from '../../theory/scale/index.js';\n\n/**\n * The kind of substitution relationship a candidate realizes.\n *\n * @category Reharmonization\n */\nexport type SubstitutionType =\n | 'tritone'\n | 'relative'\n | 'borrowed'\n | 'chromaticMediant'\n | 'secondaryDominant';\n\n/**\n * A proposed chord substitution with its relationship, numeral, and function.\n *\n * @category Reharmonization\n */\nexport type Substitution = {\n chord: Chord;\n type: SubstitutionType;\n roman: string;\n function: HarmonicFunction;\n};\n\n/**\n * Options controlling which substitutions {@link substituteChord} returns.\n *\n * @category Reharmonization\n */\nexport type SubstituteOptions = {\n /**\n * Melody pitch classes that must remain chord tones. When given, only\n * substitutions whose pitch classes contain every listed pitch class are\n * kept, so the melody stays consonant against the new harmony.\n */\n melodyPcs?: number[];\n};\n\n/** Whether the chord's template carries a given interval (mod 12). */\nfunction hasInterval(chord: Chord, semitone: number): boolean {\n return chord.intervals.some((iv) => mod12(iv) === semitone);\n}\n\n/** Whether a chord is a dominant type: a major third with a minor seventh. */\nfunction isDominantType(chord: Chord): boolean {\n return hasInterval(chord, 4) && hasInterval(chord, 10);\n}\n\n/** Count the pitch classes shared between two pitch-class sets. */\nfunction commonToneCount(a: number[], b: number[]): number {\n const set = new Set(b);\n return a.filter((pc) => set.has(pc)).length;\n}\n\n/** The plain triad quality underlying a chord's own quality. */\nfunction triadQualityOf(chord: Chord): ChordQuality {\n const semis = new Set(chord.intervals.map((interval) => mod12(interval)));\n const hasThird = semis.has(4) ? 'maj' : semis.has(3) ? 'min' : undefined;\n if (hasThird === undefined) {\n return chord.quality; // sus, power, and other non-tertian chords stand alone\n }\n if (semis.has(6) && !semis.has(7)) {\n return hasThird === 'min' ? 'dim' : 'majb5';\n }\n if (semis.has(8) && !semis.has(7)) {\n return 'aug';\n }\n return hasThird;\n}\n\n/** The diatonic triads of a key, one per scale degree. */\nfunction diatonicTriadsOf(key: KeyScale): Chord[] {\n const degrees = scaleTonesInDegreeOrder(key).length;\n const triads: Chord[] = [];\n for (let degree = 0; degree < degrees; degree += 1) {\n triads.push(diatonicTriad(degree, key));\n }\n return triads;\n}\n\n/** Whether two chords share the same root pitch class and quality. */\nfunction sameChord(a: Chord, b: Chord): boolean {\n return mod12(a.rootPc) === mod12(b.rootPc) && a.quality === b.quality;\n}\n\n/** Root offsets (semitones) that form a third above or below a root. */\nconst THIRD_OFFSETS = [3, 4, 8, 9] as const;\n\n/**\n * Propose substitutions for a chord within a key.\n *\n * Candidates are generated by several relationships and deduplicated against the\n * original chord and each other:\n *\n * - `tritone`: for a dominant-type chord, the dominant seventh a tritone away.\n * - `relative`: a diatonic triad a third away that shares two common tones.\n * - `borrowed`: a triad from the parallel mode with the same harmonic function.\n * - `chromaticMediant`: a major/minor triad a third away sharing one common\n * tone.\n *\n * Each result carries its Roman numeral and harmonic function in `key`. When\n * `opts.melodyPcs` is given, only substitutions whose pitch classes contain all\n * of those pitch classes are returned.\n *\n * @param chord The chord to reharmonize.\n * @param key The prevailing key.\n * @param opts Optional melody-preservation constraint.\n * @returns The deduplicated substitution candidates.\n * @example\n * ```ts\n * import { substituteChord, makeChord, majorKey } from '@libraz/libcantus';\n * const subs = substituteChord(makeChord(7, 'dom7'), majorKey(0));\n * // includes the tritone sub Db7 (rootPc 1, quality 'dom7')\n * ```\n * @category Reharmonization\n */\nexport function substituteChord(\n chord: Chord,\n key: KeyScale,\n opts?: SubstituteOptions,\n): Substitution[] {\n // The relative test counts common tones against the chord's triad, not its\n // full pitch-class set: an exact count of two would otherwise be decided by\n // how many tensions the input carries, so C proposes both Em and Am while\n // Cmaj7 proposes only Am — penalising the candidate that overlaps *more*.\n const originalTriad = chordPitchClasses(makeChord(chord.rootPc, triadQualityOf(chord)));\n const candidates: { chord: Chord; type: SubstitutionType }[] = [];\n\n // Tritone substitution: only for dominant-type chords.\n if (isDominantType(chord)) {\n candidates.push({ chord: makeChord(mod12(chord.rootPc + 6), 'dom7'), type: 'tritone' });\n }\n\n // Relative: a diatonic triad a third away sharing two common tones.\n for (const triad of diatonicTriadsOf(key)) {\n const offset = mod12(triad.rootPc - chord.rootPc);\n if (\n (THIRD_OFFSETS as readonly number[]).includes(offset) &&\n commonToneCount(originalTriad, chordPitchClasses(triad)) === 2\n ) {\n candidates.push({ chord: triad, type: 'relative' });\n }\n }\n\n // Borrowed: a parallel-mode triad sharing the original's harmonic function.\n const targetFunction = functionOf(chord, key);\n for (const triad of diatonicTriadsOf(parallelKey(key))) {\n if (functionOf(triad, key) === targetFunction && !isDiatonic(triad, key)) {\n candidates.push({ chord: triad, type: 'borrowed' });\n }\n }\n\n // Chromatic mediants: major/minor triads a third away sharing one common tone.\n for (const offset of THIRD_OFFSETS) {\n for (const quality of ['maj', 'min'] as const) {\n const mediant = makeChord(mod12(chord.rootPc + offset), quality);\n if (\n commonToneCount(originalTriad, chordPitchClasses(mediant)) === 1 &&\n !isDiatonic(mediant, key)\n ) {\n candidates.push({ chord: mediant, type: 'chromaticMediant' });\n }\n }\n }\n\n const melodyPcs = opts?.melodyPcs?.map(mod12);\n const seen = new Set<string>();\n const results: Substitution[] = [];\n for (const candidate of candidates) {\n if (sameChord(candidate.chord, chord)) {\n continue;\n }\n const dedupeKey = `${mod12(candidate.chord.rootPc)}:${candidate.chord.quality}`;\n if (seen.has(dedupeKey)) {\n continue;\n }\n seen.add(dedupeKey);\n if (melodyPcs !== undefined) {\n const pcs = new Set(chordPitchClasses(candidate.chord));\n if (!melodyPcs.every((pc) => pcs.has(pc))) {\n continue;\n }\n }\n results.push({\n chord: candidate.chord,\n type: candidate.type,\n // A secondary dominant is named as the applied chord it is, so the\n // numeral re-parses to the chord that was proposed rather than to a\n // chromatic chord on the same root.\n roman: chordToRoman(candidate.chord, key, {\n applied: candidate.type === 'secondaryDominant',\n }),\n function: functionOf(candidate.chord, key),\n });\n }\n return results;\n}\n\n/**\n * A borrowed chord in the modal-interchange palette of a key.\n *\n * @category Reharmonization\n */\nexport type BorrowedChord = {\n chord: Chord;\n roman: string;\n source: BorrowedSource;\n};\n\n/**\n * The modal-interchange palette of a key.\n *\n * Lists the diatonic triads of the {@link parallelKey} that are not diatonic to\n * `key` (the classic borrowed chords such as `iv`, `bVI`, and `bVII` in a major\n * key), plus the Neapolitan (a major triad on the flat second degree). Each\n * carries its Roman numeral and {@link borrowedSource} relative to `key`.\n *\n * @param key The prevailing key.\n * @returns The borrowed-chord palette.\n * @category Reharmonization\n */\nexport function modalInterchangePalette(key: KeyScale): BorrowedChord[] {\n const palette: BorrowedChord[] = [];\n const seen = new Set<string>();\n const add = (chord: Chord) => {\n const dedupeKey = `${mod12(chord.rootPc)}:${chord.quality}`;\n if (seen.has(dedupeKey)) {\n return;\n }\n seen.add(dedupeKey);\n palette.push({\n chord,\n roman: chordToRoman(chord, key),\n source: borrowedSource(chord, key),\n });\n };\n\n for (const triad of diatonicTriadsOf(parallelKey(key))) {\n if (!isDiatonic(triad, key) && borrowedSource(triad, key) !== null) {\n add(triad);\n }\n }\n // The Neapolitan (major triad on b2) sits outside both parallel modes, so it\n // is added explicitly — unless b2 is already diatonic (e.g. in a Phrygian key,\n // where it is a native chord rather than a borrowing).\n const neapolitan = makeChord(mod12(key.rootPc + 1), 'maj');\n if (!isDiatonic(neapolitan, key)) {\n add(neapolitan);\n }\n return palette;\n}\n\n/**\n * Reflect a chord across the tonic–dominant axis of a key (negative harmony).\n *\n * Every pitch class `p` maps to `(2*T + 7 - p) mod 12`, where `T` is the key\n * tonic — the reflection that swaps the tonic with the dominant. The mirrored\n * pitch classes (including the bass, if set) are reassembled into a chord by\n * {@link detectChordBest}; when no chord is recognized, the mirrored root and\n * the original quality are used as a fallback.\n *\n * @param chord The chord to reflect.\n * @param key The prevailing key.\n * @returns The negative-harmony counterpart of the chord.\n * @example\n * ```ts\n * import { negativeHarmonyMirror, makeChord, majorKey } from '@libraz/libcantus';\n * negativeHarmonyMirror(makeChord(7, 'maj'), majorKey(0));\n * // G major reflected across C's axis => F minor (rootPc 5, quality 'min')\n * ```\n * @category Reharmonization\n */\nexport function negativeHarmonyMirror(chord: Chord, key: KeyScale): Chord {\n const tonic = mod12(key.rootPc);\n const mirror = (p: number) => mod12(2 * tonic + 7 - p);\n const pcs = chordPitchClasses(chord).map(mirror);\n const bassPc = chord.bassPc !== undefined ? mirror(chord.bassPc) : undefined;\n // Place the mirrored bass an octave below so it is recognized as the lowest\n // note and preserved through detection.\n const pitches = bassPc !== undefined ? [bassPc - 12, ...pcs] : pcs;\n const detected = detectChordBest(pitches);\n if (detected) {\n // Without an input bass the mirrored tones are octave-less, so detection may\n // read the lowest pitch class as a slash bass and report a spurious\n // inversion. Restore the recognized chord to root position in that case.\n if (bassPc === undefined && detected.bassPc !== undefined) {\n return makeChord(detected.rootPc, detected.quality);\n }\n return detected;\n }\n const quality: ChordQuality = chord.quality;\n return makeChord(mirror(chord.rootPc), quality, bassPc);\n}\n"],"mappings":"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","names":[]}