1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2025-01-31 12:31:45 +01:00

Rewrite OpenAL backend to support new features

This commit is contained in:
Rui Pinheiro 2018-12-21 01:16:54 +00:00 committed by kd-11
parent f90646ec88
commit 4f39457858
14 changed files with 282 additions and 215 deletions

View File

@ -0,0 +1,208 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "OpenALBackend.h"
#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib")
#endif
#define checkForAlError(sit) do { ALenum g_last_al_error = alGetError(); if(g_last_al_error != AL_NO_ERROR) fmt::throw_exception("%s: OpenAL error 0x%04x", sit, g_last_al_error); } while(0)
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) fmt::throw_exception("%s: OpenALC error 0x%04x", sit, g_last_alc_error); } while(0)
OpenALBackend::OpenALBackend()
: m_sampling_rate(get_sampling_rate())
, m_sample_size(get_sample_size())
{
ALCdevice* m_device = alcOpenDevice(nullptr);
checkForAlcError("OpenALBackend->alcOpenDevice");
ALCcontext* m_context = alcCreateContext(m_device, nullptr);
checkForAlcError("OpenALBackend->alcCreateContext");
alcMakeContextCurrent(m_context);
checkForAlcError("OpenALBackend->alcMakeContextCurrent");
if (get_channels() == 2)
{
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
}
else
{
m_format = (m_sample_size == 2) ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
}
}
OpenALBackend::~OpenALBackend()
{
if (alIsSource(m_source))
{
Close();
}
if (ALCcontext* m_context = alcGetCurrentContext())
{
ALCdevice* m_device = alcGetContextsDevice(m_context);
alcMakeContextCurrent(nullptr);
alcDestroyContext(m_context);
alcCloseDevice(m_device);
}
}
void OpenALBackend::Play()
{
AUDIT(alIsSource(m_source));
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
checkForAlError("Play->alGetSourcei(AL_SOURCE_STATE)");
if (state != AL_PLAYING)
{
alSourcePlay(m_source);
checkForAlError("Play->alSourcePlay");
}
}
void OpenALBackend::Pause()
{
AUDIT(alIsSource(m_source));
alSourcePause(m_source);
checkForAlError("Pause->alSourcePause");
}
bool OpenALBackend::IsPlaying()
{
AUDIT(alIsSource(m_source));
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
checkForAlError("IsPlaying->alGetSourcei(AL_SOURCE_STATE)");
return state == AL_PLAYING;
}
void OpenALBackend::Open(u32 num_buffers)
{
AUDIT(!alIsSource(m_source));
// Initialize Source
alGenSources(1, &m_source);
checkForAlError("Open->alGenSources");
alSourcei(m_source, AL_LOOPING, AL_FALSE);
checkForAlError("Open->alSourcei");
// Initialize Buffers
alGenBuffers(num_buffers, m_buffers);
checkForAlError("Open->alGenBuffers");
m_num_buffers = num_buffers;
m_num_unqueued = num_buffers;
}
void OpenALBackend::Close()
{
if (alIsSource(m_source))
{
// Stop & Kill Source
Pause();
alDeleteSources(1, &m_source);
// Free Buffers
alDeleteBuffers(m_num_buffers, m_buffers);
checkForAlError("alDeleteBuffers");
}
}
bool OpenALBackend::AddData(const void* src, u32 size)
{
AUDIT(alIsSource(m_source));
// Unqueue processed buffers, if any
unqueue_processed();
// Fail if there are no free buffers remaining
if (m_num_unqueued == 0)
{
LOG_WARNING(GENERAL, "XAudio2Backend : no unqueued buffers remaining");
return false;
}
// Copy data to the next available buffer
alBufferData(m_buffers[m_next_buffer], m_format, src, size * m_sample_size, m_sampling_rate);
checkForAlError("AddData->alBufferData");
// Enqueue buffer
alSourceQueueBuffers(m_source, 1, &m_buffers[m_next_buffer]);
checkForAlError("AddData->alSourceQueueBuffers");
m_num_unqueued--;
m_next_buffer = (m_next_buffer + 1) % m_num_buffers;
return true;
}
void OpenALBackend::Flush()
{
AUDIT(alIsSource(m_source));
// Stop source first
alSourceStop(m_source);
checkForAlError("Flush->alSourceStop");
// Unqueue processed buffers (should now be all of them)
unqueue_processed();
}
void OpenALBackend::unqueue_processed()
{
AUDIT(alIsSource(m_source));
// Get number of buffers
ALint num_processed;
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &num_processed);
checkForAlError("Flush->alGetSourcei(AL_BUFFERS_PROCESSED)");
if (num_processed > 0)
{
// Unqueue all buffers
ALuint x[MAX_AUDIO_BUFFERS];
alSourceUnqueueBuffers(m_source, num_processed, x);
checkForAlError("Flush->alSourceUnqueueBuffers");
m_num_unqueued += num_processed;
}
}
u64 OpenALBackend::GetNumEnqueuedSamples()
{
AUDIT(alIsSource(m_source));
// Get number of buffers queued
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);
// Get sample position
ALint sample_pos;
alGetSourcei(m_source, AL_SAMPLE_OFFSET, &sample_pos);
checkForAlError("GetNumEnqueuedSamples->alGetSourcei(AL_SAMPLE_OFFSET)");
// Return
return (num_queued * AUDIO_BUFFER_SAMPLES) + (sample_pos % AUDIO_BUFFER_SAMPLES);
}
f32 OpenALBackend::SetFrequencyRatio(f32 new_ratio)
{
new_ratio = std::clamp(new_ratio, 0.5f, 2.0f);
alSourcef(m_source, AL_PITCH, new_ratio);
checkForAlError("SetFrequencyRatio->alSourcei(AL_PITCH)");
return new_ratio;
}

