SuperCollider教程:使用Routines和Tasks实现音乐序列化
概述
在SuperCollider中,Routines和Tasks是两种强大的控制结构,它们允许我们创建复杂的音乐序列和算法作曲系统。与普通函数不同,这些结构能够暂停执行并在之后恢复,这使得它们特别适合处理音乐时序问题。
Routines基础
Routine是一种可以暂停和恢复执行的代码块。每次调用.next
方法时,Routine会从上次暂停的位置继续执行,直到遇到下一个yield
语句。
(
r = Routine({
"第一部分".yield;
"第二部分".yield;
"第三部分".yield;
});
)
r.next; // 返回"第一部分"
r.next; // 返回"第二部分"
当Routine被用于音乐时序时,yield返回的数字会被解释为等待时间(以秒为单位)。这使得我们可以创建精确的时序模式:
(
r = Routine({
loop {
// 随机等待0.5到1.5秒
(0.5.rrand(1.5)).yield;
}
});
)
音乐序列化实践
结合SynthDef和Routine,我们可以创建简单的旋律序列:
(
SynthDef(\simpleTone, { |freq=440, amp=0.2, sustain=0.5|
var env = EnvGen.ar(Env.perc(0.01, sustain), doneAction:2);
Out.ar(0, SinOsc.ar(freq) * env * amp);
}).add;
r = Routine({
var notes = [60, 62, 64, 65, 67, 69, 71, 72]; // C大调音阶
loop {
notes.do { |midi|
Synth(\simpleTone, [\freq, midi.midicps]);
0.25.wait; // 每个音符持续0.25秒
}
}
}).play;
)
Tasks的优势
Task是Routine的增强版本,主要区别在于:
- 可以被暂停后从暂停点恢复
- 提供了更精确的时序控制
- 支持量化(quantization)功能
(
t = Task({
loop {
[60, 62, 64].do { |midi|
Synth(\simpleTone, [\freq, midi.midicps]);
0.5.wait;
}
}
}).play(quant: 4); // 在下一个小节开始时播放
)
高级时序控制
量化参数
量化参数(quant)允许我们精确控制Task的开始时间:
quant: 4
- 在下个4拍(1小节)边界开始quant: [4, 0.5]
- 在下个4拍边界+0.5拍开始
多任务同步
我们可以创建多个Task并确保它们保持同步:
(
var makeTask = {
Task({
loop {
Synth(\simpleTone, [\freq, exprand(300, 800)]);
0.5.wait;
}
});
};
// 主节奏
t = makeTask.value.play(quant: 4);
// 延迟0.25拍开始的副节奏
u = makeTask.value.play(quant: [4, 0.25]);
)
服务器时序优化
为了确保精确的时序,特别是在高频事件中,我们应该使用服务器捆绑消息:
(
t = Task({
loop {
s.makeBundle(s.latency, {
Synth(\simpleTone, [\freq, exprand(400, 1200)]);
});
0.1.wait; // 每秒10个音符
}
}).play;
)
实际应用建议
- 对于简单序列,使用Routine即可
- 需要暂停/恢复功能时,选择Task
- 多个并行序列时,确保使用相同的时钟和量化设置
- 高频事件使用makeBundle确保时序精确
- 考虑将参数生成与事件调度分离(使用单独的Routine生成参数)
通过掌握Routines和Tasks,你可以在SuperCollider中创建复杂而精确的音乐序列,为算法作曲和交互式音乐表演打下坚实基础。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考