DSPHLE: Preserve fractional sample position between voice render calls. sounds slightly, slightly cleaner :P
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3637 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
f6af7794cd
commit
0008d5ef77
|
@ -31,7 +31,7 @@ struct ZeldaVoicePB
|
||||||
// Read-Write part
|
// Read-Write part
|
||||||
u16 Status; // 0x00 | 1 = play, 0 = stop
|
u16 Status; // 0x00 | 1 = play, 0 = stop
|
||||||
u16 KeyOff; // 0x01 | writing 1 stops voice?
|
u16 KeyOff; // 0x01 | writing 1 stops voice?
|
||||||
u16 RatioInt; // 0x02 | delta? ratio? integer part
|
u16 RatioInt; // 0x02 | Position delta (playback speed)
|
||||||
u16 Unk03; // 0x03 | unknown
|
u16 Unk03; // 0x03 | unknown
|
||||||
u16 NeedsReset; // 0x04 | indicates if some values in PB need to be reset
|
u16 NeedsReset; // 0x04 | indicates if some values in PB need to be reset
|
||||||
u16 ReachedEnd; // 0x05 | set to 1 when end reached
|
u16 ReachedEnd; // 0x05 | set to 1 when end reached
|
||||||
|
@ -43,7 +43,13 @@ struct ZeldaVoicePB
|
||||||
u16 Unk0B[2]; // 0x0B | unknown
|
u16 Unk0B[2]; // 0x0B | unknown
|
||||||
u16 volumeRight1; // 0x0D | Right Volume 1
|
u16 volumeRight1; // 0x0D | Right Volume 1
|
||||||
u16 volumeRight2; // 0x0E | Right Volume 2
|
u16 volumeRight2; // 0x0E | Right Volume 2
|
||||||
u16 Unk0F[0x8]; // 0x0F | unknown // Buffer / something, see 036e/ZWW. there's a pattern here
|
u16 Unk0F[2]; // 0x0F | unknown // Buffer / something, see 036e/ZWW. there's a pattern here
|
||||||
|
u16 volumeUnknown1_1; // 0x11 | Unknown Volume 1
|
||||||
|
u16 volumeUnknown1_2; // 0x12 | Unknown Volume 1
|
||||||
|
u16 Unk13[2]; // 0x13 | unknown
|
||||||
|
u16 volumeUnknown2_1; // 0x15 | Unknown Volume 2
|
||||||
|
u16 volumeUnknown2_2; // 0x16 | Unknown Volume 2
|
||||||
|
u16 Unk17; // 0x17 | unknown
|
||||||
u16 Unk18[0x10]; // 0x18 | unknown
|
u16 Unk18[0x10]; // 0x18 | unknown
|
||||||
u16 Unk28; // 0x28 | unknown
|
u16 Unk28; // 0x28 | unknown
|
||||||
u16 Unk29; // 0x29 | unknown // multiplied by 0x2a @ 0d21/ZWW
|
u16 Unk29; // 0x29 | unknown // multiplied by 0x2a @ 0d21/ZWW
|
||||||
|
@ -53,7 +59,7 @@ struct ZeldaVoicePB
|
||||||
u16 Unk2D; // 0x2D | unknown
|
u16 Unk2D; // 0x2D | unknown
|
||||||
u16 Unk2E; // 0x2E | unknown
|
u16 Unk2E; // 0x2E | unknown
|
||||||
u16 Unk2F; // 0x2F | unknown
|
u16 Unk2F; // 0x2F | unknown
|
||||||
u16 RatioFrac; // 0x30 | ??? ratio fractional part
|
u16 CurSampleFrac; // 0x30 | Fractional part of the current sample position
|
||||||
u16 Unk31; // 0x31 | unknown / unused
|
u16 Unk31; // 0x31 | unknown / unused
|
||||||
u16 CurBlock; // 0x32 | current block?
|
u16 CurBlock; // 0x32 | current block?
|
||||||
u16 FixedSample; // 0x33 | sample value for "blank" voices
|
u16 FixedSample; // 0x33 | sample value for "blank" voices
|
||||||
|
|
|
@ -26,8 +26,9 @@
|
||||||
void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||||
{
|
{
|
||||||
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
|
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
|
||||||
u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000;
|
u32 _ratio = (PB.RatioInt << 16);
|
||||||
u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor);
|
s64 ratio = (_ratio * ratioFactor) * 16;
|
||||||
|
|
||||||
int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1;
|
int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1;
|
||||||
|
|
||||||
u32 pos[2] = {0, 0};
|
u32 pos[2] = {0, 0};
|
||||||
|
|
|
@ -57,7 +57,7 @@ void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB)
|
||||||
void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||||
{
|
{
|
||||||
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
|
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
|
||||||
u32 _ratio = (((PB.RatioInt * 80) + PB.RatioFrac) << 4) & 0xFFFF0000;
|
u32 _ratio = (((PB.RatioInt * 80) + PB.CurSampleFrac) << 4) & 0xFFFF0000;
|
||||||
u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor);
|
u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor);
|
||||||
|
|
||||||
u32 pos[2] = {0, 0};
|
u32 pos[2] = {0, 0};
|
||||||
|
@ -129,7 +129,7 @@ _lRestart:
|
||||||
void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||||
{
|
{
|
||||||
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
|
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
|
||||||
u32 _ratio = (PB.RatioInt<<16) + PB.RatioFrac;
|
u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac;
|
||||||
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
|
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
|
||||||
|
|
||||||
// initialize "decoder" if the sample is played the first time
|
// initialize "decoder" if the sample is played the first time
|
||||||
|
@ -151,17 +151,23 @@ void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
|
||||||
// Copy ARAM addr from r to rw area.
|
// Copy ARAM addr from r to rw area.
|
||||||
PB.CurAddr = PB.StartAddr;
|
PB.CurAddr = PB.StartAddr;
|
||||||
PB.ReachedEnd = 0;
|
PB.ReachedEnd = 0;
|
||||||
|
PB.CurSampleFrac = 0;
|
||||||
// Looking at Zelda Four Swords
|
// Looking at Zelda Four Swords
|
||||||
// WARN_LOG(DSPHLE, "PB -----: %04x", PB.Unk03);
|
// WARN_LOG(DSPHLE, "PB -----: %04x", PB.Unk03);
|
||||||
// WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0
|
// WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0
|
||||||
// WARN_LOG(DSPHLE, "PB Unk07: %04x", PB.Unk07[0]); 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 Unk09: %04x", PB.volumeLeft1); // often same value as 0a
|
||||||
//WARN_LOG(DSPHLE, "PB Unk0a: %04x", PB.volumeLeft2);
|
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 Unk0d: %04x", PB.volumeRight1); // often same value as 0e
|
||||||
//WARN_LOG(DSPHLE, "PB Unk0e: %04x", PB.volumeRight2);
|
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 Unk78: %04x", PB.Unk78);
|
||||||
// WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79);
|
// WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79);
|
||||||
|
@ -222,18 +228,19 @@ restart:
|
||||||
AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
|
AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
|
||||||
PB.CurAddr += 9;
|
PB.CurAddr += 9;
|
||||||
|
|
||||||
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 32;
|
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
|
||||||
s64 delta = ratio; // 0x100000000ULL;
|
TrueSamplePosition += PB.CurSampleFrac;
|
||||||
|
s64 delta = ratio >> 16; // 0x100000000ULL;
|
||||||
int sampleCount = 0;
|
int sampleCount = 0;
|
||||||
while (sampleCount < _Size)
|
while (sampleCount < _Size)
|
||||||
{
|
{
|
||||||
int SamplePosition = TrueSamplePosition >> 32;
|
int SamplePosition = TrueSamplePosition >> 16;
|
||||||
_Buffer[sampleCount] = outbuf[SamplePosition & 15];
|
_Buffer[sampleCount] = outbuf[SamplePosition & 15];
|
||||||
|
|
||||||
sampleCount++;
|
sampleCount++;
|
||||||
TrueSamplePosition += delta;
|
TrueSamplePosition += delta;
|
||||||
|
|
||||||
int TargetPosition = TrueSamplePosition >> 32;
|
int TargetPosition = TrueSamplePosition >> 16;
|
||||||
|
|
||||||
// Decode forwards...
|
// Decode forwards...
|
||||||
while (SamplePosition < TargetPosition)
|
while (SamplePosition < TargetPosition)
|
||||||
|
@ -267,7 +274,7 @@ restart:
|
||||||
// }
|
// }
|
||||||
|
|
||||||
PB.NeedsReset = 0;
|
PB.NeedsReset = 0;
|
||||||
|
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
|
||||||
// write back
|
// write back
|
||||||
// NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction
|
// NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction
|
||||||
|
|
||||||
|
@ -315,7 +322,7 @@ void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _Righ
|
||||||
WARN_LOG(DSPHLE, "5 byte AFC - does it work?");
|
WARN_LOG(DSPHLE, "5 byte AFC - does it work?");
|
||||||
case 0x0009: // AFC with normal bitrate (32:9 compression).
|
case 0x0009: // AFC with normal bitrate (32:9 compression).
|
||||||
|
|
||||||
// Use this to disable music (GREAT for testing)
|
// XK: Use this to disable music (GREAT for testing)
|
||||||
//if(PB.SoundType == 0x0d00)
|
//if(PB.SoundType == 0x0d00)
|
||||||
// break;
|
// break;
|
||||||
|
|
||||||
|
|
|
@ -2880,15 +2880,23 @@ void 087c_DefaultDecoder()
|
||||||
087c 8100 clr $ACC0 // ACC0 = 0
|
087c 8100 clr $ACC0 // ACC0 = 0
|
||||||
087d 1f5e mrr $AX0.H, $AC0.M
|
087d 1f5e mrr $AX0.H, $AC0.M
|
||||||
087e 00d8 0402 lr $AX0.L, @0x0402 // AX0.L = PB.RatioInt
|
087e 00d8 0402 lr $AX0.L, @0x0402 // AX0.L = PB.RatioInt
|
||||||
0880 00dc 0430 lr $AC0.L, @0x0430 // AC0.L = PB.RatioFrac
|
|
||||||
|
// Sample fraction is stored in a common way, but sample position is not, so
|
||||||
|
// it's in the individual decoders. Some decoders, like square wave, only care about
|
||||||
|
// fractional sample position. So here we just load up the fractional sample
|
||||||
|
// position before handing control over.
|
||||||
|
0880 00dc 0430 lr $AC0.L, @0x0430 // AC0.L = PB.CurSampleFrac
|
||||||
0882 0080 0520 lri $AR0, #0x0520 // AR0 = 0x0520
|
0882 0080 0520 lri $AR0, #0x0520 // AR0 = 0x0520
|
||||||
0884 00df 0480 lr $AC1.M, @0x0480
|
|
||||||
0886 1501 lsl $ACC1, #1 // AC1.M = (PB.Format << 1)
|
// 0884 00df 0480 lr $AC1.M, @0x0480
|
||||||
0887 0340 007e andi $AC1.M, #0x007e // AC1.M &= 0x007e
|
// 0886 1501 lsl $ACC1, #1 // AC1.M = (PB.Format << 1)
|
||||||
0889 0300 0891 addi $AC1.M, #0x0891 // AC1.M += 0x0891
|
// 0887 0340 007e andi $AC1.M, #0x007e // AC1.M &= 0x007e
|
||||||
088b 1c5f mrr $AR2, $AC1.M // AR2 = AC1.M
|
// 0889 0300 0891 addi $AC1.M, #0x0891 // AC1.M += 0x0891
|
||||||
088c 175f callr $AR2 // (*$AR2)() <-- See jump table at 0x0891
|
// 088b 1c5f mrr $AR2, $AC1.M // AR2 = AC1.M
|
||||||
088d 00fc 0430 sr @0x0430, $AC0.L // PB.RatioFrac = AC0.L
|
// 088c 175f callr $AR2 // (*$AR2)() <-- See jump table at 0x0891
|
||||||
|
JumpTable0891(PB.Format);
|
||||||
|
|
||||||
|
088d 00fc 0430 sr @0x0430, $AC0.L // PB.CurSampleFrac = AC0.L
|
||||||
|
|
||||||
// 088f 029f 02d8 jmp 0x02d8
|
// 088f 029f 02d8 jmp 0x02d8
|
||||||
GOTO ContinueWithBlock: // in SyncFrame
|
GOTO ContinueWithBlock: // in SyncFrame
|
||||||
|
@ -2916,7 +2924,7 @@ void 087c_DefaultDecoder()
|
||||||
08b1 02df ret
|
08b1 02df ret
|
||||||
|
|
||||||
void 08b2_Decoder0x0_SquareWave() {
|
void 08b2_Decoder0x0_SquareWave() {
|
||||||
08b2 1401 lsl $ACC0, #1 // t = PB.RatioFrac * 2
|
08b2 1401 lsl $ACC0, #1 // t = samplePosition * 2
|
||||||
|
|
||||||
// Set up sound buffers
|
// Set up sound buffers
|
||||||
//08b3 009b c000 lri $AX1.H, #0xc000
|
//08b3 009b c000 lri $AX1.H, #0xc000
|
||||||
|
@ -2934,16 +2942,15 @@ void 08b2_Decoder0x0_SquareWave() {
|
||||||
else
|
else
|
||||||
*$AR0++ = 0xc000;
|
*$AR0++ = 0xc000;
|
||||||
|
|
||||||
08bf 4800 addax $ACC0, $AX0.L // t += PB.RatioInt
|
08bf 4800 addax $ACC0, $AX0.L // t += PB.Ratio
|
||||||
}
|
}
|
||||||
08c0 147f lsr $ACC0, #-1 // t /= 2
|
08c0 147f lsr $ACC0, #-1 // t /= 2
|
||||||
|
|
||||||
// Where ACC0 gets stored after this is interesting.
|
|
||||||
// 08c1 02df ret
|
// 08c1 02df ret
|
||||||
}
|
}
|
||||||
|
|
||||||
void 08c2_Decoder0x3_RectangleWave() {
|
void 08c2_Decoder0x3_RectangleWave() {
|
||||||
08c2 1402 lsl $ACC0, #2 // t = PB.RatioFrac * 4
|
08c2 1402 lsl $ACC0, #2 // t = PB.CurSampleFrac * 4
|
||||||
08c3 8900 clr $ACC1 // ACC1 = 0
|
08c3 8900 clr $ACC1 // ACC1 = 0
|
||||||
08c4 1fb8 mrr $AC1.L, $AX0.L // AC1.L = PB.RatioInt
|
08c4 1fb8 mrr $AC1.L, $AX0.L // AC1.L = PB.RatioInt
|
||||||
08c5 1501 lsl $ACC1, #1 // ACC1 *= 2
|
08c5 1501 lsl $ACC1, #1 // ACC1 *= 2
|
||||||
|
|
Loading…
Reference in New Issue