DDG - 2022-01-19: Below is a simple Tcl terminal application which allows to typeset chord diagrams for fretted string instruments such as Ukulele and Guitar.
Here an example use case on how to create a Fadd9-Chord diagram on a Bariton Ukulele and thereafter a Dsus4 chord diagram for a standard Guitar tuning without string note indicators at the bottom. Finally at the right a standard G-Chord on the diagram without fingerings. The cross on top means that the string should be not used, the open circle indicates that the string should ring free, the black circle on top indicates the root note of the chord which can be used in root-note/strum patterns.
tclsh tschords.tcl -file DGBE-Fadd9.svg -chord Fadd9 -positions 3213 \
-fingering RMIP -root R000 -nfrets 4 -width 200 -height 240 -tuning DGBE
tclsh tschords.tcl -file EADGBE-Dsus4.svg -chord Dsus4 -positions XX0233 \
-fingering 000IRP -root 00R000 -nfrets 5 -width 200 -height 240 -tuning ""
tclsh tschords.tcl -file EADGBE-G.svg -chord G -positions 300023 \
-fingering "" -root R0000R -nfrets 5 -width 200 -height 240 -tuning ""
#!/usr/bin/env tclsh
# Created By : Detlef Groth
# Created : Tue Jan 18 05:24:20 2022
# Last Modified : <220119.0627>
#
# Description : Simple Chord chart generator for fretted instrruments
#
# Copyright (c) 2022 Detlef Groth.
#
# License: MIT
#
##############################################################################
proc svgChord {argv} {
array set args {
-file out.svg
-tuning EADGBE
-fingering 0RM0I0
-positions X32010
-root 0R00R0
-chord Cmaj
-width 400
-height 480
-nfrets 6
}
array set args $argv
set height $args(-height)
set width $args(-width)
set hmargin [expr {$width/12}]
set vmargin [expr {$height/15}]
set ystep [expr {$height/15}]
set xstep [expr {($width-2*$hmargin+1)/([string length $args(-positions)]-1)}]
# not used yet
if {$width<400} {
set stroke1 6
set stroke2 2
}
# scaling for font in dependence of given width
set fsunit [expr {int((6*$width)/400)}]
set cy 0 ;# currenty y position in chart
set out [open $args(-file) w 0600]
puts $out "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:svgjs=\"http://svgjs.com/svgjs\" preserveAspectRatio=\"xMidYMid meet\" viewBox=\"0 0 $width $height\">"
# grey background
puts $out "<rect width=\"100%\" height=\"100%\" fill=\"#eeeeee\"></rect>"
# Display Chord on top
if {$args(-chord) ne ""} {
incr cy $ystep
puts $out "<text x=\"[expr {$width/2}]\" y=\"$cy\" font-family=\"serif\" font-size=\"[expr {$fsunit*8}]\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"#000000\">$args(-chord)</text>"
}
incr cy $ystep
# strings
incr cy [expr {int($ystep*0.9)}]
set ystart $cy
# draw nut
puts $out "<line x1=\"[expr {$hmargin-2}]\" y1=\"$cy\" x2=\"[expr {$width-$hmargin+2}]\" y2=\"$cy\" stroke-width=\"8\" stroke=\"#000000\"></line>"
# available space
if {$args(-tuning) ne ""} {
set yrange [expr {$height-$vmargin*2-$cy}]
} else {
set yrange [expr {$height-$vmargin-$cy}]
}
# draw frets
set ystep [expr {$yrange/$args(-nfrets)}]
set x1 $hmargin
set x2 [expr {$width-$hmargin}]
for {set i 0} {$i < $args(-nfrets)} {incr i} {
incr cy $ystep
puts $out "<line x1=\"$x1\" y1=\"$cy\" x2=\"$x2\" y2=\"$cy\" stroke-width=\"3\" stroke=\"#000000\"></line>"
set y1a $cy
incr y1a [expr {int($ystep/2)}]
set x1a [expr {$width/2}]
if {$i in [list 1 3]} {
# position markers
if {$i == 1 || ($i == 3 && $args(-nfrets) > 4)} {
puts $out "<text x=\"$x1a\" y=\"$y1a\" font-family=\"sans-serif\" font-size=\"[expr {$fsunit*8}]\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"#000000\"> \u00D7</text>"
}
}
}
set yend $cy
set x1 $hmargin
# draw draw strings and fingerboard
set notes [lrange [split [regsub -all {([A-Z])} $args(-tuning) ";\\1"] ";"] 1 end]
for {set x 0} {$x < [string length $args(-positions)]} {incr x} {
# draw strings
puts $out "<line x1=\"$x1\" y1=\"$ystart\" x2=\"$x1\" y2=\"$yend\" stroke-width=\"3\" stroke=\"#000000\"></line>"
set pos [string range $args(-positions) $x $x]
# draw indicators above the nut
if { $pos == "X"} {
puts $out "<text x=\"$x1\" y=\"[expr {$ystart-0.35*$ystep}]\" font-family=\"sans-serif\" font-size=\"[expr {$fsunit*6}]\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"#000000\">\u00D7</text>"
} elseif { $pos == "0"} {
puts $out "<circle r=\"[expr {$fsunit*1.7}]\" cx=\"$x1\" cy=\"[expr {$ystart-0.35*$ystep}]\" fill=\"white\" stroke-width=\"2\" stroke=\"black\"></circle>"
}
# root note indicator
set root [string range $args(-root) $x $x]
if {$root == "R"} {
puts $out "<circle r=\"[expr {$fsunit*1.7}]\" cx=\"$x1\" cy=\"[expr {$ystart-0.35*$ystep}]\" fill=\"black\" stroke-width=\"2\" stroke=\"black\"></circle>"
}
if {[llength $notes] >= $x} {
set tun [lindex $notes $x]
puts $out "<text x=\"$x1\" y=\"[expr {$yend+0.35*$ystep}]\" font-family=\"serif\" font-size=\"[expr {$fsunit*6}]\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"#000000\">$tun</text>"
}
incr x1 $xstep
}
# draw fingerings
set cx $hmargin
set cy $ystart
for {set y 0} {$y < $args(-nfrets)} {incr y} {
for {set x 0} {$x < [string length $args(-positions)]} {incr x} {
set pos [string range $args(-positions) $x $x]
if {[expr {$y+1}] == $pos} {
puts $out "<circle r=\"[expr {$fsunit*3}]\" cx=\"$cx\" cy=\"[expr {$cy+0.5*$ystep}]\" fill=\"black\" stroke-width=\"2\" stroke=\"black\"></circle>"
if {[string length $args(-fingering)] >= $x} {
set fing [string range $args(-fingering) $x $x]
puts $out "<text x=\"$cx\" y=\"[expr {$cy+0.51*$ystep}]\" font-family=\"sans-serif\" font-size=\"[expr {$fsunit*4}]\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"#FFFFFF\">$fing</text>"
}
}
incr cx $xstep
}
incr cy $ystep
set cx $hmargin
}
puts $out "</svg>"
close $out
}
if {[info exists argv] && [llength $argv] == 0} {
puts "tschord.tcl - drawing chord diagrams for fretted instruments"
puts "Author: Detlef Groth, Caputh-Schwielowsee, Germany"
puts "License: MIT\n"
puts "Usage: tschords.tcl -file file.svg -tuning EADGBE \
-fingering 00MRI0 -positions x02210 -chord Am"
} else {
svgChord $argv
}DDG - 2022-01-19: Please discuss here.