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

    Function evaluateComposition

    • Check a candidate melody against the plan it was written for.

      The candidate is read against the plan itself — its phrases, its harmony through planTimeline, its derivations — rather than re-analyzed into a profile, so every violation and fit reading judges the melody against what the plan actually calls for.

      Violations name concrete departures at a beat. span, phraseBoundary, cadence, register and motifDerivation are errors. harmony is an error, or a warning for a note inside a derived statement, where the transformation takes precedence. A derived statement passes at any pitch level its relation admits, with its durations free and its closing and out-of-register notes excused; motifDisplaced warns when that level is not the planned one or a note was excused. peakPosition is a warning. The fit fields, one per dimension, read each planned phrase of the candidate the way a reference profile reads its phrases and measure it as compareReferences would — never folded into one score.

      Parameters

      Returns CompositionEvaluation

      The violations found and the fit reading.

      If the plan or the melody cannot be read.

      If an analysis would exceed the budget.

      import { evaluateComposition, planTimeline, resolveKey } from '@libraz/libcantus';
      import type { CompositionPlan } from '@libraz/libcantus';
      const plan: CompositionPlan = {
      planVersion: 1, seed: 0, algorithmVersion: 1,
      keys: [resolveKey('C major')],
      meters: [{ startBeat: 0, ts: { numerator: 4, denominator: 4 } }],
      span: { startBeat: 0, endBeat: 4, bars: 1 },
      sections: [{ label: 'A', startBeat: 0, endBeat: 4 }],
      phrases: [
      {
      startBeat: 0, endBeat: 4, section: 0, cadence: null, shape: 'ascending',
      peakPosition: 0.5, register: { low: 60, high: 67, mean: 64 }, onsetDensity: 4, motifs: [],
      },
      ],
      harmony: [{ startBeat: 0, endBeat: 4, key: 0, roman: 'I' }],
      motifs: [],
      rhythm: { onsetLevels: [0, 0, 0, 1, 0, 0], interOnsetShares: new Array(17).fill(0).fill(1, 8, 9), syncopation: 0 },
      };
      const melody = [
      { pitch: 60, startBeat: 0, durationBeat: 1 },
      { pitch: 64, startBeat: 1, durationBeat: 1 },
      { pitch: 67, startBeat: 2, durationBeat: 1 },
      { pitch: 60, startBeat: 3, durationBeat: 1 },
      ];
      evaluateComposition(melody, plan).violations; // []