読者です 読者をやめる 読者になる 読者になる

すこしふしぎ.

VR/HI系院生による技術ブログ.まったりいきましょ.(友人ズとブログリレー中.さぼったら焼肉おごらなきゃいけない)

【python】歪み系エフェクト・ディストーション【サウンドプログラミング】

python SoundProcessing

こんにちは.1000chです. 前回はpythonでディレイ,リバーブエフェクトを作りました. 今回は引き続き,歪み系のエフェクトを作ってみようと思います. ギター,エフェクターググるディストーションとかオーバードライブとかファズとかいろいろあるみたいです. 自分は特に楽器に詳しい訳では無いのでなんちゃってサウンドになるとは思いますが,まぁやってみましょう.

歪みエフェクト

まず,ディストーションにより音がどう変わるかを聞いてみましょう(参考はこちら).

クリーンサウンド

ディストーションサウンド

いかにもギターっぽくてかっこいいですね!(小並感)

では,歪みエフェクトの原理を考えていきます.

歪み系のエフェクトは,その名の通り波形を歪ませるエフェクトです. 通常,振幅を増幅した時,1.0(または-1.0)を超すと,その値はオーバーフローして音割れの原因となります. そこである閾値を超えた場合はその値に固定するというような処理を行います. これをクリッピングと言います.

歪み系エフェクトは,あえてクリッピングを行うことで波形を歪ませ,信号に倍音成分を含ませる処理になります. イメージはこんな感じ(軸は適当です). 左側が普通のサイン波とその周波数表示,右側がクリッピング後波形とその周波数表示です. 右側は新しいピーク周波数が発生していることがわかりますね.

f:id:ism1000ch:20140610133300p:plain

波形の歪ませ方は大きく分けて2つあり,ハードクリッピングとソフトクリッピングに分かれます.

ハードクリッピングは閾値を超えた瞬間に指定値に固定し, ソフトクリッピングは次第にクリッピングが発生します. 実装としては,入力波形の各値に関して,クリッピングを行う関数を適用すれば良さそうです.

ハードクリッピング

f:id:ism1000ch:20140610144317j:plain

ソフトクリッピング(一例)

f:id:ism1000ch:20140610144322j:plain

つくってみた:ディストーション

というわけで,まずはハードクリッピングを実装してみます. 高周波の倍音成分が多く発生するため,硬めの音になります. エフェクター的に言うと,ディストーションが近いようです.

def distortion(data,amp = 5.0,level=0.7):
    out = []
    for d in data:
        d *= amp
        d = min(d,1.0)
        d = max(d,-1.0)
        out.append(d)
    return np.array(out) * level

# 再生部分,録音部分についてはコード略

出力結果

クリーンサウンド(再掲)

なんちゃってディストーション

なんかそれっぽいですね!

つくってみた:オーバードライブ

今度はソフトクリッピングを作ってみます. 高周波成分が減るため,すこし柔らかめの音になります. エフェクター的に言うと,オーバードライブが近いようです.

今回はソフトクリッピングの関数として,とりあえずarctanを使うことに. さらに正値と負値でゲイン量を変えた,非対称のソフトクリッピングにしてみます.

def overdrive(data, amp = 3.0, level = 0.5):
    out = []
    for d in data:
        d = np.arctan(d) / (np.pi / 2.0)
        if d > 0:
            res = self.amp * d
        else:
            res = self.amp * d * 0.3
        res = min(res, 1.0)
        res = max(res, -1.0)
        out.append(d)
    return np.array(out) * level

実行結果はこんな感じ.

なんちゃってオーバードライブ

先程よりは少しマイルド,,,なのかな?よくわからない(ぇ

感想と雑記

とりあえずクリーンサウンドからエフェクトかかった感じにはなりましたが,まだいまいち籠ったかんじがしたりでかっこ良くないですねー(´・ω・`) 参考サイトにあったディストーションサウンドと何が違うんだろう?

ということで波形を見てみます.

f:id:ism1000ch:20140610135338p:plain

上が参考サイトのオーバードライブ音源,下が今回つくったなんちゃってオーバードライブです. クリッピングの値が違うので上限が異なるのはともかくとしても,波形が全然違いますね.

周波数軸でも見てみましょう.

f:id:ism1000ch:20140610141128p:plain

上が参考サイト,下が今回つくったやつです. 参考サイトの音源の方が密度が高そうですね... 全体をそのままfftしてるからかも知れないけれど. スペクトログラムでみればまた違うかも? でも面倒くさいのでやらない

とにかく,シンプルにクリッピングするだけではおもちゃ程度のものしかできなさそう,問うことがわかりました. 実際にエフェクタの回路図みて,電圧特性を数式化した上でシミュレーションしないと,きちんとしたエフェクターを作るのはむずかしそうです.

こんなやつね(参考:エフェクター回路図集).

f:id:ism1000ch:20140610142021p:plain

そのうち勉強したいところである.

まとめ

  • 歪みエフェクトってなに
  • ディストーション(っぽいもの)つくった
  • オーバードライブ(っぽいもの)つくった
  • アナログ回路の読解力が求められている

参考資料

C言語ではじめる音のプログラミング―サウンドエフェクトの信号処理

C言語ではじめる音のプログラミング―サウンドエフェクトの信号処理

おまけ

numpyつかうのであれば,ufuncとか使うといいのかもしれない.よくわかんないけど. とりあえずnp.vectorize使ってこんな書き方もできた.

def clip(v,v_min=-0.5,v_max=0.5):
    v = max(v,v_min)
    v = min(v,v_max)
    return v

if __name__ == '__main__':
    n_sample = 40
    samples  = np.arange(0,n_sample,0.1)
    
    signal        = np.sin(samples)
    cliped_signal = np.vectorize(clip)(signal)

for文使うと遅くなるらしいので,こーゆー書き方もあるよというメモ.