周期波形テーブルとシングルトン
はじめに
サイン波テーブルを作成して、シングルトンでそれを使い回します。
例によって素人調べなので、間違いがありましたらご指摘いただければ幸いです。
テーブルルックアップ [1, 2]
周期波形1周期分のデータを用意し、それを使いまわす方法です。ここでは、周期波形の簡単な例としてサイン波を考えてみます。
サイン波は、上記のような周期 の周期関数です。従って、下記も成立します。
上記の右辺のsin関数の位相は、 となります。すなわち、Sin関数への入力位相 は、結局のところ の範囲に落とし込めることがわかります。
このことから、 のサイン波1周期分の波形メモリーをあらかじめ用意しておけば、入力位相を の範囲に落とし込み波形メモリーを参照することで、任意の入力位相に対するサイン関数出力を取り出すことができます。
続いて、サイン波1周期分の波形メモリーをどうやって作成するかを考えてみます。
コンピュータ上では、離散データしか扱えないので、連続した波形メモリーを用意することはできません。従って、サイン波1周期をN点でサンプリングすることで、波形メモリー数列 を作成します。
ここで、 は単位インパルス数列を表します。また、を今後、波形メモリーのアドレスと呼ぶことにします。
では、続いて任意の入力位相 から参照すべき波形メモリーのアドレスを算出する方法を考えていきます。
これは、先の入力位相を の範囲に落とし込んだやり方そのままになります。ただし、 を の範囲にスケール変換する必要があります。それを踏まえると、任意の入力位相 に対応するアドレス は下記のようにして計算できます。
これで、入力位相 をアドレス に変換できました。ところで、波形メモリーは離散データなので、アドレスが整数値の部分にしかデータが存在しません。しかしながら、先に計算した は、整数値以外の値もとりえます。
従って、 が小数値になった場合、そのアドレスに対応するデータは、前後の整数値アドレスのデータを用いて補完する必要があります。この補完方法には、様々なやり方がありますが、今回は前後1点ずつのデータを用いて行う線形補完 [2]で対処します。この線形補完を行うことで、テーブルルックアップの完成です。
実際にこのテーブルルックアップを使って波形を生成してみます。C++でコーディングしてみたものが以下になります。
以下は、生成波形をグラフ化してみたものですが、大丈夫そうですね。
波形テーブルをSingletonにする [3]
シンセサイザーの場合、サイン波のような基本波形は、メインのOSCやLFOといった様々な部分で必要になるかと思います。各モジュール毎に同じ波形テーブルのコピーを持たせてもしょうがないので、1つのSine波形テーブルをプログラム中のどこからでも、参照できるようにしてみます。
先のコードをベースにSineTableをSingleton化してみると以下のようになるでしょうか(デザインパターンは成書できちんと学んだわけでは無いので、怪しいかも...C++ベースで書かれたおすすめのデザインパターン入門書の情報ください)。
上記のようなごくごく小規模なサンプルプログラムだと、特に益が無いですね…。今回は、サイン波を例に行いましたが、バンドリミットしたノコギリ波テーブルを用いた基本波形OSCとか、もうちょっと実用的な部分もその内まとめておきたいですね。
参考文献
- Joe Wright. "Synthesising band limited waveforms using wavetables". Musicdsp.org.
http://www.musicdsp.org/files/bandlimited.pdf, (accessed 2017-07-16).
- 青木直史. C言語ではじめる音のプログラミング―サウンドエフェクトの信号処理. オーム社, 2008.
- _narumi. "ゲームプログラマのためのデザインパターン(シングルトン)". Qiita.
http://qiita.com/narumi_/items/b205e59e7fc81695f380, (参照 2017-07-16).