24

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}
  • 1
    This does not compile for me. A lot of nodes are not found: White-n-7, where n is in 0 to 6. – Tom Bombadil Oct 6 '13 at 21:31
  • @TomBombadil Hum, strange. I run a rather recent cvs version (August 2013). – cjorssen Oct 6 '13 at 21:38
18

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

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.