The songsheet package

A python module for working with songsheets. Songsheets (or leadsheets) are simple sheets showing a song’s lyrics, chords, progression patterns and other metadata.

chordpro is an existing standard serving a similar purpose. Why another implementation? A few reasons:

  • chordpro’s non-parsed format is a bit hard-to-read. It requires inserting chords in special tags before the syllable. songsheet’s non parsed text format is just as you’d write it: chords above the lyrics.
  • chordpro’s parsed text is the output format and not particularly machine-readable. Its non-parsed text is also not machine-readable. In contrast, songsheet’s parsed format is JSON. This allows developers to easily extract, store and index lyrics, chords and meta data in databases etc.
  • songsheet is flexible. You can give it JSON and it will deserialize into readable plain-text HTML, PDFs and chordpro format. You can give it readable plain-text or chordpro text and it will serialize it to JSON.
  • Chord validation and normalization. Unless you feed it chordpro text, songsheet won’t recognize chords that don’t exist such as B#. Or Hm7. If you give it “aM7”, it will normalize to “Am7” etc.
  • It’s implemented in Python, on github, has a complete and maintained test suite, builds are run on travis and docs are on on readthedocs.
songsheet.clean(s: str) → str

Cleans an input songsheet in preparation for parsing. A composition of the following functions:

  • strips spaces before and after each line
  • normalizes line breaks.
  • Strips leading and trailing spaces.
Parameters:x – The input string.
Returns:The cleaned string.
songsheet.compact_chords(line: List[str]) → List[str]

Compacts a list of letters such that a multi letter chord is one element in the list.

Parameters:line – A list of characters.
Returns:A list of compacted characters.


>>> songsheet.compact_chords(['g', 'm', ' ', 'B']
['gm', ' ', 'B']
songsheet.compose(*funcs) → Callable

Composes a list of functions into a single composite func.

Parameters:funcs – a list of functions
Returns:A function composed of the passed-in functions.
songsheet.is_chord_line(chord_line: List[str]) → bool

Determines whether an array of characters can be considered a line of valid chords.

Parameters:chord_line – A list of characters.
Returns:True if all contigious characters are chords.


>>> songsheet.is_chord_line(['a', 'B', ' ', 'g#m'])
>>> songsheet.is_chord_line(['a', 'z', ' ', 'g#m'])
songsheet.normalize_chord_case(word: str) → str

Normalizes the case of a chord.


>>> normalize_chord_case('gM#')
songsheet.normalize_line_breaks(s: str) → str

Returns a string with line breaks replaced with the OS appropriate line break.

Parameters:s – A source string.
Returns:A string with line breaks normalized.
songsheet.serialize(songsheet_str: str)

Serializes a songsheet string into a tuple of tuples.

Parameters:songsheet_str – A string representing a songsheet.
Returns:A tuple of tuples. Each tuple is a line of chords followed by a line of lyrics.


>>> songsheet.serialize('am   C   \nfoo bar')
('Am', ' ', ' ', 'C ', ' ', ' ', ' '),
('f', 'o', 'o', ' ', 'b', 'a' 'r'))

Strips spaces before and after each new line.

Parameters:x (str) – An input string.
Returns:A string with spaces stripped before and after each new-line.
Return type:str
songsheet.to_json(s: str, indent: int = 0) → str

Returns a json string given a songsheet string.

  • s – A songsheet string.
  • indent – How many spaces to indent (prettify). Defaults to None.

A string of json

songsheet.to_str(lines: List[List[str]]) → str

Converts a parsed songsheet back into a string.

Parameters:lines – A list of parsed songsheet lines
Returns:A songsheet string.
songsheet.valid_chords = ['A', 'A#', 'Am', 'A#7', 'A#m7', 'A#sus', 'A♭', 'A♭m', 'A♭7', 'A♭m7', 'A♭sus', 'Am', 'A7', 'Am7', 'Asus', 'B', 'B#', 'Bm', 'B#7', 'B#m7', 'B#sus', 'B♭', 'B♭m', 'B♭7', 'B♭m7', 'B♭sus', 'Bm', 'B7', 'Bm7', 'Bsus', 'C', 'C#', 'Cm', 'C#7', 'C#m7', 'C#sus', 'C♭', 'C♭m', 'C♭7', 'C♭m7', 'C♭sus', 'Cm', 'C7', 'Cm7', 'Csus', 'D', 'D#', 'Dm', 'D#7', 'D#m7', 'D#sus', 'D♭', 'D♭m', 'D♭7', 'D♭m7', 'D♭sus', 'Dm', 'D7', 'Dm7', 'Dsus', 'E', 'E#', 'Em', 'E#7', 'E#m7', 'E#sus', 'E♭', 'E♭m', 'E♭7', 'E♭m7', 'E♭sus', 'Em', 'E7', 'Em7', 'Esus', 'F', 'F#', 'Fm', 'F#7', 'F#m7', 'F#sus', 'F♭', 'F♭m', 'F♭7', 'F♭m7', 'F♭sus', 'Fm', 'F7', 'Fm7', 'Fsus', 'G', 'G#', 'Gm', 'G#7', 'G#m7', 'G#sus', 'G♭', 'G♭m', 'G♭7', 'G♭m7', 'G♭sus', 'Gm', 'G7', 'Gm7', 'Gsus']

A list of common chords

songsheet.valid_chords_re = re.compile('(\\bA\\b|\\bA#\\b|\\bAm\\b|\\bA#7\\b|\\bA#m7\\b|\\bA#sus\\b|\\bA♭\\b|\\bA♭m\\b|\\bA♭7\\b|\\bA♭m7\\b|\\bA♭sus\\b|\\bAm\\b|\\bA7\\b|\\bAm7\\b|\\bAsus\\b|\\bB\\b|\\bB#\\b|\\bBm\\b|\\bB#7\\b|\\bB#m7\\b|\, re.IGNORECASE)

A case-insensitive regular expression matching any valid chord.

Indices and tables