2

\gtabs part of songs package prints a guitar chord based on two parameters

\gtab{chord name}{guitar frets and strings}

The second parameter is not accepting \pgfkeys as second parameter

Here is the code to illustrate the example:

\documentclass{article}
\RequirePackage{filecontents}% write the data file
\usepackage{pgfkeys}
\usepackage{xparse}
\usepackage{songs}

\begin{filecontents}{chords.csv}
    A   = { A,0022200}
    A01 = { A,5:133211:143211}
    B = { B,X24442} 
    C = { C,032010}
\end{filecontents}

% BEGIN Read Chord Definitions
\pgfkeys{/chords/.is family, chords,
.unknown/.code args={#1,#2}{ % Format is <name>,<capital>,<population>
    \pgfkeyssetvalue{\pgfkeyscurrentpath/\pgfkeyscurrentname/c_name}{#1}
    \pgfkeyssetvalue{\pgfkeyscurrentpath/\pgfkeyscurrentname/c_def}{#2}},
}

\newcommand\printchordnm[1]{% print the key if it is defined and ???Otherwise
    \pgfkeysifdefined{/chords/#1/c_name}{\pgfkeysvalueof{/chords/#1/c_name}}{???}%
}

\newcommand\printchordef[1]{% print the key if it is defined and ???Otherwise
    \pgfkeysifdefined{/chords/#1/c_def}{\pgfkeysvalueof{/chords/#1/c_def}}{???}%
}

\newcommand\AddState[1]{\expandafter\pgfkeys\expandafter{/chords, #1}}
\newread\statefile% file handler
\def\apar{\par}% \ifx\par won't work but \ifx\apar will
\newcommand\ReadStates[1]{% read file into [\pgfkeys{/state}
    \openin\statefile=#1% open file for reading
    \loop\unless\ifeof\statefile% loop until end of file
    \read\statefile to \stateline% read line from file
    \ifx\stateline\apar% test for \par
    \else%
    \ifx\stateline\empty\relax% skip over empty lines/comments
    \else\expandafter\AddState\expandafter{\stateline}%
    \fi%
    \fi%
    \repeat% end of file reading loop
    \closein\statefile% close input file
}
\ReadStates{chords.csv}% read the file


\begin{document}
    \def\hpvardef{\printchordef{A01}}
    Hi \printchordnm{A01} and definition is \printchordef{A01}\par 

    the chord is represented as \gtab{A}{5:133211:143211}\par 
    Using macro as first parameter OK \gtab{\printchordnm{A01}}{5:133211:143211}\par 
    Now I want to use macro as second parameter \gtab{A02}{\printchordef{A01}}\par 
    which generates an error\par 
    What about local macro def hpvardef: \hpvardef\par 
    Let's try it \gtab{A02}{\hpvardef}
\begin{songs}{}
\end{songs}
\end{document}

enter image description here

  • Well, most likely \hpvardef isn't expandable, because the macro \printchordef isn't expandable? – user31729 Feb 23 '17 at 21:31
  • Why are you checking definitions and using unknown handlers ? pgfkeys exists so that you don't do those things. – percusse Feb 23 '17 at 22:51
  • @percusse I have no control on what Chords are requested from the document so as a precaution and for testing purposes I check first if a chord is defined for the key sent. Removing \pgfkeysifdefined does not change the behavior of the code. Regarding \hpvardef, the same error occurs if I enter as arguments of the \gtabs the \pgfkeysvalueof The variable \hpvardef was created to try to expand first the value of \pgfkeysvalueof. – hpcolos Feb 24 '17 at 6:29
1

Based on explanation provided by Elrich at \gtab [songs package] using macro variable as second parameter I adapted two of his macro commands as follows

\documentclass{article}
\RequirePackage{filecontents}% write the data file
\usepackage{pgfkeys}
\usepackage{xparse}
\usepackage{songs}

\begin{filecontents}{chords.csv}
    A   = { A,0022200}
    A01 = { A,5:133211:143211}
    B = { B,X24442} 
    C = { C,032010}
\end{filecontents}

% BEGIN Read US Chords Definitions
\pgfkeys{/chords/.is family, chords,
    .unknown/.code args={#1,#2}{ % Format is <name>,<capital>,<population>
        \pgfkeyssetvalue{\pgfkeyscurrentpath/\pgfkeyscurrentname/c_name}{#1}
        \pgfkeyssetvalue{\pgfkeyscurrentpath/\pgfkeyscurrentname/c_def}{#2}},
}

\newcommand\AddChord[1]{\expandafter\pgfkeys\expandafter{/chords, #1}}
\newread\Chordfile% file handler
\def\apar{\par}% \ifx\par won't work but \ifx\apar will
\newcommand\ReadChords[1]{% read file into [\pgfkeys{/Chord}
    \openin\Chordfile=#1% open file for reading
    \loop\unless\ifeof\Chordfile% loop until end of file
    \read\Chordfile to \Chordline% read line from file
    \ifx\Chordline\apar% test for \par
    \else%
    \ifx\Chordline\empty\relax% skip over empty lines/comments
    \else\expandafter\AddChord\expandafter{\Chordline}%
    \fi%
    \fi%
    \repeat% end of file reading loop
    \closein\Chordfile% close input file
}
\ReadChords{chords.csv}% read the file


\makeatletter

\newcommand\hpvarC[2]{\TotalExpandSecondFirst{\expandafter\gtab\@firstofone}{{#1}{#2}}}%

\newcommand\TotalExpandSecondFirst[2]{%
    \begingroup
    \protected@edef\mytempa{{#2}}%
    \expandafter\PassFirstToSecond\mytempa{\endgroup#1}%
}%
\makeatother

\newcommand\PassFirstToSecond[2]{#2{#1}}%

\newcommand\hptab[1]{% print the key if it is defined and ???Otherwise
    \pgfkeysgetvalue{/chords/#1/c_name}\hpdeni
    \pgfkeysgetvalue{/chords/#1/c_def}\hpdeff 

    Variant    is: #1\par 
    Chord      is: \hpdeni\par 
    Definition is: \hpdeff\par

    Hello ``\hpvarC{\hpdeni}{\hpdeff}''

}

\begin{document}

    My music book prints chords using macro definitions.\par
    All I do is send the variant chord I want to hptab\par 
    Let's try it\par 
    \bigskip
    Print First Variant of Chord A\par 
    \par 
    Let's call first hptab\{A01\} but take a look at hpvarC
    \hptab{A01}
\end{document}

enter image description here

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.