@libraz/libcantus 0.9.3 → 0.9.4

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 (198) hide show
  1. package/README.md +2 -2
  2. package/dist/analyze/index.cjs +39 -1947
  3. package/dist/analyze/index.cjs.map +1 -1
  4. package/dist/analyze/index.d.cts +197 -37
  5. package/dist/analyze/index.d.ts +197 -37
  6. package/dist/analyze/index.js +19 -8
  7. package/dist/chunk-36N73KZ3.cjs +246 -0
  8. package/dist/chunk-36N73KZ3.cjs.map +1 -0
  9. package/dist/chunk-4HLLZPXT.cjs +3077 -0
  10. package/dist/chunk-4HLLZPXT.cjs.map +1 -0
  11. package/dist/chunk-7MGZ7D62.cjs +498 -0
  12. package/dist/chunk-7MGZ7D62.cjs.map +1 -0
  13. package/dist/{chunk-4MHA432G.js → chunk-7NKDPF74.js} +403 -180
  14. package/dist/chunk-7NKDPF74.js.map +1 -0
  15. package/dist/chunk-CAN76NCU.cjs +679 -0
  16. package/dist/chunk-CAN76NCU.cjs.map +1 -0
  17. package/dist/{chunk-MIWO425M.js → chunk-D2FAJBYL.js} +101 -34
  18. package/dist/chunk-D2FAJBYL.js.map +1 -0
  19. package/dist/{chunk-SGU7SPLK.js → chunk-EHVEBWM5.js} +1056 -531
  20. package/dist/chunk-EHVEBWM5.js.map +1 -0
  21. package/dist/chunk-FCANXBAT.cjs +30 -0
  22. package/dist/chunk-FCANXBAT.cjs.map +1 -0
  23. package/dist/chunk-FNDWXRRI.cjs +479 -0
  24. package/dist/chunk-FNDWXRRI.cjs.map +1 -0
  25. package/dist/{chunk-IT2O4XFE.js → chunk-GQSGS2N4.js} +43 -24
  26. package/dist/chunk-GQSGS2N4.js.map +1 -0
  27. package/dist/{chunk-62QZKCJQ.js → chunk-HKGYCQ34.js} +10 -6
  28. package/dist/chunk-HKGYCQ34.js.map +1 -0
  29. package/dist/{chunk-AKLYPWIN.js → chunk-I24MV65U.js} +29 -6
  30. package/dist/chunk-I24MV65U.js.map +1 -0
  31. package/dist/{chunk-CHMXELDS.js → chunk-KMHOICIY.js} +311 -181
  32. package/dist/chunk-KMHOICIY.js.map +1 -0
  33. package/dist/chunk-LW53AHQU.cjs +1117 -0
  34. package/dist/chunk-LW53AHQU.cjs.map +1 -0
  35. package/dist/{chunk-2ZWMSJH6.js → chunk-NKIBQ6PT.js} +2 -2
  36. package/dist/chunk-NKIBQ6PT.js.map +1 -0
  37. package/dist/chunk-NP4NA2FB.cjs +106 -0
  38. package/dist/chunk-NP4NA2FB.cjs.map +1 -0
  39. package/dist/chunk-NVE34YGZ.cjs +1449 -0
  40. package/dist/chunk-NVE34YGZ.cjs.map +1 -0
  41. package/dist/{chunk-EH6EM37U.js → chunk-NYYWMV2C.js} +61 -49
  42. package/dist/chunk-NYYWMV2C.js.map +1 -0
  43. package/dist/{chunk-GOAW4VYL.js → chunk-Q2XUP227.js} +243 -117
  44. package/dist/chunk-Q2XUP227.js.map +1 -0
  45. package/dist/chunk-Q6OP4U43.cjs +327 -0
  46. package/dist/chunk-Q6OP4U43.cjs.map +1 -0
  47. package/dist/chunk-RC6GBMCD.cjs +845 -0
  48. package/dist/chunk-RC6GBMCD.cjs.map +1 -0
  49. package/dist/{chunk-C5XYKUVG.js → chunk-RK35RIN7.js} +370 -157
  50. package/dist/chunk-RK35RIN7.js.map +1 -0
  51. package/dist/chunk-RUMU3UA6.cjs +53 -0
  52. package/dist/chunk-RUMU3UA6.cjs.map +1 -0
  53. package/dist/chunk-T64C7ZD7.cjs +1 -0
  54. package/dist/chunk-T64C7ZD7.cjs.map +1 -0
  55. package/dist/chunk-XEBG3G53.js +498 -0
  56. package/dist/chunk-XEBG3G53.js.map +1 -0
  57. package/dist/{chunk-I5R7ZBJS.js → chunk-YLEMGEFH.js} +103 -59
  58. package/dist/chunk-YLEMGEFH.js.map +1 -0
  59. package/dist/chunk-ZEJR4TKL.cjs +173 -0
  60. package/dist/chunk-ZEJR4TKL.cjs.map +1 -0
  61. package/dist/core/index.cjs +130 -647
  62. package/dist/core/index.cjs.map +1 -1
  63. package/dist/core/index.d.cts +301 -39
  64. package/dist/core/index.d.ts +301 -39
  65. package/dist/core/index.js +54 -16
  66. package/dist/{function-DYt4iKsn.d.cts → function-BtiZb9i9.d.ts} +28 -7
  67. package/dist/{function-DVH4Eusr.d.ts → function-DNugAOrt.d.cts} +28 -7
  68. package/dist/generate/index.cjs +28 -4085
  69. package/dist/generate/index.cjs.map +1 -1
  70. package/dist/generate/index.d.cts +370 -62
  71. package/dist/generate/index.d.ts +370 -62
  72. package/dist/generate/index.js +23 -9
  73. package/dist/{index-CxqBQtH1.d.cts → index-6VR8-kit.d.ts} +19 -4
  74. package/dist/index-70p168VM.d.ts +192 -0
  75. package/dist/{index-CpOsP1y9.d.cts → index-Be74mcon.d.cts} +18 -17
  76. package/dist/index-BtXT6UQ0.d.cts +192 -0
  77. package/dist/{index-DxvARIP2.d.ts → index-C5UBbQ4G.d.ts} +18 -17
  78. package/dist/{index-Bt4tOUD9.d.ts → index-C83mZI1P.d.ts} +93 -8
  79. package/dist/{index-Bg5dYMmZ.d.ts → index-D6b6na69.d.cts} +14 -11
  80. package/dist/{index-Cl7mhOFM.d.cts → index-DXd9JikN.d.cts} +92 -10
  81. package/dist/{index-Cl7mhOFM.d.ts → index-DXd9JikN.d.ts} +92 -10
  82. package/dist/index-OG65ocOr.d.cts +272 -0
  83. package/dist/index-OG65ocOr.d.ts +272 -0
  84. package/dist/{index-Jc0Ryi79.d.ts → index-tJhkmQgE.d.cts} +19 -4
  85. package/dist/{index-Dikst44v.d.cts → index-tSQh-xwY.d.ts} +14 -11
  86. package/dist/{index-BNlGP86A.d.cts → index-y_ak9_Hi.d.cts} +93 -8
  87. package/dist/index.cjs +419 -7383
  88. package/dist/index.cjs.map +1 -1
  89. package/dist/index.d.cts +14 -14
  90. package/dist/index.d.ts +14 -14
  91. package/dist/index.js +111 -27
  92. package/dist/model/index.cjs +8 -2562
  93. package/dist/model/index.cjs.map +1 -1
  94. package/dist/model/index.d.cts +433 -75
  95. package/dist/model/index.d.ts +433 -75
  96. package/dist/model/index.js +6 -7
  97. package/dist/styled-DIRkk9Uz.d.ts +506 -0
  98. package/dist/styled-DJbkJQfj.d.cts +506 -0
  99. package/dist/theory/index.cjs +172 -1822
  100. package/dist/theory/index.cjs.map +1 -1
  101. package/dist/theory/index.d.cts +151 -233
  102. package/dist/theory/index.d.ts +151 -233
  103. package/dist/theory/index.js +30 -7
  104. package/dist/{types-MGP29r3t.d.cts → types-BN6_Q9Kl.d.cts} +11 -2
  105. package/dist/{types-MGP29r3t.d.ts → types-BN6_Q9Kl.d.ts} +11 -2
  106. package/package.json +24 -6
  107. package/dist/chunk-2ZWMSJH6.js.map +0 -1
  108. package/dist/chunk-4MHA432G.js.map +0 -1
  109. package/dist/chunk-62QZKCJQ.js.map +0 -1
  110. package/dist/chunk-AKLYPWIN.js.map +0 -1
  111. package/dist/chunk-C5XYKUVG.js.map +0 -1
  112. package/dist/chunk-CHMXELDS.js.map +0 -1
  113. package/dist/chunk-DYWFNC4A.js +0 -152
  114. package/dist/chunk-DYWFNC4A.js.map +0 -1
  115. package/dist/chunk-EH6EM37U.js.map +0 -1
  116. package/dist/chunk-FBQK3ZQN.js +0 -131
  117. package/dist/chunk-FBQK3ZQN.js.map +0 -1
  118. package/dist/chunk-GOAW4VYL.js.map +0 -1
  119. package/dist/chunk-I5R7ZBJS.js.map +0 -1
  120. package/dist/chunk-IT2O4XFE.js.map +0 -1
  121. package/dist/chunk-MIWO425M.js.map +0 -1
  122. package/dist/chunk-SGU7SPLK.js.map +0 -1
  123. package/dist/index-CGMZNCx6.d.cts +0 -140
  124. package/dist/index-CGMZNCx6.d.ts +0 -140
  125. package/dist/index-CnZCo29u.d.cts +0 -108
  126. package/dist/index-JnF4v9bx.d.ts +0 -108
  127. package/dist/styled-DZ7GjShb.d.ts +0 -282
  128. package/dist/styled-ZTbdaVFM.d.cts +0 -282
  129. package/src/analyze/arrange/index.ts +0 -21
  130. package/src/analyze/arrange/internal.ts +0 -127
  131. package/src/analyze/arrange/tension.ts +0 -199
  132. package/src/analyze/arrange/tracks.ts +0 -312
  133. package/src/analyze/detect/index.ts +0 -272
  134. package/src/analyze/functional/borrowed.ts +0 -84
  135. package/src/analyze/functional/cadence.ts +0 -66
  136. package/src/analyze/functional/function.ts +0 -184
  137. package/src/analyze/functional/index.ts +0 -23
  138. package/src/analyze/functional/internal.ts +0 -29
  139. package/src/analyze/functional/roman.ts +0 -402
  140. package/src/analyze/index.ts +0 -49
  141. package/src/analyze/timeline/index.ts +0 -451
  142. package/src/analyze/voice/index.ts +0 -339
  143. package/src/core/event-index/index.ts +0 -104
  144. package/src/core/index.ts +0 -61
  145. package/src/core/interval/index.ts +0 -81
  146. package/src/core/meter/index.ts +0 -302
  147. package/src/core/pitch/index.ts +0 -311
  148. package/src/core/random/index.ts +0 -76
  149. package/src/core/tuning/index.ts +0 -186
  150. package/src/core/types.ts +0 -29
  151. package/src/core/validation/index.ts +0 -119
  152. package/src/generate/bass/index.ts +0 -373
  153. package/src/generate/countermelody/index.ts +0 -470
  154. package/src/generate/drums/beat.ts +0 -266
  155. package/src/generate/drums/euclid.ts +0 -65
  156. package/src/generate/drums/fills.ts +0 -356
  157. package/src/generate/drums/ghost.ts +0 -119
  158. package/src/generate/drums/hihat.ts +0 -285
  159. package/src/generate/drums/hit.ts +0 -31
  160. package/src/generate/drums/index.ts +0 -361
  161. package/src/generate/drums/internal.ts +0 -257
  162. package/src/generate/drums/kick.ts +0 -160
  163. package/src/generate/drums/percussion.ts +0 -121
  164. package/src/generate/drums/rng.ts +0 -7
  165. package/src/generate/drums/swing.ts +0 -71
  166. package/src/generate/groove/index.ts +0 -351
  167. package/src/generate/harmonize/index.ts +0 -451
  168. package/src/generate/index.ts +0 -58
  169. package/src/generate/motif/index.ts +0 -422
  170. package/src/generate/progression/index.ts +0 -362
  171. package/src/generate/reharmony/index.ts +0 -323
  172. package/src/generate/rhythm/index.ts +0 -175
  173. package/src/index.ts +0 -13
  174. package/src/model/chord.ts +0 -442
  175. package/src/model/index.ts +0 -15
  176. package/src/model/interval.ts +0 -82
  177. package/src/model/key.ts +0 -266
  178. package/src/model/note.ts +0 -176
  179. package/src/model/progression.ts +0 -161
  180. package/src/model/shared.ts +0 -12
  181. package/src/theory/chord/index.ts +0 -375
  182. package/src/theory/chordscale/index.ts +0 -374
  183. package/src/theory/counterpoint/index.ts +0 -230
  184. package/src/theory/harmony/index.ts +0 -77
  185. package/src/theory/index.ts +0 -112
  186. package/src/theory/safety/index.ts +0 -488
  187. package/src/theory/scale/degrees.ts +0 -123
  188. package/src/theory/scale/index.ts +0 -28
  189. package/src/theory/scale/key.ts +0 -56
  190. package/src/theory/scale/masks.ts +0 -153
  191. package/src/theory/spelling/index.ts +0 -249
  192. package/src/theory/symbol/index.ts +0 -268
  193. package/src/theory/voicing/index.ts +0 -5
  194. package/src/theory/voicing/internal.ts +0 -168
  195. package/src/theory/voicing/leading.ts +0 -112
  196. package/src/theory/voicing/satb.ts +0 -216
  197. package/src/theory/voicing/styled.ts +0 -199
  198. package/tsconfig.json +0 -23
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/libcantus/libcantus/dist/chunk-CAN76NCU.cjs","../src/analyze/detect/index.ts","../src/analyze/functional/internal.ts","../src/analyze/functional/roman.ts","../src/analyze/functional/borrowed.ts","../src/analyze/functional/function.ts","../src/analyze/functional/cadence.ts"],"names":[],"mappings":"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AAC5B;AAgB2B;AACA,EAAA;AAChB,IAAA;AACT,EAAA;AACmB,EAAA;AACC,EAAA;AACG,EAAA;AACG,IAAA;AAC1B,EAAA;AACO,EAAA;AACT;AA2ByC;AACd,EAAA;AAC3B;AAYqD;AAC5C,EAAA;AACS,IAAA;AACS,IAAA;AACzB,EAAA;AACF;AAGS;AACY,EAAA;AACrB;AAGuB;AACE,EAAA;AACzB;AAsB6B;AACZ,EAAA;AACR,EAAA;AACgB,IAAA;AACA,IAAA;AACrB,IAAA;AACoB,IAAA;AACtB,EAAA;AACF;AAWkC;AAGlB,EAAA;AACK,EAAA;AACF,EAAA;AACnB;AL+Z4B;AACA;AMrlBE;AACd,EAAA;AACK,EAAA;AACF,EAAA;AAIQ,EAAA;AACD,EAAA;AACf,IAAA;AACT,EAAA;AACwB,EAAA;AACf,IAAA;AACT,EAAA;AACwB,EAAA;AACf,IAAA;AACT,EAAA;AAGsB,EAAA;AACb,IAAA;AACT,EAAA;AACO,EAAA;AACT;ANklB4B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/libcantus/libcantus/dist/chunk-CAN76NCU.cjs","sourcesContent":[null,"/**\n * Recognition: infer a chord name from a set of pitches, or a key from a set of\n * pitch classes. This is the inverse direction of the chord/scale builders,\n * which only go name -> notes.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\nimport type { KeyScale, NoteEvent } from '../../core/types.js';\nimport { assertFiniteNumber, assertGenerationBudget } from '../../core/validation/index.js';\nimport type { Chord, ChordQuality } from '../../theory/chord/index.js';\nimport { chordPitchClasses, chordQualities, makeChord } from '../../theory/chord/index.js';\nimport {\n HARMONIC_MINOR_MASK,\n MAJOR_MASK,\n MELODIC_MINOR_MASK,\n NATURAL_MINOR_MASK,\n} from '../../theory/scale/index.js';\n\n/**\n * A candidate chord interpretation of a pitch set.\n *\n * @category Recognition\n */\nexport type ChordMatch = {\n rootPc: number;\n quality: ChordQuality;\n /** Chord tones absent from the input (an incomplete voicing). */\n missingPcs: number[];\n /** Input pitch classes not belonging to the chord. */\n extraPcs: number[];\n /** True when the input pitch-class set equals the chord exactly. */\n exact: boolean;\n /**\n * Inversion implied by a known bass: 0 for root position, 1..n for an\n * inversion. Null when no inversion can be named — either the input is an\n * unordered pitch-class set with no bass, or the bass is not a chord tone (a\n * pedal or passing bass), in which case `bassPc` still reports it.\n */\n inversion: number | null;\n /** Bass pitch class when the lowest note is not the root. */\n bassPc?: number;\n};\n\n/**\n * Input interpretation for {@link detectChord} and {@link detectChordBest}.\n *\n * @category Recognition\n */\nexport type DetectChordOptions = {\n /**\n * `midi` uses the numerically lowest pitch as bass; `pitchClass` treats the\n * input as unordered. `auto` (default) selects pitch-class mode only when all\n * values lie in 0..11.\n */\n input?: 'auto' | 'midi' | 'pitchClass';\n /** Explicit bass pitch class, including for an unordered pitch-class set. */\n bassPc?: number;\n};\n\n/**\n * A candidate key interpretation of a pitch-class set.\n *\n * @category Recognition\n */\nexport type KeyMatch = {\n /** The scale that scored best for this tonic and mode, `variant` included. */\n key: KeyScale;\n mode: 'major' | 'minor';\n /** Which scale form `key` uses; minor keys pick the best-scoring of the three. */\n variant: KeyVariant;\n /**\n * Fraction of the distinct input pitch classes that belong to `key`, in\n * [0, 1]. Measured against the returned scale, so it always agrees with\n * `isScaleTone(pc, match.key)`. This is a coverage figure, not the ranking:\n * see `score`.\n */\n fit: number;\n /**\n * The value the results are ranked by, in [0, 1.5]. Unlike `fit` it counts\n * every occurrence rather than every distinct pitch class, so a repeated tone\n * weighs more, and it adds half a count per sounding of the tonic itself to\n * break ties between keys that contain the same notes.\n */\n score: number;\n};\n\n/**\n * Which form of a scale a {@link KeyMatch} settled on.\n *\n * @category Recognition\n */\nexport type KeyVariant = 'major' | 'natural' | 'harmonic' | 'melodic';\n\n/**\n * Input weighting for {@link detectKey}.\n *\n * @category Recognition\n */\nexport type DetectKeyOptions = {\n /**\n * How much each pitch counts toward the histogram, one entry per pitch.\n * Defaults to one per pitch, which weighs a thirty-second-note ornament as\n * heavily as the whole note under it. {@link detectKeyFromNotes} supplies\n * duration times velocity, matching how chord inference weighs its own\n * histogram.\n */\n weights?: readonly number[];\n};\n\n/** Unique pitch classes of the input, sorted ascending. */\nfunction uniquePitchClasses(pitches: readonly number[]): number[] {\n return [...new Set(pitches.map(pitchClass))].sort((a, b) => a - b);\n}\n\nfunction assertPitches(pitches: readonly number[]): void {\n assertGenerationBudget(pitches.length, 'detection pitches');\n for (let index = 0; index < pitches.length; index += 1) {\n assertFiniteNumber(pitches[index] ?? Number.NaN, `pitches[${index}]`);\n }\n}\n\n/**\n * Identify chords matching a set of pitches.\n *\n * Every input pitch class is tried as a root against every known chord quality.\n * A match is reported when all of the chord's tones are present in the input, or\n * when the only absent tone is the perfect fifth (a common omission in shell\n * voicings); matches are ranked best-first by fewest extra notes, then fewest\n * missing notes, then most specific (largest) chord. An exact match (no extras,\n * no missing) is flagged and ranked first.\n *\n * @param pitches MIDI pitches or bare pitch classes (octave-agnostic).\n * @returns Ranked chord interpretations (may be empty).\n * @example\n * ```ts\n * import { detectChord } from '@libraz/libcantus';\n * const matches = detectChord([60, 64, 67]); // C E G\n * matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }\n * ```\n * @category Recognition\n */\nexport function detectChord(\n pitches: readonly number[],\n opts: DetectChordOptions = {},\n): ChordMatch[] {\n assertPitches(pitches);\n if (opts.bassPc !== undefined) assertFiniteNumber(opts.bassPc, 'bassPc');\n const input = uniquePitchClasses(pitches);\n if (input.length === 0) {\n return [];\n }\n const inputKind =\n opts.input === undefined || opts.input === 'auto'\n ? pitches.every((pitch) => Number.isInteger(pitch) && pitch >= 0 && pitch <= 11)\n ? 'pitchClass'\n : 'midi'\n : opts.input;\n const bassPc =\n opts.bassPc !== undefined\n ? pitchClass(opts.bassPc)\n : inputKind === 'midi'\n ? pitchClass(pitches.reduce((lowest, pitch) => Math.min(lowest, pitch), Infinity))\n : undefined;\n const inputSet = new Set(input);\n const matches: ChordMatch[] = [];\n const qualities = chordQualities();\n for (const rootPc of input) {\n for (const quality of qualities) {\n const chord = makeChord(rootPc, quality);\n const tones = chordPitchClasses(chord);\n const toneSet = new Set(tones);\n const missingPcs = tones.filter((pc) => !inputSet.has(pc));\n // Accept an exact-tone match, or one whose only absent tone is the perfect\n // fifth; any other missing tone (third, sus tone, seventh, ...) rejects.\n const fifthPc = pitchClass(rootPc + 7);\n if (missingPcs.length > 1 || (missingPcs.length === 1 && missingPcs[0] !== fifthPc)) {\n continue;\n }\n const extraPcs = input.filter((pc) => !toneSet.has(pc));\n const bassIndex =\n bassPc === undefined\n ? -1\n : chord.intervals.findIndex((iv) => pitchClass(rootPc + iv) === bassPc);\n // A bass that is not a chord tone names no inversion; reporting it as 0\n // would be indistinguishable from root position for a caller that reads\n // `inversion === 0` as \"no slash needed\".\n const inversion = bassPc === undefined || bassIndex < 0 ? null : bassIndex;\n const match: ChordMatch = {\n rootPc,\n quality,\n missingPcs,\n extraPcs,\n exact: extraPcs.length === 0 && missingPcs.length === 0,\n inversion,\n };\n if (bassPc !== undefined && bassPc !== rootPc) {\n match.bassPc = bassPc;\n }\n matches.push(match);\n }\n }\n matches.sort((a, b) => {\n if (a.extraPcs.length !== b.extraPcs.length) {\n return a.extraPcs.length - b.extraPcs.length;\n }\n if (a.missingPcs.length !== b.missingPcs.length) {\n return a.missingPcs.length - b.missingPcs.length;\n }\n // Prefer root position (the bass is the chord root) on a tie.\n if ((a.inversion === 0) !== (b.inversion === 0)) {\n return a.inversion === 0 ? -1 : 1;\n }\n const aSize = chordPitchClasses(makeChord(a.rootPc, a.quality)).length;\n const bSize = chordPitchClasses(makeChord(b.rootPc, b.quality)).length;\n return bSize - aSize;\n });\n return matches;\n}\n\n/**\n * The single best chord interpretation of a pitch set, or null if none.\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @returns The top-ranked chord, or null when nothing matches.\n * @example\n * ```ts\n * import { detectChordBest } from '@libraz/libcantus';\n * detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }\n * ```\n * @category Recognition\n */\nexport function detectChordBest(\n pitches: readonly number[],\n opts: DetectChordOptions = {},\n): Chord | null {\n const best = detectChord(pitches, opts)[0];\n if (!best) {\n return null;\n }\n return makeChord(best.rootPc, best.quality, best.bassPc);\n}\n\n/**\n * Minor-scale variants scored for each minor-key candidate. Scoring against all\n * three lets the raised sixth and seventh (e.g. the leading tone G# in A minor)\n * count toward their own tonic instead of only penalizing it. Natural minor\n * comes first so it wins a tie as the most diatonic reading.\n */\nconst MINOR_VARIANTS = [\n { variant: 'natural', mask: NATURAL_MINOR_MASK },\n { variant: 'harmonic', mask: HARMONIC_MINOR_MASK },\n { variant: 'melodic', mask: MELODIC_MINOR_MASK },\n] as const satisfies readonly { variant: KeyVariant; mask: number }[];\n\n/** The single major form, kept in the same shape as the minor variants. */\nconst MAJOR_VARIANTS = [{ variant: 'major', mask: MAJOR_MASK }] as const satisfies readonly {\n variant: KeyVariant;\n mask: number;\n}[];\n\n/**\n * Rank major and minor keys by how well they contain a set of pitch classes.\n *\n * Ranking is by `score`, which counts repetitions and adds a tonic weight so\n * that, among equally-fitting keys, the one whose root is actually sounded is\n * preferred. Minor candidates are scored against the natural, harmonic, and\n * melodic minor variants and keep the best of the three, so a minor cadence\n * containing the leading tone still resolves to its own tonic; the winning\n * variant is what `key` and `variant` report, so `fit` describes the scale the\n * caller receives. Returns all 24 keys ranked best-first, or an empty array for\n * an empty input (mirroring {@link detectChord}).\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @returns Ranked key interpretations (empty for an empty input).\n * @example\n * ```ts\n * import { detectKey } from '@libraz/libcantus';\n * const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale\n * keys[0].mode; // 'major', with keys[0].key.rootPc === 0\n * ```\n * @category Recognition\n */\nexport function detectKey(pitches: readonly number[], opts: DetectKeyOptions = {}): KeyMatch[] {\n assertPitches(pitches);\n const input = uniquePitchClasses(pitches);\n if (input.length === 0) {\n return [];\n }\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== pitches.length) {\n throw new InvalidInputError('weights must have one entry per pitch');\n }\n const counts = new Map<number, number>();\n let total = 0;\n for (let index = 0; index < pitches.length; index += 1) {\n const weight = weights === undefined ? 1 : (weights[index] ?? 0);\n assertFiniteNumber(weight, `weights[${index}]`);\n if (weight <= 0) {\n continue;\n }\n const pc = pitchClass(pitches[index] ?? 0);\n counts.set(pc, (counts.get(pc) ?? 0) + weight);\n total += weight;\n }\n if (total === 0) {\n return [];\n }\n const results: KeyMatch[] = [];\n for (let tonic = 0; tonic < 12; tonic += 1) {\n for (const mode of ['major', 'minor'] as const) {\n const variants = mode === 'major' ? MAJOR_VARIANTS : MINOR_VARIANTS;\n // Score each scale variant and keep the best; ties keep the earlier\n // (more diatonic) variant. The winner is what the match reports, so its\n // fit is measured against the very scale the caller receives.\n let inScale = 0;\n let weighted = Number.NEGATIVE_INFINITY;\n let best: { variant: KeyVariant; mask: number } = variants[0];\n for (const candidate of variants) {\n let variantInScale = 0;\n let variantWeighted = 0;\n for (const pc of input) {\n const offset = (pc - tonic + 12) % 12;\n if ((candidate.mask >> offset) & 1) {\n variantInScale += 1;\n }\n }\n for (const [pc, count] of counts) {\n const offset = (pc - tonic + 12) % 12;\n if ((candidate.mask >> offset) & 1) {\n variantWeighted += count;\n }\n }\n if (variantWeighted > weighted) {\n weighted = variantWeighted;\n inScale = variantInScale;\n best = candidate;\n }\n }\n weighted += (counts.get(tonic) ?? 0) * 0.5;\n results.push({\n key: { rootPc: tonic, modeMask12: best.mask },\n mode,\n variant: best.variant,\n fit: inScale / input.length,\n score: weighted / total,\n });\n }\n }\n results.sort((a, b) => b.score - a.score);\n return results;\n}\n\n/** Default MIDI velocity assumed when a note event does not carry one. */\nconst DEFAULT_VELOCITY = 100;\n\n/**\n * Rank keys by how well they contain a set of note events, weighting each note\n * by how much of the music it actually occupies.\n *\n * {@link detectKey} counts every pitch once, which lets a run of fast ornamental\n * notes outvote the sustained harmony that establishes the key. This weighs\n * each note by duration times velocity, the same measure chord inference uses,\n * so the two agree on what the music emphasises. Notes that never sound (zero\n * or negative duration) are ignored.\n *\n * @param notes The note events to weigh.\n * @returns Ranked key interpretations (empty when nothing sounds).\n * @example\n * ```ts\n * import { detectKeyFromNotes } from '@libraz/libcantus';\n * detectKeyFromNotes([{ pitch: 60, startBeat: 0, durationBeat: 4 }])[0]?.key.rootPc; // 0\n * ```\n * @category Recognition\n */\nexport function detectKeyFromNotes(notes: readonly NoteEvent[]): KeyMatch[] {\n const sounding = notes.filter((note) => note.durationBeat > 0);\n return detectKey(\n sounding.map((note) => note.pitch),\n { weights: sounding.map((note) => note.durationBeat * (note.velocity ?? DEFAULT_VELOCITY)) },\n );\n}\n\n/**\n * The single best key interpretation of a pitch set.\n *\n * The counterpart of {@link detectChordBest}: the ranked list is the general\n * answer, but a caller that just wants \"what key is this\" should not have to\n * index into it and assert the result is there.\n *\n * @param pitches MIDI pitches or bare pitch classes.\n * @param opts How to weigh the input; see {@link DetectKeyOptions}.\n * @returns The top-ranked key, or null when nothing sounds.\n * @example\n * ```ts\n * import { detectKeyBest } from '@libraz/libcantus';\n * detectKeyBest([0, 2, 4, 5, 7, 9, 11])?.mode; // 'major'\n * ```\n * @category Recognition\n */\nexport function detectKeyBest(\n pitches: readonly number[],\n opts: DetectKeyOptions = {},\n): KeyMatch | null {\n return detectKey(pitches, opts)[0] ?? null;\n}\n","/**\n * Shared helpers for the functional-harmony modules.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport { pitchClassOf as mod12 } from '../../core/pitch/index.js';\n\nexport { pitchClassOf as mod12 } from '../../core/pitch/index.js';\n\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../../theory/chord/index.js';\nimport { MAJOR_MASK, majorKey, scaleTonesInDegreeOrder } from '../../theory/scale/index.js';\n\n/** Diatonic pitch class of a 1-based scale degree in a key. */\nexport function degreeRootPc(degreeNumber: number, key: KeyScale): number {\n const tones = scaleTonesInDegreeOrder(key);\n if (tones.length === 0) {\n return mod12(key.rootPc);\n }\n // A plain `%` yields a negative index for a degree below the first, which\n // reads as undefined and collapses to the tonic; wrap into range instead.\n const index = (((degreeNumber - 1) % tones.length) + tones.length) % tones.length;\n return tones[index] ?? mod12(key.rootPc);\n}\n\n/**\n * The 1-based scale degrees that already sit a semitone below their parallel\n * major counterpart — the third, sixth and seventh of a natural minor key, the\n * third and seventh of dorian, and so on.\n *\n * Roman-numeral spelling and parsing both need this: a flat sign on such a\n * degree is the degree itself rather than a further lowering, and a chromatic\n * root a semitone above one of them is that degree raised (`#III` in a minor\n * key), not a flattened version of the degree above it.\n *\n * Only heptatonic keys have a degree-for-degree correspondence with a major\n * scale, so anything else reports no lowered degrees.\n */\nexport function loweredDegrees(key: KeyScale): Set<number> {\n const tones = scaleTonesInDegreeOrder(key);\n const out = new Set<number>();\n if (tones.length !== 7) {\n return out;\n }\n const major = scaleTonesInDegreeOrder({ rootPc: mod12(key.rootPc), modeMask12: MAJOR_MASK });\n for (let index = 0; index < 7; index += 1) {\n const tone = tones[index];\n const majorTone = major[index];\n if (tone !== undefined && majorTone !== undefined && mod12(majorTone - tone) === 1) {\n out.add(index + 1);\n }\n }\n return out;\n}\n\n/**\n * The heptatonic frame a Roman numeral is measured against for a key.\n *\n * Roman numerals only have seven glyphs, so a scale with any other number of\n * tones has no degree-for-degree numeral of its own: a pentatonic key would\n * make `VI` wrap around to the tonic and an octatonic or chromatic key would\n * have degrees no numeral can name. Such keys are read against their parallel\n * major instead — the same frame the chromatic fallback spelling already uses —\n * so `chordToRoman` and `romanToChord` stay mutual inverses for every key.\n */\nexport function romanReference(key: KeyScale): KeyScale {\n return scaleTonesInDegreeOrder(key).length === 7 ? key : majorKey(mod12(key.rootPc));\n}\n\n/** Whether a chord is the Neapolitan: a major triad on the flat second degree. */\nexport function isNeapolitan(chord: Chord, key: KeyScale): boolean {\n return mod12(chord.rootPc - key.rootPc) === 1 && chord.quality === 'maj';\n}\n","/**\n * Roman-numeral parsing and formatting.\n *\n * The {@link ROMAN_STYLE} table is the single source of truth for both\n * directions, so {@link chordToRoman} and {@link romanToChord} stay mutual\n * inverses by construction.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord, ChordQuality } from '../../theory/chord/index.js';\nimport { chordPitchClasses, makeChord } from '../../theory/chord/index.js';\nimport { isScaleTone, majorKey, scaleTonesInDegreeOrder } from '../../theory/scale/index.js';\nimport { degreeRootPc, loweredDegrees, mod12, romanReference } from './internal.js';\n\n/** Roman numeral glyphs indexed by degree number - 1. */\nconst ROMAN = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII'] as const;\n\n/** Roman glyph -> degree number (1..7). */\nconst ROMAN_TO_DEGREE: Record<string, number> = {\n I: 1,\n II: 2,\n III: 3,\n IV: 4,\n V: 5,\n VI: 6,\n VII: 7,\n};\n\n/** Major-key Roman spelling for each semitone offset above the tonic. */\nconst OFFSET_SPELLING: readonly [number, string][] = [\n [1, ''],\n [2, 'b'],\n [2, ''],\n [3, 'b'],\n [3, ''],\n [4, ''],\n [4, '#'],\n [5, ''],\n [6, 'b'],\n [6, ''],\n [7, 'b'],\n [7, ''],\n];\n\n/** Choose a seventh-chord quality from a triad label and the numeral case. */\nfunction seventhQuality(base: 'maj' | 'min' | 'dim' | 'aug', halfDim: boolean): ChordQuality {\n if (halfDim) {\n return 'm7b5';\n }\n if (base === 'dim') {\n return 'dim7';\n }\n if (base === 'aug') {\n return 'aug7';\n }\n return base === 'maj' ? 'dom7' : 'min7';\n}\n\n/** Figure strings that denote a recognized figured-bass inversion. */\nconst INVERSION_FIGURES = new Set(['6', '64', '65', '43', '42', '2', '7']);\n\n/**\n * Canonical Roman-numeral rendering (numeral case and quality suffix) for every\n * supported chord quality. The table is the single source of truth for both\n * directions: {@link chordToRoman} renders from it and {@link romanToChord}\n * recognizes its exact case-sensitive suffixes, so the two stay mutual\n * inverses by construction. Suffixes are chosen to never collide with\n * figured-bass inversion digits (`6`, `64`, `65`, `43`, `42`, `2`) — the added\n * sixth is `add6`, the six-nine chord is `69` — and each (case, suffix) pair is\n * unique.\n */\nconst ROMAN_STYLE: Record<ChordQuality, { lower: boolean; suffix: string }> = {\n maj: { lower: false, suffix: '' },\n min: { lower: true, suffix: '' },\n dim: { lower: true, suffix: 'o' },\n aug: { lower: false, suffix: '+' },\n maj7: { lower: false, suffix: 'maj7' },\n min7: { lower: true, suffix: '7' },\n dom7: { lower: false, suffix: '7' },\n dim7: { lower: true, suffix: 'o7' },\n m7b5: { lower: true, suffix: 'ø7' },\n minMaj7: { lower: true, suffix: 'maj7' },\n aug7: { lower: false, suffix: '+7' },\n augMaj7: { lower: false, suffix: '+maj7' },\n majb5: { lower: false, suffix: 'b5' },\n '6': { lower: false, suffix: 'add6' },\n min6: { lower: true, suffix: 'add6' },\n '6/9': { lower: false, suffix: '69' },\n sus2: { lower: false, suffix: 'sus2' },\n sus4: { lower: false, suffix: 'sus4' },\n add9: { lower: false, suffix: 'add9' },\n add11: { lower: false, suffix: 'add11' },\n maj9: { lower: false, suffix: 'maj9' },\n min9: { lower: true, suffix: '9' },\n dom9: { lower: false, suffix: '9' },\n '7b9': { lower: false, suffix: '7b9' },\n '7#9': { lower: false, suffix: '7#9' },\n '7#11': { lower: false, suffix: '7#11' },\n '7b13': { lower: false, suffix: '7b13' },\n '11': { lower: false, suffix: '11' },\n '13': { lower: false, suffix: '13' },\n '5': { lower: false, suffix: '5' },\n '7sus4': { lower: false, suffix: '7sus4' },\n '7b5': { lower: false, suffix: '7b5' },\n '7alt': { lower: false, suffix: '7alt' },\n '13b9': { lower: false, suffix: '13b9' },\n maj13: { lower: false, suffix: 'maj13' },\n 'maj7#11': { lower: false, suffix: 'maj7#11' },\n min11: { lower: true, suffix: '11' },\n min13: { lower: true, suffix: '13' },\n minAdd9: { lower: true, suffix: 'add9' },\n 'min6/9': { lower: true, suffix: '69' },\n};\n\n/** Reverse lookup of {@link ROMAN_STYLE}: `(case, exact suffix) -> quality`. */\nconst SUFFIX_QUALITY: ReadonlyMap<string, ChordQuality> = new Map(\n (Object.entries(ROMAN_STYLE) as [ChordQuality, { lower: boolean; suffix: string }][]).map(\n ([quality, style]) => [`${style.lower ? 'l' : 'u'}:${style.suffix}`, quality],\n ),\n);\n\n/** Read figured-bass digits into a chord inversion and whether a seventh is implied. */\nfunction parseInversion(figures: string): { inversion: number; seventh: boolean } {\n if (figures === '65') {\n return { inversion: 1, seventh: true };\n }\n if (figures === '43') {\n return { inversion: 2, seventh: true };\n }\n if (figures === '42' || figures === '2') {\n return { inversion: 3, seventh: true };\n }\n if (figures === '7') {\n return { inversion: 0, seventh: true };\n }\n if (figures === '64') {\n return { inversion: 2, seventh: false };\n }\n if (figures === '6') {\n return { inversion: 1, seventh: false };\n }\n return { inversion: 0, seventh: false };\n}\n\n/** Parse a Roman numeral (no secondary '/') into a root, quality, and inversion. */\nfunction parseSimpleRoman(\n text: string,\n key: KeyScale,\n): { rootPc: number; quality: ChordQuality; inversion: number } {\n const match = /^([b#]?)([iIvV]+)(.*)$/.exec(text.trim());\n if (!match) {\n throw new InvalidInputError(`Invalid Roman numeral: ${text}`);\n }\n const accidental = match[1] === 'b' ? -1 : match[1] === '#' ? 1 : 0;\n const glyph = (match[2] ?? '').toUpperCase();\n const degreeNumber = ROMAN_TO_DEGREE[glyph];\n if (degreeNumber === undefined) {\n throw new InvalidInputError(`Invalid Roman numeral: ${text}`);\n }\n const isUpper = (match[2] ?? '')[0] === (match[2] ?? '')[0]?.toUpperCase();\n const suffix = match[3] ?? '';\n // Degrees are read in the key's heptatonic frame, so a numeral means the same\n // root in both directions even when the key itself is not heptatonic.\n const frame = romanReference(key);\n // A flat on a degree the mode already lowers is that degree, not a further\n // lowering: `bVII` in A minor is G, the pop reading, rather than F#.\n const redundantFlat = accidental === -1 && loweredDegrees(frame).has(degreeNumber);\n const rootPc = mod12(degreeRootPc(degreeNumber, frame) + (redundantFlat ? 0 : accidental));\n\n // Canonical quality suffixes (exact match, case-sensitive on the numeral)\n // come first so every chordToRoman rendering re-parses to the same quality:\n // `V9` -> dom9 but `ii9` -> min9 and `Imaj9` -> maj9, and added-tone suffixes\n // whose digits would otherwise be misread as figured bass (`Iadd6`, `I69`,\n // `Isus2`, `Iadd11`) resolve to their qualities in root position.\n const canonical = SUFFIX_QUALITY.get(`${isUpper ? 'u' : 'l'}:${suffix}`);\n if (canonical !== undefined) {\n return { rootPc, quality: canonical, inversion: 0 };\n }\n\n // Non-canonical spellings are limited to a complete quality marker followed\n // by an optional major-seventh marker and a recognized figured bass. Never\n // search substrings: `Vfoo` must not become diminished merely because it\n // contains an \"o\", and unknown trailing text must be rejected in full.\n const parsedSuffix = /^(o|°|dim|ø|\\+|aug)?(maj7|M7)?(65|64|43|42|7|6|2)?$/.exec(suffix);\n if (!parsedSuffix) {\n throw new InvalidInputError(`Unsupported suffix \"${suffix}\" in Roman numeral: ${text}`);\n }\n const qualityMarker = parsedSuffix[1] ?? '';\n const isDim = qualityMarker === 'o' || qualityMarker === '°' || qualityMarker === 'dim';\n const isAug = qualityMarker === '+' || qualityMarker === 'aug';\n const isHalfDim = qualityMarker === 'ø';\n const explicitMaj7 = parsedSuffix[2] !== undefined;\n const figures = parsedSuffix[3] ?? '';\n\n // Reject figure strings that are neither a known figured-bass inversion nor a\n // canonical quality suffix rather than silently degrading to a root triad.\n if (figures !== '' && !INVERSION_FIGURES.has(figures)) {\n throw new InvalidInputError(\n `Unsupported figured-bass or extension \"${figures}\" in Roman numeral: ${text}`,\n );\n }\n\n const { inversion, seventh } = parseInversion(figures);\n // The ø glyph is the half-diminished seventh by definition (there is no\n // half-diminished triad), so it always implies a seventh.\n const hasSeventh = explicitMaj7 || seventh || isHalfDim;\n\n let base: 'maj' | 'min' | 'dim' | 'aug';\n if (isDim || isHalfDim) {\n base = 'dim';\n } else if (isAug) {\n base = 'aug';\n } else {\n base = isUpper ? 'maj' : 'min';\n }\n\n let quality: ChordQuality;\n if (explicitMaj7) {\n quality = base === 'min' ? 'minMaj7' : base === 'aug' ? 'augMaj7' : 'maj7';\n } else if (hasSeventh) {\n quality = seventhQuality(base, isHalfDim);\n } else if (base === 'dim') {\n quality = 'dim';\n } else if (base === 'aug') {\n quality = 'aug';\n } else {\n quality = base;\n }\n return { rootPc, quality, inversion };\n}\n\n/** Build a chord from a parsed Roman numeral, attaching a bass for inversions. */\nfunction chordFromParsed(parsed: {\n rootPc: number;\n quality: ChordQuality;\n inversion: number;\n}): Chord {\n const chord = makeChord(parsed.rootPc, parsed.quality);\n if (parsed.inversion > 0 && parsed.inversion < chord.intervals.length) {\n chord.bassPc = mod12(parsed.rootPc + (chord.intervals[parsed.inversion] ?? 0));\n }\n return chord;\n}\n\n/**\n * Build the chord denoted by a Roman numeral in a key.\n *\n * Supports accidentals (`bVII`, `#iv`), case-based triad quality, the `o`/`ø`/`+`\n * suffixes, sevenths (`V7`, `viio7`, `Imaj7`), figured-bass inversions\n * (`V6`, `V64`, `V65`, `V43`, `V42`), and applied/secondary chords via a slash\n * (`V7/V`, `viio/ii`). The target after the slash is read as a scale degree\n * whose root becomes a local major tonic for the applied chord. Inverted chords\n * carry a `bassPc`.\n *\n * The `ø` glyph always denotes the half-diminished seventh (`iiø` == `iiø7` ==\n * `m7b5`), since no half-diminished triad exists. Extension and added-tone\n * suffixes are the canonical case-sensitive forms emitted by\n * {@link chordToRoman} and honor the numeral case: `V9` -> `dom9`, `ii9` ->\n * `min9`, `Imaj9` -> `maj9`, `V11` -> `11`, `V13` -> `13`, `Iadd6`/`iadd6` ->\n * `6`/`min6`, `I69` -> `6/9`, `Isus2`/`Isus4`, `Iadd9`/`Iadd11`, `Ib5` ->\n * `majb5`, `I5` -> `5`, and the altered dominants `V7b9`/`V7#9`/`V7#11`/`V7b13`.\n * A figure string that is neither a recognized inversion nor a supported\n * quality suffix throws rather than silently degrading to a triad.\n *\n * @param text The Roman numeral.\n * @param key The prevailing key.\n * @returns The chord.\n * @example\n * ```ts\n * import { romanToChord, majorKey } from '@libraz/libcantus';\n * romanToChord('V7', majorKey(0)); // G7 in C major: { rootPc: 7, quality: 'dom7', ... }\n * ```\n * @category Functional Harmony\n */\nexport function romanToChord(text: string, key: KeyScale): Chord {\n const trimmed = text.trim();\n const slash = trimmed.indexOf('/');\n if (slash >= 0) {\n const applied = trimmed.slice(0, slash);\n const target = trimmed.slice(slash + 1);\n const targetRoot = parseSimpleRoman(target, key).rootPc;\n const localKey = majorKey(targetRoot);\n return chordFromParsed(parseSimpleRoman(applied, localKey));\n }\n return chordFromParsed(parseSimpleRoman(trimmed, key));\n}\n\n/** Case and suffix for rendering a chord quality as a Roman numeral. */\nfunction romanStyle(quality: ChordQuality): { lower: boolean; suffix: string } {\n return ROMAN_STYLE[quality];\n}\n\n/** Choose the degree number and accidental to spell a root as a Roman numeral. */\nfunction romanSpelling(\n rootPc: number,\n key: KeyScale,\n): { degreeNumber: number; accidental: string } {\n const tones = scaleTonesInDegreeOrder(romanReference(key));\n const diatonic = tones.indexOf(mod12(rootPc));\n if (diatonic >= 0) {\n return { degreeNumber: diatonic + 1, accidental: '' };\n }\n // A chromatic root a semitone above a degree the mode already lowers is that\n // degree raised: C# in A minor is `#III`, not `bIV`.\n const lowered = loweredDegrees(romanReference(key));\n for (let i = 0; i < tones.length; i += 1) {\n if (lowered.has(i + 1) && mod12((tones[i] ?? 0) + 1) === mod12(rootPc)) {\n return { degreeNumber: i + 1, accidental: '#' };\n }\n }\n // Otherwise prefer a flat of the diatonic degree a semitone above it,\n // then a sharp of the degree a semitone below. Degree 1 (the tonic) and\n // degree 5 (the dominant) are skipped in the flat pass, so a raised leading\n // tone spells as `#vii` rather than a flat tonic `bI`, and the tritone above\n // the tonic spells as `#iv` rather than a flat fifth `bV` (matching the\n // conventional `OFFSET_SPELLING` for offset 6).\n for (let i = 0; i < tones.length; i += 1) {\n const degreeNumber = i + 1;\n if (degreeNumber === 1 || degreeNumber === 5) {\n continue;\n }\n if (mod12((tones[i] ?? 0) - 1) === mod12(rootPc)) {\n return { degreeNumber, accidental: 'b' };\n }\n }\n for (let i = 0; i < tones.length; i += 1) {\n if (mod12((tones[i] ?? 0) + 1) === mod12(rootPc)) {\n return { degreeNumber: i + 1, accidental: '#' };\n }\n }\n const [degreeNumber, accidental] = OFFSET_SPELLING[mod12(rootPc - key.rootPc)] ?? [1, ''];\n return { degreeNumber, accidental };\n}\n\n/** Quality marker (without the seventh digit) used when a figure carries the 7. */\nfunction baseMarker(quality: ChordQuality): string {\n if (quality === 'dim' || quality === 'dim7') {\n return 'o';\n }\n if (quality === 'm7b5') {\n return 'ø';\n }\n if (quality === 'aug' || quality === 'aug7') {\n return '+';\n }\n if (quality === 'augMaj7') {\n return '+maj7';\n }\n if (quality === 'maj7' || quality === 'minMaj7') {\n return 'maj7';\n }\n return '';\n}\n\nconst TRIAD_FIGURES: Record<number, string> = { 1: '6', 2: '64' };\nconst SEVENTH_FIGURES: Record<number, string> = { 1: '65', 2: '43', 3: '42' };\n\n/** Qualities whose inversions render as lossless triad figures (6, 64). */\nconst TRIAD_FIGURE_QUALITIES: ReadonlySet<ChordQuality> = new Set(['maj', 'min', 'dim', 'aug']);\n\n/**\n * Qualities carrying a chordal seventh, whose inversions render as seventh\n * figures (65, 43, 42). Membership is decided by the quality itself — a 7th\n * above the root (10 or 11 semitones, or the diminished 7th of `dim7`) — never\n * by interval count, which would turn added-tone chords into false sevenths.\n */\nconst SEVENTH_FIGURE_QUALITIES: ReadonlySet<ChordQuality> = new Set([\n 'maj7',\n 'min7',\n 'dom7',\n 'dim7',\n 'm7b5',\n 'minMaj7',\n 'aug7',\n 'augMaj7',\n]);\n\n/**\n * The numeral glyph for a degree number, cased for the chord quality.\n *\n * Only the seven glyphs exist, so a degree outside 1..7 is a contract violation\n * rather than something to paper over with a default numeral.\n */\nfunction numeralFor(degreeNumber: number, lower: boolean): string {\n const glyph = ROMAN[degreeNumber - 1];\n if (glyph === undefined) {\n throw new InvalidInputError(`no Roman numeral for scale degree ${degreeNumber}`);\n }\n return lower ? glyph.toLowerCase() : glyph;\n}\n\n/** Whether every pitch class of a chord belongs to the key's scale. */\nfunction isDiatonicChord(chord: Chord, key: KeyScale): boolean {\n return chordPitchClasses(chord).every((pc) => isScaleTone(pc, key));\n}\n\n/**\n * Whether the chord sounds like an applied dominant: a major triad, or any\n * chord stacking a major third and a minor seventh above its root. The\n * diminished family is handled separately, as the leading-tone chord.\n */\nfunction isAppliedDominantSonority(chord: Chord): boolean {\n const has = (semitones: number): boolean => chord.intervals.some((i) => mod12(i) === semitones);\n return chord.quality === 'maj' || (has(4) && has(10));\n}\n\n/** Diminished-family qualities, which tonicize from a semitone below. */\nconst LEADING_TONE_QUALITIES: ReadonlySet<ChordQuality> = new Set(['dim', 'dim7', 'm7b5']);\n\n/** The third and fifth above a scale degree, measured within its own scale. */\nfunction degreeTriad(tones: readonly number[], index: number): { third: number; fifth: number } {\n const root = tones[index] ?? 0;\n return {\n third: mod12((tones[(index + 2) % tones.length] ?? 0) - root),\n fifth: mod12((tones[(index + 4) % tones.length] ?? 0) - root),\n };\n}\n\n/**\n * The scale degree a chromatic chord tonicizes, or null when it tonicizes\n * nothing. A dominant sonority points a fifth below itself, a diminished one a\n * semitone above itself; the tonic is never a target (that chord is the key's own\n * dominant) and neither is a degree carrying a diminished triad, which has no\n * fifth to be tonicized.\n */\nfunction appliedTarget(\n chord: Chord,\n key: KeyScale,\n): { degreeNumber: number; rootPc: number; lower: boolean } | null {\n const dominant = isAppliedDominantSonority(chord);\n const leadingTone = LEADING_TONE_QUALITIES.has(chord.quality);\n if (!dominant && !leadingTone) {\n return null;\n }\n const tones = scaleTonesInDegreeOrder(romanReference(key));\n for (let index = 1; index < tones.length; index += 1) {\n const targetRoot = tones[index];\n if (targetRoot === undefined) {\n continue;\n }\n const triad = degreeTriad(tones, index);\n if (triad.fifth === 6) {\n continue;\n }\n const expectedRoot = mod12(targetRoot + (dominant ? 7 : -1));\n if (expectedRoot === mod12(chord.rootPc)) {\n return { degreeNumber: index + 1, rootPc: targetRoot, lower: triad.third === 3 };\n }\n }\n return null;\n}\n\n/**\n * Options for {@link chordToRoman}.\n *\n * @category Functional Harmony\n */\nexport type ChordToRomanOptions = {\n /**\n * Render a tonicizing chord as an applied numeral (`V7/V`, `viio7/ii`)\n * instead of naming its root against the home key (`II7`, `#ivo7`).\n *\n * Off by default: naming the root is always a correct spelling, whereas\n * whether a chromatic dominant is genuinely applied is a reading only the\n * caller can make. Turning it on makes {@link chordToRoman} the exact inverse\n * of {@link romanToChord} for the chords {@link secondaryDominant} builds.\n */\n applied?: boolean;\n};\n\n/**\n * Render a chord as a Roman numeral relative to a key.\n *\n * Diatonic roots take their scale-degree numeral directly, so numerals are\n * correct in both major and minor keys (and any custom scale). The quality\n * selects the case and suffix; chromatic roots receive a flat/sharp spelling by\n * convention. A key that is not heptatonic has no numeral of its own for every\n * degree, so its roots are named against its parallel major.\n *\n * When the chord carries a `bassPc` on a chord tone, a figured-bass inversion\n * (`6`, `64`, `65`, `43`, `42`) is emitted for plain triads and true seventh\n * chords; added-tone and extended qualities have no lossless figure and render\n * in root position instead (the bass is dropped, pitch classes are preserved).\n *\n * A `bassPc` that is *not* a chord tone — a pedal or passing bass such as\n * `C/D` — is likewise dropped, and the numeral names the upper chord alone.\n * Roman-numeral notation spends its slash on applied chords (`V7/V`), so there\n * is no unambiguous way to write such a bass; a caller that must keep it should\n * read `chord.bassPc` alongside the numeral.\n *\n * @param chord The chord to name.\n * @param key The prevailing key.\n * @param opts `applied` renders tonicizing chords as `V7/V`-style numerals.\n * @returns The Roman numeral string.\n * @example\n * ```ts\n * import { chordToRoman, makeChord, majorKey } from '@libraz/libcantus';\n * chordToRoman(makeChord(7, 'dom7'), majorKey(0)); // => 'V7' (G7 in C major)\n * chordToRoman(makeChord(2, 'dom7'), majorKey(0), { applied: true }); // => 'V7/V'\n * ```\n * @category Functional Harmony\n */\nexport function chordToRoman(chord: Chord, key: KeyScale, opts: ChordToRomanOptions = {}): string {\n if (opts.applied === true && !isDiatonicChord(chord, key)) {\n const target = appliedTarget(chord, key);\n if (target !== null) {\n const local = chordToRoman(chord, majorKey(target.rootPc));\n return `${local}/${numeralFor(target.degreeNumber, target.lower)}`;\n }\n }\n const { degreeNumber, accidental } = romanSpelling(chord.rootPc, key);\n const { lower, suffix } = romanStyle(chord.quality);\n const cased = numeralFor(degreeNumber, lower);\n\n let inversion = 0;\n if (chord.bassPc !== undefined) {\n const idx = chord.intervals.findIndex((iv) => mod12(chord.rootPc + iv) === chord.bassPc);\n if (idx > 0) {\n inversion = idx;\n }\n }\n if (inversion > 0) {\n const figure = SEVENTH_FIGURE_QUALITIES.has(chord.quality)\n ? SEVENTH_FIGURES[inversion]\n : TRIAD_FIGURE_QUALITIES.has(chord.quality)\n ? TRIAD_FIGURES[inversion]\n : undefined;\n if (figure !== undefined) {\n return `${accidental}${cased}${baseMarker(chord.quality)}${figure}`;\n }\n // No lossless figured-bass symbol exists — the quality is an added-tone or\n // extended chord, or the bass falls on a tension beyond the seventh — so\n // fall back to root-position rendering with the quality suffix rather than\n // emitting a figure that would re-parse as a different chord.\n }\n return `${accidental}${cased}${suffix}`;\n}\n","/**\n * Borrowed chords (modal interchange) and the Neapolitan.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../../theory/chord/index.js';\nimport { HARMONIC_MINOR_MASK } from '../../theory/scale/index.js';\nimport { isDiatonic, isMinorKey, parallelKey } from './function.js';\nimport { isNeapolitan, mod12 } from './internal.js';\n\n/**\n * The origin of a recognized non-diatonic chord, or null when none applies.\n *\n * @category Functional Harmony\n */\nexport type BorrowedSource = 'parallelMinor' | 'parallelMajor' | 'neapolitan' | null;\n\n/**\n * In a minor key, whether a non-diatonic chord is explained by the harmonic\n * minor scale on the same tonic (major V, V7, the raised-leading-tone viio).\n * Such chords are in-key chromatic alterations, not modal interchange.\n */\nfunction isHarmonicMinorAlteration(chord: Chord, key: KeyScale): boolean {\n return (\n isMinorKey(key) &&\n isDiatonic(chord, { rootPc: mod12(key.rootPc), modeMask12: HARMONIC_MINOR_MASK })\n );\n}\n\n/**\n * Whether a chord is borrowed from the parallel mode (modal interchange).\n *\n * True when the chord is not diatonic to `key` but is diatonic to its\n * {@link parallelKey} — e.g. iv, bVI, or bVII in a major key, or the Picardy\n * tonic and major IV in a minor key. Two non-diatonic families are excluded:\n * chords diatonic to neither mode (they are chromatic, not borrowed), and, in\n * a minor key, chords explained by the harmonic minor scale (the major\n * dominant and raised-leading-tone chords), which are in-key alterations\n * rather than interchange even though they happen to fit the parallel major.\n *\n * @param chord The chord to test.\n * @param key The prevailing key.\n * @returns True if the chord is borrowed from the parallel mode.\n * @category Functional Harmony\n */\nexport function isBorrowedChord(chord: Chord, key: KeyScale): boolean {\n if (isDiatonic(chord, key)) {\n return false;\n }\n if (isHarmonicMinorAlteration(chord, key)) {\n return false;\n }\n return isDiatonic(chord, parallelKey(key));\n}\n\n/**\n * Identify where a non-diatonic chord comes from.\n *\n * The Neapolitan (major triad on b2) is recognized first, since it sits\n * outside both parallel modes; parallel-mode borrowing follows the\n * {@link isBorrowedChord} rules. Diatonic chords, harmonic-minor alterations,\n * and unrecognized chromatic chords all yield null.\n *\n * @param chord The chord to classify.\n * @param key The prevailing key.\n * @returns The borrowing source, or null.\n * @category Functional Harmony\n */\nexport function borrowedSource(chord: Chord, key: KeyScale): BorrowedSource {\n if (isDiatonic(chord, key)) {\n return null;\n }\n if (isNeapolitan(chord, key)) {\n return 'neapolitan';\n }\n if (isBorrowedChord(chord, key)) {\n return isMinorKey(key) ? 'parallelMajor' : 'parallelMinor';\n }\n return null;\n}\n","/**\n * Harmonic function (tonic / subdominant / dominant), diatonicity, parallel-key\n * mirroring, and full chord analysis.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport type { KeyScale } from '../../core/types.js';\nimport { assertInteger } from '../../core/validation/index.js';\nimport type { Chord, ChordQuality } from '../../theory/chord/index.js';\nimport { chordPitchClasses, makeChord } from '../../theory/chord/index.js';\nimport { isScaleTone, MAJOR_MASK, NATURAL_MINOR_MASK } from '../../theory/scale/index.js';\nimport { type BorrowedSource, borrowedSource } from './borrowed.js';\nimport { degreeRootPc, isNeapolitan, mod12 } from './internal.js';\nimport { chordToRoman } from './roman.js';\n\n/**\n * The three broad harmonic functions of tonal music.\n *\n * @category Functional Harmony\n */\nexport type HarmonicFunction = 'tonic' | 'subdominant' | 'dominant';\n\n/** Harmonic function of each semitone offset above the tonic (major context). */\nconst FUNCTION_BY_OFFSET: readonly HarmonicFunction[] = [\n 'tonic', // 0 I\n 'subdominant', // 1 bII (Neapolitan)\n 'subdominant', // 2 ii\n 'tonic', // 3 bIII\n 'tonic', // 4 iii\n 'subdominant', // 5 IV\n 'dominant', // 6 #IV / bV\n 'dominant', // 7 V\n 'subdominant', // 8 bVI\n 'tonic', // 9 vi\n 'subdominant', // 10 bVII\n 'dominant', // 11 vii\n];\n\n/**\n * Whether a key's scale has a minor third and no major third (a minor key).\n *\n * @category Functional Harmony\n */\nexport function isMinorKey(key: KeyScale): boolean {\n const hasMinorThird = (key.modeMask12 >> 3) & 1;\n const hasMajorThird = (key.modeMask12 >> 4) & 1;\n return Boolean(hasMinorThird) && !hasMajorThird;\n}\n\n/**\n * The harmonic function of a chord in a key.\n *\n * The root's offset above the tonic gives the baseline mapping, which follows\n * common-practice major-key function and is a useful approximation in minor and\n * for borrowed chords. Chord quality then refines it where the sonority settles\n * an ambiguity the root offset cannot:\n *\n * - A chord that *sounds* like a dominant — a major third with a minor seventh,\n * or a diminished-family chord — and is not diatonic to the key has dominant\n * function when its root resolves down a fifth or by a semitone onto a\n * diatonic degree. This is what makes an applied dominant (`A7` in C, which\n * tonicizes ii) and its tritone substitute (`Db7`) read as dominant rather\n * than inheriting the function of the degree they happen to sit on.\n * - The Neapolitan is subdominant.\n * - A major triad on bVI or bVII of a major key is subdominant — the borrowed\n * pop cadence chord, distinct from the bVII7 above, which has a seventh and\n * is a dominant sonority.\n *\n * @param chord The chord.\n * @param key The prevailing key.\n * @returns The harmonic function.\n * @example\n * ```ts\n * import { functionOf, makeChord, majorKey } from '@libraz/libcantus';\n * functionOf(makeChord(9, 'dom7'), majorKey(0)); // 'dominant' — A7 tonicizes ii\n * functionOf(makeChord(10, 'maj'), majorKey(0)); // 'subdominant' — borrowed bVII\n * ```\n * @category Functional Harmony\n */\nexport function functionOf(chord: Chord, key: KeyScale): HarmonicFunction {\n const offset = mod12(chord.rootPc - key.rootPc);\n if (isNeapolitan(chord, key)) {\n return 'subdominant';\n }\n if (isAppliedDominant(chord, key)) {\n return 'dominant';\n }\n if (!isMinorKey(key) && hasMajorThird(chord) && (offset === 8 || offset === 10)) {\n return 'subdominant';\n }\n return FUNCTION_BY_OFFSET[offset] ?? 'tonic';\n}\n\n/**\n * Whether the chord is a dominant sonority pointing at a diatonic degree.\n *\n * A chord already diatonic to the key keeps the offset table's reading; what is\n * classified here is the chromatic chord whose sonority and resolution give it\n * dominant function regardless of the degree it sits on.\n *\n * The resolution required depends on the sonority. A dominant seventh (major\n * third plus minor seventh) must fall a perfect fifth — the applied dominants —\n * or a semitone, which is the same motion its tritone substitute makes. A\n * diminished-family chord must rise a semitone, the leading-tone resolution;\n * requiring that is what keeps a borrowed `iiø7`, which falls a fifth like any\n * other supertonic chord, reading as a predominant rather than a dominant.\n */\nfunction isAppliedDominant(chord: Chord, key: KeyScale): boolean {\n if (isDiatonic(chord, key)) {\n return false;\n }\n const root = mod12(chord.rootPc);\n const resolvesTo = (step: number) => isScaleTone(mod12(root + step), key);\n if (hasMajorThird(chord) && chord.intervals.some((i) => mod12(i) === 10)) {\n return resolvesTo(5) || resolvesTo(11);\n }\n return isDiminishedQuality(chord.quality) && resolvesTo(1);\n}\n\n/**\n * The result of {@link analyzeChord}: function, borrowing, and Roman numeral.\n *\n * @category Functional Harmony\n */\nexport type ChordAnalysis = {\n function: HarmonicFunction;\n borrowed: boolean;\n source: BorrowedSource;\n roman: string;\n};\n\n/**\n * Whether every pitch class of a chord belongs to the key's scale.\n *\n * The test is strict against the key's own mode mask: in a natural-minor key\n * the harmonic-minor dominant (major V) is *not* diatonic, since the raised\n * leading tone lies outside the mask. Borrowing predicates treat that case as\n * an in-key alteration separately (see {@link isBorrowedChord}).\n *\n * @param chord The chord to test.\n * @param key The prevailing key.\n * @returns True if all chord pitch classes are scale tones.\n * @category Functional Harmony\n */\nexport function isDiatonic(chord: Chord, key: KeyScale): boolean {\n return chordPitchClasses(chord).every((pc) => isScaleTone(pc, key));\n}\n\n/**\n * The parallel key: same tonic, opposite mode.\n *\n * A key with a minor third (natural/harmonic/melodic minor, dorian, phrygian)\n * maps to the parallel major; any other key maps to the parallel natural minor.\n *\n * @param key The key to mirror.\n * @returns The parallel major or natural-minor key on the same tonic.\n * @category Functional Harmony\n */\nexport function parallelKey(key: KeyScale): KeyScale {\n return {\n rootPc: mod12(key.rootPc),\n modeMask12: isMinorKey(key) ? MAJOR_MASK : NATURAL_MINOR_MASK,\n };\n}\n\n/** Diminished-family qualities: diminished triad, dim7, half-diminished. */\nfunction isDiminishedQuality(quality: ChordQuality): boolean {\n return quality === 'dim' || quality === 'dim7' || quality === 'm7b5';\n}\n\n/** Whether the chord's interval template carries a major third above the root. */\nfunction hasMajorThird(chord: Chord): boolean {\n return chord.intervals.some((interval) => mod12(interval) === 4);\n}\n\n/**\n * Analyze a chord in a key: harmonic function, borrowing, and Roman numeral.\n *\n * The function is quality-aware (see the predicates behind it), the source\n * follows {@link borrowedSource}, and the numeral comes from\n * {@link chordToRoman}. `borrowed` is true whenever a source is identified —\n * including the Neapolitan, which the stricter parallel-mode predicate\n * {@link isBorrowedChord} does not count.\n *\n * @param chord The chord to analyze.\n * @param key The prevailing key.\n * @returns The chord analysis.\n * @example\n * ```ts\n * import { analyzeChord, makeChord, majorKey } from '@libraz/libcantus';\n * analyzeChord(makeChord(7, 'dom7'), majorKey(0));\n * // { function: 'dominant', borrowed: false, source: null, roman: 'V7' }\n * ```\n * @category Functional Harmony\n */\nexport function analyzeChord(chord: Chord, key: KeyScale): ChordAnalysis {\n const source = borrowedSource(chord, key);\n return {\n function: functionOf(chord, key),\n borrowed: source !== null,\n source,\n roman: chordToRoman(chord, key),\n };\n}\n\n/**\n * The secondary dominant (V7) that tonicizes a scale degree.\n *\n * @param targetDegree 0-based scale degree to tonicize, in 0..6.\n * @param key The prevailing key.\n * @returns A dominant-seventh chord a fifth above the target's root.\n * @throws If `targetDegree` is not an integer in 0..6.\n * @category Functional Harmony\n */\nexport function secondaryDominant(targetDegree: number, key: KeyScale): Chord {\n // A degree outside the scale is a caller error, not a wrap-around: silently\n // tonicizing some other degree produces a chord that reads as intentional.\n assertInteger(targetDegree, 'targetDegree', 0, 6);\n const targetRoot = degreeRootPc(targetDegree + 1, key);\n return makeChord(mod12(targetRoot + 7), 'dom7');\n}\n","/**\n * Cadence detection between two successive chords.\n *\n * Roots are pitch classes measured against the key tonic, so borrowed and\n * chromatic chords are handled by their semitone offset rather than requiring a\n * spelled key signature.\n */\n\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../../theory/chord/index.js';\nimport { isMinorKey } from './function.js';\nimport { mod12 } from './internal.js';\n\n/**\n * A recognized cadence type, or null when a chord pair forms none.\n *\n * @category Functional Harmony\n */\nexport type Cadence = 'authentic' | 'plagal' | 'half' | 'deceptive' | null;\n\n/**\n * Classify the cadence formed by moving from one chord to the next.\n *\n * - authentic: V (dominant a fifth above the tonic) to I\n * - plagal: IV (a fourth above the tonic) to I\n * - deceptive: V to the submediant (diatonic vi or borrowed bVI in major, VI in\n * minor)\n * - half: any chord other than the dominant itself to V\n *\n * A static V-to-V repeat with no root motion is not a cadence and yields null.\n *\n * @param from The penultimate chord.\n * @param to The final chord.\n * @param key The prevailing key.\n * @returns The cadence type, or null.\n * @example\n * ```ts\n * import { detectCadence, makeChord, majorKey } from '@libraz/libcantus';\n * detectCadence(makeChord(7, 'maj'), makeChord(0, 'maj'), majorKey(0)); // => 'authentic'\n * ```\n * @category Functional Harmony\n */\nexport function detectCadence(from: Chord, to: Chord, key: KeyScale): Cadence {\n const tonic = mod12(key.rootPc);\n const fromOffset = mod12(from.rootPc - tonic);\n const toOffset = mod12(to.rootPc - tonic);\n // Deceptive targets: the diatonic submediant (vi at offset 9 in major, VI at\n // offset 8 in minor) plus, in a major key, the borrowed flat-submediant bVI\n // at offset 8.\n const deceptiveTargets = isMinorKey(key) ? [8] : [8, 9];\n if (fromOffset === 7 && toOffset === 0) {\n return 'authentic';\n }\n if (fromOffset === 5 && toOffset === 0) {\n return 'plagal';\n }\n if (fromOffset === 7 && deceptiveTargets.includes(toOffset)) {\n return 'deceptive';\n }\n // A move to the dominant is a half cadence, but a no-root-motion V-to-V repeat\n // is not a cadence at all.\n if (toOffset === 7 && fromOffset !== 7) {\n return 'half';\n }\n return null;\n}\n"]}
@@ -1,13 +1,14 @@
1
1
  import {
2
- isConsonantInterval
3
- } from "./chunk-FBQK3ZQN.js";
2
+ InvalidInputError,
3
+ assertFiniteNumber,
4
+ assertInteger,
5
+ isConsonantInterval,
6
+ pitchClassOf
7
+ } from "./chunk-XEBG3G53.js";
4
8
 
5
9
  // src/theory/scale/degrees.ts
6
- function pitchClass(pitch) {
7
- return (Math.trunc(pitch) % 12 + 12) % 12;
8
- }
9
10
  function scaleOffset(pitch, key) {
10
- return (pitchClass(pitch) - pitchClass(key.rootPc) + 12) % 12;
11
+ return (pitchClassOf(pitch) - pitchClassOf(key.rootPc) + 12) % 12;
11
12
  }
12
13
  function isScaleTone(pitch, key) {
13
14
  return (key.modeMask12 >> scaleOffset(pitch, key) & 1) === 1;
@@ -40,7 +41,7 @@ function pitchToScaleDegree(pitch, key) {
40
41
  return degree;
41
42
  }
42
43
  function diatonicPitchClasses(key) {
43
- const root = pitchClass(key.rootPc);
44
+ const root = pitchClassOf(key.rootPc);
44
45
  const pcs = [];
45
46
  for (let n = 0; n < 12; n += 1) {
46
47
  if ((key.modeMask12 >> n & 1) === 1) {
@@ -50,7 +51,7 @@ function diatonicPitchClasses(key) {
50
51
  return pcs.sort((a, b) => a - b);
51
52
  }
52
53
  function scaleTonesInDegreeOrder(key) {
53
- const root = pitchClass(key.rootPc);
54
+ const root = pitchClassOf(key.rootPc);
54
55
  const pcs = [];
55
56
  for (let n = 0; n < 12; n += 1) {
56
57
  if ((key.modeMask12 >> n & 1) === 1) {
@@ -84,7 +85,12 @@ var WHOLE_TONE_MASK = maskFromOffsets([0, 2, 4, 6, 8, 10]);
84
85
  var OCTATONIC_HALF_WHOLE_MASK = maskFromOffsets([0, 1, 3, 4, 6, 7, 9, 10]);
85
86
  var OCTATONIC_WHOLE_HALF_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 9, 11]);
86
87
  var CHROMATIC_MASK = 4095;
87
- var NAMED_SCALES = {
88
+ var LYDIAN_DOMINANT_MASK = maskFromOffsets([0, 2, 4, 6, 7, 9, 10]);
89
+ var MIXOLYDIAN_B13_MASK = maskFromOffsets([0, 2, 4, 5, 7, 8, 10]);
90
+ var LOCRIAN_NATURAL2_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 10]);
91
+ var ALTERED_MASK = maskFromOffsets([0, 1, 3, 4, 6, 8, 10]);
92
+ var PHRYGIAN_DOMINANT_MASK = maskFromOffsets([0, 1, 4, 5, 7, 8, 10]);
93
+ var NAMED_SCALES = Object.freeze({
88
94
  major: MAJOR_MASK,
89
95
  ionian: MAJOR_MASK,
90
96
  naturalMinor: NATURAL_MINOR_MASK,
@@ -96,6 +102,11 @@ var NAMED_SCALES = {
96
102
  lydian: LYDIAN_MASK,
97
103
  mixolydian: MIXOLYDIAN_MASK,
98
104
  locrian: LOCRIAN_MASK,
105
+ lydianDominant: LYDIAN_DOMINANT_MASK,
106
+ mixolydianB13: MIXOLYDIAN_B13_MASK,
107
+ locrianNatural2: LOCRIAN_NATURAL2_MASK,
108
+ altered: ALTERED_MASK,
109
+ phrygianDominant: PHRYGIAN_DOMINANT_MASK,
99
110
  majorPentatonic: MAJOR_PENTATONIC_MASK,
100
111
  minorPentatonic: MINOR_PENTATONIC_MASK,
101
112
  blues: BLUES_MASK,
@@ -103,7 +114,17 @@ var NAMED_SCALES = {
103
114
  octatonicHalfWhole: OCTATONIC_HALF_WHOLE_MASK,
104
115
  octatonicWholeHalf: OCTATONIC_WHOLE_HALF_MASK,
105
116
  chromatic: CHROMATIC_MASK
106
- };
117
+ });
118
+ function namedScaleMask(name) {
119
+ return Object.hasOwn(NAMED_SCALES, name) ? NAMED_SCALES[name] : void 0;
120
+ }
121
+ function requireScaleMask(name, label = "scale") {
122
+ const mask = namedScaleMask(name);
123
+ if (mask === void 0) {
124
+ throw new InvalidInputError(`Unknown ${label}: ${String(name)}`);
125
+ }
126
+ return mask;
127
+ }
107
128
 
108
129
  // src/theory/scale/key.ts
109
130
  function majorKey(rootPc) {
@@ -113,11 +134,7 @@ function minorKey(rootPc) {
113
134
  return { rootPc: (rootPc % 12 + 12) % 12, modeMask12: NATURAL_MINOR_MASK };
114
135
  }
115
136
  function scaleByName(name, rootPc) {
116
- const mask = NAMED_SCALES[name];
117
- if (mask === void 0) {
118
- throw new Error(`Unknown scale: ${name}`);
119
- }
120
- return { rootPc: (rootPc % 12 + 12) % 12, modeMask12: mask };
137
+ return { rootPc: (rootPc % 12 + 12) % 12, modeMask12: requireScaleMask(name) };
121
138
  }
122
139
 
123
140
  // src/theory/chord/index.ts
@@ -151,44 +168,87 @@ var QUALITY_INTERVALS = {
151
168
  "7b13": [0, 4, 7, 10, 20],
152
169
  "11": [0, 7, 10, 14, 17],
153
170
  "13": [0, 4, 7, 10, 14, 21],
154
- "5": [0, 7]
171
+ "5": [0, 7],
172
+ "7sus4": [0, 5, 7, 10],
173
+ "7b5": [0, 4, 6, 10],
174
+ // The altered dominant as it is voiced from a lead sheet: a dominant seventh
175
+ // with a raised fifth and a raised ninth. The full seven-note altered stack
176
+ // has no seven-letter spelling, so it is not what this symbol denotes.
177
+ "7alt": [0, 4, 8, 10, 15],
178
+ "13b9": [0, 4, 7, 10, 13, 21],
179
+ maj13: [0, 4, 7, 11, 14, 21],
180
+ "maj7#11": [0, 4, 7, 11, 18],
181
+ min11: [0, 3, 7, 10, 14, 17],
182
+ min13: [0, 3, 7, 10, 14, 21],
183
+ minAdd9: [0, 3, 7, 14],
184
+ "min6/9": [0, 3, 7, 9, 14]
155
185
  };
156
- function pitchClass2(value) {
157
- return (Math.trunc(value) % 12 + 12) % 12;
158
- }
159
186
  function chordQualities() {
160
187
  return Object.keys(QUALITY_INTERVALS);
161
188
  }
162
189
  function chordFromDegree(degree, ext, key) {
190
+ assertInteger(degree, "chord degree", -1e3, 1e3);
191
+ if (!Object.hasOwn(QUALITY_INTERVALS, ext)) {
192
+ throw new InvalidInputError(`Unknown chord quality: ${String(ext)}`);
193
+ }
163
194
  const tones = scaleTonesInDegreeOrder(key);
164
195
  const length = tones.length;
165
196
  const index = length > 0 ? (degree % length + length) % length : 0;
166
- const rootPc = tones[index] ?? pitchClass2(key.rootPc);
197
+ const rootPc = tones[index] ?? pitchClassOf(key.rootPc);
167
198
  return { rootPc, quality: ext, intervals: [...QUALITY_INTERVALS[ext]] };
168
199
  }
169
200
  function makeChord(rootPc, quality, bassPc) {
201
+ assertFiniteNumber(rootPc, "chord rootPc");
202
+ if (bassPc !== void 0) {
203
+ assertFiniteNumber(bassPc, "chord bassPc");
204
+ }
205
+ if (!Object.hasOwn(QUALITY_INTERVALS, quality)) {
206
+ throw new InvalidInputError(`Unknown chord quality: ${String(quality)}`);
207
+ }
170
208
  const chord = {
171
- rootPc: pitchClass2(rootPc),
209
+ rootPc: pitchClassOf(rootPc),
172
210
  quality,
173
- intervals: [...QUALITY_INTERVALS[quality]]
211
+ intervals: [...QUALITY_INTERVALS[quality] ?? []]
174
212
  };
175
213
  if (bassPc !== void 0) {
176
- chord.bassPc = pitchClass2(bassPc);
214
+ chord.bassPc = pitchClassOf(bassPc);
177
215
  }
178
216
  return chord;
179
217
  }
180
- function chordPitchClasses(chord) {
218
+ function transposeChord(chord, semitones) {
219
+ assertFiniteNumber(semitones, "semitones");
220
+ const steps = Math.round(semitones);
221
+ const moved = {
222
+ rootPc: pitchClassOf(chord.rootPc + steps),
223
+ quality: chord.quality,
224
+ intervals: [...chord.intervals]
225
+ };
226
+ if (chord.bassPc !== void 0) {
227
+ moved.bassPc = pitchClassOf(chord.bassPc + steps);
228
+ }
229
+ return moved;
230
+ }
231
+ function chordPitchClasses(chord, opts = {}) {
181
232
  const set = /* @__PURE__ */ new Set();
182
233
  for (const interval of chord.intervals) {
183
- set.add(pitchClass2(chord.rootPc + interval));
234
+ set.add(pitchClassOf(chord.rootPc + interval));
235
+ }
236
+ if (opts.includeBass !== false && chord.bassPc !== void 0) {
237
+ set.add(pitchClassOf(chord.bassPc));
184
238
  }
185
239
  return [...set].sort((a, b) => a - b);
186
240
  }
241
+ function intervalAboveRoot(pitch, chord) {
242
+ return ((pitchClassOf(pitch) - pitchClassOf(chord.rootPc)) % 12 + 12) % 12;
243
+ }
244
+ function isChordMember(pitch, chord) {
245
+ return chord === null ? false : chordPitchClasses(chord).includes(pitchClassOf(pitch));
246
+ }
187
247
  function chordToneOffsets(chord) {
188
248
  return new Set(chord.intervals.map((i) => (i % 12 + 12) % 12));
189
249
  }
190
250
  function chordToneRole(pitch, chord) {
191
- const interval = (pitchClass2(pitch) - pitchClass2(chord.rootPc) + 12) % 12;
251
+ const interval = (pitchClassOf(pitch) - pitchClassOf(chord.rootPc) + 12) % 12;
192
252
  const tones = chordToneOffsets(chord);
193
253
  if (interval === 0) {
194
254
  return "root";
@@ -264,12 +324,12 @@ function stackThirds(degree, key, size) {
264
324
  const tones = scaleTonesInDegreeOrder(key);
265
325
  const length = tones.length;
266
326
  if (length !== 7) {
267
- throw new Error(
327
+ throw new InvalidInputError(
268
328
  `diatonic chord stacking requires a heptatonic scale (received ${length} tones)`
269
329
  );
270
330
  }
271
331
  const idx = (step) => ((degree + step) % length + length) % length;
272
- const rootPc = tones[idx(0)] ?? pitchClass2(key.rootPc);
332
+ const rootPc = tones[idx(0)] ?? pitchClassOf(key.rootPc);
273
333
  const offsets = [0, 2, 4, 6].slice(0, size).map((step) => {
274
334
  const pc = tones[idx(step)] ?? rootPc;
275
335
  return ((pc - rootPc) % 12 + 12) % 12;
@@ -287,9 +347,6 @@ function diatonicSeventh(degree, key) {
287
347
  }
288
348
 
289
349
  // src/theory/counterpoint/index.ts
290
- function pitchClass3(pitch) {
291
- return (Math.trunc(pitch) % 12 + 12) % 12;
292
- }
293
350
  function createsVoiceCrossing(upperPitch, lowerPitch) {
294
351
  return upperPitch < lowerPitch;
295
352
  }
@@ -356,9 +413,9 @@ function exceedsSpacing(upperPitch, lowerPitch, maxSemitones = 12) {
356
413
  return Math.abs(upperPitch - lowerPitch) > maxSemitones;
357
414
  }
358
415
  function isLeadingToneResolution(prev, cur, key) {
359
- const tonic = pitchClass3(key.rootPc);
416
+ const tonic = pitchClassOf(key.rootPc);
360
417
  const leading = (tonic + 11) % 12;
361
- if (pitchClass3(prev) !== leading || pitchClass3(cur) !== tonic) {
418
+ if (pitchClassOf(prev) !== leading || pitchClassOf(cur) !== tonic) {
362
419
  return false;
363
420
  }
364
421
  return cur > prev && cur - prev <= 2;
@@ -387,14 +444,24 @@ export {
387
444
  OCTATONIC_HALF_WHOLE_MASK,
388
445
  OCTATONIC_WHOLE_HALF_MASK,
389
446
  CHROMATIC_MASK,
447
+ LYDIAN_DOMINANT_MASK,
448
+ MIXOLYDIAN_B13_MASK,
449
+ LOCRIAN_NATURAL2_MASK,
450
+ ALTERED_MASK,
451
+ PHRYGIAN_DOMINANT_MASK,
390
452
  NAMED_SCALES,
453
+ namedScaleMask,
454
+ requireScaleMask,
391
455
  majorKey,
392
456
  minorKey,
393
457
  scaleByName,
394
458
  chordQualities,
395
459
  chordFromDegree,
396
460
  makeChord,
461
+ transposeChord,
397
462
  chordPitchClasses,
463
+ intervalAboveRoot,
464
+ isChordMember,
398
465
  chordToneRole,
399
466
  diatonicTriad,
400
467
  diatonicSeventh,
@@ -409,4 +476,4 @@ export {
409
476
  exceedsSpacing,
410
477
  isLeadingToneResolution
411
478
  };
412
- //# sourceMappingURL=chunk-MIWO425M.js.map
479
+ //# sourceMappingURL=chunk-D2FAJBYL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theory/scale/degrees.ts","../src/theory/scale/masks.ts","../src/theory/scale/key.ts","../src/theory/chord/index.ts","../src/theory/counterpoint/index.ts"],"sourcesContent":["import { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\n\n/** Scale offset of a pitch relative to the key root, in [0, 11]. */\nfunction scaleOffset(pitch: number, key: KeyScale): number {\n return (pitchClass(pitch) - pitchClass(key.rootPc) + 12) % 12;\n}\n\n/**\n * Test whether a pitch belongs to the scale.\n *\n * @param pitch MIDI pitch or bare pitch class.\n * @param key The key/scale to test against.\n * @returns True if the pitch class is a member of the scale.\n *\n * @example\n * ```ts\n * import { majorKey, isScaleTone } from '@libraz/libcantus';\n * const key = majorKey(0); // C major\n * isScaleTone(64, key); // true — E is in C major\n * isScaleTone(61, key); // false — C# is not\n * ```\n *\n * @category Scales\n */\nexport function isScaleTone(pitch: number, key: KeyScale): boolean {\n return ((key.modeMask12 >> scaleOffset(pitch, key)) & 1) === 1;\n}\n\n/**\n * Find the nearest MIDI pitch whose pitch class is in the scale.\n *\n * The search expands symmetrically outward from `pitch`. On a tie (equal\n * distance above and below) the lower pitch is returned.\n *\n * @param pitch MIDI pitch to snap.\n * @param key The key/scale to snap to.\n * @returns The nearest in-scale MIDI pitch.\n *\n * @category Scales\n */\nexport function nearestScaleTone(pitch: number, key: KeyScale): number {\n const base = Math.round(pitch);\n for (let distance = 0; distance < 12; distance += 1) {\n const lower = base - distance;\n if (isScaleTone(lower, key)) {\n return lower;\n }\n const higher = base + distance;\n if (isScaleTone(higher, key)) {\n return higher;\n }\n }\n return base;\n}\n\n/**\n * Get the 0-based scale degree of a pitch.\n *\n * @param pitch MIDI pitch or bare pitch class.\n * @param key The key/scale to measure against.\n * @returns The 0-based degree, or -1 if the pitch is not in the scale.\n *\n * @category Scales\n */\nexport function pitchToScaleDegree(pitch: number, key: KeyScale): number {\n const offset = scaleOffset(pitch, key);\n if (((key.modeMask12 >> offset) & 1) === 0) {\n return -1;\n }\n let degree = 0;\n for (let n = 0; n < offset; n += 1) {\n if (((key.modeMask12 >> n) & 1) === 1) {\n degree += 1;\n }\n }\n return degree;\n}\n\n/**\n * List the pitch classes of a key's scale.\n *\n * @param key The key/scale to enumerate.\n * @returns The member pitch classes, sorted ascending in [0, 11].\n *\n * @category Scales\n */\nexport function diatonicPitchClasses(key: KeyScale): number[] {\n const root = pitchClass(key.rootPc);\n const pcs: number[] = [];\n for (let n = 0; n < 12; n += 1) {\n if (((key.modeMask12 >> n) & 1) === 1) {\n pcs.push((root + n) % 12);\n }\n }\n return pcs.sort((a, b) => a - b);\n}\n\n/**\n * List the pitch classes of a key's scale in ascending scale-degree order.\n *\n * Degree 0 is the root; degrees follow the mask bits in offset order rather\n * than sorted pitch-class order.\n *\n * @param key The key/scale to enumerate.\n * @returns The member pitch classes ordered by scale degree.\n *\n * @category Scales\n */\nexport function scaleTonesInDegreeOrder(key: KeyScale): number[] {\n const root = pitchClass(key.rootPc);\n const pcs: number[] = [];\n for (let n = 0; n < 12; n += 1) {\n if (((key.modeMask12 >> n) & 1) === 1) {\n pcs.push((root + n) % 12);\n }\n }\n return pcs;\n}\n","/**\n * Build a 12-bit mode mask from a list of semitone offsets above the root.\n *\n * Bit 0 (the root) is always set, enforcing the `KeyScale` invariant that the\n * root is a scale tone even when the offset list omits 0.\n *\n * @category Scales\n */\nimport { InvalidInputError } from '../../core/errors/index.js';\nexport function maskFromOffsets(offsets: readonly number[]): number {\n let mask = 1;\n for (const offset of offsets) {\n mask |= 1 << (((offset % 12) + 12) % 12);\n }\n return mask;\n}\n\n/**\n * Mode mask for the major (Ionian) scale: offsets {0, 2, 4, 5, 7, 9, 11}.\n *\n * @category Scales\n */\nexport const MAJOR_MASK = 0b101010110101;\n\n/**\n * Mode mask for the natural minor (Aeolian) scale: offsets {0, 2, 3, 5, 7, 8, 10}.\n *\n * @category Scales\n */\nexport const NATURAL_MINOR_MASK = 0b010110101101;\n\n/**\n * Harmonic minor: natural minor with a raised seventh — offsets {0,2,3,5,7,8,11}.\n *\n * @category Scales\n */\nexport const HARMONIC_MINOR_MASK = maskFromOffsets([0, 2, 3, 5, 7, 8, 11]);\n\n/**\n * Ascending melodic minor: offsets {0,2,3,5,7,9,11}.\n *\n * @category Scales\n */\nexport const MELODIC_MINOR_MASK = maskFromOffsets([0, 2, 3, 5, 7, 9, 11]);\n\n/**\n * Dorian mode: offsets {0,2,3,5,7,9,10}.\n *\n * @category Scales\n */\nexport const DORIAN_MASK = maskFromOffsets([0, 2, 3, 5, 7, 9, 10]);\n\n/**\n * Phrygian mode: offsets {0,1,3,5,7,8,10}.\n *\n * @category Scales\n */\nexport const PHRYGIAN_MASK = maskFromOffsets([0, 1, 3, 5, 7, 8, 10]);\n\n/**\n * Lydian mode: offsets {0,2,4,6,7,9,11}.\n *\n * @category Scales\n */\nexport const LYDIAN_MASK = maskFromOffsets([0, 2, 4, 6, 7, 9, 11]);\n\n/**\n * Mixolydian mode: offsets {0,2,4,5,7,9,10}.\n *\n * @category Scales\n */\nexport const MIXOLYDIAN_MASK = maskFromOffsets([0, 2, 4, 5, 7, 9, 10]);\n\n/**\n * Locrian mode: offsets {0,1,3,5,6,8,10}.\n *\n * @category Scales\n */\nexport const LOCRIAN_MASK = maskFromOffsets([0, 1, 3, 5, 6, 8, 10]);\n\n/**\n * Major pentatonic: offsets {0,2,4,7,9}.\n *\n * @category Scales\n */\nexport const MAJOR_PENTATONIC_MASK = maskFromOffsets([0, 2, 4, 7, 9]);\n\n/**\n * Minor pentatonic: offsets {0,3,5,7,10}.\n *\n * @category Scales\n */\nexport const MINOR_PENTATONIC_MASK = maskFromOffsets([0, 3, 5, 7, 10]);\n\n/**\n * Hexatonic blues scale: minor pentatonic plus the flat-fifth — {0,3,5,6,7,10}.\n *\n * @category Scales\n */\nexport const BLUES_MASK = maskFromOffsets([0, 3, 5, 6, 7, 10]);\n\n/**\n * Whole-tone scale: offsets {0,2,4,6,8,10}.\n *\n * @category Scales\n */\nexport const WHOLE_TONE_MASK = maskFromOffsets([0, 2, 4, 6, 8, 10]);\n\n/**\n * Octatonic (half-step first): offsets {0,1,3,4,6,7,9,10}.\n *\n * @category Scales\n */\nexport const OCTATONIC_HALF_WHOLE_MASK = maskFromOffsets([0, 1, 3, 4, 6, 7, 9, 10]);\n\n/**\n * Octatonic (whole-step first): offsets {0,2,3,5,6,8,9,11}.\n *\n * @category Scales\n */\nexport const OCTATONIC_WHOLE_HALF_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 9, 11]);\n\n/**\n * Chromatic scale: all twelve pitch classes.\n *\n * @category Scales\n */\nexport const CHROMATIC_MASK = 0b111111111111;\n\n/**\n * Lydian dominant (melodic minor's fourth mode): offsets {0,2,4,6,7,9,10}.\n *\n * The scale over an unaltered dominant with a raised eleventh.\n *\n * @category Scales\n */\nexport const LYDIAN_DOMINANT_MASK = maskFromOffsets([0, 2, 4, 6, 7, 9, 10]);\n\n/**\n * Mixolydian b13, the aeolian dominant (melodic minor's fifth mode): offsets\n * {0,2,4,5,7,8,10}.\n *\n * The scale over a dominant with a flat thirteenth.\n *\n * @category Scales\n */\nexport const MIXOLYDIAN_B13_MASK = maskFromOffsets([0, 2, 4, 5, 7, 8, 10]);\n\n/**\n * Locrian natural 2 (melodic minor's sixth mode): offsets {0,2,3,5,6,8,10}.\n *\n * The scale over a half-diminished chord used as a minor ii.\n *\n * @category Scales\n */\nexport const LOCRIAN_NATURAL2_MASK = maskFromOffsets([0, 2, 3, 5, 6, 8, 10]);\n\n/**\n * The altered scale, or superlocrian (melodic minor's seventh mode): offsets\n * {0,1,3,4,6,8,10}.\n *\n * The scale over an altered dominant: every tension raised or lowered.\n *\n * @category Scales\n */\nexport const ALTERED_MASK = maskFromOffsets([0, 1, 3, 4, 6, 8, 10]);\n\n/**\n * Phrygian dominant (harmonic minor's fifth mode): offsets {0,1,4,5,7,8,10}.\n *\n * The scale over the dominant of a minor key, and the characteristic sound of\n * the flamenco and maqam repertoires.\n *\n * @category Scales\n */\nexport const PHRYGIAN_DOMINANT_MASK = maskFromOffsets([0, 1, 4, 5, 7, 8, 10]);\n\n/**\n * Named scale masks addressable by {@link scaleByName}.\n *\n * @category Scales\n */\nexport const NAMED_SCALES = Object.freeze({\n major: MAJOR_MASK,\n ionian: MAJOR_MASK,\n naturalMinor: NATURAL_MINOR_MASK,\n aeolian: NATURAL_MINOR_MASK,\n harmonicMinor: HARMONIC_MINOR_MASK,\n melodicMinor: MELODIC_MINOR_MASK,\n dorian: DORIAN_MASK,\n phrygian: PHRYGIAN_MASK,\n lydian: LYDIAN_MASK,\n mixolydian: MIXOLYDIAN_MASK,\n locrian: LOCRIAN_MASK,\n lydianDominant: LYDIAN_DOMINANT_MASK,\n mixolydianB13: MIXOLYDIAN_B13_MASK,\n locrianNatural2: LOCRIAN_NATURAL2_MASK,\n altered: ALTERED_MASK,\n phrygianDominant: PHRYGIAN_DOMINANT_MASK,\n majorPentatonic: MAJOR_PENTATONIC_MASK,\n minorPentatonic: MINOR_PENTATONIC_MASK,\n blues: BLUES_MASK,\n wholeTone: WHOLE_TONE_MASK,\n octatonicHalfWhole: OCTATONIC_HALF_WHOLE_MASK,\n octatonicWholeHalf: OCTATONIC_WHOLE_HALF_MASK,\n chromatic: CHROMATIC_MASK,\n});\n\n/**\n * The name of a built-in scale, as accepted by {@link scaleByName},\n * {@link avoidNotes}, and {@link availableTensions}.\n *\n * @category Scales\n */\nexport type ScaleName = keyof typeof NAMED_SCALES;\n\n/**\n * A scale name that completes to the built-in names but still accepts any\n * string, so a caller with a name from configuration is not forced to cast.\n *\n * @category Scales\n */\nexport type ScaleNameInput = ScaleName | (string & {});\n\n/**\n * The mask of a named scale, or undefined when the name is not one.\n *\n * Looking the name up through this helper is what keeps `'constructor'` or\n * `'toString'` from resolving to something inherited from `Object.prototype`\n * and producing a scale whose mask is a function.\n *\n * @param name The scale name.\n * @returns The 12-bit mask, or undefined for an unknown name.\n * @category Scales\n */\nexport function namedScaleMask(name: ScaleNameInput): number | undefined {\n return Object.hasOwn(NAMED_SCALES, name) ? NAMED_SCALES[name as ScaleName] : undefined;\n}\n\n/**\n * The mask of a named scale, rejecting an unknown name.\n *\n * Every public entry point that takes a scale name funnels through here, so a\n * typo is reported the same way everywhere instead of being answered with an\n * empty result that also means \"this scale has none\".\n *\n * @param name The scale name.\n * @param label What the name is, for the error message.\n * @returns The 12-bit mask.\n * @throws If the name is not a built-in scale.\n * @category Scales\n */\nexport function requireScaleMask(name: ScaleNameInput, label = 'scale'): number {\n const mask = namedScaleMask(name);\n if (mask === undefined) {\n throw new InvalidInputError(`Unknown ${label}: ${String(name)}`);\n }\n return mask;\n}\n","import type { KeyScale } from '../../core/types.js';\nimport type { ScaleNameInput } from './masks.js';\nimport { MAJOR_MASK, NATURAL_MINOR_MASK, requireScaleMask } from './masks.js';\n\n/**\n * Build a `KeyScale` for a major key on the given root pitch class.\n *\n * @example\n * ```ts\n * import { majorKey } from '@libraz/libcantus';\n * const cMajor = majorKey(0); // C major: { rootPc: 0, modeMask12: MAJOR_MASK }\n * ```\n *\n * @category Scales\n */\nexport function majorKey(rootPc: number): KeyScale {\n return { rootPc: ((rootPc % 12) + 12) % 12, modeMask12: MAJOR_MASK };\n}\n\n/**\n * Build a `KeyScale` for a natural-minor key on the given root pitch class.\n *\n * @example\n * ```ts\n * import { minorKey } from '@libraz/libcantus';\n * const aMinor = minorKey(9); // A natural minor: { rootPc: 9, modeMask12: NATURAL_MINOR_MASK }\n * ```\n *\n * @category Scales\n */\nexport function minorKey(rootPc: number): KeyScale {\n return { rootPc: ((rootPc % 12) + 12) % 12, modeMask12: NATURAL_MINOR_MASK };\n}\n\n/**\n * Build a `KeyScale` from a named scale (see {@link NAMED_SCALES}).\n *\n * @param name The scale name, e.g. `'dorian'` or `'harmonicMinor'`.\n * @param rootPc The root pitch class.\n * @returns The key/scale.\n * @throws If the name is not a known scale.\n *\n * @example\n * ```ts\n * import { scaleByName } from '@libraz/libcantus';\n * const dDorian = scaleByName('dorian', 2); // D Dorian, rootPc 2\n * ```\n *\n * @category Scales\n */\nexport function scaleByName(name: ScaleNameInput, rootPc: number): KeyScale {\n return { rootPc: ((rootPc % 12) + 12) % 12, modeMask12: requireScaleMask(name) };\n}\n","import { InvalidInputError } from '../../core/errors/index.js';\nimport { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport { assertFiniteNumber, assertInteger } from '../../core/validation/index.js';\nimport { scaleTonesInDegreeOrder } from '../scale/index.js';\n\n/**\n * Chord quality identifiers understood by the chord builder.\n *\n * @category Chords\n */\nexport type ChordQuality =\n | 'maj'\n | 'min'\n | 'dim'\n | 'aug'\n | 'maj7'\n | 'min7'\n | 'dom7'\n | 'dim7'\n | 'm7b5'\n | 'minMaj7'\n | 'aug7'\n | 'augMaj7'\n | 'majb5'\n | '6'\n | 'min6'\n | '6/9'\n | 'sus2'\n | 'sus4'\n | 'add9'\n | 'add11'\n | 'maj9'\n | 'min9'\n | 'dom9'\n | '7b9'\n | '7#9'\n | '7#11'\n | '7b13'\n | '11'\n | '13'\n | '5'\n | '7sus4'\n | '7b5'\n | '7alt'\n | '13b9'\n | 'maj13'\n | 'maj7#11'\n | 'min11'\n | 'min13'\n | 'minAdd9'\n | 'min6/9';\n\n/**\n * The basic role a chord tone plays: the degrees a chord's own template names.\n *\n * The shared vocabulary behind {@link chordToneRole}, the harmony layer's\n * `HarmonyRole`, and the voice analyser's labels, so the three cannot drift.\n *\n * @category Chords\n */\nexport type ChordToneRole = 'root' | 'third' | 'fifth' | 'sixth' | 'seventh';\n\n/**\n * A bare spelled pitch used as an enharmonic hint: a diatonic letter\n * (0..6 = C..B) plus a chromatic alteration (-2 double-flat .. +2 double-sharp).\n * Mirrors the letter/alter half of the pitch module's `Note` without an octave.\n *\n * @category Chords\n */\nexport type PitchSpelling = {\n letter: number;\n alter: number;\n};\n\n/**\n * A chord expressed as a root pitch class plus semitone offsets.\n *\n * `rootSpelling`/`bassSpelling` are optional enharmonic hints recorded by\n * parsers (e.g. `parseChordSymbol('Bb7')`) so formatters can reproduce the\n * original spelling instead of defaulting to sharps. Consumers may ignore\n * them; a hint is only trusted when its pitch class still matches the\n * corresponding `rootPc`/`bassPc`.\n *\n * @category Chords\n */\nexport type Chord = {\n rootPc: number;\n quality: ChordQuality;\n intervals: number[];\n bassPc?: number;\n rootSpelling?: PitchSpelling;\n bassSpelling?: PitchSpelling;\n};\n\n/**\n * A chord positioned in time: a root pitch class and quality placed at a beat,\n * with optional harmonic-analysis hints. Serves as the neutral exchange record\n * between progression generators and timeline analysers.\n *\n * @category Composition\n */\nexport type ChordSpan = {\n rootPc: number;\n quality: ChordQuality;\n startBeat: number;\n bassPc?: number;\n /** 0-based scale degree of the chord root, when known. */\n degree?: number;\n /** True when the chord is a secondary dominant tonicizing another degree. */\n secondaryDominant?: boolean;\n};\n\n/**\n * A chord occupying a half-open beat span `[startBeat, endBeat)`.\n *\n * The exchange record between anything that lays chords out in time — a\n * timeline analysis, a bass-line plan, an accompaniment generator — so those\n * surfaces share one definition instead of agreeing by coincidence.\n *\n * @category Composition\n */\nexport type ChordSegment = {\n startBeat: number;\n endBeat: number;\n chord: Chord;\n};\n\n/** Semitone offsets from the root for each supported chord quality. */\nconst QUALITY_INTERVALS: Record<ChordQuality, number[]> = {\n maj: [0, 4, 7],\n min: [0, 3, 7],\n dim: [0, 3, 6],\n aug: [0, 4, 8],\n majb5: [0, 4, 6],\n maj7: [0, 4, 7, 11],\n min7: [0, 3, 7, 10],\n dom7: [0, 4, 7, 10],\n dim7: [0, 3, 6, 9],\n m7b5: [0, 3, 6, 10],\n minMaj7: [0, 3, 7, 11],\n aug7: [0, 4, 8, 10],\n augMaj7: [0, 4, 8, 11],\n '6': [0, 4, 7, 9],\n min6: [0, 3, 7, 9],\n '6/9': [0, 4, 7, 9, 14],\n sus2: [0, 2, 7],\n sus4: [0, 5, 7],\n add9: [0, 4, 7, 14],\n add11: [0, 4, 7, 17],\n maj9: [0, 4, 7, 11, 14],\n min9: [0, 3, 7, 10, 14],\n dom9: [0, 4, 7, 10, 14],\n '7b9': [0, 4, 7, 10, 13],\n '7#9': [0, 4, 7, 10, 15],\n '7#11': [0, 4, 7, 10, 18],\n '7b13': [0, 4, 7, 10, 20],\n '11': [0, 7, 10, 14, 17],\n '13': [0, 4, 7, 10, 14, 21],\n '5': [0, 7],\n '7sus4': [0, 5, 7, 10],\n '7b5': [0, 4, 6, 10],\n // The altered dominant as it is voiced from a lead sheet: a dominant seventh\n // with a raised fifth and a raised ninth. The full seven-note altered stack\n // has no seven-letter spelling, so it is not what this symbol denotes.\n '7alt': [0, 4, 8, 10, 15],\n '13b9': [0, 4, 7, 10, 13, 21],\n maj13: [0, 4, 7, 11, 14, 21],\n 'maj7#11': [0, 4, 7, 11, 18],\n min11: [0, 3, 7, 10, 14, 17],\n min13: [0, 3, 7, 10, 14, 21],\n minAdd9: [0, 3, 7, 14],\n 'min6/9': [0, 3, 7, 9, 14],\n};\n\n/**\n * All chord qualities the builder understands, in declaration order.\n *\n * The order is stable but carries no meaning: it is neither alphabetical nor\n * sorted by template size. {@link detectChord} uses it as its final tie-break,\n * so it is part of the observable behaviour and does not get reshuffled\n * casually — but do not read it as a ranking.\n *\n * @category Chords\n */\nexport function chordQualities(): ChordQuality[] {\n return Object.keys(QUALITY_INTERVALS) as ChordQuality[];\n}\n\n/**\n * Build a chord rooted on a diatonic scale degree.\n *\n * The root pitch class is the degree's diatonic pitch class in `key`; the\n * quality's interval template is attached unchanged. Degrees beyond the scale\n * length wrap around.\n *\n * @param degree 0-based scale degree of the chord root.\n * @param ext Chord quality to apply.\n * @param key Key context supplying the diatonic root.\n * @returns The constructed chord.\n *\n * @category Chords\n */\nexport function chordFromDegree(degree: number, ext: ChordQuality, key: KeyScale): Chord {\n assertInteger(degree, 'chord degree', -1000, 1000);\n if (!Object.hasOwn(QUALITY_INTERVALS, ext)) {\n throw new InvalidInputError(`Unknown chord quality: ${String(ext)}`);\n }\n const tones = scaleTonesInDegreeOrder(key);\n const length = tones.length;\n const index = length > 0 ? ((degree % length) + length) % length : 0;\n const rootPc = tones[index] ?? pitchClass(key.rootPc);\n return { rootPc, quality: ext, intervals: [...QUALITY_INTERVALS[ext]] };\n}\n\n/**\n * Build a chord from an explicit root pitch class and quality.\n *\n * @param rootPc Root pitch class (0..11).\n * @param quality Chord quality supplying the interval template.\n * @param bassPc Optional slash-chord bass pitch class.\n * @returns The constructed chord.\n *\n * @example\n * ```ts\n * import { makeChord } from '@libraz/libcantus';\n * const cmaj7 = makeChord(0, 'maj7');\n * // { rootPc: 0, quality: 'maj7', intervals: [0, 4, 7, 11] }\n * ```\n *\n * @category Chords\n */\nexport function makeChord(rootPc: number, quality: ChordQuality, bassPc?: number): Chord {\n // A NaN root formats as 'C' and an unknown quality as 'Cundefined', so both\n // travel on into voicing, detection, and serialization as a chord that looks\n // real. They are rejected where the chord is built instead.\n assertFiniteNumber(rootPc, 'chord rootPc');\n if (bassPc !== undefined) {\n assertFiniteNumber(bassPc, 'chord bassPc');\n }\n if (!Object.hasOwn(QUALITY_INTERVALS, quality)) {\n throw new InvalidInputError(`Unknown chord quality: ${String(quality)}`);\n }\n const chord: Chord = {\n rootPc: pitchClass(rootPc),\n quality,\n intervals: [...(QUALITY_INTERVALS[quality] ?? [])],\n };\n if (bassPc !== undefined) {\n chord.bassPc = pitchClass(bassPc);\n }\n return chord;\n}\n\n/**\n * Transpose a chord by a number of semitones.\n *\n * The interval template is carried over untouched, so a chord whose intervals\n * were customised keeps them, and a slash bass moves with the root. Enharmonic\n * spelling hints are dropped rather than shifted: the letter a transposed root\n * should take depends on the destination key, which a semitone count does not\n * carry. Pass the result through {@link spellChord} to respell it.\n *\n * @param chord The chord to transpose.\n * @param semitones The signed semitone offset.\n * @returns The transposed chord.\n * @throws If `semitones` is not finite.\n *\n * @example\n * ```ts\n * import { formatChordSymbol, parseChordSymbol, transposeChord } from '@libraz/libcantus';\n * formatChordSymbol(transposeChord(parseChordSymbol('C/G'), 2)); // 'D/A'\n * ```\n *\n * @category Chords\n */\nexport function transposeChord(chord: Chord, semitones: number): Chord {\n assertFiniteNumber(semitones, 'semitones');\n const steps = Math.round(semitones);\n const moved: Chord = {\n rootPc: pitchClass(chord.rootPc + steps),\n quality: chord.quality,\n intervals: [...chord.intervals],\n };\n if (chord.bassPc !== undefined) {\n moved.bassPc = pitchClass(chord.bassPc + steps);\n }\n return moved;\n}\n\n/**\n * Get the sorted, deduplicated pitch classes of a chord.\n *\n * A slash bass is one of them: `F/G` sounds a G, the voicers put it in the\n * bass, and a set that omitted it would not re-detect as the chord it came\n * from. Pass `includeBass: false` to enumerate the interval template alone.\n *\n * @param chord The chord to enumerate.\n * @param opts Set `includeBass: false` to omit a slash bass.\n * @returns The chord's pitch classes, sorted ascending in [0, 11].\n *\n * @example\n * ```ts\n * import { makeChord, chordPitchClasses } from '@libraz/libcantus';\n * chordPitchClasses(makeChord(0, 'maj7')); // [0, 4, 7, 11]\n * chordPitchClasses(makeChord(5, 'maj', 7)); // [0, 5, 7, 9] — F/G, G included\n * ```\n *\n * @category Chords\n */\nexport function chordPitchClasses(chord: Chord, opts: { includeBass?: boolean } = {}): number[] {\n const set = new Set<number>();\n for (const interval of chord.intervals) {\n set.add(pitchClass(chord.rootPc + interval));\n }\n if (opts.includeBass !== false && chord.bassPc !== undefined) {\n set.add(pitchClass(chord.bassPc));\n }\n return [...set].sort((a, b) => a - b);\n}\n\n/**\n * A pitch's interval class above the chord root, in [0, 11].\n *\n * The shared reading of \"where does this pitch sit in the chord\", used by the\n * safety evaluator and the voice analyser alike so they cannot disagree.\n *\n * @param pitch MIDI pitch or bare pitch class.\n * @param chord The chord providing the root reference.\n * @returns The interval class above the root.\n * @category Chords\n */\nexport function intervalAboveRoot(pitch: number, chord: Chord): number {\n return (((pitchClass(pitch) - pitchClass(chord.rootPc)) % 12) + 12) % 12;\n}\n\n/**\n * Whether a pitch is one of a chord's tones, ignoring octave.\n *\n * @param pitch MIDI pitch or bare pitch class.\n * @param chord The chord, or null for no sounding harmony.\n * @returns True when the pitch class belongs to the chord.\n * @category Chords\n */\nexport function isChordMember(pitch: number, chord: Chord | null): boolean {\n return chord === null ? false : chordPitchClasses(chord).includes(pitchClass(pitch));\n}\n\n/** The chord-tone offsets present in a chord, reduced to pitch-class space. */\nfunction chordToneOffsets(chord: Chord): Set<number> {\n return new Set(chord.intervals.map((i) => ((i % 12) + 12) % 12));\n}\n\n/**\n * Determine a pitch's harmonic role within a chord.\n *\n * The role is derived from the pitch's interval above the chord root, reduced\n * modulo 12. A major sixth (9) reads as a `sixth` for sixth chords but as a\n * `seventh` for a diminished-seventh chord; ninths and other tensions have no\n * basic role and return null.\n *\n * @param pitch MIDI pitch or bare pitch class.\n * @param chord The chord providing the root reference.\n * @returns The chord-tone role, or null if the pitch has no basic role.\n *\n * @category Chords\n */\nexport function chordToneRole(pitch: number, chord: Chord): ChordToneRole | null {\n const interval = (pitchClass(pitch) - pitchClass(chord.rootPc) + 12) % 12;\n const tones = chordToneOffsets(chord);\n if (interval === 0) {\n return 'root';\n }\n if (interval === 3 || interval === 4) {\n return tones.has(interval) ? 'third' : null;\n }\n if (interval === 7) {\n return tones.has(7) ? 'fifth' : null;\n }\n if (interval === 6) {\n // A diminished fifth is the chord's fifth only when no perfect fifth is\n // present; alongside a perfect fifth it is a #11 tension, not a fifth.\n return tones.has(6) && !tones.has(7) ? 'fifth' : null;\n }\n if (interval === 8) {\n // An augmented fifth is the chord's fifth only without a perfect fifth;\n // alongside a perfect fifth it is a b13 tension, not a fifth.\n return tones.has(8) && !tones.has(7) ? 'fifth' : null;\n }\n if (interval === 9) {\n const hasHigherSeventh = tones.has(10) || tones.has(11);\n const isDiminishedSeventh = tones.has(3) && tones.has(6) && !hasHigherSeventh;\n if (isDiminishedSeventh) {\n return 'seventh';\n }\n if (tones.has(9) && !hasHigherSeventh) {\n return 'sixth';\n }\n return null;\n }\n if (interval === 10 || interval === 11) {\n return tones.has(interval) ? 'seventh' : null;\n }\n return null;\n}\n\n/** Classify a stacked-thirds triad into a chord quality from its interval set. */\nfunction classifyTriad(thirdIc: number, fifthIc: number): ChordQuality {\n if (thirdIc === 4 && fifthIc === 8) {\n return 'aug';\n }\n if (thirdIc === 4 && fifthIc === 6) {\n return 'majb5';\n }\n if (thirdIc === 3 && fifthIc === 6) {\n return 'dim';\n }\n if (thirdIc === 3) {\n return 'min';\n }\n return 'maj';\n}\n\n/** Classify a stacked-thirds seventh chord into a chord quality. */\nfunction classifySeventh(thirdIc: number, fifthIc: number, seventhIc: number): ChordQuality {\n if (thirdIc === 3 && fifthIc === 6 && seventhIc === 9) {\n return 'dim7';\n }\n if (thirdIc === 3 && fifthIc === 6 && seventhIc === 10) {\n return 'm7b5';\n }\n if (thirdIc === 3 && seventhIc === 11) {\n return 'minMaj7';\n }\n if (thirdIc === 3) {\n return 'min7';\n }\n if (fifthIc === 8 && seventhIc === 10) {\n return 'aug7';\n }\n if (fifthIc === 8 && seventhIc === 11) {\n return 'augMaj7';\n }\n if (seventhIc === 11) {\n return 'maj7';\n }\n return 'dom7';\n}\n\n/** Stack scale thirds from a scale degree into a chord of `size` notes. */\nfunction stackThirds(degree: number, key: KeyScale, size: 3 | 4): Chord {\n const tones = scaleTonesInDegreeOrder(key);\n const length = tones.length;\n if (length !== 7) {\n throw new InvalidInputError(\n `diatonic chord stacking requires a heptatonic scale (received ${length} tones)`,\n );\n }\n const idx = (step: number) => (((degree + step) % length) + length) % length;\n const rootPc = tones[idx(0)] ?? pitchClass(key.rootPc);\n const offsets = [0, 2, 4, 6].slice(0, size).map((step) => {\n const pc = tones[idx(step)] ?? rootPc;\n return (((pc - rootPc) % 12) + 12) % 12;\n });\n const thirdIc = offsets[1] ?? 4;\n const fifthIc = offsets[2] ?? 7;\n const quality =\n size === 3\n ? classifyTriad(thirdIc, fifthIc)\n : classifySeventh(thirdIc, fifthIc, offsets[3] ?? 11);\n return { rootPc, quality, intervals: offsets };\n}\n\n/**\n * Build the diatonic triad rooted on a scale degree by stacking scale thirds.\n *\n * Unlike {@link chordFromDegree}, the chord quality is derived from the scale\n * rather than supplied, so degrees yield their scale-correct triads (e.g. a\n * diminished triad on the leading tone of a major key).\n *\n * @param degree 0-based scale degree of the chord root.\n * @param key Key/scale context.\n * @returns The diatonic triad.\n * @throws If the scale is not heptatonic. Stacking thirds means skipping every\n * other degree, which only lands on a triad when there are seven of them, so\n * the pentatonic, blues, whole-tone, octatonic and chromatic scales have no\n * diatonic triad; use {@link chordFromDegree} with an explicit quality there.\n *\n * @example\n * ```ts\n * import { majorKey, diatonicTriad } from '@libraz/libcantus';\n * const tonic = diatonicTriad(0, majorKey(0)); // C major triad (degree 0 of C major)\n * ```\n *\n * @category Chords\n */\nexport function diatonicTriad(degree: number, key: KeyScale): Chord {\n return stackThirds(degree, key, 3);\n}\n\n/**\n * Build the diatonic seventh chord rooted on a scale degree.\n *\n * @param degree 0-based scale degree of the chord root.\n * @param key Key/scale context.\n * @returns The diatonic seventh chord.\n * @throws If the scale is not heptatonic, for the reason given on\n * {@link diatonicTriad}.\n *\n * @category Chords\n */\nexport function diatonicSeventh(degree: number, key: KeyScale): Chord {\n return stackThirds(degree, key, 4);\n}\n","import { isConsonantInterval } from '../../core/interval/index.js';\nimport { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\n\n/**\n * Whether an upper voice has crossed below a lower voice.\n *\n * @param upperPitch Pitch of the nominally higher voice.\n * @param lowerPitch Pitch of the nominally lower voice.\n * @returns True when the upper voice sits below the lower voice.\n * @category Voicing & Counterpoint\n */\nexport function createsVoiceCrossing(upperPitch: number, lowerPitch: number): boolean {\n return upperPitch < lowerPitch;\n}\n\n/**\n * Whether two simultaneous pitches form a dissonance.\n *\n * @param a First pitch.\n * @param b Second pitch.\n * @param twoVoice When true, the perfect fourth counts as dissonant.\n * @returns True when the vertical interval is dissonant.\n * @category Voicing & Counterpoint\n */\nexport function createsVerticalDissonance(a: number, b: number, twoVoice: boolean): boolean {\n return !isConsonantInterval(a - b, twoVoice);\n}\n\n/**\n * Whether a melodic move is a forbidden leap: a tritone, either seventh (minor\n * or major), or any leap wider than an octave.\n *\n * Operates on the raw absolute distance, so compound leaps are not reduced to\n * their simple class before the octave check.\n *\n * @param prev Starting pitch.\n * @param cur Ending pitch.\n * @returns True when the leap is forbidden in strict counterpoint.\n * @category Voicing & Counterpoint\n */\nexport function isForbiddenMelodicLeap(prev: number, cur: number): boolean {\n const semis = Math.abs(cur - prev);\n return semis === 6 || semis === 10 || semis === 11 || semis > 12;\n}\n\n/** Reduce an interval to its simple class in [0, 11]. */\nfunction simpleClass(semitones: number): number {\n return Math.abs(semitones) % 12;\n}\n\n/** Whether a simple interval class is a perfect kind (unison/octave or fifth). */\nfunction isPerfectClass(cls: number): boolean {\n return cls === 0 || cls === 7;\n}\n\n/** Whether two voices move in the same direction (similar or parallel motion). */\nfunction similarMotion(aMove: number, bMove: number): boolean {\n return aMove !== 0 && bMove !== 0 && aMove > 0 === bMove > 0;\n}\n\n/** Whether both voices actually move (neither is stationary — excludes oblique motion). */\nfunction bothVoicesMove(aMove: number, bMove: number): boolean {\n return aMove !== 0 && bMove !== 0;\n}\n\n/**\n * Whether two voices move into consecutive perfect intervals of the same kind\n * (fifth-to-fifth, octave-to-octave, unison-to-unison).\n *\n * Both true parallels (similar motion) and anti-parallels — the same perfect\n * class reached by contrary motion, e.g. octave to octave with the voices moving\n * in opposite directions — are flagged, as both are forbidden in strict two-voice\n * counterpoint. The rule requires that both voices actually move: oblique motion\n * (either voice stationary) and the no-change case (identical pitches) are excluded.\n *\n * A fifth expanding to a twelfth counts (same perfect class); a fifth moving to\n * an octave does not (different perfect kinds — the direct/hidden case owned by\n * {@link createsHiddenParallelPerfect}).\n *\n * @category Voicing & Counterpoint\n */\nexport function createsParallelPerfect(\n aPrev: number,\n aCur: number,\n bPrev: number,\n bCur: number,\n): boolean {\n if (!bothVoicesMove(aCur - aPrev, bCur - bPrev)) {\n return false;\n }\n const nowClass = simpleClass(aCur - bCur);\n const prevClass = simpleClass(aPrev - bPrev);\n return isPerfectClass(nowClass) && nowClass === prevClass;\n}\n\n/**\n * Whether two voices move in consecutive parallel octaves (or unisons) by\n * similar motion.\n *\n * This is a strict subset of {@link createsParallelPerfect}: a similar-motion\n * octave-to-octave is the perfect-class-zero case that predicate already flags\n * (and it additionally catches the contrary-motion anti-parallel). Callers that\n * tally parallel violations should therefore use {@link createsParallelPerfect}\n * alone to avoid double counting; this predicate remains for callers wanting a\n * dedicated similar-motion octave test.\n *\n * @category Voicing & Counterpoint\n */\nexport function createsParallelOctave(\n aPrev: number,\n aCur: number,\n bPrev: number,\n bCur: number,\n): boolean {\n if (!similarMotion(aCur - aPrev, bCur - bPrev)) {\n return false;\n }\n return simpleClass(aCur - bCur) === 0 && simpleClass(aPrev - bPrev) === 0;\n}\n\n/**\n * Whether two voices move in consecutive parallel unisons — both landing on the\n * same pitch, having shared a pitch on the previous move.\n *\n * @category Voicing & Counterpoint\n */\nexport function createsParallelUnison(\n aPrev: number,\n aCur: number,\n bPrev: number,\n bCur: number,\n): boolean {\n if (aCur === aPrev || bCur === bPrev) {\n return false;\n }\n return aCur === bCur && aPrev === bPrev;\n}\n\n/**\n * Whether two voices reach a perfect interval by similar motion from an\n * imperfect one (a hidden/direct fifth or octave).\n *\n * The traditional step exception is applied: the approach is allowed when the\n * upper of the two voices moves by step, so only leaps into the perfect\n * interval are flagged.\n *\n * @category Voicing & Counterpoint\n */\nexport function createsHiddenParallelPerfect(\n aPrev: number,\n aCur: number,\n bPrev: number,\n bCur: number,\n): boolean {\n const aMove = aCur - aPrev;\n const bMove = bCur - bPrev;\n if (!similarMotion(aMove, bMove)) {\n return false;\n }\n const nowClass = simpleClass(aCur - bCur);\n const prevClass = simpleClass(aPrev - bPrev);\n // Approaching the same perfect class (e.g. fifth to fifth) is a true parallel\n // owned by createsParallelPerfect; approaching a different perfect interval\n // (fifth to octave, or vice versa) is the hidden/direct case flagged here.\n if (!isPerfectClass(nowClass) || prevClass === nowClass) {\n return false;\n }\n const upperMove = aCur >= bCur ? aMove : bMove;\n if (Math.abs(upperMove) <= 2) {\n return false; // upper voice moves by step — direct interval is acceptable\n }\n return true;\n}\n\n/**\n * Whether two voices overlap: the upper voice descends below where the lower\n * voice just was, or the lower voice rises above where the upper voice just was.\n * Distinct from a simultaneous voice crossing.\n *\n * @param upperPrev Previous pitch of the upper voice.\n * @param upperCur Current pitch of the upper voice.\n * @param lowerPrev Previous pitch of the lower voice.\n * @param lowerCur Current pitch of the lower voice.\n * @category Voicing & Counterpoint\n */\nexport function createsVoiceOverlap(\n upperPrev: number,\n upperCur: number,\n lowerPrev: number,\n lowerCur: number,\n): boolean {\n return upperCur < lowerPrev || lowerCur > upperPrev;\n}\n\n/**\n * Whether two adjacent upper voices are spaced more than a maximum apart\n * (commonly an octave). Bass-to-tenor spacing is conventionally exempt, so this\n * is meant for the upper voice pairs.\n *\n * @param upperPitch Pitch of the higher voice.\n * @param lowerPitch Pitch of the lower voice.\n * @param maxSemitones Maximum allowed spacing in semitones (default an octave).\n * @category Voicing & Counterpoint\n */\nexport function exceedsSpacing(upperPitch: number, lowerPitch: number, maxSemitones = 12): boolean {\n return Math.abs(upperPitch - lowerPitch) > maxSemitones;\n}\n\n/**\n * Whether a leading tone resolves correctly upward to the tonic.\n *\n * @param prev The leading-tone pitch.\n * @param cur The following pitch.\n * @param key Key context supplying the tonic.\n * @returns True when `prev` is the leading tone and `cur` is the tonic a step above.\n * @category Voicing & Counterpoint\n */\nexport function isLeadingToneResolution(prev: number, cur: number, key: KeyScale): boolean {\n const tonic = pitchClass(key.rootPc);\n const leading = (tonic + 11) % 12;\n if (pitchClass(prev) !== leading || pitchClass(cur) !== tonic) {\n return false;\n }\n return cur > prev && cur - prev <= 2;\n}\n"],"mappings":"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","names":[]}