MMLを解釈して再生するロジック

DXRubyのSoundEffectを利用して、ファミコンの音楽を作れるかしらん。
と思って、いろいろと考えている。
はてなMML記法を使えば既にそんなことできるわけだが、自分で作るというプロセスが目的であって、それで何かを再生することにはそんなに興味は無い。
俗に言う「手段と目的を履き違えている」人である。
趣味ってのは、世の中に貢献したり、生産的である必要などないと考えている。
そうだったらいいな、とは思うが。
でもそのために頑張りすぎて疲れちゃったりするなら、むしろそっちのほうが「手段と目的を履き違えている」といえるのではなかろうか。


さて、DXRubyのSoundEffect機能で音楽を再生するには、シンプルに設計するなら、MMLを順番に解釈して、いまの文字の再生時間が終わるまで、そのデータを出し続ける、という感じになる。
PSGなら周波数データは、エフェクトさえかけなければ同じものを出すことになるが、ボリュームは通常、アタックやらディケイやらリリースやらを設定して変動させるから、時間の経過とともに計算していかないといけない。
このあたりが、ハードウェアのチップを叩いて再生するドライバとの大きな違いで、そういうものならまだ簡単なのだが、文字列の解釈とデータの生成を同時にやるとややこしいことになってしまう。
設計は簡単でもプログラムが大変だ。
リアルタイム再生でもないんだし、MMLを解釈して、例えば音の起動時間と周波数とボリューム変化パターンを持つ配列をバッファ配列にpushしまくるとかしといて、SoundEffect.newに渡すブロック内では、カウンタを見つつ配列からデータを取り出して、その通りにデータを吐き出す、みたいな感じにすれば、中間データが必要になるから設計はややこしくなるがプログラムは簡単になる。


MMLから波形を生成することで厄介なのは実はその辺じゃなくて、いま悩んでるのはテンポの作り方だ。
T150ってしたら、1分間に4分音符が150回のスピードだったっけ。
分解能を1/1000秒にしてるから、1分で60000、そいつを150で割ると400ということで、4分音符は400カウント保持すれば作ることができる。
この数はキッカリのように見えるが、例えば3連符を再生しようとすると誤差が出る。
波形レベルで音を生成するなんていままでやったことがないから、どのぐらいの精度で作ればいいのか、どのように計算すればいいのか、さっぱりわからない。
デフォルトは1/1000秒だが、1サンプル単位までいけるから、1/44100秒単位で設定することができるのだが、結局どこまで細かくしてみても誤差があるわけで。
ブレゼンハムみたいな方式で誤差を吸収するか、浮動小数点を使うか、それとも他にうまい方法があるのか。
いい感じで再生できるようになったら大喜びで公開するんだろうけど、このぶんだとまだしばらくかかりそうだなー