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.