Score

The top-level object. Owns all staves, manages system layout and reflow, and is the primary entry point for adding notes and rendering.

pylute.Score score.py
PyLute Score object rendered — two-staff layout with all notation elements
A Score with staffs=2, key="G", time=(4,4), 8 bars — treble + bass grand staff.

Constructor

class Score
Top-level score object. Creates and owns all Staff, Bar, and notation element instances.
Score(
    surface=None,
    staffs=1,
    length=500,
    bars=3,
    clef_types=None,
    key="C",
    time=(4, 4),
    bars_per_system=None,
)
ParameterTypeDefaultDescription
surfacepygame.Surface | NoneNoneRender target. Can be set later: score.surface = screen. Required before draw().
staffsint1Number of staves. Use 2 for piano grand staff (treble + bass). Staves are indexed 0-based.
lengthint500Staff width in pixels. Affects bar spacing and how many bars fit per system.
barsint3Total number of bars per staff across all systems. Create more bars than you need — full bars are silently skipped by addNote().
clef_typeslist[str] | NoneNoneClef for each staff. ["treble", "bass"] for piano. Defaults to all "treble" if omitted.
keystr | int"C"Key signature as a name ("G", "Bb", "F#", "Cb") or a signed accidental count (−7 to +7). 0 or "C" = no accidentals.
timetuple[int, int](4, 4)Time signature as (beats_per_bar, beat_type). E.g. (3, 4) for waltz, (6, 8) for compound duple.
bars_per_systemint | NoneNoneOverride the automatic bars-per-system calculation. Useful for fixed-width layouts.

Object hierarchy

score = pylute.Score(staffs=2, bars=8, key="G", time=(3, 4))

score.staffs          # [Staff, Staff]
score.staffs[0].bars  # [Bar, Bar, Bar, Bar, Bar, Bar, Bar, Bar]
score.staffs[0].bars[0].events  # [] initially, filled by addNote()
Diagram: Score → Staff → Bar → Note/Rest hierarchy Add docs/img/pylute-hierarchy.png

Properties

PropertyTypeDescription
surfacepygame.Surface | NoneActive render target. Update on every VIDEORESIZE event.
staffslist[Staff]All Staff objects, one per staff line.
timetuple[int, int]Time signature as (beats, beat_type).
key_accidentalsintSigned accidental count. Negative = flats, positive = sharps.
key_notesdict[str, str]Accidentals in the current key, e.g. {"F": "#"} for G major. Used internally to apply key accidentals to note rendering.
frontal_offsetintPixel width of the frontal area (clef + key signature + time signature) before bar 1. Read-only.
title / subtitle / composer / lyricist / copyrightstrMetadata strings. Populated automatically by load_musicxml(). Empty string by default.
clefslist[Clef]One Clef per staff, in order.
braceBrace | NoneVertical brace connecting staves. Created automatically when staffs > 1.

Methods

addNote(ntype="whole", pitch="C4", staff_index=0) → None

Append a note to the next available position across all bars on the given staff. Automatically advances to the next bar when the current bar is at capacity. If all bars are full, the note is silently dropped.

ParameterTypeDescription
ntypestrDuration: "whole", "half", "quarter", "eighth", "sixteenth", "dotted_half", "dotted_quarter", "dotted_eighth".
pitchstrScientific pitch notation. Octave 4 = middle C octave. Examples: "C4", "F#4", "Bb3", "D5".
staff_indexintWhich staff to add to (0 = first, 1 = second, etc.).
addRest(rtype="quarter", staff_index=0) → None

Append a rest. Identical behaviour to addNote() but with no pitch. Accepts the same duration types.

draw() → None

Render the complete score to self.surface. Reads the current surface size and reflows all systems. Call this once per frame inside your pygame loop, after clearing the screen. Has no effect if surface is None.

total_content_height(canvas_w=None) → int

Returns the total pixel height required for all systems at a given canvas width. Called by ScoreCanvas to compute the scrollable area. Pass a width to simulate the layout at that width.

system_height() → int

Height in pixels of a single system (all staves + inter-staff gaps). Constant across all systems in the score.

system_y_tops() → list[int]

Y coordinates of the top line of each system. Used by ScorePager to compute page breaks at system boundaries.

Example

import pygame as pg
import pylute

pg.init()
screen = pg.display.set_mode((1200, 700), pg.RESIZABLE)

# Piano grand staff, G major, 3/4 (waltz)
score = pylute.Score(
    surface=screen,
    staffs=2,
    length=1100,
    bars=16,
    clef_types=["treble", "bass"],
    key="G",
    time=(3, 4),
)

# Add melody to treble staff
for pitch in ["D5", "B4", "G4", "A4", "B4", "C5", "D5", "G4"]:
    score.addNote("quarter", pitch, staff_index=0)

# Add bass line
score.addNote("quarter", "G3", staff_index=1)
score.addNote("half", "G2", staff_index=1)

clock = pg.time.Clock()
while True:
    for event in pg.event.get():
        if event.type == pg.QUIT: pg.quit(); exit()
        if event.type == pg.VIDEORESIZE:
            screen = pg.display.set_mode(event.size, pg.RESIZABLE)
            score.surface = screen

    screen.fill((255, 255, 255))
    score.draw()
    pg.display.flip()
    clock.tick(60)