Symi 语法
宏
宏定义和调用
宏是Symi中一种强大的抽象机制,允许你定义可重用的代码块,并在需要的地方调用它们,这在音乐的重复结构中尤其有用。
定义宏
宏定义的基本形式都是:
宏名 = ...
其中宏名使用标识符(字母、数字、下划线组合,且不能以数字开头)。
当前版本中,宏分为三类:
- alias macro:单行、无
:,表示一个音高链别名 - simple macro:单行、含
:,表示多个音高项 - complex macro:多行片段(或以非音高标记开头的单行片段)
别名宏
别名(alias)宏的 body 是一个音高链:
a = 3/2@5/4
b = C4+
别名宏可用于:
- 在音高链中作为标识符被引用(例如
C4@a) - 直接作为宏调用(例如
a,、a@D4,) - 在基准音定义右侧被引用(例如
<C4=a>)
简单宏
简单(simple)宏用于定义一组音高项,内容由 : 分隔,例如:
arp = 1/1:3/2:2/1
上例定义了一个名为 arp 的简单宏,内部是一个三音组。
简单宏只负责音高内容复用,不在定义处固定时间戳推进;实际时值与节奏由调用位置决定。
复杂宏
复杂(complex)宏用于定义完整的行级片段(可包含时间控制、和弦、分号细分、控制信息等)。
写法是将 = 后换行,然后在下一行(或多行)书写宏体,最后用一个额外的空白行结束:
riff =
{4}C,E,G,E,
D,F,A,F,
如果宏体只有一行,也可以直接写在 = 后,但是宏体必须以非音高标记开头:
riff = {4}C,E,G,E, // 这是合法的单行复杂宏定义
riff = C,E,G,E, // 这样写会被解析为 alias/simple 路径,而不是 complex 宏
复杂宏的宏体在逻辑上是一段独立片段:
- 宏体内部按自身内容推进时间;
- 调用时会将宏体事件整体平移到调用位置;
- 宏体可以包含多个小节(多行)。
小节分隔记号看起来就像是没有名字的单行复杂宏,其实它就是对复杂宏的一种特殊语法糖。
调用宏
宏调用的基础形式是直接写宏名:
arp,
riff,
a,
调用时可以在宏名后追加音高链尾部(@...、+、-):
arp@D4,
arp@3/2@10c,
riff@A3,
a+,
其语义与音高链一致:调用尾部会拼接到宏内每个音符(或 alias 链)的音高链末尾,再按 @ 右结合计算最终频率。
这对 alias/simple/complex 三类宏都生效。
示例
<C4=261.63>
a = 3/2@5/4
arp = 1/1:3/2:2/1
riff =
{4}C,E,G,E,
D,F,A,F,
{1}a,
arp@D4,
riff,
,
riff@A3,
上例中:
a作为 alias 宏可直接调用;arp@D4与riff@A3会把@D4追加到展开后的音高链末尾;- 该调用尾部只影响当前调用,不影响后续内容。