mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-14 10:48:36 +12:00
Implement FAudio backend (#6374)
This commit is contained in:
parent
a32f979814
commit
06433d614a
15 changed files with 265 additions and 5 deletions
179
rpcs3/Emu/Audio/FAudio/FAudioBackend.cpp
Normal file
179
rpcs3/Emu/Audio/FAudio/FAudioBackend.cpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
#include "FAudioBackend.h"
|
||||
|
||||
#ifdef HAVE_FAUDIO
|
||||
|
||||
FAudioBackend::FAudioBackend()
|
||||
{
|
||||
u32 res;
|
||||
|
||||
res = FAudioCreate(&m_instance, 0, FAUDIO_DEFAULT_PROCESSOR);
|
||||
if (res)
|
||||
{
|
||||
fmt::throw_exception("FAudioCreate() failed(0x%08x)", res);
|
||||
}
|
||||
|
||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000, 0, 0, nullptr);
|
||||
if (res)
|
||||
{
|
||||
fmt::throw_exception("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||
}
|
||||
}
|
||||
|
||||
FAudioBackend::~FAudioBackend()
|
||||
{
|
||||
if (m_source_voice != nullptr)
|
||||
{
|
||||
FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
FAudioVoice_DestroyVoice(m_source_voice);
|
||||
}
|
||||
|
||||
if (m_master_voice != nullptr)
|
||||
{
|
||||
FAudioVoice_DestroyVoice(m_master_voice);
|
||||
}
|
||||
|
||||
if (m_instance != nullptr)
|
||||
{
|
||||
FAudio_StopEngine(m_instance);
|
||||
FAudio_Release(m_instance);
|
||||
}
|
||||
}
|
||||
|
||||
void FAudioBackend::Play()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
u32 res = FAudioSourceVoice_Start(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_Start() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void FAudioBackend::Pause()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
u32 res = FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_Stop() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void FAudioBackend::Flush()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
u32 res = FAudioSourceVoice_FlushSourceBuffers(m_source_voice);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_FlushSourceBuffers() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
bool FAudioBackend::IsPlaying()
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||
}
|
||||
|
||||
void FAudioBackend::Close()
|
||||
{
|
||||
Pause();
|
||||
Flush();
|
||||
}
|
||||
|
||||
void FAudioBackend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
FAudioWaveFormatEx waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudio_CreateSourceVoice() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
FAudioVoice_SetVolume(m_source_voice, channels == 2 ? 1.0f : 4.0f, FAUDIO_COMMIT_NOW);
|
||||
}
|
||||
|
||||
bool FAudioBackend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
}
|
||||
|
||||
FAudioBuffer buffer;
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
buffer.LoopLength = 0;
|
||||
buffer.pAudioData = static_cast<const u8*>(src);
|
||||
buffer.pContext = 0;
|
||||
buffer.PlayBegin = 0;
|
||||
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
u32 res = FAudioSourceVoice_SubmitSourceBuffer(m_source_voice, &buffer, nullptr);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 FAudioBackend::GetNumEnqueuedSamples()
|
||||
{
|
||||
FAudioVoiceState state;
|
||||
FAudioSourceVoice_GetState(m_source_voice, &state, 0);
|
||||
|
||||
// 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 FAudioBackend::SetFrequencyRatio(f32 new_ratio)
|
||||
{
|
||||
new_ratio = std::clamp(new_ratio, FAUDIO_MIN_FREQ_RATIO, FAUDIO_DEFAULT_FREQ_RATIO);
|
||||
|
||||
u32 res = FAudioSourceVoice_SetFrequencyRatio(m_source_voice, new_ratio, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return new_ratio;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue