4

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 ?

LCK
  • 43
  • 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
  • @Skillmon, no, I use 440 Hz to calculate and the formula in the code uses 440 Hz too : \frequency=(2^((\note-49)/12))*440; – LCK Aug 28 '18 at 13:42
  • It was a wild guess:) I guess if the formula is correct and the correct values are used in the formula, the only source of discrepancy left is in fact a precision issue. – Skillmon Aug 28 '18 at 13:48
  • 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
  • Probably, is it a pgf issue ? I can't explain why the values [in this post] (https://tex.stackexchange.com/questions/111008/range-of-a-piano-annotate-note-frequency) are correct. The formula is the same... – LCK Aug 28 '18 at 13:56
  • 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
  • @Mark Wibrow (I try to earburn the author of the answer, if it is not appropriate, tell me, I am a newbie here... can't do it in the original post) did you notice ? – LCK Aug 28 '18 at 14:04
  • 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
  • OK so the authors of tikz decided that "nobody will ever need more than 5 decimal places (of an inch?) for drawing pictures," I suppose! – alephzero Aug 28 '18 at 14:25
  • 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
  • As a physicist, I can tell you this: there's absolutely no need to use three decimals here, because no instrument can stay that precise, and no ear can hear the difference of 0.007 Hz. At frequencies this low, you're lucky if you can hear the difference between C1 and C1#, which is about 2 Hz. Thus, simply round to one or zero decimals. – PhilipPirrip Aug 28 '18 at 15:37

1 Answers1

11

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

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
Skillmon
  • 60,462
  • 1
    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 07: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 07: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 07:44
  • @Skillmonlikestopanswers.xyz I am a complete beginner of TikZ and I want to draw a plain piano without it's range. I am trying to learn how you have coded it, but everything is tightly nested. Can you explain how to have a plain piano template without any other stuff on it with the help of this code? – Niranjan Feb 04 '20 at 12:14
  • @Niranjan you should ask a new question on the site. Reference this question and the question linked to in the OP. – Skillmon Feb 04 '20 at 12:19
  • @sgmoye I found a nice article that looks into the details of black key spacing. – Petr Oct 10 '20 at 10:06