make audio output thread safe(r?)
This commit is contained in:
parent
1b0a24a9bd
commit
05b94eff66
|
@ -999,6 +999,7 @@ u32 RunFrame()
|
||||||
ARM7Timestamp-SysTimestamp,
|
ARM7Timestamp-SysTimestamp,
|
||||||
GPU3D::Timestamp-SysTimestamp);
|
GPU3D::Timestamp-SysTimestamp);
|
||||||
#endif
|
#endif
|
||||||
|
SPU::TransferOutput();
|
||||||
|
|
||||||
NDSCart::FlushSRAMFile();
|
NDSCart::FlushSRAMFile();
|
||||||
|
|
||||||
|
|
127
src/SPU.cpp
127
src/SPU.cpp
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "Platform.h"
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "DSi.h"
|
#include "DSi.h"
|
||||||
#include "SPU.h"
|
#include "SPU.h"
|
||||||
|
@ -61,11 +62,15 @@ const s16 PSGTable[8][8] =
|
||||||
{-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF}
|
{-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF}
|
||||||
};
|
};
|
||||||
|
|
||||||
const u32 OutputBufferSize = 2*1024;
|
const u32 OutputBufferSize = 2*2048;
|
||||||
s16 OutputBuffer[2 * OutputBufferSize];
|
s16 OutputBackbuffer[2 * OutputBufferSize];
|
||||||
volatile u32 OutputReadOffset;
|
u32 OutputBackbufferWritePosition;
|
||||||
volatile u32 OutputWriteOffset;
|
|
||||||
|
|
||||||
|
s16 OutputFrontBuffer[2 * OutputBufferSize];
|
||||||
|
u32 OutputFrontBufferWritePosition;
|
||||||
|
u32 OutputFrontBufferReadPosition;
|
||||||
|
|
||||||
|
Platform::Mutex* AudioLock;
|
||||||
|
|
||||||
u16 Cnt;
|
u16 Cnt;
|
||||||
u8 MasterVolume;
|
u8 MasterVolume;
|
||||||
|
@ -83,6 +88,8 @@ bool Init()
|
||||||
Capture[0] = new CaptureUnit(0);
|
Capture[0] = new CaptureUnit(0);
|
||||||
Capture[1] = new CaptureUnit(1);
|
Capture[1] = new CaptureUnit(1);
|
||||||
|
|
||||||
|
AudioLock = Platform::Mutex_Create();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +100,8 @@ void DeInit()
|
||||||
|
|
||||||
delete Capture[0];
|
delete Capture[0];
|
||||||
delete Capture[1];
|
delete Capture[1];
|
||||||
|
|
||||||
|
Platform::Mutex_Free(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
|
@ -114,10 +123,13 @@ void Reset()
|
||||||
|
|
||||||
void Stop()
|
void Stop()
|
||||||
{
|
{
|
||||||
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2);
|
||||||
|
|
||||||
OutputReadOffset = 0;
|
OutputBackbufferWritePosition = 0;
|
||||||
OutputWriteOffset = 0;
|
OutputFrontBufferReadPosition = 0;
|
||||||
|
OutputFrontBufferWritePosition = 0;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void DoSavestate(Savestate* file)
|
||||||
|
@ -704,59 +716,88 @@ void Mix(u32 dummy)
|
||||||
if (rightoutput < -0x8000) rightoutput = -0x8000;
|
if (rightoutput < -0x8000) rightoutput = -0x8000;
|
||||||
else if (rightoutput > 0x7FFF) rightoutput = 0x7FFF;
|
else if (rightoutput > 0x7FFF) rightoutput = 0x7FFF;
|
||||||
|
|
||||||
OutputBuffer[OutputWriteOffset ] = leftoutput >> 1;
|
// OutputBufferFrame can never get full because it's
|
||||||
OutputBuffer[OutputWriteOffset + 1] = rightoutput >> 1;
|
// transfered to OutputBuffer at the end of the frame
|
||||||
OutputWriteOffset += 2;
|
OutputBackbuffer[OutputBackbufferWritePosition ] = leftoutput >> 1;
|
||||||
OutputWriteOffset &= ((2*OutputBufferSize)-1);
|
OutputBackbuffer[OutputBackbufferWritePosition + 1] = rightoutput >> 1;
|
||||||
if (OutputWriteOffset == OutputReadOffset)
|
OutputBackbufferWritePosition += 2;
|
||||||
{
|
|
||||||
//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);
|
|
||||||
}
|
|
||||||
|
|
||||||
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024, Mix, 0);
|
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()
|
void TrimOutput()
|
||||||
{
|
{
|
||||||
|
Platform::Mutex_Lock(AudioLock);
|
||||||
const int halflimit = (OutputBufferSize / 2);
|
const int halflimit = (OutputBufferSize / 2);
|
||||||
|
|
||||||
int readpos = OutputWriteOffset - (halflimit*2);
|
int readpos = OutputFrontBufferWritePosition - (halflimit*2);
|
||||||
if (readpos < 0) readpos += (OutputBufferSize*2);
|
if (readpos < 0) readpos += (OutputBufferSize*2);
|
||||||
|
|
||||||
OutputReadOffset = readpos;
|
OutputFrontBufferReadPosition = readpos;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrainOutput()
|
void DrainOutput()
|
||||||
{
|
{
|
||||||
OutputReadOffset = 0;
|
Platform::Mutex_Lock(AudioLock);
|
||||||
OutputWriteOffset = 0;
|
OutputFrontBufferWritePosition = 0;
|
||||||
|
OutputFrontBufferReadPosition = 0;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitOutput()
|
void InitOutput()
|
||||||
{
|
{
|
||||||
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
|
Platform::Mutex_Lock(AudioLock);
|
||||||
OutputReadOffset = 0;
|
memset(OutputBackbuffer, 0, 2*OutputBufferSize*2);
|
||||||
OutputWriteOffset = OutputBufferSize;
|
memset(OutputFrontBuffer, 0, 2*OutputBufferSize*2);
|
||||||
|
OutputFrontBufferReadPosition = 0;
|
||||||
|
OutputFrontBufferWritePosition = 0;
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetOutputSize()
|
int GetOutputSize()
|
||||||
{
|
{
|
||||||
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
if (OutputWriteOffset >= OutputReadOffset)
|
if (OutputFrontBufferWritePosition >= OutputFrontBufferReadPosition)
|
||||||
ret = OutputWriteOffset - OutputReadOffset;
|
ret = OutputFrontBufferWritePosition - OutputFrontBufferReadPosition;
|
||||||
else
|
else
|
||||||
ret = (OutputBufferSize*2) - OutputReadOffset + OutputWriteOffset;
|
ret = (OutputBufferSize*2) - OutputFrontBufferReadPosition + OutputFrontBufferWritePosition;
|
||||||
|
|
||||||
ret >>= 1;
|
ret >>= 1;
|
||||||
|
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sync(bool wait)
|
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
|
// sync to audio output in case the core is running too fast
|
||||||
// * wait=true: wait until enough audio data has been played
|
// * wait=true: wait until enough audio data has been played
|
||||||
// * wait=false: merely skip some audio data to avoid a FIFO overflow
|
// * wait=false: merely skip some audio data to avoid a FIFO overflow
|
||||||
|
@ -770,32 +811,42 @@ void Sync(bool wait)
|
||||||
}
|
}
|
||||||
else if (GetOutputSize() > halflimit)
|
else if (GetOutputSize() > halflimit)
|
||||||
{
|
{
|
||||||
int readpos = OutputWriteOffset - (halflimit*2);
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
|
||||||
|
int readpos = OutputFrontBufferWritePosition - (halflimit*2);
|
||||||
if (readpos < 0) readpos += (OutputBufferSize*2);
|
if (readpos < 0) readpos += (OutputBufferSize*2);
|
||||||
|
|
||||||
OutputReadOffset = readpos;
|
OutputFrontBufferReadPosition = readpos;
|
||||||
|
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadOutput(s16* data, int samples)
|
int ReadOutput(s16* data, int samples)
|
||||||
{
|
{
|
||||||
if (OutputReadOffset == OutputWriteOffset)
|
Platform::Mutex_Lock(AudioLock);
|
||||||
|
if (OutputFrontBufferReadPosition == OutputFrontBufferWritePosition)
|
||||||
|
{
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < samples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
{
|
{
|
||||||
*data++ = OutputBuffer[OutputReadOffset];
|
*data++ = OutputFrontBuffer[OutputFrontBufferReadPosition];
|
||||||
*data++ = OutputBuffer[OutputReadOffset + 1];
|
*data++ = OutputFrontBuffer[OutputFrontBufferReadPosition + 1];
|
||||||
|
|
||||||
//if (OutputReadOffset != OutputWriteOffset)
|
OutputFrontBufferReadPosition += 2;
|
||||||
|
OutputFrontBufferReadPosition &= ((2*OutputBufferSize)-1);
|
||||||
|
|
||||||
|
if (OutputFrontBufferWritePosition == OutputFrontBufferReadPosition)
|
||||||
{
|
{
|
||||||
OutputReadOffset += 2;
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
OutputReadOffset &= ((2*OutputBufferSize)-1);
|
|
||||||
}
|
|
||||||
if (OutputReadOffset == OutputWriteOffset)
|
|
||||||
return i+1;
|
return i+1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Platform::Mutex_Unlock(AudioLock);
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ void InitOutput();
|
||||||
int GetOutputSize();
|
int GetOutputSize();
|
||||||
void Sync(bool wait);
|
void Sync(bool wait);
|
||||||
int ReadOutput(s16* data, int samples);
|
int ReadOutput(s16* data, int samples);
|
||||||
|
void TransferOutput();
|
||||||
|
|
||||||
u8 Read8(u32 addr);
|
u8 Read8(u32 addr);
|
||||||
u16 Read16(u32 addr);
|
u16 Read16(u32 addr);
|
||||||
|
|
Loading…
Reference in New Issue