使用 tikz 绘制钢琴图

使用 tikz 绘制钢琴图

答案提供了一个漂亮的代码来绘制钢琴及其音域。我尝试学习它们来绘制一个简单朴素的钢琴图,并在琴键上写上键名(A、B、C、C#),但代码中嵌套了太多其他要求,以至于我无法理解。有人能帮助我理解代码并从中得出一个简单的钢琴图吗?

代码 -

\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}

答案1

如果我正确理解了这些要求,那么musictex可以删除该部分。为了进一步简化,可以使用常规的双 for 循环计算 5 个八度和 7 个音高的键的坐标。可以使用计算出的 x 坐标将音高数组中的字母打印在键上,对于黑键,也可以使用类似的方法,在音高字母上添加一个升号。

剩下的就是对键和音高标签的位置进行一些调整。请注意,由于原始代码中的新键被绘制为矩形,因此矩形的左线将与前一个键的右线重叠。通常这不是问题,但是当音符名称以白色印在黑键上时,下一个白键将出现在音符名称的上方。为了解决这个问题,白键被绘制为三条线,只有顶部、右侧和底部。对于第一个键,在循环之前绘制了一条额外的左线。

梅威瑟:

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

\begin{tikzpicture}

\coordinate (origin) at (0,0);
\coordinate (stave) at (origin);
% left line of first key
\draw (0.25,-1) -- (0.25,-5);

\newif\ifblacknote
\foreach \octave in {0,...,5}
    \foreach \pitch [count=\p] in {A,...,G}{
        % calculate x position from octave and pitch
        \pgfmathparse{\octave*7+\p+0.25}
        \edef\myx{\pgfmathresult}
        % draw three lines for top, right, bottom of this key
        \draw (\myx,-1) -- (\myx,-5);
        \draw (\myx,-1) -- ($(\myx,-1)+(-1,0)$);
        \draw (\myx,-5) -- ($(\myx,-5)+(-1,0)$);
        % print pitch on line
        \node [anchor=base,xshift=-15] at (\pgfmathresult,-4.5) {\pitch};
        \blacknotefalse
        \ifcase\p
        \or
            \blacknotetrue
        \or
        \or
            \blacknotetrue
        \or
            \blacknotetrue
        \or
        \or
            \blacknotetrue
        \or
            \ifnum\octave<5
                \blacknotetrue
            \fi
        \else
        \fi
        \ifblacknote
            % recalculate x
            \pgfmathparse{\octave*7+\p}
                \fill ([xshift=0.25cm, yshift=-1cm]stave.south -| \pgfmathresult,0) ++(-0.25cm,0) rectangle ++(0.5cm,-2.5cm);
                % print pitch on black key
                \node [anchor=base,xshift=0.25cm,white] at (\pgfmathresult,-2.5) {\textbf{\pitch}${}^\sharp$};
        \fi
    }

\end{tikzpicture}
\end{document}

结果(部分截图):

在此处输入图片描述

编辑:在黑键上添加降号。代码:

% recalculate x
\pgfmathparse{\octave*7+\p}
\edef\myx{\pgfmathresult}
% calculate flats
\pgfmathparse{array({"B","C","D","E","F","G","A"},\p-1)}
\edef\nextnote{\pgfmathresult}
\fill ([xshift=0.25cm, yshift=-1cm]stave.south -| \myx,0) ++(-0.25cm,0) rectangle ++(0.5cm,-2.5cm);
% print pitch on black key
\node [anchor=base,xshift=0.25cm,white] at (\myx,-2.5) {\textbf{\pitch}${}^\sharp$};
\node [anchor=base,xshift=0.25cm,white] at (\myx,-3.0) {\textbf{\nextnote}${}^\flat$};

在此处输入图片描述


编辑:一个八度,音符名称的不同字符。

\documentclass[border=0.5cm]{standalone}
\usepackage{fontspec}
\setmainfont[Script=Devanagari,Mapping=devanagarinumerals]{Shobhika}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{ulem}
\begin{document}

\begin{tikzpicture}

\coordinate (origin) at (0,0);
\coordinate (stave) at (origin);
% left line of first key
\draw (0.25,-1) -- (0.25,-5);

\newif\ifblacknote
 \foreach \pitch [count=\p] in {सा,रे,ग,म,प,ध,नी}{
     % calculate x position from octave and pitch
     \pgfmathparse{\p+0.25}
     \edef\myx{\pgfmathresult}
     % draw three lines for top, right, bottom of this key
     \draw (\myx,-1) -- (\myx,-5);
     \draw (\myx,-1) -- ($(\myx,-1)+(-1,0)$);
     \draw (\myx,-5) -- ($(\myx,-5)+(-1,0)$);
     % print pitch on line
     \node [anchor=base,xshift=-15] at (\pgfmathresult,-4.5) {\pitch};
     \blacknotefalse
     \ifcase\p
     \or
         \blacknotetrue
     \or
         \blacknotetrue
     \or
     \or
         \blacknotetrue
     \or
         \blacknotetrue
     \or
         \blacknotetrue
     \or
     \else
     \fi
     \ifblacknote
         \fill ([xshift=0.25cm, yshift=-1cm]stave.south -| \p,0) ++(-0.25cm,0) rectangle ++(0.5cm,-2.5cm);
         % print pitch on black key
         \pgfmathparse{array({"\underline{रे}","\underline{ग}",,"मऺ","\underline{ध}","\underline{नी}"},\p-1)}
            \edef\nextnote{\pgfmathresult}
         \node [anchor=base,xshift=0.25cm,white] at (\p,-2.5) {\nextnote};
     \fi
 }

\end{tikzpicture}
\end{document}

3

答案2

