***************************************************************************** The SPU of the PSX by Dodger of CREATURE http://www.in-brb.de/~creature/index.htm ***************************************************************************** (1) The Body - レジスタ (2) Let's play - ボイスのコントロール (3) Getting Tracks - 波形データのロード (より良い理解のために、我々のページにあるサンプルコードを見てください) ---------------------------------- (1)レジスタ ------------------ すべてのSPUのレジスタは長さ16ビットです。 -これらの2つは最も重要なもので、SPUを制御し、ステータスを読むために使用されます: sp0 : 0x1F801DAA (フラグ) sp1 : 0x1F801DAE (ステータス) (sp0はフラグレジスタのように働きます!) SPUリセット : *sp0 = 0x0 SPUをon : *sp0 |= 0x8000 演奏有効 : *sp0 |= 0x4000 DMAデータ転送有効 : *sp0 |= 0x0020 データ転送モード : CPUからSPU : *sp0 &= 0xFFDF (ビット4をクリア) SPUからCPU : *sp0 |= 0x0010 (ビット4をセット) リバーブon : *sp0 |= 0x80 -左右のチャンネルのための主音量レジスタ: spu_mvol_l : 0x1F801D80 spu_mvol_r : 0x1F801D82 To set the volume (0-127) : *spu_mvol_l = (vol_left << 7) + vol_left; -これらはボイスをon/offするのに使われます。 spu_keyON_1 : 0x1F801D88 spu_keyON_2 : 0x1F801D8A spu_keyOFF_1 : 0x1F801D8C spu_keyOFF_2 : 0x1F801D8E long voice_mask ; // voice_mask の最初の24ビットは SPU の24ボイスを表します。 // ビットnのセットは、ボイス番号nのステータスを変更します。 // the first 24 bits of voice_mask represent the 24 voices of the SPU . // bit no. n set means "change status of voice no. n" ボイスon : *spu_keyON_1 = voice_mask & 0xFFFF ; // first 16 voices *spu_keyON_2 = voice_mask >> 16 ; // last 8 voices SPUwait(); SPUwait(); SPUwait(); SPUwait(); ボイスoff : *spu_keyOFF_1 = voice_mask & 0xFFFF ; // first 16 voices *spu_keyOFF_2 = voice_mask >> 16 ; // last 8 voices SPUwait(); SPUwait(); SPUwait(); SPUwait(); 例のために、2章を見てください -波形データ読み込み/書き込み転送時にサウンドバッファのアドレスをストアします。 spu_sb_addr : 0x1F801DA6 3章を見てください -CDオーディオの主音量レジスタ : cd_mvol_l : 0x1F801DB0 cd_mvol_r : 0x1F801DB2 (CDオーディオの使い方は不明) -リバーブ深さレジスタ : reverb_depth_l : 0x1F801D84 reverb_depth_r : 0x1F801D86 リバーブ深さの設定 : *reverb_depth_l = ((depth<<7)+depth)<<1; (リバーブは完全にハックされていません) -ボイスのアドレス : voice_base : 0x1F801C00 2章を見てください -リバーブ設定領域 : 0x1F801DC0 - 0x1F801DFE (説明のように、リバーブは完全にハックされていません) -その他 (全て32ビット長): spu_delay : 0x1F801014 SPU DMAチャンネル (ロードデータに使われます) : spu_dma_1 : 0x1F8010C0 (メモリアドレス) spu_dma_2 : 0x1F8010C4 (サイズ) spu_dma_3 : 0x1F8010C8 (転送開始) DMA制御レジスタ (DMA経由のデータ転送を可能にするために使われます) : d_pcr : 0x1F8010F0 d_icr : 0x1F8010F4 3章を見てください ---------------------------------- (2) ボイスの制御 ------------------- 0x1F801C00 に「ボイス領域」があります。各ボイス毎に16バイトあります。 ボイスnのアドレスを計算するには : short *v_base = 16 * n + 0x1F801C00 ; (ここで"short"は2バイト長であることを忘れないでください) -ボイスデータの構造 : *(v_base + 0x0) : ボイスの左音量 *(v_base + 0x1) : ボイスの右音量 *(v_base + 0x2) : ピッチ *(v_base + 0x3) : ボイスで使われている波形データのサウンドバッファアドレス *(v_base + 0x4) : "attack rate" , "decay rate" and "sustain level" *(v_base + 0x5) : "sustain rate" , "release rate" *(v_base + 0x6) : 主音量(-決して触れる必要はない-) ボイスを最大にセットし始める時 *(v_base + 0x7) : リピートアドレス レート (詳細): *(v_base + 0x4) = (v->s_level & 0xF)|((v->dr & 0xF) << 4)|(v->ar << 8) ; *(v_base + 0x5) = (v->rr & 0x3F) | (v->sr << 6) ; -ボイス開始 (例): ボイス0,4,7,15,23をon : voice_mask = 0x00808091 ; // 2進で明白にすると : 0000 0000 1000 0000 1000 0000 1001 0001 *spu_keyON_1 = voice_mask & 0xFFFF ; // first 16 voices *spu_keyON_2 = voice_mask >> 16 ; // last 8 voices SPUwait(); SPUwait(); SPUwait(); SPUwait(); -ボイスストップ (例): 全ボイスのOFF : *spu_keyOFF_1 = 0xFFFF; *spu_keyOFF_2 = 0xFF; SPUwait(); SPUwait(); SPUwait(); SPUwait(); -SPU readyまで待つ ( SPUwait ): long c,v; // wait for some cycles for (c=0;c<0x60;c++) v = ( (v << 1)+v ) << 2 + v ; // *13 if (*sp1 & 0x7FF) // If SPU busy for (c=0;*sp1 & 0x7FF;c++) // wait . if (c>3841) // Thats too long { _printf ("SPU fucked up .. wait (reset)\n");exit;} ---------------------------------- (3) 波形データのロード : ------------------------ -> 512KBのサウンドバッファがSPUによって制御されます -> For Transfer-Wait-Code look at the sample file "si.c" (私たちのページの("spucode.zip")にあります) a) SPU DMAをonにする : *d_pcr |= 0xB0000 ; b) サウンドバッファ内のアドレスの宣言 : *spu_sb_addr = sb_addr >> 3 ; // address in SB to load from / write to c) モードの宣言 : CPUからSPU : *sp0 = *sp0 & 0xFFCF | 0x20 ; SPUからCPU : *sp0 = *sp0 & 0xFFCF | 0x30 ; CPUからSPU : *spu_delay = *spu_delay & 0xF0FFFFFF 0x20000000 ; SPUからCPU : *spu_delay = *spu_delay & 0xF0FFFFFF 0x22000000 ; d) DMAチャンネルの初期化と転送開始 : *spu_dma_1 = addr ; // 読み書きするメインメモリのアドレス if (size & 0x3F > 0) {i=1;}else{i=0;} *spu_dma_2 = (size>>6 + i)<<16 | 0x10; 転送開始 : CPUからSPU : *spu_dma_3 = 0x01000201 ; SPUからCPU : *spu_dma_3 = 0x01000200 ; e) 転送終了まで待つ : while (*spu_dma_3 & 0x01000000) {}; !- (知らない人たちのために。CPUはメインメモリを制御し、SPUはサウンドバッファ を制御するので、"CPUからSPU"は、メインメモリからサウンドバッファへの転送 を意味します。)