TikZ-PGF – Range of a Piano: Keyboard vs Staves

musictikz-pgf

This is a kind of follow-up to this question. I'd like to reproduce with tikz the following image.

piano scale

I have no idea of how I could "synchronize" the output of musictex and tikz. Maybe I'd better stick with tikz but then I don't know how to draw realistic notes, staves and keys (borrowing them from musictex)?

Here is what I've done so far in tikz.

tikz piano

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
  \tikzset{%
    White/.style = {%
      node distance = 0cm and 0cm,
      draw,
      minimum width = .25cm,
      minimum height = 1.25cm,
      inner sep = 0pt},
    Black/.style = {%
      fill = black,
      minimum width = .15cm,
      minimum height = .75cm,
      inner sep = 0pt,
      anchor = north},
  }

  \node[White] (White--1-6) {};

  \node[font = \tiny,above] at (White--1-6.north)
  {$\mathrm{A}_{-1}$}; 

  \node[font = \tiny,below] at (White--1-6.south)
  {1};

  \pgfmathsetmacro\frequency{round(440 * 2^(((1)-49)/12))}
  \node[font = \tiny,above,rotate = 90,transform shape,anchor = west] at
  (White--1-6.south) {\frequency};


  \node[White,right = of White--1-6] (White--1-7) {};

  \node[font = \tiny,above] at (White--1-7.north)
  {$\mathrm{B}_{-1}$}; 

  \node[font = \tiny,below] at (White--1-7.south)
  {3};

  \pgfmathsetmacro\frequency{round(440 * 2^(((3)-49)/12))}
  \node[font = \tiny,above,rotate = 90,transform shape,anchor = west] at
  (White--1-7.south) {\frequency};


  \def\noteindex{4}%

  \foreach \octave [remember = \octave as \lastoctave (initially -1)] 
                   in {0,...,6}{%
    \foreach \White/\note [remember = \White as \lastWhite (initially 7)]
                   in {1/C,2/D,3/E,4/F,5/G,6/A,7/B} {%
      \ifnum\White=1\relax
        \node[%
              White,
              right = of White-\lastoctave-\lastWhite]
              (White-\octave-\White) {};
      \else
        \node[%
              White,
              right = of White-\octave-\lastWhite]
              (White-\octave-\White) {};
      \fi
      \node[font = \tiny,above] at (White-\octave-\White.north)
      {$\mathrm{\note}_{\octave}$}; 

      \node[font = \tiny,below] at (White-\octave-\White.south)
      {\noteindex};

      \pgfmathsetmacro\frequency{round(440 * 2^(((\noteindex)-49)/12))}
      \node[font = \tiny,above,rotate = 90,transform shape,anchor = west] at
      (White-\octave-\White.south) {\frequency};

      \ifcase\White\relax
      \or% next is D
        \xdef\noteindex{\number\numexpr\noteindex+2\relax}%
      \or% next is E
        \xdef\noteindex{\number\numexpr\noteindex+2\relax}%
      \or% next is F
        \xdef\noteindex{\number\numexpr\noteindex+1\relax}%
      \or% next is G
        \xdef\noteindex{\number\numexpr\noteindex+2\relax}%
      \or% next is A
        \xdef\noteindex{\number\numexpr\noteindex+2\relax}%
      \or% next is B
        \xdef\noteindex{\number\numexpr\noteindex+2\relax}%
      \or% next is C
        \xdef\noteindex{\number\numexpr\noteindex+1\relax}%
      \fi

    }
  }

  \node[White,right = of White-6-7] (White-7-1) {};

  \node[font = \tiny,above] at (White-7-1.north)
  {$\mathrm{C}_{7}$}; 

  \node[font = \tiny,below] at (White-7-1.south)
  {\noteindex};

  \pgfmathsetmacro\frequency{round(440 * 2^(((\noteindex)-49)/12))}
  \node[font = \tiny,above,rotate = 90,transform shape,anchor = west] at
  (White-7-1.south) {\frequency};


  \begin{scope}[every node/.style = {%
                  Black,
                }]
  \node at (White--1-6.north east) {};

  \foreach \octave in {0,...,6}{%
    \foreach \White in {1,2,4,5,6} {%
      \node at (White-\octave-\White.north east) {};
      }
    }
  \end{scope}
\end{tikzpicture}
\end{document}

Best Answer

Not properly worked through, but hopefully shows how to "integrate" (in a very loose sense) musixtex and tikz.

EDIT: added keyboard and tonic sol-fa labels. Still a bit of mess though.

\documentclass[border=0.25cm]{standalone}
\usepackage{etex}
\usepackage{tikz}
\usepackage{musixtex}
\usetikzlibrary{fit}
\begin{document}

\begin{tikzpicture}

\def\lastnotename{origin}
\newbox\notebox
\coordinate (origin) at (0,0);
\coordinate (stave) at (origin);
\foreach \octave [evaluate={\t=int(\octave*7-7);}] in {0, ..., 5}{
    \foreach \pitch [count=\c from 0, evaluate={\x=int(\octave*7+\c+1);}] in {A,...,G}{
        \ifnum\t>6
            \tikzset{extract anchor/.style={anchor=south west, at=(\lastnotename.south east)}}
        \else
            \tikzset{extract anchor/.style={anchor=north west, at=(\lastnotename.north east)}}
        \fi
        \edef\notename{\pitch-\octave}  
        \node (\notename)  [inner sep=0pt, outer sep=0pt,text width=1cm, extract anchor/.try]  {%
            \begin{music}
                \instrumentnumber{1}
                \instrumentnumber{2}
                \nostartrule        
                \setstaffs1{1}
                \setstaffs2{1}  
                \ifnum\x>1
                    \setclefsymbol1{\empty}
                    \setclefsymbol2{\empty}
                \fi
                \setclef1{\bass}
                \setclef2{\treble}                                  
                \startextract
                \transpose\t
                \ifnum\t>7
                    \ifnum\t>14
                        \Notes \nextinstrument \ql{\pitch} \en      
                    \else
                        \Notes \nextinstrument \qu{\pitch} \en                      
                    \fi
                \else
                    \Notes \qu{\pitch} \en
                \fi
                \zendextract
            \end{music}};
            \xdef\lastnotename{\pitch-\octave}
}}

\node (stave) [fit={(A-0) (G-5)}] {};

\newif\ifblacknote
\foreach \octave in {0,...,5}
    \foreach \pitch [count=\p, evaluate={\t={"la", "si", "so", "r\`e","mi", "fa", "sol"}[\p-1];}] in {A,...,G}{
        \node [anchor=base] at ([xshift=0.25cm, yshift=-0.25cm]stave.south -| \pitch-\octave.south) {\t};
        \draw ([xshift=0.25cm, yshift=-1cm]stave.south -| \pitch-\octave.south west) rectangle ++(1cm,-4cm);
        \blacknotefalse
        \ifcase\p
        \or
            \blacknotetrue
        \or
        \or
            \blacknotetrue
        \or
            \blacknotetrue
        \or
        \or
            \blacknotetrue
        \or
            \ifnum\octave<5
                \blacknotetrue
            \fi
        \else
        \fi
        \ifblacknote
            \fill ([xshift=0.25cm, yshift=-1cm]stave.south -| \pitch-\octave.south east) ++(-0.25cm,0) rectangle ++(0.5cm,-2.5cm);
        \fi
    }

\end{tikzpicture}

\end{document}

enter image description here

OK, here's a much better version...

\documentclass[border=0.25cm]{standalone}
\usepackage{etex}
\usepackage{tikz}
\usepackage{musixtex}
\def\threedp#1{\pgfmathparse{#1}\expandafter\Threedp\pgfmathresult0000@}
\def\Threedp#1.#2#3#4#5@{#1.#2#3#4}
\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=(2^((\note-49)/12))*440;}
] 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) {\threedp\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) {\threedp\frequency};
        \end{pgfonlayer}
    \fi
}
\node [rotate=90] at (0,-6) {Fr\`equency (Hz)};
\end{tikzpicture}

\end{document}

enter image description here