コンプレッサーの実装例
コンプレッサーとは入力音声の音圧に応じて音量を調整するエフェクターです。
パラメーターとして下記がよく利用されます。
パラメーター | 意味 | だいたいの範囲 |
---|---|---|
スレッショルド | 圧縮が始まる音圧 | 0.1~1.0程度(dBで計算する場合もある) |
レシオ | 圧縮する割合 | 2.0~10.0程度(例えば2.0の場合、圧縮比率2:1でスレッショルドを超えた分が1/2になる。)/td> |
音量 | 最終的な音量 | 1.0~3.0倍程度(dBで計算する場合もある) |
実装では下記のような処理を行います。
- 入力信号に応じた音圧を検知。
- 検知した音圧に応じて音量(ゲイン)を計算。
- 入力信号に計算した音量(ゲイン)を
音圧を検知は「入力信号の絶対値をとったものにローパスフィルタを通す」ことでできます。
(他の方法もありますが、ここではこの方法を利用しています。)
フィルタは「簡単なデジタルフィルタのサンプルコード」を使用しています。
あくまで実装例ですのでいい音質のものがほしい場合は、ご自身で試行錯誤いただくようお願いします。
【実装イメージ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
void Compressor(float inL[], float inR[], float outL[], float outR[], int wavelength) { // inL[]、inR[]、outL[]、outR[]はそれぞれ入力信号と出力信号のバッファ(左右) // wavelenghtはバッファのサイズ、サンプリング周波数は44100Hzとする // エフェクターのパラメーター static float threshold = 0.3; // 圧縮が始まる音圧。0.1~1.0程度 static float ratio = 2.0f; // 圧縮する割合。2.0~10.0程度 static float volume = 2.0f; // 最終的な音量。1.0~3.0程度 // 内部変数 // フィルタークラス(https://www.utsbox.com/?page_id=728 より) static CMyFilter envfilterL, envfilterR; // 音圧を検知するために使うローパスフィルタ static CMyFilter gainfilterL, gainfilterR; // 急激な音量変化を避けるためのローパスフィルタ // ローパスフィルターを設定 // カットオフ周波数が高いほど音圧変化に敏感になる。目安は10~50Hz程度 envfilterL.LowPass(30.0f, 1.0); envfilterR.LowPass(30.0f, 1.0); // カットオフ周波数が高いほど急激な音量変化になる。目安は5~50Hz程度 gainfilterL.LowPass(5.0f, 1.0); gainfilterR.LowPass(5.0f, 1.0); // 入力信号にエフェクトをかける for (int i = 0; i < wavelength; i++) { // 入力信号の絶対値をとったものをローパスフィルタにかけて音圧を検知する float tmpL = envfilterL.Process(abs(inL[i])); float tmpR = envfilterR.Process(abs(inR[i])); // 音圧をもとに音量(ゲイン)を調整(左) float gainL = 1.0f; if (tmpL > threshold) { // スレッショルドを超えたので音量(ゲイン)を調節(圧縮) gainL = threshold + (tmpL - threshold) / ratio; } // 音量(ゲイン)が急激に変化しないようローパスフィルタを通す gainL = gainfilterL.Process(gainL); // 左と同様に右も音圧をもとに音量(ゲイン)を調整 float gainR = 1.0f; if (tmpR > threshold) { gainR = threshold + (tmpR - threshold) / ratio; } gainR = gainfilterR.Process(gainL); // 入力信号に音量(ゲイン)をかけ、さらに最終的な音量を調整し出力する outL[i] = volume * gainL * inL[i]; outR[i] = volume * gainR * inR[i]; } |
上記はあくまで実装例です。
今回は急激に音量(ゲイン)が変化しないようにローパスフィルタを使用していますが、アタックやリリースを持ったエンベロープを使用することもあります。
また、音圧検知にRMS(二乗平均平方根)を使用することもあります。
質問はコメント欄や掲示板、Twitterでいただけばとおもいます。
他のエフェクター実装例はこちらにもあります。 → エフェクターの簡単な実装例
■掲示板
■Twitterアカウント:@vstcpp URL:https://twitter.com/vstcpp