RSS Twitter Facebook

2012/10/02 (2012年10月 のアーカイブ)

ADSRの実装

ADSRと言えばシンセを扱う人なら誰でも知っている音の音量カーブを決めるパラメータですが...

Twitterの方でモハヨナオさんの発言「ADSRエンベロープの実装って真面目にやるとキーオフのタイミングをめぐってややこしくなるけど、キーオンとキーオフ、二つのエンベロープに分割するとすごく楽になる 」というのがあって、なんか面白かったので自分のコードを眺めなおしたりしてたのだけど、なんか毎回ちょっとずつ違う実装してたりしてまとまりがないのだ。

正直ADSRのカーブを見ながらソフトで実装しようとすると変に複雑になりがちなんで、モハヨナオさんのアイデアとはまた違うのですが、この際、自分なりのADSRの実装について考察してみます。
ハードウェアとして一般的な回路がどうなってるかは武田さんのページなんかからたどれば色々でてきます。
http://www.aleph.co.jp/~takeda/radio/hms6.html
http://www.uni-bonn.de/~uzs159/adsr2.png

単純に書くとこんな構造です。

基本的にはこれをシミュレートする方向で考えると、回路的にはタイマーIC(NE555)一個だけでできているのですね。つまりADSR内部で必要なのはTimerOnのフラグ1つあれば良くて、出力される電圧は結局の所、タイマーICに繋がっている1つのコンデンサに対する充放電のカーブになっています。

ダイオードで充放電の方向が決まるのですが、動作を言葉で説明するとこうなります。出力するレベルは 0.0-1.0 の範囲で、Key信号はオン=1.0、オフ=0.0です。

■TimerはKeyの立ち上がりでOnして出力が1.0になったらOff (途中でKeyが下がっても強制Off)
■Timer On期間はAttackレートでピークに向かって充電
■Timer Off期間は出力がSustain Levelより大きいければSustain Levelに向かってDecayレートで放電
■出力がKey Levelより高ければKey Levelに向かって放電
これだけです。これは言葉で書いたほうがすっきりしてプログラムに落とすのも簡単な気がしますね。

ちなみに「xxに向かって充電(放電)」て言うのは、一定の周期で
現在値=目標値 + (現在値 - 目標値)×係数
を繰り返して目標値に漸近するカーブになります。

で、まあ、実は音の性格を決める所でアタックのカーブの取り方が結構重要な気がします。「ピークに向かって充電」と書きましたけど、1.0に漸近する曲線ではいつまでたっても1.0にならないわけで、このピーク付近のカーブの違いでアタック部分の音の図太さが変わっちゃいます。もう1つパラメータを追加するならAHDSRの「Hold」に相当する部分ですね。


NE555の仕様に忠実に行くならば、タイマーのスレッショルドは電源の1/3の所ですので、正確には「3.0に向かって充電して1.0を超えたらリセット」電源の2/3の所ですので、正確には「1.5に向かって充電して1.0を超えたらリセット」って感じになります。他の方法としてはアタックは直線で上らせるというやりかたもありますね。これだとちょっとピークが細い感じになります。

Posted by g200kg : 2012/10/02 20:12:25