PascalChordSVG
A CLI and a library to create SVG files of guitar chords.
- Active · last change 6-1-2026
- ★ 1 on GitHub
README
ChordSVG
A Free Pascal command-line tool and reusable library for generating SVG guitar chord diagrams. Produces clean, print-ready chord charts as standalone SVG files or multi-chord page sheets.
Contents
- Features
- Requirements
- Building
- Quick Start
- CLI Reference
- Input File Format
- Themes
- Page Layout
- Library API
- Examples
- File Structure
- Licence
Features
- Single chord diagrams — one SVG per chord, native 196×340 px
- Multi-chord sheets — fixed 3×3 portrait (9 chords) or 4×2 landscape (8 chords) grid, auto-scaled to fill the page
- Three built-in themes — Dark (navy/gold), Light (cream/blue), Black & White (print-optimised)
- Title and subtitle — rendered above the chord grid; page numbers appended automatically on multi-page output
- Input file format — plain-text
.txtfiles with directives, chord lines, page breaks, and inline comments - Two output modes — one SVG per page (
--pages) or one SVG per chord (--individual) - Barre chord detection — automatically draws a pill-shaped barre bar when two or more strings share the lowest fret
- High-position chords — fret window shifts automatically; position label (e.g.
5fr) rendered beside the grid - Reusable library — all logic lives in
ChordSVGLib.pas; the CLI is a thin wrapper
Requirements
- Free Pascal Compiler 3.2.0 or later (
fpc) - Standard FPC RTL units:
SysUtils,StrUtils,Math,Classes - No external dependencies
Tested on Linux x86-64 with FPC 3.2.2. Should compile on macOS and Windows without modification.
Building
fpc chordsvg.pasFPC resolves ChordSVGLib.pas automatically because it is in the same directory. The compiled binary is chordsvg (or chordsvg.exe on Windows).
To compile just the library unit (e.g. for use in another project):
fpc ChordSVGLib.pasQuick Start
# Single chord to stdout
./chordsvg "C" "x 3 2 0 1 0"
# Single chord to file, light theme
./chordsvg "Am" "x 0 2 2 1 0" am.svg --light
# Inline sheet, dark theme, portrait
./chordsvg --sheet --title "Key of C" \
"C:x 3 2 0 1 0" "Am:x 0 2 2 1 0" "F:1 1 2 3 3 1" "G:3 2 0 0 0 3" \
sheet.svg
# From a text file — one SVG per page
./chordsvg --input chords.txt --pages output/sheet
# From a text file — one SVG per chord
./chordsvg --input chords.txt --individual output/chords/CLI Reference
Single Chord
chordsvg "Name" "frets" [output.svg] [--dark|--light|--bw]Renders one chord diagram. Output goes to stdout if no file is specified.
| Argument | Description |
|---|---|
"Name" |
Chord display name, e.g. "Cmaj7" |
"frets" |
Six space-separated fret values (see Fret Values) |
output.svg |
Optional output file path (detected by .svg extension) |
--dark / --light / --bw |
Colour theme (default: --dark) |
Examples:
./chordsvg "C" "x 3 2 0 1 0"
./chordsvg "F" "1 1 2 3 3 1" f_barre.svg
./chordsvg "Bm" "x 2 4 4 3 2" bm.svg --bw
./chordsvg "Cmaj7" "x 3 2 0 0 0" --lightFret Values
Frets are specified as six whitespace-separated tokens, ordered low-E (string 6) to high-E (string 1):
| Token | Meaning |
|---|---|
x or - |
Muted string (shown as ✕ above nut) |
0 |
Open string (shown as â—‹ above nut) |
1–24 |
Fret number (filled dot on grid) |
Inline Sheet
chordsvg --sheet [options] [output.svg] "Name:frets" "Name:frets" ...Lays out multiple chords on a single page-sized SVG. Each chord argument uses a colon to separate the name from the fret string.
| Flag | Description |
|---|---|
--sheet |
Enable sheet mode |
--portrait |
Portrait orientation, 3×3 grid (default) |
--landscape |
Landscape orientation, 4×2 grid |
--dark / --light / --bw |
Colour theme |
--title "text" |
Large title at top of page |
--subtitle "text" |
Smaller italic subtitle below title |
output.svg |
Output file (stdout if omitted) |
Examples:
./chordsvg --sheet \
"C:x 3 2 0 1 0" "Am:x 0 2 2 1 0" "F:1 1 2 3 3 1" "G:3 2 0 0 0 3" \
sheet.svg
./chordsvg --sheet --landscape --bw --title "Beginner Chords" \
"D:x x 0 2 3 2" "E:0 2 2 1 0 0" "A:x 0 2 2 2 0" \
beginner.svg
./chordsvg --sheet --light --title "Barre Chords" --subtitle "E-shape" \
"F:1 1 2 3 3 1" "G:3 3 5 5 4 3" "A:5 5 7 7 6 5" sheet_barre.svgInput File Mode
chordsvg --input <file.txt> (--pages [stem] | --individual [dir/]) [options]Reads chord definitions from a plain-text file. Requires either --pages or --individual to specify the output mode.
| Flag | Description |
|---|---|
--input <file> |
Path to the chord input file |
--pages [stem] |
Write one SVG per page; files named stem_1.svg, stem_2.svg, … Default stem: page |
--individual [dir/] |
Write one SVG per chord into a directory. Default: current directory |
--dark / --light / --bw |
Theme override (file directives take priority) |
--portrait / --landscape |
Orientation override (file directives take priority) |
--title "text" |
Title override (file title: directive takes priority) |
--subtitle "text" |
Subtitle override (file subtitle: directive takes priority) |
Examples:
# Pages output — files: page_1.svg, page_2.svg, ...
./chordsvg --input chords.txt --pages
# Custom stem — files: book_1.svg, book_2.svg, ...
./chordsvg --input chords.txt --pages book
# Individual SVGs into a subdirectory
./chordsvg --input chords.txt --individual chords/
# Override theme from CLI even if file sets one
./chordsvg --input chords.txt --pages --bwNote: When both the input file and the CLI specify a theme or orientation, the file directive takes priority. This lets you lock a file's appearance without worrying about CLI flags.
Input File Format
Input files are plain UTF-8 text. Lines are processed in order; blank lines and comment lines (starting with #) are ignored.
# ── Directives ──────────────────────────────────────────────────────────────
title: Common Guitar Chords # shown at top of every page
subtitle: Open & Barre Positions # shown below title, italic
theme: bw # dark | light | bw
orientation: portrait # portrait | landscape
# ── Chord lines ──────────────────────────────────────────────────────────────
# Format: Name<whitespace>fret1 fret2 fret3 fret4 fret5 fret6
C x 3 2 0 1 0
Am x 0 2 2 1 0
F 1 1 2 3 3 1 # inline comments are stripped
G 3 2 0 0 0 3
# ── Page break ───────────────────────────────────────────────────────────────
--- # plain break, inherits global title
--- Minor Chords # break + per-page title override
Dm x x 0 2 3 1
Em 0 2 2 0 0 0
Bm x 2 4 4 3 2Directives
| Directive | Values | Description |
|---|---|---|
title: |
Any text | Page title (large, bold, centred) |
subtitle: |
Any text | Page subtitle (smaller, italic, centred) |
theme: |
dark light bw |
Colour theme for all output |
orientation: |
portrait landscape |
Page orientation |
Page Breaks
A line beginning with --- starts a new page. Any text after --- (trimmed) becomes that page's title override, replacing the global title for that page only:
--- Minor Chords → page title becomes "Minor Chords"
--- → page uses global title (or no title)Chord Name Rules
- The chord name is the first whitespace-delimited token on the line
- Names may contain letters, numbers,
#,b,/, and most Unicode characters - When writing individual SVG files, characters outside
[A-Za-z0-9\-_#]are replaced with_in the filename; the display name is unaffected
Themes
| Flag | Background | Dots / Barre | Mute X | Best for |
|---|---|---|---|---|
--dark |
Navy #1a1a2e |
Warm gold #c8a96e |
Red #e05555 |
Screens, dark-mode docs |
--light |
Cream #f5f0e8 |
Steel blue #2a6496 |
Red #c0392b |
Light documents, e-readers |
--bw |
White #ffffff |
Black #000000 |
Black #000000 |
Laser/inkjet printing |
All themes use Georgia serif for chord names and titles, and monospace for fret-position labels.
Page Layout
Grid dimensions
| Orientation | Columns | Rows | Chords per page |
|---|---|---|---|
| Portrait | 3 | 3 | 9 |
| Landscape | 4 | 2 | 8 |
Chords are scaled uniformly to fill the grid area. Scale is capped at 1.0 (native size) so small chord counts are never enlarged.
Page size
Pages are sized at 96 dpi, matching CSS pixel dimensions for direct use in web contexts and browser-based PDF export:
| Orientation | Width | Height |
|---|---|---|
| Portrait | 794 px | 1123 px |
| Landscape | 1123 px | 794 px |
Header
When a title is present, 70 px are reserved at the top of the page. The title is rendered in 28 px bold Georgia, the subtitle in 16 px italic Georgia below it. When there are multiple pages, (N of M) is automatically appended to the subtitle.
Native cell size
A single chord diagram at scale 1.0 is 196 × 340 px:
Padding top (90 px) — chord name + open/mute markers
Grid (5 frets × 38 px) — 190 px
Padding bottom (30 px)Library API
All rendering logic is in ChordSVGLib.pas. Add it to your project with:
uses ChordSVGLib;Types
TFretValue = -1..24
A single string's fret value. -1 = muted, 0 = open, 1–24 = fret number.
TChordFrets = array[0..5] of TFretValue
Six fret values ordered low-E (index 0) to high-E (index 5).
TChordEntry
TChordEntry = record
Name : string; // display name, e.g. 'Cmaj7'
Frets : TChordFrets; // voicing
end;TChordList = array of TChordEntry
Dynamic array of chord entries, used for sheet rendering.
TPage
TPage = record
Chords : TChordList;
TitleOverride : string; // '' = use global title
end;A single page of a chord book. TitleOverride is populated from --- Title lines in input files.
TPageList = array of TPage
TTheme
TTheme = record
Background : string; // diagram background colour
ChordName : string; // chord name text colour
Nut : string; // nut rectangle fill
Fret : string; // fret line stroke
Str : string; // string line stroke
Dot : string; // fretted dot / barre fill
Open : string; // open string circle stroke
Mute : string; // muted string X stroke
FretLbl : string; // fret position label colour
TitleText : string; // page title colour
SubtitleText : string; // page subtitle colour
end;All colour fields are CSS hex strings, e.g. '#1a1a2e'.
TFileSettings
TFileSettings = record
ThemeOverride : string; // '' if not set in file
OrientationOverride : string; // '' | 'portrait' | 'landscape'
Title : string;
Subtitle : string;
end;Constants
| Constant | Value | Description |
|---|---|---|
CS_NUM_STRINGS |
6 |
Strings per diagram |
CS_FRETS_SHOWN |
5 |
Fret slots in grid |
CS_CELL_W |
196 |
Native cell width (px) |
CS_CELL_H |
340 |
Native cell height (px) |
CS_PAGE_PORTRAIT_W/H |
794 / 1123 |
Portrait page size (px) |
CS_PAGE_LANDSCAPE_W/H |
1123 / 794 |
Landscape page size (px) |
CS_PAGE_MARGIN |
40 |
Page margin (px) |
CS_PORTRAIT_COLS/ROWS |
3 / 3 |
Portrait grid |
CS_LANDSCAPE_COLS/ROWS |
4 / 2 |
Landscape grid |
THEME_DARK |
— | Built-in dark theme |
THEME_LIGHT |
— | Built-in light theme |
THEME_BW |
— | Built-in B&W theme |
Parsing Functions
ParseFrets
function ParseFrets(const S: string; out Frets: TChordFrets): Boolean;Parses a whitespace-separated fret string into a TChordFrets array.
var Frets: TChordFrets;
if ParseFrets('x 3 2 0 1 0', Frets) then
WriteLn('Parsed OK');Returns False if the token count is not exactly 6 or any value is out of range.
ParseChordArg
function ParseChordArg(const S: string; out Entry: TChordEntry): Boolean;Parses a "Name:frets" CLI-style argument.
var Entry: TChordEntry;
ParseChordArg('Cmaj7:x 3 2 0 0 0', Entry);
// Entry.Name = 'Cmaj7'
// Entry.Frets = [−1, 3, 2, 0, 0, 0]ParseInputFile
function ParseInputFile(const Path: string;
out Pages: TPageList;
out FileSettings: TFileSettings): Boolean;Reads a chord text file and returns a TPageList split at --- boundaries, plus any directives found.
var Pages: TPageList; Settings: TFileSettings;
if ParseInputFile('chords.txt', Pages, Settings) then
WriteLn('Pages: ', Length(Pages));ThemeFromName
function ThemeFromName(const Name: string): TTheme;Returns the matching built-in theme. Unrecognised names return THEME_DARK.
Theme := ThemeFromName('bw'); // returns THEME_BW
Theme := ThemeFromName('dark'); // returns THEME_DARKRendering Functions
ChordToSVG
function ChordToSVG(const ChordName: string;
const Frets: TChordFrets;
const Theme: TTheme): string;Returns a complete <?xml ...?><svg ...>...</svg> document for a single chord diagram at native size (196×340 px).
var Frets: TChordFrets; SVG: string;
ParseFrets('x 3 2 0 1 0', Frets);
SVG := ChordToSVG('C', Frets, THEME_DARK);
WriteLn(SVG);ChordSheetToSVG
function ChordSheetToSVG(
const Chords: TChordList;
const Theme: TTheme;
PageW, PageH: Integer;
const Title, Subtitle: string;
PageNum, PageCount: Integer): string;Returns a complete SVG document for one page of the chord sheet grid.
var Chords: TChordList; SVG: string;
SetLength(Chords, 2);
Chords[0].Name := 'C'; ParseFrets('x 3 2 0 1 0', Chords[0].Frets);
Chords[1].Name := 'Am'; ParseFrets('x 0 2 2 1 0', Chords[1].Frets);
SVG := ChordSheetToSVG(Chords, THEME_LIGHT,
CS_PAGE_PORTRAIT_W, CS_PAGE_PORTRAIT_H,
'My Songs', 'Key of C',
1, 1); // page 1 of 1Pass PageNum and PageCount to enable automatic (N of M) suffixes in multi-page output.
ChordsPerPage
function ChordsPerPage(IsLandscape: Boolean): Integer;Returns the maximum number of chords that fit on one page (9 portrait, 8 landscape).
Output Helpers
WriteToFile
procedure WriteToFile(const SVGText, Path: string);Writes SVG content to a file. Logs the path to StdErr on success; halts with exit code 3 on failure.
WritePagesOutput
procedure WritePagesOutput(
const Pages: TPageList;
const Theme: TTheme;
PageW, PageH: Integer;
const Stem, GlobalTitle, GlobalSubtitle: string);Renders each page and writes Stem_1.svg, Stem_2.svg, … Resolves per-page titles from TPage.TitleOverride, falling back to GlobalTitle.
WriteIndividualOutput
procedure WriteIndividualOutput(
const Pages: TPageList;
const Theme: TTheme;
const Dir: string);Renders each chord individually and writes Dir/ChordName.svg. Duplicate chord names get a numeric suffix (C.svg, C_2.svg, …).
SafeFilename
function SafeFilename(const S: string): string;Replaces characters outside [A-Za-z0-9\-_#] with underscores.
SafeFilename('F#m') // → 'F#m' (# is allowed)
SafeFilename('G/B') // → 'G_B'
SafeFilename('Cmaj7') // → 'Cmaj7'EnsureTrailingSep
function EnsureTrailingSep(const Dir: string): string;Appends DirectorySeparator if absent. Used internally by WriteIndividualOutput.
Advanced: DrawChordCell
procedure DrawChordCell(
Lines: TStringList;
const ChordName: string;
const Frets: TChordFrets;
const Theme: TTheme;
OX, OY: Integer;
Scale: Double;
NameFontSize, LblFontSize: Integer);Low-level procedure that appends SVG element strings (without wrapping <svg> tags) to an existing TStringList. Use this to embed chord diagrams into a custom SVG canvas at arbitrary positions and scales.
var Lines: TStringList; Frets: TChordFrets;
Lines := TStringList.Create;
Lines.Add('<svg xmlns="http://www.w3.org/2000/svg" width="600" height="340">');
Lines.Add(' <rect fill="#1a1a2e" width="600" height="340"/>');
ParseFrets('x 3 2 0 1 0', Frets);
DrawChordCell(Lines, 'C', Frets, THEME_DARK, 0, 0, 1.0, 30, 14);
ParseFrets('x 0 2 2 1 0', Frets);
DrawChordCell(Lines, 'Am', Frets, THEME_DARK, 200, 0, 1.0, 30, 14);
ParseFrets('1 1 2 3 3 1', Frets);
DrawChordCell(Lines, 'F', Frets, THEME_DARK, 400, 0, 1.0, 30, 14);
Lines.Add('</svg>');
WriteLn(Lines.Text);
Lines.Free;Examples
Minimal single-chord program
program HelloChord;
{$mode objfpc}{$H+}
uses SysUtils, ChordSVGLib;
var Frets: TChordFrets;
begin
ParseFrets('x 3 2 0 1 0', Frets);
Write(ChordToSVG('C', Frets, THEME_DARK));
end.Build a chord book from code
program ChordBook;
{$mode objfpc}{$H+}
uses SysUtils, ChordSVGLib;
procedure AddChord(var List: TChordList; const Name, FretsStr: string);
var N: Integer;
begin
N := Length(List);
SetLength(List, N + 1);
List[N].Name := Name;
ParseFrets(FretsStr, List[N].Frets);
end;
var
Chords : TChordList;
Pages : TPageList;
SVG : string;
begin
SetLength(Chords, 0);
AddChord(Chords, 'C', 'x 3 2 0 1 0');
AddChord(Chords, 'Am', 'x 0 2 2 1 0');
AddChord(Chords, 'F', '1 1 2 3 3 1');
AddChord(Chords, 'G', '3 2 0 0 0 3');
SVG := ChordSheetToSVG(Chords, THEME_BW,
CS_PAGE_PORTRAIT_W, CS_PAGE_PORTRAIT_H,
'Beginner Chords', 'Open positions',
1, 1);
WriteToFile(SVG, 'beginner.svg');
end.Process an input file programmatically
var
Pages : TPageList;
Settings: TFileSettings;
Theme : TTheme;
i : Integer;
begin
if not ParseInputFile('chords.txt', Pages, Settings) then
Halt(1);
Theme := ThemeFromName(Settings.ThemeOverride);
for i := 0 to High(Pages) do
WriteToFile(
ChordSheetToSVG(Pages[i].Chords, Theme,
CS_PAGE_PORTRAIT_W, CS_PAGE_PORTRAIT_H,
Pages[i].TitleOverride, Settings.Subtitle,
i + 1, Length(Pages)),
Format('out_%d.svg', [i + 1]));
end.File Structure
chordsvg/
├── ChordSVGLib.pas Library unit — all types, rendering, parsing
├── chordsvg.pas CLI wrapper — argument parsing only
├── example_chords.txt Sample input file demonstrating all directives
└── README.md This file
samples/ Pre-generated SVG output samples
├── C_dark.svg Single chord, dark theme
├── C_light.svg Single chord, light theme
├── C_bw.svg Single chord, B&W theme
├── F_dark.svg Barre chord, dark theme
├── Am_bw.svg Open chord, B&W theme
├── page_1.svg Sheet page 1 (majors, B&W)
├── page_2.svg Sheet page 2 (minors & 7ths, B&W)
├── page_3.svg Sheet page 3 (power chords, B&W)
├── dark_portrait.svg 9-chord portrait, dark theme
└── dark_landscape.svg 8-chord landscape, dark themeLicence
MIT Licence. See source file headers.
Copyright © 2025 Schmitty Guitars
https://schmittyguitars.com

