From b96ac8e000536e9c3f498579abb319c6cfe3d022 Mon Sep 17 00:00:00 2001 From: StapleButter Date: Sat, 11 Nov 2017 18:46:42 +0100 Subject: (finally) fix sound * reset capture position when starting capture * reorder channel/capture handling * implement FIFO for channel and capture --- src/NDS.cpp | 3 - src/SPU.cpp | 185 ++++++++++++++++++++++++++++++++++++++----------- src/SPU.h | 28 +++++++- src/libui_sdl/main.cpp | 2 +- 4 files changed, 173 insertions(+), 45 deletions(-) diff --git a/src/NDS.cpp b/src/NDS.cpp index ab7b5a2..c75b168 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -329,9 +329,6 @@ void Reset() memset(SchedList, 0, sizeof(SchedList)); SchedListMask = 0; - /*ARM9Cycles = 0; - ARM7Cycles = 0; - SchedCycles = 0;*/ CurIterationCycles = 0; ARM7Offset = 0; diff --git a/src/SPU.cpp b/src/SPU.cpp index a3f61b4..a0d8dc8 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -61,6 +61,8 @@ const s16 PSGTable[8][8] = {-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF} }; +const u32 kSamplesPerRun = 1; + const u32 OutputBufferSize = 2*1024; s16 OutputBuffer[2 * OutputBufferSize]; u32 OutputReadOffset; @@ -99,7 +101,7 @@ void Reset() { memset(OutputBuffer, 0, 2*OutputBufferSize*2); OutputReadOffset = 0; - OutputWriteOffset = 0; + OutputWriteOffset = OutputBufferSize; Cnt = 0; MasterVolume = 0; @@ -111,7 +113,7 @@ void Reset() Capture[0]->Reset(); Capture[1]->Reset(); - NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*16, Mix, 16); + NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*kSamplesPerRun, Mix, kSamplesPerRun); } void Stop() @@ -144,6 +146,53 @@ void Channel::Reset() Length = 0; Timer = 0; + + Pos = 0; + FIFOReadPos = 0; + FIFOWritePos = 0; + FIFOReadOffset = 0; + FIFOLevel = 0; +} + +void Channel::FIFO_BufferData() +{ + u32 totallen = LoopPos + Length; + + if (FIFOReadOffset >= totallen) + { + u32 repeatmode = (Cnt >> 27) & 0x3; + if (repeatmode == 2) return; // one-shot sound, we're done + if (repeatmode == 1) FIFOReadOffset = LoopPos; + } + + u32 burstlen = 16; + if ((FIFOReadOffset + 16) > totallen) + burstlen = totallen - FIFOReadOffset; + + for (u32 i = 0; i < burstlen; i += 4) + { + FIFO[FIFOWritePos] = NDS::ARM7Read32(SrcAddr + FIFOReadOffset); + FIFOReadOffset += 4; + FIFOWritePos++; + FIFOWritePos &= 0x7; + } + + FIFOLevel += burstlen; +} + +template +T Channel::FIFO_ReadData() +{ + T ret = *(T*)&((u8*)FIFO)[FIFOReadPos]; + + FIFOReadPos += sizeof(T); + FIFOReadPos &= 0x1F; + FIFOLevel -= sizeof(T); + + if (FIFOLevel <= 16) + FIFO_BufferData(); + + return ret; } void Channel::Start() @@ -157,6 +206,18 @@ void Channel::Start() NoiseVal = 0x7FFF; CurSample = 0; + + FIFOReadPos = 0; + FIFOWritePos = 0; + FIFOReadOffset = 0; + FIFOLevel = 0; + + // when starting a channel, two 4-word chunks are buffered + if (((Cnt >> 29) & 0x3) != 3) + { + FIFO_BufferData(); + FIFO_BufferData(); + } } void Channel::NextSample_PCM8() @@ -179,7 +240,7 @@ void Channel::NextSample_PCM8() } } - s8 val = (s8)NDS::ARM7Read8(SrcAddr + Pos); + s8 val = FIFO_ReadData(); CurSample = val << 8; } @@ -203,7 +264,7 @@ void Channel::NextSample_PCM16() } } - s16 val = (s16)NDS::ARM7Read16(SrcAddr + (Pos<<1)); + s16 val = FIFO_ReadData(); CurSample = val; } @@ -215,7 +276,7 @@ void Channel::NextSample_ADPCM() if (Pos == 0) { // setup ADPCM - u32 header = NDS::ARM7Read32(SrcAddr); + u32 header = FIFO_ReadData(); ADPCMVal = header & 0xFFFF; ADPCMIndex = (header >> 16) & 0x7F; if (ADPCMIndex > 88) ADPCMIndex = 88; @@ -242,12 +303,13 @@ void Channel::NextSample_ADPCM() Pos = LoopPos<<1; ADPCMVal = ADPCMValLoop; ADPCMIndex = ADPCMIndexLoop; + ADPCMCurByte = FIFO_ReadData(); } } else { if (!(Pos & 0x1)) - ADPCMCurByte = NDS::ARM7Read8(SrcAddr + (Pos>>1)); + ADPCMCurByte = FIFO_ReadData(); else ADPCMCurByte >>= 4; @@ -308,6 +370,8 @@ 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++) { Timer += 512; // 1 sample = 512 cycles at 16MHz @@ -335,6 +399,20 @@ void Channel::Run(s32* buf, u32 samples) } } +void Channel::PanOutput(s32* inbuf, u32 samples, s32* leftbuf, s32* rightbuf) +{ + for (u32 s = 0; s < samples; s++) + { + s32 val = (s32)inbuf[s]; + + s32 l = ((s64)val * (128-Pan)) >> 10; + s32 r = ((s64)val * Pan) >> 10; + + leftbuf[s] += l; + rightbuf[s] += r; + } +} + CaptureUnit::CaptureUnit(u32 num) { @@ -353,6 +431,44 @@ void CaptureUnit::Reset() Length = 0; Timer = 0; + + Pos = 0; + FIFOReadPos = 0; + FIFOWritePos = 0; + FIFOWriteOffset = 0; + FIFOLevel = 0; +} + +void CaptureUnit::FIFO_FlushData() +{ + for (u32 i = 0; i < 4; i++) + { + NDS::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]); + + FIFOReadPos++; + FIFOReadPos &= 0x3; + FIFOLevel -= 4; + + FIFOWriteOffset += 4; + if (FIFOWriteOffset >= Length) + { + FIFOWriteOffset = 0; + break; + } + } +} + +template +void CaptureUnit::FIFO_WriteData(T val) +{ + *(T*)&((u8*)FIFO)[FIFOWritePos] = val; + + FIFOWritePos += sizeof(T); + FIFOWritePos &= 0xF; + FIFOLevel += sizeof(T); + + if (FIFOLevel >= 16) + FIFO_FlushData(); } void CaptureUnit::Run(s32 sample) @@ -365,10 +481,13 @@ void CaptureUnit::Run(s32 sample) { Timer = TimerReload + (Timer - 0x10000); - NDS::ARM7Write8(DstAddr + Pos, (u8)(sample >> 8)); + FIFO_WriteData((s8)(sample >> 8)); Pos++; if (Pos >= Length) { + if (FIFOLevel >= 4) + FIFO_FlushData(); + if (Cnt & 0x04) { Cnt &= 0x7F; @@ -385,10 +504,13 @@ void CaptureUnit::Run(s32 sample) { Timer = TimerReload + (Timer - 0x10000); - NDS::ARM7Write16(DstAddr + Pos, (u16)sample); + FIFO_WriteData((s16)sample); Pos += 2; if (Pos >= Length) { + if (FIFOLevel >= 4) + FIFO_FlushData(); + if (Cnt & 0x04) { Cnt &= 0x7F; @@ -406,7 +528,7 @@ void Mix(u32 samples) { s32 channelbuf[32]; s32 leftbuf[32], rightbuf[32]; - s32 ch1buf[32], ch3buf[32]; + s32 ch0buf[32], ch1buf[32], ch2buf[32], ch3buf[32]; s32 leftoutput[32], rightoutput[32]; for (u32 s = 0; s < samples; s++) @@ -417,29 +539,24 @@ void Mix(u32 samples) if (Cnt & (1<<15)) { - u32 mixermask = 0xFFFF; - if (Cnt & (1<<12)) mixermask &= ~(1<<1); - if (Cnt & (1<<13)) mixermask &= ~(1<<3); + Channels[0]->DoRun(ch0buf, samples); + Channels[1]->DoRun(ch1buf, samples); + Channels[2]->DoRun(ch2buf, samples); + Channels[3]->DoRun(ch3buf, samples); + + // TODO: addition from capture registers + Channels[0]->PanOutput(ch0buf, samples, leftbuf, rightbuf); + Channels[2]->PanOutput(ch2buf, samples, leftbuf, rightbuf); + + if (!(Cnt & (1<<12))) Channels[1]->PanOutput(ch1buf, samples, leftbuf, rightbuf); + if (!(Cnt & (1<<13))) Channels[3]->PanOutput(ch3buf, samples, leftbuf, rightbuf); - for (int i = 0; i < 16; i++) + for (int i = 4; i < 16; i++) { - if (!(mixermask & (1<Cnt & (1<<31))) continue; - // TODO: what happens if we use type 3 on channels 0-7?? chan->DoRun(channelbuf, samples); - - for (u32 s = 0; s < samples; s++) - { - s32 val = (s32)channelbuf[s]; - - s32 l = ((s64)val * (128-chan->Pan)) >> 10; - s32 r = ((s64)val * chan->Pan) >> 10; - - leftbuf[s] += l; - rightbuf[s] += r; - } + chan->PanOutput(channelbuf, samples, leftbuf, rightbuf); } // sound capture @@ -477,17 +594,6 @@ void Mix(u32 samples) // final output - if (Cnt & 0x0500) - { - // mix channel 1 if needed - Channels[1]->DoRun(ch1buf, samples); - } - if (Cnt & 0x0A00) - { - // mix channel 3 if needed - Channels[3]->DoRun(ch3buf, samples); - } - switch (Cnt & 0x0300) { case 0x0000: // left mixer @@ -574,8 +680,7 @@ void Mix(u32 samples) OutputWriteOffset &= ((2*OutputBufferSize)-1); } - - NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*16, Mix, 16); + NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*kSamplesPerRun, Mix, kSamplesPerRun); } diff --git a/src/SPU.h b/src/SPU.h index 0d59db7..cc0127a 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -70,6 +70,15 @@ public: s32 ADPCMIndexLoop; u8 ADPCMCurByte; + u32 FIFO[8]; + u32 FIFOReadPos; + u32 FIFOWritePos; + u32 FIFOReadOffset; + u32 FIFOLevel; + + void FIFO_BufferData(); + template T FIFO_ReadData(); + void SetCnt(u32 val) { u32 oldcnt = Cnt; @@ -139,6 +148,15 @@ public: u32 Timer; s32 Pos; + u32 FIFO[4]; + u32 FIFOReadPos; + u32 FIFOWritePos; + u32 FIFOWriteOffset; + u32 FIFOLevel; + + void FIFO_FlushData(); + template void FIFO_WriteData(T val); + void SetCnt(u8 val) { if ((val & 0x80) && !(Cnt & 0x80)) @@ -153,7 +171,15 @@ public: void SetTimerReload(u32 val) { TimerReload = val & 0xFFFF; } void SetLength(u32 val) { Length = val << 2; if (Length == 0) Length = 4; } - void Start() { Timer = TimerReload; } + void Start() + { + Timer = TimerReload; + Pos = 0; + FIFOReadPos = 0; + FIFOWritePos = 0; + FIFOWriteOffset = 0; + FIFOLevel = 0; + } void Run(s32 sample); }; diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp index fdbcda2..320f31e 100644 --- a/src/libui_sdl/main.cpp +++ b/src/libui_sdl/main.cpp @@ -662,7 +662,7 @@ void OnAreaResize(uiAreaHandler* handler, uiArea* area, int width, int height) void Run() -{printf("go sonic go\n"); +{ EmuRunning = 1; RunningSomething = true; -- cgit v1.2.3