Skip to main content

songleaf

Dense, readable one-page song sheets: lyrics and chords on one A4 page, with the lyrics as large as will fit.

pip install songleaf
python -m songleaf sheet "wonderwall oasis"    # -> a one-page PDF in ~/.local/share/songleaf/sheets/

The default source is the Kaggle chords-and-lyrics corpus (about 135,000 songs), read from a local copy of its zip (see Sources).

What the sheet looks like

  • One page, largest type that fits. The lyric font size is found by search for each song. On 1,500 randomly sampled corpus songs, the median came out around 22 pt, and 1,498 of the 1,500 fit on one page. A song that cannot fit at the minimum size spills onto a second page.
  • Chords take no line of their own. They are smaller and blue, start over the syllable they land on, and overlap the tops of the letters of their lyric line.
  • Lines share rows. Consecutive lines of a paragraph are packed onto one row, separated by a light /. A blank line or a new section starts a new row.
  • Small labels. Sections are grey prefixes (V1, Ch, Br); title, artist, capo and key are one small line at the top.

Command line

python -m songleaf search "wonderwall oasis"              # fuzzy: typos and word order don't matter
python -m songleaf search --artist oasis --lyrics "roads winding"
python -m songleaf sheet "wonderwall oasis" --output wonderwall.pdf
python -m songleaf sheet "wonderwall oasis" --pick 2      # the second-best match
python -m songleaf songs                                  # songs already stored
python -m songleaf sheet kaggle_chords:1234               # a song by its key: no search
python -m songleaf sheet kaggle_chords:1234 --refresh     # fetch it again from its source

The songleaf console script is the same command.

Python

import songleaf

hits = songleaf.search("wonderwall oasis")
song = songleaf.get_song(hits[0].key)  # a Song: lyrics text + annotations
songleaf.render_dense_a4(song, "wonderwall.pdf")  # {'font_size': ..., 'pages': 1, ...}

songleaf.sheet("wonderwall oasis")  # search, store and render in one call

The song model

A Song is lyrics text plus standoff annotations anchored on character offsets, so annotation layers never touch the text:

  • section: spans its lines, {"label": "Chorus"};
  • chord: a point on the first character of the syllable the chord lands on, {"symbol": "G/B", "timing": "at"} ("before" marks a chord that sounds ahead of that syllable);
  • score: a link from a stretch of lyrics to a score snippet, {"source", "id", "url", "format"}.

Metadata (title, artist, capo, key) and provenance (source, id, url, licence) travel with the song, and Song.to_dict() is its JSON form.

from songleaf import Song, chord, section, parse_chords_over_lyrics

song = Song(
    "Paper boats drift", [section(0, 17, "Verse 1"), chord(0, "G"), chord(6, "D")]
)
song = parse_chords_over_lyrics(
    "G     D\nPaper boats drift"
)  # the same chords, from a chart

Storage

Songs are kept in a MutableMapping (songleaf.song_store()): one JSON file per song under ~/.local/share/songleaf/songs/. Rendered sheets go to ~/.local/share/songleaf/sheets/. Set SONGLEAF_DATA_DIR to move both.

Sources

KaggleChordsSource reads the chords-and-lyrics dataset through sung. It needs a local copy of the zip: point SUNG_CHORDS_AND_LYRICS_ZIP at it, or keep it where haggle downloads it ($HAGGLE_ROOTDIR/zips/eitanbentora/chords-and-lyrics-dataset.zip). Without a local copy, sung downloads it from Kaggle, which needs Kaggle credentials. The corpus was scraped from a chords site, so keep it to personal use.

Loading the corpus takes about five seconds on the first search in a process.

Extending

Three keyword arguments are the extension points, on sheet (and search for sources):

  • sources=: objects with a name, search(query, *, title, artist, lyrics, limit) returning Hits, and get(song_id) returning a Song;
  • store=: any MutableMapping[str, Song] (a dict works);
  • renderer=: any (song, output) -> dict function.
songleaf.sheet("paper boats", sources=[my_source], store={}, renderer=my_renderer)

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

songleaf-0.0.2.tar.gz (30.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

songleaf-0.0.2-py3-none-any.whl (24.5 kB view details)

Uploaded Python 3

File details

Details for the file songleaf-0.0.2.tar.gz.

File metadata

  • Download URL: songleaf-0.0.2.tar.gz
  • Upload date:
  • Size: 30.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.14 {"installer":{"name":"uv","version":"0.12.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for songleaf-0.0.2.tar.gz
Algorithm Hash digest
SHA256 ff50051b800dbe1dc5a0e16308478b4833b65835e61ace5f0efaf64ff7260525
MD5 3d161abd28c68910e7f624f0c57fb76f
BLAKE2b-256 625aabc85e18bc3f234249e016bab5081648d9cbf5afb965b05e30f64166ba31

See more details on using hashes here.

File details

Details for the file songleaf-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: songleaf-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 24.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.14 {"installer":{"name":"uv","version":"0.12.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for songleaf-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 44d59406c966c969bf7827cc2fefc2647037ffea5be316261744baab329bfb3d
MD5 bad4b19113c2095f88baa5067d8c125e
BLAKE2b-256 0c90874f5975f166caadc7fada356bcfa6a5d60b21fdf170f565a0e1b57bd866

See more details on using hashes here.

Release history Release notifications | RSS feed

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

This release

0.0.2 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page