diff options
Diffstat (limited to 'src/SPU.cpp')
-rw-r--r-- | src/SPU.cpp | 112 |
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++) |