@libraz/libcantus - v1.1.0
    Preparing search index...

    Function checkPartWriting

    • Check a finished part-writing exercise and report every rule it breaks.

      The voicings are given one per chord, each with one spelled note per voice in voice order (index 0 = bass), the order voiceChord and SATB_RANGES already use. Notes must carry octaves. A crossing is reported rather than rejected.

      Each chord is checked for voice crossing, over-wide spacing between adjacent upper voices, and voices outside their range; each pair of consecutive chords for parallel and hidden perfects, voice overlap, cross relations, augmented melodic intervals, and unresolved tendency tones. Violations come back in musical order: the rules inside a chord, then the rules taking it to the next.

      Parameters

      • voicings: readonly SpelledVoicing[]

        One voicing per chord, in voice order, in spelled notes.

      • chords: readonly ChordData[]

        The chords those voicings realize, in the same order.

      • keyLike: KeyLike

        The key the exercise is written in; it names the leading tone.

      • Optionalopts: PartWritingOptions

        Ranges and the upper-voice spacing limit. Both are validated before any rule runs: an empty result has to mean that nothing was broken, never that a rule could not be evaluated.

      Returns PartWritingViolation[]

      Every violation found, in musical order; an empty array for a clean exercise.

      If the two arrays differ in length, a note carries no octave, the spacing limit is not a non-negative finite number, or the ranges are empty, malformed, or too few for the voices being checked.

      import { checkPartWriting, majorKey, makeChord, spellVoicing } from '@libraz/libcantus';
      const key = majorKey(0);
      const chords = [makeChord(0, 'maj'), makeChord(2, 'min')];
      const voicings = [[48, 55, 64, 72], [50, 57, 65, 69]].map((pitches, i) =>
      spellVoicing(pitches, chords[i] ?? chords[0], key),
      );
      const violations = checkPartWriting(voicings, chords, key);
      violations.map((violation) => violation.kind); // ['parallelFifth']
      violations[0]?.voices; // [0, 1]