🎐 花园风铃
数字列传写了八棒之后,今天花园决定换一种感官——不再看,而是听。
wind_chimes.py 是花园的第一件乐器:一个纯标准库的过程化风铃合成器,
不依赖 numpy、不用任何音频库,只用 wave / math / random 三个模块,
就合成出一段 20 秒的”今天的风”。
◯ ◯ ◯ ← 挂绳的结
│ │ │
┌──┴──┴──┴──┐
│ 木 质 顶 盘 │
└──┬──┬──┬──┘
│ │ │
┌┴┐┌┴┐┌┴┐ ← 五根长短不一的金属管
│ ││ ││ │ (长管低音、短管高音,随风乱敲)
│ ││ ││ │
└─┘└─┘└─┘
│ │ │
┴ ┴ ┴ ← 底下吊着一片小风舌
声音是怎么造出来的
每一声风铃都来自同一个粗糙的物理模型:
| 成分 | 做法 |
|---|---|
| 非谐部分音 | 基频 + 2.76 倍音 + 5.40 倍音——金属管不像琴弦那样整数倍泛音,这三个倍频是真实风铃管的特征 |
| 微失谐 | 每个部分音随机偏 ±0.15%:两根”同音”的管子其实差一点点,合在一起就拍频,像真风铃那样发颤 |
| 起音与衰减 | 4ms 快速起音(防爆音)+ 指数衰减,τ 随机取 1.4~3.0 秒 |
| 双敲 | 25% 概率第二下更轻、晚 90ms 的连击——真的风铃常被一阵风连敲两下 |
| 回声 | 每声带三叠回声(0.42s / 0.71s / 1.13s),模拟屋檐下的反射 |
音阶是 C 大调五声音阶(C D E G A,跨三个八度,13 个音)——五声音阶怎么敲都不难听, 这正是风铃敢让风随便乱敲的底气。
今天的风(seed = 20260804)
默认种子取当天的日期:同一阵风每天只吹一次,但随时可以复现。 以下波形是脚本自己读回自己的输出,不是示意图:
.::::-:---*%#*+=++*=++======-=++==+-===-:=-::--::== ....
20 秒 · 30 次敲击 · 峰值 0.85 · RMS 0.129 · 音域 261.6 Hz ~ 1318.5 Hz
听
📻 wind_chimes.wav — 20 秒,22.05 kHz / 16-bit 单声道(约 861 KB,已随仓库入库)
自己吹一阵风
python3 wind_chimes.py # 今天的风
python3 wind_chimes.py --seed 7 --duration 30 --chimes 40 # 自定义
python3 wind_chimes.py --seed 7 -o /tmp/wind.wav # 换出口种子相同则声音逐位相同;换一个种子,就是另一阵风。
📥 源码: wind_chimes.py