基于节拍和时间的编程
wait()函数
到目前为止我们所写的程序,生成的伴奏音都是与输入音符同步发声的。如果我们想让伴奏音延迟发声,例如做出延迟效果或者琶音器,又要如何编程呢?这就要涉及到一个非常重要的语句了:wait()函数(等待函数)。
wait()函数就地将回调函数暂停一段时间。换言之,此函数将脚本冻结(其他脚本可以继续运作),设定时间过后,回调函数继续运行。
下面是使用wait()函数的实例:
on init declare %addNote[12] := (4, 6, 3, 6, 3, 4, 6, 4, 6, 3, 6, 3) declare $keyClass end on on note $keyClass := $EVENT_NOTE mod 12 wait(500000) play_note($EVENT_NOTE + %addNote[$keyClass],$EVENT_VELOCITY,0,-1) wait(500000) play_note($EVENT_NOTE + 12,$EVENT_VELOCITY,0,-1) end on
此时如果用户演奏了C3,过0.5秒后会再响起一个E3,再0.5秒后又会出现C4。wait()函数将代码暂停了一段时间,致使回调函数不能立即执行,只有在一秒钟之后才能执行(两个wait()函数,每个0.5秒)。
现在如果用户放开C3演奏E3,得到的结果是类似的:伴奏音为G3和E4。目前为止似乎没有问题,但是如果用户同时演奏了C3和E3,得到的结果就不尽如人意了。因为同时演奏和分别演奏是不一样的,我们之前并没有探讨过这种情况。
为什么这段代码不能处理多个音符呢?上例中的回调函数持续时间是1秒,如果在这1秒内又有新音符输入,这个音符也会触发一个回调函数,会出现两个回调函数并行执行的情况。第一个回调函数需要$keyClass这个变量,但第二个回调函数(由E3触发)会给$keyClass分配一个新值,因此第一个回调函数得到的$keyClass值是错的。想要解决这个问题,我们就需要给每个音符都分配一个变量,即复音变量(polyphonic variable)。
复音变量
请读者试用以下代码:
on init declare %addNote[12] := (4, 6, 3, 6, 3, 4, 6, 4, 6, 3, 6, 3) declare polyphonic $keyClass end on on note $keyClass := $EVENT_NOTE mod 12 wait(500000) play_note($EVENT_NOTE + %addNote[$keyClass],$EVENT_VELOCITY,0,-1) wait(500000) play_note($EVENT_NOTE + 12,$EVENT_VELOCITY,0,-1) end on
上述代码中的$keyClass变成了一个复音变量。在declare与变量名之间插入一个polyphonic即可完成复音变量的声明。
declare polyphonic $<变量名> |
声明一个用户定义复音变量,用于储存单个整数值 |
现在再演奏C3和E3,得到的便是正确的琶音效果了。背后的原因是每个回调函数都有其独立的$keyClass值。复音变量消耗的内存更多,每一个实例(instance)消耗4KB内存,并且只能在音符与释放回调函数中使用。