LapOrk (OTAMATONE)
About
作业是设计一个自己的声音, 因为刷到了 【雫るる】电音蝌蚪演奏音乐会 开庭时带上你的蝌蚪, 那么就尝试用 SuperCollider 复刻试试. (虽然不一定能成)
Analyze
从视频里面截取了一个单音, 然后在 Audacity 中 Analyze-Plot Spectrum 查看频谱:

Analyze I: \(\mathrm{FFT}^{-1}\)
理论上去生成频谱然后逆变换就可以得到声音了, 比如把频谱中的峰挑出来再合成:
(defsynth otamatone1 ((out 0) (freq 700) (gate 1) (amp 0.9))
(out.ar out (* (env-gen.ar (adsr 0.01 0.01 0.95 0.01 amp -0.5) :gate gate)
(klang.ar (list (list 1 2 3 4 5 6 7)
(list 0.2 0.2 0.1 0.1 0.05 0.05 0.01)
nil)
freq))))
解释
- Klang: 给一组
(频率, 增幅, 相位)并合成正弦波的叠加, 理论上等效于:(reduce #'+ (mapcar (lambda (freq amp phr) (sin-osc.ar freq phr amp)) freq amp pharses))
比如以
700为基础频率, 得到: ADSR设计得让声音有一个没啥变化的死鱼一样地起伏:- 其他的都之前介绍过了
(defparameter *tone* (synth 'otamatone1 :gate 0))
(oscdef :freq (freq)
(ctrl *tone* :freq (+ (* freq 800) 100)))
(oscdef :gate (gate)
(ctrl *tone* :gate gate))
注: Klang 貌似并不支持控制 freq.
一个暴力的修正方法
(defsynth otamatone1 ((out 0) (freq 700) (gate 1) (amp 0.9))
(out.ar out (* (env-gen.ar (adsr 0.01 0.01 0.95 0.01 amp -0.5) :gate gate)
(reduce #'sc::+~
(mapcar (lambda (f a)
(sin-osc.ar (sc::*~ f freq) 0 a))
'(1 2 3 4 5 6 7)
'(0.2 0.2 0.1 0.1 0.05 0.05 0.01))))))
对应到 SuperCollider 中的代码如下:
(
SynthDef(\otamatone1, { |out=0, gate=1, amp=0.9, freq=700|
var env = EnvGen.ar(
Env.adsr(0.01, 0.01, 0.95, 0.01, 1, -0.5),
gate,
doneAction: 2
);
var sig = SinOsc.ar(freq, 0.0, 0.2) +
SinOsc.ar(2 * freq, 0.0, 0.2) +
SinOsc.ar(3 * freq, 0.0, 0.1) +
SinOsc.ar(4 * freq, 0.0, 0.1);
Out.ar(out, amp * sig * env);
} ).add;
)
Update: 稍微更聪明一点的办法:
(defsynth otamatone1 ((out 0) (freq 700) (gate 1) (amp 0.9))
(out.ar out (* (env-gen.ar (adsr 0.01 0.01 0.95 0.01 amp -0.5) :gate gate)
(dyn-klang.ar (list (sc::*~ '(1 2 3 4 5 6 7) freq)
(list 0.2 0.2 0.1 0.1 0.05 0.05 0.01)
nil)))))
(TouchOSC 文件见 otamatone1.tosc)
Analyze II: WOWOWOWOWOWOWOWOWOWOWA
上面的演示视频里面, 如果鼠标在划移的话, 听起来声音会像一些, 但是如果只是停在某处不动的话, 就会有一种比较怪怪的感觉:
如果把前面频谱分析的片段时间拉长一点, 就会看到在时间轴方向上, 频率会有一个小小的波动:

所以其实是需要给这个 freq 加上一点点的正弦的偏置的…
(defsynth otamatone2 ((out 0) (freq 700) (gate 1) (amp 0.9)
(wowf 2) (wowa 0.1) (wowb 0.5) (wow 0))
(out.ar out (* (env-gen.ar (adsr 0.01 0.01 0.95 0.01 amp -0.5) :gate gate)
(dyn-klang.ar
(list (sc::+~ (sc::*~ '(1 2 3 4 5 6 7) freq)
(sc::*~ wow
(sin-osc.kr wowf 0
(sc::*~ wowa freq)
(sc::*~ wowb freq))))
(list 0.2 0.2 0.1 0.1 0.05 0.05 0.01)
nil)))))
(defparameter *tone* (synth 'otamatone2 :gate 0))
Analyze III: Saw
与其做逆傅立叶变换那套, 不妨试试用信号滤波, 由伟大的 LLM 告诉我们, 一个三角波信号的傅立叶变换为分立的频谱峰, 其峰值为 \(\frac{1}{n}\)…
虽然现在的频谱峰很接近了, 但是现在的峰值显然不是 \(\frac{1}{n}\) 的分布, 所以可以猜测里面做了一个滤波 – 总之先试试低通:
(defsynth otamatone3 ((out 0) (freq 700) (gate 1) (amp 0.9)
(wowf 2) (wowa 0.1) (wowb 0.5) (wow 0))
(out.ar
out
(* (env-gen.ar (adsr 0.01 0.01 0.95 0.01 amp -0.5) :gate gate)
(hpf.ar (lpf.ar
(saw.ar (sc::+~ (sc::*~ wow (sin-osc.ar wowf 0
(sc::*~ freq wowa)
(sc::*~ freq wowb)))
freq))
freq)
(sc::*~ freq 2)))))
这样再加一个 wow 的控制就好了.
(oscdef :wow (wow)
(ctrl *tone* :wow wow))
效果如下:
大概就酱.