跳转到内容

和弦与纵向堆叠

上一章的 @stack 给我们带来了多行并行的能力。下面我们考虑和弦(更宽泛的:同一个声部同时演奏多个音符)怎么记录——用多声部吗?但明明是同一个乐器发出来的。此时,使用 @up 这种纵向堆叠函数就非常合适。

使用 @up 包裹几个音符,即可把它们叠成和弦:

@up(音符1, 音符2, ...)

每个参数只能放一个可见的元素。 写和弦时,就是每个参数放一个音符,不能像 @stack 那样放入一整段旋律,也不能包含多声部结构。例如 @up(1, 3, 5) 可以,但 @up({1 2}, 3) 不可以。

第一个音符留在当前谱线上,后续音符按参数顺序依次叠在它的上方。它们从同一时刻开始,一起演奏:

用 up 组成和弦
1 2 @up(1, 3, 5) 7 @up(2, 4, 6)
复制代码

这里的 @up(1, 3, 5) 从下到上依次是 1、3、5。写和弦时,一般把低音写在前面(下面)。

@up 的简写是 ^。用起来和 @stack 的语法糖一样,在需要叠起来的音符之间加上它即可,连续使用就能叠上更多音:

用 ^ 层叠音符
1 2 1^3^5 2^4^6 | 1^3^5 - - -
复制代码

@up 的时值由第一个音符决定,其他音符跟随它的时值。 因此不必给每个音都重复写一遍减时线或附点:

由第一个音符决定节奏
1/^3^5 {2^4^6}/ 3^{5/}^{7.}
复制代码

1/^3^5 是一个八分音符时值的和弦,三个音都演奏半拍。如果直接给整个 @up 设置时值,会自动作用到第一个参数,进而影响所有后面的成员。即使后面的成员写了不同的时值,也不会成为独立的节奏(甚至不会有视觉效果)。

up函数和stack最大的区别是up函数仍然在一个轨道里——它不会像 @stack 那样为后续参数分出子音轨,而是把这些内容收在同一个时间位置上,作为一个整体参与排版。

上一章提到,同一轨道上多次出现的 @stack 会复用子音轨,因此上层声部的对齐会相互影响。@up 则只在当前位置堆叠,各个和弦上层的音符不必彼此对齐:

stack 与 up 的对比
1 2 3&4 5 6&7,,,,&1

1 2 3^4 5 6^7,,,,^1
复制代码

第一行使用 &,前面的 4 会被后面同一子音轨上的 7,,,, 抬高;第二行改用 ^,后一个和弦不会把前一个和弦的上层音符一起抬高。

两者对时间的处理也不同:@stack 的各段可以各自推进,整体时长取最长的一段;@up 的音符共用第一个音符的时值。如果需要叠加两段节奏不同的旋律,应继续使用 @stack,而不是把整段旋律塞进 @up。

与 @up 相对应,@down 把后续内容依次叠在第一个音符的下方,简写是 _:

向下堆叠与上下混写
@down(5, 3, 1) 5_3_1 | 3^5_1 - - -
复制代码

@down(5, 3, 1) 和 5_3_1 等价,第一个音符 5 仍留在原来的谱线上,3、1 依次叠在下面。^ 和 _ 也可以混写:3^5_1 以 3 为基准,把 5 放在上方、1 放在下方。它们仍然属于同一个轨道,节奏也仍由第一个音符承担。

@up 不仅仅能层叠音符,其实是一个强大的布局函数。它并不要求放进去的内容都是音符:颤音记号、延长音记号、文字等,都可以放到音符上方。

把记号放在音符上方
1 ^ $tr
2 ^ 3 ^ $mordent
1 ^ $fermata _ $f
1 ^ @text("轻柔地")
2 _ $pp
复制代码

这里 $ 是符号函数的简写,比如 $tr 表示颤音记号。更多符号的写法请参看 函数速查。

可以把 @up 理解为“什么都能往里面放”(仅限一个元素)的纵向布局工具:音符、符号和文字都可以组合,不必把它只当成和弦函数。利用这点,我们可以在谱面上实现丰富的视觉效果和标记。比如,现在设置调性和速度,就不用写在行内了,可以用 @up 把设置类的函数放在上面:

用 up 放置设置类函数
E3^@key(E4) F#3 G#3 |^"(2)" 1^@tempo(96) 2 3
复制代码

需要注意的是,@up 和 @down 后面的成员并不会参与横向避让,它们只是单纯地在垂直方向上堆叠,不会影响第一个参数的水平位置,因此很有可能发生重叠,比如上面的例子中,小节编号和速度设置重合了。为了应对这个问题,jpFun 提供了微调函数 @adjust,可以调整元素的包围盒与大小。比如上面的例子中,我们至少有两种做法:

  • 让第二小节的第一个音符左边宽一些
  • 让速度设置往右移动一些
用 adjust 微调 up 的元素
|^"(2)" @adjust(1^@tempo(96), dw=10, dx=10) 2 3

|^"(2)" 1^@adjust(@tempo(96), dx=10) 2 3
复制代码

关于 @adjust 的用法请参看 函数速查。