オーディオプログラミングをしていて、よくある矩形波の作り方は 1
と -1
を周期的に繰り返すというもの。
で、最近までなんの疑問も持たずにそれで実装していたんだけど、 FFT で周波数スペクトルを描いてみて気づいた。
なんか汚い。
いやいやまさかね、何かの間違いでしょと思ってよく耳を澄ますと、わずかに高音にブジジジィィィ...というノイズ混じりの音が聴こえる。気がする。耳より目を信じるミュージシャンなので、見た目がそうならきっとそう。 おかしいなと思って検索しまくったら、同じことを Stackoverflow で質問して自己解決している人がいて "Band-limited waveform" を使えば良さそうと書いてあった。
自分なりの解釈だと、真の矩形波はフーリエ級数展開すると無限の周波数までの足しあわせになるんだけど、実際のデジタル波形はナイキスト周波数(サンプリング周波数の半分)までしか出ないので、それを超えた分は低い周波数に折り返されてノイズになるということだと思う。たぶん。
というわけで、ナイキスト周波数を超えない範囲で正弦波を足しあわせて矩形波を再現することにする。具体的な方法は以下が参考になる。リアルタイムに計算するのはコストが馬鹿にならないので Wavetable をあらかじめ作っておく。
https://www.musicdsp.org/en/latest/Synthesis/17-bandlimited-waveform-generation.html
面倒なのが、周波数の上限が決まっているので低い音は倍音が沢山出せるが高い音だと少ない倍音で打ち切るしかない。なので、ノート毎に 128 個の配列を用意する(glide する時は線形補完)。 という感じで Wavetable を用意したら、40MB にもなってしまった。うーん。
ともあれ、結果こうなった。
正弦波を足しているのだからそれはそう、という感じ。でもちゃんと矩形波の音が聴こえるし、このスペクトルを見ながら聴くとよりクリーンに聴こえるぞ(いいのか)。ノコギリ波も同じ要領で出来た。
以下、課題。