音符、调性和音高
前两章介绍了 jpFun 的函数调用,以及参数的六种基本类型。这一章只关注最基本的音符:先从 @note 的完整定义出发,再把它缩写成日常写谱时使用的简洁记号。还会介绍数字音名与字母音名的区别,以及调性的设置。
在正式介绍音符之前,我们先了解一下注释的写法。后面的谱例会用注释在代码旁边加上说明,帮助你理解每一行的作用。
注释用 % 开头,从 % 到这一行结束的内容都是给人看的说明,不会影响乐谱:
% 这里是注释1 2 3 % 这里也是注释删掉这些注释,仍然会得到相同的三个音符。除了说明,你还可以通过注释来临时失效某些代码。
在编辑器中,使用
Ctrl+/可以快速添加或取消注释。
@note 函数
Section titled “@note 函数”音符由 @note 函数创建,它还有一个较短的别名 @n:
@note(name, acc="", octave=4, color="#000")| 参数 | 类型 | 含义 |
|---|---|---|
name | 字符串 | 必填。可以是数字音名 1~7,也可以是字母音名 A~G |
acc | 字符串 | 升降记号,默认为空。# 升高半音,b 降低半音,n 显示还原号,可以连续写多个 |
octave | 数值 | 八度。数字音名使用相对八度,默认 0;字母音名使用绝对八度,默认 4 |
color | 字符串 | 音符颜色,默认为 #000(黑色) |
下面的谱例完全使用函数调用。第一小节是数字音名,第二小节是字母音名:
@note(1) @note(2, "#") @note(3, "bb", 1) |
@note(C, "", 4) @note(D, "#", 4) @note(E, "bb", 5, #f00) |name 还有几个特殊取值:
- 可见休止符:
0(或Z) - 节拍记号:
9(或X)是显示为X、播放为短促打击音的节拍记号 - 占位符:
8不显示也不发声,但是推进时间
这三个特殊取值时,acc 和 octave 参数会被忽略。
% 三个特殊取值只有 name 参数有效
@n(0, "#") % 可见休止符,acc 参数会被忽略
@n(8, octave=9) % 占位符,octave 参数会被忽略
@n(9, color="#00f") % 节拍记号,color 参数不会被忽略,因为和音高没关系数字音名与字母音名
Section titled “数字音名与字母音名”name 参数支持写数字和字母。数字音名与字母音名的区别在于它们确定实际音高的方式。简单来说,数字音名忠于视觉,适合打谱;字母音名忠于音高,适合转调。
数字音名是相对音高
Section titled “数字音名是相对音高”简谱中,一个数字音名的音高并不是绝对的,而是和调性相关的。比如,在 D 大调中,数字 1 其实是钢琴上的 D4,频率约为 293.66 Hz。jpFun 吸纳了这个记录方法,1~7 表示相对于当前调性基准的音级。
因此必须有一个“1 是什么音”的基准。这个基准由 @key 函数 的 tonality 参数设置,含义为调性:
@key(tonality=C4) % 默认基准是 C4tonality 写成“字母音名 + 可选升降号 + 绝对八度”,例如 C4、F#3、Bb4;省略八度时默认为第 4 八度。例如,@key(C4) 表示以中央 C(C4)作为 1,@key(D5) 则表示以 D5 作为 1。@key 还有一个符合简谱习惯的别名 @1,所以 @1(D4) 与 @key(D4) 完全相同。尚未调用 @key 时,默认基准是 C4。
@key 从它出现的位置开始影响后面的数字音名:
@key(C4) @note(1) @note(2) @note(3) |
@key(D5) @note(1) @note(2) @note(3) |
@key渲染的效果是 “1=<tonality>”,上面例子中和旋律排在了一行,而实际应该在音符上方。排布在上方需要使用@up函数,本章就不介绍了。
两小节都写成 1 2 3,但播放的时候会发现,第二小节的实际音高整体比第一小节高八度又一个大二度。
数字音名的 octave 也是相对基准计算的。@note(1, "", 1) 比当前基准高一个八度(对应简谱:上方加一个点),@note(1, "", -1) 则低一个八度。
也就是说,如果使用数字音名,能保证渲染后的简谱看起来和脚本一样,但是演奏的音高却会变化。如果你希望 jpFun 忠于视觉,请使用数字音名。
字母音名是绝对音高
Section titled “字母音名是绝对音高”A~G 直接指定绝对音名,octave 使用绝对八度编号。例如 @note(C, "", 4) 始终是 C4,音高不会因为 tonality 的改变而改变。但此时渲染出的简谱显示的数字会根据当前的调性进行换算:
@key(C4) @n(1) @n(C, "", 4) |
@key(D5) @n(1) @n(C, "", 4) |第一小节中,数字 1 和字母 C4 是同一个实际音高,频率约为 261.63 Hz(中央 C)。切换到 D5 基准后,数字 1 变成 D5(频率约为 587.33 Hz),而字母音名 @n(C4) 的音高仍然是 C4。
基于“字母音名忠于音高”这个特性,字母音名记谱适合转调。编辑器导入 MIDI 或者 MusicXML 时就是用了绝对音名记谱。此时只需要改动最前面的 @key 函数,就可以整体移调,只改变视觉,不影响演奏效果。
音符的语法糖
Section titled “音符的语法糖”完整函数调用适合精确控制参数,但逐个写会很长。@note 因此提供了紧凑的语法糖:直接写音名,就等于调用一次 @note。
| 函数调用 | 语法糖 | 含义 |
|---|---|---|
@note(1) | 1 | 当前基准上的第一级 |
@note(2, "#") | #2 | 升高半音的第二级 |
@note(3, "", 2) | 3'' | 高两个相对八度的第三级 |
@note(6, "b", -1) | b6, | 低一个相对八度、再降半音的第六级 |
@note(C, "", 4) | C4 | 绝对音高 C4 |
@note(F, "#", 5) | F#5 | 绝对音高 F♯5 |
数字音名后每写一个英文单引号 ',就升高一个八度;每写一个英文逗号 ,,就降低一个八度。字母音名则直接在末尾写绝对八度编号。推荐把数字音名的升降号写在音名前,例如 #1'、b3,;字母音名写成 C#4、Bb3。此外,简写也可以直接作为函数调用写法中 name 的传参。
为了兼容番茄简谱的习惯,无歧义时也接受后置升降号:
6#,,等价于#6,,,A3#等价于A#3。歧义情况:6#3依然被解析为6和#3,除非加空格分隔。
下面两小节的音高完全相同,前一小节使用完整函数,后一小节使用语法糖:
@key(C4) % 调性的写法就是数字音高的简写
@note(1) @note(2, "#") @note(3, "", 2) @note(6, "b", -1) @note(C, "bb", 2) |
1 #2 3'' @note("b6,") Cbb2 |
@note("b6,")之所以要加引号,是因为音名中包含了逗号,直接写作b6,会被解析为多个参数,而加上引号后会被作为单个字符串参数传入name。
日常写谱时优先使用语法糖即可;需要设置 color 等简写没有表达的参数时,再使用完整的 @note(...)。完整参数和默认值也可以随时在函数速查中查看。
高八度号与低八度号
Section titled “高八度号与低八度号”一段旋律整体升降八度演奏时,可以用 @ottava 标出范围,而不必给每个音符加八度点:
@ottava(a, b, shift=1)a、b 是首末元素的标签,只能按位置传入;shift 是非零整数八度数,可按位置或名称传入,正数表示高、负数表示低,默认 1。
5,/@highStart 6,/ 1/ 2/ | 5 -@highEnd |
@ottava(highStart, highEnd)
5'/@lowStart 6'/ 1/ 2/ | 5 -@lowEnd |
@ottava(lowStart, lowEnd, shift=-1)
1@doubleStart 2 3 4@doubleEnd |
@ottava(doubleStart, doubleEnd, 2)
1@tripleStart 2 3 4@tripleEnd |
@ottava(tripleStart, tripleEnd, -3)*变音记号的作用范围
Section titled “*变音记号的作用范围”目前 jpFun 的变音记号只作用于当前音符,不会自动延续到本小节后面的同度音。 例如在 C 调中,#1 1 是升高半音的 1 和普通的 1;如果两个音都要升高,请写成 #1 #1。
项目曾尝试增加可选的小节内变音延续,以兼容简谱国家标准中变音号对本小节后续同度音生效、对八度同名音不生效的规则。但实现后发现,代价不只是增加一份记忆、在小节线处清空,还需要处理与现有功能的交互:
- 和弦的同时音:
1 ^ #1中两个音同时发生,不能因为内部处理顺序而让后写的升号影响前面的自然音。需要区分同时音与先后音,协调记忆的读取和写入。 - 倚音与多声部:倚音为排版使用独立轨道,但主旋律的变音记忆需要与宿主声部共享;倚音里的额外声部又必须隔离,不能直接把布局轨道当作音乐声部。
- 音高编辑:如果变音会延续,只把
1 1的第一个音升高半音,必须改成#1 n1才能保持第二个音不变。这意味着修改一个音符可能需要给选区外的后续音符补记,并重新推演变音状态。 - 完整的标准规则:跨小节延音线连接的同音还涉及变音效力延续,转行后的提醒记号也需要额外处理。仅实现小节内记忆并不等于完整兼容标准。
这些处理让原本独立的音符依赖前文状态,扩大了实现和长期维护的复杂度。权衡收益与成本后,项目 暂时放弃小节内变音延续 ,继续采用逐音显式记号。
JE 谱兼容
Section titled “JE 谱兼容”jpFun 还兼容 JE 谱 用括号表示八度的写法:小括号 (...) 内的音符整体降低一个八度,中括号 [...] 内的音符整体升高一个八度:
(1 2 3) [4 5 6] |
1, 2, 3, 4' 5' 6' |这两小节的音高完全相同。括号可以嵌套,每多一层就再改变一个八度,例如 ((1)) 等价于 1,,,[[1]] 等价于 1''。不过注意,括号的作用范围被“内容块”范围限制。
@note创建音符,@n是它的别名。- 数字音名是相对音高,基准由
@key的tonality参数设置;@1是@key的别名。 - 字母音名是绝对音高,不会随
tonality移调,但会按当前调性换算成简谱数字显示。 1、#2'、C#5等写法都是@note(...)的语法糖。