音楽ファイル編集コマンド sox の compand オプションを調べてみた

#はじめに

録音レベルが低い多くの録音ファイルに、コンプレッサーを掛けたいと思い、sox コマンドを調べてみました。

[SoX - Sound eXchange, the Swiss Army knife of audio manipulation](http://sox.sourceforge.net/)

##マニュアルを確認
マニュアル [sox(1)](http://sox.sourceforge.net/sox.html) から compand の部分を引用します。（2014-12-17 版を意訳）

> compand attack1,decay1{,attack2,decay2}
> [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} 
> [gain [initial-volume-dB [delay]]]
> 
> オーディオのダイナミックレンジを compand (圧縮または伸張)します。
> 
> attack パラメータと decay パラメータ(単位:秒)は、入力信号の瞬間レベルを平均してその音量を決定する時間を決定します。attack は音量の増加を意味し、decay は減少を指します。ほとんどの場合、人間の耳は突然の小さくなる音楽よりも突然の大きくなる音楽に敏感なので、attack 時間(音量の増加に対する反応する時間)は decay 時間よりも短くなければなりません。複数の attack / decay パラメータが指定されている場合、各入力チャンネルは別々に圧縮され、ペアの数は入力チャンネルの数と一致する必要があります。典型的な値は 0.3,0.8 秒です。
> 
> 2番目のパラメータは、最大振幅に対する dB で指定された compand の変換関数の点のリストです。入力値は厳密に増加する順序でなければなりませんが、変換関数は単調に上昇する必要はありません。out-dB1 を省略した場合、out-dB1 の値は in-dB1 と同じ値になります。 in-dB1 以下のレベルは圧縮されません(ただし、gain が適用されている可能性はあります)。in-dB1,out-dB1 を 0,0 とすることが想定されますが、0,out-dBn によってオーバーライドされます可能性があります。リストの前に soft-knee-dB がある場合、変換関数上の隣接する線分が合う点は、与えられた量だけ丸められます。変換関数の典型的な値は、6:-70,-60,-20 です。
> 
> 3番目のパラメータ(オプション)は、変換関数のすべてのポイントに適用されるdB単位の追加ゲインであり、全体のゲインを簡単に調整できます。
> 
> 4番目のパラメータ(オプション)は、compand(圧縮または伸張)処理が開始されるときに、各チャネルで想定される初期レベルです。これにより、ユーザは通常のレベルを最初に与えることができます。例えば、compand 処理が始まる前に、非常に大きなゲインが初期信号レベルに適用されないようにすることができます。そのような場合、出力はコンパンダのゲインが適切に調整されている間はひどくクリップされます。典型的な値(最初は静かな音声)は -90 dB です。
> 
> 5番目のパラメータ(オプション)は、秒単位の遅延です。入力信号は、compand ルーチンがコントロールするためにすぐに分析されますが、ボリューム調整器に供給される前に遅延されます。attack/decay 時間にほぼ等しい遅延を指定することにより、compand ルーチンは、条件反射的ではなく「予測的」に効果的に動作することができます。典型的な値は、0.2 秒です。
> 
> 以下の例は、移動する車両のような騒がしい環境で聴くのに適する、静かなフレーズと大きなフレーズの両方をもった音楽を作成するために使われます。
> 
> `sox asz.wav asz-car.wav compand 0.3,1 6:-70,-60,-20 -5 -90 0.2`
> 
> 変換関数('6:-70, ...')は、非常にソフトな音(-70 dB 以下)は変わらないと言います。これにより、compand ルーチンは、動きの間など「無音」の音量を上げるのを止めます。ただし、-60dB から 0dBの範囲の音(最大音量)は、元の音楽の 60 dB のダイナミックレンジが 20 dB の範囲に 3:1 で圧縮されます。これは、音楽を楽しむのに十分な幅ですが、運転時の騒音を回避するには十分狭いです。'6:' は、6 dB の soft-knee compand 処理を選びます。-5 dB の gain は、クリッピング(数値は不正確であり、実験によって導出されました)を避けるために必要です。初期音量の -90 dB は、ほとんど無音で始まるクリップでうまく作用し、0.2 秒 の遅延は、compand ルーチンが突然の音量変化に対して少し早く影響する理由になります。
> 
> 次の例では、ノイズが信号よりも低いレベルにあるときに compand がノイズ・ゲートとして使用されています。
> 
> `play infile compand .1,.2 -inf,-50.1,-inf,-50,-50 0 -90 .1`
> 
> 別のノイズゲートがあります。今回は、ノイズが信号よりも高いレベルにあるときです(これはいくつかの点で、スケルチに似ています)。
> 
> `play infile compand .1,.1 -45.1,-45,-inf,0,-inf 45 -90 .1`
> 
> このエフェクトは、--plot グローバルオプション(変換関数用)をサポートします。
> 
> マルチバンド compand エフェクトについては、mcompand も参照してください。


ということです。

##変換関数を描画し確認

これだけでは、ちとわかりにくいので変換関数を描画してみました。適当な WAV ファイルを temp.wav として使っています。

### マニュアルのサンプル1

```shell-session
$ play --plot gnuplot test.wav compand 0.3,1 6:-70,-60,-20 -5 -90 0.2 > sample1.plt
$ (echo set terminal png ; echo set output \"sample1.png\"; cat sample1.plt) | gnuplot
```


![sample1.png](https://qiita-image-store.s3.amazonaws.com/0/126852/4ef28a92-aeba-b778-9ccc-84788743518d.png)
パラメーター: compand 0.3,1 6:-70,-60,-20 -5 -90 0.2

なるほど、膝とはこのカーブのことなのでしょう。
確かに膝っぽいです。けっこう圧縮してるように見えます。

### マニュアルのサンプル2

```shell-session
$ play --plot gnuplot test.wav compand .1,.2 -inf,-50.1,-inf,-50,-50 0 -90 .1 > sample2.plt
$ (echo set terminal png ; echo set output \"sample2.png\"; cat sample2.plt) | gnuplot
```

![sample2.png](https://qiita-image-store.s3.amazonaws.com/0/126852/a20a9de9-401b-958c-14a5-9ab5d629e6fe.png)
パラメーター: compand .1,.2 -inf,-50.1,-inf,-50,-50 0 -90 .1

うぉー、鋭い。壁です。見事な絶壁っぷり。とんがったノイズゲートです。

### マニュアルのサンプル3

```shell-session
$ play --plot gnuplot test.wav compand .1,.1 -45.1,-45,-inf,0,-inf 45 -90 .1 > sample3.plt
$ (echo set terminal png ; echo set output \"sample3.png\"; cat sample3.plt) | gnuplot
```

![sample3.png](https://qiita-image-store.s3.amazonaws.com/0/126852/b04d6be8-5533-0da7-3d76-7fa2271aa945.png)
パラメーター: compand .1,.1 -45.1,-45,-inf,0,-inf 45 -90 .1 

ノイズに埋もれた信号をピックアップするということですが、音楽用にはいにくそう。信号処理用でしょうか。

## 主要パラメーターの影響

今度は、主要パラメーターの影響を確認します。

### ノーマル

まずは、圧縮伸張なし。

![sample4.png](https://qiita-image-store.s3.amazonaws.com/0/126852/31bd6014-be04-1d19-d81c-fe55b90dbe06.png)
パラメーター: compand 0.1,0.1 0 0 -90 0.1

### 圧縮

-40dB を -20 dB に持ち上げるように圧縮。

![sample5.png](https://qiita-image-store.s3.amazonaws.com/0/126852/180806de-db84-751c-4e92-290ffc4c8499.png)
パラメーター: compand 0.1,0.1 -40,-20 0 -90 0.1

### 圧縮 + 増幅

-40dB を -20 dB に持ち上げて（圧縮）、全体を 10 dB 増幅する。

![sample6.png](https://qiita-image-store.s3.amazonaws.com/0/126852/85120089-788e-5d1b-9c76-dc7a2724b36f.png)
パラメーター: compand 0.1,0.1 -40,-20 10 -90 0.1

### soft-knee-dB パラメーター

soft-knee-dB パラメーターの確認。soft-knee-dB を 10 dB とし、設定有無を比較しました。

![sample7.png](https://qiita-image-store.s3.amazonaws.com/0/126852/15ab13cb-a9f3-4c8b-331d-929ea64dc789.png)
パラメーター: compand 0.1,0.1 -inf,-40.1,-inf,-40,-40 0 -90 0.1

![sample8.png](https://qiita-image-store.s3.amazonaws.com/0/126852/7a6d5be0-111a-09a9-0cde-00c2c02423f1.png)
パラメーター: compand 0.1,0.1 20:-inf,-40.1,-inf,-40,-40 0 -90 0.1

-40 dB を中心に、-50 dB から -30 dB がカーブしています。膝(knee)と例えるのは、音響業界の慣わしなのか気になりました。

### 使用例

Web カメラで録音した音源を聞きやすくするためのパラメーターです。Web カメラのオートゲインコントロールは OFF にしています。3メーター先の穏やかな話し声を、聞きやすくしました。

![sample9.png](https://qiita-image-store.s3.amazonaws.com/0/126852/911fe578-009b-8a1a-71a8-183507b6659c.png)
パラメーター: compand 0.001,2 5:-70,-50,-50,-18,-5 0 -90 0.1

##おわりに

sox コマンドの compand オプションは、plot オプションでビジュアル化すると理解しやすいようです。

当初は、楽器用コンプレッサーや audacity のような波形編集ソフトのように使えると思っており、閾値とレシオで設定しようと思いました。ところが、レシオに該当するパラメーターが無くセッティングに困っていました。私の印象では、compand オプションは変換関数（変換グラフ）を描画するための設計になっていると感じました。自由度が高いです。だから、名前が compress + expand = compand となったのでしょう。コンプレッサーにもなるエフェクトということです。

sox は、非常に高機能です。これからもお世話になると思います。ツールを開発しメンテナンスしている方々に感謝します。