gombeのブログ

マイコンの電子工作系PIC32/KiCad/C/C++/3D/

久しぶりのオルゴールについて

今回は減衰について説明しましょうかね。

オルゴールでは大抵音が鳴り始めたら減衰します。この音の減衰にあたる部分まで演算して求めようという考え方です。

人間の聴覚では音の大きさはdBで表されることが多いですね。音が相対的に大きさが触れられるのもかなり大きいです。そこで実際に操作するときはexp(指数関数)に通してから減衰させることも多いです。これは感覚的なものですがね。

最初に音がで始めるときは大きな音が出ることが多いです。そこからある一点に落ち着いてからゆっくりと減衰する。これを電子的にも再現することが今回の目的であります。

またいきなり音を出して減衰して消えるためにぷつっと消すと「ぷつっ」て鳴ります。なので鳴り始めと終わりは0にして始めの時はそこから急速に振幅をあげて鳴り終わりには余韻をもたせます。この振幅を音に乗算して音の完成です。

img_2531

音の減衰にはかなりの計算量があります。(比較回数等も)なので実際に再生するときには計算を毎回やるとかなりの負荷になります。なので実際はある間隔nだけ開けて計算します。

img_2530

計算をスキップする際に問題になる点は出力がよりギザギザになることです。(黄色ライン)この点については間を一次補完させてカバーする方法(ピンクライン)がありますのでそれを使います。たいていの場合この補完の負荷の方が毎度の計算よりも軽くなる場合の方が多いようです。これは比較回数が多いほど演算に時間がかかるためです。 テーブルの参照は減衰時には必要ですがそれを毎回参照する必要もありません。なので実際は一次補完は最終段階で用いるものとなります。 一次補完をかける際はデータの数を2nにしておきます。これは演算を論理演算に置き換えて高速化するためです。例えばデータの個数を4としておきましょう。

img_2580

位置ベクトルPについては以下の式で求められます P=(A+B3)/4 この式中で/演算は時間がかかるので簡略化するとします。するとデータの個数が2のn乗算の時のみシフト演算に置き換えられることがわかります。この場合は4なので22です。最終的には P=(A+B3)>>2 が求められます。 このように演算を簡略化する際には用いる演算に時間がかかるかどうかやそれは簡略化できるかどうかを考えて実装すべきです。