@libraz/libcantus 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -65
- package/README_ja.md +28 -66
- package/dist/analyze/index.cjs +11 -7
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +79 -144
- package/dist/analyze/index.d.ts +79 -144
- package/dist/analyze/index.js +20 -16
- package/dist/chunk-35NBV2FT.cjs +145 -0
- package/dist/chunk-35NBV2FT.cjs.map +1 -0
- package/dist/{chunk-UADYAYAT.cjs → chunk-3R3QVKY5.cjs} +1353 -580
- package/dist/chunk-3R3QVKY5.cjs.map +1 -0
- package/dist/{chunk-WWURE4XT.cjs → chunk-76ZBTRG2.cjs} +624 -729
- package/dist/chunk-76ZBTRG2.cjs.map +1 -0
- package/dist/{chunk-FVSI36UV.js → chunk-7KG3RTYS.js} +197 -110
- package/dist/chunk-7KG3RTYS.js.map +1 -0
- package/dist/{chunk-VTI6FOLB.js → chunk-AGOVW7U6.js} +709 -133
- package/dist/chunk-AGOVW7U6.js.map +1 -0
- package/dist/{chunk-E3F4AHAH.cjs → chunk-CGBADIO5.cjs} +221 -134
- package/dist/chunk-CGBADIO5.cjs.map +1 -0
- package/dist/{chunk-6XH6QZYQ.cjs → chunk-DSMJRXCZ.cjs} +1455 -849
- package/dist/chunk-DSMJRXCZ.cjs.map +1 -0
- package/dist/{chunk-PKFNUHDY.js → chunk-FBH75DAY.js} +1218 -612
- package/dist/chunk-FBH75DAY.js.map +1 -0
- package/dist/chunk-H2KJHBW4.js +3329 -0
- package/dist/chunk-H2KJHBW4.js.map +1 -0
- package/dist/chunk-HPVSH7SF.cjs +2294 -0
- package/dist/chunk-HPVSH7SF.cjs.map +1 -0
- package/dist/{chunk-MXO72PLY.cjs → chunk-HWHGOVO6.cjs} +21 -19
- package/dist/chunk-HWHGOVO6.cjs.map +1 -0
- package/dist/chunk-HYJJ2V2I.js +2294 -0
- package/dist/chunk-HYJJ2V2I.js.map +1 -0
- package/dist/{chunk-AFM2ULJH.cjs → chunk-J7FHVZII.cjs} +1567 -1067
- package/dist/chunk-J7FHVZII.cjs.map +1 -0
- package/dist/chunk-K6OZXIR6.js +1 -0
- package/dist/{chunk-H3VORETI.js → chunk-M5RYMAFI.js} +487 -592
- package/dist/chunk-M5RYMAFI.js.map +1 -0
- package/dist/chunk-NB25P3EH.js +363 -0
- package/dist/chunk-NB25P3EH.js.map +1 -0
- package/dist/{chunk-TTCLJX6D.js → chunk-NFJ4P6ZZ.js} +10 -8
- package/dist/chunk-NFJ4P6ZZ.js.map +1 -0
- package/dist/chunk-NM7UAMC3.cjs +457 -0
- package/dist/chunk-NM7UAMC3.cjs.map +1 -0
- package/dist/chunk-PM4XJE2Y.cjs +363 -0
- package/dist/chunk-PM4XJE2Y.cjs.map +1 -0
- package/dist/chunk-PUKJP2Z5.js +145 -0
- package/dist/chunk-PUKJP2Z5.js.map +1 -0
- package/dist/{chunk-VOHZB45S.js → chunk-Q6LFSAKV.js} +1321 -821
- package/dist/chunk-Q6LFSAKV.js.map +1 -0
- package/dist/{chunk-INHVXP6Z.js → chunk-RFIBF2RR.js} +1203 -430
- package/dist/chunk-RFIBF2RR.js.map +1 -0
- package/dist/{chunk-Q2WGKJNN.cjs → chunk-S5BKZZGM.cjs} +699 -123
- package/dist/chunk-S5BKZZGM.cjs.map +1 -0
- package/dist/chunk-SGLEQVJH.cjs +3329 -0
- package/dist/chunk-SGLEQVJH.cjs.map +1 -0
- package/dist/chunk-UGLFDG7L.cjs +1 -0
- package/dist/chunk-UGLFDG7L.cjs.map +1 -0
- package/dist/{chunk-YH3BIKHH.js → chunk-UMWZ4ZET.js} +146 -49
- package/dist/chunk-UMWZ4ZET.js.map +1 -0
- package/dist/{index-szBv3496.d.ts → coerce-DP0vYu-x.d.ts} +286 -199
- package/dist/{index-C_8o--VE.d.cts → coerce-DRERzdve.d.cts} +286 -199
- package/dist/core/index.cjs +9 -5
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +122 -108
- package/dist/core/index.d.ts +122 -108
- package/dist/core/index.js +32 -28
- package/dist/generate/index.cjs +8 -8
- package/dist/generate/index.d.cts +168 -84
- package/dist/generate/index.d.ts +168 -84
- package/dist/generate/index.js +7 -7
- package/dist/{index-CGpRv5sl.d.cts → index-9eoQs2C1.d.ts} +34 -19
- package/dist/{index-CCNJRG-P.d.cts → index-B9QLziDe.d.cts} +293 -56
- package/dist/{index-Dzr13q3d.d.cts → index-BBWNZS0f.d.cts} +135 -58
- package/dist/{index-9wcMhG73.d.ts → index-BHIUyjhZ.d.ts} +293 -56
- package/dist/{index-BGFW-8P2.d.cts → index-BJgP97N1.d.ts} +196 -114
- package/dist/{index-CunYKLiu.d.ts → index-BL5N2Oyz.d.cts} +1 -1
- package/dist/{index-Cj49F892.d.ts → index-BMweUlm5.d.cts} +63 -23
- package/dist/{index-CgHqxdps.d.ts → index-BNSM-DSk.d.cts} +196 -114
- package/dist/{index-D57QRbVn.d.ts → index-BRMbPkHE.d.ts} +480 -254
- package/dist/{index-Chbst3Jx.d.ts → index-CJBBiAmU.d.ts} +135 -58
- package/dist/{index-BkGmlyI3.d.cts → index-CL4b4gUQ.d.ts} +63 -23
- package/dist/{index-B9MNZboQ.d.ts → index-Cy15oTvh.d.cts} +52 -22
- package/dist/{index-B9MNZboQ.d.cts → index-Cy15oTvh.d.ts} +52 -22
- package/dist/{index-BO6xE9YU.d.cts → index-DGCNKAUr.d.cts} +480 -254
- package/dist/{index-B4o55NDr.d.cts → index-Dw2DP7vm.d.ts} +1 -1
- package/dist/{index-G1uwGGWQ.d.ts → index-cHvbYgJI.d.cts} +34 -19
- package/dist/index.cjs +42 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +82 -54
- package/dist/{masks-DYbE485J.d.cts → masks-Cc7-MzzY.d.ts} +49 -2
- package/dist/{masks-DYbE485J.d.ts → masks-pADfTOiD.d.cts} +49 -2
- package/dist/model/index.cjs +19 -12
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +504 -182
- package/dist/model/index.d.ts +504 -182
- package/dist/model/index.js +18 -11
- package/dist/{positional-Cptlj-xs.d.ts → positional-DJgs6ltD.d.ts} +85 -8
- package/dist/{positional-DvH_sd8u.d.cts → positional-DMZer-FM.d.cts} +85 -8
- package/dist/theory/index.cjs +35 -6
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +257 -62
- package/dist/theory/index.d.ts +257 -62
- package/dist/theory/index.js +41 -12
- package/package.json +7 -5
- package/dist/chunk-2LCPM3EG.js +0 -3224
- package/dist/chunk-2LCPM3EG.js.map +0 -1
- package/dist/chunk-6XH6QZYQ.cjs.map +0 -1
- package/dist/chunk-6XPTBE7Y.cjs +0 -49
- package/dist/chunk-6XPTBE7Y.cjs.map +0 -1
- package/dist/chunk-AFM2ULJH.cjs.map +0 -1
- package/dist/chunk-B6XNKWZV.cjs +0 -3224
- package/dist/chunk-B6XNKWZV.cjs.map +0 -1
- package/dist/chunk-E3F4AHAH.cjs.map +0 -1
- package/dist/chunk-ELCTZUJJ.js +0 -379
- package/dist/chunk-ELCTZUJJ.js.map +0 -1
- package/dist/chunk-FVSI36UV.js.map +0 -1
- package/dist/chunk-H3VORETI.js.map +0 -1
- package/dist/chunk-H42UHPYW.js +0 -1577
- package/dist/chunk-H42UHPYW.js.map +0 -1
- package/dist/chunk-HFPS7JFD.js +0 -1
- package/dist/chunk-INHVXP6Z.js.map +0 -1
- package/dist/chunk-K4ZJUGF4.cjs +0 -379
- package/dist/chunk-K4ZJUGF4.cjs.map +0 -1
- package/dist/chunk-KNJEKLKV.js +0 -49
- package/dist/chunk-KNJEKLKV.js.map +0 -1
- package/dist/chunk-MXO72PLY.cjs.map +0 -1
- package/dist/chunk-NLEU4QSE.cjs +0 -360
- package/dist/chunk-NLEU4QSE.cjs.map +0 -1
- package/dist/chunk-OE6WK2Y2.cjs +0 -1577
- package/dist/chunk-OE6WK2Y2.cjs.map +0 -1
- package/dist/chunk-PKFNUHDY.js.map +0 -1
- package/dist/chunk-Q2WGKJNN.cjs.map +0 -1
- package/dist/chunk-RHIJ3S4I.cjs +0 -1
- package/dist/chunk-RHIJ3S4I.cjs.map +0 -1
- package/dist/chunk-TTCLJX6D.js.map +0 -1
- package/dist/chunk-UADYAYAT.cjs.map +0 -1
- package/dist/chunk-VOHZB45S.js.map +0 -1
- package/dist/chunk-VTI6FOLB.js.map +0 -1
- package/dist/chunk-WWURE4XT.cjs.map +0 -1
- package/dist/chunk-YH3BIKHH.js.map +0 -1
- /package/dist/{chunk-HFPS7JFD.js.map → chunk-K6OZXIR6.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/theory/transposition/index.ts","../src/theory/chordscale/index.ts","../src/theory/figured-bass/index.ts","../src/theory/voicing/tendency.ts","../src/theory/voicing/internal.ts","../src/theory/voicing/satb.ts","../src/theory/voicing/leading.ts","../src/theory/voicing/styled.ts","../src/theory/partwriting/internal.ts","../src/theory/partwriting/species.ts","../src/theory/partwriting/index.ts"],"sourcesContent":["/**\n * Transposing instruments: the fixed interval between the pitch a player reads\n * and the pitch the instrument sounds.\n *\n * The distance is a spelled interval, never a semitone count. A clarinet in A\n * sounds a minor third below what it reads, so a written C sounds A, a written\n * D sounds B, and a written D# sounds B#: the letter always moves by the\n * interval's diatonic number, where a bare count of three semitones would take\n * the last of those to C natural and lose the letter the part is written on.\n *\n * The octave is part of that interval rather than folded away into a pitch\n * class, so instruments pitched in the same key stay apart: the alto saxophone\n * sounds a major sixth lower, the baritone saxophone a major thirteenth (the\n * same key an octave further down), and the E flat clarinet a minor third\n * higher. The pure octave transposers — piccolo, double bass, contrabassoon,\n * guitar — are a perfect octave, a unison-class interval displaced by one\n * octave.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport type { IntervalLike, Note, NoteLike, SpelledInterval } from '../../core/pitch/index.js';\nimport {\n parseInterval,\n toNoteData,\n toSpelledInterval,\n transposeByInterval,\n} from '../../core/pitch/index.js';\n\n/**\n * The interval from a written pitch to the pitch the instrument sounds, one\n * entry per built-in instrument.\n *\n * Each value is an interval name as {@link parseInterval} reads it, in the\n * written-to-sounding direction: a leading `'-'` marks an instrument that\n * sounds below what it reads, which is most of them. A transposition wider than\n * an octave is named by its compound interval rather than reduced, because the\n * octave is exactly what separates the tenor saxophone from the soprano and the\n * baritone from the alto.\n *\n * @example\n * ```ts\n * import { TRANSPOSING_INSTRUMENTS } from '@libraz/libcantus';\n * TRANSPOSING_INSTRUMENTS.clarinetA; // '-m3' — sounds a minor third lower\n * TRANSPOSING_INSTRUMENTS.piccolo; // 'P8' — sounds an octave higher\n * ```\n * @category Pitch & Intervals\n */\nexport const TRANSPOSING_INSTRUMENTS = Object.freeze({\n // In B flat: a written C sounds B flat. The lower members of the family read\n // in the same key an octave higher, so their interval is the compound one.\n clarinetBb: '-M2',\n trumpetBb: '-M2',\n sopranoSax: '-M2',\n tenorSax: '-M9',\n bassClarinet: '-M9',\n // In A: a written C sounds A.\n clarinetA: '-m3',\n // In F: a written C sounds F.\n hornF: '-P5',\n englishHorn: '-P5',\n // In E flat: one key, three registers. The sopranino clarinet sounds above\n // what it reads, the alto saxophone a major sixth below, and the baritone\n // saxophone an octave below that.\n clarinetEb: 'm3',\n altoSax: '-M6',\n baritoneSax: '-M13',\n // In D: a written C sounds D.\n trumpetD: 'M2',\n // Octave transposers: the instrument is in C, only the register moves.\n piccolo: 'P8',\n doubleBass: '-P8',\n contrabassoon: '-P8',\n guitar: '-P8',\n});\n\n/**\n * The name of a built-in transposing instrument, as\n * {@link TRANSPOSING_INSTRUMENTS} keys them.\n *\n * @example\n * ```ts\n * import type { TransposingInstrumentName } from '@libraz/libcantus';\n * const part: TransposingInstrumentName = 'clarinetA';\n * ```\n * @category Pitch & Intervals\n */\nexport type TransposingInstrumentName = keyof typeof TRANSPOSING_INSTRUMENTS;\n\n/**\n * A transposing instrument: one of the built-in names, or a spelled interval\n * for an instrument the table does not carry.\n *\n * An interval is read in the same written-to-sounding direction as the table,\n * so `'-M2'` is any instrument in B flat and `'P8'` any that sounds an octave\n * up. The names complete in an editor while any other string is still accepted,\n * which is what lets an instrument read from configuration go straight in.\n *\n * @example\n * ```ts\n * import type { TransposingInstrument } from '@libraz/libcantus';\n * const clarinet: TransposingInstrument = 'clarinetA';\n * const altoFlute: TransposingInstrument = '-P4';\n * ```\n * @category Pitch & Intervals\n */\nexport type TransposingInstrument =\n | TransposingInstrumentName\n | (string & {})\n | Exclude<IntervalLike, string>;\n\n/**\n * The interval a transposing instrument sounds at, measured from what it reads.\n *\n * This is the table's own direction: the answer descends for an instrument that\n * sounds below the printed part, which is most of them. Applying it to a\n * written pitch is {@link toSoundingPitch}, and applying it to a concert key is\n * how a written key is read back as the key it sounds in.\n *\n * @param instrument A built-in instrument name, or an interval naming a\n * transposition the table does not carry.\n * @returns The written-to-sounding interval.\n * @throws If the value is neither a known instrument nor a spelled interval.\n * @example\n * ```ts\n * import { instrumentTransposition } from '@libraz/libcantus';\n * instrumentTransposition('clarinetA');\n * // { number: 3, quality: 'm', semitones: -3, descending: true }\n * instrumentTransposition('piccolo'); // { number: 8, quality: 'P', semitones: 12 }\n * ```\n * @category Pitch & Intervals\n */\nexport function instrumentTransposition(instrument: TransposingInstrument): SpelledInterval {\n if (typeof instrument !== 'string') {\n return toSpelledInterval(instrument);\n }\n // Looked up through `hasOwn` so a name such as `'constructor'` cannot resolve\n // to something inherited from `Object.prototype`.\n if (Object.hasOwn(TRANSPOSING_INSTRUMENTS, instrument)) {\n return parseInterval(TRANSPOSING_INSTRUMENTS[instrument as TransposingInstrumentName]);\n }\n try {\n return parseInterval(instrument);\n } catch (error) {\n if (error instanceof InvalidInputError) {\n // A mistyped instrument name is the likely mistake, so the message names\n // that possibility rather than only the interval grammar it also failed.\n throw new InvalidInputError(\n `unknown transposing instrument ${JSON.stringify(instrument)}; ` +\n \"pass a name from TRANSPOSING_INSTRUMENTS or an interval such as '-M2'\",\n );\n }\n throw error;\n }\n}\n\n/**\n * The same interval taken the other way, which is what makes the two\n * conversions exact inverses.\n *\n * The `descending` flag is set rather than left to the sign, because a unison\n * spans zero semitones in both directions and the sign alone cannot say which\n * way a custom `'-P1'` was meant to go.\n */\nfunction reversedInterval(step: SpelledInterval): SpelledInterval {\n const reversed: SpelledInterval = {\n number: step.number,\n quality: step.quality,\n // Negating a zero span yields -0, which compares unequal to 0 under Object.is.\n semitones: step.semitones === 0 ? 0 : -step.semitones,\n };\n if (!(step.descending ?? step.semitones < 0)) {\n reversed.descending = true;\n }\n return reversed;\n}\n\n/**\n * The pitch an instrument sounds for a written note.\n *\n * The interval decides the letter, so the spelling of the part survives the\n * conversion: on a clarinet in A a written C sounds A, a written D sounds B,\n * and a written D# sounds B# — a semitone count alone could answer C natural\n * for that last one and lose the letter the part is written on. A note carrying\n * an octave moves register with it — a written C4 sounds A3 — while an\n * octave-less note stays octave-less, so a pure octave transposer leaves it\n * alone.\n *\n * @param note The written note, as the player reads it: a note name, a MIDI\n * number, note data, or a `Note`.\n * @param instrument A built-in instrument name, or an interval naming a\n * transposition the table does not carry.\n * @returns The sounding note, at concert pitch.\n * @throws If the note is malformed, or the instrument is neither a known name\n * nor a spelled interval.\n * @example\n * ```ts\n * import { formatNote, parseNote, toSoundingPitch } from '@libraz/libcantus';\n * formatNote(toSoundingPitch(parseNote('C4'), 'clarinetA')); // 'A3'\n * formatNote(toSoundingPitch('D#4', 'clarinetA')); // 'B#3'\n * formatNote(toSoundingPitch(parseNote('C4'), 'piccolo')); // 'C5'\n * ```\n * @category Pitch & Intervals\n */\nexport function toSoundingPitch(note: NoteLike, instrument: TransposingInstrument): Note {\n return transposeByInterval(toNoteData(note), instrumentTransposition(instrument));\n}\n\n/**\n * The note an instrument must read to sound a given concert pitch.\n *\n * The exact inverse of {@link toSoundingPitch} for every instrument: the same\n * interval applied the other way, so the letter and the octave both come back.\n * A concert A3 is written C4 for a clarinet in A, and a concert E flat 3 is\n * written C4 for an alto saxophone but C5 for a baritone saxophone, which reads\n * the same key an octave lower.\n *\n * @param note The sounding note, at concert pitch: a note name, a MIDI number,\n * note data, or a `Note`.\n * @param instrument A built-in instrument name, or an interval naming a\n * transposition the table does not carry.\n * @returns The written note, as the player reads it.\n * @throws If the note is malformed, or the instrument is neither a known name\n * nor a spelled interval.\n * @example\n * ```ts\n * import { formatNote, parseNote, toWrittenPitch } from '@libraz/libcantus';\n * formatNote(toWrittenPitch(parseNote('A3'), 'clarinetA')); // 'C4'\n * formatNote(toWrittenPitch('Eb3', 'altoSax')); // 'C4'\n * formatNote(toWrittenPitch(parseNote('Eb3'), 'baritoneSax')); // 'C5'\n * ```\n * @category Pitch & Intervals\n */\nexport function toWrittenPitch(note: NoteLike, instrument: TransposingInstrument): Note {\n return transposeByInterval(\n toNoteData(note),\n reversedInterval(instrumentTransposition(instrument)),\n );\n}\n","import { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\nimport { assertGenerationBudget, assertPositiveInt } from '../../core/validation/index.js';\nimport type { Chord } from '../chord/index.js';\nimport { chordPitchClasses } from '../chord/index.js';\nimport type { ScaleNameInput } from '../scale/index.js';\nimport { NAMED_SCALES, namedScaleMask, requireScaleMask } from '../scale/index.js';\nimport { type ChordLike, toChordData } from '../symbol/index.js';\n\n/** Count the set bits (scale tones) in a 12-bit mode mask. */\nfunction popcount12(mask: number): number {\n let count = 0;\n for (let n = 0; n < 12; n += 1) {\n count += (mask >> n) & 1;\n }\n return count;\n}\n\n/** Test whether a pitch class belongs to a mode mask rooted on `scaleRootPc`. */\nfunction maskHasPitchClass(mask: number, scaleRootPc: number, pc: number): boolean {\n const offset = pitchClass(pc - scaleRootPc);\n return ((mask >> offset) & 1) === 1;\n}\n\n/**\n * Test whether every chord pitch class is contained in a scale.\n *\n * @param chordPcs The chord's pitch classes (0..11).\n * @param scaleMask The scale's 12-bit mode mask.\n * @param scaleRootPc The pitch class the mask is rooted on.\n * @returns True if the scale is a superset of the chord.\n *\n * @category Scales\n */\nexport function scaleMatchesChord(\n chordPcs: number[],\n scaleMask: number,\n scaleRootPc: number,\n): boolean {\n for (const pc of chordPcs) {\n if (!maskHasPitchClass(scaleMask, scaleRootPc, pc)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * A named scale rooted on a pitch class that fits over a chord.\n *\n * @category Scales\n */\nexport type ChordScaleMatch = {\n name: string;\n rootPc: number;\n};\n\n/**\n * Scale names whose mask duplicates another {@link NAMED_SCALES} entry\n * (major/ionian, naturalMinor/aeolian). Chord-scale analysis conventionally\n * speaks in mode names, so these aliases are skipped and only the modal name\n * is reported.\n */\nconst ALIASED_SCALE_NAMES = new Set(['major', 'naturalMinor']);\n\n/** Number of tones in a heptatonic (seven-note) scale. */\nconst HEPTATONIC_SIZE = 7;\n\n/**\n * Conventional preference among equally-fitting scales, brightest first.\n *\n * Several modes fit a chord that states no third or sixth — a power chord, a\n * suspension — equally well. Alphabetical order made `aeolian` the answer for\n * those, naming a minor mode as the best fit for a mode-neutral chord.\n */\nconst SCALE_PREFERENCE = [\n 'ionian',\n 'major',\n 'mixolydian',\n 'dorian',\n 'lydian',\n 'aeolian',\n 'naturalMinor',\n 'phrygian',\n 'locrian',\n] as const;\n\n/** Conventional first choices that pure set-fit ranking cannot express. */\nconst IDIOMATIC_SCALES: Partial<Record<Chord['quality'], readonly string[]>> = {\n aug: ['wholeTone'],\n m7b5: ['locrian'],\n // The diminished scale played over a diminished seventh is the whole-half\n // octatonic. Its half-whole rotation belongs to the dominant it colours: over\n // a diminished seventh every one of its non-chord tones lands a semitone\n // above a chord tone, so it offers no tension at all.\n dim7: ['octatonicWholeHalf'],\n minMaj7: ['melodicMinor'],\n};\n\n/** Position of a scale in {@link SCALE_PREFERENCE}, or last when unlisted. */\nfunction conventionalRank(name: string): number {\n const index = (SCALE_PREFERENCE as readonly string[]).indexOf(name);\n return index < 0 ? SCALE_PREFERENCE.length : index;\n}\n\n/** Whether this scale is an idiomatic color choice for the chord quality. */\nfunction idiomaticRank(chord: Chord, name: string): number {\n const choices = IDIOMATIC_SCALES[chord.quality];\n if (choices === undefined) {\n return 0;\n }\n const index = choices.indexOf(name);\n return index < 0 ? choices.length + 1 : index;\n}\n\n/**\n * An ordinary dominant seventh may use altered colors while retaining its\n * perfect fifth in the voicing; the `7alt` quality makes that alteration\n * explicit, but lead sheets commonly write the shorter `7` here.\n */\nfunction isAlteredDominant(chord: Chord, scaleName: string): boolean {\n return chord.quality === 'dom7' && scaleName === 'altered';\n}\n\n/**\n * List the scales that fit over a chord, best fit first.\n *\n * Only the chord root is considered as the scale root, matching the\n * conventional chord-scale relationship. Every entry of {@link NAMED_SCALES}\n * whose pitch-class set is a superset of the chord's is returned once per\n * distinct pitch-class set (aliased masks such as major/ionian report only the\n * modal name), ranked by fewest extra scale tones beyond the chord and then by\n * conventional\n * preference. For bare triads and smaller chords, heptatonic scales rank before\n * pentatonics and other sizes: a pentatonic adds no modal color over a triad,\n * so the seven-note modes are the more useful answer. The chromatic scale is\n * only returned as a fallback when no other scale contains the chord.\n *\n * The ranking is by fit, so the first entry is the tightest-fitting scale\n * rather than the idiomatic choice: a four-note chord that a pentatonic covers\n * exactly puts that pentatonic ahead of the mode a player would name. Read the\n * whole list, or pick by name, when the idiomatic scale is what is wanted;\n * {@link scalesForChanges} makes that choice for a progression.\n *\n * @param chord The chord to fit scales over, as a chord symbol, chord data, or\n * a `Chord`.\n * @returns The matching scales rooted on the chord root, best fit first.\n *\n * @example\n * ```ts\n * import { makeChord, chordScales } from '@libraz/libcantus';\n * const scales = chordScales(makeChord(0, 'maj7'));\n * // scales for Cmaj7, best fit first; each is { name, rootPc: 0 }\n * ```\n *\n * @category Scales\n */\nexport function chordScales(chord: ChordLike): ChordScaleMatch[] {\n const data = toChordData(chord);\n const chordPcs = chordPitchClasses(data);\n const rootPc = pitchClass(data.rootPc);\n const ranked: { name: string; extra: number; size: number; avoid: number }[] = [];\n const seenMasks = new Set<number>();\n for (const name of Object.keys(NAMED_SCALES)) {\n if (name === 'chromatic' || ALIASED_SCALE_NAMES.has(name)) {\n continue;\n }\n const mask = namedScaleMask(name);\n if (mask === undefined || seenMasks.has(mask)) {\n continue;\n }\n seenMasks.add(mask);\n if (scaleMatchesChord(chordPcs, mask, rootPc) || isAlteredDominant(data, name)) {\n const size = popcount12(mask);\n ranked.push({\n name,\n extra: size - chordPcs.length,\n size,\n avoid: avoidNotes(data, name).length,\n });\n }\n }\n if (ranked.length === 0) {\n // No diatonic-style scale contains the chord; fall back to the chromatic\n // scale, which trivially contains every pitch class.\n if (NAMED_SCALES.chromatic !== undefined) {\n return [{ name: 'chromatic', rootPc }];\n }\n return [];\n }\n const preferHeptatonic = chordPcs.length <= 3;\n ranked.sort((a, b) => {\n const idiomaticA = idiomaticRank(data, a.name);\n const idiomaticB = idiomaticRank(data, b.name);\n if (idiomaticA !== idiomaticB) {\n return idiomaticA - idiomaticB;\n }\n if (preferHeptatonic && (a.size === HEPTATONIC_SIZE) !== (b.size === HEPTATONIC_SIZE)) {\n return a.size === HEPTATONIC_SIZE ? -1 : 1;\n }\n if (a.extra !== b.extra) {\n return a.extra - b.extra;\n }\n const rankA = conventionalRank(a.name);\n const rankB = conventionalRank(b.name);\n if (rankA !== rankB) {\n return rankA - rankB;\n }\n // Among scales the modal preference does not name — the symmetric and\n // melodic-minor scales — the one that clashes with the chord least is the\n // one a player reaches for. Alphabetical order answered with the rotation\n // that leaves nothing playable.\n if (a.avoid !== b.avoid) {\n return a.avoid - b.avoid;\n }\n return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;\n });\n return ranked.map((entry) => ({ name: entry.name, rootPc }));\n}\n\n/**\n * The tone standing in the third's place when a chord suspends its third.\n *\n * Read from the tones the chord sounds rather than from its quality name: one\n * suspension is written `sus4`, `7sus4`, `9sus4`, `11` and `sus4(add9)`, and\n * the eleventh chord states it by omitting the third rather than by naming a\n * suspension, so a set of names can only ever cover part of it. A chord with no\n * third that sounds a fourth suspends into that fourth; one that sounds a\n * second suspends into the second.\n *\n * @param chordPcs The chord's pitch classes.\n * @param rootPc The chord root's pitch class.\n * @returns The suspended tone's pitch class, or undefined when the chord states\n * a third of its own.\n */\nfunction suspendedTone(chordPcs: number[], rootPc: number): number | undefined {\n const sounds = (semitones: number): boolean => chordPcs.includes(pitchClass(rootPc + semitones));\n if (sounds(3) || sounds(4)) {\n return undefined;\n }\n if (sounds(5)) {\n return pitchClass(rootPc + 5);\n }\n if (sounds(2)) {\n return pitchClass(rootPc + 2);\n }\n return undefined;\n}\n\n/**\n * Which use an avoid note is judged for: sounding it, or passing through it.\n *\n * `'harmonic'` is the Berklee-style rule in full — a tone that must not be\n * sounded against the chord. `'melodic'` keeps only what a line cannot pass\n * through either, which is the semitone above the root; every other clash\n * resolves as the line moves on.\n *\n * @category Scales\n */\nexport type AvoidNoteUse = 'harmonic' | 'melodic';\n\n/**\n * Options for {@link avoidNotes}.\n *\n * @category Scales\n */\nexport type AvoidNotesOptions = {\n use?: AvoidNoteUse;\n};\n\n/**\n * List a scale's avoid notes over a chord.\n *\n * An avoid note is a non-chord scale tone that lies a semitone directly above a\n * chord tone, or the third a suspension displaced; sounding it against the\n * chord clashes. The scale is rooted on the chord root. If the scale does not\n * contain the chord, no avoid notes exist.\n *\n * The rule states which tones must not be *sounded* against the chord, which is\n * not the same question as which tones a line may not touch. Pass\n * `{ use: 'melodic' }` for the melodic reading: only the semitone above the\n * root survives it, so the result is always a subset of the harmonic one.\n *\n * @param chord The chord providing the chord tones, as a chord symbol, chord\n * data, or a `Chord`.\n * @param scaleName A key of {@link NAMED_SCALES}.\n * @param opts Set `use: 'melodic'` to judge a line rather than a voicing.\n * @returns The avoid-note pitch classes, sorted ascending in [0, 11].\n * @throws If `scaleName` is not a built-in scale. An empty result already\n * means \"this scale has no avoid notes over this chord\"; answering a typo\n * the same way would make the two indistinguishable.\n *\n * @example\n * ```ts\n * import { makeChord, avoidNotes } from '@libraz/libcantus';\n * avoidNotes(makeChord(0, 'maj7'), 'ionian'); // [5] — F clashes with the third\n * avoidNotes(makeChord(0, 'maj7'), 'ionian', { use: 'melodic' }); // [] — a line may pass through it\n * ```\n *\n * @category Scales\n */\nexport function avoidNotes(\n chord: ChordLike,\n scaleName: ScaleNameInput,\n opts: AvoidNotesOptions = {},\n): number[] {\n const mask = requireScaleMask(scaleName);\n const data = toChordData(chord);\n const rootPc = pitchClass(data.rootPc);\n const chordPcs = chordPitchClasses(data);\n const alteredDominant = isAlteredDominant(data, scaleName);\n if (!scaleMatchesChord(chordPcs, mask, rootPc) && !alteredDominant) {\n return [];\n }\n const chordSet = new Set(chordPcs);\n const suspended = suspendedTone(chordPcs, rootPc);\n // The tone the suspension displaced sits a semitone below it, and sounding it\n // is what undoes the suspension.\n const displacedThird = suspended === undefined ? undefined : pitchClass(suspended - 1);\n const melodic = opts.use === 'melodic';\n const semitoneAboveRoot = pitchClass(rootPc + 1);\n const avoid: number[] = [];\n for (let pc = 0; pc < 12; pc += 1) {\n if (!maskHasPitchClass(mask, rootPc, pc) || chordSet.has(pc)) {\n continue;\n }\n if (melodic && pc !== semitoneAboveRoot) {\n continue;\n }\n if (!alteredDominant && (chordSet.has(pitchClass(pc - 1)) || pc === displacedThird)) {\n avoid.push(pc);\n }\n }\n return avoid.sort((a, b) => a - b);\n}\n\n/**\n * Semitones above the root of the colors a dominant takes when it resolves to a\n * minor tonic: the flat ninth, the sharp ninth, and the flat thirteenth.\n *\n * Over a dominant read on its own, each of them sits a semitone above a chord\n * tone and is an avoid note. Heard as the dominant of a minor key they are the\n * key's own tones, and standard practice, so the function the chord serves is\n * what decides.\n */\nconst MINOR_RESOLUTION_TENSIONS = [1, 3, 8] as const;\n\n/** Whether this chord is a dominant seventh resolving down a fifth to minor. */\nfunction resolvesToMinorTonic(\n chord: Chord,\n chordPcs: number[],\n target: Chord | undefined,\n): boolean {\n if (target === undefined) {\n return false;\n }\n const rootPc = pitchClass(chord.rootPc);\n const sounds = (semitones: number): boolean => chordPcs.includes(pitchClass(rootPc + semitones));\n if (!sounds(4) || !sounds(10)) {\n return false;\n }\n const targetRootPc = pitchClass(target.rootPc);\n if (targetRootPc !== pitchClass(rootPc + 5)) {\n return false;\n }\n return chordPitchClasses(target).includes(pitchClass(targetRootPc + 3));\n}\n\n/**\n * Options for {@link availableTensions}.\n *\n * @category Scales\n */\nexport type AvailableTensionsOptions = {\n /**\n * The chord this one resolves to, as a chord symbol, chord data, or a\n * `Chord`.\n */\n resolvesTo?: ChordLike;\n};\n\n/**\n * List a scale's available tensions over a chord.\n *\n * Available tensions are scale tones that are neither chord tones nor avoid\n * notes, i.e. the usable color tones (typically the 9/11/13 region). The scale\n * is rooted on the chord root. If the scale does not contain the chord, there\n * are no available tensions.\n *\n * A tension's availability also depends on what the chord is doing. Pass\n * `resolvesTo` to say which chord this one resolves to: a dominant seventh\n * resolving down a fifth to a minor tonic takes its flat ninth, sharp ninth and\n * flat thirteenth, which read on their own would each be an avoid note. Only\n * scale tones are ever added, so the result stays within the scale.\n *\n * @param chord The chord providing the chord tones, as a chord symbol, chord\n * data, or a `Chord`.\n * @param scaleName A key of {@link NAMED_SCALES}.\n * @param opts Set `resolvesTo` to the chord this one resolves to.\n * @returns The available-tension pitch classes, sorted ascending in [0, 11].\n * @throws If `scaleName` is not a built-in scale, as {@link avoidNotes} does.\n *\n * @example\n * ```ts\n * import { makeChord, availableTensions } from '@libraz/libcantus';\n * availableTensions(makeChord(0, 'maj7'), 'ionian'); // [2, 9] — color tones over Cmaj7\n * availableTensions(makeChord(7, 'dom7'), 'phrygianDominant', { resolvesTo: makeChord(0, 'min') });\n * // [3, 8] — the b13 and b9 the resolution to C minor makes available\n * ```\n *\n * @category Scales\n */\nexport function availableTensions(\n chord: ChordLike,\n scaleName: ScaleNameInput,\n opts: AvailableTensionsOptions = {},\n): number[] {\n const mask = requireScaleMask(scaleName);\n const data = toChordData(chord);\n const rootPc = pitchClass(data.rootPc);\n const chordPcs = chordPitchClasses(data);\n const alteredDominant = isAlteredDominant(data, scaleName);\n if (!scaleMatchesChord(chordPcs, mask, rootPc) && !alteredDominant) {\n return [];\n }\n const chordSet = new Set(chordPcs);\n const avoidSet = alteredDominant ? new Set<number>() : new Set(avoidNotes(data, scaleName));\n const functional = resolvesToMinorTonic(\n data,\n chordPcs,\n opts.resolvesTo === undefined ? undefined : toChordData(opts.resolvesTo),\n )\n ? new Set(MINOR_RESOLUTION_TENSIONS.map((semitones) => pitchClass(rootPc + semitones)))\n : undefined;\n const tensions: number[] = [];\n for (let pc = 0; pc < 12; pc += 1) {\n if (!maskHasPitchClass(mask, rootPc, pc) || chordSet.has(pc)) {\n continue;\n }\n if (avoidSet.has(pc) && functional?.has(pc) !== true) {\n continue;\n }\n tensions.push(pc);\n }\n return tensions.sort((a, b) => a - b);\n}\n\n/**\n * A scale fit over a chord, with its non-chord tones sorted by what may be done\n * with them.\n *\n * `avoid`, `passing` and `tensions` partition the scale tones the chord does\n * not state: `avoid` may not be played at all, `passing` may be passed through\n * melodically but not sounded against the chord, and `tensions` may be added\n * freely as color. `avoid` is {@link avoidNotes} under `use: 'melodic'`, and\n * `avoid` together with `passing` is the harmonic reading.\n *\n * @category Scales\n */\nexport type ChordScaleReportEntry = {\n name: string;\n rootPc: number;\n avoid: number[];\n passing: number[];\n tensions: number[];\n};\n\n/**\n * Report the best-fitting scales for a chord with their avoid notes and tensions.\n *\n * Combines {@link chordScales}, {@link avoidNotes}, and {@link availableTensions}\n * into a single ergonomic result, ordered best fit first. The report is read as\n * playing advice, so the tones a line may pass through are reported apart from\n * the ones it may not touch; see {@link ChordScaleReportEntry}.\n *\n * @param chord The chord to analyze, as a chord symbol, chord data, or a\n * `Chord`.\n * @param limit Optional maximum number of scales to report; all by default.\n * @returns One entry per reported scale, best fit first.\n *\n * @category Scales\n */\nexport function chordScaleReport(chord: ChordLike, limit?: number): ChordScaleReportEntry[] {\n if (limit !== undefined) {\n assertPositiveInt(limit, 'chord-scale report limit');\n }\n const data = toChordData(chord);\n const matches = chordScales(data);\n const chosen = limit === undefined ? matches : matches.slice(0, limit);\n return chosen.map((match) => {\n const harmonic = avoidNotes(data, match.name);\n const melodic = new Set(avoidNotes(data, match.name, { use: 'melodic' }));\n return {\n name: match.name,\n rootPc: match.rootPc,\n avoid: harmonic.filter((pc) => melodic.has(pc)),\n passing: harmonic.filter((pc) => !melodic.has(pc)),\n tensions: availableTensions(data, match.name),\n };\n });\n}\n\n/**\n * A chord paired with the scale chosen for it by {@link scalesForChanges}.\n *\n * @category Scales\n */\nexport type ScaleChoice = {\n chord: Chord;\n scale: ChordScaleMatch;\n};\n\n/**\n * Small per-candidate penalty added in {@link scalesForChanges} so that, among\n * choices of otherwise-equal transition cost, the tighter best-fit scale wins.\n */\nconst RANK_PENALTY = 0.01;\n\n/** Build the pitch-class set of a named scale rooted on `rootPc`. */\nfunction scalePitchClassSet(name: string, rootPc: number): Set<number> {\n const mask = namedScaleMask(name);\n const pcs = new Set<number>();\n if (mask === undefined) {\n return pcs;\n }\n for (let n = 0; n < 12; n += 1) {\n if (((mask >> n) & 1) === 1) {\n pcs.add(pitchClass(rootPc + n));\n }\n }\n return pcs;\n}\n\n/** Count pitch classes that belong to exactly one of two sets. */\nfunction symmetricDifferenceSize(a: Set<number>, b: Set<number>): number {\n let count = 0;\n for (const pc of a) {\n if (!b.has(pc)) {\n count += 1;\n }\n }\n for (const pc of b) {\n if (!a.has(pc)) {\n count += 1;\n }\n }\n return count;\n}\n\n/**\n * Choose one scale per chord across a progression, favoring continuity.\n *\n * Each chord's {@link chordScales} candidates form a stage in a Viterbi-style\n * dynamic program. The transition cost between adjacent choices is the number\n * of pitch classes that differ between their pitch-class sets (the symmetric\n * difference), plus a small penalty for straying from a chord's best-fit scale\n * so that ties break toward the tighter fit. The minimum-total-cost path is\n * returned, one {@link ScaleChoice} per input chord in the original order.\n *\n * Each choice pairs its scale with the chord exactly as it was handed in, so\n * this takes plain chord data rather than the wider forms the entry points\n * above accept.\n *\n * @param chords The chord sequence to choose scales for.\n * @returns One scale choice per chord, in input order.\n *\n * @category Scales\n */\nexport function scalesForChanges(chords: readonly Chord[]): ScaleChoice[] {\n assertGenerationBudget(chords.length, 'chord-scale changes');\n if (chords.length === 0) {\n return [];\n }\n const candidateLists = chords.map((chord) => chordScales(chord));\n const pcSets = candidateLists.map((candidates) =>\n candidates.map((match) => scalePitchClassSet(match.name, match.rootPc)),\n );\n\n const first = candidateLists[0] ?? [];\n const dp: number[][] = [first.map((_, j) => j * RANK_PENALTY)];\n const back: number[][] = [first.map(() => -1)];\n\n for (let i = 1; i < candidateLists.length; i += 1) {\n const candidates = candidateLists[i] ?? [];\n const prevCosts = dp[i - 1] ?? [];\n const prevSets = pcSets[i - 1] ?? [];\n const curSets = pcSets[i] ?? [];\n const stageCosts: number[] = [];\n const stageBack: number[] = [];\n for (let j = 0; j < candidates.length; j += 1) {\n let bestCost = Number.POSITIVE_INFINITY;\n let bestPrev = -1;\n for (let k = 0; k < prevCosts.length; k += 1) {\n const transition = symmetricDifferenceSize(\n prevSets[k] ?? new Set(),\n curSets[j] ?? new Set(),\n );\n const cost = (prevCosts[k] ?? 0) + transition;\n if (cost < bestCost) {\n bestCost = cost;\n bestPrev = k;\n }\n }\n stageCosts.push(bestCost + j * RANK_PENALTY);\n stageBack.push(bestPrev);\n }\n dp.push(stageCosts);\n back.push(stageBack);\n }\n\n const lastCosts = dp[dp.length - 1] ?? [];\n let bestFinal = 0;\n for (let j = 1; j < lastCosts.length; j += 1) {\n if ((lastCosts[j] ?? Number.POSITIVE_INFINITY) < (lastCosts[bestFinal] ?? 0)) {\n bestFinal = j;\n }\n }\n\n const chosenIndices: number[] = new Array(candidateLists.length);\n let current = bestFinal;\n for (let i = candidateLists.length - 1; i >= 0; i -= 1) {\n chosenIndices[i] = current;\n current = back[i]?.[current] ?? -1;\n }\n\n return chords.map((chord, i) => {\n const candidates = candidateLists[i] ?? [];\n const scale = candidates[chosenIndices[i] ?? 0] ?? { name: 'chromatic', rootPc: chord.rootPc };\n return { chord, scale };\n });\n}\n","/**\n * Figured bass: read a bass note and its figures as the chord they name.\n *\n * The figures are intervals above the bass, and every interval a figure does\n * not alter is the one the key's own scale gives. That is the whole rule of the\n * notation, and the reason a realization needs the key: the same `6` names a\n * major triad over one degree of C major and a diminished one over another.\n *\n * The bass arrives spelled, so the intervals above it are spelled too. The\n * third above a G in C minor is the Bb the signature gives, and the bare `#`\n * that raises it names B natural rather than an enharmonic Cb — which is what\n * makes the figures of a real exercise readable as written.\n */\n\nimport { InvalidInputError, NoSolutionError } from '../../core/errors/index.js';\nimport type { Note, NoteLike } from '../../core/pitch/index.js';\nimport {\n diatonicLetterOf as mod7,\n pitchClassOf as mod12,\n noteToPitchClass,\n toNoteData,\n} from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord, ChordQuality } from '../chord/index.js';\nimport { chordQualities, makeChord } from '../chord/index.js';\nimport { type KeyLike, scaleTonesInDegreeOrder, spelledKeyOf, toKeyScale } from '../scale/index.js';\nimport { noteNames, spellChord, spellScale } from '../spelling/index.js';\nimport { type ChordLike, toChordData } from '../symbol/index.js';\n\n/** Smallest interval a figure may name above the bass: a second. */\nconst MIN_FIGURE_NUMBER = 2;\n\n/** Largest interval a figure may name above the bass: a ninth. */\nconst MAX_FIGURE_NUMBER = 9;\n\n/** The octave figure, which names the bass itself and so adds no chord tone. */\nconst OCTAVE_FIGURE = 8;\n\n/** Number of tones in the largest stack a figure can name: a seventh chord. */\nconst MAX_STACK_SIZE = 4;\n\n/** How an accidental on a figure alters the interval the key would give. */\ntype FigureAccidental = 'none' | 'sharp' | 'doubleSharp' | 'flat' | 'doubleFlat' | 'natural';\n\n/** One written figure: an interval above the bass and the accidental on it. */\ntype Figure = { number: number; accidental: FigureAccidental };\n\n/** A figure that moves to another over the same bass, such as `4-3`. */\ntype FigureMotion = { from: Figure; to: Figure };\n\n/** The figures a written string names: the static ones and the moving ones. */\ntype ParsedFigures = { figures: Figure[]; motions: FigureMotion[] };\n\n/** Two-character accidental prefixes, matched before the single-character ones. */\nconst DOUBLE_ACCIDENTALS: Record<string, FigureAccidental> = {\n '##': 'doubleSharp',\n '♯♯': 'doubleSharp',\n bb: 'doubleFlat',\n '♭♭': 'doubleFlat',\n};\n\n/**\n * Single-character accidental prefixes. `+` is the typed form of the slashed or\n * crossed figure, which raises its interval exactly as `#` does.\n */\nconst SINGLE_ACCIDENTALS: Record<string, FigureAccidental> = {\n '#': 'sharp',\n '♯': 'sharp',\n '+': 'sharp',\n b: 'flat',\n '♭': 'flat',\n n: 'natural',\n '♮': 'natural',\n};\n\n/** Characters that merely separate stacked figures, as the slash in `6/4` does. */\nconst FIGURE_SEPARATORS = new Set([' ', '\\t', ',', '/']);\n\n/** Characters that link a figure to the figure it moves to, as in `4-3`. */\nconst MOTION_MARKS = new Set(['-', '–']);\n\n/** Glyph for each alteration a figure can report against the key, in semitones. */\nconst ACCIDENTAL_GLYPHS: Record<number, string> = {\n 1: '#',\n 2: '##',\n '-1': 'b',\n '-2': 'bb',\n};\n\n/** An error naming the figure string that was rejected. */\nfunction invalidFigures(figures: string, detail: string): InvalidInputError {\n return new InvalidInputError(`figured bass ${JSON.stringify(figures)} ${detail}`);\n}\n\n/** The alteration an accidental produces from the one the key gives. */\nfunction alteredBy(diatonicAlter: number, accidental: FigureAccidental): number {\n switch (accidental) {\n case 'sharp':\n return diatonicAlter + 1;\n case 'doubleSharp':\n return diatonicAlter + 2;\n case 'flat':\n return diatonicAlter - 1;\n case 'doubleFlat':\n return diatonicAlter - 2;\n // A natural sign names the natural note, whatever the key would have given.\n case 'natural':\n return 0;\n default:\n return diatonicAlter;\n }\n}\n\n/**\n * Read one figure — an optional accidental and an optional digit — starting at\n * `start`, and report where the figure ends.\n *\n * An accidental with no digit alters the third above the bass, which is what a\n * lone `#` under a bass note means.\n */\nfunction readFigure(text: string, start: number): { figure: Figure; index: number } {\n let index = start;\n let accidental: FigureAccidental = 'none';\n const pair = DOUBLE_ACCIDENTALS[text.slice(index, index + 2)];\n const single = SINGLE_ACCIDENTALS[text[index] ?? ''];\n if (pair !== undefined) {\n accidental = pair;\n index += 2;\n } else if (single !== undefined) {\n accidental = single;\n index += 1;\n }\n const digit = text[index] ?? '';\n if (digit >= '0' && digit <= '9') {\n const number = Number(digit);\n if (number < MIN_FIGURE_NUMBER || number > MAX_FIGURE_NUMBER) {\n throw invalidFigures(\n text,\n `names the interval ${number}, which is outside ${MIN_FIGURE_NUMBER}..${MAX_FIGURE_NUMBER}`,\n );\n }\n return { figure: { number, accidental }, index: index + 1 };\n }\n if (accidental === 'none') {\n // An empty slice means the string ended where a figure was expected, as in\n // a trailing `4-`; naming the position is more use than naming nothing.\n const found = text.slice(start, start + 1);\n throw invalidFigures(\n text,\n found === ''\n ? `ends where a figure was expected, at position ${start}`\n : `has an unexpected character ${JSON.stringify(found)}`,\n );\n }\n return { figure: { number: 3, accidental }, index };\n}\n\n/** Split a figure string into its static figures and its moving ones. */\nfunction parseFigures(text: string): ParsedFigures {\n const figures: Figure[] = [];\n const motions: FigureMotion[] = [];\n let index = 0;\n while (index < text.length) {\n if (FIGURE_SEPARATORS.has(text[index] ?? '')) {\n index += 1;\n continue;\n }\n const first = readFigure(text, index);\n index = first.index;\n if (!MOTION_MARKS.has(text[index] ?? '')) {\n figures.push(first.figure);\n continue;\n }\n const second = readFigure(text, index + 1);\n index = second.index;\n if (MOTION_MARKS.has(text[index] ?? '')) {\n throw invalidFigures(text, 'chains more than one motion onto a single figure');\n }\n if (first.figure.number === second.figure.number) {\n throw invalidFigures(text, `moves the interval ${first.figure.number} onto itself`);\n }\n motions.push({ from: first.figure, to: second.figure });\n }\n return { figures, motions };\n}\n\n/** What a figure set sounds, and where the chord root sits above the bass. */\ntype FiguredSonority = { intervals: readonly number[]; rootInterval: number };\n\n/** The root-position triad, which every unfigured bass note carries. */\nconst TRIAD: FiguredSonority = { intervals: [3, 5], rootInterval: 1 };\n\n/** The first-inversion triad: the bass is the third of the chord. */\nconst TRIAD_FIRST: FiguredSonority = { intervals: [3, 6], rootInterval: 6 };\n\n/** The second-inversion triad: the bass is the fifth of the chord. */\nconst TRIAD_SECOND: FiguredSonority = { intervals: [4, 6], rootInterval: 4 };\n\n/** The root-position seventh chord. */\nconst SEVENTH: FiguredSonority = { intervals: [3, 5, 7], rootInterval: 1 };\n\n/** The first-inversion seventh chord, written `6/5`. */\nconst SEVENTH_FIRST: FiguredSonority = { intervals: [3, 5, 6], rootInterval: 6 };\n\n/** The second-inversion seventh chord, written `4/3`. */\nconst SEVENTH_SECOND: FiguredSonority = { intervals: [3, 4, 6], rootInterval: 4 };\n\n/** The third-inversion seventh chord, written `4/2` or `2`. */\nconst SEVENTH_THIRD: FiguredSonority = { intervals: [2, 4, 6], rootInterval: 2 };\n\n/**\n * Every figure set the grammar recognizes, keyed by the intervals actually\n * written in ascending order. Both the abbreviation a musician writes and the\n * full stack it stands for are listed, so `6` and `63` name one sonority and\n * `2`, `42` and `642` another.\n */\nconst FIGURE_SETS: ReadonlyMap<string, FiguredSonority> = new Map([\n ['', TRIAD],\n ['3', TRIAD],\n ['5', TRIAD],\n ['3,5', TRIAD],\n ['6', TRIAD_FIRST],\n ['3,6', TRIAD_FIRST],\n ['4,6', TRIAD_SECOND],\n ['7', SEVENTH],\n ['3,7', SEVENTH],\n ['5,7', SEVENTH],\n ['3,5,7', SEVENTH],\n ['5,6', SEVENTH_FIRST],\n ['3,5,6', SEVENTH_FIRST],\n ['3,4', SEVENTH_SECOND],\n ['3,4,6', SEVENTH_SECOND],\n ['2', SEVENTH_THIRD],\n ['2,4', SEVENTH_THIRD],\n ['2,4,6', SEVENTH_THIRD],\n]);\n\n/**\n * The digits a realized sonority is conventionally written with, keyed by its\n * full interval stack. The inverse of the abbreviations in {@link FIGURE_SETS},\n * and the reason {@link figuredBassOf} emits `6` rather than `63`.\n */\nconst FIGURE_ABBREVIATIONS: ReadonlyMap<string, readonly number[]> = new Map([\n [TRIAD.intervals.join(','), []],\n [TRIAD_FIRST.intervals.join(','), [6]],\n [TRIAD_SECOND.intervals.join(','), [6, 4]],\n [SEVENTH.intervals.join(','), [7]],\n [SEVENTH_FIRST.intervals.join(','), [6, 5]],\n [SEVENTH_SECOND.intervals.join(','), [4, 3]],\n [SEVENTH_THIRD.intervals.join(','), [4, 2]],\n]);\n\n/**\n * Index the chord vocabulary by interval template, for the triads and seventh\n * chords a figure can stack. Reading the templates back from the chord builder\n * keeps the two in step: a quality added to the vocabulary becomes reachable\n * from a figure without a second table to maintain.\n */\nfunction tertianQualityIndex(): ReadonlyMap<string, ChordQuality> {\n const index = new Map<string, ChordQuality>();\n for (const quality of chordQualities()) {\n const { intervals } = makeChord(0, quality);\n const template = intervals.join(',');\n // Declaration order decides a tie, exactly as it does for chord detection.\n if (intervals.length >= 3 && intervals.length <= MAX_STACK_SIZE && !index.has(template)) {\n index.set(template, quality);\n }\n }\n return index;\n}\n\nconst TERTIAN_QUALITIES = tertianQualityIndex();\n\n/**\n * The alteration each diatonic letter carries in a key, indexed by letter.\n *\n * This one lookup is what makes an unfigured interval diatonic: the letter of\n * an interval above the bass comes from counting letters, and its accidental\n * comes from the key's own spelling of that letter, so a flat-side key hands\n * back its flats and a harmonic minor its raised leading tone.\n */\nfunction keyLetterAlters(key: KeyScale): number[] {\n const size = scaleTonesInDegreeOrder(key).length;\n if (size !== 7) {\n throw new InvalidInputError(`figured bass requires a heptatonic key (received ${size} tones)`);\n }\n const alters: number[] = [];\n for (const note of spellScale(spelledKeyOf(key).tonic, key)) {\n alters[mod7(note.letter)] = note.alter;\n }\n return alters;\n}\n\n/** The note a figure names: its letter from the bass, its accidental from the key. */\nfunction noteAbove(bass: Note, figure: Figure, alters: readonly number[]): Note {\n const letter = mod7(bass.letter + figure.number - 1);\n return { letter, alter: alteredBy(alters[letter] ?? 0, figure.accidental) };\n}\n\n/** A bass note reduced to the letter and accidental the figures are read from. */\nfunction bareNote(note: Note): Note {\n return { letter: mod7(note.letter), alter: note.alter };\n}\n\n/**\n * Build the chord a resolved figure set names over a bass.\n *\n * The figure set fixes which tone is the root, so the stack is read from that\n * root upward in diatonic thirds and matched against the chord vocabulary. A\n * stack no quality names — the augmented sixths, above all — is reported as\n * having no solution rather than being rounded to a chord it is not.\n */\nfunction realizeSonority(\n bass: Note,\n resolved: Figure[],\n text: string,\n alters: readonly number[],\n): { chord: Chord; notes: Note[] } {\n const numbers = [...new Set(resolved.map((figure) => figure.number))].sort((a, b) => a - b);\n const sonority = FIGURE_SETS.get(numbers.join(','));\n if (sonority === undefined) {\n throw invalidFigures(text, 'names no chord over the bass');\n }\n const written = new Map(resolved.map((figure) => [figure.number, figure.accidental]));\n const notes = sonority.intervals.map((number) =>\n noteAbove(bass, { number, accidental: written.get(number) ?? 'none' }, alters),\n );\n const tones = [bass, ...notes];\n const root = tones[[1, ...sonority.intervals].indexOf(sonority.rootInterval)] ?? bass;\n const rootPc = noteToPitchClass(root);\n const stack: number[] = [];\n for (let step = 0; step < tones.length; step += 1) {\n // The chord tones sit two letters apart: root, third, fifth, seventh.\n const tone = tones.find((candidate) => mod7(candidate.letter - root.letter) === step * 2);\n if (tone === undefined) {\n throw new NoSolutionError(\n `figured bass ${JSON.stringify(text)} sounds ${noteNames(tones).join(' ')}, which does not stack in thirds`,\n );\n }\n stack.push(mod12(noteToPitchClass(tone) - rootPc));\n }\n const quality = TERTIAN_QUALITIES.get(stack.join(','));\n if (quality === undefined) {\n throw new NoSolutionError(\n `figured bass ${JSON.stringify(text)} sounds ${noteNames(tones).join(' ')}, which no chord quality names`,\n );\n }\n const chord = makeChord(rootPc, quality, noteToPitchClass(bass));\n chord.rootSpelling = { letter: root.letter, alter: root.alter };\n chord.bassSpelling = { letter: bass.letter, alter: bass.alter };\n return { chord, notes };\n}\n\n/**\n * A figure that moves over a held bass, such as the `4-3` suspension.\n *\n * @category Functional Harmony\n */\nexport type FiguredBassSuspension = {\n /** The interval above the bass that sounds first: the suspended note. */\n from: number;\n /** The interval it moves to, which is the one the chord contains. */\n to: number;\n /** The suspended note, spelled. */\n note: Note;\n /** The note it moves to, spelled. */\n resolution: Note;\n};\n\n/**\n * Everything a figured bass states: the chord, its spelled notes, and any\n * figure that moves.\n *\n * @category Functional Harmony\n */\nexport type FiguredBassRealization = {\n /**\n * The chord the figures name, carrying the given bass as its `bassPc` and\n * the letter spellings of its root and bass as enharmonic hints.\n */\n chord: Chord;\n /**\n * The spelled notes, bass first and then each figured interval in ascending\n * order. They carry no octave: figures fix the intervals above the bass, not\n * the register the upper voices take them in.\n */\n notes: Note[];\n /**\n * Every moving figure, in written order, or an empty array for a static one.\n * The chord above is the harmony these resolve into.\n */\n suspensions: FiguredBassSuspension[];\n};\n\n/**\n * Read a figured bass in full: the chord, its spelled notes, and its\n * suspensions.\n *\n * The figure grammar, in the forms this accepts:\n *\n * - Nothing at all, `5`, `3` or `53` — the root-position triad.\n * - `6` or `63` — the first-inversion triad; `64` — the second-inversion triad.\n * - `7` — the root-position seventh chord; `65`, `43`, and `42` (also written\n * `2`) — its first, second, and third inversions. The full stacks `753`,\n * `653`, `643` and `642` name the same four chords.\n * - Stacked figures may be written run together (`64`) or separated by a slash,\n * a comma or a space (`6/4`), which is the same figure either way.\n * - An accidental in front of a figure alters that interval: `#6`, `b7`, `#43`.\n * A slashed or crossed figure raises its interval, and is typed `+` — `+6` is\n * `#6`. An accidental with no figure alters the third above the bass, so a\n * lone `#` over the dominant of a minor key raises its third to the leading\n * tone. `#` and `b` move the interval a semitone from what the key gives,\n * `##` and `bb` a whole tone, and `n` names the natural note whatever the key\n * gives. The Unicode accidentals are accepted alongside the typed ones.\n * - A figure that moves is written with a hyphen: `4-3`, `9-8`, `7-6`, and any\n * other pair. Each side may carry its own accidental, as `4-#3` does in a\n * minor key. Moving figures may stand beside static ones (`5 4-3`).\n *\n * Every interval no accidental touches is the one the key's scale gives, which\n * is why the key is required and why the same figure names different qualities\n * over different degrees.\n *\n * A moving figure resolves into the chord: `4-3` over a G in C major returns\n * the G major triad, and the suspended C is reported as a suspension rather\n * than as a chord tone. A suspension is a melodic event over a single harmony —\n * the sounding chord does not change when it resolves — so naming the\n * resolution is the reading that answers \"which chord is this\", and the record\n * of what was suspended is kept beside it rather than thrown away.\n *\n * @param bass The bass note, spelled: a note name, a MIDI number, note data, or\n * a `Note`; its octave, if any, is not used.\n * @param figures The figures written under the bass; empty for an unfigured\n * note.\n * @param key The prevailing key, which supplies every unaltered interval, as a\n * key name, a key/scale, or a `Key`.\n * @returns The chord, its spelled notes, and any suspensions.\n * @throws If the figures are malformed or name no chord\n * ({@link InvalidInputError}), if the key is not heptatonic\n * ({@link InvalidInputError}), or if the figures sound a chord no\n * {@link ChordQuality} names, such as an augmented sixth\n * ({@link NoSolutionError}).\n * @example\n * ```ts\n * import { figuredBassRealization, majorKey, noteNames, parseNote } from '@libraz/libcantus';\n * const realized = figuredBassRealization(parseNote('G'), '4-3', majorKey(0));\n * noteNames(realized.notes); // ['G', 'B', 'D']\n * realized.suspensions[0]?.from; // 4 — the suspended C above the bass\n * ```\n * @category Functional Harmony\n */\nexport function figuredBassRealization(\n bass: NoteLike,\n figures: string,\n key: KeyLike,\n): FiguredBassRealization {\n if (typeof figures !== 'string') {\n throw new InvalidInputError(`figured bass must be a string; received ${typeof figures}`);\n }\n const bassData = toNoteData(bass);\n const scale = toKeyScale(key);\n const alters = keyLetterAlters(scale);\n // Reading the pitch class validates the note's fields before its letter is\n // used for the interval arithmetic above it.\n noteToPitchClass(bassData);\n const bassNote = bareNote(bassData);\n const text = figures.trim();\n const { figures: written, motions } = parseFigures(text);\n const suspensions = motions.map((motion) => ({\n from: motion.from.number,\n to: motion.to.number,\n note: noteAbove(bassNote, motion.from, alters),\n resolution: noteAbove(bassNote, motion.to, alters),\n }));\n // A figure resolving onto the octave lands on the bass itself, which is\n // already sounding and so adds nothing to the stack: `9-8` resolves to a\n // plain root-position triad.\n const resolved = [\n ...written,\n ...motions.map((motion) => motion.to).filter((figure) => figure.number !== OCTAVE_FIGURE),\n ];\n const { chord, notes } = realizeSonority(bassNote, resolved, text, alters);\n return { chord, notes: [bassNote, ...notes], suspensions };\n}\n\n/**\n * Realize a figured bass: the chord a bass note and its figures name in a key.\n *\n * The chord carries the given bass as its `bassPc`, so an inversion reads as\n * one everywhere the library measures a bass against a root, and carries the\n * letter spellings of its root and bass so the realization can be respelled\n * without losing the accidentals the figures asked for.\n *\n * See {@link figuredBassRealization} for the figure grammar this accepts and\n * for the spelled notes and suspensions it drops. A moving figure such as\n * `4-3` returns the chord it resolves into.\n *\n * @param bass The bass note, spelled; its octave, if any, is not used.\n * @param figures The figures written under the bass; empty for an unfigured\n * note.\n * @param key The prevailing key, which supplies every unaltered interval.\n * @param bass The bass note, spelled: a note name, a MIDI number, note data, or\n * a `Note`.\n * @param figures The figures written under the bass.\n * @param key The prevailing key, as a key name, a key/scale, or a `Key`.\n * @returns The chord the figures name.\n * @throws If the figures are malformed or name no chord\n * ({@link InvalidInputError}), if the key is not heptatonic\n * ({@link InvalidInputError}), or if the figures sound a chord no\n * {@link ChordQuality} names ({@link NoSolutionError}).\n * @example\n * ```ts\n * import { majorKey, minorKey, parseNote, realizeFiguredBass } from '@libraz/libcantus';\n * realizeFiguredBass(parseNote('B'), '6', majorKey(0));\n * // G major with B in the bass: { rootPc: 7, quality: 'maj', bassPc: 11, ... }\n * realizeFiguredBass(parseNote('G'), '#', minorKey(0));\n * // G major in C minor: the raised third is a B natural\n * ```\n * @category Functional Harmony\n */\nexport function realizeFiguredBass(bass: NoteLike, figures: string, key: KeyLike): Chord {\n return figuredBassRealization(bass, figures, key).chord;\n}\n\n/**\n * Write a chord as the figures a bass would carry under it, in a key.\n *\n * The inverse of {@link realizeFiguredBass} for every chord the figure grammar\n * reaches: the conventional abbreviation for the inversion (`6`, `64`, `7`,\n * `65`, `43`, `42`, or nothing at all for a root-position triad), with an\n * accidental on any interval the key does not already give. An altered\n * interval the abbreviation would leave implied is written out, so the raised\n * third of a dominant in a minor key emits `#3` rather than the bare `#` a\n * score would print — the figures this returns read back as the same chord.\n *\n * What this returns is read back before it is returned, so the two directions\n * cannot disagree: a chord the digits would name only approximately — an\n * augmented sixth, whose tones do not stack in thirds over its bass — has no\n * figures rather than figures that fail to realize.\n *\n * @param chord The chord to figure, as a chord symbol, chord data, or a\n * `Chord`; its `bassPc`, when present, is the bass the intervals are measured\n * above.\n * @param key The prevailing key, which decides which intervals need no\n * accidental, as a key name, a key/scale, or a `Key`.\n * @returns The figures, as {@link realizeFiguredBass} accepts them.\n * @throws If the key is not heptatonic ({@link InvalidInputError}), or if no\n * figure names the chord — its bass is not one of its tones, its tones do not\n * stack in diatonic thirds above that bass, or it is an added-tone or\n * extended chord the notation has no abbreviation for\n * ({@link NoSolutionError}).\n * @example\n * ```ts\n * import { figuredBassOf, majorKey, makeChord } from '@libraz/libcantus';\n * figuredBassOf(makeChord(7, 'maj', 11), majorKey(0)); // '6' — G major over B\n * figuredBassOf(makeChord(7, 'dom7', 2), majorKey(0)); // '43' — G7 over D\n * ```\n * @category Functional Harmony\n */\nexport function figuredBassOf(chord: ChordLike, key: KeyLike): string {\n const data = toChordData(chord);\n const scale = toKeyScale(key);\n const alters = keyLetterAlters(scale);\n const tones = spellChord(data, spelledKeyOf(scale).tonic, scale);\n const bassPc = mod12(data.bassPc ?? data.rootPc);\n const bass = tones.find((tone) => noteToPitchClass(tone) === bassPc);\n if (bass === undefined) {\n throw new NoSolutionError(\n \"figured bass measures intervals above a chord tone, and this chord's bass is not one of its tones\",\n );\n }\n const written = new Map<number, Note>();\n for (const tone of tones) {\n if (tone !== bass) {\n written.set(mod7(tone.letter - bass.letter) + 1, tone);\n }\n }\n const digits = FIGURE_ABBREVIATIONS.get([...written.keys()].sort((a, b) => a - b).join(','));\n if (digits === undefined) {\n throw new NoSolutionError(\n `no figured bass names ${noteNames(tones).join(' ')} over ${noteNames([bass])[0]}`,\n );\n }\n const accidentals = new Map<number, string>();\n for (const [number, tone] of written) {\n const alteration = tone.alter - (alters[mod7(tone.letter)] ?? 0);\n if (alteration === 0) {\n continue;\n }\n const glyph = ACCIDENTAL_GLYPHS[alteration];\n if (glyph === undefined) {\n throw new NoSolutionError(\n `no figure names an interval altered by ${alteration} semitones from the key`,\n );\n }\n accidentals.set(number, glyph);\n }\n // Figures are written from the top down, and an altered interval the\n // abbreviation leaves implied has to be named for its accidental to land on\n // anything: a raised third under a `6` is written `6#3`, not `#6`.\n const figures = [...new Set([...digits, ...accidentals.keys()])]\n .sort((a, b) => b - a)\n .map((number) => `${accidentals.get(number) ?? ''}${number}`)\n .join('');\n assertRealizesAs(bass, figures, scale, tones);\n return figures;\n}\n\n/** The pitch classes a set of spelled notes sounds, ascending. */\nfunction pitchClassesOf(notes: readonly Note[]): number[] {\n return [...new Set(notes.map(noteToPitchClass))].sort((a, b) => a - b);\n}\n\n/**\n * Require the figures just written to read back as the chord they were written\n * from, and report the ones that do not as having no figured bass.\n *\n * The digits are chosen by which intervals are written above the bass, which is\n * a weaker test than the one a realization applies: a chord may occupy the\n * interval positions of an inversion without stacking in thirds over its bass,\n * and the augmented sixths do exactly that. Reading the figures back is what\n * keeps the two directions from disagreeing about which chords the notation\n * reaches, rather than a second table that would drift from the first.\n */\nfunction assertRealizesAs(bass: Note, figures: string, key: KeyScale, tones: Note[]): void {\n const noFigures = (detail: string): NoSolutionError =>\n new NoSolutionError(\n `no figured bass names ${noteNames(tones).join(' ')} over ${noteNames([bass])[0]}: the figures ${JSON.stringify(figures)} ${detail}`,\n );\n let realized: FiguredBassRealization;\n try {\n realized = figuredBassRealization(bass, figures, key);\n } catch (error) {\n throw error instanceof NoSolutionError ? noFigures('read back as no chord at all') : error;\n }\n const written = pitchClassesOf(realized.notes);\n const expected = pitchClassesOf(tones);\n if (written.length !== expected.length || written.some((pc, index) => pc !== expected[index])) {\n throw noFigures(`sound ${noteNames(realized.notes).join(' ')} instead`);\n }\n}\n","/**\n * Tendency tones: which pitch class of a chord owes its next move to a rule.\n *\n * The voicing search and the part-writing checker both need this, and they have\n * to agree on it. A generator resolving a tone the checker does not recognize —\n * or holding one the checker thinks must move — would report its own output as\n * faulty, so both read the same predicates from here.\n */\n\nimport { pitchClassOf } from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord, ChordQuality } from '../chord/index.js';\nimport { chordToneRole } from '../chord/index.js';\n\n/** The key's leading tone as a pitch class. */\nexport function leadingTonePcOf(key: KeyScale): number {\n return pitchClassOf(key.rootPc - 1);\n}\n\n/** The qualities a leading-tone chord takes: the diminished triad and sevenths. */\nconst LEADING_TONE_QUALITIES: ReadonlySet<ChordQuality> = new Set(['dim', 'dim7', 'm7b5']);\n\n/**\n * Whether the key's leading tone is functioning as one in a chord.\n *\n * The tendency is the dominant's, not the pitch class's: the leading tone must\n * rise where it is the third of a chord built on the dominant degree, or the\n * root of a leading-tone chord, which are the two places it carries dominant\n * function. The same pitch class is an ordinary chord tone elsewhere — the\n * fifth of iii, or the seventh of Imaj7 — and is free to move as the line asks,\n * which for a seventh means falling by step.\n */\nexport function isFunctioningLeadingTone(chord: Chord, key: KeyScale): boolean {\n const role = chordToneRole(leadingTonePcOf(key), chord);\n if (role === 'third') {\n return pitchClassOf(chord.rootPc) === pitchClassOf(key.rootPc + 7);\n }\n if (role === 'root') {\n return LEADING_TONE_QUALITIES.has(chord.quality);\n }\n return false;\n}\n\n/** The chord's own seventh as a pitch class, or undefined when it has none. */\nexport function seventhPcOf(chord: Chord): number | undefined {\n for (const interval of chord.intervals) {\n const pc = pitchClassOf(chord.rootPc + interval);\n if (chordToneRole(pc, chord) === 'seventh') {\n return pc;\n }\n }\n return undefined;\n}\n","import { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\n\nexport { pitchClassOf as pitchClass } from '../../core/pitch/index.js';\n\nimport { NoSolutionError } from '../../core/errors/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../chord/index.js';\nimport { chordPitchClasses, chordToneRole } from '../chord/index.js';\nimport {\n createsHiddenParallelPerfect,\n createsParallelPerfect,\n createsVoiceOverlap,\n} from '../counterpoint/index.js';\nimport type { VoiceRange } from './satb.js';\nimport { isFunctioningLeadingTone, leadingTonePcOf, seventhPcOf } from './tendency.js';\n\n/** Default maximum spacing between adjacent upper voices (one octave). */\nexport const DEFAULT_MAX_SPACING = 12;\n\n/** Score penalty per counterpoint violation between consecutive voicings. */\nexport const VIOLATION_PENALTY = 1000;\n/** Score penalty per chord tone absent from a voicing. */\nconst MISSING_TONE_PENALTY = 500;\n/**\n * Score penalty for omitting the chord's fifth. Far milder than any other\n * missing tone: the fifth carries no identity, and the textbook resolution of a\n * complete dominant seventh onto a tonic triad — every tendency tone resolving\n * inward — leaves the tonic without its fifth. Weighted below\n * {@link RESOLUTION_PENALTY} so a resolution can buy the omission, and above\n * {@link POOR_DOUBLING_PENALTY} so nothing else can.\n */\nconst MISSING_FIFTH_PENALTY = 20;\n/** Score penalty per doubled tone that is neither the root nor the fifth. */\nconst POOR_DOUBLING_PENALTY = 4;\n/** Penalty for adjacent voices sharing exactly the same MIDI pitch. */\nconst UNISON_PENALTY = 100;\n/**\n * Score penalty for doubling the key's leading tone. Doubling it guarantees\n * parallel octaves on its resolution, so it is a rule violation rather than a\n * matter of taste — weighted far above {@link POOR_DOUBLING_PENALTY}, but below\n * a missing chord tone, which damages the chord itself.\n */\nconst LEADING_TONE_DOUBLING_PENALTY = 200;\n/**\n * Score penalty per tendency tone that fails to resolve. Well above the few\n * semitones of extra motion a correct resolution usually costs, so smoothness\n * can never buy an unresolved seventh, and well below\n * {@link VIOLATION_PENALTY}, so avoiding parallels still comes first.\n */\nexport const RESOLUTION_PENALTY = 200;\n/** Hard cap on candidate voicings evaluated per chord, keeping the search bounded. */\nconst DEFAULT_MAX_CANDIDATES = 4000;\n/**\n * Hard cap on search-tree nodes visited per chord. The candidate cap alone only\n * counts completed voicings, so a search whose upper voices admit no chord tone\n * would expand the whole cartesian product without ever reaching a leaf.\n */\nconst SEARCH_NODES_PER_CANDIDATE = 16;\n\n/**\n * Moderate penalty for a hidden/direct perfect fifth or octave reached on the\n * outer-voice (bass–soprano) pair. Unlike a true parallel perfect it is\n * discouraged rather than forbidden, so the weight sits alongside voice-leading\n * motion rather than the hard {@link VIOLATION_PENALTY}.\n */\nconst HIDDEN_PERFECT_PENALTY = 6;\n\n/**\n * Candidate voicings of one chord, held flat: voice `v` of candidate `i` sits at\n * `pitches[i * voices + v]`.\n *\n * A four-voice search reaches four thousand candidates, so a voicing per\n * candidate would be four thousand short arrays per chord — the bulk of what\n * voicing a lead sheet allocates. One buffer holds them all instead, and\n * {@link voiceProgression} reuses the same buffer for every chord, so the whole\n * progression allocates it once.\n */\nexport type VoicingCandidates = {\n /** The candidate pitches, valid up to `count * voices`. */\n pitches: Int32Array;\n /** How many candidates the last enumeration wrote. */\n count: number;\n /** Voices per candidate, i.e. the stride of `pitches`. */\n voices: number;\n};\n\n/** Candidates a fresh buffer holds before it has to grow. */\nconst INITIAL_CANDIDATE_CAPACITY = 512;\n\n/** An empty candidate buffer, ready to be filled by {@link enumerateVoicings}. */\nexport function createCandidateBuffer(): VoicingCandidates {\n return { pitches: new Int32Array(0), count: 0, voices: 0 };\n}\n\n/**\n * All MIDI pitches of a pitch class inside an inclusive range, ordered from the\n * centre of the range outward (ties break toward the lower pitch). Enumerating\n * centre-outward keeps the candidate set balanced around the register when it\n * is truncated at {@link MAX_CANDIDATES}, instead of skewing to the low octaves\n * that a plain ascending scan would visit first.\n */\nfunction pitchesForPc(pc: number, range: VoiceRange): number[] {\n const result: number[] = [];\n for (let midi = Math.ceil(range.min); midi <= range.max; midi += 1) {\n if (pitchClass(midi) === pc) {\n result.push(midi);\n }\n }\n const center = (range.min + range.max) / 2;\n return result.sort((a, b) => {\n const da = Math.abs(a - center);\n const db = Math.abs(b - center);\n return da === db ? a - b : da - db;\n });\n}\n\n/**\n * Enumerate candidate voicings for a chord: the bass takes the chord's bass\n * (or root) pitch class at each available octave, and each upper voice takes\n * any chord pitch class within its range. Candidates are built in ascending\n * voice order and pruned to exclude voice crossings and over-wide adjacent\n * spacing (the bass–tenor pair is allowed an extra octave, per convention).\n * Enumeration is deterministic and capped at `maxCandidates` completed\n * voicings and a proportional number of visited nodes.\n *\n * Each voice's admissible pitches are resolved once up front rather than\n * recomputed at every node, and a voice that admits no chord tone at all fails\n * immediately: continuing would explore every combination of the voices below\n * it only to reach no leaf.\n *\n * @param into A buffer to fill, reused and grown in place. Pass the same one\n * for every chord of a progression so the search allocates once rather than\n * once per chord.\n * @throws If any voice's range contains no pitch of any chord tone.\n */\nexport function enumerateVoicings(\n chord: Chord,\n ranges: VoiceRange[],\n maxSpacing: number,\n maxCandidates = DEFAULT_MAX_CANDIDATES,\n into: VoicingCandidates = createCandidateBuffer(),\n): VoicingCandidates {\n const chordPcs = chordPitchClasses(chord);\n const bassPc = pitchClass(chord.bassPc ?? chord.rootPc);\n // Pitch-class-major order, matching the enumeration order of the search.\n const byVoice = ranges.map((range, voice) =>\n (voice === 0 ? [bassPc] : chordPcs).flatMap((pc) => pitchesForPc(pc, range)),\n );\n for (let voice = 0; voice < byVoice.length; voice += 1) {\n if ((byVoice[voice] ?? []).length === 0) {\n throw new NoSolutionError('no voicing satisfies the given ranges');\n }\n }\n const voices = ranges.length;\n into.voices = voices;\n into.count = 0;\n let capacity = Math.floor(into.pitches.length / Math.max(1, voices));\n if (capacity === 0) {\n capacity = Math.min(maxCandidates, INITIAL_CANDIDATE_CAPACITY);\n into.pitches = new Int32Array(capacity * voices);\n }\n const current = new Int32Array(voices);\n let nodes = 0;\n const maxSearchNodes = maxCandidates * SEARCH_NODES_PER_CANDIDATE;\n const build = (voice: number): void => {\n nodes += 1;\n if (into.count >= maxCandidates || nodes > maxSearchNodes) {\n return;\n }\n if (voice === voices) {\n if (into.count === capacity) {\n capacity = Math.min(maxCandidates, capacity * 2);\n const grown = new Int32Array(capacity * voices);\n grown.set(into.pitches.subarray(0, into.count * voices));\n into.pitches = grown;\n }\n into.pitches.set(current, into.count * voices);\n into.count += 1;\n return;\n }\n const prev = voice === 0 ? undefined : current[voice - 1];\n for (const pitch of byVoice[voice] ?? []) {\n if (prev !== undefined) {\n if (pitch < prev) {\n continue; // would cross below the next lower voice\n }\n const spacingLimit = voice === 1 ? maxSpacing + 12 : maxSpacing;\n if (pitch - prev > spacingLimit) {\n continue;\n }\n }\n current[voice] = pitch;\n build(voice + 1);\n }\n };\n build(0);\n return into;\n}\n\n/**\n * The per-chord tables {@link structuralPenalty} reads.\n *\n * Every entry is a function of the chord and key alone, so it is worked out\n * once per chord instead of once per candidate — which is what keeps a\n * four-thousand-candidate search from rebuilding the chord's pitch-class set,\n * and re-deriving every tone's role, four thousand times.\n */\nexport type StructuralTables = {\n /** The chord's pitch classes, ascending. */\n tones: readonly number[];\n /** Penalty for the tone at the same index of `tones` being absent. */\n missing: readonly number[];\n /** Penalty per extra copy of each pitch class 0-11. */\n doubling: Float64Array;\n};\n\n/**\n * Build the structural tables for one chord: heavily penalize missing chord\n * tones (mildly for the fifth, which carries no identity), mildly penalize\n * doubling anything other than the root or fifth, and — when a key is known and\n * the chord is one where the leading tone functions as one — heavily penalize\n * doubling that leading tone.\n *\n * The exempt fifth is the chord's own fifth, whatever its size: a diminished,\n * augmented, or absent fifth would leave the root as the only freely doubled\n * tone, which is what forces a doubled leading tone in a `viio` chord.\n */\nexport function structuralTables(chord: Chord, key?: KeyScale): StructuralTables {\n const tones = chordPitchClasses(chord);\n const missing = tones.map((pc) =>\n chordToneRole(pc, chord) === 'fifth' ? MISSING_FIFTH_PENALTY : MISSING_TONE_PENALTY,\n );\n const rootPc = pitchClass(chord.rootPc);\n const leadingTonePc =\n key !== undefined && isFunctioningLeadingTone(chord, key) ? leadingTonePcOf(key) : -1;\n const doubling = new Float64Array(12);\n for (let pc = 0; pc < 12; pc += 1) {\n if (pc === leadingTonePc) {\n doubling[pc] = LEADING_TONE_DOUBLING_PENALTY;\n } else if (pc !== rootPc && chordToneRole(pc, chord) !== 'fifth') {\n doubling[pc] = POOR_DOUBLING_PENALTY;\n }\n }\n return { tones, missing, doubling };\n}\n\n/**\n * Pitch-class tally shared by every structural evaluation. The scoring loop\n * calls nothing that could re-enter it, so one buffer serves the whole search.\n */\nconst PITCH_CLASS_COUNTS = new Int32Array(12);\n\n/**\n * Structural quality penalty of the candidate at `offset` in `pitches`, read\n * off the chord's {@link StructuralTables}.\n */\nexport function structuralPenalty(\n tables: StructuralTables,\n pitches: ArrayLike<number>,\n offset: number,\n voices: number,\n): number {\n PITCH_CLASS_COUNTS.fill(0);\n let penalty = 0;\n for (let index = 0; index < voices; index += 1) {\n const pitch = pitches[offset + index];\n if (pitch === undefined) {\n continue;\n }\n const pc = pitchClass(pitch);\n PITCH_CLASS_COUNTS[pc] = (PITCH_CLASS_COUNTS[pc] ?? 0) + 1;\n if (index > 0 && pitch === pitches[offset + index - 1]) {\n penalty += UNISON_PENALTY;\n }\n }\n for (let index = 0; index < tables.tones.length; index += 1) {\n const pc = tables.tones[index];\n if (pc !== undefined && PITCH_CLASS_COUNTS[pc] === 0) {\n penalty += tables.missing[index] ?? 0;\n }\n }\n for (let pc = 0; pc < 12; pc += 1) {\n const count = PITCH_CLASS_COUNTS[pc] ?? 0;\n if (count > 1) {\n penalty += (count - 1) * (tables.doubling[pc] ?? 0);\n }\n }\n return penalty;\n}\n\n/**\n * The per-chord-pair tables {@link resolutionViolations} reads, worked out once\n * per chord rather than once per candidate.\n */\nexport type ResolutionTables = {\n /** The leaving chord's seventh, or -1 when it has none. */\n seventhPc: number;\n /**\n * The key's leading tone, or -1 without a key and wherever the leaving chord\n * is not one the leading tone functions in.\n */\n leadingTonePc: number;\n /** The key's tonic, or -1 without a key. */\n tonicPc: number;\n /** Whether the arriving chord contains each pitch class 0-11. */\n nextHas: Uint8Array;\n};\n\n/** Build the resolution tables for one chord-to-chord move. */\nexport function resolutionTables(\n prevChord: Chord,\n nextChord: Chord,\n key?: KeyScale,\n): ResolutionTables {\n const nextHas = new Uint8Array(12);\n for (const pc of chordPitchClasses(nextChord)) {\n nextHas[pc] = 1;\n }\n return {\n seventhPc: seventhPcOf(prevChord) ?? -1,\n leadingTonePc:\n key !== undefined && isFunctioningLeadingTone(prevChord, key) ? leadingTonePcOf(key) : -1,\n tonicPc: key === undefined ? -1 : pitchClass(key.rootPc),\n nextHas,\n };\n}\n\n/**\n * Count the tendency tones that fail to resolve between two consecutive\n * voicings of the same progression.\n *\n * A chordal seventh is a dissonance: unless the next chord holds it as a common\n * tone, the voice carrying it must fall by step. A leading tone must rise to\n * the tonic whenever the next chord contains one, and only where it is\n * functioning as a leading tone; without a key there is no leading tone to\n * speak of, so that half of the rule is skipped.\n */\nexport function resolutionViolations(\n tables: ResolutionTables,\n prev: ArrayLike<number>,\n prevOffset: number,\n cur: ArrayLike<number>,\n curOffset: number,\n voices: number,\n): number {\n const { seventhPc, leadingTonePc, tonicPc, nextHas } = tables;\n let count = 0;\n for (let voice = 0; voice < voices; voice += 1) {\n const from = prev[prevOffset + voice];\n const to = cur[curOffset + voice];\n if (from === undefined || to === undefined) {\n continue;\n }\n const fromPc = pitchClass(from);\n const motion = to - from;\n if (fromPc === seventhPc && nextHas[fromPc] === 0 && motion !== -1 && motion !== -2) {\n count += 1;\n }\n if (\n fromPc === leadingTonePc &&\n tonicPc >= 0 &&\n nextHas[tonicPc] === 1 &&\n nextHas[fromPc] === 0 &&\n motion !== 1\n ) {\n count += 1;\n }\n }\n return count;\n}\n\n/**\n * Total voice-leading cost from the voicing at `prevOffset` to the one at\n * `curOffset`: summed absolute semitone motion, plus\n * {@link HIDDEN_PERFECT_PENALTY} when the outer-voice pair reaches a\n * hidden/direct perfect fifth or octave by similar motion.\n */\nexport function leadingCost(\n prev: ArrayLike<number>,\n prevOffset: number,\n cur: ArrayLike<number>,\n curOffset: number,\n voices: number,\n): number {\n let total = 0;\n for (let voice = 0; voice < voices; voice += 1) {\n const a = prev[prevOffset + voice];\n const b = cur[curOffset + voice];\n if (a === undefined || b === undefined) {\n continue;\n }\n total += Math.abs(b - a);\n }\n // Discourage hidden/direct perfects between the outermost voices, where they\n // are most audible. True parallels are handled (and forbidden) elsewhere.\n if (voices >= 2) {\n const bassPrev = prev[prevOffset];\n const bassCur = cur[curOffset];\n const sopPrev = prev[prevOffset + voices - 1];\n const sopCur = cur[curOffset + voices - 1];\n if (\n bassPrev !== undefined &&\n bassCur !== undefined &&\n sopPrev !== undefined &&\n sopCur !== undefined &&\n createsHiddenParallelPerfect(bassPrev, bassCur, sopPrev, sopCur)\n ) {\n total += HIDDEN_PERFECT_PENALTY;\n }\n }\n return total;\n}\n\n/**\n * Count counterpoint violations between two consecutive voicings of equal\n * length: parallel perfects (fifths and octaves alike, since octaves are the\n * perfect-class-zero case of {@link createsParallelPerfect}) on every voice\n * pair, and voice overlaps on adjacent pairs.\n *\n * Voice crossing and over-wide spacing are not counted: {@link\n * enumerateVoicings} rejects both while building a candidate, so a candidate\n * that reaches here cannot exhibit either. Overlap involves the previous\n * voicing and so is still live.\n */\nexport function violationCount(\n prev: ArrayLike<number>,\n prevOffset: number,\n cur: ArrayLike<number>,\n curOffset: number,\n voices: number,\n): number {\n let count = 0;\n for (let lower = 0; lower < voices; lower += 1) {\n for (let upper = lower + 1; upper < voices; upper += 1) {\n const prevLower = prev[prevOffset + lower];\n const prevUpper = prev[prevOffset + upper];\n const curLower = cur[curOffset + lower];\n const curUpper = cur[curOffset + upper];\n if (\n prevLower === undefined ||\n prevUpper === undefined ||\n curLower === undefined ||\n curUpper === undefined\n ) {\n continue;\n }\n if (createsParallelPerfect(prevUpper, curUpper, prevLower, curLower)) {\n count += 1;\n }\n if (upper === lower + 1) {\n if (createsVoiceOverlap(prevUpper, curUpper, prevLower, curLower)) {\n count += 1;\n }\n }\n }\n }\n return count;\n}\n","import { InvalidInputError, NoSolutionError } from '../../core/errors/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport {\n assertFiniteNumber,\n assertGenerationBudget,\n assertPositiveInt,\n} from '../../core/validation/index.js';\nimport type { Chord } from '../chord/index.js';\nimport { type KeyLike, toKeyScale } from '../scale/index.js';\nimport { type ChordLike, formatChordSymbol, toChordData } from '../symbol/index.js';\nimport {\n createCandidateBuffer,\n DEFAULT_MAX_SPACING,\n enumerateVoicings,\n leadingCost,\n RESOLUTION_PENALTY,\n resolutionTables,\n resolutionViolations,\n structuralPenalty,\n structuralTables,\n VIOLATION_PENALTY,\n violationCount,\n} from './internal.js';\n\n/**\n * An inclusive MIDI pitch range for a single voice.\n *\n * @category Voicing & Counterpoint\n */\nexport type VoiceRange = {\n readonly min: number;\n readonly max: number;\n};\n\n/**\n * Default four-voice SATB ranges, ascending (index 0 = lowest):\n * bass E2–C4 (40–60), tenor C3–G4 (48–67), alto G3–D5 (55–74),\n * soprano C4–G5 (60–79).\n *\n * @category Voicing & Counterpoint\n */\nexport const SATB_RANGES: readonly Readonly<VoiceRange>[] = Object.freeze([\n Object.freeze({ min: 40, max: 60 }),\n Object.freeze({ min: 48, max: 67 }),\n Object.freeze({ min: 55, max: 74 }),\n Object.freeze({ min: 60, max: 79 }),\n]);\n\n/**\n * Options controlling {@link voiceChord} and {@link voiceProgression}.\n *\n * @category Voicing & Counterpoint\n */\nexport type VoicingOptions = {\n /**\n * Number of voices to realize. Ignored when `ranges` is given.\n *\n * @defaultValue 4\n */\n voices?: number;\n /** Explicit per-voice ranges, ascending (index 0 = lowest). Takes precedence over `voices`. */\n ranges?: VoiceRange[];\n /**\n * Maximum spacing in semitones between adjacent upper voices.\n *\n * @defaultValue 12\n */\n maxSpacing?: number;\n /**\n * Maximum candidate voicings evaluated for one chord.\n *\n * Raise this for large voicings when exact optimum matters more than bounded\n * search time.\n *\n * @defaultValue 4000\n */\n maxCandidates?: number;\n /**\n * Maximum number of chords {@link voiceProgression} will voice. The search\n * per chord is bounded internally, so the cost of a progression is linear in\n * its length; this is the guard against an unbounded caller, not a limit on\n * the search.\n *\n * @defaultValue 1000000\n */\n budget?: number;\n /**\n * The prevailing key, as a key name, a key/scale, or a `Key`. Supplying it\n * enables the rules that only make sense relative to a tonic: the leading\n * tone is neither doubled nor left unresolved. Without it, voicings are\n * chosen from chord structure and voice-leading distance alone.\n */\n key?: KeyLike;\n /**\n * The chord that produced the current voicing passed to {@link nextVoicing},\n * as a chord symbol, chord data, or a `Chord`. When supplied, chordal-seventh\n * resolution is scored exactly as it is by {@link voiceProgression}.\n */\n previousChord?: ChordLike;\n};\n\n/** Overall pitch floor/ceiling used when deriving ranges for arbitrary voice counts. */\nconst DERIVED_LOW = 40;\nconst DERIVED_HIGH = 79;\n/** Span of each derived per-voice range in semitones. */\nconst DERIVED_SPAN = 19;\n\n/**\n * Resolve the per-voice ranges implied by the options: explicit `ranges` win,\n * four voices use {@link SATB_RANGES}, and other counts get evenly spaced\n * ranges spanning roughly the bass-to-soprano compass.\n */\nexport function resolveRanges(opts?: VoicingOptions): VoiceRange[] {\n if (opts?.ranges !== undefined) {\n if (opts.ranges.length === 0) {\n throw new InvalidInputError('ranges must contain at least one voice range');\n }\n assertGenerationBudget(opts.ranges.length, 'voice ranges', 128);\n return opts.ranges.map((range, index) => {\n assertFiniteNumber(range.min, `ranges[${index}].min`);\n assertFiniteNumber(range.max, `ranges[${index}].max`);\n if (range.min > range.max) {\n throw new InvalidInputError(`ranges[${index}].min must not exceed max`);\n }\n assertGenerationBudget(\n Math.floor(range.max) - Math.ceil(range.min) + 1,\n `ranges[${index}] span`,\n 4096,\n );\n return { ...range };\n });\n }\n const voices = opts?.voices ?? 4;\n assertPositiveInt(voices, 'voices', 128);\n if (voices === 4) {\n return SATB_RANGES.map((range) => ({ ...range }));\n }\n if (voices === 1) {\n return [{ min: DERIVED_LOW, max: DERIVED_HIGH }];\n }\n const ranges: VoiceRange[] = [];\n for (let i = 0; i < voices; i += 1) {\n const min = Math.round(\n DERIVED_LOW + (i * (DERIVED_HIGH - DERIVED_SPAN - DERIVED_LOW)) / (voices - 1),\n );\n ranges.push({ min, max: min + DERIVED_SPAN });\n }\n return ranges;\n}\n\n/**\n * Resolve and validate the adjacent-voice spacing limit. Shared by every entry\n * point so `nextVoicing` cannot accept a NaN that silently disables the spacing\n * constraint, nor a negative value that reports itself as an impossible range.\n */\nexport function resolveMaxSpacing(opts?: VoicingOptions): number {\n const maxSpacing = opts?.maxSpacing ?? DEFAULT_MAX_SPACING;\n assertFiniteNumber(maxSpacing, 'maxSpacing');\n if (maxSpacing < 0) {\n throw new InvalidInputError('maxSpacing must be non-negative');\n }\n return maxSpacing;\n}\n\n/**\n * Resolve the prevailing key once per entry point, so the scoring tables below\n * are handed a key/scale rather than re-reading whatever form the caller wrote.\n */\nexport function resolveKey(opts?: VoicingOptions): KeyScale | undefined {\n return opts?.key === undefined ? undefined : toKeyScale(opts.key);\n}\n\n/** Resolve the chord a `nextVoicing` caller says the current voicing came from. */\nexport function resolvePreviousChord(opts?: VoicingOptions): Chord | undefined {\n return opts?.previousChord === undefined ? undefined : toChordData(opts.previousChord);\n}\n\n/** Resolve and validate the per-chord candidate-search cap. */\nexport function resolveMaxCandidates(opts?: VoicingOptions): number | undefined {\n if (opts?.maxCandidates === undefined) return undefined;\n assertPositiveInt(opts.maxCandidates, 'maxCandidates', 1_000_000);\n return opts.maxCandidates;\n}\n\n/**\n * Realize a single chord as one MIDI pitch per voice, ascending (index 0 =\n * lowest). The bass voice takes the chord's `bassPc` when set, otherwise the\n * root; upper voices take chord pitch classes, doubling the root or fifth as\n * needed to fill all voices. The result stays inside each voice's range, keeps\n * adjacent upper voices within `maxSpacing`, avoids voice crossing, and is\n * deterministic: a compact close-position voicing centered in the ranges.\n *\n * @param chord The chord to voice.\n * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.\n * @returns MIDI pitches, ascending, one per voice.\n * @throws If no voicing fits the given ranges.\n * @example\n * ```ts\n * import { parseChordSymbol, voiceChord } from '@libraz/libcantus';\n * const chord = parseChordSymbol('Cmaj7');\n * voiceChord(chord); // four ascending MIDI pitches within the SATB ranges\n * ```\n * @category Voicing & Counterpoint\n */\nexport function voiceChord(chord: ChordLike, opts?: VoicingOptions): number[] {\n const data = toChordData(chord);\n const ranges = resolveRanges(opts);\n const maxSpacing = resolveMaxSpacing(opts);\n const candidates = enumerateVoicings(data, ranges, maxSpacing, resolveMaxCandidates(opts));\n const tables = structuralTables(data, resolveKey(opts));\n const { pitches, voices } = candidates;\n let bestOffset = -1;\n let bestScore = Number.POSITIVE_INFINITY;\n for (let index = 0; index < candidates.count; index += 1) {\n const offset = index * voices;\n let score = structuralPenalty(tables, pitches, offset, voices);\n for (let i = 0; i < voices; i += 1) {\n const pitch = pitches[offset + i];\n const range = ranges[i];\n if (pitch === undefined || range === undefined) {\n continue;\n }\n // Prefer pitches near the middle of each voice's range for a centered,\n // compact default voicing.\n score += Math.abs(pitch - (range.min + range.max) / 2);\n }\n if (score < bestScore) {\n bestScore = score;\n bestOffset = offset;\n }\n }\n if (bestOffset < 0) {\n throw new NoSolutionError(\n `no voicing satisfies the given ranges for ${formatChordSymbol(chord)}`,\n );\n }\n return [...pitches.subarray(bestOffset, bestOffset + voices)];\n}\n\n/**\n * Voice a chord progression with smooth voice leading. The first chord is\n * voiced with {@link voiceChord}; each subsequent chord picks, from a bounded\n * deterministic candidate set, the voicing minimizing the voice-leading cost\n * from the previous voicing plus a large penalty per counterpoint violation\n * (parallel perfects/octaves, voice crossing, voice overlap, and over-wide\n * upper-voice spacing).\n *\n * Tendency tones are resolved rather than merely moved economically: the voice\n * holding a chordal seventh falls by step unless the next chord keeps that tone,\n * and — when `opts.key` is given — the leading tone rises to the tonic and is\n * never doubled, wherever it is functioning as a leading tone rather than\n * sounding as an ordinary tone of some other chord. Without a key the\n * leading-tone rules cannot apply, since nothing identifies which pitch class is\n * the leading tone.\n *\n * @param chords The chords to voice in order.\n * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.\n * @returns One voicing per chord, each ascending with one MIDI pitch per voice.\n * @throws If any chord admits no voicing within the given ranges, or if the\n * progression is longer than `opts.budget` chords.\n * @example\n * ```ts\n * import { parseChordSymbol, voiceProgression } from '@libraz/libcantus';\n * const chords = ['C', 'Am', 'F', 'G'].map((s) => parseChordSymbol(s));\n * voiceProgression(chords); // one four-voice voicing per chord, smoothly led\n * ```\n * @category Voicing & Counterpoint\n */\n/** The unsatisfiable-constraints error for one chord of a progression. */\nfunction noSolutionAt(index: number, chord: Chord): NoSolutionError {\n return new NoSolutionError(\n `no voicing satisfies the given ranges for ${formatChordSymbol(chord)} at index ${index}`,\n { at: index },\n );\n}\n\n/**\n * Run one chord's work, re-raising an unsatisfiable-constraints failure with\n * the chord it happened on. Voicing a whole lead sheet is otherwise told only\n * that some chord did not fit.\n */\nfunction locate<T>(index: number, chord: Chord, work: () => T): T {\n try {\n return work();\n } catch (error) {\n if (error instanceof NoSolutionError) {\n throw noSolutionAt(index, chord);\n }\n throw error;\n }\n}\n\n/**\n * Voice a chord progression with smooth, bounded SATB-style leading.\n *\n * Each chord is chosen from a deterministic candidate set, minimizing motion\n * while penalizing counterpoint violations. A supplied key additionally\n * resolves leading tones and chordal sevenths.\n *\n * @param chords The chords to voice in order.\n * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.\n * @returns One ascending MIDI voicing per chord.\n * @throws {@link NoSolutionError} with the failing chord index when a chord\n * cannot fit the requested ranges.\n * @category Voicing & Counterpoint\n */\nexport function voiceProgression(chords: readonly ChordLike[], opts?: VoicingOptions): number[][] {\n assertGenerationBudget(chords.length, 'voiced progression chords', opts?.budget);\n const data = chords.map((chord) => toChordData(chord));\n const key = resolveKey(opts);\n const ranges = resolveRanges(opts);\n const maxSpacing = resolveMaxSpacing(opts);\n const maxCandidates = resolveMaxCandidates(opts);\n const result: number[][] = [];\n // One candidate buffer serves the whole progression: the search overwrites it\n // per chord, so a lead sheet allocates it once rather than once per chord.\n const buffer = createCandidateBuffer();\n let prev: number[] | undefined;\n let prevChord: Chord | undefined;\n for (let index = 0; index < data.length; index += 1) {\n const chord = data[index];\n if (chord === undefined) {\n continue;\n }\n if (prev === undefined) {\n prev = locate(index, chord, () => voiceChord(chord, opts));\n prevChord = chord;\n result.push(prev);\n continue;\n }\n const candidates = locate(index, chord, () =>\n enumerateVoicings(chord, ranges, maxSpacing, maxCandidates, buffer),\n );\n const { pitches, voices } = candidates;\n const structure = structuralTables(chord, key);\n const resolution =\n prevChord === undefined ? undefined : resolutionTables(prevChord, chord, key);\n let bestOffset = -1;\n let bestScore = Number.POSITIVE_INFINITY;\n for (let candidate = 0; candidate < candidates.count; candidate += 1) {\n const offset = candidate * voices;\n const unresolved =\n resolution === undefined\n ? 0\n : resolutionViolations(resolution, prev, 0, pitches, offset, voices);\n const score =\n structuralPenalty(structure, pitches, offset, voices) +\n leadingCost(prev, 0, pitches, offset, voices) +\n VIOLATION_PENALTY * violationCount(prev, 0, pitches, offset, voices) +\n RESOLUTION_PENALTY * unresolved;\n if (score < bestScore) {\n bestScore = score;\n bestOffset = offset;\n }\n }\n if (bestOffset < 0) {\n throw noSolutionAt(index, chord);\n }\n const best = [...pitches.subarray(bestOffset, bestOffset + voices)];\n result.push(best);\n prev = best;\n prevChord = chord;\n }\n return result;\n}\n","import { InvalidInputError, NoSolutionError } from '../../core/errors/index.js';\nimport { assertFiniteNumber } from '../../core/validation/index.js';\nimport { type ChordLike, toChordData } from '../symbol/index.js';\nimport {\n enumerateVoicings,\n leadingCost,\n RESOLUTION_PENALTY,\n resolutionTables,\n resolutionViolations,\n structuralPenalty,\n structuralTables,\n VIOLATION_PENALTY,\n violationCount,\n} from './internal.js';\nimport type { VoicingOptions } from './satb.js';\nimport {\n resolveKey,\n resolveMaxCandidates,\n resolveMaxSpacing,\n resolvePreviousChord,\n resolveRanges,\n} from './satb.js';\n\n/**\n * Total voice-leading cost between two voicings: the sum of absolute semitone\n * motion across voices, plus a moderate hidden-perfect penalty when the\n * outer-voice (bass–soprano) pair reaches a hidden/direct perfect fifth or\n * octave by similar motion. The arrays must be the same length; when they\n * differ the voicings are not comparable and the cost is `Infinity`.\n *\n * @param from The previous voicing, one MIDI pitch per voice.\n * @param to The next voicing, one MIDI pitch per voice.\n * @returns The summed absolute motion (plus any hidden-perfect penalty), or\n * `Infinity` when lengths differ.\n * @category Voicing & Counterpoint\n */\nexport function voiceLeadingCost(from: number[], to: number[]): number {\n if (from.length !== to.length) {\n return Number.POSITIVE_INFINITY;\n }\n return leadingCost(from, 0, to, 0, from.length);\n}\n\n/**\n * Voice a single chord to follow smoothly from an arbitrary current voicing.\n *\n * Candidate voicings of `chord` are enumerated within ranges taken from `opts`,\n * or — when neither `voices` nor `ranges` is given — from a one-octave window\n * around each pitch of `current` (so the result matches `current`'s voice\n * count). Each candidate is scored by structural quality, voice-leading motion\n * from `current`, and a large penalty per counterpoint violation; the lowest\n * scoring candidate is returned, ascending.\n *\n * @param current The current voicing to lead from, ascending (index 0 = lowest).\n * @param chord The next chord to voice, as a chord symbol, chord data, or a\n * `Chord`.\n * @param opts Voicing options; when omitted, ranges follow `current`'s span.\n * @returns The chosen voicing, ascending with one MIDI pitch per voice.\n * @throws If `current` is empty or holds a non-finite pitch while the ranges\n * are derived from it, if it asks for more voices than the search will take,\n * or if no voicing fits the ranges.\n * @category Voicing & Counterpoint\n */\nexport function nextVoicing(current: number[], chord: ChordLike, opts?: VoicingOptions): number[] {\n const data = toChordData(chord);\n const derived = opts?.ranges === undefined && opts?.voices === undefined;\n if (derived) {\n // The ranges are read off `current`, so an empty voicing would describe a\n // zero-voice chord and return an empty result — the same input that throws\n // when written as an explicit `{ ranges: [] }`.\n if (current.length === 0) {\n throw new InvalidInputError('current must contain at least one pitch');\n }\n for (let index = 0; index < current.length; index += 1) {\n assertFiniteNumber(current[index] ?? Number.NaN, `current[${index}]`);\n }\n }\n // Both branches end in the same resolver, so the voice-count budget and the\n // range checks apply wherever the ranges came from: a texture read off\n // `current` is no smaller a search than the same one written out as `ranges`.\n const ranges = derived\n ? resolveRanges({\n ranges: current.map((pitch) => {\n // Window one octave around each current pitch, clamped so extreme-low\n // or extreme-high input can never yield MIDI outside [0, 127].\n const centre = Math.min(127, Math.max(0, pitch));\n return { min: Math.max(0, centre - 12), max: Math.min(127, centre + 12) };\n }),\n })\n : resolveRanges(opts);\n for (let index = 0; index < current.length; index += 1) {\n assertFiniteNumber(current[index] ?? Number.NaN, `current[${index}]`);\n }\n if (current.length < ranges.length) {\n throw new InvalidInputError(\n `current has ${current.length} voices but the requested ranges require ${ranges.length}`,\n );\n }\n // Thinning an existing texture is a normal use case (SATB to three voices,\n // for example). Keep the outer voices and select evenly spaced inner voices\n // so motion is still measured between like voice roles.\n const source =\n current.length === ranges.length\n ? current\n : ranges.length === 1\n ? [current[0] ?? Number.NaN]\n : ranges.map((_, index) => {\n const sourceIndex = Math.round((index * (current.length - 1)) / (ranges.length - 1));\n return current[sourceIndex] ?? Number.NaN;\n });\n const maxSpacing = resolveMaxSpacing(opts);\n const candidates = enumerateVoicings(data, ranges, maxSpacing, resolveMaxCandidates(opts));\n const key = resolveKey(opts);\n const previousChord = resolvePreviousChord(opts);\n const structure = structuralTables(data, key);\n const resolution =\n previousChord === undefined ? undefined : resolutionTables(previousChord, data, key);\n const { pitches, voices } = candidates;\n let bestOffset = -1;\n let bestScore = Number.POSITIVE_INFINITY;\n for (let candidate = 0; candidate < candidates.count; candidate += 1) {\n const offset = candidate * voices;\n const score =\n structuralPenalty(structure, pitches, offset, voices) +\n leadingCost(source, 0, pitches, offset, voices) +\n VIOLATION_PENALTY * violationCount(source, 0, pitches, offset, voices) +\n RESOLUTION_PENALTY *\n (resolution === undefined\n ? 0\n : resolutionViolations(resolution, source, 0, pitches, offset, voices));\n if (score < bestScore) {\n bestScore = score;\n bestOffset = offset;\n }\n }\n if (bestOffset < 0) {\n throw new NoSolutionError('no voicing satisfies the given ranges');\n }\n return [...pitches.subarray(bestOffset, bestOffset + voices)];\n}\n","import { InvalidInputError } from '../../core/errors/index.js';\nimport { assertFiniteNumber, assertInteger } from '../../core/validation/index.js';\nimport type { Chord } from '../chord/index.js';\nimport { chordToneRole } from '../chord/index.js';\nimport { pitchClass } from './internal.js';\n\n/**\n * A tertian voicing style for {@link voiceChordStyled}.\n *\n * - `close`: the plain close-position tertian stack.\n * - `drop2`: the second voice from the top dropped an octave (drop-2 voicing).\n * - `drop3`: the third voice from the top dropped an octave (drop-3 voicing).\n * - `shell`: root plus guide tones (third and seventh) for seventh chords, or\n * root/third/fifth for triads; the fifth and tensions are omitted.\n * - `rootless`: the root omitted, keeping third/fifth/seventh and tensions\n * (a typical left-hand jazz voicing).\n *\n * @category Voicing & Counterpoint\n */\nexport type VoicingStyle = 'close' | 'drop2' | 'drop3' | 'shell' | 'rootless';\n\n/**\n * Options controlling {@link voiceChordStyled}.\n *\n * @category Voicing & Counterpoint\n */\nexport type StyledVoicingOptions = {\n /**\n * Voicing style to build.\n *\n * @defaultValue 'close'\n */\n style?: VoicingStyle;\n /** Constrain the highest voice to this pitch class (0..11) when given. */\n topNote?: number;\n /**\n * Base octave in scientific pitch notation: octave 4 starts the stack near\n * middle C (MIDI 60), i.e. near `12 * (octave + 1)`.\n *\n * @defaultValue 4\n */\n octave?: number;\n /**\n * Omit the root regardless of style (relevant for jazz voicings).\n *\n * @defaultValue false\n */\n rootless?: boolean;\n};\n\n/** Default base octave for a styled close-position stack. */\nconst DEFAULT_STYLE_OCTAVE = 4;\n\n/** Return the pitch classes of a list in order, without duplicates. */\nfunction dedupePcs(pcs: number[]): number[] {\n const seen = new Set<number>();\n const result: number[] = [];\n for (const pc of pcs) {\n if (!seen.has(pc)) {\n seen.add(pc);\n result.push(pc);\n }\n }\n return result;\n}\n\n/** The lowest MIDI pitch of a pitch class at or above a floor. */\nfunction lowestPitchAtOrAbove(pc: number, floor: number): number {\n return floor + ((((pc - pitchClass(floor)) % 12) + 12) % 12);\n}\n\n/** The pitch class in `pcs` whose circular distance to `target` is smallest. */\nfunction nearestPc(target: number, pcs: number[]): number {\n let best = pcs[0] ?? target;\n let bestDist = 12;\n for (const pc of pcs) {\n const dist = Math.min((((pc - target) % 12) + 12) % 12, (((target - pc) % 12) + 12) % 12);\n if (dist < bestDist) {\n bestDist = dist;\n best = pc;\n }\n }\n return best;\n}\n\n/**\n * Realize a single chord as an explicit tertian voicing in a chosen style,\n * independent of the SATB range search used by {@link voiceChord}.\n *\n * The chord tones are stacked in close position from the bass (`bassPc`, else\n * `rootPc`) in the given scientific-pitch `octave` upward (octave 4 starts the\n * bass near C4 = MIDI 60, matching {@link midiToNote} and the bass module).\n * When `topNote` is given the stack is rotated so the highest voice's pitch\n * class equals that note (or the nearest chord tone). The chosen\n * {@link VoicingStyle} then transforms the stack, and the result is returned as\n * ascending MIDI pitches (index 0 = lowest).\n *\n * Every returned pitch is a valid MIDI number: an octave whose stack would run\n * off either end of the 0..127 range is rejected rather than voiced out of\n * range, matching {@link nextVoicing}, which clamps its derived ranges.\n *\n * @param chord The chord to voice.\n * @param opts Styled voicing options; defaults to a close voicing at octave 4.\n * @returns MIDI pitches, ascending, one per retained voice.\n * @throws If the voicing would not fit inside MIDI 0..127 at the given octave.\n * @example\n * ```ts\n * import { parseChordSymbol, voiceChordStyled } from '@libraz/libcantus';\n * const chord = parseChordSymbol('Dm7');\n * voiceChordStyled(chord, { style: 'drop2' }); // ascending MIDI pitches, drop-2 voicing\n * ```\n * @category Voicing & Counterpoint\n */\nexport function voiceChordStyled(chord: Chord, opts?: StyledVoicingOptions): number[] {\n const style = opts?.style ?? 'close';\n const octave = opts?.octave ?? DEFAULT_STYLE_OCTAVE;\n assertInteger(octave, 'styled voicing octave', -10, 10);\n if (opts?.topNote !== undefined) {\n assertFiniteNumber(opts.topNote, 'styled voicing topNote');\n }\n const base = 12 * (octave + 1);\n const rootPc = pitchClass(chord.rootPc);\n const bassPc = pitchClass(chord.bassPc ?? chord.rootPc);\n const omitRoot = style === 'rootless' || opts?.rootless === true;\n\n // Tertian chord tones in order, with the bass tone rotated to the bottom.\n let order = dedupePcs(chord.intervals.map((interval) => pitchClass(chord.rootPc + interval)));\n const bassIndex = order.indexOf(bassPc);\n if (bassIndex > 0) {\n order = [...order.slice(bassIndex), ...order.slice(0, bassIndex)];\n } else if (bassIndex < 0) {\n order = [bassPc, ...order];\n }\n\n if (style === 'shell') {\n const roles = order.map((pc) => chordToneRole(pc, chord));\n // The guide tone is the seventh when present; on a sixth chord the sixth\n // stands in for it, and otherwise the voicing falls back to the fifth.\n const guide = roles.includes('seventh')\n ? 'seventh'\n : roles.includes('sixth')\n ? 'sixth'\n : 'fifth';\n order = order.filter((_pc, i) => {\n const role = roles[i];\n return _pc === bassPc || role === 'root' || role === 'third' || role === guide;\n });\n }\n\n if (omitRoot) {\n order = order.filter((pc) => pc !== rootPc || (chord.bassPc !== undefined && pc === bassPc));\n }\n\n if (order.length === 0) {\n return [];\n }\n\n if (opts?.topNote !== undefined) {\n const target = order.includes(pitchClass(opts.topNote))\n ? pitchClass(opts.topNote)\n : nearestPc(pitchClass(opts.topNote), order);\n const targetIndex = order.indexOf(target);\n order = [...order.slice(targetIndex + 1), ...order.slice(0, targetIndex + 1)];\n }\n\n // Stack the ordered pitch classes upward in close position.\n const stack: number[] = [];\n let prev: number | undefined;\n for (const pc of order) {\n if (prev === undefined) {\n prev = lowestPitchAtOrAbove(pc, base);\n } else {\n let delta = (((pc - pitchClass(prev)) % 12) + 12) % 12;\n if (delta === 0) {\n delta = 12;\n }\n prev += delta;\n }\n stack.push(prev);\n }\n\n if (style === 'drop2' && stack.length >= 2) {\n stack[stack.length - 2] = (stack[stack.length - 2] ?? 0) - 12;\n } else if (style === 'drop3' && stack.length >= 3) {\n stack[stack.length - 3] = (stack[stack.length - 3] ?? 0) - 12;\n }\n\n // An explicit slash bass is a structural requirement, including when it is\n // not a chord member. Drop voicings and top-note rotation may have moved a\n // different tone below it, so lower the retained bass by octaves before the\n // final sort. This gives the bass priority over a conflicting top-note hint.\n if (chord.bassPc !== undefined) {\n const bassIndexInStack = stack.findIndex((pitch) => pitchClass(pitch) === bassPc);\n if (bassIndexInStack >= 0) {\n const otherLowest = Math.min(\n ...stack.filter((_pitch, index) => index !== bassIndexInStack),\n Number.POSITIVE_INFINITY,\n );\n while ((stack[bassIndexInStack] ?? 0) >= otherLowest) {\n stack[bassIndexInStack] = (stack[bassIndexInStack] ?? 0) - 12;\n }\n }\n }\n\n const voicing = stack.sort((a, b) => a - b);\n const lowest = voicing[0] ?? 0;\n const highest = voicing[voicing.length - 1] ?? 0;\n if (lowest < 0 || highest > 127) {\n throw new InvalidInputError(\n `styled voicing at octave ${octave} spans MIDI ${lowest}..${highest}, outside 0..127`,\n );\n }\n return voicing;\n}\n","/**\n * Shared construction of {@link PartWritingViolation} records.\n *\n * The four-part checker and the species checker report the same violation type,\n * so they build it and name intervals the same way.\n */\n\nimport type { PartWritingViolation, PartWritingViolationKind } from './index.js';\n\n/** Diatonic names of the interval numbers a melodic step or leap can span. */\nconst INTERVAL_WORDS = [\n 'unison',\n 'second',\n 'third',\n 'fourth',\n 'fifth',\n 'sixth',\n 'seventh',\n 'octave',\n] as const;\n\n/** Name an interval number, falling back to a bare noun beyond the octave. */\nexport function intervalWord(numberValue: number): string {\n return INTERVAL_WORDS[numberValue - 1] ?? 'interval';\n}\n\n/** Build one violation record, so the field order is written once. */\nexport function violation(\n kind: PartWritingViolationKind,\n voices: number[],\n fromIndex: number,\n toIndex: number,\n rationale: string,\n): PartWritingViolation {\n return { kind, voices, fromIndex, toIndex, rationale };\n}\n","/**\n * Species counterpoint: mark a two-voice exercise against the sixteenth-century\n * rules.\n *\n * This is the conservatory exercise, not a general style checker. It grades a\n * counterpoint written above or below a given cantus firmus in one of the five\n * species, and reports what it finds as the same {@link PartWritingViolation}\n * the four-part checker uses.\n *\n * Both voices arrive as spelled notes, because half of what the rules forbid is\n * invisible in a pitch: the augmented second of the harmonic minor is a minor\n * third by ear, and the diminished fourth that may not stand as a consonance is\n * a major third by ear.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport { ConsonanceClass } from '../../core/interval/index.js';\nimport type { Note, SpelledInterval } from '../../core/pitch/index.js';\nimport {\n noteToMidi,\n noteToPitchClass,\n pitchClassOf,\n spelledInterval,\n} from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport {\n classifySpelledInterval,\n createsBattuta,\n createsHiddenParallelPerfect,\n createsParallelPerfect,\n createsVoiceCrossing,\n isAugmentedMelodicInterval,\n isForbiddenMelodicLeap,\n} from '../counterpoint/index.js';\nimport { simpleIntervalNumber } from '../counterpoint/internal.js';\nimport type { PartWritingViolation } from './index.js';\nimport { intervalWord, violation } from './internal.js';\n\n/**\n * Which species an exercise is written in: note against note, two, three or\n * four notes against one, suspensions, or the florid mixture of them all.\n *\n * @category Voicing & Counterpoint\n */\nexport type Species = 1 | 2 | 3 | 4 | 5;\n\n/**\n * Options controlling {@link checkSpecies}.\n *\n * @category Voicing & Counterpoint\n */\nexport type SpeciesOptions = {\n /**\n * Length of each counterpoint note, measured in cantus-firmus notes: 1 is a\n * whole note filling a measure, 0.5 a half, 0.25 a quarter.\n *\n * The first four species have a fixed ratio, so the durations are implied by\n * the note count and this is only needed to describe something unusual. The\n * fifth species mixes note values by definition and cannot be read without it.\n */\n durations?: readonly number[];\n /**\n * Which side of the cantus firmus the counterpoint is written on. Defaults to\n * whichever side it actually lies on, by mean pitch.\n */\n counterpointAbove?: boolean;\n};\n\n/** Tolerance for comparing positions measured in cantus-firmus notes. */\nconst EPS = 1e-9;\n\n/** Notes of counterpoint per cantus-firmus note, by species. */\nconst SPECIES_RATIO: Readonly<Record<Species, number>> = { 1: 1, 2: 2, 3: 4, 4: 2, 5: 0 };\n\n/** The species there are, read from the ratio table rather than listed twice. */\nconst SPECIES_NUMBERS: readonly number[] = Object.keys(SPECIES_RATIO).map(Number);\n\n/** The smallest note value the fifth species may write, in cantus-firmus notes. */\nconst MIN_FLORID_VALUE = 0.125;\n\n/** One counterpoint note, placed in time against the cantus firmus. */\ntype Entry = {\n /** The counterpoint note itself. */\n note: Note;\n /** Its index in the counterpoint array. */\n index: number;\n /** Onset, in cantus-firmus notes from the start of the exercise. */\n onset: number;\n /** Length, in cantus-firmus notes. */\n duration: number;\n /** The cantus-firmus note sounding under it. */\n against: Note;\n /** Index of that cantus-firmus note. */\n againstIndex: number;\n /** Whether the note falls on the downbeat of its measure. */\n downbeat: boolean;\n /** The interval between the two voices, read from the lower note upward. */\n interval: SpelledInterval;\n /** How that interval sounds in two-voice counterpoint. */\n consonance: ConsonanceClass;\n};\n\n/** Mean sounding pitch of a line, for deciding which voice lies above. */\nfunction meanPitch(notes: readonly Note[]): number {\n if (notes.length === 0) {\n return 0;\n }\n return notes.reduce((sum, note) => sum + noteToMidi(note), 0) / notes.length;\n}\n\n/**\n * Note lengths implied by the species when the caller gives none.\n *\n * Every measure but the last carries the species' full ratio; whatever notes\n * are left share the closing measure, which lets an exercise end on the single\n * whole note convention asks for without being described note by note.\n */\nfunction impliedDurations(count: number, measures: number, ratio: number): number[] {\n const full = ratio * Math.max(measures - 1, 0);\n const closing = Math.max(count - full, 1);\n return Array.from({ length: count }, (_, index) => (index < full ? 1 / ratio : 1 / closing));\n}\n\n/** Whether a melodic interval is a diatonic step. */\nfunction isStep(interval: SpelledInterval): boolean {\n return interval.number === 2;\n}\n\n/** The direction a melodic interval moves: 1 up, -1 down, 0 for a repetition. */\nfunction direction(interval: SpelledInterval): number {\n return Math.sign(interval.semitones);\n}\n\n/** Whether two spelled notes are the same note, so a tie joins them. */\nfunction sameNote(a: Note, b: Note): boolean {\n return a.letter === b.letter && a.alter === b.alter && a.octave === b.octave;\n}\n\n/**\n * Whether a dissonance is passed through: approached and left by step in one\n * direction (a passing note) or by step and back (a neighbour note).\n */\nfunction isPassedThrough(entries: readonly Entry[], position: number): boolean {\n const previous = entries[position - 1];\n const current = entries[position];\n const next = entries[position + 1];\n if (previous === undefined || current === undefined || next === undefined) {\n return false;\n }\n const incoming = spelledInterval(previous.note, current.note);\n const outgoing = spelledInterval(current.note, next.note);\n if (!isStep(incoming) || !isStep(outgoing)) {\n return false;\n }\n const passing = direction(incoming) === direction(outgoing);\n const neighbour = sameNote(previous.note, next.note);\n return passing || neighbour;\n}\n\n/** Whether a melodic interval leaps a third, the only leap the figures write. */\nfunction isThird(interval: SpelledInterval): boolean {\n return interval.number === 3;\n}\n\n/** The four notes of a figure, starting at one position, if the line has them. */\nfunction figureAt(\n entries: readonly Entry[],\n start: number,\n): [Entry, Entry, Entry, Entry] | undefined {\n const first = entries[start];\n const second = entries[start + 1];\n const third = entries[start + 2];\n const fourth = entries[start + 3];\n if (first === undefined || second === undefined || third === undefined || fourth === undefined) {\n return undefined;\n }\n return [first, second, third, fourth];\n}\n\n/**\n * Whether four notes spell the *nota cambiata*: a consonance, a dissonance\n * stepped down onto, a leap of a third down onto a consonance, and a step back\n * up.\n *\n * Fux grants the figure by name. The dissonance is quitted by leap, which every\n * other licence forbids, and the ear hears the note leapt to as the resolution\n * the step would have reached.\n */\nfunction isCambiata(entries: readonly Entry[], start: number): boolean {\n const figure = figureAt(entries, start);\n if (figure === undefined) {\n return false;\n }\n const [first, second, third, fourth] = figure;\n if (\n first.consonance === ConsonanceClass.Dissonance ||\n third.consonance === ConsonanceClass.Dissonance\n ) {\n return false;\n }\n const approach = spelledInterval(first.note, second.note);\n const leap = spelledInterval(second.note, third.note);\n const answer = spelledInterval(third.note, fourth.note);\n return (\n isStep(approach) &&\n direction(approach) < 0 &&\n isThird(leap) &&\n direction(leap) < 0 &&\n isStep(answer) &&\n direction(answer) > 0\n );\n}\n\n/**\n * Whether four notes spell the double neighbour: a step to one side of a note,\n * a leap of a third across to the other side, and a step back to the note the\n * figure left.\n *\n * Both notes in the middle decorate the same consonance, so either of them may\n * be the dissonance even though the figure moves between them by leap.\n */\nfunction isDoubleNeighbour(entries: readonly Entry[], start: number): boolean {\n const figure = figureAt(entries, start);\n if (figure === undefined) {\n return false;\n }\n const [first, second, third, fourth] = figure;\n if (first.consonance === ConsonanceClass.Dissonance || !sameNote(first.note, fourth.note)) {\n return false;\n }\n const away = spelledInterval(first.note, second.note);\n const across = spelledInterval(second.note, third.note);\n const back = spelledInterval(third.note, fourth.note);\n return (\n isStep(away) &&\n isThird(across) &&\n isStep(back) &&\n direction(away) !== 0 &&\n direction(across) === -direction(away)\n );\n}\n\n/**\n * Whether a dissonance stands inside one of the figures that quit a dissonance\n * by leap: the *nota cambiata* or the double neighbour.\n *\n * Both belong to the quarter-note line, so they are read in the third and fifth\n * species only. The second species moves a note against each half of the\n * measure and writes neither.\n */\nfunction isFiguredDissonance(\n entries: readonly Entry[],\n position: number,\n species: Species,\n): boolean {\n if (species !== 3 && species !== 5) {\n return false;\n }\n return (\n isCambiata(entries, position - 1) ||\n isDoubleNeighbour(entries, position - 1) ||\n isDoubleNeighbour(entries, position - 2)\n );\n}\n\n/** Where a species allows a dissonance to fall. */\ntype DissonanceLicence = 'none' | 'passing' | 'suspension';\n\n/** The licence a species grants at one metric position. */\nfunction licenceFor(species: Species, downbeat: boolean): DissonanceLicence {\n if (species === 1) {\n return 'none';\n }\n if (species === 4) {\n return downbeat ? 'suspension' : 'none';\n }\n if (species === 5) {\n return downbeat ? 'suspension' : 'passing';\n }\n return downbeat ? 'none' : 'passing';\n}\n\n/**\n * The rules judged on one counterpoint note: the vertical interval it forms,\n * and whether the voices have crossed.\n */\nfunction verticalViolations(\n entries: readonly Entry[],\n position: number,\n species: Species,\n counterpointAbove: boolean,\n): PartWritingViolation[] {\n const entry = entries[position];\n if (entry === undefined) {\n return [];\n }\n const found: PartWritingViolation[] = [];\n const upper = counterpointAbove ? entry.note : entry.against;\n const lower = counterpointAbove ? entry.against : entry.note;\n if (createsVoiceCrossing(upper, lower)) {\n found.push(\n violation(\n 'voiceCrossing',\n [0, 1],\n entry.index,\n entry.index,\n 'The counterpoint crosses to the wrong side of the cantus firmus',\n ),\n );\n }\n if (entry.consonance !== ConsonanceClass.Dissonance) {\n return found;\n }\n const licence = licenceFor(species, entry.downbeat);\n if (\n licence === 'passing' &&\n (isPassedThrough(entries, position) || isFiguredDissonance(entries, position, species))\n ) {\n return found;\n }\n if (licence === 'suspension') {\n found.push(...suspensionViolations(entries, position));\n return found;\n }\n found.push(\n violation(\n 'unpreparedDissonance',\n [0, 1],\n entry.index,\n entry.index,\n licence === 'none'\n ? `A ${entry.interval.quality}${entry.interval.number} falls where this species allows only a consonance`\n : 'The dissonance is not passed through by step',\n ),\n );\n return found;\n}\n\n/**\n * The rules judged on a dissonant downbeat where the species writes\n * suspensions: it must be tied over from a consonance and fall by step onto the\n * next note.\n */\nfunction suspensionViolations(entries: readonly Entry[], position: number): PartWritingViolation[] {\n const entry = entries[position];\n if (entry === undefined) {\n return [];\n }\n const previous = entries[position - 1];\n const next = entries[position + 1];\n const prepared =\n previous !== undefined &&\n sameNote(previous.note, entry.note) &&\n previous.consonance !== ConsonanceClass.Dissonance;\n if (!prepared) {\n return [\n violation(\n 'unpreparedDissonance',\n [0, 1],\n entry.index,\n entry.index,\n 'The suspended dissonance is not tied over from a consonance',\n ),\n ];\n }\n const resolution = next === undefined ? undefined : spelledInterval(entry.note, next.note);\n if (\n next === undefined ||\n resolution === undefined ||\n !isStep(resolution) ||\n direction(resolution) >= 0\n ) {\n return [\n violation(\n 'unresolvedSuspension',\n [0, 1],\n entry.index,\n next === undefined ? entry.index : next.index,\n 'The suspension does not fall by step onto its resolution',\n ),\n ];\n }\n return [];\n}\n\n/** The rules judged along the counterpoint line itself. */\nfunction melodicViolations(from: Entry, to: Entry): PartWritingViolation[] {\n const interval = spelledInterval(from.note, to.note);\n if (isAugmentedMelodicInterval(from.note, to.note)) {\n return [\n violation(\n 'augmentedMelodicInterval',\n [1],\n from.index,\n to.index,\n `The counterpoint moves by an augmented ${intervalWord(interval.number)}`,\n ),\n ];\n }\n if (isForbiddenMelodicLeap(from.note, to.note)) {\n return [\n violation(\n 'illegalLeap',\n [1],\n from.index,\n to.index,\n `The counterpoint leaps by a ${interval.quality}${interval.number}`,\n ),\n ];\n }\n return [];\n}\n\n/** How many leaps in a row may carry the line the same way. */\nconst MAX_LEAPS_IN_ONE_DIRECTION = 2;\n\n/** How far leaps in one direction may carry the line in total, in semitones. */\nconst MAX_LEAP_CHAIN_SPAN = 12;\n\n/** The smallest leap that must be answered by a step the other way. */\nconst LEAP_NEEDING_ANSWER = 6;\n\n/** The tritone, in semitones, whichever way it is spelled. */\nconst TRITONE_SEMITONES = 6;\n\n/** One melodic move of the counterpoint, as the shape rules read it. */\ntype Move = {\n /** The note moved from. */\n from: Entry;\n /** The note moved to. */\n to: Entry;\n /** The interval between them. */\n interval: SpelledInterval;\n};\n\n/** Whether a melodic interval leaps rather than steps or repeats the note. */\nfunction isLeap(interval: SpelledInterval): boolean {\n return interval.number > 2;\n}\n\n/** Every move of the counterpoint, in order. */\nfunction melodicMoves(entries: readonly Entry[]): Move[] {\n const moves: Move[] = [];\n for (let position = 1; position < entries.length; position += 1) {\n const from = entries[position - 1];\n const to = entries[position];\n if (from === undefined || to === undefined) {\n continue;\n }\n moves.push({ from, to, interval: spelledInterval(from.note, to.note) });\n }\n return moves;\n}\n\n/**\n * The one high point: the line reaches its highest note once and does not\n * return to it.\n *\n * A note repeated in place is one arrival, and the closing note is left out of\n * the comparison — where the counterpoint ends is fixed by the cadence rather\n * than by the shape of the line, so a line that climbs to its final is not\n * charged with reaching its peak twice.\n */\nfunction climaxViolations(entries: readonly Entry[]): PartWritingViolation[] {\n const body = entries.slice(0, -1);\n const peak = body.reduce(\n (high, entry) => Math.max(high, noteToMidi(entry.note)),\n Number.NEGATIVE_INFINITY,\n );\n const arrivals = body.filter((entry, position) => {\n const previous = body[position - 1];\n return (\n noteToMidi(entry.note) === peak &&\n (previous === undefined || noteToMidi(previous.note) !== peak)\n );\n });\n const first = arrivals[0];\n const second = arrivals[1];\n if (first === undefined || second === undefined) {\n return [];\n }\n return [\n violation(\n 'melodicShape',\n [1],\n first.index,\n second.index,\n 'The line reaches its highest note more than once, so it has no one climax',\n ),\n ];\n}\n\n/**\n * Leaps taken one after another the same way: two at most, spanning an octave\n * at most, so that a chain of leaps still outlines a chord the ear can follow.\n */\nfunction leapChainViolations(moves: readonly Move[]): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n let run: Move[] = [];\n const close = (): void => {\n const first = run[0];\n const last = run[run.length - 1];\n const span = run.reduce((total, move) => total + Math.abs(move.interval.semitones), 0);\n if (first !== undefined && last !== undefined) {\n if (run.length > MAX_LEAPS_IN_ONE_DIRECTION) {\n found.push(\n violation(\n 'melodicShape',\n [1],\n first.from.index,\n last.to.index,\n `The counterpoint leaps ${run.length} times in a row in the same direction`,\n ),\n );\n } else if (run.length > 1 && span > MAX_LEAP_CHAIN_SPAN) {\n found.push(\n violation(\n 'melodicShape',\n [1],\n first.from.index,\n last.to.index,\n 'Two leaps in the same direction carry the line further than an octave',\n ),\n );\n }\n }\n run = [];\n };\n for (const move of moves) {\n if (!isLeap(move.interval)) {\n close();\n continue;\n }\n const previous = run[run.length - 1];\n if (previous !== undefined && direction(previous.interval) !== direction(move.interval)) {\n close();\n }\n run.push(move);\n }\n close();\n return found;\n}\n\n/**\n * A wide leap is answered by a step the other way, which fills the gap it tore\n * open. Thirds, fourths and fifths are free to carry on: the wider the leap,\n * the stronger the style asks for the turn, and it asks outright from the sixth\n * upward.\n */\nfunction leapAnswerViolations(moves: readonly Move[]): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n for (let position = 0; position < moves.length; position += 1) {\n const leap = moves[position];\n const answer = moves[position + 1];\n if (leap === undefined || answer === undefined || leap.interval.number < LEAP_NEEDING_ANSWER) {\n continue;\n }\n if (isStep(answer.interval) && direction(answer.interval) === -direction(leap.interval)) {\n continue;\n }\n const word = intervalWord(leap.interval.number);\n found.push(\n violation(\n 'melodicShape',\n [1],\n leap.from.index,\n answer.to.index,\n `The leap of ${word === 'octave' ? 'an' : 'a'} ${word} is not answered by a step the other way`,\n ),\n );\n }\n return found;\n}\n\n/**\n * The tritone the line may not leap is also the tritone it may not draw: a run\n * of notes moving one way, however it is filled in, may not turn around on the\n * interval between its own extremes.\n *\n * A repeated note does not end the run, and a run of a single interval is left\n * to the leap rule, which already forbids it.\n */\nfunction tritoneOutlineViolations(entries: readonly Entry[]): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n let run: Move[] = [];\n const close = (): void => {\n const first = run[0];\n const last = run[run.length - 1];\n if (first !== undefined && last !== undefined && run.length > 1) {\n const outline = spelledInterval(first.from.note, last.to.note);\n if (Math.abs(outline.semitones) === TRITONE_SEMITONES) {\n found.push(\n violation(\n 'melodicShape',\n [1],\n first.from.index,\n last.to.index,\n 'The line turns around on a tritone, outlining the interval it may not leap',\n ),\n );\n }\n }\n run = [];\n };\n for (const move of melodicMoves(entries)) {\n if (direction(move.interval) === 0) {\n continue;\n }\n const previous = run[run.length - 1];\n if (previous !== undefined && direction(previous.interval) !== direction(move.interval)) {\n close();\n }\n run.push(move);\n }\n close();\n return found;\n}\n\n/**\n * The moving species do not repeat a note: the second and third species are\n * written to keep the line going, and the repetition that carries a fourth or\n * fifth species phrase is a tie rather than a second attack.\n *\n * The closing measure is exempt. An exercise that writes its final measure in\n * the species' own note values rather than as the single whole note convention\n * asks for is holding the final, not attacking it again.\n */\nfunction repeatedNoteViolations(\n moves: readonly Move[],\n closingMeasure: number,\n): PartWritingViolation[] {\n return moves\n .filter(\n (move) => sameNote(move.from.note, move.to.note) && move.from.againstIndex < closingMeasure,\n )\n .map((move) =>\n violation(\n 'melodicShape',\n [1],\n move.from.index,\n move.to.index,\n 'The counterpoint repeats a note where this species keeps the line moving',\n ),\n );\n}\n\n/**\n * The rules judged on the shape of the counterpoint rather than on any one of\n * its intervals: the single climax, the chain of leaps and the step that\n * answers a wide one, the tritone outlined between turning points, and the\n * repeated note the moving species do not write.\n *\n * These belong to the species exercise, whose whole subject is the line. The\n * four-part exercise is judged chord by chord and lets a voice leap where the\n * harmony asks, so {@link checkPartWriting} does not apply them.\n */\nfunction melodicShapeViolations(\n entries: readonly Entry[],\n species: Species,\n): PartWritingViolation[] {\n const moves = melodicMoves(entries);\n const closingMeasure = entries[entries.length - 1]?.againstIndex ?? 0;\n const found = [\n ...climaxViolations(entries),\n ...leapChainViolations(moves),\n ...leapAnswerViolations(moves),\n ...tritoneOutlineViolations(entries),\n ...(species === 2 || species === 3 ? repeatedNoteViolations(moves, closingMeasure) : []),\n ];\n return found.sort((left, right) => left.fromIndex - right.fromIndex);\n}\n\n/** The rules judged between two voices moving together. */\nfunction motionViolations(\n from: Entry,\n to: Entry,\n counterpointAbove: boolean,\n): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n const upperPrev = counterpointAbove ? from.note : from.against;\n const upperCur = counterpointAbove ? to.note : to.against;\n const lowerPrev = counterpointAbove ? from.against : from.note;\n const lowerCur = counterpointAbove ? to.against : to.note;\n if (createsParallelPerfect(upperPrev, upperCur, lowerPrev, lowerCur)) {\n const fifth = simpleIntervalNumber(to.interval.number) === 5;\n found.push(\n violation(\n fifth ? 'parallelFifth' : 'parallelOctave',\n [0, 1],\n from.index,\n to.index,\n fifth\n ? 'The two voices move into consecutive perfect fifths'\n : 'The two voices move into consecutive perfect octaves',\n ),\n );\n }\n if (createsHiddenParallelPerfect(upperPrev, upperCur, lowerPrev, lowerCur)) {\n found.push(\n violation(\n 'hiddenPerfect',\n [0, 1],\n from.index,\n to.index,\n 'The voices leap into a perfect interval by similar motion',\n ),\n );\n }\n if (createsBattuta(upperPrev, upperCur, lowerPrev, lowerCur)) {\n found.push(\n violation(\n 'battuta',\n [0, 1],\n from.index,\n to.index,\n 'The upper voice leaps down into an octave against the lower voice',\n ),\n );\n }\n return found;\n}\n\n/**\n * The last counterpoint note sounding against an earlier cantus-firmus note\n * than the given one.\n *\n * The closing formula is a motion from one measure into the next, so it is read\n * by measure rather than by position in the array. A closing measure written in\n * the species' own note values holds more than one counterpoint note, and the\n * note before the last one then lies inside the final measure, which would\n * judge the cadence against itself.\n */\nfunction lastEntryBefore(entries: readonly Entry[], againstIndex: number): Entry | undefined {\n for (let position = entries.length - 1; position >= 0; position -= 1) {\n const entry = entries[position];\n if (entry !== undefined && entry.againstIndex < againstIndex) {\n return entry;\n }\n }\n return undefined;\n}\n\n/**\n * The opening and closing formulas.\n *\n * An exercise begins on a perfect consonance and ends on the octave or unison,\n * approached by step in the counterpoint from the major sixth above the cantus\n * firmus, or the minor third below it — the sixth or third that carries the\n * leading tone.\n */\nfunction cadenceViolations(\n entries: readonly Entry[],\n mode: KeyScale,\n counterpointAbove: boolean,\n): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n const first = entries[0];\n const last = entries[entries.length - 1];\n if (first === undefined || last === undefined) {\n return found;\n }\n if (classifySpelledInterval(first.interval) !== ConsonanceClass.PerfectConsonance) {\n found.push(\n violation(\n 'missingCadence',\n [0, 1],\n first.index,\n first.index,\n 'The exercise does not begin on a perfect consonance',\n ),\n );\n }\n if (noteToPitchClass(last.note) !== pitchClassOf(mode.rootPc)) {\n found.push(\n violation(\n 'missingCadence',\n [0, 1],\n last.index,\n last.index,\n 'The counterpoint does not close on the final of the mode',\n ),\n );\n }\n const closing = last.interval;\n if (closing.quality !== 'P' || simpleIntervalNumber(closing.number) !== 1) {\n found.push(\n violation(\n 'missingCadence',\n [0, 1],\n last.index,\n last.index,\n 'The exercise does not close on an octave or unison',\n ),\n );\n return found;\n }\n const penultimate = lastEntryBefore(entries, last.againstIndex);\n if (penultimate === undefined) {\n return found;\n }\n const arrival = entries.find((entry) => entry.againstIndex === last.againstIndex) ?? last;\n const approach = spelledInterval(penultimate.note, arrival.note);\n const expected = counterpointAbove ? { quality: 'M', number: 6 } : { quality: 'm', number: 3 };\n if (\n penultimate.interval.quality !== expected.quality ||\n simpleIntervalNumber(penultimate.interval.number) !== expected.number ||\n !isStep(approach)\n ) {\n found.push(\n violation(\n 'missingCadence',\n [0, 1],\n penultimate.index,\n arrival.index,\n counterpointAbove\n ? 'The close is not the major sixth stepping out to the octave'\n : 'The close is not the minor third stepping in to the unison',\n ),\n );\n }\n return found;\n}\n\n/** The note lengths to read the exercise by, or the reason they cannot be read. */\nfunction resolveDurations(\n counterpoint: readonly Note[],\n measures: number,\n species: Species,\n opts: SpeciesOptions | undefined,\n): { durations: number[] } | { problem: string } {\n const given = opts?.durations;\n if (given !== undefined) {\n if (given.length !== counterpoint.length) {\n return {\n problem: `The exercise gives ${given.length} durations for ${counterpoint.length} notes`,\n };\n }\n for (const duration of given) {\n const units = duration / MIN_FLORID_VALUE;\n if (!(duration > 0) || duration > 1 || Math.abs(units - Math.round(units)) > EPS) {\n return {\n problem: `A note lasts ${duration} of a measure, which this style does not write`,\n };\n }\n }\n const total = given.reduce((sum, duration) => sum + duration, 0);\n if (Math.abs(total - measures) > EPS) {\n return { problem: `The counterpoint fills ${total} of the ${measures} measures` };\n }\n return { durations: [...given] };\n }\n if (species === 5) {\n throw new InvalidInputError(\n 'checkSpecies needs durations for the fifth species, whose note values are not fixed',\n );\n }\n const ratio = SPECIES_RATIO[species];\n const full = ratio * measures;\n // A closing measure written as one whole note is the convention rather than\n // an exception, so both note counts read as the correct ratio.\n if (counterpoint.length !== full && counterpoint.length !== full - ratio + 1) {\n return {\n problem: `Species ${species} sets ${ratio} notes against each of the ${measures} cantus firmus notes, and the counterpoint has ${counterpoint.length}`,\n };\n }\n return { durations: impliedDurations(counterpoint.length, measures, ratio) };\n}\n\n/** Place every counterpoint note against the cantus-firmus note it sounds with. */\nfunction buildEntries(\n cantusFirmus: readonly Note[],\n counterpoint: readonly Note[],\n durations: readonly number[],\n counterpointAbove: boolean,\n): Entry[] {\n const entries: Entry[] = [];\n let onset = 0;\n for (let index = 0; index < counterpoint.length; index += 1) {\n const note = counterpoint[index];\n const duration = durations[index] ?? 0;\n if (note === undefined) {\n continue;\n }\n const againstIndex = Math.min(Math.floor(onset + EPS), cantusFirmus.length - 1);\n const against = cantusFirmus[againstIndex];\n if (against === undefined) {\n continue;\n }\n const interval = counterpointAbove\n ? spelledInterval(against, note)\n : spelledInterval(note, against);\n entries.push({\n note,\n index,\n onset,\n duration,\n against,\n againstIndex,\n downbeat: Math.abs(onset - Math.round(onset)) < EPS,\n interval,\n consonance: classifySpelledInterval(interval),\n });\n onset += duration;\n }\n return entries;\n}\n\n/**\n * The pairs of counterpoint notes the motion rules are judged over: the\n * successive attacks that cross a bar line.\n *\n * Two counterpoint notes over one unmoving cantus-firmus note are oblique\n * motion, which no parallel rule can touch, so the pairs that can break a rule\n * are the ones where the lower voice has moved too. Perfect intervals on two\n * successive downbeats with other notes in between are deliberately not judged\n * here: whether the intervening note excuses them is exactly what the sources\n * disagree about, and the fourth species is built on the ligature that does.\n */\nfunction motionPairs(entries: readonly Entry[]): [number, number][] {\n const pairs: [number, number][] = [];\n for (let position = 1; position < entries.length; position += 1) {\n const previous = entries[position - 1];\n const current = entries[position];\n if (previous === undefined || current === undefined) {\n continue;\n }\n if (previous.againstIndex !== current.againstIndex) {\n pairs.push([position - 1, position]);\n }\n }\n return pairs;\n}\n\n/**\n * Check a species counterpoint exercise and report every rule it breaks.\n *\n * The cantus firmus is one note per measure. The counterpoint is aligned to it\n * by position rather than by written rhythm: the first four species have a fixed\n * number of notes per measure, so the note count alone says where each note\n * falls, and a closing measure written as a single whole note is accepted as the\n * convention it is. The fifth species mixes note values and therefore needs\n * `opts.durations`, given in cantus-firmus notes.\n *\n * Judged are the vertical intervals under each species' dissonance licence\n * (none in the first, a passing dissonance on the weak half in the second and\n * third, a prepared suspension on the downbeat in the fourth, both in the\n * fifth; the third and fifth species also write the *nota cambiata* and the\n * double neighbour, which quit a dissonance by leap), parallel and hidden\n * perfects and the *battuta* between the voices, augmented and otherwise\n * forbidden leaps along the counterpoint, the shape of the counterpoint as a\n * line, and the opening and closing formulas. Violations name the cantus firmus\n * as voice 0 and the counterpoint as voice 1, and index into the counterpoint.\n *\n * @param cantusFirmus The given voice, one spelled note per measure.\n * @param counterpoint The written voice, in spelled notes.\n * @param species Which species the exercise is written in.\n * @param mode The mode the exercise is in.\n * @param opts Note lengths, and which side the counterpoint is written on.\n * @returns Every violation found, in the order the exercise commits them; an\n * empty array for a clean exercise.\n * @throws If the species is not one of the five, either voice is empty, a note\n * carries no octave, or the fifth species is given without durations.\n * @example\n * ```ts\n * import { checkSpecies, majorKey, parseNote } from '@libraz/libcantus';\n * const cf = ['C4', 'D4', 'E4', 'D4', 'C4'].map((n) => parseNote(n));\n * const cp = ['C5', 'A4', 'G4', 'B4', 'C5'].map((n) => parseNote(n));\n * checkSpecies(cf, cp, 1, majorKey(0)); // [] — a clean first-species exercise\n * ```\n * @category Voicing & Counterpoint\n */\nexport function checkSpecies(\n cantusFirmus: readonly Note[],\n counterpoint: readonly Note[],\n species: Species,\n mode: KeyScale,\n opts?: SpeciesOptions,\n): PartWritingViolation[] {\n if (!SPECIES_NUMBERS.includes(species)) {\n throw new InvalidInputError(\n `species must be one of ${SPECIES_NUMBERS.join(', ')}; received ${JSON.stringify(species)}`,\n );\n }\n if (cantusFirmus.length === 0 || counterpoint.length === 0) {\n throw new InvalidInputError('checkSpecies needs both a cantus firmus and a counterpoint');\n }\n const resolved = resolveDurations(counterpoint, cantusFirmus.length, species, opts);\n if ('problem' in resolved) {\n return [violation('wrongRhythmicRatio', [1], 0, counterpoint.length - 1, resolved.problem)];\n }\n const counterpointAbove =\n opts?.counterpointAbove ?? meanPitch(counterpoint) >= meanPitch(cantusFirmus);\n const entries = buildEntries(cantusFirmus, counterpoint, resolved.durations, counterpointAbove);\n\n const violations: PartWritingViolation[] = [];\n for (let position = 0; position < entries.length; position += 1) {\n violations.push(...verticalViolations(entries, position, species, counterpointAbove));\n const previous = entries[position - 1];\n const current = entries[position];\n if (previous !== undefined && current !== undefined) {\n violations.push(...melodicViolations(previous, current));\n }\n }\n violations.push(...melodicShapeViolations(entries, species));\n for (const [from, to] of motionPairs(entries)) {\n const previous = entries[from];\n const current = entries[to];\n if (previous !== undefined && current !== undefined) {\n violations.push(...motionViolations(previous, current, counterpointAbove));\n }\n }\n violations.push(...cadenceViolations(entries, mode, counterpointAbove));\n return violations;\n}\n","/**\n * Part writing: grade a finished exercise against the classical four-part rules.\n *\n * The counterpoint predicates each judge one pair of voices at one moment; this\n * module walks a whole progression and reports every violation it finds, so a\n * completed exercise can be marked in a single call.\n *\n * The input is spelled notes rather than MIDI pitches because two of the rules\n * cannot be decided without them: a cross relation is one letter carrying two\n * different accidentals, and an augmented second is a minor third under another\n * name. A caller holding only pitches spells them with {@link spellVoicing}.\n */\n\nimport { InvalidInputError } from '../../core/errors/index.js';\nimport type { Note, SpelledInterval } from '../../core/pitch/index.js';\nimport {\n diatonicLetterOf,\n formatNote,\n noteToMidi,\n noteToPitchClass,\n pitchClassOf,\n spelledInterval,\n} from '../../core/pitch/index.js';\nimport type { KeyScale } from '../../core/types.js';\nimport type { Chord } from '../chord/index.js';\nimport { chordPitchClasses } from '../chord/index.js';\nimport {\n createsHiddenParallelPerfect,\n createsParallelPerfect,\n createsVoiceCrossing,\n createsVoiceOverlap,\n exceedsSpacing,\n isAugmentedMelodicInterval,\n isLeadingToneResolution,\n} from '../counterpoint/index.js';\nimport { spelledKeyOf } from '../scale/index.js';\nimport { spellPitch } from '../spelling/index.js';\nimport type { VoiceRange } from '../voicing/index.js';\nimport { SATB_RANGES } from '../voicing/index.js';\nimport { resolveMaxSpacing, resolveRanges } from '../voicing/satb.js';\nimport { isFunctioningLeadingTone, leadingTonePcOf, seventhPcOf } from '../voicing/tendency.js';\nimport { intervalWord, violation } from './internal.js';\n\n/**\n * The rule a {@link PartWritingViolation} breaks.\n *\n * - `parallelFifth`, `parallelOctave`: consecutive perfect intervals of the same\n * kind between one pair of voices. A parallel unison is reported as a\n * `parallelOctave`, since it is the same perfect class.\n * - `hiddenPerfect`: the outer voices reach a perfect fifth or octave by similar\n * motion with a leap in the upper voice.\n * - `crossRelation`: one letter carries two different accidentals in two\n * different voices across a chord change, exposed — neither note led into by\n * step, at least one of them in an outer voice, and neither chord one of the\n * chromatic harmonies that are written with the contradiction.\n * - `voiceCrossing`, `overlap`, `spacing`, `range`: the texture rules.\n * - `unresolvedLeadingTone`, `unresolvedSeventh`: a tendency tone that does not\n * go where it must.\n * - `augmentedMelodicInterval`: a single voice moves by an augmented interval.\n *\n * The rest are raised by {@link checkSpecies} alone, since they describe faults\n * only a species exercise can commit:\n *\n * - `wrongRhythmicRatio`: the counterpoint does not present the number of notes\n * per cantus-firmus note its species requires.\n * - `unpreparedDissonance`: a dissonance falls where the species allows none, or\n * is reached or left by leap where it must be passed through by step.\n * - `unresolvedSuspension`: a fourth-species suspension that does not fall by\n * step onto the following consonance.\n * - `illegalLeap`: a melodic leap the style forbids — either seventh, the\n * tritone, or anything wider than an octave.\n * - `battuta`: an octave or unison reached by contrary motion with the upper\n * voice leaping down.\n * - `missingCadence`: the exercise does not open or close on the formula its\n * species requires.\n * - `melodicShape`: the counterpoint is a poor line — it has no single climax,\n * leaps too often or too far one way, leaves a wide leap unanswered, outlines\n * a tritone, or repeats a note where the species keeps moving. The rationale\n * says which.\n *\n * @category Voicing & Counterpoint\n */\nexport type PartWritingViolationKind =\n | 'parallelFifth'\n | 'parallelOctave'\n | 'hiddenPerfect'\n | 'crossRelation'\n | 'voiceCrossing'\n | 'overlap'\n | 'spacing'\n | 'range'\n | 'unresolvedLeadingTone'\n | 'unresolvedSeventh'\n | 'augmentedMelodicInterval'\n | 'wrongRhythmicRatio'\n | 'unpreparedDissonance'\n | 'unresolvedSuspension'\n | 'illegalLeap'\n | 'battuta'\n | 'missingCadence'\n | 'melodicShape';\n\n/**\n * One broken rule, located in the progression and in the texture.\n *\n * @category Voicing & Counterpoint\n */\nexport type PartWritingViolation = {\n /** The rule that was broken. */\n kind: PartWritingViolationKind;\n /**\n * The voices involved, by index into a voicing (0 = lowest). A rule about a\n * pair names both, ascending; a rule about a single line names one. A\n * `crossRelation` is the exception: it names the voice holding the earlier\n * note first, whichever is higher. In a species exercise there are only two\n * voices and they are named by role instead: 0 is the cantus firmus and 1 the\n * counterpoint, whichever lies above.\n */\n voices: number[];\n /**\n * Index of the chord the motion starts on; in a species exercise, the index\n * into the counterpoint.\n */\n fromIndex: number;\n /** Index of the chord it ends on; equal to `fromIndex` for a vertical rule. */\n toIndex: number;\n /** A short sentence naming the musical reason. */\n rationale: string;\n};\n\n/**\n * A chord realized as one spelled note per voice, ascending (index 0 = lowest),\n * matching the voice order {@link voiceChord} and {@link SATB_RANGES} use.\n *\n * Every note must carry an octave: the rules measure real distances between\n * sounding pitches, which a bare pitch class does not have.\n *\n * @category Voicing & Counterpoint\n */\nexport type SpelledVoicing = Note[];\n\n/**\n * Options controlling {@link checkPartWriting}.\n *\n * @category Voicing & Counterpoint\n */\nexport type PartWritingOptions = {\n /**\n * Per-voice ranges, ascending (index 0 = lowest), against which the `range`\n * rule is judged. Defaults to {@link SATB_RANGES} for a four-voice exercise;\n * for any other voice count there is no conventional compass to assume, so\n * the rule is skipped unless ranges are given. Given ranges must cover every\n * voice of the widest chord, and each must be finite with `min` no greater\n * than `max`.\n */\n ranges?: VoiceRange[];\n /**\n * Maximum spacing in semitones between adjacent upper voices. The bass-tenor\n * pair is exempt, as convention has it. Must be finite and non-negative.\n *\n * @defaultValue 12\n */\n maxSpacing?: number;\n};\n\n/** A note without its octave, for naming it in a rationale. */\nfunction bare(note: Note): Note {\n return { letter: note.letter, alter: note.alter };\n}\n\n/** The sounding pitch of a spelled note, located for the error message. */\nfunction midiOf(note: Note, index: number, voice: number): number {\n if (note.octave === undefined) {\n throw new InvalidInputError(`voicings[${index}][${voice}] must carry an octave`);\n }\n return noteToMidi(note);\n}\n\n/** Whether a melodic interval descends by a diatonic step. */\nfunction isDescendingStep(interval: SpelledInterval): boolean {\n return interval.number === 2 && (interval.semitones === -1 || interval.semitones === -2);\n}\n\n/** One chord of the exercise, and everything the rules read off it. */\ntype Moment = {\n notes: SpelledVoicing;\n pitches: number[];\n chord: Chord;\n index: number;\n};\n\n/** The rules judged inside one chord: crossing, spacing, and range. */\nfunction verticalViolations(\n moment: Moment,\n ranges: readonly Readonly<VoiceRange>[] | undefined,\n maxSpacing: number,\n): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n const { pitches, index } = moment;\n for (let voice = 1; voice < pitches.length; voice += 1) {\n const upper = pitches[voice];\n const lower = pitches[voice - 1];\n if (upper === undefined || lower === undefined) {\n continue;\n }\n if (createsVoiceCrossing(upper, lower)) {\n found.push(\n violation(\n 'voiceCrossing',\n [voice - 1, voice],\n index,\n index,\n 'The upper voice lies below the voice beneath it',\n ),\n );\n }\n // The bass-tenor pair is conventionally allowed to open up further than the\n // upper voices, so the spacing rule starts one pair above it.\n if (voice >= 2 && exceedsSpacing(upper, lower, maxSpacing)) {\n found.push(\n violation(\n 'spacing',\n [voice - 1, voice],\n index,\n index,\n `Adjacent upper voices lie more than ${maxSpacing} semitones apart`,\n ),\n );\n }\n }\n if (ranges === undefined) {\n return found;\n }\n for (let voice = 0; voice < pitches.length; voice += 1) {\n const pitch = pitches[voice];\n const range = ranges[voice];\n if (pitch === undefined || range === undefined) {\n continue;\n }\n if (pitch < range.min || pitch > range.max) {\n found.push(violation('range', [voice], index, index, 'The voice sings outside its range'));\n }\n }\n return found;\n}\n\n/**\n * Two consecutive chords of the exercise, the key they sound in, and the chords\n * on either side of the pair. The neighbours are what tells a chromatic tone\n * that was led into by step from one that was leapt at, and an applied dominant\n * from the diatonic triad that sounds the same.\n */\ntype Transition = {\n from: Moment;\n to: Moment;\n key: KeyScale;\n before?: Moment;\n after?: Moment;\n};\n\n/** The rules judged between two voices moving together: parallels and overlap. */\nfunction pairViolations(transition: Transition): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n const { from, to } = transition;\n const voices = Math.min(from.pitches.length, to.pitches.length);\n for (let lower = 0; lower < voices; lower += 1) {\n for (let upper = lower + 1; upper < voices; upper += 1) {\n const upperPrev = from.pitches[upper];\n const upperCur = to.pitches[upper];\n const lowerPrev = from.pitches[lower];\n const lowerCur = to.pitches[lower];\n if (\n upperPrev === undefined ||\n upperCur === undefined ||\n lowerPrev === undefined ||\n lowerCur === undefined\n ) {\n continue;\n }\n if (createsParallelPerfect(upperPrev, upperCur, lowerPrev, lowerCur)) {\n const fifth = pitchClassOf(upperCur - lowerCur) === 7;\n found.push(\n violation(\n fifth ? 'parallelFifth' : 'parallelOctave',\n [lower, upper],\n from.index,\n to.index,\n fifth\n ? 'The two voices move into consecutive perfect fifths'\n : 'The two voices move into consecutive perfect octaves',\n ),\n );\n }\n if (upper === lower + 1 && createsVoiceOverlap(upperPrev, upperCur, lowerPrev, lowerCur)) {\n found.push(\n violation(\n 'overlap',\n [lower, upper],\n from.index,\n to.index,\n 'The voice moves past where its neighbour just was',\n ),\n );\n }\n }\n }\n // The hidden perfect is judged on the outer voices alone, where the bare fifth\n // or octave is exposed; between inner voices it is covered by the others.\n const bassPrev = from.pitches[0];\n const bassCur = to.pitches[0];\n const topPrev = from.pitches[voices - 1];\n const topCur = to.pitches[voices - 1];\n if (\n voices >= 2 &&\n bassPrev !== undefined &&\n bassCur !== undefined &&\n topPrev !== undefined &&\n topCur !== undefined &&\n createsHiddenParallelPerfect(topPrev, topCur, bassPrev, bassCur)\n ) {\n found.push(\n violation(\n 'hiddenPerfect',\n [0, voices - 1],\n from.index,\n to.index,\n 'The outer voices leap into a perfect interval by similar motion',\n ),\n );\n }\n return found;\n}\n\n/** Whether a pitch class belongs to the key. */\nfunction inKey(pc: number, key: KeyScale): boolean {\n return ((key.modeMask12 >> pitchClassOf(pc - key.rootPc)) & 1) === 1;\n}\n\n/**\n * Whether a chord has the dominant's sonority: a major triad, or any chord\n * sounding a major third and a minor seventh above its root.\n */\nfunction isDominantSonority(chord: Chord): boolean {\n const has = (semitones: number): boolean =>\n chord.intervals.some((interval) => pitchClassOf(interval) === semitones);\n return chord.quality === 'maj' || (has(4) && has(10));\n}\n\n/**\n * Whether a chord is an applied dominant: the dominant's sonority, taken down a\n * fifth onto a degree of the key other than the tonic.\n *\n * The resolution is part of the reading rather than a consequence of it. The\n * same major triad on the third degree of a major key is V/vi where vi follows\n * and a plain III where nothing does, and only the first of the two licenses\n * the chromatic tone it introduces.\n */\nfunction isAppliedDominant(chord: Chord, next: Chord | undefined, key: KeyScale): boolean {\n if (next === undefined || !isDominantSonority(chord)) {\n return false;\n }\n const target = pitchClassOf(chord.rootPc + 5);\n return (\n target !== pitchClassOf(key.rootPc) &&\n inKey(target, key) &&\n pitchClassOf(next.rootPc) === target\n );\n}\n\n/** Whether a chord is the Neapolitan: a major triad on the lowered second degree. */\nfunction isNeapolitan(chord: Chord, key: KeyScale): boolean {\n return chord.quality === 'maj' && pitchClassOf(chord.rootPc - key.rootPc) === 1;\n}\n\n/**\n * Whether a voicing sounds an augmented sixth above the lowered submediant.\n *\n * That interval is what the Italian, French and German chords are all named\n * for, and it is the only thing separating them from the bVI7 they sound like,\n * so it is read off the written letters rather than the pitch classes.\n */\nfunction soundsAugmentedSixth(moment: Moment, key: KeyScale): boolean {\n const bass = moment.notes[0];\n if (bass === undefined || noteToPitchClass(bass) !== pitchClassOf(key.rootPc + 8)) {\n return false;\n }\n return moment.notes.some((note, voice) => {\n if (voice === 0) {\n return false;\n }\n const interval = spelledInterval(bass, note);\n return ((interval.number - 1) % 7) + 1 === 6 && pitchClassOf(interval.semitones) === 10;\n });\n}\n\n/**\n * Whether a chord is one of the chromatic harmonies whose own definition\n * contains the contradiction: an applied dominant, the Neapolitan, or an\n * augmented sixth. Approaching or leaving one of these is where the textbooks\n * license the cross relation, since the chord cannot be written without it.\n */\nfunction isChromaticHarmony(moment: Moment, next: Chord | undefined, key: KeyScale): boolean {\n return (\n isAppliedDominant(moment.chord, next, key) ||\n isNeapolitan(moment.chord, key) ||\n soundsAugmentedSixth(moment, key)\n );\n}\n\n/** Whether a voice reaches its note at `moment` by a diatonic step. */\nfunction approachedByStep(before: Moment | undefined, moment: Moment, voice: number): boolean {\n const earlier = before?.notes[voice];\n const later = moment.notes[voice];\n if (earlier === undefined || later === undefined) {\n return false;\n }\n return spelledInterval(earlier, later).number === 2;\n}\n\n/** Whether a voice is the bass or the top voice of its chord. */\nfunction isOuterVoice(voice: number, moment: Moment): boolean {\n return voice === 0 || voice === moment.notes.length - 1;\n}\n\n/**\n * Cross relations: the same letter carrying different accidentals in two\n * different voices across the chord change. Within one voice the same motion is\n * an ordinary chromatic inflection, so a voice is never compared with itself.\n *\n * What the rule forbids is a semitone exposed across the texture, and three\n * things take that exposure away, each of which is reason enough on its own:\n *\n * - either of the two notes is led into by step, which is how a chromatic tone\n * is introduced rather than sprung;\n * - both notes lie in inner voices, where the classical norm is markedly\n * milder than it is between the outer ones;\n * - the chord being left or reached is an applied dominant, the Neapolitan, or\n * an augmented sixth, whose definition contains the altered degree.\n *\n * Each pair of voices is reported once. The two voices are walked in both\n * directions, so the same clash is met twice and the second reading is dropped.\n */\nfunction crossRelationViolations(transition: Transition): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n const { from, to, key, before, after } = transition;\n const chromatic =\n isChromaticHarmony(from, to.chord, key) || isChromaticHarmony(to, after?.chord, key);\n const reported = new Set<string>();\n for (let first = 0; first < from.notes.length; first += 1) {\n for (let second = 0; second < to.notes.length; second += 1) {\n if (first === second) {\n continue;\n }\n const earlier = from.notes[first];\n const later = to.notes[second];\n if (earlier === undefined || later === undefined) {\n continue;\n }\n const letter = diatonicLetterOf(earlier.letter);\n if (letter !== diatonicLetterOf(later.letter) || earlier.alter === later.alter) {\n continue;\n }\n if (\n chromatic ||\n approachedByStep(before, from, first) ||\n approachedByStep(from, to, second) ||\n (!isOuterVoice(first, from) && !isOuterVoice(second, to))\n ) {\n continue;\n }\n const pair = `${letter}:${Math.min(first, second)}:${Math.max(first, second)}`;\n if (reported.has(pair)) {\n continue;\n }\n reported.add(pair);\n found.push(\n violation(\n 'crossRelation',\n [first, second],\n from.index,\n to.index,\n `${formatNote(bare(earlier))} is contradicted by ${formatNote(bare(later))} in another voice`,\n ),\n );\n }\n }\n return found;\n}\n\n/**\n * The rules judged along one line: augmented melodic intervals, and the tendency\n * tones that must go somewhere in particular.\n *\n * A chordal seventh is a dissonance, so the voice carrying it falls by step\n * unless the next chord holds it as a common tone. A leading tone rises to the\n * tonic when it is functioning as one — the third of a dominant chord or the\n * root of a leading-tone chord — and the next chord contains the tonic and has\n * dropped the leading tone itself. Elsewhere the same pitch class is an\n * ordinary chord tone, so `iii` moving to `IV` is not asked to resolve its\n * fifth. The rule is judged in every voice rather than the outer ones alone.\n */\nfunction melodicViolations(transition: Transition): PartWritingViolation[] {\n const found: PartWritingViolation[] = [];\n const { from, to, key } = transition;\n const seventhPc = seventhPcOf(from.chord);\n const nextPcs = new Set(chordPitchClasses(to.chord));\n const leadingTonePc = leadingTonePcOf(key);\n const tonicPc = pitchClassOf(key.rootPc);\n const voices = Math.min(from.notes.length, to.notes.length);\n for (let voice = 0; voice < voices; voice += 1) {\n const earlier = from.notes[voice];\n const later = to.notes[voice];\n const earlierPitch = from.pitches[voice];\n const laterPitch = to.pitches[voice];\n if (\n earlier === undefined ||\n later === undefined ||\n earlierPitch === undefined ||\n laterPitch === undefined\n ) {\n continue;\n }\n const interval = spelledInterval(earlier, later);\n if (isAugmentedMelodicInterval(earlier, later)) {\n found.push(\n violation(\n 'augmentedMelodicInterval',\n [voice],\n from.index,\n to.index,\n `The voice moves by an augmented ${intervalWord(interval.number)}`,\n ),\n );\n }\n const earlierPc = noteToPitchClass(earlier);\n if (earlierPc === seventhPc && !nextPcs.has(earlierPc) && !isDescendingStep(interval)) {\n found.push(\n violation(\n 'unresolvedSeventh',\n [voice],\n from.index,\n to.index,\n 'The chordal seventh does not fall by step',\n ),\n );\n }\n if (\n earlierPc === leadingTonePc &&\n isFunctioningLeadingTone(from.chord, key) &&\n nextPcs.has(tonicPc) &&\n !nextPcs.has(earlierPc) &&\n !isLeadingToneResolution(earlierPitch, laterPitch, key)\n ) {\n found.push(\n violation(\n 'unresolvedLeadingTone',\n [voice],\n from.index,\n to.index,\n 'The leading tone does not rise to the tonic',\n ),\n );\n }\n }\n return found;\n}\n\n/**\n * Spell a voicing given as MIDI pitches, so it can be checked by\n * {@link checkPartWriting}.\n *\n * Each pitch is named against the chord sounding under it and then the key, so a\n * chord tone takes the letter its interval above the root implies: the third of\n * a D major chord in C major spells F#, not Gb. The octave is kept, since the\n * rules measure real distances.\n *\n * @param voicing MIDI pitches, ascending (index 0 = lowest).\n * @param chord The chord sounding, supplying the enharmonic evidence.\n * @param key The key the exercise is written in.\n * @returns One spelled note per pitch, in the same order.\n * @example\n * ```ts\n * import { majorKey, makeChord, noteNames, spellVoicing } from '@libraz/libcantus';\n * noteNames(spellVoicing([50, 57, 66, 69], makeChord(2, 'maj'), majorKey(0)));\n * // ['D3', 'A3', 'F#4', 'A4'] — the third of D spells F# in C major\n * ```\n * @category Voicing & Counterpoint\n */\nexport function spellVoicing(\n voicing: readonly number[],\n chord: Chord,\n key: KeyScale,\n): SpelledVoicing {\n const { tonic } = spelledKeyOf(key);\n return voicing.map((pitch) => spellPitch(pitch, tonic, key, { chordRoot: chord.rootPc }));\n}\n\n/**\n * Check a finished part-writing exercise and report every rule it breaks.\n *\n * The voicings are given one per chord, each ascending with one spelled note per\n * voice (index 0 = lowest, the bass), the voice order {@link voiceChord} and\n * {@link SATB_RANGES} already use. Notes must carry octaves.\n *\n * Each chord is checked for voice crossing, over-wide spacing between adjacent\n * upper voices, and voices outside their range; each pair of consecutive chords\n * for parallel and hidden perfects, voice overlap, cross relations, augmented\n * melodic intervals, and unresolved tendency tones. Violations come back in\n * musical order: the rules inside a chord, then the rules taking it to the next.\n *\n * @param voicings One voicing per chord, ascending, in spelled notes.\n * @param chords The chords those voicings realize, in the same order.\n * @param key The key the exercise is written in; it names the leading tone.\n * @param opts Ranges and the upper-voice spacing limit. Both are validated\n * before any rule runs: an empty result has to mean that nothing was broken,\n * never that a rule could not be evaluated.\n * @returns Every violation found, in musical order; an empty array for a clean\n * exercise.\n * @throws If the two arrays differ in length, a note carries no octave, the\n * spacing limit is not a non-negative finite number, or the ranges are empty,\n * malformed, or too few for the voices being checked.\n * @example\n * ```ts\n * import { checkPartWriting, majorKey, makeChord, spellVoicing } from '@libraz/libcantus';\n * const key = majorKey(0);\n * const chords = [makeChord(0, 'maj'), makeChord(2, 'min')];\n * const voicings = [[48, 55, 64, 72], [50, 57, 65, 69]].map((pitches, i) =>\n * spellVoicing(pitches, chords[i] ?? chords[0], key),\n * );\n * const violations = checkPartWriting(voicings, chords, key);\n * violations.map((violation) => violation.kind); // ['parallelFifth']\n * violations[0]?.voices; // [0, 1]\n * ```\n * @category Voicing & Counterpoint\n */\nexport function checkPartWriting(\n voicings: readonly SpelledVoicing[],\n chords: readonly Chord[],\n key: KeyScale,\n opts?: PartWritingOptions,\n): PartWritingViolation[] {\n if (voicings.length !== chords.length) {\n throw new InvalidInputError(\n `checkPartWriting needs one chord per voicing; received ${voicings.length} voicings and ${chords.length} chords`,\n );\n }\n // The limits are resolved through the same validators the voicing search\n // uses, and before any rule runs: a NaN limit would silently switch the\n // spacing rule off, and ranges too short for the texture would leave the top\n // voices unjudged, both of which report as a clean exercise.\n const maxSpacing = resolveMaxSpacing(opts);\n const voiceCount = voicings.reduce((widest, voicing) => Math.max(widest, voicing.length), 0);\n let ranges: readonly Readonly<VoiceRange>[] | undefined;\n if (opts?.ranges === undefined) {\n // Four voices are the SATB exercise these ranges were written for; any other\n // count has no conventional compass, so an unasked-for range check would\n // invent one.\n ranges = voiceCount === 4 ? SATB_RANGES : undefined;\n } else {\n ranges = resolveRanges(opts);\n if (ranges.length < voiceCount) {\n throw new InvalidInputError(\n `checkPartWriting needs one range per voice; received ${ranges.length} ranges for ${voiceCount} voices`,\n );\n }\n }\n\n const moments: Moment[] = [];\n for (let index = 0; index < voicings.length; index += 1) {\n const notes = voicings[index];\n const chord = chords[index];\n if (notes === undefined || chord === undefined) {\n continue;\n }\n moments.push({\n notes,\n pitches: notes.map((note, voice) => midiOf(note, index, voice)),\n chord,\n index,\n });\n }\n\n const violations: PartWritingViolation[] = [];\n for (let position = 0; position < moments.length; position += 1) {\n const moment = moments[position];\n const previous = position > 0 ? moments[position - 1] : undefined;\n if (moment === undefined) {\n continue;\n }\n if (previous !== undefined) {\n const transition: Transition = {\n from: previous,\n to: moment,\n key,\n before: position > 1 ? moments[position - 2] : undefined,\n after: moments[position + 1],\n };\n violations.push(...pairViolations(transition));\n violations.push(...crossRelationViolations(transition));\n violations.push(...melodicViolations(transition));\n }\n violations.push(...verticalViolations(moment, ranges, maxSpacing));\n }\n return violations;\n}\n\nexport type { Species, SpeciesOptions } from './species.js';\nexport { checkSpecies } from './species.js';\n"],"mappings":"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","names":["verticalViolations","melodicViolations"]}
|