如果你仔细观察音乐键盘(钢琴、风琴、大键琴等),你可能会对所看到的东西感到惊讶:在任何一组七个相邻的自然(白色)键中,没有两个形状是相同的。确实,C 和 E 键互为镜像(F 和 B 键也是如此),但七个相邻的自然键之间都不能互换。事实上,这些键的尺寸和位置构成了一个有趣且非常实用(尽管可能出乎意料)的线性规划示例。网上有一些关于此问题的有用讨论:https://www.mathpages.com/home/kmath043.htmhttp://www.quadibloc.com/other/cnv05.htmhttp://datagenetics.com/blog/may32016/index.html

以下内容来自http://datagenetics.com/blog/may32016/index.html代码相当简单(感谢 TiZ!——我最早的绘画是用铅笔和尺子在计算尺的帮助下完成的)这样可以相对轻松地进行编辑和实验。有无数其他方法可以实现这一点,但这种方法的优点是所有黑键都具有相同的宽度,所有白键(自然键)都具有相同的宽度——有些键盘布局不一定如此。

\documentclass[tikz,border=3mm]{standalone}

\usepackage{xparse}

\usetikzlibrary{calc}

\newlength{\CtoBwd}%% Width of 7 adjacent white (natural) keys
\newlength{\Whitewd}%% Width of a natural key
\newlength{\Blackwd}%% Width of a black key
\newlength{\Whitefrontht}%% Distance from front of white key to black key
\newlength{\Backwdi}%% <<-- See below
\newlength{\Backwdii}%% <<-- See below
\newlength{\Backwdiii}%% <<-- See below
\newlength{\FronttoBack}%% Total length of a natural key
\newlength{\Blackht}%% Length of a black key

%% http://datagenetics.com/blog/may32016/index.html

\NewDocumentCommand{\drawaccidental}{mmmm}{% Lower left, sharp name, flat name, coordinate name for upper right of accidental
    \draw[fill=black] (#1)
        rectangle node[white,text width=\Backwdii,align=center]
            {\bfseries\huge#2${}^\sharp$\\[1ex]#3${}^\flat$}
        ++ (\Blackwd,\Blackht)coordinate (#4);
}

\NewDocumentCommand{\drawname}{m}{% Coordinate name of lower left of key and name of key
    \node at ($(#1) + (\Whitewd/2,\Whitefrontht/2)$) {\bfseries\Huge#1};
}

%% f b = \Backwdi
%% cs ds fs gs as = \Backwdii
%% d g a = \Backwdii
%% c e = \Backwdiii

\NewDocumentCommand{\drawkeyboard}{}{%
    \draw (0,0)coordinate(C) -- ++(0,\FronttoBack) -- ++(\Backwdiii,0) --
        ++(0,-\Blackht)coordinate(CS) -| (\Whitewd,0)coordinate(D) -- cycle;
    \drawaccidental{CS}{C}{D}{CS0}
    \drawname{C}

    \draw (D) -- ++(0,\Whitefrontht) -| (CS0) -- ++(\Backwdii,0) -- ++(0,-\Blackht)coordinate(DS)
        -| (2\Whitewd,0)coordinate(E) -- cycle;
    \drawaccidental{DS}{D}{E}{DS0}
    \drawname{D}

    \draw (E) -- ++(0,\Whitefrontht) -| (DS0) -- ++(\Backwdiii,0) -- ++(0,-\FronttoBack)coordinate(F)
        -- cycle;
    \drawname {E}

    \draw (F) -- ++(0,\FronttoBack) -- ++(\Backwdi,0) -- ++(0,-\Blackht)coordinate(FS)
        -| (4\Whitewd,0)coordinate(G) -- cycle;
    \drawaccidental{FS}{F}{G}{FS0}
    \drawname{F}

    \draw (G) -- ++(0,\Whitefrontht) -| (FS0) -- ++(\Backwdii,0) -- ++(0,-\Blackht)coordinate(GS)
        -| (5\Whitewd,0)coordinate(A) -- cycle;
    \drawaccidental{GS}{G}{A}{GS0}
    \drawname{G}

    \draw (A) -- ++(0,\Whitefrontht) -| (GS0) -- ++(\Backwdii,0) -- ++(0,-\Blackht)coordinate(AS)
    -| (6\Whitewd,0)coordinate(B) -- cycle;
    \drawaccidental{AS}{A}{B}{AS0}
    \drawname{A}

    \draw (B) -- ++(0,\Whitefrontht) -| (AS0) -- ++(\Backwdi,0) -- ++(0,-\FronttoBack) -- cycle;
    \drawname{B}
}

\begin{document}

\setlength{\CtoBwd}{6.5in} %% This varies between 160mm to 167mm depending upon manufacturer
\pgfmathsetlengthmacro{\tmpwd}{\CtoBwd/5880}\typeout{\tmpwd!!!!}
\setlength{\Whitewd}{\dimexpr \tmpwd*840\relax}
\setlength{\Blackwd}{\dimexpr \tmpwd*490\relax}
\setlength{\Blackht}{3.75in}
\setlength{\Whitefrontht}{2in}
\setlength{\FronttoBack}{\dimexpr \Whitefrontht + \Blackht\relax}
\setlength{\Backwdi}{\dimexpr\tmpwd*455\relax}
\setlength{\Backwdii}{\dimexpr\tmpwd*490\relax}
\setlength{\Backwdiii}{\dimexpr\tmpwd*525\relax}

\begin{tikzpicture}[rounded corners=4pt]
    \foreach \oct in {0,...,3}{% for 4 octaves; vary at will
        \begin{scope}[xshift=\oct*\CtoBwd]
        \drawkeyboard
        \end{scope}
    }
\end{tikzpicture}

\end{document}

一个八度 四个八度

我有许多使用其他布局的插图,最初是我准备帮助我的键盘学生的。

相关内容