View File

@ -0,0 +1,44 @@
#pragma once
#include "Emu/Audio/AudioBackend.h"
#include "3rdparty/OpenAL/include/alext.h"
#include <memory>
class OpenALBackend : public AudioBackend
{
private:
ALint m_format;
ALuint m_source;
ALuint m_buffers[MAX_AUDIO_BUFFERS];
ALsizei m_num_buffers;
u32 m_next_buffer = 0;
u32 m_num_unqueued = 0;
const u32 m_sampling_rate;
const u32 m_sample_size;
void unqueue_processed();
public:
OpenALBackend();
virtual ~OpenALBackend() override;
virtual const char* GetName() const override { return "OpenAL"; };
static const u32 capabilities = NON_BLOCKING | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
virtual u32 GetCapabilities() const override { return capabilities; };
virtual void Open(u32 num_buffers) override;
virtual void Close() override;
virtual void Play() override;
virtual void Pause() override;
virtual bool IsPlaying() override;
virtual bool AddData(const void* src, u32 size) override;
virtual void Flush() override;
virtual u64 GetNumEnqueuedSamples() override;
virtual f32 SetFrequencyRatio(f32 new_ratio) override;
};

View File

@ -1,160 +0,0 @@
/*#include "stdafx.h"
#include "Emu/System.h"
#include "OpenALThread.h"
#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib")
#endif
ALenum g_last_al_error = AL_NO_ERROR;
ALCenum g_last_alc_error = ALC_NO_ERROR;
#define checkForAlError(sit) if((g_last_al_error = alGetError()) != AL_NO_ERROR) printAlError(g_last_al_error, sit)
#define checkForAlcError(sit) if((g_last_alc_error = alcGetError(m_device)) != ALC_NO_ERROR) printAlcError(g_last_alc_error, sit)
void printAlError(ALenum err, const char* situation)
{
if (err != AL_NO_ERROR)
{
LOG_ERROR(HLE, "%s: OpenAL error 0x%04x", situation, err);
Emu.Pause();
}
}
void printAlcError(ALCenum err, const char* situation)
{
if (err != ALC_NO_ERROR)
{
LOG_ERROR(HLE, "%s: OpenALC error 0x%04x", situation, err);
Emu.Pause();
}
}
OpenALThread::OpenALThread()
{
ALCdevice* m_device = alcOpenDevice(nullptr);
checkForAlcError("alcOpenDevice");
ALCcontext* m_context = alcCreateContext(m_device, nullptr);
checkForAlcError("alcCreateContext");
alcMakeContextCurrent(m_context);
checkForAlcError("alcMakeContextCurrent");
if (g_cfg.audio.downmix_to_2ch)
{
m_format = g_cfg.audio.convert_to_u16 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
}
else
{
m_format = g_cfg.audio.convert_to_u16 ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32;
}
m_buffers = std::make_unique<ALuint[]>(g_cfg.audio.frames);
}
OpenALThread::~OpenALThread()
{
if (ALCcontext* m_context = alcGetCurrentContext())
{
ALCdevice* m_device = alcGetContextsDevice(m_context);
alcMakeContextCurrent(nullptr);
alcDestroyContext(m_context);
alcCloseDevice(m_device);
}
}
void OpenALThread::Play()
{
ALint state;
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
checkForAlError("OpenALThread::Play -> alGetSourcei");
if (state != AL_PLAYING)
{
alSourcePlay(m_source);
checkForAlError("alSourcePlay");
}
}
void OpenALThread::Close()
{
alSourceStop(m_source);
checkForAlError("alSourceStop");
if (alIsSource(m_source))
alDeleteSources(1, &m_source);
alDeleteBuffers(g_cfg.audio.frames, m_buffers.get());
checkForAlError("alDeleteBuffers");
}
void OpenALThread::Stop()
{
alSourceStop(m_source);
checkForAlError("alSourceStop");
}
void OpenALThread::Open(const void* src, int size)
{
alGenSources(1, &m_source);
checkForAlError("alGenSources");
alGenBuffers(g_cfg.audio.frames, m_buffers.get());
checkForAlError("alGenBuffers");
alSourcei(m_source, AL_LOOPING, AL_FALSE);
checkForAlError("OpenALThread::Open ->alSourcei");
m_buffer_size = size;
for (int i = 0; i < g_cfg.audio.frames; ++i)
{
alBufferData(m_buffers[i], m_format, src, m_buffer_size, 48000);
checkForAlError("alBufferData");
}
alSourceQueueBuffers(m_source, g_cfg.audio.frames, m_buffers.get());
checkForAlError("alSourceQueueBuffers");
Play();
}
void OpenALThread::AddData(const void* src, int size)
{
const char* bsrc = (const char*)src;
ALuint buffer;
ALint buffers_count;
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &buffers_count);
checkForAlError("OpenALThread::AddData -> alGetSourcei");
while (size)
{
if (buffers_count-- <= 0)
{
Play();
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &buffers_count);
checkForAlError("OpenALThread::AddData(in loop) -> alGetSourcei");
continue;
}
alSourceUnqueueBuffers(m_source, 1, &buffer);
checkForAlError("alSourceUnqueueBuffers");
int bsize = size < m_buffer_size ? size : m_buffer_size;
alBufferData(buffer, m_format, bsrc, bsize, 48000);
checkForAlError("alBufferData");
alSourceQueueBuffers(m_source, 1, &buffer);
checkForAlError("alSourceQueueBuffers");
size -= bsize;
bsrc += bsize;
}
Play();
}
*/

