Skip to content

Commit

Permalink
Audio plugin changes for SDL2
Browse files Browse the repository at this point in the history
*Added SDL2 thread async
*fixed bug that prevented linux audio from working.
  • Loading branch information
z2442 committed Aug 17, 2024
1 parent 8072b78 commit 3784886
Showing 1 changed file with 105 additions and 99 deletions.
204 changes: 105 additions & 99 deletions Source/HLEAudio/Plugin/SDL/AudioPluginSDL.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#include <SDL2/SDL.h>



#include "Base/Types.h"
#include "Interface/ConfigOptions.h"
#include "Utility/FramerateLimiter.h"
Expand All @@ -10,118 +8,117 @@
#include "HLEAudio/AudioPlugin.h"
#include "HLEAudio/HLEAudioInternal.h"
#include "System/Timing.h"
#include <pthread.h>

EAudioPluginMode gAudioPluginEnabled = APM_ENABLED_ASYNC;

pthread_t Asyncthread;
int Asyncthreadreturn;
SDL_Thread* Asyncthread = nullptr;
int Asyncthreadreturn;

void* Audio_UcodeEntry(void* arg) {
Audio_Ucode();
return nullptr;
}

SDL_AudioDeviceID audio_device;
SDL_AudioDeviceID audio_device = 0;

struct Sample {
s16 L;
s16 R;
s16 L;
s16 R;
};

class AudioPluginSDL : public CAudioPlugin
{
public:
AudioPluginSDL();
virtual ~AudioPluginSDL();
AudioPluginSDL();
virtual ~AudioPluginSDL();

virtual bool StartEmulation();
virtual void StopEmulation();
virtual bool StartEmulation();
virtual void StopEmulation();

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

void AddBuffer(void * ptr, u32 length); // Uploads a new buffer and returns status
void StopAudio(); // Stops the Audio PlayBack (as if paused)
void StartAudio(); // Starts the Audio PlayBack (as if unpaused)
void AddBuffer(void * ptr, u32 length); // Uploads a new buffer and returns status
void StopAudio(); // Stops the Audio PlayBack (as if paused)
void StartAudio(); // Starts the Audio PlayBack (as if unpaused)

static void AudioSyncFunction(void * arg);
static int AudioThread(void * arg);
static void AudioSyncFunction(void * arg);
static int AudioThread(void * arg);

private:
u32 mFrequency;
SDL_Thread* mAudioThread;
u32 mFrequency;
SDL_Thread* mAudioThread;
};

AudioPluginSDL::AudioPluginSDL()
: mFrequency( 44100 )
: mFrequency(44100), mAudioThread(nullptr)
{}

AudioPluginSDL::~AudioPluginSDL()
{
StopAudio();
StopAudio();
}

bool AudioPluginSDL::StartEmulation()
{
return true;
return true;
}

void AudioPluginSDL::StopEmulation()
{
Audio_Reset();
StopAudio();
Audio_Reset();
StopAudio();
}

void AudioPluginSDL::DacrateChanged(int system_type)
{
u32 clock = (system_type == ST_NTSC) ? VI_NTSC_CLOCK : VI_PAL_CLOCK;
u32 dacrate = Memory_AI_GetRegister(AI_DACRATE_REG);
u32 frequency = clock / (dacrate + 1);
u32 clock = (system_type == ST_NTSC) ? VI_NTSC_CLOCK : VI_PAL_CLOCK;
u32 dacrate = Memory_AI_GetRegister(AI_DACRATE_REG);
u32 frequency = clock / (dacrate + 1);

mFrequency = frequency;
mFrequency = frequency;
}

void AudioPluginSDL::LenChanged()
{
if (gAudioPluginEnabled > APM_DISABLED)
{
u32 address = Memory_AI_GetRegister(AI_DRAM_ADDR_REG) & 0xFFFFFF;
u32 length = Memory_AI_GetRegister(AI_LEN_REG);
if (gAudioPluginEnabled > APM_DISABLED)
{
u32 address = Memory_AI_GetRegister(AI_DRAM_ADDR_REG) & 0xFFFFFF;
u32 length = Memory_AI_GetRegister(AI_LEN_REG);

AddBuffer( g_pu8RamBase + address, length );
}
AddBuffer(g_pu8RamBase + address, length);
}
}

