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

    Class Arrangement

    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.

    import { Arrangement } from '@libraz/libcantus';
    const arrangement = Arrangement.of([
    { name: 'melody', role: 'melody', notes: [{ pitch: 72, startBeat: 0, durationBeat: 4 }] },
    { name: 'bass', role: 'bass', notes: [{ pitch: 48, startBeat: 0, durationBeat: 4 }] },
    ]);
    arrangement.track('melody')?.totalBeats; // 4
    Index
    • get conflicts(): Conflict[]

      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.

      Returns Conflict[]

    • Build 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.

      Parameters

      Returns Arrangement

      The arrangement.

      import { Arrangement } from '@libraz/libcantus';
      const arrangement = Arrangement.of(
      [{ name: 'lead', notes: [{ pitch: 60, startBeat: 0, durationBeat: 4 }] }],
      { key: 'C major' },
      );
      arrangement.tracks.length; // 1
    • 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.

      Parameters

      • name: string

        The track's name, as the analysis reports it.

      Returns Score | undefined

      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.

      Parameters

      • edits: readonly TrackEdit[]

        The tracks whose notes changed, each with the notes it holds after the edit.

      Returns Arrangement

      A new arrangement over the edited tracks; this one is unchanged.

      If an edit names no track of this arrangement, or carries a note the analysis cannot read.

      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.

      Parameters

      • 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.

      Returns TensionPoint[]

      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.

      Parameters

      • 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.

      Returns ArrangementAnalysis

      The inferred harmony, per-track annotations, cadences, and conflicts.

      If a setting carries a value the analysis cannot hold, or the tracks exceed the budget.

    • 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.

      Parameters

      Returns boolean

      True when the tracks and the settings match.