% --------------------------------------------------------------------------
% the GUITARCHORDSCHEMES package
% 
%   Guitar Chord and Scale Tablatures with TikZ
% 
% --------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://bitbucket.org/cgnieder/guitarchordschemes/
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2013 Clemens Niederberger
% 
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
% 
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Clemens Niederberger.
% --------------------------------------------------------------------------
% The guitarchordschemes package consists of the files
%  - guitarchordschemes.sty,
%  - guitarchordschemes_en.tex,
%  - guitarchordschemes_en.pdf,
%  - README
% --------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% --------------------------------------------------------------------------
%
% package info and requirements:
\NeedsTeXFormat{LaTeX2e}
\def\gcs@date{2013/08/25}
\def\gcs@version{v0.4}
\def\gcs@description{Guitar Chord and Scale Tablatures with TikZ (CN)}

\ProvidesPackage{guitarchordschemes}[\gcs@date\space \gcs@version\space \gcs@description]

\RequirePackage{tikz,etoolbox,pgfopts}
\usetikzlibrary{shapes.misc,arrows,calc}
% --------------------------------------------------------------------------
% message handling
\def\gcs@create@message#1{%
  \ifstrequal{#1}{Error}
    {%
      \lowercase{\csdef{gcs@#1}}##1##2{%
        \csuse{Package#1}{guitarchordschemes}{##1}{##2}}%
    }{%
      \lowercase{\csdef{gcs@#1}}##1{%
        \csuse{Package#1}{guitarchordschemes}{##1}}%
    }}
\gcs@create@message{Error}
\gcs@create@message{Warning}
\gcs@create@message{WarningNoLine}
\gcs@create@message{Info}

\def\gcs@missing@date@error#1#2{%
  \gcs@error
    {#1: empty #2}
    {#1: It seems you didn't specify the #2}%
}

\def\gcs@cs@new{\protected\def}

% --------------------------------------------------------------------------
% package options and setup:
\newbool{gcs@rbc}

\def\gcs@finger@font{\sffamily\small}
\def\gcs@position@font{\sffamily}
\def\gcs@name@font{\large}
\def\gcs@string@name@format{\sffamily\small}

\def\gcs@x@unit{.8cm}
\def\gcs@y@unit{.8cm}
\def\gcs@line@width{1pt}
\def\gcs@finger@radius{.1875}
\def\gcs@finger@x@offset{.375}
\def\gcs@finger@y@offset{.275}

\pgfkeys{
  guitarchordschemes/.cd ,
    x-unit/.code              = \def\gcs@x@unit{#1} ,
    y-unit/.code              = \def\gcs@y@unit{#1} ,
    finger-format/.code       = \def\gcs@finger@font{#1} ,
    finger-format+/.code      =
      \expandafter\def\expandafter\gcs@finger@font
      \expandafter{\gcs@finger@font#1} ,
    position-format/.code     = \def\gcs@position@font{#1} ,
    position-format+/.code    =
      \expandafter\def\expandafter\gcs@position@font
      \expandafter{\gcs@position@font#1} ,
    name-format/.code         = \def\gcs@name@font{#1} ,
    name-format+/.code        =
      \expandafter\def\expandafter\gcs@name@font
      \expandafter{\gcs@name@font#1} ,
    string-name-format/.code  = \def\gcs@string@name@format{#1} ,
    string-name-format+/.code =
      \expandafter\def\expandafter\gcs@string@name@format
      \expandafter{\gcs@string@name@format#1} ,
    line-width/.code          = \def\gcs@line@width{#1} ,
    finger-radius/.code       = \def\gcs@finger@radius{#1} ,
    finger-x-offset/.code     = \def\gcs@finger@x@offset{#1} ,
    finger-y-offset/.code     = \def\gcs@finger@y@offset{#1} ,
    finger-style/.code        = \tikzset{finger style/.style={#1}} ,
    root-style/.code          = \tikzset{root style/.style={#1}} ,
    show-root-style/.code     = \tikzset{show root style/.style={#1}} , ,
    ringing-style/.code       = \tikzset{ringing style/.style={#1}} ,
    muted-style/.code         = \tikzset{muted style/.style={#1}} ,
    tuning/.code              = \gcs@chord@tuning{#1} ,
    use-rbc/.is if            = gcs@rbc
}

% the setup command:
\newrobustcmd*\setchordscheme[1]{\pgfqkeys{/guitarchordschemes}{#1}}

\newcounter{gcs@string@number}
\newcommand\gcs@chord@tuning[1]{%
  \setcounter{gcs@string@number}{0}%
  \foreach \string@name in {#1}
    {%
      \stepcounter{gcs@string@number}%
      \csxdef{guitar@string@\arabic{gcs@string@number}}{\expandonce\string@name}%
    }%
}

% some defaults - need to be set before options are processed:
\setchordscheme{
  tuning          = {E,B,G,D,A,E} ,
  muted-style     = {cross out,draw} ,
  root-style      = {fill} ,
  show-root-style = {draw} ,
  ringing-style   = {draw} ,
  finger-style    = {fill}
}

\ProcessPgfOptions*

% --------------------------------------------------------------------------
% are we using `realbookchords'?
\ifbool{gcs@rbc}{\RequirePackage{realbookchords}}{}

% --------------------------------------------------------------------------
% settings for the whole scheme:
\tikzset{
  gcs/finger/.style =
    {
      xshift = \gcs@finger@x@offset*\gcs@x@unit ,
      yshift = \gcs@finger@y@offset*\gcs@y@unit ,
      font   = \gcs@finger@font
    }
}

% setting a chord scheme:
\pgfkeys{
  gcs/chord/.cd ,
    name/.code      = \gcs@chord@name{#1} ,
    position/.code  = \def\gcs@chord@position{#1} ,
    finger/.code    = \gcs@chord@finger{#1} ,
    root/.code      = \gcs@chord@root{#1} ,
    show-root/.code = \gcs@chord@show@root{#1} ,
    mute/.code      = \gcs@chord@mute{#1} ,
    ring/.code      = \gcs@chord@ring{#1} ,
    barre/.code     = \gcs@chord@barre{#1}
}

% setting a scale:
\pgfkeys{
  gcs/scales/.cd ,
    name/.code         = \gcs@scales@name{#1} ,
    position/.code     = \def\gcs@scales@position{#1} ,
    finger/.code       = \gcs@scales@finger{#1} ,
    root/.code         = \gcs@scales@root{#1} ,
    fret number/.code  =
      \ifnumless{#1}{6}
        {%
          \gcs@warning{You cannot use less than 6 frets for a scale!}%
          \def\gcs@scales@fret@number{6}%
        }
        {\def\gcs@scales@fret@number{#1}} ,
    fingering/.is choice ,
    fingering/type 1/.code =
      \gcs@scales@finger{%
        1/1:1s,        3/1:2,        5/1:4,
                       3/2:2,        5/2:4,
                2/3:1,        4/3:3,
                2/4:1, 3/4:2,        5/4:4,
                2/5:1,               5/5:4,
        1/6:1s,        3/6:2,        5/6:4
      }%
      \gcs@scales@root{5/3:4, 3/5:2} ,
    fingering/type 1A/.code =
      \gcs@scales@finger{%
                       3/1:2,        5/1:4,
                       3/2:2,        5/2:4,
                2/3:1, 3/3:2,        5/3:4,
                2/4:1,               5/4:4,
        1/5:1s,        3/5:2,        5/5:4,
                       3/6:2,        5/6:4
      }%
      \gcs@scales@root{1/1:1s, 3/4:2, 1/6:1s} ,
    fingering/type 2/.code =
      \gcs@scales@finger{%
                2/1:1,               5/1:4,
                       3/2:2,        5/2:4,
                2/3:1,        4/3:3, 5/3:4,
                2/4:1,        4/4:3,
                2/5:1, 3/5:2,        5/5:4,
                2/6:1,               5/6:4
      }%
      \gcs@scales@root{3/1:2, 5/4:4, 3/6:2},
    fingering/type 3/.code =
      \gcs@scales@finger{%
                2/1:1, 3/1:2,        5/1:4,
                2/2:1,               5/2:4,
                2/3:1,        4/3:3,
                2/4:1,        4/4:3, 5/4:4,
                2/5:1,        4/5:3,
                2/6:1, 3/6:2,        5/6:4
      }%
      \gcs@scales@root{3/2:2, 5/5:4},
    fingering/type 4/.code =
      \gcs@scales@finger{%
                2/1:1,        4/1:3,
                2/2:1, 3/2:2,        5/2:4,
                              4/3:3,
                2/4:1,        4/4:3,        6/4:4s,
                2/5:1,        4/5:3, 5/5:4,
                2/6:1,        4/6:3
      }%
      \gcs@scales@root{5/1:4, 2/3:1, 5/6:4},
    fingering*/.is choice ,
    fingering*/type 1/.code =
      \gcs@scales@finger{%
        1/1:1s,        3/1:2,        5/1:4,
                       3/2:2,        5/2:4,
                2/3:1,        4/3:3, 5/3:4,
                2/4:1, 3/4:2,        5/4:4,
                2/5:1, 3/5:2,        5/5:4,
        1/6:1s,        3/6:2,        5/6:4
      } ,
    fingering*/type 1A/.code =
      \gcs@scales@finger{%
        1/1:1s,        3/1:2,        5/1:4,
                       3/2:2,        5/2:4,
                2/3:1, 3/3:2,        5/3:4,
                2/4:1, 3/4:2,        5/4:4,
        1/5:1s,        3/5:2,        5/5:4,
        1/6:1s,        3/6:2,        5/6:4
      } ,
    fingering*/type 2/.code =
      \gcs@scales@finger{%
                2/1:1, 3/1:2,        5/1:4,
                       3/2:2,        5/2:4,
                2/3:1,        4/3:3, 5/3:4,
                2/4:1,        4/4:3, 5/4:4,
                2/5:1, 3/5:2,        5/5:4,
                2/6:1, 3/6:2,        5/6:4
      } ,
    fingering*/type 3/.code =
      \gcs@scales@finger{%
                2/1:1, 3/1:2,        5/1:4,
                2/2:1, 3/2:2,        5/2:4,
                2/3:1,        4/3:3,
                2/4:1,        4/4:3, 5/4:4,
                2/5:1,        4/5:3, 5/5:4,
                2/6:1, 3/6:2,        5/6:4
      } ,
    fingering*/type 4/.code =
      \gcs@scales@finger{%
                2/1:1,        4/1:3, 5/1:4,
                2/2:1, 3/2:2,        5/2:4,
                2/3:1,        4/3:3,
                2/4:1,        4/4:3,        6/4:4s,
                2/5:1,        4/5:3, 5/5:4,
                2/6:1,        4/6:3, 5/6:4
      },
    fingering?/.is choice ,
    fingering?/type 1/.code =
      \gcs@scales@finger{%
        1/1,      3/1,      5/1,
                  3/2,      5/2,
             2/3,      4/3, 5/3,
             2/4, 3/4,      5/4,
             2/5, 3/5,      5/5,
        1/6,      3/6,      5/6
      } ,
    fingering?/type 1A/.code =
      \gcs@scales@finger{%
        1/1,      3/1,      5/1,
                  3/2,      5/2,
             2/3, 3/3,      5/3,
             2/4, 3/4,      5/4,
        1/5,      3/5,      5/5,
        1/6,      3/6,      5/6
      } ,
    fingering?/type 2/.code =
      \gcs@scales@finger{%
             2/1, 3/1,      5/1,
                  3/2,      5/2,
             2/3,      4/3, 5/3,
             2/4,      4/4, 5/4,
             2/5, 3/5,      5/5,
             2/6, 3/6,      5/6
      } ,
    fingering?/type 3/.code =
      \gcs@scales@finger{%
             2/1, 3/1,      5/1,
             2/2, 3/2,      5/2,
             2/3,      4/3,
             2/4,      4/4, 5/4,
             2/5,      4/5, 5/5,
             2/6, 3/6,      5/6
      } ,
    fingering?/type 4/.code =
      \gcs@scales@finger{%
             2/1,      4/1, 5/1,
             2/2, 3/2,      5/2,
             2/3,      4/3,
             2/4,      4/4,      6/4,
             2/5,      4/5, 5/5,
             2/6,      4/6, 5/6
      }
}

% --------------------------------------------------------------------------
% the internal commands

% placing fingers:
%   <fret>/<string>:<finger>
\gcs@cs@new\gcs@chord@finger#1{%
  \foreach \gcs@finger@spec in {#1}
    {
      \expandafter\gcs@get@finger@data\gcs@finger@spec::\q@stop
      \ifdefvoid\finger@x
        {\gcs@missing@date@error{finger}{position}}
        {
          \pgfmathsetmacro\finger@fret{1.5*\finger@x-0.75}
          \ifdefvoid\finger@y
            {\gcs@missing@date@error{finger}{string}}
            {
              \pgfmathsetmacro\finger@string{(6-\finger@y)*4/5}
              \draw[finger style]
                (\finger@fret,\finger@string) circle (\gcs@finger@radius*\gcs@x@unit) ;
              \node[gcs/finger] at (\finger@fret,\finger@string) {\finger@number} ;
            }
        }
    }
}
\let\gcs@scales@finger\gcs@chord@finger

\gcs@cs@new\gcs@get@finger@data#1/#2:#3:#4\q@stop{%
  \def\finger@x{#1}%
  \def\finger@y{#2}%
  \def\finger@number{#3}%
}

% placing a barre:
%   <fret>/<string>-<string>:<finger>
\gcs@cs@new\gcs@chord@barre#1{%
  \foreach \gcs@barre@spec in {#1}
    {
      \expandafter\gcs@get@barre@data\gcs@barre@spec::\q@stop
      \ifdefvoid\barre@x
        {\gcs@missing@date@error{barre}{position}}
        {\pgfmathsetmacro\barre@fret{1.5*\barre@x-0.75}}
      \ifdefvoid\barre@fromto
        {\gcs@missing@date@error{barre}{string range}}
        {
          \expandafter\gcs@barre@getstrings\barre@fromto--\q@stop
          \pgfmathsetmacro\barre@lower@string{(6-\barre@lower@y)*4/5}
          \pgfmathsetmacro\barre@upper@string{(6-\barre@upper@y)*4/5}
          \draw[finger style,round cap-round cap,line width=2*\gcs@finger@radius*\gcs@x@unit]
            (\barre@fret,\barre@lower@string) node[gcs/finger] {\barre@finger}
            ++ (0,\gcs@finger@radius*\gcs@x@unit)
            --
            ($(\barre@fret,\barre@upper@string)+(0,-\gcs@finger@radius*\gcs@x@unit)$)
          ;
        }
    }
}

\gcs@cs@new\gcs@get@barre@data#1/#2:#3:#4\q@stop{%
  \def\barre@x{#1}%
  \def\barre@fromto{#2}%
  \def\barre@finger{#3}%
}

\gcs@cs@new\gcs@barre@getstrings#1-#2-#3\q@stop{%
  \ifx#3-\relax
    \def\barre@lower@y{#1}%
    \def\barre@upper@y{#2}%
  \else
    \gcs@error
      {barre: wrong string range syntax}
      {barre: wrong string range syntax}%
  \fi
}

% placing root fingers:
%   <fret>/<string>:<finger>
\gcs@cs@new\gcs@chord@root#1{%
  \foreach \gcs@finger@spec in {#1}
    {
      \expandafter\gcs@get@finger@data\gcs@finger@spec::\q@stop
      \ifdefvoid\finger@x
        {\gcs@missing@date@error{root}{position}}
        {
          \pgfmathsetmacro\finger@fret{1.5*\finger@x-0.75}
          \ifdefvoid\finger@y
            {\gcs@missing@date@error{root}{string}}
            {
              \pgfmathsetmacro\finger@string{(6-\finger@y)*4/5}
              \node[minimum size=2*\gcs@finger@radius*\gcs@x@unit,root style]
                at (\finger@fret,\finger@string) {} ;
              \node[gcs/finger] at (\finger@fret,\finger@string) {\finger@number} ;
            }
        }
    }
}
\let\gcs@scales@root\gcs@chord@root

% placing ghost roots:
%   <fret>/<string>
\gcs@cs@new\gcs@chord@show@root#1{%
  \foreach \gcs@finger@spec in {#1}
    {
      \expandafter\gcs@get@finger@data\gcs@finger@spec::\q@stop
      \ifdefvoid\finger@x
        {\gcs@missing@date@error{show-root}{position}}
        {
          \pgfmathsetmacro\finger@fret{1.5*\finger@x-0.75}
          \ifdefvoid\finger@x
            {\gcs@missing@date@error{show-root}{string}}
            {
              \pgfmathsetmacro\finger@string{(6-\finger@y)*4/5}
              \node[minimum size=2*\gcs@finger@radius*\gcs@x@unit,show root style]
                at (\finger@fret,\finger@string) {} ;
            }
        }
    }
}

% muted strings:
\gcs@cs@new\gcs@chord@mute#1{%
  \foreach \muted@string in {#1}
    {
      \pgfmathsetmacro\muted@string@pos{(6-\muted@string)*4/5}
      \node[muted style] at (0,\muted@string@pos) {} ;
    }
}

% ringing strings:
\gcs@cs@new\gcs@chord@ring#1{%
  \foreach \ringing@string in {#1}
    {
      \pgfmathsetmacro\ringing@string@pos{(6-\ringing@string)*4/5}
      \draw[ringing style]
        (0,\ringing@string@pos) circle (\gcs@finger@radius*\gcs@x@unit) ;
    }
}

% the chord name:
\gcs@cs@new\gcs@chord@name#1{%
  \node[above,yshift=4ex] at (3,4) {%
  \foreach \gcs@chord@name@variant in {#1}
    {%
      \gcs@name@font
      \space
      \ifbool{gcs@rbc}
        {\expandafter\rbc\expandafter{\gcs@chord@name@variant}}
        {\gcs@chord@name@variant}%
      \space
    }%
  } ;
}

% the scale name:
\gcs@cs@new\gcs@scales@name#1{%
  \node[above,yshift=4ex] at (4.5,4) {%
  \foreach \gcs@scales@name@variant in {#1}
    {%
      \gcs@name@font
      \space
      \gcs@scales@name@variant
      \space
    }%
  } ;
}

% --------------------------------------------------------------------------
% the chord scheme command:
\gcs@cs@new\gcs@chordscheme#1{%
\begingroup
\begin{tikzpicture}[
   x=\gcs@x@unit,
   y=\gcs@y@unit,
   line width=\gcs@line@width,
   baseline=(6thstring)
 ]
 \coordinate (6thstring) at (0,0) ;
 \foreach \fret in { 0,1.5,3,4.5,6 }
   { \draw (\fret,0) -- (\fret,4) ; }
 \foreach \string@pos/\string@number in
   { 0/6, 0.8/5, 1.6/4, 2.4/3, 3.2/2, 4/1, 0 }
   {
     \draw (0,\string@pos) node[left,minimum width=2em]
       {\gcs@string@name@format\csuse{guitar@string@\string@number}} -- (6,\string@pos) ;
   }
 \pgfqkeys{/gcs/chord}{#1}%
 \ifdefvoid\gcs@chord@position
   {}
   {\node[above,yshift=1ex,font=\gcs@position@font] at (.75,4) {\gcs@chord@position} ;}
\end{tikzpicture}
\endgroup
}

% --------------------------------------------------------------------------
% the scalescommand:
\def\gcs@scales@fret@number{6}

\gcs@cs@new\gcs@scales#1{%
  \begingroup
    \begin{tikzpicture}[
       x=\gcs@x@unit,
       y=\gcs@y@unit,
       line width=\gcs@line@width,
       baseline=(6thstring)
     ]
     \pgfqkeys{/gcs/scales}{#1}%
     \coordinate (6thstring) at (0,0) ;
     \foreach \fret in { 0,1,...,\gcs@scales@fret@number }
       { \draw (1.5*\fret,0) -- (1.5*\fret,4) ; }
     \foreach \string@pos/\string@number in
       { 0/6, 0.8/5, 1.6/4, 2.4/3, 3.2/2, 4/1, 0 }
       {
         \draw (0,\string@pos) node[left,minimum width=2em]
           {\gcs@string@name@format\csuse{guitar@string@\string@number}}
           -- (1.5*\gcs@scales@fret@number,\string@pos) ;
       }
     \ifdefvoid\gcs@scales@position
       {}
       {%
         \node[above,yshift=1ex,font=\gcs@position@font] at (.75,4)
           {\gcs@scales@position} ;
       }
    \end{tikzpicture}
  \endgroup
}

% --------------------------------------------------------------------------
% the user commands:
\newrobustcmd*\chordscheme[1][]{\gcs@chordscheme{#1}}

\newrobustcmd*\scales[1][]{\gcs@scales{#1}}

% --------------------------------------------------------------------------
% the symbols for use outside of a scheme:
\newrobustcmd*\fingersymbol{%
  \tikz\draw[finger style] (0,0) circle (\gcs@finger@radius*\gcs@x@unit);}

\newrobustcmd*\rootsymbol{%
  \tikz\node[root style,minimum size=2*\gcs@finger@radius*\gcs@x@unit] at (0,0) {} ;}

\newrobustcmd*\showrootsymbol{%
  \tikz\node[
    show root style,
    minimum size=2*\gcs@finger@radius*\gcs@x@unit,
    line width=\gcs@line@width] at (0,0) {} ;}

\newrobustcmd*\ringingstring{%
  \tikz\draw[
    ringing style,
    line width=\gcs@line@width] (0,0) circle (\gcs@finger@radius*\gcs@x@unit);}

\newrobustcmd*\mutedstring{%
  \tikz\node[
    muted style,
    line width=\gcs@line@width] at (0,0) {};}

\endinput
% --------------------------------------------------------------------------
% HISTORY
2013/04/28 v0.1  - first version
2013/04/29 v0.1a - added error handling and messages
2013/04/30 v0.2  - it's stupid to set colors explicitly -- better define TikZ
                   styles for this
2013/05/01 v0.3  - added \scales command
2013/05/01 v0.3a - set all lengths as multiples of the base unit
2013/08/25 v0.4  - added scale option that allows variable number of frets
