diff --git a/rpcs3/Emu/Audio/AL/OpenALBackend.cpp b/rpcs3/Emu/Audio/AL/OpenALBackend.cpp index ed6ff6726e..3c6c7a0878 100644 --- a/rpcs3/Emu/Audio/AL/OpenALBackend.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALBackend.cpp @@ -118,7 +118,7 @@ void OpenALBackend::Close() } } -bool OpenALBackend::AddData(const void* src, u32 size) +bool OpenALBackend::AddData(const void* src, u32 num_samples) { AUDIT(alIsSource(m_source)); @@ -133,7 +133,7 @@ bool OpenALBackend::AddData(const void* src, u32 size) } // Copy data to the next available buffer - alBufferData(m_buffers[m_next_buffer], m_format, src, size * m_sample_size, m_sampling_rate); + alBufferData(m_buffers[m_next_buffer], m_format, src, num_samples * m_sample_size, m_sampling_rate); checkForAlError("AddData->alBufferData"); // Enqueue buffer @@ -186,7 +186,7 @@ u64 OpenALBackend::GetNumEnqueuedSamples() ALint num_queued; alGetSourcei(m_source, AL_BUFFERS_QUEUED, &num_queued); checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_BUFFERS_QUEUED)"); - AUDIT(num_queued <= m_num_buffers - m_num_unqueued); + AUDIT(static_cast(num_queued) <= m_num_buffers - m_num_unqueued); // Get sample position ALint sample_pos; diff --git a/rpcs3/Emu/Audio/AL/OpenALBackend.h b/rpcs3/Emu/Audio/AL/OpenALBackend.h index 895252c84e..f3c27e94ec 100644 --- a/rpcs3/Emu/Audio/AL/OpenALBackend.h +++ b/rpcs3/Emu/Audio/AL/OpenALBackend.h @@ -26,7 +26,7 @@ public: virtual const char* GetName() const override { return "OpenAL"; }; - static const u32 capabilities = NON_BLOCKING | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO; + static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO; virtual u32 GetCapabilities() const override { return capabilities; }; virtual void Open(u32 num_buffers) override; diff --git a/rpcs3/Emu/Audio/ALSA/ALSAThread.cpp b/rpcs3/Emu/Audio/ALSA/ALSABackend.cpp similarity index 77% rename from rpcs3/Emu/Audio/ALSA/ALSAThread.cpp rename to rpcs3/Emu/Audio/ALSA/ALSABackend.cpp index 4302dc1e44..52795585ed 100644 --- a/rpcs3/Emu/Audio/ALSA/ALSAThread.cpp +++ b/rpcs3/Emu/Audio/ALSA/ALSABackend.cpp @@ -1,15 +1,10 @@ #include "stdafx.h" #include "Emu/System.h" -#include "ALSAThread.h" +#include "ALSABackend.h" #ifdef HAVE_ALSA -#include - -static thread_local snd_pcm_t* s_tls_handle{nullptr}; -static thread_local snd_pcm_hw_params_t* s_tls_hw_params{nullptr}; -static thread_local snd_pcm_sw_params_t* s_tls_sw_params{nullptr}; static void error(int err, const char* reason) { @@ -27,7 +22,19 @@ static bool check(int err, const char* reason) return true; } -ALSAThread::ALSAThread() +ALSABackend::ALSABackend() +{ +} + +ALSABackend::~ALSABackend() +{ + if (s_tls_sw_params || s_tls_hw_params || s_tls_handle) + { + Close(); + } +} + +void ALSABackend::Open(u32 num_buffers) { if (!check(snd_pcm_open(&s_tls_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), "snd_pcm_open")) return; @@ -44,11 +51,11 @@ ALSAThread::ALSAThread() if (!check(snd_pcm_hw_params_set_format(s_tls_handle, s_tls_hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format")) return; - uint rate = 48000; + uint rate = get_sampling_rate(); if (!check(snd_pcm_hw_params_set_rate_near(s_tls_handle, s_tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near")) return; - if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, s_tls_hw_params, g_cfg.audio.downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels")) + if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, s_tls_hw_params, get_channels()), "snd_pcm_hw_params_set_channels")) return; //uint period = 5333; @@ -58,8 +65,8 @@ ALSAThread::ALSAThread() //if (!check(snd_pcm_hw_params_set_periods(s_tls_handle, s_tls_hw_params, 4, 0), "snd_pcm_hw_params_set_periods")) // return; - snd_pcm_uframes_t bufsize_frames = g_cfg.audio.frames * 256; - snd_pcm_uframes_t period_frames = 256; + snd_pcm_uframes_t bufsize_frames = num_buffers * AUDIO_BUFFER_SAMPLES; + snd_pcm_uframes_t period_frames = AUDIO_BUFFER_SAMPLES; if (!check(snd_pcm_hw_params_set_buffer_size_near(s_tls_handle, s_tls_hw_params, &bufsize_frames), "snd_pcm_hw_params_set_buffer_size_near")) return; @@ -84,7 +91,7 @@ ALSAThread::ALSAThread() period_frames *= g_cfg.audio.startt; - if (!check(snd_pcm_sw_params_set_start_threshold(s_tls_handle, s_tls_sw_params, period_frames), "snd_pcm_sw_params_set_start_threshold")) + if (!check(snd_pcm_sw_params_set_start_threshold(s_tls_handle, s_tls_sw_params, period_frames + 1), "snd_pcm_sw_params_set_start_threshold")) return; if (!check(snd_pcm_sw_params_set_stop_threshold(s_tls_handle, s_tls_sw_params, bufsize_frames), "snd_pcm_sw_params_set_stop_threshold")) @@ -99,52 +106,37 @@ ALSAThread::ALSAThread() LOG_NOTICE(GENERAL, "ALSA: bufsize_frames=%u, period_frames=%u", bufsize_frames, period_frames); } -ALSAThread::~ALSAThread() +void ALSABackend::Close() { if (s_tls_sw_params) { snd_pcm_sw_params_free(s_tls_sw_params); + s_tls_sw_params = nullptr; } if (s_tls_hw_params) { snd_pcm_hw_params_free(s_tls_hw_params); + s_tls_hw_params = nullptr; } if (s_tls_handle) { snd_pcm_close(s_tls_handle); + s_tls_handle = nullptr; } } -void ALSAThread::Play() +bool ALSABackend::AddData(const void* src, u32 num_samples) { -} + u32 num_frames = num_samples / get_channels(); -void ALSAThread::Close() -{ -} - -void ALSAThread::Stop() -{ -} - -void ALSAThread::Open(const void* src, int size) -{ - AddData(src, size); -} - -void ALSAThread::AddData(const void* src, int size) -{ - size /= g_cfg.audio.convert_to_u16 ? 2 : 4; - size /= g_cfg.audio.downmix_to_2ch ? 2 : 8; - - int res = snd_pcm_writei(s_tls_handle, src, size); + int res = snd_pcm_writei(s_tls_handle, src, num_frames); if (res == -EAGAIN) { LOG_WARNING(GENERAL, "ALSA: EAGAIN"); - return; + return false; } if (res < 0) @@ -154,16 +146,19 @@ void ALSAThread::AddData(const void* src, int size) if (res < 0) { LOG_WARNING(GENERAL, "ALSA: failed to recover (%d)", res); - return; + return false; } - res = snd_pcm_writei(s_tls_handle, src, size); + res = snd_pcm_writei(s_tls_handle, src, num_frames); } - if (res != size) + if (res != num_frames) { LOG_WARNING(GENERAL, "ALSA: error (%d)", res); + return false; } + + return true; } #endif diff --git a/rpcs3/Emu/Audio/ALSA/ALSABackend.h b/rpcs3/Emu/Audio/ALSA/ALSABackend.h new file mode 100644 index 0000000000..ed46bd09a7 --- /dev/null +++ b/rpcs3/Emu/Audio/ALSA/ALSABackend.h @@ -0,0 +1,30 @@ +#pragma once + +#ifdef HAVE_ALSA + +#include "Emu/Audio/AudioBackend.h" + +#include + +class ALSABackend : public AudioBackend +{ + snd_pcm_t* s_tls_handle{nullptr}; + snd_pcm_hw_params_t* s_tls_hw_params{nullptr}; + snd_pcm_sw_params_t* s_tls_sw_params{nullptr}; + +public: + ALSABackend(); + virtual ~ALSABackend() override; + + virtual const char* GetName() const override { return "ALSA"; }; + + static const u32 capabilities = 0; + virtual u32 GetCapabilities() const override { return capabilities; }; + + virtual void Open(u32) override; + virtual void Close() override; + + virtual bool AddData(const void* src, u32 num_samples) override; +}; + +#endif diff --git a/rpcs3/Emu/Audio/ALSA/ALSAThread.h b/rpcs3/Emu/Audio/ALSA/ALSAThread.h deleted file mode 100644 index 14f4ce40d5..0000000000 --- a/rpcs3/Emu/Audio/ALSA/ALSAThread.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#ifdef HAVE_ALSA - -#include "Emu/Audio/AudioThread.h" - -class ALSAThread : public AudioBackend -{ -public: - ALSAThread(); - virtual ~ALSAThread() override; - - virtual void Play() override; - virtual void Open(const void* src, int size) override; - virtual void Close() override; - virtual void Stop() override; - virtual void AddData(const void* src, int size) override; -}; - -#endif diff --git a/rpcs3/Emu/Audio/AudioBackend.h b/rpcs3/Emu/Audio/AudioBackend.h index 3aa1968ea6..ef334f9569 100644 --- a/rpcs3/Emu/Audio/AudioBackend.h +++ b/rpcs3/Emu/Audio/AudioBackend.h @@ -15,45 +15,80 @@ class AudioBackend public: enum Capabilities : u32 { - NON_BLOCKING = 0x1, - IS_PLAYING = 0x2, - GET_NUM_ENQUEUED_SAMPLES = 0x4, - SET_FREQUENCY_RATIO = 0x8, + PLAY_PAUSE_FLUSH = 0x1, // AddData implements Play, Pause, Flush + IS_PLAYING = 0x2, // Implements IsPlaying method + GET_NUM_ENQUEUED_SAMPLES = 0x4, // Supports GetNumEnqueuedSamples method + SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio method }; virtual ~AudioBackend() = default; - // Callbacks + /* + * Pure virtual methods + */ virtual const char* GetName() const = 0; virtual u32 GetCapabilities() const = 0; virtual void Open(u32 num_buffers) = 0; virtual void Close() = 0; - virtual void Play() = 0; - virtual void Pause() = 0; + virtual bool AddData(const void* src, u32 num_samples) = 0; + + /* + * Virtual methods - should be implemented depending on backend capabilities + */ + + // Start playing enqueued data + // Should be implemented if capabilities & PLAY_PAUSE_FLUSH + virtual void Play() + { + fmt::throw_exception("Play() not implemented"); + } + + // Pause playing enqueued data + // Should be implemented if capabilities & PLAY_PAUSE_FLUSH + virtual void Pause() + { + fmt::throw_exception("Pause() not implemented"); + } + + // Pause audio, and unqueue all currently queued buffers + // Should be implemented if capabilities & PLAY_PAUSE_FLUSH + virtual void Flush() + { + + fmt::throw_exception("Flush() not implemented"); + } + + // Returns true if audio is currently being played, false otherwise + // Should be implemented if capabilities & IS_PLAYING virtual bool IsPlaying() { fmt::throw_exception("IsPlaying() not implemented"); - }; - - virtual bool AddData(const void* src, u32 size) = 0; - virtual void Flush() = 0; + } + // Returns the number of currently enqueued samples + // Should be implemented if capabilities & GET_NUM_ENQUEUED_SAMPLES virtual u64 GetNumEnqueuedSamples() { fmt::throw_exception("GetNumEnqueuedSamples() not implemented"); return 0; } + // Sets a new frequency ratio. Backend is allowed to modify the ratio value, e.g. clamping it to the allowed range + // Returns the new frequency ratio set + // Should be implemented if capabilities & SET_FREQUENCY_RATIO virtual f32 SetFrequencyRatio(f32 /* new_ratio */) // returns the new ratio { fmt::throw_exception("SetFrequencyRatio() not implemented"); return 1.0f; } - // Helper methods + + /* + * Helper methods + */ static u32 get_sampling_rate() { const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier; @@ -76,9 +111,9 @@ public: return g_cfg.audio.downmix_to_2ch ? 2 : 8; } - bool has_capability(Capabilities cap) const + bool has_capability(u32 cap) const { - return (cap & GetCapabilities()) != 0; + return (cap & GetCapabilities()) == cap; } void dump_capabilities(std::string& out) const @@ -86,9 +121,9 @@ public: u32 count = 0; u32 capabilities = GetCapabilities(); - if (capabilities & NON_BLOCKING) + if (capabilities & PLAY_PAUSE_FLUSH) { - fmt::append(out, "NON_BLOCKING"); + fmt::append(out, "PLAY_PAUSE_FLUSH"); count++; } diff --git a/rpcs3/Emu/Audio/Null/NullAudioBackend.h b/rpcs3/Emu/Audio/Null/NullAudioBackend.h index 28c63eaaa3..3a097f7f25 100644 --- a/rpcs3/Emu/Audio/Null/NullAudioBackend.h +++ b/rpcs3/Emu/Audio/Null/NullAudioBackend.h @@ -10,7 +10,7 @@ public: virtual const char* GetName() const override { return "Null"; } - static const u32 capabilities = NON_BLOCKING; + static const u32 capabilities = PLAY_PAUSE_FLUSH; virtual u32 GetCapabilities() const override { return capabilities; }; virtual void Open(u32) override {}; diff --git a/rpcs3/Emu/Audio/Pulse/PulseThread.cpp b/rpcs3/Emu/Audio/Pulse/PulseBackend.cpp similarity index 65% rename from rpcs3/Emu/Audio/Pulse/PulseThread.cpp rename to rpcs3/Emu/Audio/Pulse/PulseBackend.cpp index 8ad34120a2..aa4d6f7049 100644 --- a/rpcs3/Emu/Audio/Pulse/PulseThread.cpp +++ b/rpcs3/Emu/Audio/Pulse/PulseBackend.cpp @@ -1,25 +1,21 @@ #include "Emu/System.h" -#include "PulseThread.h" +#include "PulseBackend.h" #ifdef HAVE_PULSE #include #include -PulseThread::PulseThread() +PulseBackend::PulseBackend() { } -PulseThread::~PulseThread() +PulseBackend::~PulseBackend() { this->Close(); } -void PulseThread::Play() -{ -} - -void PulseThread::Close() +void PulseBackend::Close() { if(this->connection) { pa_simple_free(this->connection); @@ -27,19 +23,15 @@ void PulseThread::Close() } } -void PulseThread::Stop() -{ -} - -void PulseThread::Open(const void* src, int size) +void PulseBackend::Open(u32 /* num_buffers */) { pa_sample_spec ss; - ss.format = g_cfg.audio.convert_to_u16 ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE; - ss.rate = 48000; + ss.format = (get_sample_size() == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE; + ss.rate = get_sampling_rate(); pa_channel_map channel_map; - if (g_cfg.audio.downmix_to_2ch) + if (get_channels() == 2) { channel_map.channels = 2; channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; @@ -64,18 +56,19 @@ void PulseThread::Open(const void* src, int size) if(!this->connection) { fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err)); } - - this->AddData(src, size); } -void PulseThread::AddData(const void* src, int size) +bool PulseBackend::AddData(const void* src, u32 num_samples) { - if(this->connection) { - int err; - if(pa_simple_write(this->connection, src, size, &err) < 0) { - fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err)); - } + AUDIT(this->connection); + + int err; + if(pa_simple_write(this->connection, src, num_samples * get_sample_size(), &err) < 0) { + fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err)); + return false; } + + return true; } #endif diff --git a/rpcs3/Emu/Audio/Pulse/PulseBackend.h b/rpcs3/Emu/Audio/Pulse/PulseBackend.h new file mode 100644 index 0000000000..27c324ddc4 --- /dev/null +++ b/rpcs3/Emu/Audio/Pulse/PulseBackend.h @@ -0,0 +1,27 @@ +#pragma once + +#ifdef HAVE_PULSE +#include +#include "Emu/Audio/AudioBackend.h" + +class PulseBackend : public AudioBackend +{ +public: + PulseBackend(); + virtual ~PulseBackend() override; + + virtual const char* GetName() const override { return "Pulse"; }; + + static const u32 capabilities = 0; + virtual u32 GetCapabilities() const override { return capabilities; }; + + virtual void Open(u32) override; + virtual void Close() override; + + virtual bool AddData(const void* src, u32 num_samples) override; + +private: + pa_simple *connection = nullptr; +}; + +#endif diff --git a/rpcs3/Emu/Audio/Pulse/PulseThread.h b/rpcs3/Emu/Audio/Pulse/PulseThread.h deleted file mode 100644 index 94dda9e8e2..0000000000 --- a/rpcs3/Emu/Audio/Pulse/PulseThread.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#ifdef HAVE_PULSE -#include -#include "Emu/Audio/AudioThread.h" - -class PulseThread : public AudioBackend -{ -public: - PulseThread(); - virtual ~PulseThread() override; - - virtual void Play() override; - virtual void Open(const void* src, int size) override; - virtual void Close() override; - virtual void Stop() override; - virtual void AddData(const void* src, int size) override; - -private: - pa_simple *connection = nullptr; -}; - -#endif diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio27Backend.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio27Backend.cpp index 4d31d8eb76..9767a7a91c 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio27Backend.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio27Backend.cpp @@ -7,189 +7,197 @@ #include "XAudio2Backend.h" #include "3rdparty/XAudio2_7/XAudio2.h" -static thread_local HMODULE s_tls_xaudio2_lib{}; -static thread_local IXAudio2* s_tls_xaudio2_instance{}; -static thread_local IXAudio2MasteringVoice* s_tls_master_voice{}; -static thread_local IXAudio2SourceVoice* s_tls_source_voice{}; - -void XAudio2Backend::xa27_init(void* lib2_7) +class XAudio27Library : public XAudio2Backend::XAudio2Library { - s_tls_xaudio2_lib = (HMODULE)lib2_7; + const HMODULE s_tls_xaudio2_lib; + IXAudio2* s_tls_xaudio2_instance{}; + IXAudio2MasteringVoice* s_tls_master_voice{}; + IXAudio2SourceVoice* s_tls_source_voice{}; - HRESULT hr = S_OK; - - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if (FAILED(hr)) +public: + XAudio27Library(void* lib2_7) + : s_tls_xaudio2_lib(static_cast(lib2_7)) { - LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return; - } + HRESULT hr = S_OK; - hr = XAudio2Create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return; + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + hr = XAudio2Create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr); + s_tls_xaudio2_instance->Release(); + Emu.Pause(); + } } - hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000); - if (FAILED(hr)) + ~XAudio27Library() { - LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr); - s_tls_xaudio2_instance->Release(); - Emu.Pause(); - } -} + if (s_tls_source_voice != nullptr) + { + s_tls_source_voice->Stop(); + s_tls_source_voice->DestroyVoice(); + } -void XAudio2Backend::xa27_destroy() + if (s_tls_master_voice != nullptr) + { + s_tls_master_voice->DestroyVoice(); + } + + if (s_tls_xaudio2_instance != nullptr) + { + s_tls_xaudio2_instance->StopEngine(); + s_tls_xaudio2_instance->Release(); + } + + CoUninitialize(); + + FreeLibrary(s_tls_xaudio2_lib); + } + + virtual void play() override + { + HRESULT hr = s_tls_source_voice->Start(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } + } + + virtual void flush() override + { + HRESULT hr = s_tls_source_voice->FlushSourceBuffers(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } + } + + virtual void stop() override + { + HRESULT hr = s_tls_source_voice->Stop(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } + } + + virtual bool is_playing() override + { + XAUDIO2_VOICE_STATE state; + s_tls_source_voice->GetState(&state); + + return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr; + } + + virtual void open() override + { + HRESULT hr; + + const u32 sample_size = AudioBackend::get_sample_size(); + const u32 channels = AudioBackend::get_channels(); + const u32 sampling_rate = AudioBackend::get_sampling_rate(); + + WAVEFORMATEX waveformatex; + waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; + waveformatex.nChannels = channels; + waveformatex.nSamplesPerSec = sampling_rate; + waveformatex.nAvgBytesPerSec = static_cast(sampling_rate * channels * sample_size); + waveformatex.nBlockAlign = channels * sample_size; + waveformatex.wBitsPerSample = sample_size * 8; + waveformatex.cbSize = 0; + + hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f); + } + + virtual bool add(const void* src, u32 num_samples) override + { + XAUDIO2_VOICE_STATE state; + s_tls_source_voice->GetState(&state); + + // XAudio 2.7 bug workaround, when it says "SimpList: non-growable list ran out of room for new elements" and hits int 3 + if (state.BuffersQueued >= MAX_AUDIO_BUFFERS) + { + LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed); + return false; + } + + XAUDIO2_BUFFER buffer; + + buffer.AudioBytes = num_samples * AudioBackend::get_sample_size(); + buffer.Flags = 0; + buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION; + buffer.LoopCount = 0; + buffer.LoopLength = 0; + buffer.pAudioData = (const BYTE*)src; + buffer.pContext = 0; + buffer.PlayBegin = 0; + buffer.PlayLength = AUDIO_BUFFER_SAMPLES; + + HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return false; + } + + return true; + } + + virtual u64 enqueued_samples() override + { + XAUDIO2_VOICE_STATE state; + s_tls_source_voice->GetState(&state); + + // all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining + return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES); + } + + virtual f32 set_freq_ratio(f32 new_ratio) override + { + new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO); + + HRESULT hr = s_tls_source_voice->SetFrequencyRatio(new_ratio); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : SetFrequencyRatio() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return 1.0f; + } + + return new_ratio; + } +}; + +XAudio2Backend::XAudio2Library* XAudio2Backend::xa27_init(void* lib2_7) { - if (s_tls_source_voice != nullptr) - { - s_tls_source_voice->Stop(); - s_tls_source_voice->DestroyVoice(); - } - - if (s_tls_master_voice != nullptr) - { - s_tls_master_voice->DestroyVoice(); - } - - if (s_tls_xaudio2_instance != nullptr) - { - s_tls_xaudio2_instance->StopEngine(); - s_tls_xaudio2_instance->Release(); - } - - CoUninitialize(); - - FreeLibrary(s_tls_xaudio2_lib); -} - -void XAudio2Backend::xa27_play() -{ - HRESULT hr = s_tls_source_voice->Start(); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr); - Emu.Pause(); - } -} - -void XAudio2Backend::xa27_flush() -{ - HRESULT hr = s_tls_source_voice->FlushSourceBuffers(); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr); - Emu.Pause(); - } -} - -void XAudio2Backend::xa27_stop() -{ - HRESULT hr = s_tls_source_voice->Stop(); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr); - Emu.Pause(); - } -} - -bool XAudio2Backend::xa27_is_playing() -{ - XAUDIO2_VOICE_STATE state; - s_tls_source_voice->GetState(&state); - - return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr; -} - -void XAudio2Backend::xa27_open() -{ - HRESULT hr; - - const u32 sample_size = get_sample_size(); - const u32 channels = get_channels(); - const u32 sampling_rate = get_sampling_rate(); - - WAVEFORMATEX waveformatex; - waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; - waveformatex.nChannels = channels; - waveformatex.nSamplesPerSec = sampling_rate; - waveformatex.nAvgBytesPerSec = static_cast(sampling_rate * channels * sample_size); - waveformatex.nBlockAlign = channels * sample_size; - waveformatex.wBitsPerSample = sample_size * 8; - waveformatex.cbSize = 0; - - hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return; - } - - s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f); -} - -bool XAudio2Backend::xa27_add(const void* src, u32 size) -{ - XAUDIO2_VOICE_STATE state; - s_tls_source_voice->GetState(&state); - - // XAudio 2.7 bug workaround, when it says "SimpList: non-growable list ran out of room for new elements" and hits int 3 - if (state.BuffersQueued >= MAX_AUDIO_BUFFERS) - { - LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed); - return false; - } - - XAUDIO2_BUFFER buffer; - - buffer.AudioBytes = size * get_sample_size(); - buffer.Flags = 0; - buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION; - buffer.LoopCount = 0; - buffer.LoopLength = 0; - buffer.pAudioData = (const BYTE*)src; - buffer.pContext = 0; - buffer.PlayBegin = 0; - buffer.PlayLength = AUDIO_BUFFER_SAMPLES; - - HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return false; - } - - return true; -} - -u64 XAudio2Backend::xa27_enqueued_samples() -{ - XAUDIO2_VOICE_STATE state; - s_tls_source_voice->GetState(&state); - - // all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining - return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES); -} - -f32 XAudio2Backend::xa27_set_freq_ratio(f32 new_ratio) -{ - new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO); - - HRESULT hr = s_tls_source_voice->SetFrequencyRatio(new_ratio); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : SetFrequencyRatio() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return 1.0f; - } - - return new_ratio; + return new XAudio27Library(lib2_7); } #endif diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio28Backend.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio28Backend.cpp index 65cc2984e5..8aeb0b1b9a 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio28Backend.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio28Backend.cpp @@ -7,201 +7,209 @@ #include "XAudio2Backend.h" #include "3rdparty/minidx12/Include/xaudio2.h" -static thread_local HMODULE s_tls_xaudio2_lib{}; -static thread_local IXAudio2* s_tls_xaudio2_instance{}; -static thread_local IXAudio2MasteringVoice* s_tls_master_voice{}; -static thread_local IXAudio2SourceVoice* s_tls_source_voice{}; - -void XAudio2Backend::xa28_init(void* lib) +class XAudio28Library : public XAudio2Backend::XAudio2Library { - s_tls_xaudio2_lib = (HMODULE)lib; + const HMODULE s_tls_xaudio2_lib; + IXAudio2* s_tls_xaudio2_instance{}; + IXAudio2MasteringVoice* s_tls_master_voice{}; + IXAudio2SourceVoice* s_tls_source_voice{}; - const auto create = (XAudio2Create)GetProcAddress(s_tls_xaudio2_lib, "XAudio2Create"); - - HRESULT hr = S_OK; - - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if (FAILED(hr)) +public: + XAudio28Library(void* lib2_8) + : s_tls_xaudio2_lib(static_cast(lib2_8)) { - LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return; - } + const auto create = (XAudio2Create)GetProcAddress(s_tls_xaudio2_lib, "XAudio2Create"); - hr = create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return; + HRESULT hr = S_OK; + + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + hr = create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr); + s_tls_xaudio2_instance->Release(); + Emu.Pause(); + } } - hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000); - if (FAILED(hr)) + ~XAudio28Library() { - LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr); - s_tls_xaudio2_instance->Release(); - Emu.Pause(); - } -} + if (s_tls_source_voice != nullptr) + { + s_tls_source_voice->Stop(); + s_tls_source_voice->DestroyVoice(); + } -void XAudio2Backend::xa28_destroy() + if (s_tls_master_voice != nullptr) + { + s_tls_master_voice->DestroyVoice(); + } + + if (s_tls_xaudio2_instance != nullptr) + { + s_tls_xaudio2_instance->StopEngine(); + s_tls_xaudio2_instance->Release(); + } + + CoUninitialize(); + + FreeLibrary(s_tls_xaudio2_lib); + } + + virtual void play() override + { + AUDIT(s_tls_source_voice != nullptr); + + HRESULT hr = s_tls_source_voice->Start(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } + } + + virtual void flush() override + { + AUDIT(s_tls_source_voice != nullptr); + + HRESULT hr = s_tls_source_voice->FlushSourceBuffers(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } + } + + virtual void stop() override + { + AUDIT(s_tls_source_voice != nullptr); + + HRESULT hr = s_tls_source_voice->Stop(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } + } + + virtual bool is_playing() override + { + AUDIT(s_tls_source_voice != nullptr); + + XAUDIO2_VOICE_STATE state; + s_tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED); + + return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr; + } + + virtual void open() override + { + HRESULT hr; + + const u32 sample_size = AudioBackend::get_sample_size(); + const u32 channels = AudioBackend::get_channels(); + const u32 sampling_rate = AudioBackend::get_sampling_rate(); + + WAVEFORMATEX waveformatex; + waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; + waveformatex.nChannels = channels; + waveformatex.nSamplesPerSec = sampling_rate; + waveformatex.nAvgBytesPerSec = static_cast(sampling_rate * channels * sample_size); + waveformatex.nBlockAlign = channels * sample_size; + waveformatex.wBitsPerSample = sample_size * 8; + waveformatex.cbSize = 0; + + hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + AUDIT(s_tls_source_voice != nullptr); + s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f); + } + + virtual bool add(const void* src, u32 num_samples) override + { + AUDIT(s_tls_source_voice != nullptr); + + XAUDIO2_VOICE_STATE state; + s_tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED); + + if (state.BuffersQueued >= MAX_AUDIO_BUFFERS) + { + LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d)", state.BuffersQueued); + return false; + } + + XAUDIO2_BUFFER buffer; + + buffer.AudioBytes = num_samples * AudioBackend::get_sample_size(); + buffer.Flags = 0; + buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION; + buffer.LoopCount = 0; + buffer.LoopLength = 0; + buffer.pAudioData = (const BYTE*)src; + buffer.pContext = 0; + buffer.PlayBegin = 0; + buffer.PlayLength = AUDIO_BUFFER_SAMPLES; + + HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return false; + } + + return true; + } + + virtual u64 enqueued_samples() override + { + XAUDIO2_VOICE_STATE state; + s_tls_source_voice->GetState(&state); + + // all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining + return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES); + } + + virtual f32 set_freq_ratio(f32 new_ratio) override + { + new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO); + + HRESULT hr = s_tls_source_voice->SetFrequencyRatio(new_ratio); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Backend : SetFrequencyRatio() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return 1.0f; + } + + return new_ratio; + } +}; + +XAudio2Backend::XAudio2Library* XAudio2Backend::xa28_init(void* lib2_8) { - if (s_tls_source_voice != nullptr) - { - s_tls_source_voice->Stop(); - s_tls_source_voice->DestroyVoice(); - } - - if (s_tls_master_voice != nullptr) - { - s_tls_master_voice->DestroyVoice(); - } - - if (s_tls_xaudio2_instance != nullptr) - { - s_tls_xaudio2_instance->StopEngine(); - s_tls_xaudio2_instance->Release(); - } - - CoUninitialize(); - - FreeLibrary(s_tls_xaudio2_lib); -} - -void XAudio2Backend::xa28_play() -{ - AUDIT(s_tls_source_voice != nullptr); - - HRESULT hr = s_tls_source_voice->Start(); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr); - Emu.Pause(); - } -} - -void XAudio2Backend::xa28_flush() -{ - AUDIT(s_tls_source_voice != nullptr); - - HRESULT hr = s_tls_source_voice->FlushSourceBuffers(); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr); - Emu.Pause(); - } -} - -void XAudio2Backend::xa28_stop() -{ - AUDIT(s_tls_source_voice != nullptr); - - HRESULT hr = s_tls_source_voice->Stop(); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr); - Emu.Pause(); - } -} - -bool XAudio2Backend::xa28_is_playing() -{ - AUDIT(s_tls_source_voice != nullptr); - - XAUDIO2_VOICE_STATE state; - s_tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED); - - return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr; -} - -void XAudio2Backend::xa28_open() -{ - HRESULT hr; - - const u32 sample_size = get_sample_size(); - const u32 channels = get_channels(); - const u32 sampling_rate = get_sampling_rate(); - - WAVEFORMATEX waveformatex; - waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; - waveformatex.nChannels = channels; - waveformatex.nSamplesPerSec = sampling_rate; - waveformatex.nAvgBytesPerSec = static_cast(sampling_rate * channels * sample_size); - waveformatex.nBlockAlign = channels * sample_size; - waveformatex.wBitsPerSample = sample_size * 8; - waveformatex.cbSize = 0; - - hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return; - } - - AUDIT(s_tls_source_voice != nullptr); - s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f); -} - -bool XAudio2Backend::xa28_add(const void* src, u32 size) -{ - AUDIT(s_tls_source_voice != nullptr); - - XAUDIO2_VOICE_STATE state; - s_tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED); - - if (state.BuffersQueued >= MAX_AUDIO_BUFFERS) - { - LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d)", state.BuffersQueued); - return false; - } - - XAUDIO2_BUFFER buffer; - - buffer.AudioBytes = size * get_sample_size(); - buffer.Flags = 0; - buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION; - buffer.LoopCount = 0; - buffer.LoopLength = 0; - buffer.pAudioData = (const BYTE*)src; - buffer.pContext = 0; - buffer.PlayBegin = 0; - buffer.PlayLength = AUDIO_BUFFER_SAMPLES; - - HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return false; - } - - return true; -} - -u64 XAudio2Backend::xa28_enqueued_samples() -{ - XAUDIO2_VOICE_STATE state; - s_tls_source_voice->GetState(&state); - - // all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining - return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES); -} - -f32 XAudio2Backend::xa28_set_freq_ratio(f32 new_ratio) -{ - new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO); - - HRESULT hr = s_tls_source_voice->SetFrequencyRatio(new_ratio); - if (FAILED(hr)) - { - LOG_ERROR(GENERAL, "XAudio2Backend : SetFrequencyRatio() failed(0x%08x)", (u32)hr); - Emu.Pause(); - return 1.0f; - } - - return new_ratio; + return new XAudio28Library(lib2_8); } #endif diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp index f717d9bd72..35f04b8dbe 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp @@ -8,113 +8,87 @@ XAudio2Backend::XAudio2Backend() { - if (auto lib2_9 = LoadLibraryExW(L"XAudio2_9.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)) - { - // xa28* implementation is fully compatible with library 2.9 - xa28_init(lib2_9); - - m_funcs.destroy = &xa28_destroy; - m_funcs.play = &xa28_play; - m_funcs.flush = &xa28_flush; - m_funcs.stop = &xa28_stop; - m_funcs.open = &xa28_open; - m_funcs.is_playing = &xa28_is_playing; - m_funcs.add = &xa28_add; - m_funcs.enqueued_samples = &xa28_enqueued_samples; - m_funcs.set_freq_ratio = &xa28_set_freq_ratio; - - LOG_SUCCESS(GENERAL, "XAudio 2.9 initialized"); - return; - } - - if (auto lib2_8 = LoadLibraryExW(L"XAudio2_8.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)) - { - xa28_init(lib2_8); - - m_funcs.destroy = &xa28_destroy; - m_funcs.play = &xa28_play; - m_funcs.flush = &xa28_flush; - m_funcs.stop = &xa28_stop; - m_funcs.open = &xa28_open; - m_funcs.is_playing = &xa28_is_playing; - m_funcs.add = &xa28_add; - m_funcs.enqueued_samples = &xa28_enqueued_samples; - m_funcs.set_freq_ratio = &xa28_set_freq_ratio; - - LOG_SUCCESS(GENERAL, "XAudio 2.8 initialized"); - return; - } - - if (auto lib2_7 = LoadLibraryExW(L"XAudio2_7.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)) - { - xa27_init(lib2_7); - - m_funcs.destroy = &xa27_destroy; - m_funcs.play = &xa27_play; - m_funcs.flush = &xa27_flush; - m_funcs.stop = &xa27_stop; - m_funcs.open = &xa27_open; - m_funcs.is_playing = &xa27_is_playing; - m_funcs.add = &xa27_add; - m_funcs.enqueued_samples = &xa27_enqueued_samples; - m_funcs.set_freq_ratio = &xa27_set_freq_ratio; - - LOG_SUCCESS(GENERAL, "XAudio 2.7 initialized"); - return; - } - - fmt::throw_exception("No supported XAudio2 library found"); } XAudio2Backend::~XAudio2Backend() { - m_funcs.destroy(); } void XAudio2Backend::Play() { - m_funcs.play(); + lib->play(); } void XAudio2Backend::Close() { - m_funcs.stop(); - m_funcs.flush(); + lib->stop(); + lib->flush(); } void XAudio2Backend::Pause() { - m_funcs.stop(); + lib->stop(); } void XAudio2Backend::Open(u32 /* num_buffers */) { - m_funcs.open(); + if (lib.get() == nullptr) + { + void* hmodule; + + if (hmodule = LoadLibraryExW(L"XAudio2_9.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)) + { + // XAudio 2.9 uses the same code as XAudio 2.8 + lib.reset(xa28_init(hmodule)); + + LOG_SUCCESS(GENERAL, "XAudio 2.9 initialized"); + } + else if (hmodule = LoadLibraryExW(L"XAudio2_8.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)) + { + // XAudio 2.9 uses the same code as XAudio 2.8 + lib.reset(xa28_init(hmodule)); + + LOG_SUCCESS(GENERAL, "XAudio 2.8 initialized"); + } + else if (hmodule = LoadLibraryExW(L"XAudio2_7.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)) + { + // XAudio 2.9 uses the same code as XAudio 2.8 + lib.reset(xa27_init(hmodule)); + + LOG_SUCCESS(GENERAL, "XAudio 2.7 initialized"); + } + else + { + fmt::throw_exception("No supported XAudio2 library found"); + } + } + + lib->open(); } bool XAudio2Backend::IsPlaying() { - return m_funcs.is_playing(); + return lib->is_playing(); } -bool XAudio2Backend::AddData(const void* src, u32 size) +bool XAudio2Backend::AddData(const void* src, u32 num_samples) { - return m_funcs.add(src, size); + return lib->add(src, num_samples); } void XAudio2Backend::Flush() { - m_funcs.flush(); + lib->flush(); } u64 XAudio2Backend::GetNumEnqueuedSamples() { - return m_funcs.enqueued_samples(); + return lib->enqueued_samples(); } f32 XAudio2Backend::SetFrequencyRatio(f32 new_ratio) { - return m_funcs.set_freq_ratio(new_ratio); + return lib->set_freq_ratio(new_ratio); } #endif diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h index 784e9f6286..5f8aad2afe 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h @@ -4,44 +4,28 @@ #include "Emu/Audio/AudioBackend.h" + class XAudio2Backend : public AudioBackend { - struct vtable +public: + class XAudio2Library { - void(*destroy)(); - void(*play)(); - void(*flush)(); - void(*stop)(); - void(*open)(); - bool(*is_playing)(); - bool(*add)(const void*, u32); - u64(*enqueued_samples)(); - f32(*set_freq_ratio)(f32); + public: + virtual void play() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual void open() = 0; + virtual bool is_playing() = 0; + virtual bool add(const void*, u32) = 0; + virtual u64 enqueued_samples() = 0; + virtual f32 set_freq_ratio(f32) = 0; }; - vtable m_funcs; +private: + static XAudio2Library* xa27_init(void*); + static XAudio2Library* xa28_init(void*); - static void xa27_init(void*); - static void xa27_destroy(); - static void xa27_play(); - static void xa27_flush(); - static void xa27_stop(); - static void xa27_open(); - static bool xa27_is_playing(); - static bool xa27_add(const void*, u32); - static u64 xa27_enqueued_samples(); - static f32 xa27_set_freq_ratio(f32); - - static void xa28_init(void*); - static void xa28_destroy(); - static void xa28_play(); - static void xa28_flush(); - static void xa28_stop(); - static void xa28_open(); - static bool xa28_is_playing(); - static bool xa28_add(const void*, u32); - static u64 xa28_enqueued_samples(); - static f32 xa28_set_freq_ratio(f32); + std::unique_ptr lib = nullptr; public: XAudio2Backend(); @@ -49,7 +33,7 @@ public: virtual const char* GetName() const override { return "XAudio2"; }; - static const u32 capabilities = NON_BLOCKING | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO; + static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO; virtual u32 GetCapabilities() const override { return capabilities; }; virtual void Open(u32 /* num_buffers */) override; @@ -59,7 +43,7 @@ public: virtual void Pause() override; virtual bool IsPlaying() override; - virtual bool AddData(const void* src, u32 size) override; + virtual bool AddData(const void* src, u32 num_samples) override; virtual void Flush() override; virtual u64 GetNumEnqueuedSamples() override; diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index d06c916c43..325af2965d 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -6,6 +6,7 @@ #include "Emu/Cell/lv2/sys_event.h" #include "cellAudio.h" #include +#include LOG_CHANNEL(cellAudio); @@ -37,10 +38,25 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } + +cell_audio_config::cell_audio_config() +{ + // Warn if audio backend does not support all requested features + if (raw_buffering_enabled && !buffering_enabled) + { + cellAudio.error("Audio backend %s does not support buffering, this option will be ignored.", backend->GetName()); + } + if (raw_time_stretching_enabled && !time_stretching_enabled) + { + cellAudio.error("Audio backend %s does not support time stretching, this option will be ignored.", backend->GetName()); + } +} + + audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg) : cfg(_cfg) - , backend(Emu.GetCallbacks().get_audio()) - , buf_sz(AUDIO_BUFFER_SAMPLES * cfg.audio_channels) + , backend(_cfg.backend) + , buf_sz(AUDIO_BUFFER_SAMPLES * _cfg.audio_channels) , emu_paused(Emu.IsPaused()) { // Initialize buffers @@ -64,13 +80,13 @@ audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg) { std::string str; backend->dump_capabilities(str); - cellAudio.error("cellAudio initializing. Backend: %s, Capabilities: %s", backend->GetName(), str.c_str()); + cellAudio.notice("cellAudio initializing. Backend: %s, Capabilities: %s", backend->GetName(), str.c_str()); } backend->Open(cfg.num_allocated_buffers); backend_open = true; - ASSERT(!backend_is_playing()); + ASSERT(!get_backend_playing()); } audio_ringbuffer::~audio_ringbuffer() @@ -80,7 +96,7 @@ audio_ringbuffer::~audio_ringbuffer() return; } - if (backend_is_playing()) + if (get_backend_playing() && has_capability(AudioBackend::PLAY_PAUSE_FLUSH)) { backend->Pause(); } @@ -98,7 +114,7 @@ f32 audio_ringbuffer::set_frequency_ratio(f32 new_ratio) else { frequency_ratio = backend->SetFrequencyRatio(new_ratio); - //cellAudio.error("set_frequency_ratio(%1.2f) -> %1.2f", new_ratio, frequency_ratio); + //cellAudio.trace("set_frequency_ratio(%1.2f) -> %1.2f", new_ratio, frequency_ratio); } return frequency_ratio; } @@ -119,11 +135,11 @@ void audio_ringbuffer::enqueue(const float* in_buffer) // Dump audio if enabled if (m_dump) { - m_dump->WriteData(buf, buf_sz); + m_dump->WriteData(buf, cfg.audio_buffer_size); } // Enqueue audio - bool success = backend->AddData(buf, buf_sz); + bool success = backend->AddData(buf, AUDIO_BUFFER_SAMPLES * cfg.audio_channels); if (!success) { cellAudio.error("Could not enqueue buffer onto audio backend. Attempting to recover..."); @@ -131,14 +147,19 @@ void audio_ringbuffer::enqueue(const float* in_buffer) return; } - enqueued_samples += AUDIO_BUFFER_SAMPLES; + if (has_capability(AudioBackend::PLAY_PAUSE_FLUSH)) + { + enqueued_samples += AUDIO_BUFFER_SAMPLES; - // Start playing audio - play(); + // Start playing audio + play(); + } } void audio_ringbuffer::enqueue_silence(u32 buf_count) { + AUDIT(has_capability(AudioBackend::PLAY_PAUSE_FLUSH)); + for (u32 i = 0; i < buf_count; i++) { enqueue(silence_buffer); @@ -147,8 +168,16 @@ void audio_ringbuffer::enqueue_silence(u32 buf_count) void audio_ringbuffer::play() { - if (has_capability(AudioBackend::IS_PLAYING) && playing) + if (!has_capability(AudioBackend::PLAY_PAUSE_FLUSH)) + { + playing = true; return; + } + + if (has_capability(AudioBackend::IS_PLAYING) && playing) + { + return; + } if (frequency_ratio != 1.0f) { @@ -165,7 +194,13 @@ void audio_ringbuffer::play() void audio_ringbuffer::flush() { - cellAudio.trace("Flushing an estimated %llu enqueued samples", enqueued_samples); + if (!has_capability(AudioBackend::PLAY_PAUSE_FLUSH)) + { + playing = false; + return; + } + + //cellAudio.trace("Flushing an estimated %llu enqueued samples", enqueued_samples); backend->Pause(); playing = false; @@ -186,7 +221,7 @@ u64 audio_ringbuffer::update() if (Emu.IsPaused()) { // Emulator paused - if (playing) + if (has_capability(AudioBackend::PLAY_PAUSE_FLUSH) && playing) { backend->Pause(); } @@ -200,7 +235,7 @@ u64 audio_ringbuffer::update() } const u64 timestamp = get_timestamp(); - const bool new_playing = !emu_paused && backend_is_playing(); + const bool new_playing = !emu_paused && get_backend_playing(); // Calculate how many audio samples have played since last time if (cfg.buffering_enabled && (playing || new_playing)) @@ -234,7 +269,7 @@ u64 audio_ringbuffer::update() if (enqueued_samples == 0) { - cellAudio.warning("Audio buffer about to underrun!"); + cellAudio.trace("Audio buffer about to underrun!"); } } } @@ -245,7 +280,7 @@ u64 audio_ringbuffer::update() { if (!new_playing) { - cellAudio.error("Audio backend stopped unexpectedly, likely due to a buffer underrun"); + cellAudio.warning("Audio backend stopped unexpectedly, likely due to a buffer underrun"); flush(); playing = false; @@ -261,11 +296,6 @@ u64 audio_ringbuffer::update() return timestamp; } -constexpr bool audio_port::is_tag(float val) -{ - return val == 0.0f && std::signbit(val); -} - void audio_port::tag(s32 offset) { auto port_pos = position(offset); @@ -281,26 +311,12 @@ void audio_port::tag(s32 offset) for (u32 tag_pos = tag_first_pos, tag_nr = 0; tag_nr < PORT_BUFFER_TAG_COUNT; tag_pos += tag_delta, tag_nr++) { port_buf[tag_pos] = tag; - tag_backup[port_pos][tag_nr] = 0.0f; + last_tag_value[tag_nr] = -0.0f; } prev_touched_tag_nr = UINT32_MAX; } -void audio_port::apply_tag_backups(s32 offset) -{ - auto port_pos = position(offset); - auto port_buf = get_vm_ptr(offset); - - const u32 tag_first_pos = num_channels == 2 ? PORT_BUFFER_TAG_FIRST_2CH : PORT_BUFFER_TAG_FIRST_8CH; - const u32 tag_delta = num_channels == 2 ? PORT_BUFFER_TAG_DELTA_2CH : PORT_BUFFER_TAG_DELTA_8CH; - - for (u32 tag_pos = tag_first_pos, tag_nr = 0; tag_nr < PORT_BUFFER_TAG_COUNT; tag_pos += tag_delta, tag_nr++) - { - port_buf[tag_pos] += tag_backup[port_pos][tag_nr]; - } -} - std::tuple cell_audio_thread::count_port_buffer_tags() { AUDIT(cfg.buffering_enabled); @@ -322,18 +338,17 @@ std::tuple cell_audio_thread::count_port_buffer_tags() const u32 tag_first_pos = port.num_channels == 2 ? PORT_BUFFER_TAG_FIRST_2CH : PORT_BUFFER_TAG_FIRST_8CH; const u32 tag_delta = port.num_channels == 2 ? PORT_BUFFER_TAG_DELTA_2CH : PORT_BUFFER_TAG_DELTA_8CH; - const f32 tag = -0.0f; - u32 last_touched_tag_nr = port.prev_touched_tag_nr; bool retouched = false; for (u32 tag_pos = tag_first_pos, tag_nr = 0; tag_nr < PORT_BUFFER_TAG_COUNT; tag_pos += tag_delta, tag_nr++) { // grab current value and re-tag atomically - f32 val = atomic_storage, 4>::exchange(port_buf[tag_pos], tag); + const f32 val = port_buf[tag_pos]; + f32& last_val = port.last_tag_value[tag_nr]; - if (!audio_port::is_tag(val)) + if (val != last_val || (last_val == -0.0f && std::signbit(last_val) && !std::signbit(val))) { - port.tag_backup[port_pos][tag_nr] += val; + last_val = val; retouched |= tag_nr < port.prev_touched_tag_nr && port.prev_touched_tag_nr != UINT32_MAX; last_touched_tag_nr = tag_nr; @@ -374,7 +389,7 @@ std::tuple cell_audio_thread::count_port_buffer_tags() void cell_audio_thread::reset_ports(s32 offset) { - // Memset previous buffer to 0 + // Memset previous buffer to 0 and tag for (auto& port : ports) { if (port.state != audio_port_state::started) continue; @@ -383,7 +398,6 @@ void cell_audio_thread::reset_ports(s32 offset) if (cfg.buffering_enabled) { - //port.reset_tag_backups(offset); port.tag(offset); } } @@ -414,7 +428,7 @@ void cell_audio_thread::advance(u64 timestamp, bool reset) if (cfg.buffering_enabled) { // Calculate rolling average of enqueued playtime - const u64 enqueued_playtime = ringbuffer->get_enqueued_playtime(); + const u64 enqueued_playtime = ringbuffer->get_enqueued_playtime(/* raw */ true); m_average_playtime = cfg.period_average_alpha * enqueued_playtime + (1.0f - cfg.period_average_alpha) * m_average_playtime; //cellAudio.error("m_average_playtime=%4.2f, enqueued_playtime=%u", m_average_playtime, enqueued_playtime); } @@ -450,23 +464,6 @@ void cell_audio_thread::operator()() // Allocate ringbuffer ringbuffer.reset(new audio_ringbuffer(cfg)); - // Check backend capabilities - if (cfg.buffering_enabled) - { - if (!has_capability(AudioBackend::NON_BLOCKING) || !has_capability(AudioBackend::IS_PLAYING)) - { - // We need a non-blocking backend to be able to do buffering correctly - // We also need to be able to query the current playing state - fmt::throw_exception("Audio backend %s does not support buffering.", ringbuffer->get_backend_name()); - } - - if (cfg.time_stretching_enabled && !has_capability(AudioBackend::SET_FREQUENCY_RATIO)) - { - // We need to be able to set a dynamic frequency ratio to be able to do time stretching - fmt::throw_exception("Audio backend %s does not support time stretching", ringbuffer->get_backend_name()); - } - } - // Initialize loop variables m_counter = 0; m_start_time = ringbuffer->get_timestamp(); @@ -490,7 +487,6 @@ void cell_audio_thread::operator()() // TODO: send beforemix event (in ~2,6 ms before mixing) const u64 time_since_last_period = timestamp - m_last_period_end; - const bool playing = !ringbuffer->is_playing(); if (!cfg.buffering_enabled) { @@ -533,7 +529,7 @@ void cell_audio_thread::operator()() f32 desired_duration_adjusted = cfg.desired_buffer_duration + (cfg.audio_block_period / 2.0f); if (average_playtime_ratio < 1.0f) { - desired_duration_adjusted /= average_playtime_ratio; + desired_duration_adjusted /= std::max(average_playtime_ratio, 0.25f); } if (cfg.time_stretching_enabled) @@ -548,13 +544,12 @@ void cell_audio_thread::operator()() // update frequency ratio if necessary f32 new_ratio = frequency_ratio; - if (desired_duration_rate < cfg.time_stretching_threshold) + if ( + (desired_duration_rate < cfg.time_stretching_threshold && desired_duration_rate < frequency_ratio - cfg.time_stretching_step) || // Reduce frequency ratio below threshold in 0.1f steps + (desired_duration_rate > frequency_ratio + cfg.time_stretching_step) // Increase frequency ratio in 0.1f steps + ) { - new_ratio = ringbuffer->set_frequency_ratio(desired_duration_rate * cfg.time_stretching_frequency_scale_factor); - } - else if (frequency_ratio != 1.0f) - { - new_ratio = ringbuffer->set_frequency_ratio(1.0f); + new_ratio = ringbuffer->set_frequency_ratio(std::min(desired_duration_rate, 1.0f)); } if (new_ratio != frequency_ratio) @@ -714,11 +709,6 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset) { if (port.state != audio_port_state::started) continue; - if (cfg.buffering_enabled) - { - port.apply_tag_backups(offset); - } - auto buf = port.get_vm_ptr(offset); static const float k = 1.0f; float& m = port.level; @@ -876,7 +866,6 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset) for (size_t i = 0; i < out_buffer_sz; i += 8) { - // TODO ruipin: Revisit this const auto scale = _mm_set1_ps(0x8000); _mm_store_ps(out_buffer + i / 2, _mm_castsi128_ps(_mm_packs_epi32( _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(out_buffer + i), scale)), diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.h b/rpcs3/Emu/Cell/Modules/cellAudio.h index ccf5c18771..8743624a27 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.h +++ b/rpcs3/Emu/Cell/Modules/cellAudio.h @@ -90,7 +90,7 @@ enum : u32 AUDIO_BLOCK_SIZE_2CH = 2 * AUDIO_BUFFER_SAMPLES, AUDIO_BLOCK_SIZE_8CH = 8 * AUDIO_BUFFER_SAMPLES, - PORT_BUFFER_TAG_COUNT = 8, + PORT_BUFFER_TAG_COUNT = 6, PORT_BUFFER_TAG_LAST_2CH = AUDIO_BLOCK_SIZE_2CH - 1, PORT_BUFFER_TAG_DELTA_2CH = PORT_BUFFER_TAG_LAST_2CH / (PORT_BUFFER_TAG_COUNT - 1), @@ -163,37 +163,59 @@ struct audio_port // Tags u32 prev_touched_tag_nr; - f32 tag_backup[AUDIO_MAX_BLOCK_COUNT][PORT_BUFFER_TAG_COUNT] = { 0 }; + f32 last_tag_value[PORT_BUFFER_TAG_COUNT] = { 0 }; - constexpr static bool is_tag(float val); void tag(s32 offset = 0); - void apply_tag_backups(s32 offset = 0); }; struct cell_audio_config { - const s64 period_comparison_margin = 100; // When comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer + const std::shared_ptr backend = Emu.GetCallbacks().get_audio(); const u32 audio_channels = AudioBackend::get_channels(); const u32 audio_sampling_rate = AudioBackend::get_sampling_rate(); const u32 audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate; - const u64 desired_buffer_duration = g_cfg.audio.enable_buffering ? g_cfg.audio.desired_buffer_duration : 0; const u32 audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels; - const u32 audio_buffer_size = audio_buffer_length * sizeof(f32); - const bool buffering_enabled = g_cfg.audio.enable_buffering && (desired_buffer_duration >= audio_block_period); + const u32 audio_buffer_size = audio_buffer_length * AudioBackend::get_sample_size(); + + /* + * Buffering + */ + const u64 desired_buffer_duration = g_cfg.audio.enable_buffering ? g_cfg.audio.desired_buffer_duration : 0; +private: + const bool raw_buffering_enabled = g_cfg.audio.enable_buffering && (desired_buffer_duration >= audio_block_period); +public: + // We need a non-blocking backend (implementing play/pause/flush) to be able to do buffering correctly + // We also need to be able to query the current playing state + const bool buffering_enabled = raw_buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING); const u64 minimum_block_period = audio_block_period / 2; // the block period will not be dynamically lowered below this value (usecs) const u64 maximum_block_period = (6 * audio_block_period) / 5; // the block period will not be dynamically increased above this value (usecs) - const u32 desired_full_buffers = buffering_enabled ? static_cast(desired_buffer_duration / audio_block_period) + 1 : 1; + const u32 desired_full_buffers = buffering_enabled ? static_cast(desired_buffer_duration / audio_block_period) + 1 : 2; const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers const f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average - const bool time_stretching_enabled = buffering_enabled && g_cfg.audio.enable_time_stretching && (g_cfg.audio.time_stretching_threshold > 0); + const s64 period_comparison_margin = 250; // when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer + + /* + * Time Stretching + */ +private: + const bool raw_time_stretching_enabled = buffering_enabled && g_cfg.audio.enable_time_stretching && (g_cfg.audio.time_stretching_threshold > 0); +public: + // We need to be able to set a dynamic frequency ratio to be able to do time stretching + const bool time_stretching_enabled = raw_time_stretching_enabled && backend->has_capability(AudioBackend::SET_FREQUENCY_RATIO); + const f32 time_stretching_threshold = g_cfg.audio.time_stretching_threshold / 100.0f; // we only apply time stretching below this buffer fill rate (adjusted for average period) - const f32 time_stretching_frequency_scale_factor = 1.0f / time_stretching_threshold; + const f32 time_stretching_step = 0.1f; + + /* + * Constructor + */ + cell_audio_config(); }; class audio_ringbuffer @@ -224,9 +246,9 @@ private: u32 cur_pos = 0; - bool backend_is_playing() const + bool get_backend_playing() const { - return has_capability(AudioBackend::IS_PLAYING) ? backend->IsPlaying() : playing; + return has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING) ? backend->IsPlaying() : playing; } public: @@ -280,7 +302,7 @@ public: return frequency_ratio; } - u32 has_capability(AudioBackend::Capabilities cap) const + u32 has_capability(u32 cap) const { return backend->has_capability(cap); } @@ -307,7 +329,7 @@ class cell_audio_thread constexpr static u64 get_thread_wait_delay(u64 time_left) { - return (time_left > 1000) ? time_left - 750 : 100; + return (time_left > 350) ? time_left - 250 : 100; } public: @@ -349,7 +371,7 @@ public: return nullptr; } - bool has_capability(AudioBackend::Capabilities cap) const + bool has_capability(u32 cap) const { return ringbuffer->has_capability(cap); } diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 3b84552002..2c80706808 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -526,12 +526,12 @@ struct cfg_root : cfg::node cfg::_bool dump_to_file{this, "Dump to file"}; cfg::_bool convert_to_u16{this, "Convert to 16 bit"}; cfg::_bool downmix_to_2ch{this, "Downmix to Stereo", true}; - cfg::_int<1, 128> startt{this, "Start Threshold", 1}; + cfg::_int<1, 128> startt{this, "Start Threshold", 1}; // TODO: used only by ALSA, should probably be removed once ALSA is upgraded cfg::_int<0, 200> volume{this, "Master Volume", 100}; cfg::_bool enable_buffering{this, "Enable Buffering", true}; cfg::_int <0, 250'000> desired_buffer_duration{this, "Desired Audio Buffer Duration", 100'000}; cfg::_int<1, 1000> sampling_period_multiplier{this, "Sampling Period Multiplier", 100}; - cfg::_bool enable_time_stretching{this, "Enable Time Stretching", true}; + cfg::_bool enable_time_stretching{this, "Enable Time Stretching", false}; cfg::_int<0, 100> time_stretching_threshold{this, "Time Stretching Threshold", 75}; } audio{this}; diff --git a/rpcs3/rpcs3_app.cpp b/rpcs3/rpcs3_app.cpp index a163d819cd..2a7abe4e5e 100644 --- a/rpcs3/rpcs3_app.cpp +++ b/rpcs3/rpcs3_app.cpp @@ -48,10 +48,10 @@ #include "Emu/Audio/XAudio2/XAudio2Backend.h" #endif #ifdef HAVE_ALSA -#include "Emu/Audio/ALSA/ALSAThread.h" +#include "Emu/Audio/ALSA/ALSABackend.h" #endif #ifdef HAVE_PULSE -#include "Emu/Audio/Pulse/PulseThread.h" +#include "Emu/Audio/Pulse/PulseBackend.h" #endif #ifdef _WIN32 @@ -263,10 +263,10 @@ void rpcs3_app::InitializeCallbacks() case audio_renderer::xaudio: return std::make_shared(); #endif #ifdef HAVE_ALSA - case audio_renderer::alsa: return std::make_shared(); + case audio_renderer::alsa: return std::make_shared(); #endif #ifdef HAVE_PULSE - case audio_renderer::pulse: return std::make_shared(); + case audio_renderer::pulse: return std::make_shared(); #endif case audio_renderer::openal: return std::make_shared();