任天堂純正?サウンドドライバはシーケンスデータを同時に二つ以上(4つ まで?)再生することが出来、MOTHER3はそれを利用して様々な演出を作って いるな。 戦闘BGMに鼓動を重ね、更にジングルが重なり、効果音もシーケンスデータ で再生して……とか。二つのBGMを同時に鳴らしたりする豪快さもあったり。 拙作ドライバもほんの数行を書き直すだけで複数シーケンス同時再生に対応 できるので後で対応しておくか。(なぜ今すぐやらないのか)
いやなブログ: checkstack.pl で関数のスタック消費量を調べる 試しに使ってみたら_vfprintf_rくらいしか引っかからなかったので、少し パターンを書き換えて、ついでにSTMも引っかけるようにしてみた。 checkstack.agb.pl 使い方: >arm-elf-objdump -d HOGE.elf | perl checkstack.agb.pl arm でまあ、こんな感じで出力される模様。二つ以上引っかかる場合は別個に表示される(赤字になってるところ)の で、見づらいなら連想配列に関数名を突っ込んでGO。俺は別に見づらくな い。見づらくないぞオオオ。0x030011a0 SpriteMoveWorld: STM:12 0x03001414 DMAChain_Enqueue: STM:12 0x03001460 DMAChain_Transfer: STM:20 0x03001504 DMAChain_Intr: STM:32 0x030015a4 DMAChain_TransferIntr: STM:28 0x03001654 PCG_SearchBlankCache: STM:44 0x03001674 PCG_SearchBlankCache: 4 0x030017c4 PCG_CleanCache: STM:20 0x030018cc PCG_Set: STM:36 0x030019ac PCG_Release: STM:16 0x03001b10 SFIXDIV: STM:8 0x03001bc0 ATAN2: STM:24 0x03001cac init_genrand: STM:8 0x03001d2c genrand: STM:20
俺は新約のサウンドアレンジに呆れてGBAを弄り始めたので、今度は聖剣DS に呆れてDSも始めなければならない予定だったんだけど、MOTHER3が予想外 にかなり頑張っているのに刺激されたので、まだまだGBAで頑張る予定。
やっぱ駄目だ。 色々と問題はあるんだけど、とりあえず、グローバル変数をewramセクション からsbssセクションに移しただけで挙動がおかしくなる原因を追ってる。取 り合えずobjdumpでアセンブリ吐かせて目で追ってる。コード上は問題ない。 いやもちろん問題はあって、俺が見逃してるだけに違いないんだけど。 つーか、もう、めんどいから、toolchain一式を、以前の、環境に、戻したよ。 さあ、まずはスプライトダブラの再コンパイルだ。あれれ? 環境を戻す前と挙動が変わらないよ? もう駄目だ。
gba_crt0.sを見る限りではゼロクリアされているはずなんだが、何故か起動 時に謎の値が代入されていておかしいのだが、そもそもゼロクリアされてい ることを期待するなという説もあるが、でもでも。だってだってなんだもん。
コンパイラを変えただけで0.5%ほど高速化しホクホク。つーか0.5%じゃ全然 嬉しくないよ。それどころかスプライトダブラがまともに動かなくなったり 色々と挙動が変わってしまって大変だ。つーか、自分で言うのもなんだけど コンパイラによって挙動が変わるって、だっせえなあ。死のうかな。
某所の日記に「bssがEWRAMに無い」と書かれていて(その記述はもう削除さ れてるのでリンク無し)気になったので調べてみたら、ちゃんとあるじゃな い。 と思ったらdevkitARMの拡張だった模様。DevkitAdvanceからの移行組は慣例にしたがって、 gba.h 辺りに以下の行を 追加すればいいやね。(初期値のある変数をEWRAMに置く事はまずないので、 IN_EWRAMをsbssにし、DATA_IN_EWRAMを設けた)devkitarm/arm-elf/gba_cart.ld: /* Additions by WinterMute */ /* v1.4 - .sbss section added for unitialised */ /* data in ewram */libgbaを使う場合は既に gba_base.h で以下のように定義されている。#define IN_EWRAM __attribute__ ((section (".sbss"))) #define DATA_IN_EWRAM __attribute__ ((section (".ewram"))) #define CODE_IN_EWRAM __attribute__ ((section (".ewram"), long_call)) #define CODE_IN_IWRAM __attribute__ ((section (".iwram"), long_call))libgbaは面倒見が良すぎ。#define IWRAM_CODE __attribute__((section(".iwram"), long_call)) #define EWRAM_CODE __attribute__((section(".ewram"), long_call)) #define IWRAM_DATA __attribute__((section(".iwram"))) #define EWRAM_DATA __attribute__((section(".ewram"))) #define EWRAM_BSS __attribute__((section(".sbss")))
PSGとPCMで同音階・同デューティ比の矩形波をユニゾンさせてやったところ 猛烈にデチューンコーラスが掛かっており、音の広がりを得ることが出来た。 …いや、それじゃ駄目なんだよ! この場合PSGとPCMどちらの音階テーブルがずれてるのか、判断しづらいので 困ってしまう。ひょっとしたらPCM サンプル自体がずれてる可能性もある。 完全に同じ音が鳴るようエミュレータ上でチューニングして、いざ実機に持っ ていったら、またデチューンコーラス…。やり直しかよ!かなり凹んだよ。
モニタを縦横に置き換えるのが面倒くさいので二台並べて切り替え機を経由 するようにしてみたらマジでボヤけて目が疲れるというか一日7時間くらい 平気で寝てしまうようになったのが俺。 解像度を下げて更にフォントサイズを2ポイントほど上げたらようやくマシ になったけど、何か間違ってるような気がしないでもない。
大仏噛めて、いや、大分掴めてきた。 GBでファミコン並のクオリティを出したければ、シーケンス側の調整にそれ なりの根気が必要だね。 VisualboyAdvance1.7.2におけるDMG音源のエミュレート精度はろくなもんじゃ ないということが判明したので、未だに1.7.2を使っている人がいたら今すぐ 1.8.0に乗り換えるべき。SG2のI/OレジスタへのBYTE書き込みが反映されなさ すぎる。 ソフトエンベロープの組めないDMGで、hvca(fca)やpogonsfなどのエミュレー タがNESのソフトエンベロープをどの様に再現しているか調べてみたら、再発 音で強引に処理しているようだった。そのおかげで、アタックなどの急速に 音量が変わる部分はとてもノイジーだ。これはもうどうしようもない。マジ で再現するならPCMで合成すればよいが明らかにCPUパワーが足りないよなあ。
処理負荷を少しでも軽減するために、サウンドドライバでDMG音源を扱える ようにしているところなのであった。今のところ、PCM1音辺り1.8%の負荷が 掛かっているので、DMGの3音で代用すれば5.4%の節約になるし。 でー、見事にハマってしまったんだけどー、DMG音源ってNESのようなソフト ウェアエンベロープは組めないんだな。ボリュームレジスタをいじれば反映 されると考えていたので、思ったように発音されず無駄に試行錯誤してしまっ たよ。どおりでのっぺりした曲のゲーム(代表例:ドラキュラ伝説)が氾濫 していたわけだ。 ハードウェアエンベロープでもADSRくらいは作れなくもないけど、音量が0 になると発音停止してしまうので、ベロシティとの兼ね合いが難しいなー。悩ましいな。ベロシティ12の場合 16 |/\ 12 | \ 8 | \_______ 4 | \ 0 +------------------------\----------------------- ベロシティ4の場合 16 | 12 | 8 |/\ 4 | \ ↓ここで発音停止してしまう 0 +------\-----------------------------------------
超連射の敵行動パターンを調べるためにショットを一切撃たずにプレイして いるのだがこれがなかなか難しい。1面はノーミス安定で越せるようになっ たが2面でどうしても詰まってしまった。 2面ヘリは画面に溜まりやすく、しかも折を見てこちらに突進してくるので 四方を囲まれたらどうしようもなくなってしまう。それでもなんとか越える と次は中ボスの大砲に上下から挟まれてやられてしまう……。 いや、待って!違うよ!行動パターンを調べるためにやってるのに、なんで 攻略パターンを作ってるんだよ!おかしいよ!本末転倒だよ!でも楽しけりゃ それでGO。
GBAのPCMは通常、VSYNC割り込みかTIMER割り込みでバッファを切り替えるが、 今日ワンダーウィッチ系のサイトを見て回っていたら、HSYNCもしくはVCOUNT 割り込みで切り替えるのはどうかなと一瞬思った。 VSYNCで切り替える場合、モノラル再生のとき最大で704バイトのバッファが 必要になるけど、HSYNC/VCOUNTなら大幅に減らせるし。 割とよさそうに思えたのだが、切り替えた後に音声を多重合成している時間 的余裕が無いので、やっぱり良くないや。ちぇー。
GBの波形メモリ音源(以降SG3)は4bit・32ステップ GBC で倍に拡張されて4bit・64ステップ これを64ステップとして使うか、32ステップ x 2バンクとして使うことが出 来る。つまりバンク切り替えをしまくれば 4bit PCM として扱うことが出来 るはず。 実際に鳴らすには、SG3の周波数と切り替えのためのタイマ割り込み周期が 重要となる。32ステップ全てを鳴らしきる前にバンクを切り替えてしまうと プチノイズが発生してしまうので。 あ、発音タイミングを調整して64ステップを前半後半に分けて書けば、別に バンク切り替えは必要ないか。音源側で勝手にループするし。バンク切り替 えというノイズ源が無くなる分、有利かもしれない? でも折角だからバンク切り替えの方向で考えてみたいじゃない。というわけ でSG3の、各周波数ごとの割り込みタイミングを計算してみる。左から順にREG_SG3CNT_Xに入れる値、周波数、サンプリングレート、分周比 1のときのタイマの値が出力される。(int で補正してるけど、実は補正を しなくてもタイマの値は整数になるんだな……) まだ妄想段階だし、DSOUNDで8bit PCMが使えるためあまり本気になって考え てないんだけど、ひょっとしたら続くかも。print "SG3,\tFREQ,\tRATE,\tTIMER\n"; for (my $sg3 = 0; $sg3 < 2048; $sg3++) { my $freq = 65536 / (2048 - $sg3); my $rate = int $freq * 32; my $timer = 65536 - int (16 * 1024 * 1024 / $freq); $freq = int $freq; if ($timer > 0) { print "$sg3,\t$freq,\t$rate,\t$timer\n"; } }