mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-12 13:13:43 +00:00
Try to make most audio configs dynamic
This commit is contained in:
parent
8ee953ef8e
commit
20d6664dc1
@ -12,8 +12,7 @@ LOG_CHANNEL(OpenAL);
|
|||||||
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
|
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
|
||||||
|
|
||||||
OpenALBackend::OpenALBackend()
|
OpenALBackend::OpenALBackend()
|
||||||
: m_sampling_rate(get_sampling_rate())
|
: AudioBackend()
|
||||||
, m_sample_size(get_sample_size())
|
|
||||||
{
|
{
|
||||||
ALCdevice* m_device = alcOpenDevice(nullptr);
|
ALCdevice* m_device = alcOpenDevice(nullptr);
|
||||||
checkForAlcError("alcOpenDevice");
|
checkForAlcError("alcOpenDevice");
|
||||||
@ -24,9 +23,7 @@ OpenALBackend::OpenALBackend()
|
|||||||
alcMakeContextCurrent(m_context);
|
alcMakeContextCurrent(m_context);
|
||||||
checkForAlcError("alcMakeContextCurrent");
|
checkForAlcError("alcMakeContextCurrent");
|
||||||
|
|
||||||
const auto channels = get_channels();
|
switch (m_channels)
|
||||||
|
|
||||||
switch (channels)
|
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
|
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
|
||||||
|
@ -15,9 +15,6 @@ private:
|
|||||||
u32 m_next_buffer = 0;
|
u32 m_next_buffer = 0;
|
||||||
u32 m_num_unqueued = 0;
|
u32 m_num_unqueued = 0;
|
||||||
|
|
||||||
const u32 m_sampling_rate;
|
|
||||||
const u32 m_sample_size;
|
|
||||||
|
|
||||||
void unqueue_processed();
|
void unqueue_processed();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#ifndef HAVE_ALSA
|
#ifndef HAVE_ALSA
|
||||||
#error "ALSA support disabled but still being built."
|
#error "ALSA support disabled but still being built."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ static bool check(int err, const char* reason)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALSABackend::ALSABackend()
|
ALSABackend::ALSABackend()
|
||||||
|
: AudioBackend()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,14 +52,14 @@ void ALSABackend::Open(u32 num_buffers)
|
|||||||
if (!check(snd_pcm_hw_params_set_access(tls_handle, tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
|
if (!check(snd_pcm_hw_params_set_access(tls_handle, tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!check(snd_pcm_hw_params_set_format(tls_handle, 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"))
|
if (!check(snd_pcm_hw_params_set_format(tls_handle, tls_hw_params, m_convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint rate = get_sampling_rate();
|
uint rate = m_sampling_rate;
|
||||||
if (!check(snd_pcm_hw_params_set_rate_near(tls_handle, tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near"))
|
if (!check(snd_pcm_hw_params_set_rate_near(tls_handle, tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, get_channels()), "snd_pcm_hw_params_set_channels"))
|
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, m_channels), "snd_pcm_hw_params_set_channels"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//uint period = 5333;
|
//uint period = 5333;
|
||||||
@ -92,7 +93,7 @@ void ALSABackend::Open(u32 num_buffers)
|
|||||||
if (!check(snd_pcm_sw_params_current(tls_handle, tls_sw_params), "snd_pcm_sw_params_current"))
|
if (!check(snd_pcm_sw_params_current(tls_handle, tls_sw_params), "snd_pcm_sw_params_current"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
period_frames *= g_cfg.audio.startt;
|
period_frames *= m_start_threshold;
|
||||||
|
|
||||||
if (!check(snd_pcm_sw_params_set_start_threshold(tls_handle, tls_sw_params, period_frames + 1), "snd_pcm_sw_params_set_start_threshold"))
|
if (!check(snd_pcm_sw_params_set_start_threshold(tls_handle, tls_sw_params, period_frames + 1), "snd_pcm_sw_params_set_start_threshold"))
|
||||||
return;
|
return;
|
||||||
@ -132,7 +133,7 @@ void ALSABackend::Close()
|
|||||||
|
|
||||||
bool ALSABackend::AddData(const void* src, u32 num_samples)
|
bool ALSABackend::AddData(const void* src, u32 num_samples)
|
||||||
{
|
{
|
||||||
u32 num_frames = num_samples / get_channels();
|
u32 num_frames = num_samples / m_channels;
|
||||||
|
|
||||||
int res = snd_pcm_writei(tls_handle, src, num_frames);
|
int res = snd_pcm_writei(tls_handle, src, num_frames);
|
||||||
|
|
||||||
|
@ -2,45 +2,69 @@
|
|||||||
#include "AudioBackend.h"
|
#include "AudioBackend.h"
|
||||||
#include "Emu/system_config.h"
|
#include "Emu/system_config.h"
|
||||||
|
|
||||||
/*
|
AudioBackend::AudioBackend()
|
||||||
* Helper methods
|
|
||||||
*/
|
|
||||||
u32 AudioBackend::get_sampling_rate()
|
|
||||||
{
|
{
|
||||||
|
m_convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16);
|
||||||
|
m_sample_size = m_convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||||
|
m_start_threshold = g_cfg.audio.start_threshold;
|
||||||
|
|
||||||
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
|
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
|
||||||
|
|
||||||
if (sampling_period_multiplier_u32 == 100)
|
if (sampling_period_multiplier_u32 == 100)
|
||||||
return DEFAULT_AUDIO_SAMPLING_RATE;
|
{
|
||||||
|
m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||||
|
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||||
|
m_sampling_rate = static_cast<u32>(f32{ DEFAULT_AUDIO_SAMPLING_RATE } *sampling_rate_multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
|
||||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
|
||||||
return static_cast<u32>(f32{DEFAULT_AUDIO_SAMPLING_RATE} * sampling_rate_multiplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 AudioBackend::get_sample_size()
|
|
||||||
{
|
|
||||||
return g_cfg.audio.convert_to_u16 ? sizeof(u16) : sizeof(float);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 AudioBackend::get_channels()
|
|
||||||
{
|
|
||||||
const audio_channels channels = g_cfg.audio.audio_channel_downmix.get();
|
const audio_channels channels = g_cfg.audio.audio_channel_downmix.get();
|
||||||
|
|
||||||
switch (channels)
|
switch (channels)
|
||||||
{
|
{
|
||||||
case audio_channels::use_application_settings:
|
case audio_channels::use_application_settings:
|
||||||
return 2; // TODO
|
m_channels = 2; // TODO
|
||||||
|
break;
|
||||||
case audio_channels::downmix_to_stereo:
|
case audio_channels::downmix_to_stereo:
|
||||||
return 2;
|
m_channels = 2;
|
||||||
|
break;
|
||||||
case audio_channels::downmix_to_5_1:
|
case audio_channels::downmix_to_5_1:
|
||||||
return 6;
|
m_channels = 6;
|
||||||
|
break;
|
||||||
case audio_channels::surround_7_1:
|
case audio_channels::surround_7_1:
|
||||||
return 8;
|
m_channels = 8;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fmt::throw_exception("Unknown audio channel mode %s (%d)", channels, static_cast<int>(channels));
|
fmt::throw_exception("Unknown audio channel mode %s (%d)", channels, static_cast<int>(channels));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper methods
|
||||||
|
*/
|
||||||
|
u32 AudioBackend::get_sampling_rate() const
|
||||||
|
{
|
||||||
|
return m_sampling_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 AudioBackend::get_sample_size() const
|
||||||
|
{
|
||||||
|
return m_sample_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 AudioBackend::get_channels() const
|
||||||
|
{
|
||||||
|
return m_channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioBackend::get_convert_to_u16() const
|
||||||
|
{
|
||||||
|
return m_convert_to_u16;
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioBackend::has_capability(u32 cap) const
|
bool AudioBackend::has_capability(u32 cap) const
|
||||||
{
|
{
|
||||||
return (cap & GetCapabilities()) == cap;
|
return (cap & GetCapabilities()) == cap;
|
||||||
|
@ -20,6 +20,8 @@ public:
|
|||||||
SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio
|
SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AudioBackend();
|
||||||
|
|
||||||
virtual ~AudioBackend() = default;
|
virtual ~AudioBackend() = default;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -94,13 +96,22 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Helper methods
|
* Helper methods
|
||||||
*/
|
*/
|
||||||
static u32 get_sampling_rate();
|
u32 get_sampling_rate() const;
|
||||||
|
|
||||||
static u32 get_sample_size();
|
u32 get_sample_size() const;
|
||||||
|
|
||||||
static u32 get_channels();
|
u32 get_channels() const;
|
||||||
|
|
||||||
|
bool get_convert_to_u16() const;
|
||||||
|
|
||||||
bool has_capability(u32 cap) const;
|
bool has_capability(u32 cap) const;
|
||||||
|
|
||||||
void dump_capabilities(std::string& out) const;
|
void dump_capabilities(std::string& out) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_convert_to_u16 = false;
|
||||||
|
u32 m_sample_size = sizeof(float);
|
||||||
|
u32 m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||||
|
u32 m_channels = 0;
|
||||||
|
u32 m_start_threshold = 1;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#ifndef HAVE_FAUDIO
|
#ifndef HAVE_FAUDIO
|
||||||
#error "FAudio support disabled but still being built."
|
#error "FAudio support disabled but still being built."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -10,6 +10,7 @@
|
|||||||
LOG_CHANNEL(FAudio_, "FAudio");
|
LOG_CHANNEL(FAudio_, "FAudio");
|
||||||
|
|
||||||
FAudioBackend::FAudioBackend()
|
FAudioBackend::FAudioBackend()
|
||||||
|
: AudioBackend()
|
||||||
{
|
{
|
||||||
u32 res;
|
u32 res;
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ FAudioBackend::FAudioBackend()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000, 0, 0, nullptr);
|
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, m_channels, 48000, 0, 0, nullptr);
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||||
@ -102,17 +103,13 @@ void FAudioBackend::Close()
|
|||||||
|
|
||||||
void FAudioBackend::Open(u32 /* num_buffers */)
|
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;
|
FAudioWaveFormatEx waveformatex;
|
||||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
waveformatex.wFormatTag = m_convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||||
waveformatex.nChannels = channels;
|
waveformatex.nChannels = m_channels;
|
||||||
waveformatex.nSamplesPerSec = sampling_rate;
|
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(sampling_rate * channels * sample_size);
|
waveformatex.nAvgBytesPerSec = static_cast<u32>(m_sampling_rate * m_channels * m_sample_size);
|
||||||
waveformatex.nBlockAlign = channels * sample_size;
|
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||||
waveformatex.wBitsPerSample = sample_size * 8;
|
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||||
waveformatex.cbSize = 0;
|
waveformatex.cbSize = 0;
|
||||||
|
|
||||||
u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
|
u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
|
||||||
@ -140,7 +137,7 @@ bool FAudioBackend::AddData(const void* src, u32 num_samples)
|
|||||||
}
|
}
|
||||||
|
|
||||||
FAudioBuffer buffer;
|
FAudioBuffer buffer;
|
||||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
buffer.AudioBytes = num_samples * m_sample_size;
|
||||||
buffer.Flags = 0;
|
buffer.Flags = 0;
|
||||||
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
|
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
|
||||||
buffer.LoopCount = 0;
|
buffer.LoopCount = 0;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#ifndef HAVE_PULSE
|
#ifndef HAVE_PULSE
|
||||||
#error "PulseAudio support disabled but still being built."
|
#error "PulseAudio support disabled but still being built."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -9,6 +9,7 @@
|
|||||||
#include <pulse/error.h>
|
#include <pulse/error.h>
|
||||||
|
|
||||||
PulseBackend::PulseBackend()
|
PulseBackend::PulseBackend()
|
||||||
|
: AudioBackend()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,7 +20,8 @@ PulseBackend::~PulseBackend()
|
|||||||
|
|
||||||
void PulseBackend::Close()
|
void PulseBackend::Close()
|
||||||
{
|
{
|
||||||
if(this->connection) {
|
if (this->connection)
|
||||||
|
{
|
||||||
pa_simple_free(this->connection);
|
pa_simple_free(this->connection);
|
||||||
this->connection = nullptr;
|
this->connection = nullptr;
|
||||||
}
|
}
|
||||||
@ -28,20 +30,30 @@ void PulseBackend::Close()
|
|||||||
void PulseBackend::Open(u32 /* num_buffers */)
|
void PulseBackend::Open(u32 /* num_buffers */)
|
||||||
{
|
{
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
ss.format = (get_sample_size() == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
ss.format = (m_sample_size == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
||||||
ss.rate = get_sampling_rate();
|
ss.rate = m_sampling_rate;
|
||||||
|
|
||||||
pa_channel_map channel_map;
|
pa_channel_map channel_map;
|
||||||
|
|
||||||
if (get_channels() == 2)
|
if (m_channels == 2)
|
||||||
{
|
{
|
||||||
channel_map.channels = 2;
|
channel_map.channels = 2;
|
||||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||||
}
|
}
|
||||||
|
else if (m_channels == 6)
|
||||||
|
{
|
||||||
|
channel_map.channels = 6;
|
||||||
|
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||||
|
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||||
|
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||||
|
channel_map.map[3] = PA_CHANNEL_POSITION_LFE;
|
||||||
|
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
|
||||||
|
channel_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
channel_map.channels = 8;
|
channel_map.channels = 8;
|
||||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||||
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||||
@ -55,7 +67,8 @@ void PulseBackend::Open(u32 /* num_buffers */)
|
|||||||
|
|
||||||
int err;
|
int err;
|
||||||
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, &channel_map, NULL, &err);
|
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, &channel_map, NULL, &err);
|
||||||
if(!this->connection) {
|
if (!this->connection)
|
||||||
|
{
|
||||||
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
|
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,10 +78,11 @@ bool PulseBackend::AddData(const void* src, u32 num_samples)
|
|||||||
AUDIT(this->connection);
|
AUDIT(this->connection);
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
if(pa_simple_write(this->connection, src, num_samples * get_sample_size(), &err) < 0) {
|
if (pa_simple_write(this->connection, src, num_samples * m_sample_size, &err) < 0)
|
||||||
|
{
|
||||||
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
|
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
LOG_CHANNEL(XAudio);
|
LOG_CHANNEL(XAudio);
|
||||||
|
|
||||||
XAudio2Backend::XAudio2Backend()
|
XAudio2Backend::XAudio2Backend()
|
||||||
|
: AudioBackend()
|
||||||
{
|
{
|
||||||
Microsoft::WRL::ComPtr<IXAudio2> instance;
|
Microsoft::WRL::ComPtr<IXAudio2> instance;
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ XAudio2Backend::XAudio2Backend()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = instance->CreateMasteringVoice(&m_master_voice, get_channels(), 48000);
|
hr = instance->CreateMasteringVoice(&m_master_voice, m_channels, 48000);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||||
@ -94,17 +95,13 @@ void XAudio2Backend::Open(u32 /* num_buffers */)
|
|||||||
{
|
{
|
||||||
HRESULT hr;
|
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 waveformatex;
|
||||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
waveformatex.wFormatTag = m_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||||
waveformatex.nChannels = channels;
|
waveformatex.nChannels = m_channels;
|
||||||
waveformatex.nSamplesPerSec = sampling_rate;
|
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
|
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(m_sampling_rate * m_channels * m_sample_size);
|
||||||
waveformatex.nBlockAlign = channels * sample_size;
|
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||||
waveformatex.wBitsPerSample = sample_size * 8;
|
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||||
waveformatex.cbSize = 0;
|
waveformatex.cbSize = 0;
|
||||||
|
|
||||||
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||||
@ -144,7 +141,7 @@ bool XAudio2Backend::AddData(const void* src, u32 num_samples)
|
|||||||
|
|
||||||
XAUDIO2_BUFFER buffer;
|
XAUDIO2_BUFFER buffer;
|
||||||
|
|
||||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
buffer.AudioBytes = num_samples * m_sample_size;
|
||||||
buffer.Flags = 0;
|
buffer.Flags = 0;
|
||||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||||
buffer.LoopCount = 0;
|
buffer.LoopCount = 0;
|
||||||
|
@ -44,6 +44,43 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
|
|||||||
|
|
||||||
cell_audio_config::cell_audio_config()
|
cell_audio_config::cell_audio_config()
|
||||||
{
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cell_audio_config::reset()
|
||||||
|
{
|
||||||
|
backend.reset();
|
||||||
|
backend = Emu.GetCallbacks().get_audio();
|
||||||
|
|
||||||
|
audio_channels = backend->get_channels();
|
||||||
|
audio_sampling_rate = backend->get_sampling_rate();
|
||||||
|
audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
|
||||||
|
|
||||||
|
audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
|
||||||
|
audio_buffer_size = audio_buffer_length * backend->get_sample_size();
|
||||||
|
|
||||||
|
desired_buffer_duration = g_cfg.audio.desired_buffer_duration * 1000llu;
|
||||||
|
|
||||||
|
const bool raw_buffering_enabled = static_cast<bool>(g_cfg.audio.enable_buffering);
|
||||||
|
|
||||||
|
buffering_enabled = raw_buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING);;
|
||||||
|
|
||||||
|
minimum_block_period = audio_block_period / 2;
|
||||||
|
maximum_block_period = (6 * audio_block_period) / 5;
|
||||||
|
|
||||||
|
desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 3 : 2;
|
||||||
|
num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS;
|
||||||
|
|
||||||
|
fully_untouched_timeout = static_cast<u64>(audio_block_period) * 2;
|
||||||
|
partially_untouched_timeout = static_cast<u64>(audio_block_period) * 4;
|
||||||
|
|
||||||
|
const s64 raw_time_stretching_threshold = g_cfg.audio.time_stretching_threshold;
|
||||||
|
const bool raw_time_stretching_enabled = buffering_enabled && g_cfg.audio.enable_time_stretching && (raw_time_stretching_threshold > 0);
|
||||||
|
|
||||||
|
time_stretching_enabled = raw_time_stretching_enabled && backend->has_capability(AudioBackend::SET_FREQUENCY_RATIO);
|
||||||
|
|
||||||
|
time_stretching_threshold = raw_time_stretching_threshold / 100.0f;
|
||||||
|
|
||||||
// Warn if audio backend does not support all requested features
|
// Warn if audio backend does not support all requested features
|
||||||
if (raw_buffering_enabled && !buffering_enabled)
|
if (raw_buffering_enabled && !buffering_enabled)
|
||||||
{
|
{
|
||||||
@ -500,6 +537,31 @@ void cell_audio_thread::advance(u64 timestamp, bool reset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
void configure_audio()
|
||||||
|
{
|
||||||
|
if (const auto g_audio = g_fxo->get<cell_audio>())
|
||||||
|
{
|
||||||
|
g_audio->m_update_configuration = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cell_audio_thread::update_config()
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
|
// Clear ringbuffer
|
||||||
|
ringbuffer.reset();
|
||||||
|
|
||||||
|
// Reload config
|
||||||
|
cfg.reset();
|
||||||
|
|
||||||
|
// Allocate ringbuffer
|
||||||
|
ringbuffer.reset(new audio_ringbuffer(cfg));
|
||||||
|
}
|
||||||
|
|
||||||
void cell_audio_thread::operator()()
|
void cell_audio_thread::operator()()
|
||||||
{
|
{
|
||||||
thread_ctrl::set_native_priority(1);
|
thread_ctrl::set_native_priority(1);
|
||||||
@ -519,6 +581,12 @@ void cell_audio_thread::operator()()
|
|||||||
// Main cellAudio loop
|
// Main cellAudio loop
|
||||||
while (thread_ctrl::state() != thread_state::aborting)
|
while (thread_ctrl::state() != thread_state::aborting)
|
||||||
{
|
{
|
||||||
|
if (m_update_configuration)
|
||||||
|
{
|
||||||
|
update_config();
|
||||||
|
m_update_configuration = false;
|
||||||
|
}
|
||||||
|
|
||||||
const u64 timestamp = ringbuffer->update();
|
const u64 timestamp = ringbuffer->update();
|
||||||
|
|
||||||
if (Emu.IsPaused())
|
if (Emu.IsPaused())
|
||||||
@ -959,7 +1027,7 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
|||||||
{
|
{
|
||||||
std::memset(out_buffer, 0, out_buffer_sz * sizeof(float));
|
std::memset(out_buffer, 0, out_buffer_sz * sizeof(float));
|
||||||
}
|
}
|
||||||
else if (g_cfg.audio.convert_to_u16)
|
else if (cfg.backend->get_convert_to_u16())
|
||||||
{
|
{
|
||||||
// convert the data from float to u16 with clipping:
|
// convert the data from float to u16 with clipping:
|
||||||
// 2x MULPS
|
// 2x MULPS
|
||||||
|
@ -187,49 +187,46 @@ struct audio_port
|
|||||||
|
|
||||||
struct cell_audio_config
|
struct cell_audio_config
|
||||||
{
|
{
|
||||||
const std::shared_ptr<AudioBackend> backend = Emu.GetCallbacks().get_audio();
|
std::shared_ptr<AudioBackend> backend = nullptr;
|
||||||
|
|
||||||
const u32 audio_channels = AudioBackend::get_channels();
|
u32 audio_channels = 0;
|
||||||
const u32 audio_sampling_rate = AudioBackend::get_sampling_rate();
|
u32 audio_sampling_rate = 0;
|
||||||
const u32 audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
|
u32 audio_block_period = 0;
|
||||||
|
|
||||||
const u32 audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
|
u32 audio_buffer_length = 0;
|
||||||
const u32 audio_buffer_size = audio_buffer_length * AudioBackend::get_sample_size();
|
u32 audio_buffer_size = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buffering
|
* Buffering
|
||||||
*/
|
*/
|
||||||
const u64 desired_buffer_duration = g_cfg.audio.desired_buffer_duration * 1000llu;
|
|
||||||
private:
|
u64 desired_buffer_duration = 0;
|
||||||
const bool raw_buffering_enabled = static_cast<bool>(g_cfg.audio.enable_buffering);
|
|
||||||
public:
|
|
||||||
// We need a non-blocking backend (implementing play/pause/flush) to be able to do buffering correctly
|
// 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
|
// 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);
|
bool buffering_enabled = false;
|
||||||
|
|
||||||
const u64 minimum_block_period = audio_block_period / 2; // the block period will not be dynamically lowered below this value (usecs)
|
u64 minimum_block_period = 0; // 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)
|
u64 maximum_block_period = 0; // 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) + 3 : 2;
|
u32 desired_full_buffers = 0;
|
||||||
const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers
|
u32 num_allocated_buffers = 0; // number of ringbuffer buffers
|
||||||
|
|
||||||
const f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average
|
const f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average
|
||||||
|
|
||||||
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
|
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
|
||||||
|
|
||||||
const u64 fully_untouched_timeout = 2 * audio_block_period; // timeout if the game has not touched any audio buffer yet
|
u64 fully_untouched_timeout = 0; // timeout if the game has not touched any audio buffer yet
|
||||||
const u64 partially_untouched_timeout = 4 * audio_block_period; // timeout if the game has not touched all audio buffers yet
|
u64 partially_untouched_timeout = 0; // timeout if the game has not touched all audio buffers yet
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Time Stretching
|
* 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)
|
// We need to be able to set a dynamic frequency ratio to be able to do time stretching
|
||||||
|
bool time_stretching_enabled = false;
|
||||||
|
|
||||||
|
f32 time_stretching_threshold = 0.0f; // we only apply time stretching below this buffer fill rate (adjusted for average period)
|
||||||
const f32 time_stretching_step = 0.1f; // will only reduce/increase the frequency ratio in steps of at least this value
|
const f32 time_stretching_step = 0.1f; // will only reduce/increase the frequency ratio in steps of at least this value
|
||||||
const f32 time_stretching_scale = 0.9f;
|
const f32 time_stretching_scale = 0.9f;
|
||||||
|
|
||||||
@ -237,6 +234,11 @@ public:
|
|||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
cell_audio_config();
|
cell_audio_config();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Config changes
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
class audio_ringbuffer
|
class audio_ringbuffer
|
||||||
@ -337,6 +339,7 @@ public:
|
|||||||
|
|
||||||
class cell_audio_thread
|
class cell_audio_thread
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
std::unique_ptr<audio_ringbuffer> ringbuffer;
|
std::unique_ptr<audio_ringbuffer> ringbuffer;
|
||||||
|
|
||||||
void reset_ports(s32 offset = 0);
|
void reset_ports(s32 offset = 0);
|
||||||
@ -351,8 +354,11 @@ class cell_audio_thread
|
|||||||
return (time_left > 350) ? time_left - 250 : 100;
|
return (time_left > 350) ? time_left - 250 : 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_config();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cell_audio_config cfg;
|
cell_audio_config cfg;
|
||||||
|
atomic_t<bool> m_update_configuration = false;
|
||||||
|
|
||||||
shared_mutex mutex;
|
shared_mutex mutex;
|
||||||
atomic_t<u32> init = 0;
|
atomic_t<u32> init = 0;
|
||||||
@ -375,7 +381,7 @@ public:
|
|||||||
u64 m_counter = 0;
|
u64 m_counter = 0;
|
||||||
u64 m_start_time = 0;
|
u64 m_start_time = 0;
|
||||||
u64 m_dynamic_period = 0;
|
u64 m_dynamic_period = 0;
|
||||||
f32 m_average_playtime;
|
f32 m_average_playtime = 0.0f;
|
||||||
|
|
||||||
void operator()();
|
void operator()();
|
||||||
|
|
||||||
@ -405,3 +411,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
using cell_audio = named_thread<cell_audio_thread>;
|
using cell_audio = named_thread<cell_audio_thread>;
|
||||||
|
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
void configure_audio();
|
||||||
|
}
|
||||||
|
@ -208,23 +208,23 @@ struct cfg_root : cfg::node
|
|||||||
|
|
||||||
cfg::_enum<audio_renderer> renderer{ this, "Renderer",
|
cfg::_enum<audio_renderer> renderer{ this, "Renderer",
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
audio_renderer::xaudio };
|
audio_renderer::xaudio, true };
|
||||||
#elif HAVE_FAUDIO
|
#elif HAVE_FAUDIO
|
||||||
audio_renderer::faudio };
|
audio_renderer::faudio, true };
|
||||||
#else
|
#else
|
||||||
audio_renderer::openal };
|
audio_renderer::openal, true };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cfg::_bool dump_to_file{ this, "Dump to file" };
|
cfg::_bool dump_to_file{ this, "Dump to file" };
|
||||||
cfg::_bool convert_to_u16{ this, "Convert to 16 bit" };
|
cfg::_bool convert_to_u16{ this, "Convert to 16 bit", false, true };
|
||||||
cfg::_enum<audio_channels> audio_channel_downmix{ this, "Audio Channels", audio_channels::downmix_to_stereo };
|
cfg::_enum<audio_channels> audio_channel_downmix{ this, "Audio Channels", audio_channels::downmix_to_stereo, true };
|
||||||
cfg::_int<1, 128> startt{ this, "Start Threshold", 1 }; // TODO: used only by ALSA, should probably be removed once ALSA is upgraded
|
cfg::_int<1, 128> start_threshold{ this, "Start Threshold", 1, true }; // TODO: used only by ALSA, should probably be removed once ALSA is upgraded
|
||||||
cfg::_int<0, 200> volume{ this, "Master Volume", 100, true };
|
cfg::_int<0, 200> volume{ this, "Master Volume", 100, true };
|
||||||
cfg::_bool enable_buffering{ this, "Enable Buffering", true };
|
cfg::_bool enable_buffering{ this, "Enable Buffering", true, true };
|
||||||
cfg::_int <4, 250> desired_buffer_duration{ this, "Desired Audio Buffer Duration", 100 };
|
cfg::_int <4, 250> desired_buffer_duration{ this, "Desired Audio Buffer Duration", 100, true };
|
||||||
cfg::_int<1, 1000> sampling_period_multiplier{ this, "Sampling Period Multiplier", 100 };
|
cfg::_int<1, 1000> sampling_period_multiplier{ this, "Sampling Period Multiplier", 100, true };
|
||||||
cfg::_bool enable_time_stretching{ this, "Enable Time Stretching", false };
|
cfg::_bool enable_time_stretching{ this, "Enable Time Stretching", false, true };
|
||||||
cfg::_int<0, 100> time_stretching_threshold{ this, "Time Stretching Threshold", 75 };
|
cfg::_int<0, 100> time_stretching_threshold{ this, "Time Stretching Threshold", 75, true };
|
||||||
cfg::_enum<microphone_handler> microphone_type{ this, "Microphone Type", microphone_handler::null };
|
cfg::_enum<microphone_handler> microphone_type{ this, "Microphone Type", microphone_handler::null };
|
||||||
cfg::string microphone_devices{ this, "Microphone Devices", ";;;;" };
|
cfg::string microphone_devices{ this, "Microphone Devices", ";;;;" };
|
||||||
} audio{ this };
|
} audio{ this };
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "_discord_utils.h"
|
#include "_discord_utils.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "Emu/Cell/Modules/cellAudio.h"
|
||||||
#include "Emu/RSX/Overlays/overlay_perf_metrics.h"
|
#include "Emu/RSX/Overlays/overlay_perf_metrics.h"
|
||||||
#include "trophy_notification_helper.h"
|
#include "trophy_notification_helper.h"
|
||||||
#include "save_data_dialog.h"
|
#include "save_data_dialog.h"
|
||||||
@ -474,6 +475,7 @@ void gui_application::OnEmuSettingsChange()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Emu.ConfigureLogs();
|
Emu.ConfigureLogs();
|
||||||
|
audio::configure_audio();
|
||||||
rsx::overlays::reset_performance_overlay();
|
rsx::overlays::reset_performance_overlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user