The melody motifs was extracted from. Notes that never sound
are dropped, exactly as extractMotifs drops them, so the two agree
on which note an occurrence's noteIndex addresses.
The motifs to graph, as extractMotifs reports them.
Key context, the variation threshold, and a work budget; see MotifGraphOptions.
The statements as nodes, and the derivation drawn to each from an earlier one.
import { extractMotifs, motifGraph } from '@libraz/libcantus';
const notes = [
{ pitch: 60, startBeat: 0, durationBeat: 1 },
{ pitch: 62, startBeat: 1, durationBeat: 1 },
{ pitch: 64, startBeat: 2, durationBeat: 1 },
{ pitch: 67, startBeat: 4, durationBeat: 1 },
{ pitch: 69, startBeat: 5, durationBeat: 1 },
{ pitch: 71, startBeat: 6, durationBeat: 1 },
];
const graph = motifGraph(notes, extractMotifs(notes));
graph.edges[0]?.relation?.kind; // 'transposition'
Read a melody's motif statements as a derivation forest.
Every statement after the first is compared against every statement that precedes it: the pair relateMotifs can name outranks any it cannot, the closest-scoring precedent among equals outranks the rest, and a statement whose best precedent is neither named nor close enough by
melodicSimilarityis a root — new material, not a derivation of what came before it. The derivation traced this way explains a subject restated, transposed, inverted, augmented, or loosely varied by what it grew out of, and leaves a truly new idea unattached rather than forcing it onto whatever came earliest.motifsis read againstlinerather than against its own prime statements: an occurrence's notes can differ from the motif's first statement in duration even where their intervals and onset gaps agree, and a retrograde reading depends on that duration. So every occurrence is read back offlineand named fresh, occurrence to occurrence.