自动化
用 ramp() 做渐变,用 env() 画点和曲线,再加上模式和信号——让设备参数、推子和发送随时间变化,和“在 TuttiDAW 中打开”后显示的自动化完全一样。
设备参数不必一成不变。给它一个模式,它就逐个循环地变化;给它一个信号,它就平滑地扫动。这就是用代码写的自动化:“在 TuttiDAW 中打开”会把它显示为声部片段上的包络,在 /code 上声部也按同样的方式播放。
| 值 | 设备得到的是 |
|---|---|
0.4、"4s"、slider(0.4) |
一个保持不变的设置 |
ramp(-60, 0, 4) |
4 小节内从 -60 直线变到 0,然后重来 |
env("0:200 2:4000~.5 4:200") |
用直线和曲线连接起来的点 |
"<0.1 0.6>"、"0 0.5 1 0.5" |
每个事件处一个台阶:值一直保持到下一个事件 |
sine.range(300, 3000) |
平滑的扫动,每个循环采样 16 次 |
和 .inst、.fx、.midifx 本身一样,这是 TuttiDAW 独有的功能。
渐变:ramp
ramp(from, to, bars) 是在若干小节内从一个值到另一个值的直线。给底鼓的推子做一个 4 小节的淡入:
kick: s("bd*4").mix({vol: ramp(-60, 0, 4)})之后渐变会重新开始,就像模式会循环一样。加上 .once(),它就从程序开头只播放一次,然后保持最后的值:
pad: note("<c3 eb3 g3 bb3>").s("sawtooth").release(0.3)
.mix({vol: ramp(-60, -6, 8).once()})程序的循环会变长,盖住渐变或包络(这里是 8 小节),所以在 /code 上能听到完整的变化。
点、直线和曲线:env
env("...") 用 position:value 点画出任意形状,点之间用直线连接。位置以小节计(1.5、3/4);值使用参数自己的单位,可以带单位("-6dB"、"2kHz"):
pad: note("c3").s("sawtooth")
.fx("Auto Filter", {frequency: env("0:200 2:4000~.5 4:200")})| 写法 | 含义 |
|---|---|
2:4000 |
第 2 小节处值为 4000,一条直线通向这里 |
2:4000~.5 |
结束于此的线段弯曲(-1..1;正值在起点附近停留更久,和工作室里的曲线一样) |
_2:4000 |
保持之前的值直到第 2 小节,然后跳变 |
2:0 2:1 |
同一位置的两个点:跳变 |
包络按最后一个位置循环。第二个参数可以让循环更长:env("0:0 2:1", 4) 先上升两小节,再保持两小节。在第一个点之前,它保持第一个值。
精确形式
工作室还可以把曲线存成贝塞尔曲线(Live 的曲线手柄)。代码把它写成点的列表,每个点是 [position, value],可以带一段线段:{curve: k}、{curve: [x1, y1, x2, y2]} 或 "hold":
lead: note("c4 eb4 g4").s("sawtooth")
.mix({pan: env([[0, -1], [2, 1, {curve: [0.2, 0, 0.8, 1]}], [4, -1, "hold"]])})很少需要手写它:工作室里的“复制为 TuttiCode 代码”会写出能精确保留自动化的最短形式——ramp、env 字符串,或者这个列表。
每隔一小节更湿的混响
"<0.1 0.6>" 在第一个循环是 0.1,第二个循环是 0.6:
pad: note("<c3 eb3 g3 bb3>").s("sawtooth").release(0.3)
.fx("Reverb", {dryWetBalance: "<0.1 0.6>", decayTime: "3s"})decayTime 是常量,所以一直是 3 秒。同一个设备的多个参数可以同时变化,各用各的模式。
滤波器扫频
信号是连续变化的。sine.range(300, 3000) 每个循环从 300 Hz 升到 3000 Hz 再回来;.slow(4) 把它拉长到四个循环:
bass: note("c2*8").s("sawtooth")
.fx("Auto Filter", {frequency: sine.range(300, 3000).slow(4)})这样程序会在四个循环后重复,和任何四个循环才变一轮的模式一样。
单位、乐器和 MIDI 效果器
模式接受的值和常量一样,用参数自己的单位:带单位的字符串会被换算("<-6dB 0dB>"、"<1s 4s>")。乐器参数也能自动化:
lead: note("c4 eb4 g4 bb4").inst("Drift", {cutoff: "<400 1200 2400 800>"})
.fx("Utility", {gainDb: "<-6dB 0dB>"})选项类参数在它的名称之间跳变。在模式里,Arpeggiator 的 rate 名称(1/16、1/8)按名称读,不当作除法:
arp: note("[c3,e3,g3]").midifx("Arpeggiator", {style: "<Up Down>", rate: "<1/16 1/8>"})带空格的名称("Up & Down")不能作为模式里的一步:请用它的序号。百分数("30%")只能写成常量,因为 % 在迷你记法里另有含义——在模式里请写 0.3。
总线、编组和 master
总线、编组和 master 也能这样变化:它们的 .mix({vol, pan})、编组的 .send(bus, level) 以及它们设备的参数都可以用模式和信号。
bus("verb").fx("Reverb", {dryWetBalance: 1, decayTime: "<2s 6s>"})
.mix({vol: sine.range(-18, -6).slow(4)})
group("drums").fx("Drum Buss", {drive: "<0 20>"}).send("verb", "<-30 -12>")
master.mix({vol: "<0 -3>"})
kick: s("bd*4").group("drums")
pad: note("<c3 eb3>").s("sawtooth").release(0.3).send("verb", -6)这些轨道没有自己的片段,所以“在 TuttiDAW 中打开”会把它们的自动化写进编排视图:写在返回轨道、drums 编组和程序的编组(master)上,在声部片段覆盖的范围内每个循环一份。把片段拉长后再求值一次,自动化会跟着延伸。代码写下的点归代码所有——手动编辑其中一个点,那条总线、编组或 master 就会与代码分离(“重新关联”可以让代码重新生效)。你在这个范围之前或之后画的点归你所有,代码从不改动它们。
不能变化的东西
- 静态设置只接受常量:例如 Ensemble 声部的
voice或滤波器类型。在那里写模式会报错,并列出可以变化的参数。 - 用名称模式指定设备本身(
.fx("<Reverb Delay>"))是错误:一个声部只有一条效果链。
在工作室里
包络归代码所有,和声部的其他值一样:每次求值都会重写它,设备显示的是模式的第一个值。ramp 和 env 会变成带曲线的真实断点,可以像任何包络一样编辑。和声部片段一样长的包络随片段循环;更长或更短的是带自己循环的非关联片段包络,.once() 的则是关闭了循环的非关联包络。手动编辑这条包络会让声部与代码分离(“重新关联”可以让代码重新生效)。一条包络最多 1024 个点;变化得更频繁的模式会改在更粗的网格上保持,并给出警告。