mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
Implement Audio Backend Capabilities querying
Also renames "AudioThread" to "AudioBackend". The new name is more descriptive of what the class really is responsible for, since the backends are not responsible for managing the audio thread. NOTE: Right now only XAudio2 is supported
This commit is contained in:
parent
2addbe6be2
commit
5159d3559e
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/*#include "Emu/Audio/AudioThread.h"
|
/*#include "Emu/Audio/AudioBackend.h"
|
||||||
#include "3rdparty/OpenAL/include/alext.h"
|
#include "3rdparty/OpenAL/include/alext.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class OpenALThread : public AudioThread
|
class OpenALThread : public AudioBackend
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ALint m_format;
|
ALint m_format;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "Emu/Audio/AudioThread.h"
|
#include "Emu/Audio/AudioThread.h"
|
||||||
|
|
||||||
class ALSAThread : public AudioThread
|
class ALSAThread : public AudioBackend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ALSAThread();
|
ALSAThread();
|
||||||
|
@ -10,22 +10,42 @@ enum : u32
|
|||||||
AUDIO_BUFFER_SAMPLES = 256
|
AUDIO_BUFFER_SAMPLES = 256
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioThread
|
class AudioBackend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~AudioThread() = default;
|
enum Capabilities : u32
|
||||||
|
{
|
||||||
|
NON_BLOCKING = 0x1,
|
||||||
|
IS_PLAYING = 0x2,
|
||||||
|
GET_NUM_ENQUEUED_SAMPLES = 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~AudioBackend() = default;
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
|
virtual const char* GetName() const = 0;
|
||||||
|
virtual u32 GetCapabilities() const = 0;
|
||||||
|
|
||||||
virtual void Open() = 0;
|
virtual void Open() = 0;
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
|
|
||||||
virtual void Play() = 0;
|
virtual void Play() = 0;
|
||||||
virtual void Pause() = 0;
|
virtual void Pause() = 0;
|
||||||
virtual bool IsPlaying() = 0;
|
|
||||||
|
virtual bool IsPlaying()
|
||||||
|
{
|
||||||
|
fmt::throw_exception("IsPlaying() not implemented");
|
||||||
|
};
|
||||||
|
|
||||||
virtual bool AddData(const void* src, int size) = 0;
|
virtual bool AddData(const void* src, int size) = 0;
|
||||||
virtual void Flush() = 0;
|
virtual void Flush() = 0;
|
||||||
|
|
||||||
|
virtual u64 GetNumEnqueuedSamples()
|
||||||
|
{
|
||||||
|
fmt::throw_exception("GetNumEnqueuedSamples() not implemented");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
static u32 get_sampling_rate()
|
static u32 get_sampling_rate()
|
||||||
{
|
{
|
24
rpcs3/Emu/Audio/Null/NullAudioBackend.h
Normal file
24
rpcs3/Emu/Audio/Null/NullAudioBackend.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Emu/Audio/AudioBackend.h"
|
||||||
|
|
||||||
|
class NullAudioBackend : public AudioBackend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NullAudioBackend() {}
|
||||||
|
virtual ~NullAudioBackend() {}
|
||||||
|
|
||||||
|
virtual const char* GetName() const override { return "NullAudioBackend"; }
|
||||||
|
|
||||||
|
static const u32 capabilities = NON_BLOCKING;
|
||||||
|
virtual u32 GetCapabilities() const override { return capabilities; };
|
||||||
|
|
||||||
|
virtual void Open() override {};
|
||||||
|
virtual void Close() override {};
|
||||||
|
|
||||||
|
virtual void Play() override {};
|
||||||
|
virtual void Pause() override {};
|
||||||
|
|
||||||
|
virtual bool AddData(const void* src, int size) override { return true; };
|
||||||
|
virtual void Flush() override {};
|
||||||
|
};
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Emu/Audio/AudioThread.h"
|
|
||||||
|
|
||||||
class NullAudioThread : public AudioThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NullAudioThread() {}
|
|
||||||
virtual ~NullAudioThread() {}
|
|
||||||
|
|
||||||
virtual void Open() {};
|
|
||||||
virtual void Close() {};
|
|
||||||
|
|
||||||
virtual void Play() {};
|
|
||||||
virtual void Pause() {};
|
|
||||||
virtual bool IsPlaying() { return true; };
|
|
||||||
|
|
||||||
virtual bool AddData(const void* src, int size) { return true; };
|
|
||||||
virtual void Flush() {};
|
|
||||||
};
|
|
@ -4,7 +4,7 @@
|
|||||||
#include <pulse/simple.h>
|
#include <pulse/simple.h>
|
||||||
#include "Emu/Audio/AudioThread.h"
|
#include "Emu/Audio/AudioThread.h"
|
||||||
|
|
||||||
class PulseThread : public AudioThread
|
class PulseThread : public AudioBackend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PulseThread();
|
PulseThread();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "Utilities/StrFmt.h"
|
#include "Utilities/StrFmt.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
|
||||||
#include "XAudio2Thread.h"
|
#include "XAudio2Backend.h"
|
||||||
#include "3rdparty/XAudio2_7/XAudio2.h"
|
#include "3rdparty/XAudio2_7/XAudio2.h"
|
||||||
|
|
||||||
static thread_local HMODULE s_tls_xaudio2_lib{};
|
static thread_local HMODULE s_tls_xaudio2_lib{};
|
||||||
@ -12,7 +12,7 @@ static thread_local IXAudio2* s_tls_xaudio2_instance{};
|
|||||||
static thread_local IXAudio2MasteringVoice* s_tls_master_voice{};
|
static thread_local IXAudio2MasteringVoice* s_tls_master_voice{};
|
||||||
static thread_local IXAudio2SourceVoice* s_tls_source_voice{};
|
static thread_local IXAudio2SourceVoice* s_tls_source_voice{};
|
||||||
|
|
||||||
void XAudio2Thread::xa27_init(void* lib2_7)
|
void XAudio2Backend::xa27_init(void* lib2_7)
|
||||||
{
|
{
|
||||||
s_tls_xaudio2_lib = (HMODULE)lib2_7;
|
s_tls_xaudio2_lib = (HMODULE)lib2_7;
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ void XAudio2Thread::xa27_init(void* lib2_7)
|
|||||||
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : CoInitializeEx() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ void XAudio2Thread::xa27_init(void* lib2_7)
|
|||||||
hr = XAudio2Create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
hr = XAudio2Create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : XAudio2Create() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -37,13 +37,13 @@ void XAudio2Thread::xa27_init(void* lib2_7)
|
|||||||
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
||||||
s_tls_xaudio2_instance->Release();
|
s_tls_xaudio2_instance->Release();
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa27_destroy()
|
void XAudio2Backend::xa27_destroy()
|
||||||
{
|
{
|
||||||
if (s_tls_source_voice != nullptr)
|
if (s_tls_source_voice != nullptr)
|
||||||
{
|
{
|
||||||
@ -67,37 +67,37 @@ void XAudio2Thread::xa27_destroy()
|
|||||||
FreeLibrary(s_tls_xaudio2_lib);
|
FreeLibrary(s_tls_xaudio2_lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa27_play()
|
void XAudio2Backend::xa27_play()
|
||||||
{
|
{
|
||||||
HRESULT hr = s_tls_source_voice->Start();
|
HRESULT hr = s_tls_source_voice->Start();
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : Start() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa27_flush()
|
void XAudio2Backend::xa27_flush()
|
||||||
{
|
{
|
||||||
HRESULT hr = s_tls_source_voice->FlushSourceBuffers();
|
HRESULT hr = s_tls_source_voice->FlushSourceBuffers();
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa27_stop()
|
void XAudio2Backend::xa27_stop()
|
||||||
{
|
{
|
||||||
HRESULT hr = s_tls_source_voice->Stop();
|
HRESULT hr = s_tls_source_voice->Stop();
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : Stop() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XAudio2Thread::xa27_is_playing()
|
bool XAudio2Backend::xa27_is_playing()
|
||||||
{
|
{
|
||||||
XAUDIO2_VOICE_STATE state;
|
XAUDIO2_VOICE_STATE state;
|
||||||
s_tls_source_voice->GetState(&state);
|
s_tls_source_voice->GetState(&state);
|
||||||
@ -105,7 +105,7 @@ bool XAudio2Thread::xa27_is_playing()
|
|||||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa27_open()
|
void XAudio2Backend::xa27_open()
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ void XAudio2Thread::xa27_open()
|
|||||||
hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ void XAudio2Thread::xa27_open()
|
|||||||
s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
|
s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XAudio2Thread::xa27_add(const void* src, int size)
|
bool XAudio2Backend::xa27_add(const void* src, int size)
|
||||||
{
|
{
|
||||||
XAUDIO2_VOICE_STATE state;
|
XAUDIO2_VOICE_STATE state;
|
||||||
s_tls_source_voice->GetState(&state);
|
s_tls_source_voice->GetState(&state);
|
||||||
@ -141,7 +141,7 @@ bool XAudio2Thread::xa27_add(const void* src, int size)
|
|||||||
// XAudio 2.7 bug workaround, when it says "SimpList: non-growable list ran out of room for new elements" and hits int 3
|
// 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)
|
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||||
{
|
{
|
||||||
LOG_WARNING(GENERAL, "XAudio2Thread : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed);
|
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,11 +160,21 @@ bool XAudio2Thread::xa27_add(const void* src, int size)
|
|||||||
HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer);
|
HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : AddData() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -4,7 +4,7 @@
|
|||||||
#include "Utilities/StrFmt.h"
|
#include "Utilities/StrFmt.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
|
||||||
#include "XAudio2Thread.h"
|
#include "XAudio2Backend.h"
|
||||||
#include "3rdparty/minidx12/Include/xaudio2.h"
|
#include "3rdparty/minidx12/Include/xaudio2.h"
|
||||||
|
|
||||||
static thread_local HMODULE s_tls_xaudio2_lib{};
|
static thread_local HMODULE s_tls_xaudio2_lib{};
|
||||||
@ -12,7 +12,7 @@ static thread_local IXAudio2* s_tls_xaudio2_instance{};
|
|||||||
static thread_local IXAudio2MasteringVoice* s_tls_master_voice{};
|
static thread_local IXAudio2MasteringVoice* s_tls_master_voice{};
|
||||||
static thread_local IXAudio2SourceVoice* s_tls_source_voice{};
|
static thread_local IXAudio2SourceVoice* s_tls_source_voice{};
|
||||||
|
|
||||||
void XAudio2Thread::xa28_init(void* lib)
|
void XAudio2Backend::xa28_init(void* lib)
|
||||||
{
|
{
|
||||||
s_tls_xaudio2_lib = (HMODULE)lib;
|
s_tls_xaudio2_lib = (HMODULE)lib;
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ void XAudio2Thread::xa28_init(void* lib)
|
|||||||
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : CoInitializeEx() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ void XAudio2Thread::xa28_init(void* lib)
|
|||||||
hr = create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
hr = create(&s_tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : XAudio2Create() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -39,13 +39,13 @@ void XAudio2Thread::xa28_init(void* lib)
|
|||||||
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
||||||
s_tls_xaudio2_instance->Release();
|
s_tls_xaudio2_instance->Release();
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa28_destroy()
|
void XAudio2Backend::xa28_destroy()
|
||||||
{
|
{
|
||||||
if (s_tls_source_voice != nullptr)
|
if (s_tls_source_voice != nullptr)
|
||||||
{
|
{
|
||||||
@ -69,43 +69,43 @@ void XAudio2Thread::xa28_destroy()
|
|||||||
FreeLibrary(s_tls_xaudio2_lib);
|
FreeLibrary(s_tls_xaudio2_lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa28_play()
|
void XAudio2Backend::xa28_play()
|
||||||
{
|
{
|
||||||
AUDIT(s_tls_source_voice != nullptr);
|
AUDIT(s_tls_source_voice != nullptr);
|
||||||
|
|
||||||
HRESULT hr = s_tls_source_voice->Start();
|
HRESULT hr = s_tls_source_voice->Start();
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : Start() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa28_flush()
|
void XAudio2Backend::xa28_flush()
|
||||||
{
|
{
|
||||||
AUDIT(s_tls_source_voice != nullptr);
|
AUDIT(s_tls_source_voice != nullptr);
|
||||||
|
|
||||||
HRESULT hr = s_tls_source_voice->FlushSourceBuffers();
|
HRESULT hr = s_tls_source_voice->FlushSourceBuffers();
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa28_stop()
|
void XAudio2Backend::xa28_stop()
|
||||||
{
|
{
|
||||||
AUDIT(s_tls_source_voice != nullptr);
|
AUDIT(s_tls_source_voice != nullptr);
|
||||||
|
|
||||||
HRESULT hr = s_tls_source_voice->Stop();
|
HRESULT hr = s_tls_source_voice->Stop();
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : Stop() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XAudio2Thread::xa28_is_playing()
|
bool XAudio2Backend::xa28_is_playing()
|
||||||
{
|
{
|
||||||
AUDIT(s_tls_source_voice != nullptr);
|
AUDIT(s_tls_source_voice != nullptr);
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ bool XAudio2Thread::xa28_is_playing()
|
|||||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::xa28_open()
|
void XAudio2Backend::xa28_open()
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ void XAudio2Thread::xa28_open()
|
|||||||
hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
hr = s_tls_xaudio2_instance->CreateSourceVoice(&s_tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ void XAudio2Thread::xa28_open()
|
|||||||
s_tls_source_voice->SetVolume(channels == 2 ? 1.0 : 4.0);
|
s_tls_source_voice->SetVolume(channels == 2 ? 1.0 : 4.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XAudio2Thread::xa28_add(const void* src, int size)
|
bool XAudio2Backend::xa28_add(const void* src, int size)
|
||||||
{
|
{
|
||||||
AUDIT(s_tls_source_voice != nullptr);
|
AUDIT(s_tls_source_voice != nullptr);
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ bool XAudio2Thread::xa28_add(const void* src, int size)
|
|||||||
|
|
||||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||||
{
|
{
|
||||||
LOG_WARNING(GENERAL, "XAudio2Thread : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed);
|
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,11 +172,21 @@ bool XAudio2Thread::xa28_add(const void* src, int size)
|
|||||||
HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer);
|
HRESULT hr = s_tls_source_voice->SubmitSourceBuffer(&buffer);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
LOG_ERROR(GENERAL, "XAudio2Thread : AddData() failed(0x%08x)", (u32)hr);
|
LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -3,16 +3,11 @@
|
|||||||
#include "Utilities/Log.h"
|
#include "Utilities/Log.h"
|
||||||
#include "Utilities/StrFmt.h"
|
#include "Utilities/StrFmt.h"
|
||||||
|
|
||||||
#include "XAudio2Thread.h"
|
#include "XAudio2Backend.h"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
XAudio2Thread::XAudio2Thread()
|
XAudio2Backend::XAudio2Backend()
|
||||||
{
|
{
|
||||||
if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
|
|
||||||
{
|
|
||||||
LOG_ERROR(GENERAL, "XAudio: failed to increase thread priority");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto lib2_9 = LoadLibraryExW(L"XAudio2_9.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
|
if (auto lib2_9 = LoadLibraryExW(L"XAudio2_9.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
|
||||||
{
|
{
|
||||||
// xa28* implementation is fully compatible with library 2.9
|
// xa28* implementation is fully compatible with library 2.9
|
||||||
@ -25,11 +20,29 @@ XAudio2Thread::XAudio2Thread()
|
|||||||
m_funcs.open = &xa28_open;
|
m_funcs.open = &xa28_open;
|
||||||
m_funcs.is_playing = &xa28_is_playing;
|
m_funcs.is_playing = &xa28_is_playing;
|
||||||
m_funcs.add = &xa28_add;
|
m_funcs.add = &xa28_add;
|
||||||
|
m_funcs.enqueued_samples = &xa28_enqueued_samples;
|
||||||
|
|
||||||
LOG_SUCCESS(GENERAL, "XAudio 2.9 initialized");
|
LOG_SUCCESS(GENERAL, "XAudio 2.9 initialized");
|
||||||
return;
|
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;
|
||||||
|
|
||||||
|
LOG_SUCCESS(GENERAL, "XAudio 2.8 initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto lib2_7 = LoadLibraryExW(L"XAudio2_7.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
|
if (auto lib2_7 = LoadLibraryExW(L"XAudio2_7.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
|
||||||
{
|
{
|
||||||
xa27_init(lib2_7);
|
xa27_init(lib2_7);
|
||||||
@ -41,69 +54,59 @@ XAudio2Thread::XAudio2Thread()
|
|||||||
m_funcs.open = &xa27_open;
|
m_funcs.open = &xa27_open;
|
||||||
m_funcs.is_playing = &xa27_is_playing;
|
m_funcs.is_playing = &xa27_is_playing;
|
||||||
m_funcs.add = &xa27_add;
|
m_funcs.add = &xa27_add;
|
||||||
|
m_funcs.enqueued_samples = &xa27_enqueued_samples;
|
||||||
|
|
||||||
LOG_SUCCESS(GENERAL, "XAudio 2.7 initialized");
|
LOG_SUCCESS(GENERAL, "XAudio 2.7 initialized");
|
||||||
return;
|
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;
|
|
||||||
|
|
||||||
LOG_SUCCESS(GENERAL, "XAudio 2.8 initialized");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::throw_exception("No supported XAudio2 library found");
|
fmt::throw_exception("No supported XAudio2 library found");
|
||||||
}
|
}
|
||||||
|
|
||||||
XAudio2Thread::~XAudio2Thread()
|
XAudio2Backend::~XAudio2Backend()
|
||||||
{
|
{
|
||||||
m_funcs.destroy();
|
m_funcs.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::Play()
|
void XAudio2Backend::Play()
|
||||||
{
|
{
|
||||||
m_funcs.play();
|
m_funcs.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::Close()
|
void XAudio2Backend::Close()
|
||||||
{
|
{
|
||||||
m_funcs.stop();
|
m_funcs.stop();
|
||||||
m_funcs.flush();
|
m_funcs.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::Pause()
|
void XAudio2Backend::Pause()
|
||||||
{
|
{
|
||||||
m_funcs.stop();
|
m_funcs.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::Open()
|
void XAudio2Backend::Open()
|
||||||
{
|
{
|
||||||
m_funcs.open();
|
m_funcs.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XAudio2Thread::IsPlaying()
|
bool XAudio2Backend::IsPlaying()
|
||||||
{
|
{
|
||||||
return m_funcs.is_playing();
|
return m_funcs.is_playing();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XAudio2Thread::AddData(const void* src, int size)
|
bool XAudio2Backend::AddData(const void* src, int size)
|
||||||
{
|
{
|
||||||
return m_funcs.add(src, size);
|
return m_funcs.add(src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XAudio2Thread::Flush()
|
void XAudio2Backend::Flush()
|
||||||
{
|
{
|
||||||
m_funcs.flush();
|
m_funcs.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 XAudio2Backend::GetNumEnqueuedSamples()
|
||||||
|
{
|
||||||
|
return m_funcs.enqueued_samples();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include "Emu/Audio/AudioThread.h"
|
#include "Emu/Audio/AudioBackend.h"
|
||||||
|
|
||||||
class XAudio2Thread : public AudioThread
|
class XAudio2Backend : public AudioBackend
|
||||||
{
|
{
|
||||||
struct vtable
|
struct vtable
|
||||||
{
|
{
|
||||||
@ -15,6 +15,7 @@ class XAudio2Thread : public AudioThread
|
|||||||
void(*open)();
|
void(*open)();
|
||||||
bool(*is_playing)();
|
bool(*is_playing)();
|
||||||
bool(*add)(const void*, int);
|
bool(*add)(const void*, int);
|
||||||
|
u64(*enqueued_samples)();
|
||||||
};
|
};
|
||||||
|
|
||||||
vtable m_funcs;
|
vtable m_funcs;
|
||||||
@ -27,6 +28,7 @@ class XAudio2Thread : public AudioThread
|
|||||||
static void xa27_open();
|
static void xa27_open();
|
||||||
static bool xa27_is_playing();
|
static bool xa27_is_playing();
|
||||||
static bool xa27_add(const void*, int);
|
static bool xa27_add(const void*, int);
|
||||||
|
static u64 xa27_enqueued_samples();
|
||||||
|
|
||||||
static void xa28_init(void*);
|
static void xa28_init(void*);
|
||||||
static void xa28_destroy();
|
static void xa28_destroy();
|
||||||
@ -36,10 +38,16 @@ class XAudio2Thread : public AudioThread
|
|||||||
static void xa28_open();
|
static void xa28_open();
|
||||||
static bool xa28_is_playing();
|
static bool xa28_is_playing();
|
||||||
static bool xa28_add(const void*, int);
|
static bool xa28_add(const void*, int);
|
||||||
|
static u64 xa28_enqueued_samples();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
XAudio2Thread();
|
XAudio2Backend();
|
||||||
virtual ~XAudio2Thread() override;
|
virtual ~XAudio2Backend() override;
|
||||||
|
|
||||||
|
virtual const char* GetName() const override { return "XAudio2Backend"; };
|
||||||
|
|
||||||
|
static const u32 capabilities = NON_BLOCKING | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES;
|
||||||
|
virtual u32 GetCapabilities() const override { return capabilities; };
|
||||||
|
|
||||||
virtual void Open() override;
|
virtual void Open() override;
|
||||||
virtual void Close() override;
|
virtual void Close() override;
|
||||||
@ -50,6 +58,8 @@ public:
|
|||||||
|
|
||||||
virtual bool AddData(const void* src, int size) override;
|
virtual bool AddData(const void* src, int size) override;
|
||||||
virtual void Flush() override;
|
virtual void Flush() override;
|
||||||
|
|
||||||
|
virtual u64 GetNumEnqueuedSamples() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -37,21 +37,19 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_ringbuffer::audio_ringbuffer(u32 num_buffers, u32 audio_sampling_rate, u32 channels)
|
audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
|
||||||
: num_allocated_buffers(num_buffers)
|
: cfg(_cfg)
|
||||||
, audio_sampling_rate(audio_sampling_rate)
|
|
||||||
, backend(Emu.GetCallbacks().get_audio())
|
, backend(Emu.GetCallbacks().get_audio())
|
||||||
, channels(channels)
|
, buf_sz(AUDIO_BUFFER_SAMPLES * cfg.audio_channels)
|
||||||
, buf_sz(AUDIO_BUFFER_SAMPLES * channels)
|
|
||||||
, emu_paused(Emu.IsPaused())
|
, emu_paused(Emu.IsPaused())
|
||||||
{
|
{
|
||||||
// Initialize buffers
|
// Initialize buffers
|
||||||
if (num_allocated_buffers >= MAX_AUDIO_BUFFERS)
|
if (cfg.num_allocated_buffers >= MAX_AUDIO_BUFFERS)
|
||||||
{
|
{
|
||||||
fmt::throw_exception("MAX_AUDIO_BUFFERS is too small");
|
fmt::throw_exception("MAX_AUDIO_BUFFERS is too small");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < num_allocated_buffers; i++)
|
for (u32 i = 0; i < cfg.num_allocated_buffers; i++)
|
||||||
{
|
{
|
||||||
buffer[i].reset(new float[buf_sz]{});
|
buffer[i].reset(new float[buf_sz]{});
|
||||||
}
|
}
|
||||||
@ -59,37 +57,53 @@ audio_ringbuffer::audio_ringbuffer(u32 num_buffers, u32 audio_sampling_rate, u32
|
|||||||
// Init audio dumper if enabled
|
// Init audio dumper if enabled
|
||||||
if (g_cfg.audio.dump_to_file)
|
if (g_cfg.audio.dump_to_file)
|
||||||
{
|
{
|
||||||
m_dump.reset(new AudioDumper(channels));
|
m_dump.reset(new AudioDumper(cfg.audio_channels));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check configuration vs. capabilities
|
||||||
|
backend_capabilities = backend->GetCapabilities();
|
||||||
|
if (cfg.buffering_enabled)
|
||||||
|
{
|
||||||
|
if (!(backend_capabilities & AudioBackend::NON_BLOCKING) || !(backend_capabilities & AudioBackend::IS_PLAYING))
|
||||||
|
{
|
||||||
|
// We need a non-blocking backend to be able to do buffering correctly
|
||||||
|
fmt::throw_exception("Audio backend %s does not support buffering.", backend->GetName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize backend
|
// Initialize backend
|
||||||
backend->Open();
|
backend->Open();
|
||||||
backend_open = true;
|
backend_open = true;
|
||||||
ASSERT(!backend->IsPlaying());
|
|
||||||
|
ASSERT(!backend_is_playing());
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_ringbuffer::~audio_ringbuffer()
|
audio_ringbuffer::~audio_ringbuffer()
|
||||||
{
|
{
|
||||||
if (!backend_open)
|
if (!backend_open)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (backend->IsPlaying())
|
if (backend_is_playing())
|
||||||
|
{
|
||||||
backend->Pause();
|
backend->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
backend->Close();
|
backend->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_ringbuffer::enqueue(const float* in_buffer)
|
void audio_ringbuffer::enqueue(const float* in_buffer)
|
||||||
{
|
{
|
||||||
AUDIT(next_buf < num_allocated_buffers);
|
AUDIT(cur_pos < cfg.num_allocated_buffers);
|
||||||
|
|
||||||
// Prepare buffer
|
// Prepare buffer
|
||||||
const void* buf = in_buffer;
|
const void* buf = in_buffer;
|
||||||
|
|
||||||
if (buf == nullptr)
|
if (buf == nullptr)
|
||||||
{
|
{
|
||||||
buf = buffer[next_buf].get();
|
buf = buffer[cur_pos].get();
|
||||||
next_buf = (next_buf + 1) % num_allocated_buffers;
|
cur_pos = (cur_pos + 1) % cfg.num_allocated_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump audio if enabled
|
// Dump audio if enabled
|
||||||
@ -165,35 +179,42 @@ u64 audio_ringbuffer::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const u64 timestamp = get_timestamp();
|
const u64 timestamp = get_timestamp();
|
||||||
const bool new_playing = !emu_paused && backend->IsPlaying();
|
const bool new_playing = !emu_paused && backend_is_playing();
|
||||||
|
|
||||||
// Calculate how many audio samples have played since last time
|
// Calculate how many audio samples have played since last time
|
||||||
// TODO: Natively query backend for remaining samples
|
if (cfg.buffering_enabled && (playing || new_playing))
|
||||||
if (playing || new_playing)
|
|
||||||
{
|
{
|
||||||
const u64 play_delta = timestamp - (play_timestamp > update_timestamp ? play_timestamp : update_timestamp);
|
if (backend_capabilities & AudioBackend::GET_NUM_ENQUEUED_SAMPLES)
|
||||||
|
|
||||||
// NOTE: Only works with a fixed sampling rate
|
|
||||||
const u64 delta_samples_tmp = (play_delta * audio_sampling_rate) + last_remainder;
|
|
||||||
last_remainder = delta_samples_tmp % 1'000'000;
|
|
||||||
const u64 delta_samples = delta_samples_tmp / 1'000'000;
|
|
||||||
|
|
||||||
//cellAudio.error("play_delta=%llu delta_samples=%llu", play_delta, delta_samples);
|
|
||||||
if (delta_samples > 0)
|
|
||||||
{
|
{
|
||||||
|
// Backend supports querying for the remaining playtime, so just ask it
|
||||||
|
enqueued_samples = backend->GetNumEnqueuedSamples();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const u64 play_delta = timestamp - (play_timestamp > update_timestamp ? play_timestamp : update_timestamp);
|
||||||
|
|
||||||
if (enqueued_samples < delta_samples)
|
// NOTE: Only works with a fixed sampling rate
|
||||||
{
|
const u64 delta_samples_tmp = (play_delta * cfg.audio_sampling_rate) + last_remainder;
|
||||||
enqueued_samples = 0;
|
last_remainder = delta_samples_tmp % 1'000'000;
|
||||||
}
|
const u64 delta_samples = delta_samples_tmp / 1'000'000;
|
||||||
else
|
|
||||||
{
|
|
||||||
enqueued_samples -= delta_samples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enqueued_samples == 0)
|
//cellAudio.error("play_delta=%llu delta_samples=%llu", play_delta, delta_samples);
|
||||||
|
if (delta_samples > 0)
|
||||||
{
|
{
|
||||||
cellAudio.warning("Audio buffer about to underrun!");
|
|
||||||
|
if (enqueued_samples < delta_samples)
|
||||||
|
{
|
||||||
|
enqueued_samples = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enqueued_samples -= delta_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enqueued_samples == 0)
|
||||||
|
{
|
||||||
|
cellAudio.warning("Audio buffer about to underrun!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,7 +282,7 @@ void audio_port::apply_tag_backups(s32 offset)
|
|||||||
|
|
||||||
std::tuple<u32, u32, u32, u32> cell_audio_thread::count_port_buffer_tags()
|
std::tuple<u32, u32, u32, u32> cell_audio_thread::count_port_buffer_tags()
|
||||||
{
|
{
|
||||||
AUDIT(buffering_enabled);
|
AUDIT(cfg.buffering_enabled);
|
||||||
|
|
||||||
u32 active = 0;
|
u32 active = 0;
|
||||||
u32 in_progress = 0;
|
u32 in_progress = 0;
|
||||||
@ -339,7 +360,7 @@ void cell_audio_thread::reset_ports(s32 offset)
|
|||||||
|
|
||||||
memset(port.get_vm_ptr(offset), 0, port.block_size() * sizeof(float));
|
memset(port.get_vm_ptr(offset), 0, port.block_size() * sizeof(float));
|
||||||
|
|
||||||
if (buffering_enabled)
|
if (cfg.buffering_enabled)
|
||||||
{
|
{
|
||||||
//port.reset_tag_backups(offset);
|
//port.reset_tag_backups(offset);
|
||||||
port.tag(offset);
|
port.tag(offset);
|
||||||
@ -398,7 +419,7 @@ void cell_audio_thread::operator()()
|
|||||||
thread_ctrl::set_native_priority(1);
|
thread_ctrl::set_native_priority(1);
|
||||||
|
|
||||||
// Allocate ringbuffer
|
// Allocate ringbuffer
|
||||||
ringbuffer.reset(new audio_ringbuffer(num_allocated_buffers, audio_sampling_rate, audio_channels));
|
ringbuffer.reset(new audio_ringbuffer(cfg));
|
||||||
|
|
||||||
// Initialize loop variables
|
// Initialize loop variables
|
||||||
m_counter = 0;
|
m_counter = 0;
|
||||||
@ -425,12 +446,12 @@ void cell_audio_thread::operator()()
|
|||||||
const u64 time_since_last_period = timestamp - m_last_period_end;
|
const u64 time_since_last_period = timestamp - m_last_period_end;
|
||||||
const bool playing = !ringbuffer->is_playing();
|
const bool playing = !ringbuffer->is_playing();
|
||||||
|
|
||||||
if (!buffering_enabled)
|
if (!cfg.buffering_enabled)
|
||||||
{
|
{
|
||||||
const u64 period_end = (m_counter * audio_block_period) + m_start_time;
|
const u64 period_end = (m_counter * cfg.audio_block_period) + m_start_time;
|
||||||
const s64 time_left = period_end - timestamp;
|
const s64 time_left = period_end - timestamp;
|
||||||
|
|
||||||
if (time_left > period_comparison_margin)
|
if (time_left > cfg.period_comparison_margin)
|
||||||
{
|
{
|
||||||
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
|
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
|
||||||
continue;
|
continue;
|
||||||
@ -438,8 +459,8 @@ void cell_audio_thread::operator()()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const u64 enqueued_playtime = ringbuffer->get_enqueued_samples() * 1'000'000 / audio_sampling_rate;
|
const u64 enqueued_playtime = ringbuffer->get_enqueued_samples() * 1'000'000 / cfg.audio_sampling_rate;
|
||||||
const u64 enqueued_buffers = (enqueued_playtime) / audio_block_period;
|
const u64 enqueued_buffers = (enqueued_playtime) / cfg.audio_block_period;
|
||||||
|
|
||||||
const bool playing = ringbuffer->is_playing();
|
const bool playing = ringbuffer->is_playing();
|
||||||
|
|
||||||
@ -455,32 +476,32 @@ void cell_audio_thread::operator()()
|
|||||||
if (!playing)
|
if (!playing)
|
||||||
{
|
{
|
||||||
// When the buffer is empty, always use the correct block period
|
// When the buffer is empty, always use the correct block period
|
||||||
m_dynamic_period = audio_block_period;
|
m_dynamic_period = cfg.audio_block_period;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 1.0 means exactly as desired
|
// 1.0 means exactly as desired
|
||||||
// <1.0 means not as full as desired
|
// <1.0 means not as full as desired
|
||||||
// >1.0 means more full than desired
|
// >1.0 means more full than desired
|
||||||
const f32 desired_duration_rate = (enqueued_playtime) / static_cast<f32>(desired_buffer_duration);
|
const f32 desired_duration_rate = (enqueued_playtime) / static_cast<f32>(cfg.desired_buffer_duration);
|
||||||
|
|
||||||
if (desired_duration_rate >= 1.0f)
|
if (desired_duration_rate >= 1.0f)
|
||||||
{
|
{
|
||||||
// more full than desired
|
// more full than desired
|
||||||
const f32 multiplier = 1.0f / desired_duration_rate;
|
const f32 multiplier = 1.0f / desired_duration_rate;
|
||||||
m_dynamic_period = maximum_block_period - static_cast<u64>((maximum_block_period - audio_block_period) * multiplier);
|
m_dynamic_period = cfg.maximum_block_period - static_cast<u64>((cfg.maximum_block_period - cfg.audio_block_period) * multiplier);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// not as full as desired
|
// not as full as desired
|
||||||
const f32 multiplier = desired_duration_rate;
|
const f32 multiplier = desired_duration_rate;
|
||||||
m_dynamic_period = minimum_block_period + static_cast<u64>((audio_block_period - minimum_block_period) * multiplier);
|
m_dynamic_period = cfg.minimum_block_period + static_cast<u64>((cfg.audio_block_period - cfg.minimum_block_period) * multiplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 time_left = m_dynamic_period - time_since_last_period;
|
s64 time_left = m_dynamic_period - time_since_last_period;
|
||||||
if (time_left > period_comparison_margin)
|
if (time_left > cfg.period_comparison_margin)
|
||||||
{
|
{
|
||||||
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
|
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
|
||||||
continue;
|
continue;
|
||||||
@ -549,33 +570,33 @@ void cell_audio_thread::operator()()
|
|||||||
{
|
{
|
||||||
// We are not playing (likely buffer underrun)
|
// We are not playing (likely buffer underrun)
|
||||||
// align to 5.(3)ms on global clock
|
// align to 5.(3)ms on global clock
|
||||||
const s64 audio_period_alignment_delta = (timestamp - m_start_time) % audio_block_period;
|
const s64 audio_period_alignment_delta = (timestamp - m_start_time) % cfg.audio_block_period;
|
||||||
if (audio_period_alignment_delta > period_comparison_margin)
|
if (audio_period_alignment_delta > cfg.period_comparison_margin)
|
||||||
{
|
{
|
||||||
thread_ctrl::wait_for(audio_period_alignment_delta - period_comparison_margin);
|
thread_ctrl::wait_for(audio_period_alignment_delta - cfg.period_comparison_margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush, add silence, restart algorithm
|
// Flush, add silence, restart algorithm
|
||||||
cellAudio.error("play/resume audio: received first audio buffer");
|
cellAudio.error("play/resume audio: received first audio buffer");
|
||||||
ringbuffer->flush();
|
ringbuffer->flush();
|
||||||
ringbuffer->enqueue_silence(desired_full_buffers);
|
ringbuffer->enqueue_silence(cfg.desired_full_buffers);
|
||||||
finish_port_volume_stepping();
|
finish_port_volume_stepping();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mix
|
// Mix
|
||||||
float *buf = ringbuffer->get_current_buffer();
|
float *buf = ringbuffer->get_current_buffer();
|
||||||
if (audio_channels == 2)
|
if (cfg.audio_channels == 2)
|
||||||
{
|
{
|
||||||
mix<true>(buf);
|
mix<true>(buf);
|
||||||
}
|
}
|
||||||
else if (audio_channels == 8)
|
else if (cfg.audio_channels == 8)
|
||||||
{
|
{
|
||||||
mix<false>(buf);
|
mix<false>(buf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fmt::throw_exception("Unsupported number of audio channels: %u", audio_channels);
|
fmt::throw_exception("Unsupported number of audio channels: %u", cfg.audio_channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue
|
// Enqueue
|
||||||
@ -604,7 +625,7 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
|||||||
{
|
{
|
||||||
if (port.state != audio_port_state::started) continue;
|
if (port.state != audio_port_state::started) continue;
|
||||||
|
|
||||||
if (buffering_enabled)
|
if (cfg.buffering_enabled)
|
||||||
{
|
{
|
||||||
port.apply_tag_backups(offset);
|
port.apply_tag_backups(offset);
|
||||||
}
|
}
|
||||||
@ -1094,7 +1115,7 @@ error_code cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr<u64> stamp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 delta_tag = port.global_counter - tag;
|
u64 delta_tag = port.global_counter - tag;
|
||||||
u64 delta_tag_stamp = delta_tag * g_audio->audio_block_period;
|
u64 delta_tag_stamp = delta_tag * g_audio->cfg.audio_block_period;
|
||||||
*stamp = port.timestamp - delta_tag_stamp;
|
*stamp = port.timestamp - delta_tag_stamp;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "Utilities/Thread.h"
|
#include "Utilities/Thread.h"
|
||||||
#include "Emu/Memory/vm.h"
|
#include "Emu/Memory/vm.h"
|
||||||
#include "Emu/Audio/AudioThread.h"
|
#include "Emu/Audio/AudioBackend.h"
|
||||||
#include "Emu/Audio/AudioDumper.h"
|
#include "Emu/Audio/AudioDumper.h"
|
||||||
|
|
||||||
// Error codes
|
// Error codes
|
||||||
@ -170,15 +170,34 @@ struct audio_port
|
|||||||
void apply_tag_backups(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 u32 audio_channels = AudioBackend::get_channels();
|
||||||
|
const u32 audio_sampling_rate = AudioBackend::get_sampling_rate();
|
||||||
|
const u64 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 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 = audio_block_period + (audio_block_period - minimum_block_period); // the block period will not be dynamically increased above this value (usecs)
|
||||||
|
|
||||||
|
const u32 desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 1 : 1;
|
||||||
|
const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers
|
||||||
|
};
|
||||||
|
|
||||||
class audio_ringbuffer
|
class audio_ringbuffer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const std::shared_ptr<AudioThread> backend;
|
const std::shared_ptr<AudioBackend> backend;
|
||||||
|
|
||||||
|
const cell_audio_config& cfg;
|
||||||
|
|
||||||
const u32 num_allocated_buffers;
|
|
||||||
const u32 buf_sz;
|
const u32 buf_sz;
|
||||||
const u32 audio_sampling_rate;
|
|
||||||
const u32 channels;
|
|
||||||
|
|
||||||
std::unique_ptr<AudioDumper> m_dump;
|
std::unique_ptr<AudioDumper> m_dump;
|
||||||
|
|
||||||
@ -189,16 +208,23 @@ private:
|
|||||||
bool playing = false;
|
bool playing = false;
|
||||||
bool emu_paused = false;
|
bool emu_paused = false;
|
||||||
|
|
||||||
|
u32 backend_capabilities;
|
||||||
|
|
||||||
u64 update_timestamp = 0;
|
u64 update_timestamp = 0;
|
||||||
u64 play_timestamp = 0;
|
u64 play_timestamp = 0;
|
||||||
|
|
||||||
u64 last_remainder = 0;
|
u64 last_remainder = 0;
|
||||||
u64 enqueued_samples = 0;
|
u64 enqueued_samples = 0;
|
||||||
|
|
||||||
u32 next_buf = 0;
|
u32 cur_pos = 0;
|
||||||
|
|
||||||
|
bool backend_is_playing() const
|
||||||
|
{
|
||||||
|
return (backend_capabilities & AudioBackend::IS_PLAYING) ? backend->IsPlaying() : playing;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
audio_ringbuffer(u32 num_buffers, u32 audio_sampling_rate, u32 channels);
|
audio_ringbuffer(cell_audio_config &cfg);
|
||||||
~audio_ringbuffer();
|
~audio_ringbuffer();
|
||||||
|
|
||||||
void play();
|
void play();
|
||||||
@ -209,16 +235,11 @@ public:
|
|||||||
|
|
||||||
float* get_buffer(u32 num) const
|
float* get_buffer(u32 num) const
|
||||||
{
|
{
|
||||||
AUDIT(num < num_allocated_buffers);
|
AUDIT(num < cfg.num_allocated_buffers);
|
||||||
AUDIT(buffer[num].get() != nullptr);
|
AUDIT(buffer[num].get() != nullptr);
|
||||||
return buffer[num].get();
|
return buffer[num].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 get_buf_sz() const
|
|
||||||
{
|
|
||||||
return buf_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 get_timestamp() const
|
u64 get_timestamp() const
|
||||||
{
|
{
|
||||||
return get_system_time() - Emu.GetPauseTime();
|
return get_system_time() - Emu.GetPauseTime();
|
||||||
@ -226,11 +247,12 @@ public:
|
|||||||
|
|
||||||
float* get_current_buffer() const
|
float* get_current_buffer() const
|
||||||
{
|
{
|
||||||
return get_buffer(next_buf);
|
return get_buffer(cur_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 get_enqueued_samples() const
|
u64 get_enqueued_samples() const
|
||||||
{
|
{
|
||||||
|
AUDIT(cfg.buffering_enabled);
|
||||||
return enqueued_samples;
|
return enqueued_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +260,11 @@ public:
|
|||||||
{
|
{
|
||||||
return playing;
|
return playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 capabilities() const
|
||||||
|
{
|
||||||
|
return backend_capabilities;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -260,19 +287,7 @@ class cell_audio_thread
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
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
|
cell_audio_config cfg;
|
||||||
|
|
||||||
const u32 audio_channels = AudioThread::get_channels();
|
|
||||||
const u32 audio_sampling_rate = AudioThread::get_sampling_rate();
|
|
||||||
const u64 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 bool buffering_enabled = g_cfg.audio.enable_buffering && (desired_buffer_duration >= audio_block_period);
|
|
||||||
|
|
||||||
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 = audio_block_period + (audio_block_period - minimum_block_period); // the block period will not be dynamically increased above this value (usecs)
|
|
||||||
|
|
||||||
const u32 desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 1 : 1;
|
|
||||||
const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers
|
|
||||||
|
|
||||||
std::vector<u64> keys;
|
std::vector<u64> keys;
|
||||||
std::array<audio_port, AUDIO_PORT_COUNT> ports;
|
std::array<audio_port, AUDIO_PORT_COUNT> ports;
|
||||||
|
@ -633,7 +633,7 @@ s32 cellSurMixerGetTimestamp(u64 tag, vm::ptr<u64> stamp)
|
|||||||
|
|
||||||
const auto g_audio = fxm::get<cell_audio>();
|
const auto g_audio = fxm::get<cell_audio>();
|
||||||
|
|
||||||
*stamp = g_audio->m_start_time + tag * AUDIO_BUFFER_SAMPLES * 1'000'000 / g_audio->audio_sampling_rate;
|
*stamp = g_audio->m_start_time + tag * AUDIO_BUFFER_SAMPLES * 1'000'000 / g_audio->cfg.audio_sampling_rate;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ struct EmuCallbacks
|
|||||||
std::function<std::shared_ptr<class pad_thread>()> get_pad_handler;
|
std::function<std::shared_ptr<class pad_thread>()> get_pad_handler;
|
||||||
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
|
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
|
||||||
std::function<std::shared_ptr<class GSRender>()> get_gs_render;
|
std::function<std::shared_ptr<class GSRender>()> get_gs_render;
|
||||||
std::function<std::shared_ptr<class AudioThread>()> get_audio;
|
std::function<std::shared_ptr<class AudioBackend>()> get_audio;
|
||||||
std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog;
|
std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog;
|
||||||
std::function<std::shared_ptr<class OskDialogBase>()> get_osk_dialog;
|
std::function<std::shared_ptr<class OskDialogBase>()> get_osk_dialog;
|
||||||
std::function<std::unique_ptr<class SaveDialogBase>()> get_save_dialog;
|
std::function<std::unique_ptr<class SaveDialogBase>()> get_save_dialog;
|
||||||
|
@ -72,12 +72,12 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\rpcs3\Emu\Audio\XAudio2\XAudio2Thread.h" />
|
<ClInclude Include="Emu\Audio\XAudio2\XAudio2Backend.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\rpcs3\Emu\Audio\XAudio2\XAudio2Thread.cpp" />
|
<ClCompile Include="Emu\Audio\XAudio2\XAudio2Backend.cpp" />
|
||||||
<ClCompile Include="Emu\Audio\XAudio2\XAudio27Thread.cpp" />
|
<ClCompile Include="Emu\Audio\XAudio2\XAudio27Backend.cpp" />
|
||||||
<ClCompile Include="Emu\Audio\XAudio2\XAudio28Thread.cpp" />
|
<ClCompile Include="Emu\Audio\XAudio2\XAudio28Backend.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
@ -7,18 +7,18 @@
|
|||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\rpcs3\Emu\Audio\XAudio2\XAudio2Thread.cpp">
|
<ClCompile Include="Emu\Audio\XAudio2\XAudio2Backend.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Emu\Audio\XAudio2\XAudio28Thread.cpp">
|
<ClCompile Include="Emu\Audio\XAudio2\XAudio27Backend.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Emu\Audio\XAudio2\XAudio27Thread.cpp">
|
<ClCompile Include="Emu\Audio\XAudio2\XAudio28Backend.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\rpcs3\Emu\Audio\XAudio2\XAudio2Thread.h">
|
<ClInclude Include="Emu\Audio\XAudio2\XAudio2Backend.h">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -406,8 +406,8 @@
|
|||||||
<ClInclude Include="Emu\CPU\CPUTranslator.h" />
|
<ClInclude Include="Emu\CPU\CPUTranslator.h" />
|
||||||
<ClInclude Include="Emu\IPC.h" />
|
<ClInclude Include="Emu\IPC.h" />
|
||||||
<ClInclude Include="Emu\Audio\AudioDumper.h" />
|
<ClInclude Include="Emu\Audio\AudioDumper.h" />
|
||||||
<ClInclude Include="Emu\Audio\AudioThread.h" />
|
<ClInclude Include="Emu\Audio\AudioBackend.h" />
|
||||||
<ClInclude Include="Emu\Audio\Null\NullAudioThread.h" />
|
<ClInclude Include="Emu\Audio\Null\NullAudioBackend.h" />
|
||||||
<ClInclude Include="Emu\Cell\Common.h" />
|
<ClInclude Include="Emu\Cell\Common.h" />
|
||||||
<ClInclude Include="Emu\Cell\ErrorCodes.h" />
|
<ClInclude Include="Emu\Cell\ErrorCodes.h" />
|
||||||
<ClInclude Include="Emu\Cell\lv2\sys_cond.h" />
|
<ClInclude Include="Emu\Cell\lv2\sys_cond.h" />
|
||||||
|
@ -925,9 +925,6 @@
|
|||||||
<ClInclude Include="..\Utilities\Thread.h">
|
<ClInclude Include="..\Utilities\Thread.h">
|
||||||
<Filter>Utilities</Filter>
|
<Filter>Utilities</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\Audio\Null\NullAudioThread.h">
|
|
||||||
<Filter>Emu\Audio\Null</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\Utilities\File.h">
|
<ClInclude Include="..\Utilities\File.h">
|
||||||
<Filter>Utilities</Filter>
|
<Filter>Utilities</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -1456,8 +1453,11 @@
|
|||||||
<ClInclude Include="Emu\RSX\Common\texture_cache_predictor.h">
|
<ClInclude Include="Emu\RSX\Common\texture_cache_predictor.h">
|
||||||
<Filter>Emu\GPU\RSX\Common</Filter>
|
<Filter>Emu\GPU\RSX\Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\Audio\AudioThread.h">
|
<ClInclude Include="Emu\Audio\AudioBackend.h">
|
||||||
<Filter>Emu\Audio</Filter>
|
<Filter>Emu\Audio</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Audio\Null\NullAudioBackend.h">
|
||||||
|
<Filter>Emu\Audio\Null</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#include "Emu/RSX/Null/NullGSRender.h"
|
#include "Emu/RSX/Null/NullGSRender.h"
|
||||||
#include "Emu/RSX/GL/GLGSRender.h"
|
#include "Emu/RSX/GL/GLGSRender.h"
|
||||||
#include "Emu/Audio/Null/NullAudioThread.h"
|
#include "Emu/Audio/Null/NullAudioBackend.h"
|
||||||
//#include "Emu/Audio/AL/OpenALThread.h"
|
//#include "Emu/Audio/AL/OpenALThread.h"
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include "Emu/RSX/D3D12/D3D12GSRender.h"
|
#include "Emu/RSX/D3D12/D3D12GSRender.h"
|
||||||
@ -45,7 +45,7 @@
|
|||||||
#include "Emu/RSX/VK/VKGSRender.h"
|
#include "Emu/RSX/VK/VKGSRender.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Emu/Audio/XAudio2/XAudio2Thread.h"
|
#include "Emu/Audio/XAudio2/XAudio2Backend.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
#include "Emu/Audio/ALSA/ALSAThread.h"
|
#include "Emu/Audio/ALSA/ALSAThread.h"
|
||||||
@ -254,13 +254,13 @@ void rpcs3_app::InitializeCallbacks()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
callbacks.get_audio = []() -> std::shared_ptr<AudioThread>
|
callbacks.get_audio = []() -> std::shared_ptr<AudioBackend>
|
||||||
{
|
{
|
||||||
switch (audio_renderer type = g_cfg.audio.renderer)
|
switch (audio_renderer type = g_cfg.audio.renderer)
|
||||||
{
|
{
|
||||||
case audio_renderer::null: return std::make_shared<NullAudioThread>();
|
case audio_renderer::null: return std::make_shared<NullAudioBackend>();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
case audio_renderer::xaudio: return std::make_shared<XAudio2Thread>();
|
case audio_renderer::xaudio: return std::make_shared<XAudio2Backend>();
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
case audio_renderer::alsa: return std::make_shared<ALSAThread>();
|
case audio_renderer::alsa: return std::make_shared<ALSAThread>();
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "Emu/Io/KeyboardHandler.h"
|
#include "Emu/Io/KeyboardHandler.h"
|
||||||
#include "Emu/Io/PadHandler.h"
|
#include "Emu/Io/PadHandler.h"
|
||||||
#include "Emu/Io/MouseHandler.h"
|
#include "Emu/Io/MouseHandler.h"
|
||||||
#include "Emu/Audio/AudioThread.h"
|
#include "Emu/Audio/AudioBackend.h"
|
||||||
|
|
||||||
#include "rpcs3qt/msg_dialog_frame.h"
|
#include "rpcs3qt/msg_dialog_frame.h"
|
||||||
#include "rpcs3qt/osk_dialog_frame.h"
|
#include "rpcs3qt/osk_dialog_frame.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user