見出し画像

AudioKitのコンプレッサーが効かない/AudioKitのソースコードを読む

昨日AudioKitの基本的な利用方法について書いた。

もともとZoomで録画したYouTube用の対談動画の音量差を軽減すべく、コンプレッサーで音量差を整えたうえで全体的に音量を底上げするということをやりたかったわけだけど、AudioKitのCompressorがどうもおかしい。

本来はこのように効くはずが、

画像1

Cookbook(公式サンプル)のCompressorではスレッショルドを思いっきり下げても、マスターゲインを上げまくっても全然音が変わらない。

先日の記事のように自分でシンプルに実装しなおしても同様。他のエフェクトノードに差し替えるとちゃんと効くので実装が間違ってるわけではなさそう。

Compressorのソースコードを読んでみる

AudioKitのコンプレッサーを諦めて自前実装するよりはやっぱりAudioKitの方で何がおかしいのか突き止めたほうが早そうだしサステナブルだろうと思い、何がおかしいのか探るべくCompressor.swiftの中身を見てみた。

想像以上にシンプルでびっくりした。

結局、`Compressor`はただの`AVAudioUnitEffect`の`kAudioUnitSubType_DynamicsProcessor`ラッパーだった。

こんな感じでAVAudioUnitEffectを初期化して、

fileprivate let effectAU = AVAudioUnitEffect(
audioComponentDescription:
AudioComponentDescription(appleEffect: kAudioUnitSubType_DynamicsProcessor))

(`AVAudioUnitEffect(audioComponentDescription:)`や`AudioComponentDescription(appleEffect:)`といったイニシャライザはAudioKitで定義している簡易版)

こんな感じでパラメータを紐付けてるだけ

self.$threshold.associate(with: effectAU, index: 0)
self.$headRoom.associate(with: effectAU, index: 1)
self.$attackTime.associate(with: effectAU, index: 4)
self.$releaseTime.associate(with: effectAU, index: 5)
self.$masterGain.associate(with: effectAU, index: 6)

ちなみにこの`kAudioUnitSubType_DynamicsProcessor`な`AVAudioUnitEffect`のパラメータ一覧は、こんな感じで取得できる

print(effectAU.auAudioUnit.parameterTree!.allParameters)

出力結果:

[<AUParameter: 0x280c92d00, "0", "compression threshold", addr 0x0, val -35.000>, <AUParameter: 0x280c92d80, "1", "headroom", addr 0x1, val 30.000>, <AUParameter: 0x280c92e00, "2", "expansion ratio", addr 0x2, val 1.000>, <AUParameter: 0x280c92e80, "3", "expansion threshold", addr 0x3, val -100.000>, <AUParameter: 0x280c92f00, "4", "attack time", addr 0x4, val 0.030>, <AUParameter: 0x280c92f80, "5", "release time", addr 0x5, val 0.030>, <AUParameter: 0x280c93000, "6", "master gain", addr 0x6, val 0.000>]

AudioKitのCompressorでは、kAudioUnitSubType_DynamicsProcessorなAVAudioUnitEffectの全7つのパラメータのうち、0, 1, 4, 5, 6をラップして用いていることがわかる。

ちなみに上の出力では各パラメータのデフォルト値が出力されているが、それぞれのパラメータの最大/最小値は次のようにして調べられる。

let param = effectAU.auAudioUnit.parameterTree!.parameter(withAddress: index)!
print("min:\(param.minValue), max:\(param.maxValue)")

独自のAudioKitエフェクトノードを作成してみる

気になったのは、インデックス 2 の「レシオ」パラメータが使用されていない点。コンプレッサーにおいてレシオはどれぐらい圧縮するかを決める重要なパラメータのはず。

スレッショルドを超えた値をどれくらい潰す(落とす、圧縮する)かを決めるのがレシオ(Ratio)です。4:1など、比率で表します。上の図では設定したスレッショルドの値(最大音量の約半分くらい)近くまで圧縮しているので、約半分、2:1のレシオ値だと言えます。

https://guitarsele.com/article/feature/basic-knowledge-of-effector-dynamics/

"compression ratio"ではなく"expansion ratio"とのことで、潰す比率とはまた別物なのかもしれないが、デフォルト値が1というのが気になる。これが比率だとすると1ってのは「変えない」ということを意味しているのではないか?

そう思って、このレシオもパラメータとして操作できるように独自のAudioKitエフェクトノードクラスを作成してみた。

ここから先は

3,707字
文章やサンプルコードは多少荒削りかもしれませんが、ブログや書籍にはまだ書いていないことを日々大量に載せています。たったの400円で、すぐに購読解除してもその月は過去記事もさかのぼって読めるので、少しでも気になる内容がある方にはオトクかと思います。

技術的なメモやサンプルコード、思いついたアイデア、考えたこと、お金の話等々、頭をよぎった諸々を気軽に垂れ流しています。

最後まで読んでいただきありがとうございます!もし参考になる部分があれば、スキを押していただけると励みになります。 Twitterもフォローしていただけたら嬉しいです。 https://twitter.com/shu223/