Analog3 エンベロープジェネレータの試作開始

停滞しがちな VCA の製作と並行してエンベロープジェネレータの試作を開始しました。今回のものはエンベロープ生成はアナログ回路を使わず計算で行います。マイクロコントローラは前回と同じく CAN コントローラ内蔵の STM32C092KCT を使います。

マイクロコントローラによる計算でエンベロープジェネレータを実装することにはいくつか期待する利点があります。

  • CAN バスからゲート信号を拾うことができるのでゲート信号のためのパッチングをしなくても動く
  • ベロシティー対応にするが、アナログのゲート信号にベロシティー情報を乗せると精度が問題になるが CAN バスからゲート信号を拾えば精度が問題になることはない
  • 計算さえ間に合えばどんな曲線も生成できる。ADSR にこだわる必要もなくもっとステップ数を増やしたりもできる
  • パラメータをセーブ・ロードできる。これは Analog3 の重要な特徴

まずは Analog3 共通の CAN 周りの基本機能を実装しました。この部分はゆくゆく Github の analog3 プロジェクトに共用のコードとして置く予定です。次にエンベロープ生成アルゴリズムの実装です。初めは伝統的な ADSR でいくことにするので、立ち上がりや減衰カーブを作るため指数関数曲線を生成する必要があります。このマイクロコントローラは別に信号処理用というわけではないので、FPU などはついておらず、演算速度を稼ぐためには固定小数点演算で信号生成をしたいところです。固定小数点演算のやり方は忘れてしまったので過去の記事を読んで復習します。

曲線を求める計算は next = r * prev を繰り返すだけで良くて単純でした。問題は、ノブの位置から減衰率を計算する方法です。まずは愚直にノブの位置と上昇・減衰の時定数 τ の関係を指数関数にして、さらに時定数から減衰率 r を求めることにします。まず時定数の定義から減衰曲線は以下の通り

V(t) =V0et/τ

減衰率 r は、エンベロープの更新の時間差 Δt の間にどれぐらいの減衰するか決める値なので、

r = V0 e (t+Δt)/τ V0et/τ = eΔt/τ

時定数をノブの位置 k の指数関数とすると

τ = C e αk = e αkβ

これを減衰率を求める式に当てはめると

r = eΔt/τ = e Δt / e αkβ

複雑な計算式で演算量がかかりそうですが、実装が固まってくるまでこれを素直に計算することにします。時定数を求める式に現れる定数 αβ はエンベロープジェネレータが快適に使える範囲に決めないといけません。これは試行錯誤で決めるよりほかにありません。ノブの値は実際には ADC の結果を 16 ビット整数に読み込むので範囲は 0 から 65535 までです。gnuplot の力を借りて、α = 0.00015、β = 7.5 とすると、大まかに良い感じの時定数範囲が得られました。

gnuplot> plot [k=0:65535] exp(k * 0.00015 - 7.5)
Bash

ここからエンベロープの更新を 1ms おきとした場合の減衰率は

gnuplot> plot [r=0:65535] exp(-1.e-3/(exp(r * 0.000115 - 7.5)))
Bash

時定数が長くなるにつれ減衰率は 1.0 に近づくことが見て取れます。最初の版では、この計算式を使って減衰率を求めることにしました。ただ、更新周期を 1ms おきで計算した上の値では、時定数が最短時の減衰率は 0.2 を下回っていて、この値ではおそらく曲線が荒すぎるため、満足行く品質のエンベロープを生成するにはもっと速い更新周期が必要そうです。

(続く)

Comments

No comments yet. Why don’t you start the discussion?

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください