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

すこしふしぎ.

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

【python】ディレイとリバーブ【サウンドプログラミング】

python SoundProcessing

こんにちは,1000chです. 巷ではiOS8が発表されたようで.iOS7が出たのついこの前のような気がするんですが.早いですね.

んでswiftという新言語を知ったのでぱらぱらとドキュメントみてたらこんなのが.

f:id:ism1000ch:20140603130419p:plain

何でもアリですね..絵文字使えるってなんなんでしょう. ぱっと見,見た目はjsに,機能はpythonに近くなったような気がします(素人見解). もう少し調べたらブログでまとめようかな.

さてそれは置いといて,今日はいよいよpythonつかってエフェクター作っていこうと思います.

サウンドエフェクト

いままで見て来たように,音は基本的に時間軸上の1次元データです. この波形データを入力として,新しい波形データを作る関数のようなものをフィルタといいます*1エフェクターは,フィルタ単体,あるいは組み合わせでできています. 組み合わせ次第で,高周波成分を取り除くとか,振幅を増減させるとか,ディレイをかけるとか,様々なエフェクトをかけられるようになります.

そしてサウンドエフェクトは,これらの組み合わせで表現することができます. 例えばギターだとこんな感じ(写真はこちらより).

f:id:ism1000ch:20140603132442j:plain

この例だと,ギターの音はまずオレンジのエフェクタ(ディストーション)で歪まされ,グレーのエフェクタ(コーラス)でエコーがかかり,最後にアンプを経て音として再現されます. エフェクトを追加したければ,適宜エフェクターを間に挟むだけでできてしまいます.

ようするに,「入力信号 x(n)」を受け取って適切な「出力信号 y(n)」を計算する関数y=f(x)を作れば,エフェクターのシミュレーションができるということになります. ブロック図を考えると,こんな感じです.

f:id:ism1000ch:20140603163047j:plain

ここで,x(n)が入力,y(n)が出力,+は加算器,b(k)は乗算器,z^-1は遅延器です*2. 以上を式で書くとこんな感じになります.

f:id:ism1000ch:20140603163234j:plain

出力y(n)は,入力x(n)と各ゲインb(k)の積の総和で表すことができる,ということです. すなわち,フィルタを設計するということは,適切なゲインb(k)を決定することに他なりません.

ディレイ:時間遅れエフェクト

というわけで,いろいろとエフェクター作ってみましょう.

ディレイは,オリジナルの音を遅れさせて加算するエフェクターです. イメージとしては,やまびこを想像してください. 叫ぶ声が入力x(n),山で反射されたりして実際に聞こえる音がy(n)になります.

ディレイエフェクトにおけるゲイン定義式は,次のようになります.

f:id:ism1000ch:20140603163630j:plain

ここで,frameはディレイさせるフレーム数を,repeatは繰り返させる回数を,ampは入力値に対する割合(0.0~1.0)をあらわします. 例えばサンプリングレートfs=44100[hz],frame=10000[frame],repeat=3[times]のときは, 0.227秒のディレイ(= 10000 / 44100)が3回分加えられる,ということになります.

では,以上をコードにしてみましょう.

import numpy as np

def delay(data,frame=44100,amp=0.5,repeat=5):
    out = []
    amp_list = [amp ** i for i in range(repeat+1)]

    for i in range(len(data)):
        # y(i)を適宜計算
        d = 0
        for j in range(repeat + 1):
            index = i - frame * j # delay元となるindexを計算
            if index >= 0:
                d += data[index] * amp_list[j]
                d *= 0.7 # 加算しているので適宜クリッピング
        out.append(d) # y(i)をlistに格納

    return np.array(out) # y(n)をnumpy.ndarrayに変換して返す

こちらの音声を対象として実行してみましょう.

入力音声

出力音声

いい感じにディレイしてますね.やまびこっぽい.

リバーブ

リバーブは,残響をシミュレートするエフェクトです. ホールやお風呂場などで歌が上手く聞こえるアレです.

本来は空間の伝達関数をきちんと計算してシミュレートする必要がありますが,とりあえずシンプルに使ってみましょう. 簡単に作る分には,なんとディレイのパラメータをいじるだけでできてしまいます.

ということで,frame = 5000, amp = 0.5, repeat=10で実行してみました. 単音だとわかりづらいので.声を録りましたw

入力音声

出力音声

いい感じ?に残響してる感じしますねー.

とこのように,同じようなプログラムでもパラメータを変えるだけでいろいろなエフェクトを楽しむコトができます. エフェクタをモジュールとして作っておけば,いろいろ組み合わせて遊べそうです.

まとめ

  • エフェクタの考え方
  • ディレイつくった
  • リバーブつくった

参考資料はこちら.

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

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

*1:いわゆる伝達関数

*2:詳しくは「伝達関数,ブロック線図」等でググってください