音を揃える(リミッタ、コンプレッサ)

Python

リミッタ、コンプレッサの原理

リミッタ」と「コンプレッサ」はいずれも音データの振幅が特定の範囲に収まるようにするための処理です。

リミッタ

リミッタは前回の記事で紹介したディストーションによるクリッピングとまったく同じです。

下図はリミッタをかける前後で振幅がどのように変化するかを表したものです。入力する音データの振幅が任意の実数「thr」を超えたときを境に、出力波形(Output)の振幅が一定になります。

  • \( Input Amplitude \):入力波形の振幅
  • \( Output Amplitude \):出力波形の振幅
  • \( thr \):任意の閾値

コンプレッサ

コンプレッサはリミッタと似ていますが、閾値を超えた振幅を一律に切り揃えるのではなく、決められた割合(レシオ:a)で圧縮します。
コンプレッサは振幅を小さくすることが本来の目的ですが、もともと混ざり合っていた振幅の小さい音を相対的に目立たせることもできます。

聴き比べてみる

今回は作曲ソフトで打ち込んで作成した音楽に処理を施します。
音源にはメロディ(琴)とコード(電子ピアノ)とリズム(ドラム)が混ぜられており、コードは少しボリュームを絞ってあります。

リミッタなし・コンプレッサなし

リミッタあり

コンプレッサあり

聴き比べてみるとリミッタをかけた音データはディストーションをかけたときのように音割れしてしまっています。
一方、コンプレッサをかけた音データには目立った音割れは少なく、分かりにくいですがボリュームを絞っていたはずのコード部分が少し強調されているように聴こえます。

Pythonによる実装

以下からリミッタとコンプレッサをPythonで実装

リミッタの実装

from scipy.io import wavfile
import numpy as np

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

THR = 0.03

# WAVファイルからデータを読み込む。
fs, data = wavfile.read(INPUT_FILENAME)
data = data / (2**15-1) # -1 ~ 1の範囲で正規化

# リミッタをかける
tmp_data = data[:, 0]
for i in range(len(tmp_data)):
    if tmp_data[i] > THR:
        tmp_data[i] = THR
    elif tmp_data[i] < -1 * THR:
        tmp_data[i] = -1 * THR

# WAVファイルにデータを書き込む。
tmp_data = tmp_data * (2**15-1) # 正規化した分を元のスケールに戻す
wavfile.write(OUTPUT_FILENAME, fs, tmp_data.astype(np.int16))

コンプレッサの実装

from scipy.io import wavfile
import numpy as np

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

THR = 0.03
a = 0.5 # レシオ

# WAVファイルからデータを読み込む。
fs, data = wavfile.read(INPUT_FILENAME)
data = data[:, 0] / (2**15-1) # -1 ~ 1の範囲で正規化

# コンプレッサをかける
tmp_data = data
for i in range(len(tmp_data)):
    if tmp_data[i] > THR:
        tmp_data[i] = THR*(1-a) + tmp_data[i]*a
    elif tmp_data[i] < -1 * THR:
        tmp_data[i] = -1*THR*(1-a) + tmp_data[i]*a

# WAVファイルにデータを書き込む。
tmp_data = tmp_data * (2**15-1) # 正規化した分を元のスケールに戻す
wavfile.write(OUTPUT_FILENAME, fs, tmp_data.astype(np.int16))

コメント