aboutsummaryrefslogtreecommitdiff
path: root/src/SPU.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/SPU.cpp')
-rw-r--r--src/SPU.cpp112
1 files changed, 83 insertions, 29 deletions
diff --git a/src/SPU.cpp b/src/SPU.cpp
index 7f70e65..9862077 100644
--- a/src/SPU.cpp
+++ b/src/SPU.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
@@ -24,8 +24,6 @@
// SPU TODO
// * loop mode 3, what does it do?
-// * the FIFO, whatever it is. GBAtek mentions it but gives no details.
-// * consider mixing every sample instead of every 16?
namespace SPU
@@ -121,6 +119,21 @@ void Stop()
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
}
+void DoSavestate(Savestate* file)
+{
+ file->Section("SPU.");
+
+ file->Var16(&Cnt);
+ file->Var8(&MasterVolume);
+ file->Var16(&Bias);
+
+ for (int i = 0; i < 16; i++)
+ Channels[i]->DoSavestate(file);
+
+ Capture[0]->DoSavestate(file);
+ Capture[1]->DoSavestate(file);
+}
+
void SetBias(u16 bias)
{
@@ -154,6 +167,36 @@ void Channel::Reset()
FIFOLevel = 0;
}
+void Channel::DoSavestate(Savestate* file)
+{
+ file->Var32(&Cnt);
+ file->Var32(&SrcAddr);
+ file->Var16(&TimerReload);
+ file->Var32(&LoopPos);
+ file->Var32(&Length);
+
+ file->Var8(&Volume);
+ file->Var8(&VolumeShift);
+ file->Var8(&Pan);
+
+ file->Var32(&Timer);
+ file->Var32((u32*)&Pos);
+ file->Var16((u16*)&CurSample);
+ file->Var16(&NoiseVal);
+
+ file->Var32((u32*)&ADPCMVal);
+ file->Var32((u32*)&ADPCMIndex);
+ file->Var32((u32*)&ADPCMValLoop);
+ file->Var32((u32*)&ADPCMIndexLoop);
+ file->Var8(&ADPCMCurByte);
+
+ file->Var32(&FIFOReadPos);
+ file->Var32(&FIFOWritePos);
+ file->Var32(&FIFOReadOffset);
+ file->Var32(&FIFOLevel);
+ file->VarArray(FIFO, 8*4);
+}
+
void Channel::FIFO_BufferData()
{
u32 totallen = LoopPos + Length;
@@ -161,8 +204,8 @@ void Channel::FIFO_BufferData()
if (FIFOReadOffset >= totallen)
{
u32 repeatmode = (Cnt >> 27) & 0x3;
- if (repeatmode == 2) return; // one-shot sound, we're done
- if (repeatmode == 1) FIFOReadOffset = LoopPos;
+ if (repeatmode & 1) FIFOReadOffset = LoopPos;
+ else if (repeatmode & 2) return; // one-shot sound, we're done
}
u32 burstlen = 16;
@@ -212,7 +255,7 @@ void Channel::Start()
FIFOReadOffset = 0;
FIFOLevel = 0;
- // when starting a channel, two 4-word chunks are buffered
+ // when starting a channel, buffer data
if (((Cnt >> 29) & 0x3) != 3)
{
FIFO_BufferData();
@@ -226,18 +269,17 @@ void Channel::NextSample_PCM8()
if (Pos < 0) return;
if (Pos >= (LoopPos + Length))
{
- // TODO: what happens when mode 3 is used?
u32 repeat = (Cnt >> 27) & 0x3;
- if (repeat == 2)
+ if (repeat & 1)
+ {
+ Pos = LoopPos;
+ }
+ else if (repeat & 2)
{
CurSample = 0;
Cnt &= ~(1<<31);
return;
}
- else if (repeat == 1)
- {
- Pos = LoopPos;
- }
}
s8 val = FIFO_ReadData<s8>();
@@ -250,18 +292,17 @@ void Channel::NextSample_PCM16()
if (Pos < 0) return;
if ((Pos<<1) >= (LoopPos + Length))
{
- // TODO: what happens when mode 3 is used?
u32 repeat = (Cnt >> 27) & 0x3;
- if (repeat == 2)
+ if (repeat & 1)
+ {
+ Pos = LoopPos>>1;
+ }
+ else if (repeat & 2)
{
CurSample = 0;
Cnt &= ~(1<<31);
return;
}
- else if (repeat == 1)
- {
- Pos = LoopPos>>1;
- }
}
s16 val = FIFO_ReadData<s16>();
@@ -290,21 +331,20 @@ void Channel::NextSample_ADPCM()
if ((Pos>>1) >= (LoopPos + Length))
{
- // TODO: what happens when mode 3 is used?
u32 repeat = (Cnt >> 27) & 0x3;
- if (repeat == 2)
- {
- CurSample = 0;
- Cnt &= ~(1<<31);
- return;
- }
- else if (repeat == 1)
+ if (repeat & 1)
{
Pos = LoopPos<<1;
ADPCMVal = ADPCMValLoop;
ADPCMIndex = ADPCMIndexLoop;
ADPCMCurByte = FIFO_ReadData<u8>();
}
+ else if (repeat & 2)
+ {
+ CurSample = 0;
+ Cnt &= ~(1<<31);
+ return;
+ }
}
else
{
@@ -367,9 +407,6 @@ void Channel::NextSample_Noise()
template<u32 type>
void Channel::Run(s32* buf, u32 samples)
{
- for (u32 s = 0; s < samples; s++)
- buf[s] = 0;
-
if (!(Cnt & (1<<31))) return;
for (u32 s = 0; s < samples; s++)
@@ -439,6 +476,23 @@ void CaptureUnit::Reset()
FIFOLevel = 0;
}
+void CaptureUnit::DoSavestate(Savestate* file)
+{
+ file->Var8(&Cnt);
+ file->Var32(&DstAddr);
+ file->Var16(&TimerReload);
+ file->Var32(&Length);
+
+ file->Var32(&Timer);
+ file->Var32((u32*)&Pos);
+
+ file->Var32(&FIFOReadPos);
+ file->Var32(&FIFOWritePos);
+ file->Var32(&FIFOWriteOffset);
+ file->Var32(&FIFOLevel);
+ file->VarArray(FIFO, 4*4);
+}
+
void CaptureUnit::FIFO_FlushData()
{
for (u32 i = 0; i < 4; i++)