One voicing per chord, in voice order, in spelled notes.
The chords those voicings realize, in the same order.
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.
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]
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.