chord_pro 0.6.0
chord_pro: ^0.6.0 copied to clipboard
A Dart parser for the ChordPro 6 song format. Extracts chords, lyrics, metadata, comments, layout hints and chord diagrams.
chord_pro #
A Dart parser for the ChordPro 6 song format.
Built for music apps and digital songbooks — parses .cho / .crd / .chopro files into typed chords, lyrics, metadata, comments, images, layout hints, and chord diagrams.
Installation #
dart pub add chord_pro
Usage #
Parse a document #
import 'package:chord_pro/chord_pro.dart';
final result = ChordPro.parse(source);
final song = result.songs.first;
print(song.metadata.titles.firstOrNull);
print(song.metadata.key); // first key (use `metadata.keys` for the full list)
ChordPro.parse returns a ParseResult with every song in the document (split on {new_song} / {ns}) plus any diagnostics. Use ChordPro.parseSong if you only want the first song.
What a Song contains #
metadata— typedMetadata: titles, sortTitles, subtitles, artists, sortArtists, composers, lyricists, arrangers, copyright, album, year, keys, times, tempos, duration, capo, transpose (plustransposeQualifier), columns, tags, plus anothermap for anything custom. The multi-valued fields preserve source order; convenience getterskey/time/tempo/sortTitle/sortArtistreturn the first entry.sections— orderedSections for verse, chorus, bridge, tab, grid, abc, ly, svg, textblock, custom environments, and loose lines. Each section exposeslabel,attributes, plus typedgridAttributesandtextblockAttributeswhere applicable.chordDefinitions— parsed{define}/{chord}bodies includingdisplay,format,keys,copy,copyall,diagram, and the transposable bracketed[Name]form.formatting— typed font / size / colour overrides for chord, text, title, chorus, label, and friends.directives— the raw directive stream in source order.customExtensions—x_*namespaced directives.tocSuppressed—truewhen{ns toc=no}requested the song be omitted from the table of contents.titlesAlignment— typed{titles}alignment hint.diagrams— typed{diagrams}(or{g}) setting (enabledflag plus position enum).transposed(semitones)— returns a copy with every chord shifted.
Walk sections and lines #
for (final section in song.sections) {
print('${section.kind} ${section.label ?? ''}');
for (final line in section.lines) {
switch (line.kind) {
case LineKind.structured:
for (final token in line.tokens) {
// TextToken / ChordToken / AnnotationToken / InlineDirectiveToken
}
case LineKind.verbatim:
print(line.verbatim);
case LineKind.comment:
print('${line.commentStyle}: ${line.comment}');
case LineKind.image:
print('image: ${line.image?.src}');
case LineKind.layoutBreak:
print('break: ${line.layoutBreak}');
}
}
}
Transpose and conditional selectors #
Shift every chord by N semitones:
final upTwo = ChordPro.parseSong(source).transposed(2);
Activate conditional directives like {title-guitar: …} / {title-guitar!: …} by passing a selector set:
final guitar = ChordPro.parseSong(source, selectors: {'guitar'});
The selector set gates metadata, formatting, sections, comments, images, layout breaks, chord recalls, and {define} / {chord} definitions. Matching is case-insensitive.
Supported features #
All facts per the ChordPro chord reference and directive reference.
Chords #
- Letter roots
A–G, Nashville1–7, RomanI–VII. - Sharps and flats:
#,b. - Slash bass.
- Minor variants:
m,mi,min,-. - Major qualifier
majand the spec alternate^. - Diminished
dim/0, half-diminishedh. - Augmented
augand the spec alternate+. sus,sus2,sus4,add.- Emergency-bracket recovery (ChordPro 6.020/6.080):
[ ]+and[|]parse as annotations; empty[]is a zero-width placeholder.
Directives #
- Metadata —
title/t,sorttitle,subtitle/st,artist,sortartist,composer,lyricist,arranger,copyright,album,year,key,time,tempo,duration,capo,transpose(with optionals/f/k/#/b/♯/♭qualifier),columns/col,tag, plus{meta: key value}desugaring.key,time,tempo,sorttitle, andsortartistare multi-valued per spec (onesorttitlepertitle; each{key}applies from its source position). Auto-generated names (_key,key.print,today,instrument,user,page, …) are reserved. - Comments —
{comment},{ci},{cb},{highlight}emit as in-flow comment lines. - Images —
{image: …}parsed into a typedImageDirectivewith full attribute coverage:src,width,height,scale,align,border,bordertrbl(trbl=accepted as alias),title,label,href,id,chord,type,x,y,spread,center,persist,omit, plus a validatedanchorEnum(paper/page/allpages/column/float/line). - Layout breaks —
{new_page},{new_physical_page},{column_break}emit as in-flow layout breaks. - Output / song boundary —
{ns toc=no}(ortoc=false/toc=0) setsSong.tocSuppressed.{titles: left|center|right}and{diagrams: on|off|top|bottom|right|below}(with{g}alias) become typed song-level settings. - Formatting —
chordfont,textsize,titlecolour, … reduce intoFormattingSettings. Bothcolourandcoloraccepted. - Custom —
x_*extensions preserved onSong.customExtensions.
Sections #
- Built-in environments:
verse/sov,chorus/soc,bridge/sob,tab/sot,grid/sog. - Delegated
abc,ly,svg,textblockcaptured verbatim. - Custom
start_of_<name>/end_of_<name>sections preserved with their custom kind. label="…"attribute parsed for every{start_of_*}(alongside the legacy bare-value form).{start_of_grid}exposes typedshape(left+measures × beats+right),cc(plus decodedccName/ccProgressionfor the 6.070cc="Name:C1 C2 …"form), andlabelviaSection.gridAttributes.{start_of_textblock}exposes the full ChordPro 6.050 attribute set (textblock-specific plus image-inherited) viaSection.textblockAttributes.{chorus}recall accepts all four spec forms —{chorus},{chorus: Final},{chorus: label="Final"},{chorus label="Final"}.
Conditional selectors #
- Positive form
{title-guitar: …}and spec-form negation{title-guitar!: …}. - Gates metadata, formatting, sections, comments, images, layout breaks, chord recalls, and
{define}/{chord}definitions.
Source features #
- ChordPro 6.01 scanner: trailing
\line continuation and\uXXXXUnicode escapes anywhere in input text. - ChordPro 6.060 brace-form
\u{X+}Unicode escape (1+ hex digits, supports surrogate-pair recombination). - File-level
#comments dropped. parser.altbracketsconfiguration (ChordPro.parse(..., altBrackets: '«»')) rewrites the configured pair to[/]before parsing.- Diagnostics with 1-based source spans for every problem.
Non-spec extensions #
The parser is more lenient than the published spec in a few places. Each extension is opt-in by simply being present in your input — files parse either way, but the named feature is not required by ChordPro itself.
| Extension | Spec equivalent | Notes |
|---|---|---|
H letter root |
B |
German notation for B natural. |
♯ (U+266F), ♭ (U+266D) |
#, b |
Unicode accidentals. |
ø, ° |
h, 0 / dim |
Half-diminished and diminished glyphs. |
NC, N.C., N.C |
— | No-chord markers; spec is silent. |
| Backslash escapes inside lyrics | — | Escape [, ], {, }, \ inside lyric lines. |
Mid-lyric {…} directives |
— | Spec requires directives to occupy a whole line. |
{name-!sel}, {name+sel} |
{name-sel!} |
Legacy negative-selector forms; new files use the spec form. |
Known limitations #
- Pango-style markup (
<b>,<i>,<span …>,<sym …/>,<img …/>,<strut …/>) inside lyrics and comments is preserved verbatim — no inline parsing or rendering. {define format="…"}is captured as a typedStringbut the%{…}substitutions inside it are not interpreted (rendering concern).- The directive parser closes on the first unescaped
}, so attribute values cannot themselves contain a literal}. {pagetype}lands inSong.directivesonly — no typed access.- The chord-changes recall token
[^](ChordPro 6.070, experimental) is captured as a plain chord token; the cc-set advance is a rendering concern. - Chord-over-lyrics legacy auto-conversion (
chords-over-lyrics/) is not implemented; supply ChordPro-format input. - Notes mode (lowercase / solfège chord roots,
settings.notes) is not exposed. - Configuration-only switches (
parser.preprocess,settings.wraplines,settings.choruslabels,settings.maj7delta,keys.force-common) have no surface — the parser uses the ChordPro 6.100 defaults.
Example songs #
Runnable demo: example/chord_pro_example.dart.
ChordPro source files: