From 9ac60a840a1447d583b32049dab4ab327dd3b65f Mon Sep 17 00:00:00 2001 From: RSDuck Date: Sat, 31 Oct 2020 13:43:33 +0100 Subject: SPU: work with scalars instead of arrays --- src/SPU.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'src/SPU.h') diff --git a/src/SPU.h b/src/SPU.h index 964841d..397c733 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -33,7 +33,7 @@ void DoSavestate(Savestate* file); void SetBias(u16 bias); -void Mix(u32 samples); +void Mix(u32 dummy); void TrimOutput(); void DrainOutput(); @@ -123,26 +123,24 @@ public: void NextSample_PSG(); void NextSample_Noise(); - template void Run(s32* buf, u32 samples); + template s32 Run(); - void DoRun(s32* buf, u32 samples) + s32 DoRun() { - for (u32 s = 0; s < samples; s++) - buf[s] = 0; - switch ((Cnt >> 29) & 0x3) { - case 0: Run<0>(buf, samples); break; - case 1: Run<1>(buf, samples); break; - case 2: Run<2>(buf, samples); break; + case 0: return Run<0>(); break; + case 1: return Run<1>(); break; + case 2: return Run<2>(); break; case 3: - if (Num >= 14) Run<4>(buf, samples); - else if (Num >= 8) Run<3>(buf, samples); - break; + if (Num >= 14) return Run<4>(); + else if (Num >= 8) return Run<3>(); + default: + return 0; } } - void PanOutput(s32* inbuf, u32 samples, s32* leftbuf, s32* rightbuf); + void PanOutput(s32 in, s32& left, s32& right); private: u32 (*BusRead32)(u32 addr); -- cgit v1.2.3 From 05b94eff66e3ae0192dad2a638d18491b15654b0 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Wed, 11 Nov 2020 17:54:27 +0100 Subject: make audio output thread safe(r?) --- src/NDS.cpp | 1 + src/SPU.cpp | 127 ++++++++++++++++++++++++++++++++++++++++++------------------ src/SPU.h | 1 + 3 files changed, 91 insertions(+), 38 deletions(-) (limited to 'src/SPU.h') diff --git a/src/NDS.cpp b/src/NDS.cpp index 5181b34..d68045b 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -999,6 +999,7 @@ u32 RunFrame() ARM7Timestamp-SysTimestamp, GPU3D::Timestamp-SysTimestamp); #endif + SPU::TransferOutput(); NDSCart::FlushSRAMFile(); diff --git a/src/SPU.cpp b/src/SPU.cpp index bb15244..fe798c7 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -18,6 +18,7 @@ #include #include +#include "Platform.h" #include "NDS.h" #include "DSi.h" #include "SPU.h" @@ -61,11 +62,15 @@ const s16 PSGTable[8][8] = {-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF} }; -const u32 OutputBufferSize = 2*1024; -s16 OutputBuffer[2 * OutputBufferSize]; -volatile u32 OutputReadOffset; -volatile u32 OutputWriteOffset; +const u32 OutputBufferSize = 2*2048; +s16 OutputBackbuffer[2 * OutputBufferSize]; +u32 OutputBackbufferWritePosition; +s16 OutputFrontBuffer[2 * OutputBufferSize]; +u32 OutputFrontBufferWritePosition; +u32 OutputFrontBufferReadPosition; + +Platform::Mutex* AudioLock; u16 Cnt; u8 MasterVolume; @@ -83,6 +88,8 @@ bool Init() Capture[0] = new CaptureUnit(0); Capture[1] = new CaptureUnit(1); + AudioLock = Platform::Mutex_Create(); + return true; } @@ -93,6 +100,8 @@ void DeInit() delete Capture[0]; delete Capture[1]; + + Platform::Mutex_Free(AudioLock); } void Reset() @@ -114,10 +123,13 @@ void Reset() void Stop() { - memset(OutputBuffer, 0, 2*OutputBufferSize*2); + Platform::Mutex_Lock(AudioLock); + memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2); - OutputReadOffset = 0; - OutputWriteOffset = 0; + OutputBackbufferWritePosition = 0; + OutputFrontBufferReadPosition = 0; + OutputFrontBufferWritePosition = 0; + Platform::Mutex_Unlock(AudioLock); } void DoSavestate(Savestate* file) @@ -704,59 +716,88 @@ void Mix(u32 dummy) if (rightoutput < -0x8000) rightoutput = -0x8000; else if (rightoutput > 0x7FFF) rightoutput = 0x7FFF; - OutputBuffer[OutputWriteOffset ] = leftoutput >> 1; - OutputBuffer[OutputWriteOffset + 1] = rightoutput >> 1; - OutputWriteOffset += 2; - OutputWriteOffset &= ((2*OutputBufferSize)-1); - if (OutputWriteOffset == OutputReadOffset) - { - //printf("!! SOUND FIFO OVERFLOW %d\n", OutputWriteOffset>>1); - // advance the read position too, to avoid losing the entire FIFO - OutputReadOffset += 2; - OutputReadOffset &= ((2*OutputBufferSize)-1); - } + // OutputBufferFrame can never get full because it's + // transfered to OutputBuffer at the end of the frame + OutputBackbuffer[OutputBackbufferWritePosition ] = leftoutput >> 1; + OutputBackbuffer[OutputBackbufferWritePosition + 1] = rightoutput >> 1; + OutputBackbufferWritePosition += 2; NDS::ScheduleEvent(NDS::Event_SPU, true, 1024, Mix, 0); } +void TransferOutput() +{ + Platform::Mutex_Lock(AudioLock); + for (u32 i = 0; i < OutputBackbufferWritePosition; i += 2) + { + OutputFrontBuffer[OutputFrontBufferWritePosition ] = OutputBackbuffer[i ]; + OutputFrontBuffer[OutputFrontBufferWritePosition + 1] = OutputBackbuffer[i + 1]; + + OutputFrontBufferWritePosition += 2; + OutputFrontBufferWritePosition &= OutputBufferSize*2-1; + if (OutputFrontBufferWritePosition == OutputFrontBufferReadPosition) + { + // advance the read position too, to avoid losing the entire FIFO + OutputFrontBufferReadPosition += 2; + OutputFrontBufferReadPosition &= OutputBufferSize*2-1; + } + } + OutputBackbufferWritePosition = 0; + Platform::Mutex_Unlock(AudioLock); +} void TrimOutput() { + Platform::Mutex_Lock(AudioLock); const int halflimit = (OutputBufferSize / 2); - int readpos = OutputWriteOffset - (halflimit*2); + int readpos = OutputFrontBufferWritePosition - (halflimit*2); if (readpos < 0) readpos += (OutputBufferSize*2); - OutputReadOffset = readpos; + OutputFrontBufferReadPosition = readpos; + Platform::Mutex_Unlock(AudioLock); } void DrainOutput() { - OutputReadOffset = 0; - OutputWriteOffset = 0; + Platform::Mutex_Lock(AudioLock); + OutputFrontBufferWritePosition = 0; + OutputFrontBufferReadPosition = 0; + Platform::Mutex_Unlock(AudioLock); } void InitOutput() { - memset(OutputBuffer, 0, 2*OutputBufferSize*2); - OutputReadOffset = 0; - OutputWriteOffset = OutputBufferSize; + Platform::Mutex_Lock(AudioLock); + memset(OutputBackbuffer, 0, 2*OutputBufferSize*2); + memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2); + OutputFrontBufferReadPosition = 0; + OutputFrontBufferWritePosition = 0; + Platform::Mutex_Unlock(AudioLock); } int GetOutputSize() { + Platform::Mutex_Lock(AudioLock); + int ret; - if (OutputWriteOffset >= OutputReadOffset) - ret = OutputWriteOffset - OutputReadOffset; + if (OutputFrontBufferWritePosition >= OutputFrontBufferReadPosition) + ret = OutputFrontBufferWritePosition - OutputFrontBufferReadPosition; else - ret = (OutputBufferSize*2) - OutputReadOffset + OutputWriteOffset; + ret = (OutputBufferSize*2) - OutputFrontBufferReadPosition + OutputFrontBufferWritePosition; ret >>= 1; + + Platform::Mutex_Unlock(AudioLock); return ret; } void Sync(bool wait) { + // this function is currently not used anywhere + // depending on the usage context the thread safety measures could be made + // a lot faster + // sync to audio output in case the core is running too fast // * wait=true: wait until enough audio data has been played // * wait=false: merely skip some audio data to avoid a FIFO overflow @@ -770,32 +811,42 @@ void Sync(bool wait) } else if (GetOutputSize() > halflimit) { - int readpos = OutputWriteOffset - (halflimit*2); + Platform::Mutex_Lock(AudioLock); + + int readpos = OutputFrontBufferWritePosition - (halflimit*2); if (readpos < 0) readpos += (OutputBufferSize*2); - OutputReadOffset = readpos; + OutputFrontBufferReadPosition = readpos; + + Platform::Mutex_Unlock(AudioLock); } } int ReadOutput(s16* data, int samples) { - if (OutputReadOffset == OutputWriteOffset) + Platform::Mutex_Lock(AudioLock); + if (OutputFrontBufferReadPosition == OutputFrontBufferWritePosition) + { + Platform::Mutex_Unlock(AudioLock); return 0; + } for (int i = 0; i < samples; i++) { - *data++ = OutputBuffer[OutputReadOffset]; - *data++ = OutputBuffer[OutputReadOffset + 1]; + *data++ = OutputFrontBuffer[OutputFrontBufferReadPosition]; + *data++ = OutputFrontBuffer[OutputFrontBufferReadPosition + 1]; + + OutputFrontBufferReadPosition += 2; + OutputFrontBufferReadPosition &= ((2*OutputBufferSize)-1); - //if (OutputReadOffset != OutputWriteOffset) + if (OutputFrontBufferWritePosition == OutputFrontBufferReadPosition) { - OutputReadOffset += 2; - OutputReadOffset &= ((2*OutputBufferSize)-1); - } - if (OutputReadOffset == OutputWriteOffset) + Platform::Mutex_Unlock(AudioLock); return i+1; + } } + Platform::Mutex_Unlock(AudioLock); return samples; } diff --git a/src/SPU.h b/src/SPU.h index 397c733..c6b1c7f 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -41,6 +41,7 @@ void InitOutput(); int GetOutputSize(); void Sync(bool wait); int ReadOutput(s16* data, int samples); +void TransferOutput(); u8 Read8(u32 addr); u16 Read16(u32 addr); -- cgit v1.2.3