$\text{\TeX}$下简谱排版系统的探索

  1. 6周前
    6周前+299792458m 重新编辑

    本人在高中时偶尔有排版简谱乐谱的需要,但是市面上很少有免费的简谱排版软件。我通过分析部分$\text{MusiX\TeX}$的源码,初步实现了一个简单的简谱的宏包。我在将来还会继续加入平连线、倚音等功能。
    本宏包排版的简谱样例见附件所示。此帖子将通过分析源码,对该宏包(及$\text{MusiX\TeX}$)的原理进行分析。

    关于$\text{\TeX}$编程

    据某网站(现在暂时找不到)所说,$\text{\TeX}$是图灵完备的。因此,可以用$\text{\TeX}$完成一般性质的编程工作,虽然可读性会很差。我会在每段$\text{\TeX}$源码之后附上等价的C风格伪代码。

  2. 6周前+299792458m 重新编辑

    音符的输入和显示

    $\text{MusiX\TeX}$的音符输入以如下宏为基础。

    \def\[email protected]#1\relax{\[email protected]\[email protected] \[email protected]\maxdimen % par defaut
    %% \edef\[email protected]{\[email protected] #1\relax\[email protected]}%
      \edef\[email protected]{\expandafter\[email protected] #1\relax\[email protected]}%
      \edef\[email protected]{\[email protected] #1\empty\[email protected]}%
    %% pas lettre
      \ifcat a\[email protected] \[email protected]\expandafter`\[email protected]\relax
    %% ramener au E (position zero en clef de sol, [email protected]=0)
        \ifnum\[email protected]>96\advance\[email protected]%
        \else\advance\[email protected]\@lxxxiii % ramener au S= E + 14
        \fi
        \advance\[email protected]\[email protected] \advance\[email protected]\[email protected] \advance\[email protected]\transpose
        \edef\[email protected]{\noexpand\[email protected]{\[email protected]}}%
    %% cas active character dont chiffre
      \else
        \let\[email protected]\empty
        \let\[email protected]\empty
        \ifcat 1\[email protected]
          \if =\[email protected] \let\@TI\na  \[email protected] \fi
          \if *\[email protected] \sk \[email protected] \fi
          \if .\[email protected] \let\@TI\pt   \[email protected] \fi
          \if >\[email protected] \let\@TI\dsh \[email protected] \fi
          \if <\[email protected] \let\@TI\dfl \[email protected] \fi
          \if !\[email protected] \transpose\normaltranspose \[email protected] \fi  
          \if '\[email protected] \advance\transpose\[email protected]@n   \[email protected] \fi  
          \if `\[email protected] \advance\transpose-\[email protected]@n  \[email protected] \fi
          \ifnum\[email protected]<\maxdimen \[email protected]#1\fi
        \else
          \if ^\[email protected] \let\@TI\sh \[email protected] \fi
          \if _\[email protected] \let\@TI\fl \[email protected] \fi
        \fi\[email protected]
      \fi}

    以上代码等价于如下形式。

    /* extern int n1, n8; */
    void xgetn1(char input) {
        if (input.length() == 0) return;
        n8 = 0;
        n1 = INT_MAX;
    
        if (isAlpha(char)) {
            n1 = (int) first;
            // 以E(第1线)为零点
            if (n1 >= 'A') n1 -= 'E'; // 大写字母
            else n1 -= ('e' - 14); // 小写字母; 大小写差为两个八度
            n1 += 2 * utRef; // 谱号导致的偏差
            n1 += transpose;
        } else {
            // 其他情况, 暂时不讨论
        }
    }

    可以看出,\[email protected]变量在五线谱排版时是用于储存竖向的偏差的,这在下方的音符显示使用的宏中可以看出。

    \def\[email protected]{%
      \ifnum\[email protected]<\@c
    % help lines \[email protected] (position)
        \ifnum\nblines>\[email protected]@ % no help lines for percussion instruments
          \[email protected]\[email protected]
          \ifnum\[email protected]<\[email protected] % waste memory, but saves time
            \loop \advance\[email protected]\[email protected] \ifnum\[email protected]<\[email protected]
              \advance\[email protected]\[email protected] \[email protected]
            \repeat
          \else
            \[email protected]\nblines \advance\[email protected]\[email protected] \multiply\[email protected]\[email protected]
            \ifnum\[email protected]>\[email protected]
              \loop \advance\[email protected]\@ne \ifnum\[email protected]>\[email protected]
                \advance\[email protected]\@ne \[email protected]
              \repeat
            \fi
          \fi
        \fi
    %
        \[email protected]\[email protected]\[email protected]
        \ifadvance \raise\[email protected]\[email protected]\[email protected] \else \raise\[email protected]\hbox{\[email protected]}\fi
        \[email protected] \advancetrue
      \fi}

    以上代码等价于如下形式。

    /* 
     * extern int n1, n5, numberOfLines;
     * extern float y1, internote;
     * extern boolean advance;
     */
    
    void outputAdvanced(float verticalOffset, Object content);
    void output(float verticalOffset, Object content);
    
    void writeNote(Object content) {
        // 绘制加线
        if (numberOfLines > 3) { // 3线以下为打击乐, 没有加线
            n5 = 0;
            if (n1 < -1) {
                n5 -= 1;
                while (n1 < n5) {
                    drawHelpLine(n5 - 1);
                    n5 -= 2;
                }
            } else {
                n5 = numberOfLines * 2 - 1;
                while (n1 > n5) {
                    drawHelpLine(n5 + 1);
                    n5 += 2;
                }
            }
        }
        y1 = n1 * internote;
        setstem(stem);
        
        if(advance) outputAdvanced(y1, content);
        else output(y1, content);
    }

    在简谱中,则将n1的意义相应变为所用的数字字符编码,不需要y1(因为简谱音符没有高低变化),同时增加一个n2用于上下加点。
    (待续)

 

后才能发言