第 18 章:练习题与小作业——从“代码逻辑”到“音乐直觉”的综合演练
18.1 开篇段落:作曲家的健身房
欢迎来到本书的“健身房”。
在前十七章中,我们拆解了 Sonic Pi 的语法,分析了久石让的清澈和声、Hans Zimmer 的音墙轰炸以及华语古风的细腻腔调。但“看懂指南”和“写出作品”之间,隔着巨大的鸿沟。这个鸿沟只能通过刻意练习(Deliberate Practice)来填平。
本章不再教授新语法,而是提供 7 个梯度递增的专项训练。这些题目设计为“微型项目 Brief(需求书)”,模拟你在为一段游戏场景、一部短片或一首古风歌曲进行配乐。
本章的核心目标:
- 翻译能力:训练你听到脑中的旋律后,能迅速将其拆解为 Sonic Pi 的
live_loop、ring 和控制参数。
- 风格控制:不仅是写出音符,而是通过包络(ADSR)、滤波器(Cutoff)和混响(Reverb)精确控制“听感温度”。
- 算法思维:学会用
tick、look 和随机数来制造“受控的变化”,而不是无序的混乱。
18.2 练习前的准备:思维工具箱
在动手之前,请复习以下三个“思维模型”,它们是解题的钥匙:
- 减法思维(Subtractive Thinking):
- 不要一开始就堆满音符。古风需要“留白”,电影配乐需要“频段让位”。
- Rule of Thumb:如果一段代码听起来很乱,先静音掉 50% 的元素,而不是增加音量。
- 参数即表情(Parameters as Expression):
- 代码没有“轻重缓急”的手势,你需要用
amp:(力度)、release:(呼吸长短)、cutoff:(明暗语气)来模拟演奏者的表情。
- 层级视角(Layered View):
- 任何复杂的配乐都可以拆解为:律动层(Rhythm) + 低音层(Bass) + 和声层(Pad/Arp) + 旋律层(Lead)。解题时,请分层思考。
18.3 专项练习(含提示与参考逻辑)
练习 1:情感变色龙 (The Emotional Chameleon)
场景:你正在为一部互动电影配乐。同一个场景有三种平行宇宙的走向,导演要求你使用完全相同的一套和弦进行(例如 I - V - vi - IV),但通过音色设计表达出截然不同的情绪。
题目:
使用 [:c, :g, :a, :f] 为根音的基础进行。编写三个版本的 live_loop:
- 版本 A(久石让式):“夏日的午后,微风,自行车”。关键词:清脆、断奏、明亮
- 版本 B(Hans Zimmer 式):“深海潜水艇,压抑,未知”。关键词:连奏、浑浊、缓慢展开。
- 版本 C(赛博/故障风):“霓虹灯下的故障机器人”。关键词:失真、甚至有点走调。
提示 (Hint):
- A 版:重点在于短
release 和较高的八度。
- B 版:重点在于长
attack(淡入),低通滤波器(LPF)把高频切掉,以及极低的八度。
- C 版:尝试使用
detune(失谐)参数,或者 bitcrusher 效果器。
参考解题逻辑(点击展开)
* **版本 A(清新)**:
* **音源**:`:piano` 或 `:pluck`。
* **音符逻辑**:分解和弦(Arpeggio)。使用 `tick` 快速遍历和弦内音。
* **关键参数**:`release: 0.3`(短促),`reverb: 0.2`(干一点,显近)。
* **节奏**:8 分音符或 16 分音符的跳跃感。
* **版本 B(深海)**
* **音源**:`:dark_ambience` 或 `:prophet`。
* **音符逻辑**:柱式和弦(所有音同时响)。
* **关键参数**:`attack: 2.0`(像弦乐一样慢进),`sustain: 4.0`(铺满),`cutoff: 70`(闷闷的),`amp: 0.6`(克制)。
* **音区**:降低 2 个八度(`:c2` 范围)。
* **版本 C(故障)**:
* **音源**:`:saw` 或 `:dsaw`。
* **效果链**:包裹在 `with_fx :bitcrusher` 中。
* **关键参数**:`detune: 0.2`(产生不协和感),`release: 0.1`(极短的机械感)。
* **随机性**:偶尔用 `one_in(4)` 触发一个极高音或休止,模拟电路接触不良。
练习 2:古风织体的“留白”构建 (Gufeng Textures & Negative Space)
场景:你要写一首古风歌曲的前奏。导演觉得现在的版本“太满、太吵”,没有“意境”。你需要重新编排伴奏,体现中国画的疏密感。
题目:
主旋律由笛子(:flute 或采样)演奏。你需要编写三个伴奏层,要求:
- 古筝层:不要一直弹。要求模拟“流水”感——一串快速音符后,接长时间的留白。
- 大鼓层:建立“板眼”感。不要动次打次,要“沉、稳、稀”。
- 风铃/高频层:作为点缀,随机出现在立体声场的左右。
可视化目标 (ASCII 示意):
笛子 (Melody): ====== ====== ====== ====== (连贯)
古筝 (Zheng): ...~~~ ...~~~ (疏密相间)
大鼓 (Drum): X X (极稀疏)
提示 (Hint):
- 五声音阶:牢记
scale(:c4, :pentatonic_major)。
- 疏密控制:使用
if 条件判断(例如 tick % 8 == 0)来控制古筝何时触发“那一串”音符,其余时间 sleep。
参考解题逻辑(点击展开)
* **古筝层(流水逻辑)**:
* **结构**:一个 `live_loop`,步长为 0.25。
* **算法**:设定一个概率开关 `dice(6)`。如果摇到 6,则触发一个 `3.times` 的快速循环(模拟轮指),播放三个五声音阶音符。
* **关键**:如果没摇到 6,只 `sleep` 不播放。这制造了随机的留白。
* **音效**:加一点 `echo`,让那串音符有尾韵。
* **大鼓层(板眼逻辑)**:
* **音源**:`:taiko` 或低通滤波后的 `:bd_haus`。
* **节奏**:不要用简单的 `sleep 1`。尝试 `sleep 3` 然后 `sleep 1`,制造“强拍...等待...弱拍”的非对称感。
* **力度**:`amp` 应该很大,但 `cutoff` 很低,以此获得“震动感”而非“打击声”。
* **高频层(点缀)**:
* **音源**:`:noise`(带音调)或高音 `:bnoise`。
* **空间**:使用 `pan: rrand(-0.8, 0.8)` 让声音在左右耳随机出现。
练习 3:旋律发展——从“动机”到“乐句” (Motif Development)
场景:你写了一个很好听的 4 个音的动机(Motif),例如 E-G-A-G。现在需要把它发展成一段 8 小节的完整旋律,不能单调重复,要有叙事感。
题目:
使用 play_pattern_timed 或 ring,基于同一动机完成以下变奏:
- 陈述(A):原样播放。
- 模进(Sequence):将整个动机上移五度播放(模拟转调带来的情绪提升)。
- 加密(Rhythmic Diminution):保持音高不变,但将时值减半(节奏变快一倍),制造紧张感。
- 逆行(Retrograde):挑战题,将这串音符倒序播放,听听看是否可用。
提示 (Hint):
- Sonic Pi 的
Ring 链式操作非常适合做这个。
.map { |n| n + 7 } 可以实现移调。
.reverse 可以实现逆行。
参考解题逻辑(点击展开)
* **数据结构**:定义基础动机 `notes = [:e4, :g4, :a4, :g4]`,基础时值 `times = [1, 0.5, 0.5, 2]`。
* **第 1-2 小节(陈述)**:直接 `play_pattern_timed notes, times`。
* **第 3-4 小节(模进)**:
* 使用 `.map` 函数:`notes_high = notes.map { |n| n + 5 }`(上移四度/五度)。
* 播放 `notes_high`。
* **第 5-6 小节(加密/紧张)**:
* 时值缩短:`times_fast = times.map { |t| t * 0.5 }`。
* 连播两次,制造急促感。
* **第 7-8 小节(收尾/逆行)**:
* 使用 `notes.reverse` 得到 G-A-G-E。
* 最后一个音 `E` 的时值拉长(`sustain: 4`),作为乐句的解决(Resolution)。
练习 4:Zimmer 式音墙——自动化与动态 (The Wall of Sound)
场景:电影的高潮部分,英雄正在冲向终点。导演要求配乐有“巨大的推背感”,从静谧逐渐推向宏大。
题目:
编写一段 16 小节的 Loop,不做复杂的旋律,只做动态推进。要求实现 “The Sunrise Effect”(日出效应):
- 低音脉冲:16 分音符的 Bass,音色从闷(Low Cutoff)逐渐变亮(High Cutoff)。
- 弦乐长音:和声层,音量从 0 逐渐淡入到 1。
- 打击乐:只在最后 4 小节加入,并且密度越来越大。
提示 (Hint):
- 自动化核心:使用
line(start, finish, steps: n) 函数生成控制曲线。
- 同步:确保所有层都
sync 到同一个节拍器,否则推进会乱。
参考解题逻辑(点击展开)
* **全局控制变量**:
* 创建一个 `line` 对象:`brightness = line(60, 120, steps: 64, inclusive: true)`。
* 这代表在 64 个 16 分音符(即 16 小节)内,Cutoff 值从 60 升到 120。
* **Layer 1:低音脉冲**:
* `live_loop` 每次 tick 读取 `brightness` 的值。
* `play :saw, cutoff: brightness.look, release: 0.15`。
* 听感:声音会像盖子被慢慢揭开一样变亮。
* **Layer 2:打击乐引入**:
* 利用 `tick` 的计数功能。
* `if tick > 48` (即最后 4 小节):触发高频打击乐(如 Hi-hats 或 Taiko)。
* `if tick > 60` (最后 1 小节):触发滚奏(Snare Roll)。
* **重置逻辑**:
* 记得在循环结束后重置 `tick` 或停止,否则它会一直亮下去。
练习 5:人声切片与粒子化 (Vocal Granulation)
场景:你有一段干声(Dry Vocal),是一句优美的戏腔慢唱。现在想把它 remix 成一首电子风格的曲子,需要把人声变成“节奏乐器”。
题目:
使用 sample 命令,对一段人声素材进行“显微手术”:
- 基础切片:利用
onset 选项,每次只播放人声的某一个字。
- 随机重组:打乱顺序播放这些字,创造“碎片化回忆”的效果。
- 音高再造:在播放切片时,强制改变其播放速率(
rate),使其符合当前的和弦根音(例如 rate: 1.5 对应五度)。
提示 (Hint):
- Sonic Pi 的
onset: 参数能自动识别音频中的瞬态(Transient,即发声的起点)。
rate 与半音的关系公式:rate: 2 ** (n / 12.0),其中 n 是半音数。
参考解题逻辑(点击展开)
* **准备工作**:
* 选择一个咬字清晰的采样(`:loop_amen` 或外部人声 WAV)。
* **随机重组算法**:
* `live_loop` 内,使用 `n = rand_i(8)` 随机选择第 0 到 第 8 个发音点。
* `sample :my_vocal, onset: n`。
* 这会产生一种“语无伦次但节奏对齐”的电子感。
* **和声化(Harmonization)**:
* 定义一个和弦数组 `chord_intervals = [0, 4, 7]` (大三和弦)。
* 随机选择一个音程 `semi = chord_intervals.choose`。
* 计算速率:`r = 2 ** (semi / 12.0)`。
* `sample ..., rate: r`。
* 结果:人声切片不仅节奏跳跃,而且会“唱”出大三和弦的旋律。
练习 6:过门与 Crash 的艺术 (The Drop)
场景:EDM 或史诗配乐中,从 Build-up(蓄力)到 Drop(爆发)的那一瞬间至关重要。新手最容易犯的错误是“一直吵到底”。
题目:
编写一个 4 小节的过门段落,包含以下三个阶段:
- 加速(Acceleration):军鼓滚奏从 8 分音符变成 32 分音符。
- 抽空(The Vacuum):在第 4 小节的第 4 拍,强制静音(Silence),只留一点点残响。
- 爆发(Impact):紧接着触发一个巨大的 Crash 和 Sub Bass。
提示 (Hint):
- 利用
control 来改变正在休眠的 sleep 时间是不行的。通常需要根据时间流逝改变 sleep 的变量值。
- “抽空”可以通过
stop 一个循环,或者单纯的 sleep 实现。
参考解题逻辑(点击展开)
* **滚奏算法**:
* 使用 `density` 函数包裹一段简单的鼓点,并将密度参数绑定到一个 `line(1, 4)` 甚至 `line(1, 8)` 上。
* 或者手动写一个循环,`sleep_time` 变量从 0.5 递减到 0.0625。
* **静音设计(最重要的一步)**:
* 计算时间:在 Loop 运行到 3.75 小节(即第 4 小节第 4 拍)时。
* 执行逻辑:不触发任何 `play` 或 `sample`。
* 甚至可以加一个 `sample :vinyl_rewind`(倒带声)作为吸气感。
* **爆发**:
* 过门结束后,发送一个 `cue :drop`。
* 另一个 `live_loop` 等待 `sync :drop`,然后同时播放 `:bd_fat`(低音)+ `:cymbal_crash`(镲)+ 巨大的 Reverb。
练习 7:交付专项——分轨导出 (Stems Delivery)
场景:你的曲子写完了,但混音师要求你提供“分轨(Stems)”。他需要单独的鼓、单独的贝斯、单独的旋律(带混响)和单独的干声。
题目:
修改你现有的工程代码,建立一个“总控开关系统”,让你只需要改一个变量,能分别导出不同轨道。
要求:
- 导出旋律轨时,必须包含完整的尾音(Tail),不能戛然而止。
- 导出鼓轨时,不能有任何旋律的漏音。
参考解题逻辑(点击展开)
* **布尔值总控**:
* 在代码最顶端定义配置区域:
```ruby
# 混音师配置面板
MUTE_DRUMS = true
MUTE_MELODY = false
MUTE_BASS = true
```
* **条件执行**:
* 在每个 `live_loop` 的 `do` 后面紧跟一行:`stop if MUTE_DRUMS`。
* 或者用 `if !MUTE_DRUMS ... end` 包裹发声代码。
* **尾音保护**:
* 不要依赖 `stop` 按钮来结束录音。
* 在代码末尾(如果是线性写作)或手动操作时,让乐器停止触发后,继续录制 4-8 秒的“空转”时间,捕捉 Reverb 的衰减。
18.4 常见陷阱与错误 (Gotchas)
在完成这些挑战时,你可能会遇到以下“直觉”的问题:
- “为什么我的爆发(Drop)听起来没有力气?”
- 原因:通常是因为你前面的 Build-up 太吵了。
- Rule of Thumb:对比产生力量。想要 Drop 听起来响,前面的过门必须切掉低频(High Pass Filter),并在最后留出静音。没人能听到 100 分贝后的 101 分贝,但所有人都能听到 0 分贝后的 80 分贝。
- “古筝的轮指听起来像机关枪”
- 原因:因为每次触发的音量(
amp)都一样,且时间间隔过于精确。
- 解法:必须通过
rrand 给 amp 和 sleep 加微小的随机量。没有人类能弹出绝对精确的 0.125 秒间隔。
- “分轨导出后,DAW 里的速度对不上”
- 原因:Sonic Pi 的启动可能有微小延迟,或者录音文件的开头包含了一段静音。
- 解法:在导出音频的开头加一个短暂的“同步音”(如一个短促的 Click),在 DAW 里齐这个 Click,然后切掉它。
18.5 本章小结
本章的练习没有标准答案。
- 如果你的“久石让”听起来像“恐怖片”,检查你的和弦是否太低、混响是否太长。
- 如果你的“古风”听起来像“迪斯科”,检查你的节奏是否太满、缺乏呼吸。
这些练习不仅是代码训练,更是耳力训练。当你能熟练地在脑海中调整参数并预知其听感结果时,你就真正掌握了 Sonic Pi 这个乐器。