songleaf¶
songleaf: dense, readable one-page song sheets from searchable sources.
Find a song, keep it as lyrics plus anchored annotations (sections, chords, provenance, score links), and render it onto one A4 page with the lyrics as large as will fit.
>>> import songleaf
>>> song = songleaf.parse_chords_over_lyrics("C G\nHello there my friend")
>>> [a.body["symbol"] for a in song.of_kind("chord")]
['C', 'G']
From a query to a PDF, on the Kaggle chords-and-lyrics corpus:
songleaf.sheet("wonderwall oasis") # -> {'path': '.../sheets/oasis-wonderwall.pdf', ...}
or python -m songleaf sheet "wonderwall oasis".
Functions
|
A chord landing on the syllable that starts at offset |
|
The largest lyric font size at which |
|
The song named by |
|
The layout of a spec: options of |
|
The one spelling of a layout spec, for names: |
|
A |
|
Parse chords-over-lyrics text into a |
|
Render |
|
Render |
|
A link from |
|
Search every source and merge the hits, best first. |
|
A section (verse, chorus, ...) spanning |
|
Make a one-page song sheet (PDF) for the best match of |
|
Songs as JSON files in |
|
The keys of the stored songs. |
Classes
|
One annotation over |
|
Typography of the dense layouts. |
|
One search result: a song a source can |
|
The Kaggle chords-and-lyrics corpus (~135K songs, chords over lyrics). |
|
One way to lay a song out on a page. |
|
Lyrics text plus annotations, metadata and provenance. |
- class songleaf.Annotation(kind, start, end, body=<factory>)[source]¶
Bases:
objectOne annotation over
Song.text[start:end]; a point whenstart == end.
- class songleaf.DenseStyle(lyric_font='Helvetica', chord_font='Helvetica-Bold', label_font='Helvetica-Bold', title_font='Helvetica-Bold', lyric_color='#000000', chord_color='#3b73c4', label_color='#8c8c8c', separator_color='#a6a6a6', title_color='#595959', chord_scale=0.62, label_scale=0.5, title_scale=0.6, chord_rise=0.56, chord_halo='', chord_halo_width=0.16, ascent=0.72, descent=0.21, row_gap=0.06, paragraph_gap=0.3, separator=' / ', chord_gap=0.3, bare_chord_gap=0.9, label_gap=0.4, inline_chord_scale=0.7, inline_chord_rise=0.2, inline_chord_pad=0.15, before_marker='‹', column_gap=0.8, column_rule_color='#d9d9d9', chorus_shade='#f3efe4', bridge_shade='#e8eef6', band_pad=0.12, repeat_color='#4d4d4d', tonic_chord_color='#1c4a91', outside_chord_color='#c0602a')[source]¶
Bases:
objectTypography of the dense layouts. Lengths are fractions of the lyric font size.
- class songleaf.Hit(source, id, title, artist='', score=0.0, meta=<factory>)[source]¶
Bases:
objectOne search result: a song a source can
get().- property key: str¶
"<source>:<id>", the song’s name forget_song()and the store.
- class songleaf.KaggleChordsSource(*, loader=None, min_score=70)[source]¶
Bases:
objectThe Kaggle chords-and-lyrics corpus (~135K songs, chords over lyrics).
Read through
sungfrom a local copy of the zip, with no Kaggle credentials needed when that copy exists. The corpus was scraped from a chords site: personal use only (licence taggray).Title and artist are matched fuzzily (typos, punctuation and word order do not matter); lyrics must contain every word of the
lyricsquery as a whole word. Lyrics matches are not ranked beyond popularity.- Parameters:
loader –
() -> pandas.DataFramewithcolumns. Defaults to sung’s loader of the local corpus zip.min_score (
float) – Fuzzy-match cutoff, 0-100.
- class songleaf.SheetLayout(chords='over', packing='greedy', columns=1, shading=False, style=<factory>)[source]¶
Bases:
objectOne way to lay a song out on a page.
- Parameters:
chords (
str|ChordPlacement) – Where chords go:"over"(overlapping the lyric row) or"inline"(in the line, before their syllable), or anyChordPlacement.packing (
str|Callable) – Which lines share a row:"greedy"or"structured", or any packer with the signature ofsongleaf.packing.pack_greedy().columns (
int) – Columns per page.shading (
bool) – Shade sections, repeated lines and chord functions.style (
DenseStyle) – Typography and colours.
- property placement: ChordPlacement¶
The chord placement strategy.
- class songleaf.Song(text, annotations=<factory>, meta=<factory>, provenance=<factory>)[source]¶
Bases:
objectLyrics text plus annotations, metadata and provenance.
- Parameters:
text (
str) – The lyrics, lines separated by"\n".annotations (
list[Annotation]) – Standoff annotations overtext(kept sorted by start).meta (
dict) – Descriptive fields:title,artist,capo,key, …provenance (
dict) – Where the song came from:source,id,url,license.
- songleaf.chord(at, symbol, *, timing='at')[source]¶
A chord landing on the syllable that starts at offset
at.- Return type:
- songleaf.fit_font_size(song, *, page_size='A4', margin=14.0, style=None, layout=None, min_font_size=6.0, max_font_size=72.0, precision=0.05)[source]¶
The largest lyric font size at which
songfits one page inlayout(default: v1’s).style, if given, replaces the layout’s style. Returnsmin_font_sizeif even that does not fit (the song then needs more pages).- Return type:
- songleaf.get_song(key, *, sources=None)[source]¶
The song named by
key("<source>:<id>"), from the source of that name.- Return type:
- songleaf.layout_named(spec, *, style=None)[source]¶
The layout of a spec: options of
LAYOUT_OPTIONSjoined by+("inline+two-column").Options apply in order, over the v1 layout and
style(defaultDenseStyle).- Return type:
- songleaf.layout_spec(spec)[source]¶
The one spelling of a layout spec, for names:
"Dense"->"dense".- Return type:
>>> layout_spec("2col + INLINE"), layout_spec("dense+"), layout_spec("inline+2col+inline") ('two-column+inline', 'dense', 'two-column+inline')
- songleaf.make_renderer(layout='dense', **render_options)[source]¶
A
(song, output) -> dictrenderer forlayout, the shapesheet’srenderer=takes.render_optionsare passed torender_sheet()(page_size,margin, …). A bad spec fails here, not at render time.- Return type:
>>> make_renderer("packed+shaded").keywords["layout"].packing 'structured'
- songleaf.parse_chords_over_lyrics(raw, *, meta=None, provenance=None)[source]¶
Parse chords-over-lyrics text into a
Song.
- songleaf.render_dense_a4(song, output, *, page_size='A4', margin=14.0, style=None, min_font_size=6.0, max_font_size=72.0)[source]¶
Render
songin the v1 layout as a PDF tooutput(a path or a binary file object).The same as
render_sheet()withlayout="dense". Returns{"path", "font_size", "pages", "rows"};pathisNonewhenoutputis a file object.- Return type:
- songleaf.render_sheet(song, output, *, layout='dense', page_size='A4', margin=14.0, min_font_size=6.0, max_font_size=72.0)[source]¶
Render
songinlayout(aSheetLayoutor a spec) as a PDF tooutput.outputis a path or a binary file object. Returns{"path", "font_size", "pages", "rows"};pathisNonewhenoutputis a file object.- Return type:
- songleaf.score_link(start, end, *, source, id, url='', format='')[source]¶
A link from
[start, end)to a score snippet held by a source.- Return type:
- songleaf.search(query='', *, title='', artist='', lyrics='', limit=10, sources=None)[source]¶
Search every source and merge the hits, best first.
>>> search("paper boats", sources=[]) []
- songleaf.section(start, end, label)[source]¶
A section (verse, chorus, …) spanning
[start, end).- Return type:
- songleaf.sheet(query, *, output='', pick=1, refresh=False, layout='dense', sources=None, store=None, renderer=None)[source]¶
Make a one-page song sheet (PDF) for the best match of
query.querymay also be a song key, assearchandsongsshow them (kaggle_chords:1234): a stored song renders without searching, and the key of a known source is fetched from it directly.pickchooses the n-th best match instead of the best. The song is saved to the store;refreshfetches it from its source again, replacing the stored copy. The PDF goes tooutput, by default thesheetsdata directory.layoutisdense(the default), or options joined with+:overlap(chords over the words themselves),inline(chords in the line, before their syllable),packed(rows break where the lyrics do),two-column,shaded(sections, repeated lines and chord functions); for exampleinline+packed+two-column. Arendererdecides the layout itself, so it does not go withlayout.- Return type:
- songleaf.song_store(rootdir=None)[source]¶
Songs as JSON files in
rootdir(default: thesongsdata dir).- Return type:
Modules
What a chord does in its song's key, so that sheets can shade chords by function. |
|
The linked-artifact model: a song is lyrics text plus standoff annotations. |
|
Line packing: which consecutive lines of a paragraph share a row. |
|
Parse chords-over-lyrics text into a |
|
Render a song onto one dense page, with the lyrics as large as will fit. |
|
Where songs are found: sources, and a search that composes them. |
|
Where songs persist: a |
|
The single source of truth for every surface: plain functions, flat arguments, JSON-ready results. |