DSPHLE: Decoded most of 0x21. Added real conclusions to the switch case to signal the CPU that the voice has been played. More work on 0x20/0x21/Raw (and probably the end of it) this weekend.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3683 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
XTra.KrazzY 2009-07-05 19:14:10 +00:00
parent 36883d6a48
commit e7ec7d56d5
5 changed files with 258 additions and 84 deletions

View file

@ -99,16 +99,7 @@ void CUCode_Zelda::Update(int cycles)
void CUCode_Zelda::HandleMail(u32 _uMail)
{
// WARN_LOG(DSPHLE, "Zelda uCode: Handle mail %08X", _uMail);
// When we used to lose sync, the last mails we get before the audio goes bye-bye
// 0
// 0x00000
// 0
// 0x10000
// 0
// 0x20000
// 0
// 0x30000
// And then silence... Looks like some reverse countdown :)
if (m_bSyncInProgress)
{
if (m_bSyncCmdPending)

View file

@ -221,6 +221,7 @@ private:
void RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size);
void RenderVoice_PCM16(ZeldaVoicePB& PB, s32* _Buffer, int _Size);
void RenderVoice_AFC(ZeldaVoicePB& PB, s32* _Buffer, int _Size);
void RenderVoice_Raw(ZeldaVoicePB& PB, s32* _Buffer, int _Size);
// Renders a voice and mixes it into LeftBuffer, RightBuffer
void RenderAddVoice(ZeldaVoicePB& PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size);

View file

@ -28,6 +28,8 @@ void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Siz
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);
s64 ratio = (_ratio * ratioFactor) * 16;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1;
@ -65,10 +67,12 @@ _lRestart:
}
}
for (; i < _Size;)
while(i < _Size)
{
s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000;
TrueSamplePosition += (ratio >> 16);
_Buffer[i++] = (s32)sample;
(*(u64*)&pos) += ratio;
@ -87,7 +91,7 @@ _lRestart:
else
PB.RemLength -= pos[1];
//PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
}

View file

@ -23,6 +23,8 @@
#include "../main.h"
#include "Mixer.h"
#include "../Config.h"
void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB)
{
u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr);
@ -157,18 +159,6 @@ void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
// WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0
// WARN_LOG(DSPHLE, "PB Unk07: %04x", PB.Unk07[0]); 0
WARN_LOG(DSPHLE, "PB Unk09: %04x", PB.volumeLeft1); // often same value as 0a
WARN_LOG(DSPHLE, "PB Unk0a: %04x", PB.volumeLeft2);
WARN_LOG(DSPHLE, "PB Unk0d: %04x", PB.volumeRight1); // often same value as 0e
WARN_LOG(DSPHLE, "PB Unk0e: %04x", PB.volumeRight2);
WARN_LOG(DSPHLE, "PB UnkVol11: %04x", PB.volumeUnknown1_1);
WARN_LOG(DSPHLE, "PB UnkVol12: %04x", PB.volumeUnknown1_2);
WARN_LOG(DSPHLE, "PB UnkVol21: %04x", PB.volumeUnknown2_1);
WARN_LOG(DSPHLE, "PB UnkVol22: %04x", PB.volumeUnknown2_2);
/// WARN_LOG(DSPHLE, "PB Unk78: %04x", PB.Unk78);
// WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79);
// WARN_LOG(DSPHLE, "PB Unk31: %04x", PB.Unk31);
@ -280,13 +270,98 @@ restart:
// i think pTest[0x3a] and pTest[0x3b] got an update after you have decoded some samples...
// just decrement them with the number of samples you have played
// and incrrease the ARAM Offset in pTest[0x38], pTest[0x39]
// and increase the ARAM Offset in pTest[0x38], pTest[0x39]
// end of block (Zelda 03b2)
}
// Researching what's actually inside the mysterious 0x21 case
void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac;
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
if (PB.NeedsReset != 0)
{
PB.CurBlock = 0x00;
// Length in samples.
PB.RemLength = PB.Length;
// Copy ARAM addr from r to rw area.
PB.CurAddr = PB.StartAddr;
PB.ReachedEnd = 0;
PB.CurSampleFrac = 0;
}
if (PB.KeyOff != 0)
return;
u8 *source;
u32 ram_mask = 1024 * 1024 * 16 - 1;
if (m_CRC == 0xD643001F) {
source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr);
ram_mask = 1024 * 1024 * 64 - 1;
}
else
source = g_dspInitialize.pGetARAMPointer();
//restart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
// HACK: Looping doesn't work.
if (true || PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length;
return;
}
else
{
// This needs adjustment. It's not right for AFC, was just copied from PCM16.
// We should also probably reinitialize YN1 and YN2 with something - but with what?
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
}
}
u32 prev_addr = PB.CurAddr;
// Prefill the decode buffer.
//AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
const char *src = (char *)(source + (PB.CurAddr & ram_mask));
PB.CurAddr += 9;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
s64 delta = ratio >> 16; // 0x100000000ULL;
int sampleCount = 0, realSample = 0;
while (sampleCount < _Size)
{
_Buffer[sampleCount] = src[realSample] | (src[realSample + 1] << 8) | (src[realSample + 2] << 16)
| (src[realSample + 3] << 24);
//WARN_LOG(DSPHLE, "The sample: %02x", src[sampleCount]);
sampleCount++;
realSample += 4;
TrueSamplePosition += delta;
}
PB.NeedsReset = 0;
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
}
void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size)
{
static u16 lastLeft = 0x1FF, lastRight = 0x1FF;
memset(m_TempBuffer, 0, _Size * sizeof(s32));
if (PB.IsBlank)
@ -297,6 +372,19 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
}
else
{
// XK: Use this to disable music (GREAT for testing)
//if(g_Config.m_DisableStreaming && PB.SoundType == 0x0d00) {
// PB.NeedsReset = 0;
// return;
//}
//WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x",
// PB.Format, PB.SoundType, PB.Unk29, PB.Unk2a);
/*WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x %04x %04x %04x %04x %04x %04x",
PB.Format, PB.SoundType,
PB.volumeLeft1, PB.volumeLeft2, PB.volumeRight1, PB.volumeRight2,
PB.volumeUnknown1_1, PB.volumeUnknown1_2, PB.volumeUnknown2_1,
PB.volumeUnknown2_2);*/
switch (PB.Format)
{
// Synthesized sounds
@ -322,9 +410,7 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
WARN_LOG(DSPHLE, "5 byte AFC - does it work?");
case 0x0009: // AFC with normal bitrate (32:9 compression).
// XK: Use this to disable music (GREAT for testing)
//if(PB.SoundType == 0x0d00)
// break;
RenderVoice_AFC(PB, m_TempBuffer, _Size);
break;
@ -335,11 +421,15 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD.
case 0x0020:
case 0x0021: // Important for Zelda WW. Really need to implement - missing it causes hangs.
case 0x0021: // Probably raw sound. Important for Zelda WW. Really need to implement - missing it causes hangs.
WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format);
PB.ReachedEnd = 1;
// This is what 0x20 and 0x21 do on end of voice
PB.RemLength = 0;
PB.KeyOff = 1;
PB.Status = 0;
// Caution: Use at your own risk. Sounds awful :)
//RenderVoice_Raw(PB, m_TempBuffer, _Size);
break;
default:
@ -354,13 +444,18 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
for (int i = 0; i < _Size; i++)
{
if(PB.volumeLeft2)
lastLeft = PB.volumeLeft2;
if(PB.volumeRight2)
lastRight = PB.volumeRight2;
// TODO: Some noises in Zelda WW (birds, etc) have a volume of 0
// Really not sure about the masking here, but it seems to kill off some overly loud
// sounds in Zelda TP. Needs investigation.
s32 left = _LeftBuffer[i] + (m_TempBuffer[i] * (float)(
(PB.volumeLeft1 & 0x1FFF) + (PB.volumeLeft2 & 0x1FFF)) * 0.00005);
(lastLeft & 0x1FFF) + (lastLeft & 0x1FFF)) * 0.00005);
s32 right = _RightBuffer[i] + (m_TempBuffer[i] * (float)(
(PB.volumeRight1 & 0x1FFF) + (PB.volumeRight2 & 0x1FFF)) * 0.00005);
(lastRight & 0x1FFF) + (lastRight & 0x1FFF)) * 0.00005);
if (left < -32768) left = -32768;
if (left > 32767) left = 32767;

View file

