Skip to content

Commit

Permalink
*PSP audio plugin updates for ASYNC.
Browse files Browse the repository at this point in the history
-moved creating buffers to own thread "Fixes doubled audio in areogague"
-Enabled HLE to use uncahced memory address.
  • Loading branch information
z2442 committed Dec 17, 2024
1 parent 0dd8f56 commit 7b53727
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 91 deletions.
152 changes: 66 additions & 86 deletions Source/HLEAudio/AudioBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include "Base/Types.h"
#include "Interface/ConfigOptions.h"
#include "Debug/DBGConsole.h"
Expand All @@ -37,120 +36,101 @@ CAudioBuffer::CAudioBuffer(u32 buffer_size)
CAudioBuffer::~CAudioBuffer() { delete[] mBufferBegin; }

u32 CAudioBuffer::GetNumBufferedSamples() const {
// Safe? What if we read mWrite, and then mRead moves to start of buffer?
s32 diff = mWritePtr - mReadPtr;

if (diff < 0) {
diff += (mBufferEnd - mBufferBegin); // Add on buffer length
}

return diff;
s32 diff = mWritePtr - mReadPtr;
if (diff < 0) {
diff += (mBufferEnd - mBufferBegin); // Add on buffer length
}
return diff;
}

void CAudioBuffer::AddSamples(const Sample *samples, u32 num_samples,
u32 frequency, u32 output_freq) {
#ifdef DAEDALUS_ENABLE_ASSERTS
DAEDALUS_ASSERT(frequency <= output_freq, "Input frequency is too high");
DAEDALUS_ASSERT(frequency <= output_freq, "Input frequency is too high");
#endif

#ifdef DAEDALUS_DEBUG_AUDIO
std::ofstream fh;
if (!fh.is_open()) {
fh.open("audio_in.raw", std::ios::binary);
fh.write(reinterpret_cast<const char *>(samples), sizeof(Sample) * num_samples);
fh.flush();
}
#endif

#ifdef DAEDALUS_PSP
// Cache routines for PSP if needed
std::ofstream fh;
if (!fh.is_open()) {
fh.open("audio_in.raw", std::ios::binary);
fh.write(reinterpret_cast<const char *>(samples), sizeof(Sample) * num_samples);
fh.flush();
}
#endif

const Sample *read_ptr(mReadPtr); // No need to invalidate, as this is uncached/volatile
Sample *write_ptr(mWritePtr);

const s32 r = (frequency << 12) / output_freq;
s32 s = 0;
u32 in_idx = 0;
u32 output_samples = ((num_samples * output_freq) / frequency) - 1;
Sample *write_ptr = mWritePtr;
const Sample *read_ptr = mReadPtr;

for (u32 i = output_samples; i != 0; i--) {
#ifdef DAEDALUS_ENABLE_ASSERTS
DAEDALUS_ASSERT(in_idx + 1 < num_samples,
"Input index out of range - %d / %d", in_idx + 1,
num_samples);
#endif
const s32 r = (frequency << 12) / output_freq;
s32 s = 0;
u32 in_idx = 0;

Sample out;
out.L = samples[in_idx].L + (((samples[in_idx + 1].L - samples[in_idx].L) * s) >> 12);
out.R = samples[in_idx].R + (((samples[in_idx + 1].R - samples[in_idx].R) * s) >> 12);
u32 output_samples = std::min(((num_samples * output_freq) / frequency),
(u32)(mBufferEnd - mWritePtr)); // Avoid overflow

s += r;
in_idx += s >> 12;
s &= 4095;
for (u32 i = 0; i < output_samples; i++) {
Sample out;
out.L = samples[in_idx].L + (((samples[in_idx + 1].L - samples[in_idx].L) * s) >> 12);
out.R = samples[in_idx].R + (((samples[in_idx + 1].R - samples[in_idx].R) * s) >> 12);

// Circular buffer write logic
*write_ptr = out;
write_ptr++;
s += r;
in_idx += s >> 12;
s &= 4095;

if (write_ptr >= mBufferEnd) {
write_ptr = mBufferBegin;
}
*write_ptr++ = out;

if (write_ptr >= mBufferEnd) {
write_ptr = mBufferBegin;
}

// Handle buffer full condition
if (write_ptr == read_ptr) {
// The buffer is full, so move read pointer to the next sample
read_ptr = mReadPtr;
// Optionally, sleep or yield the thread here if needed
// Prevent buffer overflow by advancing read_ptr if needed
if (write_ptr == read_ptr) {
read_ptr++;
if (read_ptr >= mBufferEnd) {
read_ptr = mBufferBegin;
}
}
}
}

mWritePtr = write_ptr;
mWritePtr = write_ptr;
mReadPtr = read_ptr;
}

u32 CAudioBuffer::Drain(Sample *samples, u32 num_samples) {
#ifdef DAEDALUS_PSP
// Cache routines for PSP if needed
#endif

const Sample *read_ptr(mReadPtr); // No need to invalidate, as this is uncached/volatile
Sample *out_ptr(samples);
u32 samples_required(num_samples);
const Sample *read_ptr = mReadPtr;
Sample *out_ptr = samples;
u32 samples_required = num_samples;

while (samples_required > 0) {
// Check if the buffer is empty
if (read_ptr == mWritePtr) {
break; // Buffer is empty
}
while (samples_required > 0) {
if (read_ptr == mWritePtr) {
break; // Buffer is empty
}

*out_ptr++ = *read_ptr++;
if (read_ptr >= mBufferEnd) {
read_ptr = mBufferBegin; // Circular buffer logic
}
*out_ptr++ = *read_ptr++;
if (read_ptr >= mBufferEnd) {
read_ptr = mBufferBegin; // Circular buffer wrap-around
}

samples_required--;
}
samples_required--;
}

#ifdef DAEDALUS_DEBUG_AUDIO
std::ofstream fh;
if (!fh.is_open()) {
fh.open("audio_out.raw", std::ios::binary);
fh.write(reinterpret_cast<const char *>(samples), sizeof(Sample) * num_samples - samples_required);
fh.flush();
}
#endif

mReadPtr = read_ptr; // Update read pointer

#ifdef DAEDALUS_PSP
// Cache routines for PSP if needed
std::ofstream fh;
if (!fh.is_open()) {
fh.open("audio_out.raw", std::ios::binary);
fh.write(reinterpret_cast<const char *>(samples), sizeof(Sample) * (num_samples - samples_required));
fh.flush();
}
#endif

// If there weren't enough samples, zero out the buffer
if (samples_required > 0) {
memset(out_ptr, 0, samples_required * sizeof(Sample));
}
mReadPtr = read_ptr;

// Zero out remaining samples if buffer was empty
if (samples_required > 0) {
memset(out_ptr, 0, samples_required * sizeof(Sample));
}

// Return the number of samples written
return num_samples - samples_required;
return num_samples - samples_required;
}
3 changes: 3 additions & 0 deletions Source/HLEAudio/AudioPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class CAudioPlugin {

virtual void DacrateChanged(int SystemType) = 0;
virtual void LenChanged() = 0;
#ifdef DAEDALUS_PSP
virtual void LenChangedME() = 0;
#endif
virtual u32 ReadLength() = 0;
virtual EProcessResult ProcessAList() = 0;

Expand Down
10 changes: 9 additions & 1 deletion Source/HLEAudio/HLEMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,19 @@ inline void Audio_Ucode_Detect(OSTask *pTask) {
//*****************************************************************************
//
//*****************************************************************************
#ifdef DAEDALUS_PSP
#define UNCACHED(addr) ((void *)((uintptr_t)(addr) | 0x40000000))
#endif

void Audio_Ucode() {
#ifdef DAEDALUS_PROFILE
DAEDALUS_PROFILE("HLEMain::Audio_Ucode");
#endif
OSTask *pTask = (OSTask *)(g_pu8SpMemBase + 0x0FC0);
#ifdef DAEDALUS_PSP
OSTask *pTask = (OSTask *)(UNCACHED(g_pu8SpMemBase + 0x0FC0));
#else
OSTask *pTask = (OSTask *)(g_pu8SpMemBase + 0x0FC0);
#endif

// Only detect ABI once per game
if (!bAudioChanged) {
Expand Down
72 changes: 68 additions & 4 deletions Source/HLEAudio/Plugin/PSP/AudioPluginPSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ bool InitialiseMediaEngine()

#endif

#define AUDIO_CHANNELS 2
#define PSP_SAMPLE_RATE 44100 // Hardware sample rate
#define RSP_AUDIO_INTR_CYCLES 1
extern u32 gSoundSync;

Expand All @@ -115,6 +117,7 @@ class AudioPluginPSP : public CAudioPlugin

virtual void DacrateChanged( int system_type );
virtual void LenChanged();
virtual void LenChangedME();
virtual u32 ReadLength() {return 0;}
virtual EProcessResult ProcessAList();

Expand All @@ -139,44 +142,84 @@ class AudioPluginPSP : public CAudioPlugin

static AudioPluginPSP * ac;

s32 mSemaphorethree = sceKernelCreateSema( "pspMEbuffer", 0, 1, 1, nullptr );

s32 mSemaphoretwo = sceKernelCreateSema( "pspMEaudio", 0, 1, 1, nullptr );

s32 mSemaphore = sceKernelCreateSema( "AudioPluginPSP", 0, 1, 1, nullptr );

bool audiothreadactive = false;
bool bufferthreadactive = false;
bool hleworkdone = true;

static int audioOutput(SceSize args, void *argp)
{
while(audiothreadactive == true){

sceKernelWaitSema( mSemaphoretwo, 1, nullptr );

sceKernelDcacheWritebackInvalidateAll();

sceKernelDcacheInvalidateRange((void *)mei, sizeof(me_struct));
asm("sync");

BeginME( mei, (int)&Audio_Ucode, (int)NULL, -1, NULL, -1, NULL);

while (CheckME(mei)) {
while (CheckME(mei) != 1) {
sceKernelDcacheInvalidateRange((void *)mei, sizeof(me_struct));
sceKernelDelayThread(100); // Yield to other threads to avoid 100% CPU usage
}

hleworkdone = true;


}

return 0;


}

static int audiobuffer(SceSize args, void *argp)
{
while(bufferthreadactive == true){

sceKernelWaitSema( mSemaphorethree, 1, nullptr );

sceKernelDcacheInvalidateRange((void *)mei, sizeof(me_struct));
asm("sync");

while (CheckME(mei) != 1 && hleworkdone == false) {
sceKernelDcacheInvalidateRange((void *)mei, sizeof(me_struct));
sceKernelDelayThread(100); // Yield to other threads to avoid 100% CPU usage
}

sceKernelWaitSema( mSemaphore, 1, nullptr );

gAudioPlugin->LenChangedME();

sceKernelSignalSema( mSemaphore, 1 );

}

return 0;


}

int audioThid = sceKernelCreateThread("audioOutput", audioOutput, 0x15, 0x1800, PSP_THREAD_ATTR_USER, NULL);

int BufferThid = sceKernelCreateThread("audiobuffer", audiobuffer, 0x15, 0x1800, PSP_THREAD_ATTR_USER, NULL);

void AudioPluginPSP::FillBuffer(Sample * buffer, u32 num_samples)
{

sceKernelWaitSema( mSemaphore, 1, nullptr );

dcache_inv_range( mAudioBuffer, sizeof( CAudioBuffer ) );

mAudioBufferUncached->Drain( buffer, num_samples );

dcache_wbinv_range_unaligned( mAudioBuffer, mAudioBuffer+sizeof( CAudioBuffer ) );

sceKernelSignalSema( mSemaphore, 1 );

Expand Down Expand Up @@ -245,11 +288,11 @@ DBGConsole_Msg(0, "Audio frequency: %d", frequency);
mFrequency = frequency;
}


void AudioPluginPSP::LenChanged()
void AudioPluginPSP::LenChangedME()
{
if( gAudioPluginEnabled > APM_DISABLED )
{

u32 address = Memory_AI_GetRegister(AI_DRAM_ADDR_REG) & 0xFFFFFF;
u32 length = Memory_AI_GetRegister(AI_LEN_REG);

Expand All @@ -262,6 +305,25 @@ void AudioPluginPSP::LenChanged()
}


void AudioPluginPSP::LenChanged()
{
if( gAudioPluginEnabled > APM_DISABLED )
{

if(bufferthreadactive == false){
bufferthreadactive = true;
sceKernelStartThread(BufferThid, 0, NULL);
}

sceKernelSignalSema( mSemaphorethree, 1 );
}
else
{
StopAudio();
}
}


EProcessResult AudioPluginPSP::ProcessAList()
{
Memory_SP_SetRegisterBits(SP_STATUS_REG, SP_STATUS_HALT);
Expand All @@ -276,6 +338,8 @@ EProcessResult AudioPluginPSP::ProcessAList()
case APM_ENABLED_ASYNC:
{
//signal the audio thread to kick off a audioucode HLE task.
hleworkdone = false;
sceKernelDcacheWritebackAll();
sceKernelSignalSema( mSemaphoretwo, 1 );
if(audiothreadactive == false){
audiothreadactive = true;
Expand Down
1 change: 1 addition & 0 deletions Source/Math/Math.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef MATH_MATH_H_
#define MATH_MATH_H_

#include "Base/Types.h"
#include <math.h>
#include <utility>

Expand Down

0 comments on commit 7b53727

Please sign in to comment.