Processing math: 100%

テキトーなノイズ生成

ソフトシンセのプログラミングにおける、ノイズ(≒疑似乱数)を作る話。

(不真面目なネタ)

ノイズを出すだけなら、例えば -1, +1 の2値でもいいのですが、ここでは32bit整数の疑似乱数を作って適当に変換することを前提にしています。


用途が用途なので、メルセンヌ・ツイスターとかを持ち出す必要はないはず。できるだけ(CPUだけでなくメモリ消費も)軽い方がいい。

よく使われる(使われた)のは、線形帰還シフトレジスタ (linear-feedback shift register, LFSR) だと思う……けれど、今回は使わない。

「簡単な疑似乱数生成」の代表格の線形合同法 (linear congruential generator, LCG) は、前回の値 x_n から下のような式で次々に新しい値 x_{n+1} を求める。

x_{n+1} = (ax_n + c)\mod m

それで、この式には乗算 (ax_n) と剰余 (mod) 演算があるので、シフトとXORだけで済むLFSRより遅いというのが一般的な話。

ここで、m は周期に関わるのでできるだけ大きく、加算すらケチるために c=0a を(さすがに0, 1, 2ではダメなので)3 にしてやると、

x_{n+1} = 3x_n\mod 2^{32}

初期値1とかで、奇数しか出てこないけれど、2^{30} 周期の疑似乱数のような何かが出来上がる。で、mod 2^{32} は32bit整数のオーバーフローを無視するだけなので演算不要。つまり、前回の値を3倍にするだけ。掛け算が遅いなら (x << 1) + x みたいにすればシフト1回・加算1回で済む。LFSRより軽いのでは!

もうちょい何とかするなら、

x_{n+1} = (5x_n + 1)\mod 2^{32}

とでもすれば、インクリメント1回分の犠牲で 2^{32} 通りの数値が全部出てくる。

で、これらを *.wav に吐き出して鳴らしてみたところ、3x_n のやつでもホワイトノイズとして違和感はない感じ(私の耳が悪いだけの可能性はある)。周波数スペクトルを見ると微妙に右肩下がりにも見えるけれど、太いノイズと言い張ればアリでしょう。

結論:現代の計算機環境において、そんなところをケチる必要はない。

まあ、今ならXorshiftとかがいいんじゃないですかね。