@ -3441,10 +3441,17 @@ void 0a91_Unk() {
//////////////////////////////////////////// 0x20 DECODER
{
0a9a 8900 clr $ACC1
0a9b 0f50 lris $AC1.M, #0x50
0a9c 0083 0520 lri $AR3, #0x0520
0a9e 02bf 0ab3 call 0x0ab3
// 0a9a 8900 clr $ACC1
// 0a9b 0f50 lris $AC1.M, #0x50
// 0a9c 0083 0520 lri $AR3, #0x0520
// 0a9e 02bf 0ab3 call 0x0ab3
ACC1 = 0;
AC1.M = 0x50;
AR3 = 0x520;
0ab3_Decoder0x21Core(AC1.M=0x50, AR3=#0x0580);
// 0aa0 029f 02d8 jmp 0x02d8
GOTO ContinueWithBlock: // in SyncFrame
}
@ -3485,64 +3492,133 @@ void 0ab3_Decoder0x21Core(AC1.M, AR3) {
// 0ab8 1f1f mrr $AX0.L, $AC1.M
// 0ab9 0a00 lris $AX0.H, #0x00
// 0aba 5800 subax $ACC0, $AX0.L
ACC0 = [3a,3b] - AC1.M;
ACC0 = [0x043a,0x043b] - AC1.M;
0abb 0292 0ad1 jg 0x0ad1
if ((prev val of)ACC0 > AX0.L) {
0abd 8900 clr $ACC1
0abe 00c0 043b lr $AR0, @0x043b
0ac0 02bf 0af6 call 0x0af6 // 0af6_Decoder0x21_MoreStuff()
// 0abb 0292 0ad1 jg 0x0ad1
if ([0x043a,0x043b] > *0x043a) {
// Happens when sound has finished playing?
// 0abd 8900 clr $ACC1
// 0abe 00c0 043b lr $AR0, @0x043b
ACC1 = 0;
AR0 = 0x043b;
// 0ac0 02bf 0af6 call 0x0af6 // 0af6_Decoder0x21_MoreStuff()
0af6_Decoder0x21_MoreStuff(AR0=0x043b);
// 0ac2 8100 clr $ACC0
// 0ac3 1fd8 mrr $AC0.M, $AX0.L
// 0ac4 223b lrs $AX0.H, @0x003b
// 0ac5 5400 subr $ACC0, $AX0.H
// 0ac6 0007 dar $AR3
// 0ac7 1979 lrri $AX1.L, @$AR3
ACC0 = 0;
AX0.H = *0x043b;
AC0.M = AX0.L - *0x043b;
AX1.L = *$AR3;
// Looks like duplication of the first memory address AC0.M times
// 0ac8 005e loop $AC0.M
for(int i = 0; i < AC0.M; i++) {
// 0ac9 1b79 srri @$AR3, $AX1.L
*$AR3++ = AX1.L;
}
// 0aca 0f01 lris $AC1.M, #0x01
// 0acb 2f01 srs @0x0001, $AC1.M
// 0acc 8900 clr $ACC1
// 0acd 2f3b srs @0x003b, $AC1.M
ACC1 = 0;
// Looks like some finalization of the PB
*0x0401 = 1; // KeyOff
*0x043b = 0; // RemLength
0ac2 8100 clr $ACC0
0ac3 1fd8 mrr $AC0.M, $AX0.L
0ac4 223b lrs $AX0.H, @0x003b
0ac5 5400 subr $ACC0, $AX0.H
0ac6 0007 dar $AR3
0ac7 1979 lrri $AX1.L, @$AR3
0ac8 005e loop $AC0.M
0ac9 1b79 srri @$AR3, $AX1.L
0aca 0f01 lris $AC1.M, #0x01
0acb 2f01 srs @0x0001, $AC1.M
0acc 8900 clr $ACC1
0acd 2f3b srs @0x003b, $AC1.M
0ace 0092 00ff lri $CR, #0x00ff
0ad0 02df ret
//0ad0 02df ret
return;
}
0ad1 2e3a srs @0x003a, $AC0.M
0ad2 2c3b srs @0x003b, $AC0.L
0ad3 8100 clr $ACC0
0ad4 8900 clr $ACC1
0ad5 268a lrs $AC0.M, @0xff8a
0ad6 2734 lrs $AC1.M, @0x0034
0ad7 5c00 sub $ACC0, $AC1.L
0ad8 2e36 srs @0x0036, $AC0.M
0ad9 5000 subr $ACC0, $AX0.L
// 0ad1 2e3a srs @0x003a, $AC0.M
// 0ad2 2c3b srs @0x003b, $AC0.L
*0x043a = AC0.M;
*0x043b = AC0.L;
// 0ad3 8100 clr $ACC0
// 0ad4 8900 clr $ACC1
// 0ad5 268a lrs $AC0.M, @0xff8a
// 0ad6 2734 lrs $AC1.M, @0x0034
ACC0 = 0;
ACC1 = 0;
AC0.M = *0x048a;
AC1.M = *0x0434;
// 0ad7 5c00 sub $ACC0, $AC1.L
// 0ad8 2e36 srs @0x0036, $AC0.M
ACC0 -= AC1.L;
*0x0436 = (ACC0 & 0xFFFF0000) >> 16;
// 0ad9 5000 subr $ACC0, $AX0.L
ACC0 -= AX0.L;
0ada 0290 0af0 jns 0x0af0
if () {
if (ACC0 < 0) {
// 0adc 00c0 0436 lr $AR0, @0x0436
// 0ade 02bf 0af6 call 0x0af6
0af6_Decoder0x21_MoreStuff($AR0 = *0x0436);
0af6_Decoder0x21_MoreStuff(AR0=*0x0436);
// 0ae0 8100 clr $ACC0
0ae1 1fd8 mrr $AC0.M, $AX0.L
0ae2 2236 lrs $AX0.H, @0x0036 // 0x0436
0ae3 5400 subr $ACC0, $AX0.H
0ae4 1c1e mrr $AR0, $AC0.M
0ae5 8100 clr $ACC0
0ae6 2e34 srs @0x0034, $AC0.M
0ae7 2688 lrs $AC0.M, @0xff88 // 0x0488
0ae8 2489 lrs $AC0.L, @0xff89 // 0x0489
0ae9 2e8c srs @0xff8c, $AC0.M
0aea 2c8d srs @0xff8d, $AC0.L
// 0ae1 1fd8 mrr $AC0.M, $AX0.L
ACC0 = 0;
AC0.M = AX0.L;
// 0ae2 2236 lrs $AX0.H, @0x0036 // 0x0436
AX0.H = *0x0436;
// 0ae3 5400 subr $ACC0, $AX0.H
// 0ae4 1c1e mrr $AR0, $AC0.M
// 0ae5 8100 clr $ACC0
// 0ae6 2e34 srs @0x0034, $AC0.M
ACC0 -= AX0.H;
AR0 = (ACC0 & 0xFFFF0000) >> 16;
ACC0 = 0;
*0x0434 = 0;
// 0ae7 2688 lrs $AC0.M, @0xff88 // 0x0488
// 0ae8 2489 lrs $AC0.L, @0xff89 // 0x0489
// 0ae9 2e8c srs @0xff8c, $AC0.M
// 0aea 2c8d srs @0xff8d, $AC0.L
*0x048c = *0x0488;
*0x048d = *0x0489;
// 0aeb 02bf 0af6 call 0x0af6
0af6_Decoder0x21_MoreStuff($AR0 = *0x0436);
0af6_Decoder0x21_MoreStuff(AR0=*0x0436);
0aed 0092 00ff lri $CR, #0x00ff
// 0aef 02df ret
return;
}
0af0 1c18 mrr $AR0, $AX0.L
0af1 02bf 0af6 call 0x0af6
// 0af0 1c18 mrr $AR0, $AX0.L
// 0af1 02bf 0af6 call 0x0af6
AR0 = AX0.L;
0af6_Decoder0x21_MoreStuff(AR0=AX0.L);
0af3 0092 00ff lri $CR, #0x00ff
// 0af5 02df ret
}
@ -3552,19 +3628,24 @@ void 0ab3_Decoder0x21Core(AC1.M, AR3) {
// Does strange stuff with PB[0x34] and the address PB[0x8c,d]
// Does not touch AX0.L
void 0af6_Decoder0x21_MoreStuff($AR0) {
0af6 8100 clr $ACC0
0af7 1fc0 mrr $AC0.M, $AR0
// 0af6 8100 clr $ACC0
// 0af7 1fc0 mrr $AC0.M, $AR0
// 0af8 b100 tst $ACC0
// 0af9 02d5 retz
if (!AR0)
return;
ACC0 = 0;
AC0.M = AR0;
// 0afa 8900 clr $ACC1
// 0afb 2734 lrs $AC1.M, @0x0034
// 0afc 0340 0001 andi $AC1.M, #0x0001
// 0afe 0b00 lris $AX1.H, #0x00
// 0aff 1f3f mrr $AX1.L, $AC1.M
// AX1.L = *0x0434 & 1;
AX1.L = *0x0434 & 1;
// 0b00 268c lrs $AC0.M, @0xff8c
// 0b01 248d lrs $AC0.L, @0xff8d
// 0b02 8900 clr $ACC1
@ -3577,7 +3658,9 @@ void 0af6_Decoder0x21_MoreStuff($AR0) {
ACC0 = {8c,8d} + *0x0434 * 2 - (*0x0434 & 1) * 2
0b08 1c20 mrr $AR1, $AR0
// 0b08 1c20 mrr $AR1, $AR0
AR1 = AR0;
// 0b09 1fe0 mrr $AC1.M, $AR0
// 0b0a 0502 addis $ACC1, #0x02