View File

@ -1,25 +0,0 @@
#pragma once
/*#include "Emu/Audio/AudioBackend.h"
#include "3rdparty/OpenAL/include/alext.h"
#include <memory>
class OpenALThread : public AudioBackend
{
private:
ALint m_format;
ALuint m_source;
std::unique_ptr<ALuint[]> m_buffers;
ALsizei m_buffer_size;
public:
OpenALThread();
virtual ~OpenALThread() 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;
};
*/

View File

@ -27,7 +27,7 @@ public:
virtual const char* GetName() const = 0;
virtual u32 GetCapabilities() const = 0;
virtual void Open() = 0;
virtual void Open(u32 num_buffers) = 0;
virtual void Close() = 0;
virtual void Play() = 0;
@ -38,7 +38,7 @@ public:
fmt::throw_exception("IsPlaying() not implemented");
};
virtual bool AddData(const void* src, int size) = 0;
virtual bool AddData(const void* src, u32 size) = 0;
virtual void Flush() = 0;
virtual u64 GetNumEnqueuedSamples()
@ -47,7 +47,7 @@ public:
return 0;
}
virtual f32 SetFrequencyRatio(f32 new_ratio) // returns the new ratio
virtual f32 SetFrequencyRatio(f32 /* new_ratio */) // returns the new ratio
{
fmt::throw_exception("SetFrequencyRatio() not implemented");
return 1.0f;

View File

@ -13,12 +13,12 @@ public:
static const u32 capabilities = NON_BLOCKING;
virtual u32 GetCapabilities() const override { return capabilities; };
virtual void Open() override {};
virtual void Open(u32) 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 bool AddData(const void*, u32) override { return true; };
virtual void Flush() override {};
};

View File

@ -133,7 +133,7 @@ void XAudio2Backend::xa27_open()
s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
}
bool XAudio2Backend::xa27_add(const void* src, int size)
bool XAudio2Backend::xa27_add(const void* src, u32 size)
{
XAUDIO2_VOICE_STATE state;
s_tls_source_voice->GetState(&state);

View File

@ -141,10 +141,10 @@ void XAudio2Backend::xa28_open()
}
AUDIT(s_tls_source_voice != nullptr);
s_tls_source_voice->SetVolume(channels == 2 ? 1.0 : 4.0);
s_tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
}
bool XAudio2Backend::xa28_add(const void* src, int size)
bool XAudio2Backend::xa28_add(const void* src, u32 size)
{
AUDIT(s_tls_source_voice != nullptr);
@ -153,7 +153,7 @@ bool XAudio2Backend::xa28_add(const void* src, int size)
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
{
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed);
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d)", state.BuffersQueued);
return false;
}

View File

