随时间变化的声音
我们目前制造的声音如果我们我们不按键停止,那它们将永远播放下去。
绝大多数时候,我们想要制造的都是会在一个有限时间内进行的声音,然后经它们各自的协定停止。
听听以下两者的差别:
// 永远进行的正弦振荡器 {SinOsc.ar(440,0,0.1)}.scope
////////////
// 持续1秒的正弦音 {SinOsc.ar(440,0,Line.kr(0.1,0.0,1.0))}.scope
在第二个例子中,我使用了一个从0.1开始但一秒后归零的线性产生器乘以正弦波。
包络(Envelope)
总体来讲,我们需要得到一个对于声音的参数(比如音量或频率)随时间变化的完全控制。
// 参阅帮助文档——[Env] [EnvGen]
// 制作一个对于三个控制点的包络,在第一个数组中给定的y位置 // 以及第二个数组中给定的x位置(请查阅Env的帮助文档) Env.new([1,0,1],[1.0,0.5]).plot
.plot 提供了一个查看包络线的快捷方式——我们不使用它进行合成,但是它帮助我们看到一些包络的形状。
各式包络(后两条代码各种引数对包络线造成的影响推荐你对照图形化界面的合成器软件进行学习):
// 一秒从0到1,而后半秒从1到0 Env.new([0,1,0],[1.0,0.5]).plot
/////////
// linen的可用引数: attack, sustain, release, level, curve Env.linen(0.03,0.5,0.1).plot
/////////
// attack, decay, sustain level, release, level, curve Env.adsr(0.01, 0.5, 0.5, 0.1).plot
这儿是另一种类型的包络,适于制作打击乐音:
// 引数attack, release, level, curve——适于打击乐包络 Env.perc(0.05,0.5,1.0,0).plot
除此以外,还有很多很多类型的包络等待我们的探索和使用。
让我们开始为合成使用包络。我们使用EnvGen不断运行我们想要的包络。
这是我们将要运行的包络:
Env.new([1,0],[1.0]).plot
这仅仅是运行包络——这对听到任何声音来说太慢了(你的双耳仅能听到16-20Hz以上的声音)
{EnvGen.ar(Env.new([1,0],[1.0]))}.scope
用一直运行的包络乘以一个440Hz的普通的正弦音,来制造一个有限持续的声音
{SinOsc.ar(440,0,0.1)*EnvGen.kr(Env.new([1,0],[1.0]))}.scope
让我们尝试一个稍微复杂一些的例子
我将对频率使用一个包络:
Env.new([1000,20],[1.0]).plot
把EnvGen插入Saw波的频率输入:
{Saw.ar(EnvGen.ar(Env.new([1000,20],[1.0])),0.1)}.scope
现在来个更复杂的,我将在0.5秒内调整Saw的频率,然后使得它的振幅在2秒内归零:
{Saw.ar(EnvGen.ar(Env.new([10000,20],[0.5])),EnvGen.ar(Env.new([0.1,0],[2.0])))}.scope
由此可见,程序的嵌套可以慢慢变得何其的复杂,而且难以解读其进程。但如果分成几行来写的话,情况会好得多:
({ Saw.ar( EnvGen.kr(Env.new([10000,20],[0.5])), // 频率输入 EnvGen.kr(Env.new([0.1,0],[2.0])) // 振幅输入 ) }.scope )
在SuperCollider中,你会发觉自己总在跟什么UGen插入了什么UGen里边较劲,所有都写为文本。记住。你为各种连接在纸上画下一个流程图的方式将对你很有帮助。
我重写它时做了一点微小的变化——我运行了EnvGen的 ar 控制率(.kr)而不是音频率(.ar)。
我们尝试过 .kr 和 .ar,实际证明对我们的耳朵来说,两者并无实质区别。
我们在可能的情况下常使用 .kr,因为它意味着一个更低的CPU占用,从而可以一次运行很多个振荡器。
包络有个首要的进一步作用——一旦一个乘法包络在这个过程中运行,它们可以导致一个正在运行的UGen集群被释放。
你可以在音乐现场看到这个优点——你不想要当你在可以合成新的声音的时候,所有的声音都还一直挂在那占用你的CPU,对吧?
//FM声音 ({ SinOsc.ar( SinOsc.ar(10,0,10,440), 0.0, EnvGen.kr(Env.new([0.5,0.0],[1.0]), doneAction:2) ) }.scope )
引数 doneAction 意味着包络完成,导致其中的合成器被释放。
唯一有关系的一件事是包络维持多长时间,接下来的代码同样在包络完成后进行释放:
{Saw.ar(EnvGen.kr(Env.new([500,100],[1.0]),doneAction:2),0.1)}.scope
注意观察internal server返回的信息。
我们已经看到其它一些同样可以用做包络的UGen。它们也可用于释放:
Line // 直线生成器
XLine // 指数线生成器
/////////
{Saw.ar(SinOsc.ar(1,0,10,440),Line.kr(0,1,1,doneAction:2))}.scope
{Saw.ar(SinOsc.ar(1,0,10,440),XLine.kr(0.0001,1,1,doneAction:2))}.scope