Rendered score analysis

Score analysis can be projected directly onto LilyPond output without changing the score:

score.show(analysis=True)

The Boolean option uses a readable composition-oriented preset. For a custom selection, or to derive harmony from only part of an ensemble, pass an options object:

from paeonia.annotations import AnalysisRenderOptions

options = AnalysisRenderOptions(
    source_staves=("marimba_right", "marimba_left"),
    harmony=True,
    roman_numerals=True,
    non_chord_tones=True,
)
score.show(analysis=options)

Dense numerical analyses are opt-in. The diagnostic preset enables every available annotation lane:

score.show(analysis=AnalysisRenderOptions.diagnostic())

Annotations are computed at render time, so edits made through a voice or score window are reflected on the next call. The same renderer-independent objects can be inspected without invoking LilyPond:

annotations = score.analysis_annotations(options)

API

Project score analyses into renderer-independent annotations.

Analysis data is computed when notation is requested instead of being stored on a Score. This prevents annotations from becoming stale when a score window or voice is edited and keeps engraving concerns out of paeonia.analysis.

class paeonia.annotations.AnalysisRenderOptions(source_staves=None, harmony=True, roman_numerals=True, non_chord_tones=True, voice_leading=True, voice_leading_summary=False, register_warnings=True, confidence=False, set_theory=False, density=False, scale_degrees=False, intervals=False, dissonances=False, doublings=False, bass_motion=False, min_confidence=0.0, leap_threshold=5)[source]

Bases: object

Choose which score analyses are included in rendered notation.

The defaults form a readable composition-oriented preset. They show harmony, non-chord tones, and exceptional voice-leading or registral events while leaving dense numerical diagnostics disabled. Use diagnostic() to enable every available analysis lane.

source_staves limits the musical material used for analysis without limiting which staves are rendered. This is useful, for example, when a pair of keyboard staves establishes harmony for a larger ensemble.

Parameters:
  • source_staves (tuple[str, ...] | None)

  • harmony (bool)

  • roman_numerals (bool)

  • non_chord_tones (bool)

  • voice_leading (bool)

  • voice_leading_summary (bool)

  • register_warnings (bool)

  • confidence (bool)

  • set_theory (bool)

  • density (bool)

  • scale_degrees (bool)

  • intervals (bool)

  • dissonances (bool)

  • doublings (bool)

  • bass_motion (bool)

  • min_confidence (float)

  • leap_threshold (int)

source_staves: tuple[str, ...] | None
harmony: bool
roman_numerals: bool
non_chord_tones: bool
voice_leading: bool
voice_leading_summary: bool
register_warnings: bool
confidence: bool
set_theory: bool
density: bool
scale_degrees: bool
intervals: bool
dissonances: bool
doublings: bool
bass_motion: bool
min_confidence: float
leap_threshold: int
classmethod diagnostic(*, source_staves=None)[source]

Return a preset enabling every available analysis lane.

Parameters:

source_staves (tuple[str, ...] | None)

Return type:

AnalysisRenderOptions

class paeonia.annotations.ScoreAnnotation(bar_index, offset, duration, lane, text, staff_name=None, source=None)[source]

Bases: object

A textual analysis label positioned in one score bar.

Offsets and durations use Paeonia’s whole-note units. staff_name is None for a global label, which renderers normally place over the first staff. source identifies an exact event and chord pitch when the underlying analysis can provide that identity.

Parameters:
  • bar_index (int)

  • offset (Fraction)

  • duration (Fraction)

  • lane (str)

  • text (str)

  • staff_name (str | None)

  • source (EventReference | None)

bar_index: int
offset: Fraction
duration: Fraction
lane: str
text: str
staff_name: str | None
source: EventReference | None
paeonia.annotations.normalize_analysis_render_options(analysis)[source]

Normalize a public rendering option into an options object or none.

Parameters:

analysis (bool | AnalysisRenderOptions)

Return type:

AnalysisRenderOptions | None

paeonia.annotations.score_annotations(score, options=None)[source]

Compute fresh display annotations for an aligned score.

Tonality-independent lanes remain available when selected staves do not share a tonal context. In that situation chord symbols are inferred from pitch classes, while Roman numerals, scale degrees, and non-chord-tone classifications are omitted rather than assigned against an arbitrary key.

Parameters:
Return type:

tuple[ScoreAnnotation, …]