@ -87,7 +87,7 @@ void XAudio2Backend::Pause()
m_funcs.stop();
}
void XAudio2Backend::Open()
void XAudio2Backend::Open(u32 /* num_buffers */)
{
m_funcs.open();
}
@ -97,7 +97,7 @@ bool XAudio2Backend::IsPlaying()
return m_funcs.is_playing();
}
bool XAudio2Backend::AddData(const void* src, int size)
bool XAudio2Backend::AddData(const void* src, u32 size)
{
return m_funcs.add(src, size);
}

View File

@ -14,7 +14,7 @@ class XAudio2Backend : public AudioBackend
void(*stop)();
void(*open)();
bool(*is_playing)();
bool(*add)(const void*, int);
bool(*add)(const void*, u32);
u64(*enqueued_samples)();
f32(*set_freq_ratio)(f32);
};
@ -28,7 +28,7 @@ class XAudio2Backend : public AudioBackend
static void xa27_stop();
static void xa27_open();
static bool xa27_is_playing();
static bool xa27_add(const void*, int);
static bool xa27_add(const void*, u32);
static u64 xa27_enqueued_samples();
static f32 xa27_set_freq_ratio(f32);
@ -39,7 +39,7 @@ class XAudio2Backend : public AudioBackend
static void xa28_stop();
static void xa28_open();
static bool xa28_is_playing();
static bool xa28_add(const void*, int);
static bool xa28_add(const void*, u32);
static u64 xa28_enqueued_samples();
static f32 xa28_set_freq_ratio(f32);
@ -52,14 +52,14 @@ public:
static const u32 capabilities = NON_BLOCKING | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
virtual u32 GetCapabilities() const override { return capabilities; };
virtual void Open() override;
virtual void Open(u32 /* num_buffers */) override;
virtual void Close() override;
virtual void Play() override;
virtual void Pause() override;
virtual bool IsPlaying() override;
virtual bool AddData(const void* src, int size) override;
virtual bool AddData(const void* src, u32 size) override;
virtual void Flush() override;
virtual u64 GetNumEnqueuedSamples() override;

View File

@ -67,7 +67,7 @@ audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
cellAudio.error("cellAudio initializing. Backend: %s, Capabilities: %s", backend->GetName(), str.c_str());
}
backend->Open();
backend->Open(cfg.num_allocated_buffers);
backend_open = true;
ASSERT(!backend_is_playing());
@ -147,7 +147,7 @@ void audio_ringbuffer::enqueue_silence(u32 buf_count)
void audio_ringbuffer::play()
{
if (playing)
if (has_capability(AudioBackend::IS_PLAYING) && playing)
return;
if (frequency_ratio != 1.0f)
@ -414,7 +414,7 @@ void cell_audio_thread::advance(u64 timestamp, bool reset)
if (cfg.buffering_enabled)
{
// Calculate rolling average of enqueued playtime
const u32 enqueued_playtime = ringbuffer->get_enqueued_playtime();
const u64 enqueued_playtime = ringbuffer->get_enqueued_playtime();
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);
}
@ -669,7 +669,7 @@ void cell_audio_thread::operator()()
ringbuffer->flush();
ringbuffer->enqueue_silence(cfg.desired_full_buffers);
finish_port_volume_stepping();
m_average_playtime = ringbuffer->get_enqueued_playtime();
m_average_playtime = static_cast<f32>(ringbuffer->get_enqueued_playtime());
}
}

View File

@ -68,10 +68,10 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\AL\OpenALThread.cpp" />
<ClCompile Include="Emu\Audio\AL\OpenALBackend.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\AL\OpenALThread.h" />
<ClInclude Include="Emu\Audio\AL\OpenALBackend.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="emucore.vcxproj">

View File

@ -7,13 +7,13 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\AL\OpenALThread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\AL\OpenALThread.h">
<ClInclude Include="Emu\Audio\AL\OpenALBackend.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\AL\OpenALBackend.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -37,7 +37,7 @@
#include "Emu/RSX/Null/NullGSRender.h"
#include "Emu/RSX/GL/GLGSRender.h"
#include "Emu/Audio/Null/NullAudioBackend.h"
//#include "Emu/Audio/AL/OpenALThread.h"
#include "Emu/Audio/AL/OpenALBackend.h"
#ifdef _MSC_VER
#include "Emu/RSX/D3D12/D3D12GSRender.h"
#endif
@ -269,7 +269,7 @@ void rpcs3_app::InitializeCallbacks()
case audio_renderer::pulse: return std::make_shared<PulseThread>();
#endif
//case audio_renderer::openal: return std::make_shared<OpenALThread>();
case audio_renderer::openal: return std::make_shared<OpenALBackend>();
default: fmt::throw_exception("Invalid audio renderer: %s" HERE, type);
}
};