# Drawing an accurate guitar fretboard with TikZ

This is kind of a fun one.

dist( x ) = s / ( 2 ^ ( x / d ) )

Such that:

x = number of the fret being evaluated (let's say {0,...,24} so it's exactly 2 full octaves).
s = scale length (full length of the fretboard; let's say 651mm).
d = number of divisions per octave (12 in western music).
dist( x ) = distance from bridge (to fret x).

This produces the positions for the standard equal-tempered scale. The nut-to-fret positions and fret-to-fret positions are then produced by simple subtractions.

Musemath

To start off, I created this little thing here:

Pretty simple:

\documentclass{standalone}
\usepackage{tikz}

\begin{document}

% Define frets
\tikzstyle{fret} = [draw,fill=blue!20,minimum size=3em]

\begin{tikzpicture}
% dist( x ) = s / ( 2 ^ ( x / d ) )
\def\d = {12}
\def\s = {651mm}
% dist( x ) = 651 mm / ( 2 ^ ( x / 12 ) )

% Draw nodes, etc.
% Strings
\foreach \a/\b in {1/E, 2/B, 3/G, 4/D, 5/A, 6/E} {
\node at (0,-\a) (input\a) {$\b$};
% Frets
\foreach \x in {1,...,24} {
\node[fret] at (\x,-\a) (block\a) {$\x$};
}
}

\end{tikzpicture}
\end{document}


So what I want to do is define the equivalent of the following function: dist( x ) = s / ( 2 ^ ( x / d ) ) and use it to override the default minimum width of the each fret like: text width=dist(x). Actually, I think each iteration of this function will need to be subtracted from the iteration that follows it. In other words; each fret needs to have the previous fret subtracted from it.

I'm not really sure how functions work with TeX & TikZ, (if at all), so that's where my current knowledge starts to break down.

Here some visual aids:

Fender Stratocaster (21 Frets)
Passy's World of Mathematics

The end result might look something like this:

Acoustic Fretboard
GUITAR-CHORD.ORG

• Btw. sorry if something was possibly confusing, the issue talked about in the chat was not related to any topic you posted here or an answer to one of your topics (comment talk and over), it was a different issue, since 2018. – Stefan Kottwitz Jul 26 '19 at 23:27
• @StefanKottwitz Hey, that's fine, I'm not sure we've ever spoken before though. I rarely use the chat room. It's fairly detached from the main site; it never really seems to be used to discuss questions & answers anyway. I'm not sure I follow, are you thinking of somebody else? – voices Jul 31 '19 at 15:32

First things first, you've done something wrong when defining the variable \d and \s. You should wrote \def\d{12}! (More precisely, if you write \def\d = {A}, you'll have to write \d = each time you want the value 12). That said, you have multiple ways to set variable and do calculus, among others:

• \def\var{14} you just set a variable, without any calculus.
• You can use counter (for integers) and length (for kind of real values) which allow some simple calculus: \newlength{\var} \setlength{\var}{\dimexpr(\varA+\varB)/2\relax}.
• You can use pgf to do "advanced" math: \pgfmathsetmacro{\var}{1-sin(180*\angle)^2} (\pgfmathsetmacro\var{XXX} works too). Note that there is a lot of pgf macro, but in my opinion this one is the most useful one! Beware that \pfgmathsetmacro works weirdly with length, so maybe avoid giving \s a unit... Also note that it will gives back a real value, if you want integer, you should use \pgfmathtruncatemacro!

So in your case, in order to change the value of the text width, you could do

\def\s{20}
\pgfmathsetmacro{\distx}{\s-\s/(2^(\x/\d))}
\node[fret,minimum width=\distx em] at (XXXX) {$\x$};


But if you don't really use the node as an object, it might be easier to draw directly lines. It might produce a bigger code, but it's (in my opinion) easier to deal with.

Regarding the drawing, I've done something like that some times ago for ukulele! I decided to use some recursive formula:

• The next fret is obtained by multiplying by 2^{-1/12} = 0.94387431268;
• The center of the space is obtained by multiplying by (1+2^{-1/12})/2 = 0.97193715634.

For the recursive part, you can keep values through iteration using \xdef\var{\var} that will globally set \var value. So

  \def\var{0}
\foreach \x in {1,...,10}{
\pgfmathtruncatemacro\var{mod( \var+1, 5 )}
\xdef\var{\var}
\message{\var}
}


will print 1 2 3 4 0 1 2 3 4 0!

First, we define every possible coordinate with the name (StringNumber-FretNumber) and some other useful positions, then we print what we want without thinking of the formula for the position!

So

\documentclass[margin=.2cm]{standalone}

\usepackage{tikz}
\usetikzlibrary{calc,arrows}

\begin{document}

\begin{tikzpicture}[
ynode/.style={draw=red!50,circle,fill=red!50,scale=.35,inner sep=1pt,minimum size=1.7em}]

%%%% Draw the base and set coordinates %%%%
\begin{scope}[xscale=-15,yscale=.3,line width=.5]

\xdef\x{1}
%% Left line
\draw[line width=1.5] (1,1) -- (1,6);
\foreach \fret in {1,...,24}{
%% Set coordinate for each string
\foreach \str in {1,...,6}{
\coordinate (\str-\fret) at (0.97193715634*\x,\str);
}
%% Set coordinate for the text above
\coordinate (Top-\fret) at (0.97193715634*\x,7);
%% Compute the position of the fret
\pgfmathsetmacro\x{\x * 0.94387431268}
\xdef\x{\x}
%% Draw the fret
\draw (\x,1) -- (\x,6);
}

