The chord segments to analyze, in time order; pass a chord
timeline's segments.
Analysis options; see KeyTimelineOptions.
The key regions in time order; empty when no chords were given.
import { chordTimelineFromNotes, detectModulations } from '@libraz/libcantus';
const notes = [
{ pitch: 60, startBeat: 0, durationBeat: 4 },
{ pitch: 64, startBeat: 0, durationBeat: 4 },
{ pitch: 67, startBeat: 0, durationBeat: 4 },
];
const { timeline } = chordTimelineFromNotes(notes);
const regions = detectModulations(timeline.segments);
Infer where the key changes from a chord sequence, naming the pivot chords.
Each chord segment is one slot of the same search keyTimelineFromNotes runs, scored by how well the chord belongs to each key rather than by a pitch-class profile — a dominant seventh argues for its key far more strongly than its three or four pitch classes alone would suggest. Where the key changes, the chord sounding into the boundary is reported as the pivot if it reads in both keys.
The chords supply the slots, so
minKeyBeatscannot size them as it does in the note path; a region shorter than it is folded into the neighbouring key that reads its chords best instead, which is the same guarantee — a shorter region is reported only where the analyzed span itself ends, or across a gap in the chords that no neighbour adjoins.profilescores each region's confidence, as it does in the note path, but takes no part in choosing which keys are reported: that is settled by how the chords read.A region's evidence is the run of segments it was grouped from, which is the same reading the search itself makes of them. Where the segments given overlap each other — a chart is a sequence, so a chord timeline's are not — a chord held past the segment after it argues for its own segment's key rather than for both.