音を響かせる(ディレイ、リバーブ)

Python

ディレイ、リバーブの原理

ディレイ」は同じ音が遅れて何度も聞こえるように音データに残響効果を加えるためのサウンドエフェクトの一つです。実は「リバーブ」も基本原理は同じであり、遅延間隔が短いものをリバーブ長いものをディレイと呼びます。

音データに残響効果を与えるためには「FIR(Finite Impulse Response)フィルタ」を適用する方法があります。FIRフィルタの定義式は以下です。

\( s_1(n) = \sum_{m=0}^J b(m)s_0(n-m) \)

  • \( s_1 \):フィルタ適用の音データ
  • \( s_0 \):フィルタ適用の音データ
  • \( b \):フィルタ係数
  • \( m \):フィルタ係数の長さ
  • \( n \):音データの長さ

フィルタ係数(b)に下図のような組み合わせで値を設定すると、次第に減衰する2回の残響効果を得られます。dは残響の遅延間隔を表しており、標本化周波数fsが16000Hzの音声に対して1秒間の遅延間隔で残響効果を加えたい場合、dは16000となります。

実際にディレイ、リバーブをかけてみた音声サンプルを比較しながら聴いてみてください。
※使用させていただいた音声はあみたろの声素材工房」様の声素材です。

ディレイなし・リバーブなし

ディレイあり

リバーブあり

あみたろの声素材工房 | ゲームや動画に!セリフ数日本一の無料声素材サイト
ゲームや動画に!セリフ数日本一の無料声素材サイト

どなたでも無料で使用できる音声素材を配布しているサイトです。音声合成素材やコーパスの作成もされている方なので、クリエイターの方だけでなく音声解析を始めようとされている方にも必見です。(詳細な利用規約はReadmeまたはあみたろ様の公式HPを必ず参照してください。)

Python+Scipyによる実装

Scipyには信号処理をするために必要な関数やクラスが一通り揃っています。
中でも今回はsignalモジュールの「lfilter」関数を使用します。

lfilter関数は引数を2つとり、一つ目の「b」は前述でも触れたフィルタ係数に該当します。二つ目の「a」も同様にフィルタ係数に該当する値ではありますが、FIRフィルタとしてこのフィルタを使用する場合は固定値「1」を設定するものだと考えて良いです。詳細は本題から逸脱してしまうので、ここでは割愛します。

from scipy.io import wavfile
from scipy.signal import lfilter
import numpy as np

# wavファイルのパス
INPUT_FILENAME = "input.wav"
OUTPUT_FILENAME = "output.wav"

# WAVファイルからデータを読み込む。
fs, data = wavfile.read(INPUT_FILENAME)

# フィルタ設定
b = [1] + [0 for i in range(fs//6-1)] + [0.5] + [0 for i in range(fs//6-1)] + [0.3]
a = [1.]

# フィルタリング
data = lfilter(b, a, data)

# スケーリング
data /= np.max(np.abs(data))
data *= 2**15 - 1

# WAVファイルにデータを書き込む。
wavfile.write(OUTPUT_FILENAME, fs, data.astype(np.int16))

lfilter関数の詳細は仕様については公式のリファレンスページを参照しましょう!

コメント