%% Draw each string
\foreach \str in {1,...,6}{
\draw (1,\str) -- (0.97153194115*\x,\str);
\coordinate (start\str) at (1,\str);
}
\end{scope}

%% Draw the mark on the guitare
\foreach \f in {3,5,7,9,15,17}{
\draw[black!20,fill=black!10] ($(3-\f)!.5!(4-\f)$) circle (.08);
}
\draw[opacity=.20,fill,fill opacity=.10] (2-12) circle (.08) (5-12) circle (.08);

\end{tikzpicture}

\end{document}


which gives

It's quite easy to use it afterward. You could do for example

\node[znode] at (5-4) {\textbf{2}};
\node[znode] at (3-5) {\textbf{4}};
\draw[zbar] (2-3) -- (5-3);


with the style

zbar/.style={shorten >=-3,shorten <=-3,line width=6,round cap-round cap},
znode/.style={white,draw=black,circle,fill=black,scale=.5,inner sep=1pt,minimum size=1.7em},


which gives

If you want to display each note, you could add, in the tikzpicture,

  %% We define the name of each number
\newcommand\savename[2]{\expandafter\xdef\csname name#1\endcsname{#2}}
\newcommand\getname[1]{\csname name#1\endcsname}
\foreach \n/\t in {1/A,2/A$\sharp$,3/B,4/C,5/C$\sharp$,6/D,7/D$\sharp$,8/E,9/F,10/F$\sharp$,11/G,0/G$\sharp$}{
\savename{\n}{\t}
}

%% Boucle on the string and the first note (given its number)
\foreach \str/\note in {1/8,2/1,3/6,4/11,5/3,6/8}{
\node[anchor=east] at (start\str) {\scriptsize\getname{\note}};
\foreach \fret in {1,...,24}{
\pgfmathtruncatemacro\note{mod( \note+1, 12 )}
\xdef\note{\note}
\node[ynode] at (\str-\fret) {\textbf{\getname{\note}}};
}
}

%% Number above each space
\foreach \fret in {1,...,24}{
\node[scale=.8] at (Top-\fret) {\tiny \fret};
}


which gives

• So which part is needed just to get the correct distance between each fret? – voices Jul 18 '19 at 22:28
• Can it be simplified? I mean (don't take this the wrong way, I appreciate it), you haven't annexed or improved my code. It's a whole new thing, which makes it hard for me to use it to improve. Instead it's like I've traded one problem for another; a differential analysis of two sets of code. – voices Jul 18 '19 at 23:49
• Yes, I will change my answer to explain it more! :) – Vinzza Jul 19 '19 at 6:25
• I like very much your answer. – Sebastiano Jul 19 '19 at 8:15

Here is something to get you started, which makes use of the \pgfmathsetmacro command.

The vertical lines correspond to the frets, which I have numbered. Their locations are based on the provided formula. Note that I have reversed the formula (i.e. \s-\s/(2^(\x/12)) instead of \s/(2^(\x/12))) like in your final example, so that the 0th fret (=nut?, furthest away from the bridge) appears on the left side at x coordinate 0 instead of at \s. The coordinates of the note descriptions (now a $\timex$) are then defined so that they appear in between the frets.

\documentclass[margin=2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
\def\s{20}
% Strings
\foreach \a/\b in {1/E, 2/B, 3/G, 4/D, 5/A, 6/E} {
\node[minimum width=0.5cm] at (-0.5cm,-\a) {\b};
}
% Frets
\node[font=\tiny] at (0,0) (fret0) {};
\draw[dashed] (fret0) -- +(0,-6.5);
\foreach \x in {1,...,24} {
\pgfmathsetmacro{\distx}{\s-\s/(2^(\x/12))}
% creating and numbering frets:
\node[font=\tiny] at (\distx,0) (fret\x) {\x};
\draw (fret\x) -- +(0,-6.5);
}
% if desired, example for placement of note descriptions:
\foreach \a/\b in {1/E, 2/B, 3/G, 4/D, 5/A, 6/E} {
\foreach \x in {1,...,24} {
\pgfmathsetmacro{\xmin}{\x-1}
\path (fret\x) -- (fret\xmin) node[yshift=-\a cm,midway] {$\times$};
}
}
\end{tikzpicture}
\end{document}


• Can you elaborate on this? You've added a bunch of things that are mostly new/alien to me. What is \pgfmathsetmacro, etc? Can I apply some section of your code to mine? Or do I have to start again. – voices Jul 18 '19 at 22:34
• @tjt263 I have preserved most of your code. For calculating coordinates, I've actually just moved the frets loop out of the strings loop, as their coordinates need to be calculated only once. The \pgfmathsetmacro command is used just to parse the result of the calculation to a variable that can be used for defining a coordinate (\def does not work because it just saves exactly the string of the calculation; it does not perform the calculation). \pgfmathsetmacro is used a second time to specify the counter \x-1, to define the coordinate that lies between fret(x) and fret(x-1). – JJM Driessen Jul 22 '19 at 9:08