Wrap plain arrangement data.
The tracks and the settings they are read under; copied, never retained.
The tracks as they were given, in that order.
The reading of the whole arrangement: the key regions, the harmony, the cadences, each track's annotated notes, and the conflicts.
The analysis analyzeArrangement makes of these tracks.
The notes clashing with the harmony sounding beneath them, worst severity first.
Every ordinary non-chord tone — a passing note, a neighbour, a prepared suspension — is unsafe against the chord under it by definition, so this is a report rather than a fault list; each conflict carries the note's labels to tell those apart.
A copy of the underlying plain data.
StaticofBuild an arrangement from tracks.
A track carrying no name is named for its position — 'track 1',
'track 2' — which is the name the analysis reports for it, and the name
Arrangement.track finds it under. A track carrying no role plays
'other'; only 'drums' changes the analysis, whose pitches name
instruments rather than harmony and are kept out of the inferred key and
chords.
The tracks, in the order the caller holds them.
Optionalopts: ArrangementSetup
The key, meter, harmony and budget to read them under; see ArrangementSetup.
The arrangement.
StaticfromRebuild an arrangement from the plain data Arrangement.data hands out.
StaticfromRebuild an arrangement from its Arrangement.toJSON output.
One track's notes as a score, or undefined when no track carries the name.
The score is read against the arrangement's meter, and against its key when the arrangement was given one; the harmony the tracks spell out together is what Arrangement.analysis and Arrangement.timeline report, since a track read on its own is not read against what sounds beneath it. A score holds its notes in time order, which is not necessarily the order this track's notes arrived in.
The track's name, as the analysis reports it.
The score, or undefined.
Re-analyse after replacing the notes of one or more tracks.
The analysis is not made again from nothing: the open reading works out which beats the edit could have reached, recomputes those, and carries the rest over, and the arrangement returned takes that analysis on. What it reports is what a fresh Arrangement.of over the edited tracks reports — the same segments, keys, cadences, annotations and conflicts; only the work differs.
The tracks whose notes changed, each with the notes it holds after the edit.
A new arrangement over the edited tracks; this one is unchanged.
import { Arrangement } from '@libraz/libcantus';
const arrangement = Arrangement.of([
{ name: 'lead', notes: [{ pitch: 60, startBeat: 0, durationBeat: 4 }] },
]);
const moved = arrangement.update([
{ trackIndex: 0, notes: [{ pitch: 62, startBeat: 0, durationBeat: 4 }] },
]);
moved.tracks[0]?.notes[0]?.pitch; // 62
arrangement.tracks[0]?.notes[0]?.pitch; // 60
The harmonic tension across the arrangement, sampled at regular beats.
The harmony is the one the arrangement already found, so the curve and the annotations describe the same chords rather than two readings of the same notes.
Naming a key, its regions, or the tracks the harmony is read from asks for a harmony this arrangement did not find, so the curve is read under the one named rather than over the one it holds.
Optionalopts: ArrangementTensionOptions
The sampling step, and any setting to lay over the
arrangement's own; a meter named here replaces the arrangement's, since
ts and meters name the same thing.
One tension reading per sampled beat, in beat order.
The whole reading of the arrangement in one call, made afresh.
Arrangement.analysis answers the same question about the arrangement as it stands, and is the member to reach for: it is made once and kept across edits. This one runs analyzeArrangement again over the same tracks under settings laid on top of the arrangement's own, which is what a caller narrowing the conflict list, restricting the harmony to a few tracks, or reading the piece against a key it does not carry wants — without building a second arrangement to hold that reading.
Optionalopts: ArrangementSetup
Any setting to lay over the arrangement's own; a meter named
here replaces the arrangement's, since ts and meters name the same
thing.
The inferred harmony, per-track annotations, cadences, and conflicts.
The harmony the tracks spell out together, in time.
The inferred timeline, carrying the key regions the analysis found under it.
Whether another arrangement holds the same tracks under the same settings.
The comparison is made through the other arrangement's public data, so two arrangements built by different copies of the module still compare. The analysis is not compared: it is what these tracks and these settings produce, so two arrangements agreeing on both agree on it.
The arrangement to compare.
True when the tracks and the settings match.
The plain form of the arrangement, for JSON.stringify.
Several named tracks read together, with the analysis of how they fit.
One harmony is inferred from every pitched track pooled together, each track is annotated against it, and the notes that clash with the chord sounding beneath them are collected as conflicts — the whole of analyzeArrangement, held as a value instead of as a call whose result a caller has to carry alongside the notes it was made from.
The analysis is held open across edits: Arrangement.update works out which beats an edit could have reached and recomputes those, so a host that re-analyses on every keystroke pays for the beats that changed. The arrangement it returns is a new one — an arrangement never changes, so the reading taken before an edit stays valid and a host can keep it for undo.
A member that has another class to answer with answers with it: Arrangement.track hands back a Score and Arrangement.timeline a Timeline, so a caller stays in the class API rather than being handed the arrays behind it.
Example