Score
The top-level object. Owns all staves, manages system layout and reflow, and is the primary entry point for adding notes and rendering.
Constructor
Score(
surface=None,
staffs=1,
length=500,
bars=3,
clef_types=None,
key="C",
time=(4, 4),
bars_per_system=None,
)
| Parameter | Type | Default | Description |
|---|---|---|---|
| surface | pygame.Surface | None | None | Render target. Can be set later: score.surface = screen. Required before draw(). |
| staffs | int | 1 | Number of staves. Use 2 for piano grand staff (treble + bass). Staves are indexed 0-based. |
| length | int | 500 | Staff width in pixels. Affects bar spacing and how many bars fit per system. |
| bars | int | 3 | Total number of bars per staff across all systems. Create more bars than you need — full bars are silently skipped by addNote(). |
| clef_types | list[str] | None | None | Clef for each staff. ["treble", "bass"] for piano. Defaults to all "treble" if omitted. |
| key | str | int | "C" | Key signature as a name ("G", "Bb", "F#", "Cb") or a signed accidental count (−7 to +7). 0 or "C" = no accidentals. |
| time | tuple[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_system | int | None | None | Override 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()
Properties
| Property | Type | Description |
|---|---|---|
| surface | pygame.Surface | None | Active render target. Update on every VIDEORESIZE event. |
| staffs | list[Staff] | All Staff objects, one per staff line. |
| time | tuple[int, int] | Time signature as (beats, beat_type). |
| key_accidentals | int | Signed accidental count. Negative = flats, positive = sharps. |
| key_notes | dict[str, str] | Accidentals in the current key, e.g. {"F": "#"} for G major. Used internally to apply key accidentals to note rendering. |
| frontal_offset | int | Pixel width of the frontal area (clef + key signature + time signature) before bar 1. Read-only. |
| title / subtitle / composer / lyricist / copyright | str | Metadata strings. Populated automatically by load_musicxml(). Empty string by default. |
| clefs | list[Clef] | One Clef per staff, in order. |
| brace | Brace | None | Vertical brace connecting staves. Created automatically when staffs > 1. |
Methods
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.
| Parameter | Type | Description |
|---|---|---|
| ntype | str | Duration: "whole", "half", "quarter", "eighth", "sixteenth", "dotted_half", "dotted_quarter", "dotted_eighth". |
| pitch | str | Scientific pitch notation. Octave 4 = middle C octave. Examples: "C4", "F#4", "Bb3", "D5". |
| staff_index | int | Which staff to add to (0 = first, 1 = second, etc.). |
Append a rest. Identical behaviour to addNote() but with no pitch. Accepts the same duration types.
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.
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.
Height in pixels of a single system (all staves + inter-staff gaps). Constant across all systems in the score.
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)