EProcessResult AudioPluginSDL::ProcessAList()
{
Memory_SP_SetRegisterBits(SP_STATUS_REG, SP_STATUS_HALT);

EProcessResult result = PR_NOT_STARTED;

switch (gAudioPluginEnabled)
{
case APM_DISABLED:
result = PR_COMPLETED;
break;
case APM_ENABLED_ASYNC:
#ifdef APPLE
Asyncthreadreturn = pthread_create(&Asyncthread, NULL, &Audio_UcodeEntry, (void*)nullptr);
result = PR_COMPLETED;
#else
Audio_Ucode();
Memory_SP_SetRegisterBits(SP_STATUS_REG, SP_STATUS_HALT);

EProcessResult result = PR_NOT_STARTED;

switch (gAudioPluginEnabled)
{
case APM_DISABLED:
result = PR_COMPLETED;
break;
case APM_ENABLED_ASYNC:
Asyncthread = SDL_CreateThread((SDL_ThreadFunction)Audio_UcodeEntry, "Audio_UcodeThread", nullptr);
if (Asyncthread == nullptr) {
DBGConsole_Msg(0, "Failed to create Async thread", SDL_GetError());
} else {
SDL_DetachThread(Asyncthread);
}
result = PR_COMPLETED;
#endif
break;
case APM_ENABLED_SYNC:
Audio_Ucode();
result = PR_COMPLETED;
break;
}

return result;
break;
case APM_ENABLED_SYNC:
Audio_Ucode();
result = PR_COMPLETED;
break;
}

return result;
}

void AudioPluginSDL::AddBuffer(void * ptr, u32 length)
Expand All @@ -132,67 +129,76 @@ void AudioPluginSDL::AddBuffer(void * ptr, u32 length)
if (mAudioThread == nullptr)
StartAudio();

if (audio_device == 0) {
DBGConsole_Msg(0, "Audio device not initialized");
return;
}

u32 num_samples = length / sizeof(Sample);

// Queue the samples into SDL's audio buffer
if(SDL_QueueAudio(audio_device, ptr, num_samples * sizeof(Sample)) != 0) {
if (SDL_QueueAudio(audio_device, ptr, num_samples * sizeof(Sample)) != 0) {
DBGConsole_Msg(0, "SDL_QueueAudio error: %s", SDL_GetError());
return;
}
}

int AudioPluginSDL::AudioThread(void * arg)
{
AudioPluginSDL * plugin = static_cast< AudioPluginSDL *>(arg);

SDL_AudioSpec audio_spec;
SDL_zero(audio_spec);
audio_spec.freq = 44100;
audio_spec.format = AUDIO_S16SYS;
audio_spec.channels = 2;
audio_spec.samples = 4096;
audio_spec.callback = NULL;
audio_spec.userdata = plugin;

audio_device = SDL_OpenAudioDevice(
NULL, 0, &audio_spec, NULL, 0);

SDL_QueueAudio(0, &audio_spec, 4096);
AudioPluginSDL * plugin = static_cast<AudioPluginSDL *>(arg);

SDL_AudioSpec audio_spec;
SDL_zero(audio_spec);
audio_spec.freq = plugin->mFrequency;
audio_spec.format = AUDIO_S16SYS;
audio_spec.channels = 2;
audio_spec.samples = 4096;
audio_spec.callback = NULL;
audio_spec.userdata = plugin;

audio_device = SDL_OpenAudioDevice(NULL, 0, &audio_spec, NULL, 0);
if (audio_device == 0) {
DBGConsole_Msg(0, "Failed to open audio: %s", SDL_GetError());
return -1;
}

SDL_PauseAudioDevice(audio_device, 0);
SDL_PauseAudioDevice(audio_device, 0);

return 0;
return 0;
}

void AudioPluginSDL::StartAudio()
{
mAudioThread = SDL_CreateThread(&AudioThread, "Audio", this);
if (mAudioThread == nullptr)
{
DBGConsole_Msg(0, "Failed to start the audio thread!");
FramerateLimiter_SetAuxillarySyncFunction(nullptr, nullptr);
}
mAudioThread = SDL_CreateThread(&AudioThread, "Audio", this);

if (mAudioThread == nullptr)
{
DBGConsole_Msg(0, "Failed to start the audio thread!");
FramerateLimiter_SetAuxillarySyncFunction(nullptr, nullptr);
}
}

void AudioPluginSDL::StopAudio()
{
if (mAudioThread == nullptr)
return;
if (mAudioThread == nullptr)
return;

if (mAudioThread != nullptr)
{
int threadReturnValue;
SDL_WaitThread(mAudioThread, &threadReturnValue);
mAudioThread = nullptr;
}
if (mAudioThread != nullptr)
{
int threadReturnValue;
SDL_WaitThread(mAudioThread, &threadReturnValue);
mAudioThread = nullptr;
}

// Clear the remaining audio data in SDL's audio buffer
SDL_ClearQueuedAudio(audio_device);
SDL_CloseAudioDevice(audio_device);
if (audio_device != 0) {
SDL_ClearQueuedAudio(audio_device);
SDL_CloseAudioDevice(audio_device);
audio_device = 0;
}
}

std::unique_ptr<CAudioPlugin> CreateAudioPlugin()
{
return std::make_unique<AudioPluginSDL>();
}
return std::make_unique<AudioPluginSDL>();
}

0 comments on commit 3784886

Please sign in to comment.