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

    Type Alias HarmonizeOptions

    Options controlling harmonizeMelody.

    Only melody is required; every other knob has the default a first call wants.

    type HarmonizeOptions = {
        melody: readonly MelodyNote[];
        key?: KeyLike | "infer";
        harmonicRhythm?: number;
        ts?: MeterLike;
        reharmonize?: "diatonic" | "secondaryDominant" | "borrowed";
        placement?: HarmonizePlacement;
        phraseEnds?: readonly number[];
        ctx?: GenerationContextInput;
        budget?: number;
    }
    Index
    melody: readonly MelodyNote[]

    The melody to harmonize, in ascending onset order.

    key?: KeyLike | "infer"

    The key to harmonize in, or 'infer' to estimate it from the melody's pitch-class weighting — which is what a caller who has only a melody wants, and so the default. A key name such as 'C major' is read as that key; 'infer' names no key and always asks for the estimate.

    'infer'

    harmonicRhythm?: number

    Length of each chord slot in beats. Harmonization places chords on a fixed grid of this length — unlike chordTimelineFromNotes, which searches for the boundaries an existing piece already implies. Any positive value is honoured; a value fine enough to make the search explode is rejected by the generation budget rather than rounded up.

    Left out, it is read from ts: half a bar where the half falls on a pulse, and the whole bar where it does not, so a waltz changes chord on its downbeats rather than across them. In 4/4 that is one chord per half bar.

    half a bar of ts — 2 in 4/4

    Time signature the melody is barred in. It weights the metric accents the chords are chosen against and sets the default chord grid, so a waltz or a jig is harmonized on its own beats rather than on a 4/4 reading of them.

    4/4

    reharmonize?: "diatonic" | "secondaryDominant" | "borrowed"

    How far beyond the key's own triads the chord vocabulary reaches: 'diatonic' uses only them, 'secondaryDominant' adds the dominants that tonicize each degree, and 'borrowed' adds the parallel mode's chords too.

    Sugar for ctx: { complexity: { harmonic } } at the three dial positions these names have always stood for; a context names how far the vocabulary reaches instead of which of three steps it stops at, and wins where both are given.

    'diatonic'

    placement?: HarmonizePlacement

    Whether to search transpositions and octave placements for the melody. Both are off by default, so the melody is harmonized where it was written.

    both false
    
    phraseEnds?: readonly number[]

    Beats at which the melody's phrases end, so a longer line closes at each of them instead of only at its end.

    Naming a beat asks for a close there, and three things follow from it. The beat divides the chord grid, so the slot the phrase closes in ends where the phrase does rather than running on into the next one. The harmony moves into that slot — the chord under a named close is never the chord that was already sounding, which is what makes the close audible as one. And the note the phrase comes to rest on is read as a structural tone rather than as an ornament of the next phrase's first note, so a phrase resting on the tonic is harmonized by the tonic.

    Which cadence that close forms is still the melody's to decide: a phrase coming to rest on the tonic over an approach that can carry the dominant cadences authentically, and one whose approach cannot is harmonized by what it sounds.

    The melody always closes where it ends, whatever this says; these are the closes inside it. phrasesFromTimeline finds the phrases of a line already labelled with chords, and its endBeat values are what this expects, so a caller harmonizes a whole piece in one call rather than harmonizing each phrase and joining the results.

    A boundary landing exactly on a chord-slot boundary closes the slot before it — the beat a phrase ends on is where the next phrase begins.

    noneone close, at the end
    

    The generation context. Its complexity.harmonic is how far the chord vocabulary reaches beyond the key's own triads — 0 uses them alone, 0.5 has every secondary dominant, 1 the parallel mode's chords as well — and its seed drives the deterministic tie-break perturbation.

    { seed: 0 }

    budget?: number

    Upper bound on the work this call may do. The search is one pass per placement over every pair of candidate chords in every slot, so a long line harmonized with placement.transposeSearch on is what needs this raised.