3

This is a kind of follow-up to this question. The last answer is almost perfect, but the frequency on the keyboard is wrong. For example, C1 should be 32.703, not 32.696. I can't find the error, the formula is correct. Can someone help please ?

  • Perhaps this is caused by 440 Hz vs. 442 Hz vs. 443 Hz and you looked up the frequency of C1 in a source using 443 Hz for a4 instead of 440 Hz? In Germany and Austria 443 Hz are common, in Swiss 442 Hz, so if your source for the 32.703 Hz for C1 is in German language this could be the origin of the discrepancy. – Skillmon Aug 28 '18 at 13:37
  • 1
    Whoever voted to close: This is NOT opinion based. If the original question is using the same formula for calculation and the same standard pitch, the discrepancy between 32.703 and 32.696 is not opinion based! – Skillmon Aug 28 '18 at 13:53
  • 1
    I just checked the expl3 floating point unit and it indeed gets the correct value (I did so before you posted that link...). The source is indeed the maths implementation of pgf, which doesn't have the same precision as expl3's. – Skillmon Aug 28 '18 at 13:59
  • 1
    Just compare the results of the "exact" result (using python3) with the results if you introduce some "precision": 2**((4-49)/12) is 0.07432544468767006. This times 440 is 32.70319566257483. But if you apply a precision of 5 digits after the decimal marker you get 0.0743*440 = 32.692. – Skillmon Aug 28 '18 at 14:05
  • 2
    @alephzero no, they used TeX's calculation which happens to be limited to the precision of an sp (which is so small that no human eye can see a difference). TeX's calculation wasn't meant for scientific calculus. – Skillmon Aug 28 '18 at 14:28
8

Using expl3 to calculate the frequencies (the rest of this answer is shamelessly copied from the answer linked in this question):

\documentclass[border=0.25cm]{standalone}
\usepackage{xparse}
\usepackage{tikz}
\usepackage{musixtex}
\ExplSyntaxOn
\NewExpandableDocumentCommand \myFrequencyCalculation { m }
  { \fp_to_decimal:n { round(2**((#1-49)/12)*440,3) } }
\ExplSyntaxOff
\begin{document}
\pgfdeclarelayer{blacknotes}
\pgfsetlayers{main,blacknotes}
\tikzset{tight fit/.style={inner sep=0pt, outer sep=0pt}}

\begin{tikzpicture}
\def\lastnotenodename{clefs}
\node [text width=1cm, tight fit] (clefs) at (0,0) {
    \begin{music}
        \instrumentnumber{1}
        \instrumentnumber{2}
        \nostartrule        
        \setstaffs1{1}
        \setstaffs2{1}  
        \setclef1{\bass}
        \setclef2{\treble}                                  
        \startextract
        \hskip2.0\elemskip
        \zendextract
    \end{music}
};

\foreach \note [
    evaluate={
        \n=int(mod(\note-1, 12));
        \octave=int((\note+8)/12);
        \t=int(floor((\note-1)/12)*7-7);
        \notename={"A","","B","C","","D","","E","F","","G",""}[\n];
        \tonicsolfa={"la","","si","so","","r\`e","","mi","fa","","sol",""}[\n];
        \blacknote={0,1,0,0,1,0,1,0,0,1,0,1}[\n];
        \frequency={\myFrequencyCalculation{\note}};}
] in {1,...,88}{

    \ifnum\octave>3
        \tikzset{extract anchor/.style={anchor=south west, at=(\lastnotenodename.south east)}}
    \else
        \tikzset{extract anchor/.style={anchor=north west, at=(\lastnotenodename.north east)}}
    \fi
    \ifnum\blacknote=0
        \edef\notenodename{\notename_\octave}
        \node (\notenodename) [tight fit,text width=1cm, extract anchor/.try]  {%           
            \begin{music}
                \instrumentnumber{1}
                \instrumentnumber{2}
                \nostartrule        
                \setstaffs1{1}
                \setstaffs2{1}  
                \setclefsymbol1{\empty}
                \setclefsymbol2{\empty}     
                \setclef1{\bass}
                \setclef2{\treble}                      
                \startextract
                \transpose\t
                \hskip-1.5\elemskip         
                \ifnum\octave>3
                    \ifnum\octave>4
                        \Notes \nextinstrument \ql{\notename} \en       
                    \else
                        \Notes \nextinstrument \qu{\notename} \en                       
                    \fi
                \else
                    \ifnum\octave>2
                        \Notes \ql{\notename} \en
                    \else
                        \Notes \qu{\notename} \en
                    \fi
                \fi
                \zendextract
            \end{music}
        };
        \xdef\lastnotenodename{\notenodename}       
        \node [anchor=base] (sol-fa)  at (\notenodename |- 0,-3) {\tonicsolfa$_\octave$};

        \draw (\notenodename.south west |- 0,-4) rectangle ++(1, -4);
        \node [rotate=90, font=\footnotesize, anchor=east] 
            at (\notenodename.north |- 0,-4) {\frequency};
        \node [font=\footnotesize, anchor=south]  
            at (\notenodename.south |- 0,-8) {\note};
        \node [font=\footnotesize, anchor=south] 
            at (\notenodename.south |- 0,-8.5)  {\notename$_\octave$};
        \draw (\notenodename.south west |- sol-fa.south) 
            rectangle (\notenodename.south east |- 0,1.125); %0.125 by trial and error
    \else
        \begin{pgfonlayer}{blacknotes}
        \fill ([xshift=-0.25cm]\lastnotenodename.north east |- 0,-4) rectangle ++(0.5, -2.5);
        \node  [rotate=90, text=white, font=\footnotesize, anchor=east]
            at (\lastnotenodename.north east |- 0,-4) {\frequency};
        \end{pgfonlayer}
    \fi
}
\node [rotate=90] at (0,-6) {Fr\`equency (Hz)};
\end{tikzpicture}

\end{document}

enter image description here

  • It is an excellent answer (I upvoted it) but the piano keyboard is not absolutely correctly drawn. It may seem a minor point, but there is a lot of history and music theory behind the layout of the keyboard. This is a common thing, so common it is practically impossible to find an illustration that is correct. Almost all diagrams show black keys equally bisected by by their neighboring white keys. In fact this is true only for G-sharp. I wish I could post a diagram -- I've worked it out with TikZ, and a very informative project it was. Still, excellent answer! – sgmoye Aug 28 '18 at 18:20
  • You can use the document-level \fpeval function from xfp rather than needing to go to the expl3 layer – Joseph Wright Aug 29 '18 at 7:01
  • @JosephWright I don't see the advantage of a wrapper here (the CPU cost of the document is high already, why increase it with it?). – Skillmon Aug 29 '18 at 7:28
  • @Skillmon Avoids needing \ExplSyntaxOn, etc. in the document. There's no significant hit over the current code: the number of expansions only goes up a tiny amount. – Joseph Wright Aug 29 '18 at 7:44

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.