欢迎来到 Sonic Pi 的世界。作为一个能识谱、懂和弦走向,并对频谱有直觉的创作者,你可能会问:为什么要放弃直观的钢琴卷帘窗(Piano Roll),转而使用代码?
在 DAW 中,你是在描绘波形;而在 Sonic Pi 中,你是在描述产生波形的逻辑。对于我们设定的目标风格,这种思维转换带来了巨大的优势:
sleep 0.25 是数学上的绝对精确,能产生极具压迫感的“机械整齐度”。本章的目标是让你建立“时间=代码行”的直觉,并写出第一个包含鼓、贝斯、和声的 8 小节循环。
Sonic Pi 的底层是一个强大的音频合成引擎(SuperCollider)。作为熟悉频谱分析的,需要理解这里的采样率与缓冲设置,因为它们直接关系到声音的瞬态响应(Transient Response)。
这里谈论的是音频硬件的 Buffer,不是代码界面的 Buffer。
512 或 1024。我们是在“写作”,不是在“手指击鼓”,100ms 的延迟完全不影响代码生效,且能保证你在叠加几十层 Zimmer 式大动态管弦乐时不会爆音。256。Sonic Pi 的操作逻辑不是“播放录音带”,而是“实时解释执行”。
live_loop 已经在跑的时候再次点击 Run,Sonic Pi 会动态更新那个循环的逻辑,而不会停止它。这就是 Live Coding 的核心。界面右上角的 Scope 显示了输出信号的波形。
右侧面板。它会显示:
{run: 1, time: 0.0}:当前运行的 ID 和节拍时间。synth :prophet, {note: 60, ...}:具体触发了什么音。amp: 0)。我们需要将五线谱上的概念精准翻译成 Ruby 语法。
Sonic Pi 接受三种音高表示法,它们可以混用:
:c4 (中央C), :fs3 (F#3), :eb5 (Eb5)。这是最直观的。60 (中央C)。适合数学运算(例如:60 + 12 升八度)。440。这对于做微分音(Microtonal)或模拟古琴不标准的定弦非常有用。sleep 的哲学在 Sonic Pi 中,时间是阻塞的。程序读到 sleep 1 会真的“睡” 1 拍,然后再执行下一行。
| 五线谱 | 代码 (默认 BPM) | 说明 |
|---|---|---|
| 四分音符 (Quarter) | sleep 1 |
一拍 |
| 八分音符 (Eighth) | sleep 0.5 |
半拍 |
| 十六分音符 (16th) | sleep 0.25 |
Zimmer 动作类配乐的基础网格 |
| 三连音 (Triplet) | sleep 1.0/3 |
注意要写 1.0 这种浮点数,写 1/3 会变成 0 |
do ... end 块在 Sonic Pi 中,几乎所有的结构(循环、函数、随机选择)都包裹在 do ... end 之间。
# 这是一个代码块的示例
live_loop :my_loop do # 开始
play 60
sleep 1
end # 结束
我们将直接跳过单调的“滴滴嘟嘟”,构建一个包含 Zimmer 式低频脉冲、久石让式清澈和弦 和 古风旋律动机 的 8 小节片段。
请将以下代码复制到 Buffer 0 中:
# 全局设定:速度设为 80 BPM,适合史诗感或舒缓的古风
use_bpm 80
# === 层级 1: 节奏与脉冲 (Rhythm & Pulse) ===
# 模拟 Hans Zimmer 的 Action Strings 或合成器 Bass 脉冲
# 这种 16 分音符的持续驱动是现代配乐的骨架
live_loop :pulse do
# 选用一个模拟合成器贝斯音色
use_synth :tb303
# tick 命令:每次循环让计数器 +1
# look 命令:查看当前计数器的值
# 这是一个简单的逻辑:每 4 个音符(一拍),第一个音大声(0.3),后个小声(0.15)
# 这种强弱规律创造了“推进感”
if (look % 4) == 0
amp_val = 0.3
else
amp_val = 0.15
end
# cutoff: 滤波器截止频率。设低一点(70)让声音闷在下面,不抢高频旋律
play :c2, release: 0.2, cutoff: 70, amp: amp_val
sleep 0.25 # 16分音符网格
tick # 计数器推进
end
# === 层级 2: 氛围和声 (Atmospheric Chords) ===
# 模拟久石让风格的铺底,使用长音 Pad
live_loop :chords do
# :hollow 是一种带有风声特性的合成器,非常适合古风留白
use_synth :hollow
# 定义和弦进行:C大调 I - V - vi - IV (C - G - Am - F)
# 这里的 ring 是环形列表,tick 会自动循环读取
current_chord = (ring
[:c3, :e3, :g3, :b3], # Cmaj7
[:g2, :d3, :g3, :b3], # G/B (转位)
[:a2, :c3, :e3, :g3], # Am7
[:f2, :c3, :e3, :a3] # Fmaj7
).tick
# attack: 起音时间。4秒的缓慢淡入,制造像云雾一样的感觉
# sustain: 保持时间。
# release: 释放时间。
play current_chord, attack: 4, sustain: 2, release: 2, amp: 1.2
sleep 8 # 每个和弦持续 2 小节 (8拍)
end
# === 层级 3: 旋律 (Melody) ===
# 简单的五声音阶动机,模拟钢琴或钟琴
live_loop :melody do
use_synth :piano
# sync 极其重要!它强制让旋律层等待 :pulse 层完成一轮
# 这保证了无论你何时点击 Run,鼓和旋律永远对齐,不会乱拍
sync :pulse
# 五声音阶:C D E G A
play_pattern_timed [:c5, :d5, :e5, :g5], [0.5, 0.5, 1, 2]
play_pattern_timed [:a5, :g5, :e5, :d5], [0.5, 0.5, 1, 2]
end
cutoff: 70):在 :pulse 层,我们使用了低通滤波器。作为懂频谱的你,知道这能把 1000Hz 以上的空间留给 :melody 层,避免低频乐器和高频旋律“打架”。这就在代码里完成了初步的混音(Mixing)。attack: 4):在 :chords 层,长 Attack 意味着声音慢慢浮现,这是营“电影感”和“古风意境”的关键——不要让所有声音都瞬间冲出来。sync):这是 Sonic Pi 最强大的功能。它解决了传统编程很难处理的“对齐”问题。如果你只是点击顶部的 Rec,你会得到一个混合好的 WAV。但这不够专业。为了配合人声处理,我们需要分轨导出 (Stems)。
人声(Vocal)通常占据中频(500Hz - 2kHz)。如果你把伴奏录成了一轨,当人声切入时,你无法单独把伴奏里的钢琴中频挖掉,也无法只给鼓组加侧链压缩(Sidechain Compression)。
没有“一键导出所有分轨”的功能,我们通常这样做:
:chords 和 :melody 的 live_loop 前面加上 stop 命令,或者注释掉它们。Run,现在只听到鼓。Rec,录制 8-16 小节。保存为 Drums.wav。:chords,注释掉其他。Rec。保存为 Pad.wav。Melody.wav。💡 经验法则 - 头部静音
录音时,先点 Rec,再点 Run。让音频文件开头有一段空白。 拖入 DAW (Logic/Cubase) 后,你只需要把所有波形的第一个声音瞬态(Transient) 对齐到网格的第 2 小节或第 3 小节开头,所有轨道就会完美同步。
为了后续章节的学习,我们约定以下代码规范:
live_loop 的名字要有意义,如 :drums_kick、:piano_arp。:melody_v1 并注释掉,新的叫 :melody_v2。# 写下你的乐理意图。例如 # 这里的 sleep 是为了让出人声的空间。练习 1:音高听写与修正 下面的代码试图播放 C 大调音阶(C D E F G A B C),但听起来很怪。请找出错误的音符并修正它。
live_loop :scale_test do
play :c4
sleep 0.5
play :d4
sleep 0.5
play :e4
sleep 0.5
play :fs4 # <--- 听听这里是不是怪怪的?
sleep 0.5
play :g4
sleep 0.5
play :a4
sleep 0.5
play :bb4 # <--- 这里呢?
sleep 0.5
play :c5
sleep 0.5
end
练习 2:呼吸节奏
使用 sample :bd_tek 写一个心跳节奏。要求:
sleep 1。练习 3:和弦的声音设计
复制 1.5 节中的 :chords 循环。尝试修改 attack 和 release 参数。
练习 4:Hans Zimmer 的 5/4 拍推进 Zimmer 喜欢用非 4/4 拍的奇数拍子制造不稳定感。 请写一个 Loop:
强 弱 弱 | 强 弱)。:drum_heavy_kick。amp: 1,弱拍 amp: 0.5。练习 5:古风的“留白”概率 写一个风铃或古筝的高音 Loop。
one_in(5) 函数。如果是 true 则 play,否则不 play。live_loop 命名冲突错误:复制了两个 live_loop 但忘记改名,两个都叫 :beat。
后果:Sonic Pi 会认为你是在修改同一个 Loop。只有最后一个被定义的 :beat 会运行,前一个会消失或被覆盖。
调试:确保每个 live_loop 的名字(冒号后面的部分)在整个文件中是唯一的。
错误:想写一个休止符,于是写了 play 0 或 amp: 0。
解释:虽然听不到声音,但这实际上还是消耗了 CPU 去合成一个静音。
正确做法:直接 sleep 即可。sleep 本身就是“不发声的时间流逝”,也就是休止符。
这是新手最容易遇到的 Syntax Error。
play :c4, amp: 1 (中文逗号)play :c4, amp: 1 (英文逗号)