ディストーション
Pythonで音声信号処理(2011/05/14)
今回は、ディストーション(distortion)というサウンドエフェクトを試してみます。ディストーションは、音を極端に増幅し、わざとクリッピングを発生させることで、歪んだ(ひずんだ)音色を作る技術とのこと。普通の音にこのエフェクトをかけるとエレキギター風の音になるらしい。
音の波形データは、音声の量子化ビット数が16bitの場合は、波形は-32768から32767の値(正規化した場合は-1.0から1.0)しか取れません。波形が範囲外になるように増幅し、飛び出た部分をすぱっと切る(ハードクリッピング)とディストーションになるとのこと。サイン波にディストーションをかけると下みたいに上の部分が切れて四角波っぽくなります。上がオリジナルのサイン波(440Hzと880Hzの合成波形)で下がディストーションをかけた波です。
音声も作ってみました。上がオリジナルのサイン波で下がディストーションをかけたサイン波です。
Pythonで実装したディストーションのプログラムです。
#coding:utf-8 import wave import pyaudio import struct from pylab import * def play(data, fs, bit): p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=1, rate=int(fs), output=True) # 再生 chunk = 1024 sp = 0 buffer = data[sp:sp+chunk] while stream.is_active(): stream.write(buffer) sp += chunk buffer = data[sp:sp+chunk] if buffer == '': stream.stop_stream() stream.close() p.terminate() def distortion(data, gain, level): length = len(data) newdata = [0.0] * length for n in range(length): newdata[n] = data[n] * gain # 増幅 # クリッピング if newdata[n] > 1.0: newdata[n] = 1.0 elif newdata[n] < -1.0: newdata[n] = -1.0 # 音量を調整 newdata[n] *= level return newdata def save(data, fs, bit, filename): """波形データをWAVEファイルへ出力""" wf = wave.open(filename, "w") wf.setnchannels(1) wf.setsampwidth(bit / 8) wf.setframerate(fs) wf.writeframes(data) wf.close() if __name__ == "__main__": # 音声をロード wf = wave.open("data/sine.wav") fs = wf.getframerate() length = wf.getnframes() data = wf.readframes(length) # デフォルトの音声を再生、ファイルにも保存 play(data, fs, 16) save(data, fs, 16, "original.wav") # エフェクトをかけやすいようにバイナリデータを[-1, +1]に正規化 data = frombuffer(data, dtype="int16") / 32768.0 # オリジナル波形の一部をプロット subplot(211) plot(data[0:200]) xlabel("time [sample]") ylabel("amplitude") ylim([-1.0, 1.0]) # ここでサウンドエフェクト newdata = distortion(data, 200, 0.3) # サウンドエフェクトをかけた波形の一部をプロット subplot(212) plot(newdata[0:200]) xlabel("time [sample]") ylabel("amplitude") ylim([-1.0, 1.0]) # 正規化前のバイナリデータに戻す newdata = [int(x * 32767.0) for x in newdata] newdata = struct.pack("h" * len(newdata), *newdata) # サウンドエフェクトをかけた音声を再生 play(newdata, fs, 16) save(newdata, fs, 16, "distortion.wav") show()
音の波をgain倍して [-1.0, 1.0] を超えた場合は、最大値の-1または+1にしてクリッピングしています。このままだと非常に大きな音になってしまうためlevelをかけて音量を下げています。ちなみに波形の上限・下限を飛びぬけてしまうことを業界用語で「サチる」と呼ぶようです。初めて聞いたときはどこかの方言かと思ってましたが、Saturation(飽和する)の略語とのこと。
波形をクリッピングすると本来の音に含まれていない周波数成分が発生します。元のサイン波とディストーションをかけたサイン波でFFTを用いて周波数成分を比べてみました。
左がオリジナルの音声、右がディストーションをかけた音声のFFT結果です。ディストーションをかけると、倍音成分が発生することが確認できました。そういえば、ディストーションの結果と波形が似ている四角波にも倍音がありましたね(2011/6/11)。このようにオリジナルの音になかった周波数成分を発生させる処理を非線形処理と呼ぶとのこと。
サイン波だけではつまらないので単音のメロディにかけてみます。「ディストーション、オーヴァードライヴ攻略」から音声をお借りしました。このサイトには、ディストーションをかけた音声もあるので聴き比べてみます。できた波形は下のようになります。
音声も作ってみました。上がオリジナルのメロディで下がディストーションをかけたメロディです。
おぉ、確かにエレキギターっぽい!でも上のアルゴリズムでディストーションをかけると少しリバーブ(2011/6/19)がかかったように聞こえるのはなぜなんだろう?元サイトのディストーションとも効果が違うみたいだ。ディストーションにもいろいろあるのかな?
参考

C言語ではじめる音のプログラミング―サウンドエフェクトの信号処理
- 作者: 青木直史
- 出版社/メーカー: オーム社
- 発売日: 2008/12
- メディア: 単行本
- 購入: 19人 クリック: 235回
- この商品を含むブログ (24件) を見る