From 20d6664dc1dae43575f5098c1441fb48158d892b Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sat, 20 Jun 2020 02:44:32 +0200 Subject: [PATCH] Try to make most audio configs dynamic --- rpcs3/Emu/Audio/AL/OpenALBackend.cpp | 7 +-- rpcs3/Emu/Audio/AL/OpenALBackend.h | 3 - rpcs3/Emu/Audio/ALSA/ALSABackend.cpp | 13 ++-- rpcs3/Emu/Audio/AudioBackend.cpp | 66 +++++++++++++------- rpcs3/Emu/Audio/AudioBackend.h | 17 +++++- rpcs3/Emu/Audio/FAudio/FAudioBackend.cpp | 23 ++++--- rpcs3/Emu/Audio/Pulse/PulseBackend.cpp | 34 +++++++---- rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp | 21 +++---- rpcs3/Emu/Cell/Modules/cellAudio.cpp | 70 +++++++++++++++++++++- rpcs3/Emu/Cell/Modules/cellAudio.h | 59 ++++++++++-------- rpcs3/Emu/system_config.h | 22 +++---- rpcs3/rpcs3qt/gui_application.cpp | 2 + 12 files changed, 228 insertions(+), 109 deletions(-) diff --git a/rpcs3/Emu/Audio/AL/OpenALBackend.cpp b/rpcs3/Emu/Audio/AL/OpenALBackend.cpp index c9da8aa9da..3e3cec3697 100644 --- a/rpcs3/Emu/Audio/AL/OpenALBackend.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALBackend.cpp @@ -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) OpenALBackend::OpenALBackend() - : m_sampling_rate(get_sampling_rate()) - , m_sample_size(get_sample_size()) + : AudioBackend() { ALCdevice* m_device = alcOpenDevice(nullptr); checkForAlcError("alcOpenDevice"); @@ -24,9 +23,7 @@ OpenALBackend::OpenALBackend() alcMakeContextCurrent(m_context); checkForAlcError("alcMakeContextCurrent"); - const auto channels = get_channels(); - - switch (channels) + switch (m_channels) { case 2: m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32; diff --git a/rpcs3/Emu/Audio/AL/OpenALBackend.h b/rpcs3/Emu/Audio/AL/OpenALBackend.h index 28ef25997e..8a01d3b579 100644 --- a/rpcs3/Emu/Audio/AL/OpenALBackend.h +++ b/rpcs3/Emu/Audio/AL/OpenALBackend.h @@ -15,9 +15,6 @@ private: u32 m_next_buffer = 0; u32 m_num_unqueued = 0; - const u32 m_sampling_rate; - const u32 m_sample_size; - void unqueue_processed(); public: diff --git a/rpcs3/Emu/Audio/ALSA/ALSABackend.cpp b/rpcs3/Emu/Audio/ALSA/ALSABackend.cpp index a54be5e3f1..fc603eee52 100644 --- a/rpcs3/Emu/Audio/ALSA/ALSABackend.cpp +++ b/rpcs3/Emu/Audio/ALSA/ALSABackend.cpp @@ -1,4 +1,4 @@ -#ifndef HAVE_ALSA +#ifndef HAVE_ALSA #error "ALSA support disabled but still being built." #endif @@ -26,6 +26,7 @@ static bool check(int err, const char* reason) } 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")) 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; - 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")) 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; //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")) 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")) return; @@ -132,7 +133,7 @@ void ALSABackend::Close() 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); diff --git a/rpcs3/Emu/Audio/AudioBackend.cpp b/rpcs3/Emu/Audio/AudioBackend.cpp index f1e7ffc3a2..7165a6eeef 100644 --- a/rpcs3/Emu/Audio/AudioBackend.cpp +++ b/rpcs3/Emu/Audio/AudioBackend.cpp @@ -2,45 +2,69 @@ #include "AudioBackend.h" #include "Emu/system_config.h" -/* - * Helper methods - */ -u32 AudioBackend::get_sampling_rate() +AudioBackend::AudioBackend() { + m_convert_to_u16 = static_cast(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; 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(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(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(); switch (channels) { case audio_channels::use_application_settings: - return 2; // TODO + m_channels = 2; // TODO + break; case audio_channels::downmix_to_stereo: - return 2; + m_channels = 2; + break; case audio_channels::downmix_to_5_1: - return 6; + m_channels = 6; + break; case audio_channels::surround_7_1: - return 8; + m_channels = 8; + break; default: fmt::throw_exception("Unknown audio channel mode %s (%d)", channels, static_cast(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 { return (cap & GetCapabilities()) == cap; diff --git a/rpcs3/Emu/Audio/AudioBackend.h b/rpcs3/Emu/Audio/AudioBackend.h index 10454d342d..8ed98aa63e 100644 --- a/rpcs3/Emu/Audio/AudioBackend.h +++ b/rpcs3/Emu/Audio/AudioBackend.h @@ -20,6 +20,8 @@ public: SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio }; + AudioBackend(); + virtual ~AudioBackend() = default; /* @@ -94,13 +96,22 @@ public: /* * 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; 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; }; diff --git a/rpcs3/Emu/Audio/FAudio/FAudioBackend.cpp b/rpcs3/Emu/Audio/FAudio/FAudioBackend.cpp index 474eb9377e..2763b27ead 100644 --- a/rpcs3/Emu/Audio/FAudio/FAudioBackend.cpp +++ b/rpcs3/Emu/Audio/FAudio/FAudioBackend.cpp @@ -1,4 +1,4 @@ -#ifndef HAVE_FAUDIO +#ifndef HAVE_FAUDIO #error "FAudio support disabled but still being built." #endif @@ -10,6 +10,7 @@ LOG_CHANNEL(FAudio_, "FAudio"); FAudioBackend::FAudioBackend() + : AudioBackend() { u32 res; @@ -20,7 +21,7 @@ FAudioBackend::FAudioBackend() 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) { FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res); @@ -102,17 +103,13 @@ void FAudioBackend::Close() 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(sampling_rate * channels * sample_size); - waveformatex.nBlockAlign = channels * sample_size; - waveformatex.wBitsPerSample = sample_size * 8; + waveformatex.wFormatTag = m_convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT; + waveformatex.nChannels = m_channels; + waveformatex.nSamplesPerSec = m_sampling_rate; + waveformatex.nAvgBytesPerSec = static_cast(m_sampling_rate * m_channels * m_sample_size); + waveformatex.nBlockAlign = m_channels * m_sample_size; + waveformatex.wBitsPerSample = m_sample_size * 8; waveformatex.cbSize = 0; 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; - buffer.AudioBytes = num_samples * AudioBackend::get_sample_size(); + buffer.AudioBytes = num_samples * m_sample_size; buffer.Flags = 0; buffer.LoopBegin = FAUDIO_NO_LOOP_REGION; buffer.LoopCount = 0; diff --git a/rpcs3/Emu/Audio/Pulse/PulseBackend.cpp b/rpcs3/Emu/Audio/Pulse/PulseBackend.cpp index bf4b915f7f..7ff6232c89 100644 --- a/rpcs3/Emu/Audio/Pulse/PulseBackend.cpp +++ b/rpcs3/Emu/Audio/Pulse/PulseBackend.cpp @@ -1,4 +1,4 @@ -#ifndef HAVE_PULSE +#ifndef HAVE_PULSE #error "PulseAudio support disabled but still being built." #endif @@ -9,6 +9,7 @@ #include PulseBackend::PulseBackend() + : AudioBackend() { } @@ -19,7 +20,8 @@ PulseBackend::~PulseBackend() void PulseBackend::Close() { - if(this->connection) { + if (this->connection) + { pa_simple_free(this->connection); this->connection = nullptr; } @@ -28,20 +30,30 @@ void PulseBackend::Close() void PulseBackend::Open(u32 /* num_buffers */) { pa_sample_spec ss; - ss.format = (get_sample_size() == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE; - ss.rate = get_sampling_rate(); + ss.format = (m_sample_size == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE; + ss.rate = m_sampling_rate; 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[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 { - channel_map.channels = 8; + channel_map.channels = 8; 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; @@ -55,7 +67,8 @@ void PulseBackend::Open(u32 /* num_buffers */) int 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)); } } @@ -65,10 +78,11 @@ bool PulseBackend::AddData(const void* src, u32 num_samples) AUDIT(this->connection); 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)); return false; } - + return true; } diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp index f0d46d9e4e..e12fa30261 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp @@ -16,6 +16,7 @@ LOG_CHANNEL(XAudio); XAudio2Backend::XAudio2Backend() + : AudioBackend() { Microsoft::WRL::ComPtr instance; @@ -30,7 +31,7 @@ XAudio2Backend::XAudio2Backend() return; } - hr = instance->CreateMasteringVoice(&m_master_voice, get_channels(), 48000); + hr = instance->CreateMasteringVoice(&m_master_voice, m_channels, 48000); if (FAILED(hr)) { XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr)); @@ -94,17 +95,13 @@ void XAudio2Backend::Open(u32 /* num_buffers */) { HRESULT hr; - const u32 sample_size = AudioBackend::get_sample_size(); - const u32 channels = AudioBackend::get_channels(); - const u32 sampling_rate = AudioBackend::get_sampling_rate(); - WAVEFORMATEX waveformatex; - waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; - waveformatex.nChannels = channels; - waveformatex.nSamplesPerSec = sampling_rate; - waveformatex.nAvgBytesPerSec = static_cast(sampling_rate * channels * sample_size); - waveformatex.nBlockAlign = channels * sample_size; - waveformatex.wBitsPerSample = sample_size * 8; + waveformatex.wFormatTag = m_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; + waveformatex.nChannels = m_channels; + waveformatex.nSamplesPerSec = m_sampling_rate; + waveformatex.nAvgBytesPerSec = static_cast(m_sampling_rate * m_channels * m_sample_size); + waveformatex.nBlockAlign = m_channels * m_sample_size; + waveformatex.wBitsPerSample = m_sample_size * 8; waveformatex.cbSize = 0; 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; - buffer.AudioBytes = num_samples * AudioBackend::get_sample_size(); + buffer.AudioBytes = num_samples * m_sample_size; buffer.Flags = 0; buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION; buffer.LoopCount = 0; diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index db3f7a7b75..e4ee2016e9 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -44,6 +44,43 @@ void fmt_class_string::format(std::string& out, u64 arg) 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(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(desired_buffer_duration / audio_block_period) + 3 : 2; + num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; + + fully_untouched_timeout = static_cast(audio_block_period) * 2; + partially_untouched_timeout = static_cast(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 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()) + { + 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()() { thread_ctrl::set_native_priority(1); @@ -519,6 +581,12 @@ void cell_audio_thread::operator()() // Main cellAudio loop while (thread_ctrl::state() != thread_state::aborting) { + if (m_update_configuration) + { + update_config(); + m_update_configuration = false; + } + const u64 timestamp = ringbuffer->update(); 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)); } - 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: // 2x MULPS diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.h b/rpcs3/Emu/Cell/Modules/cellAudio.h index f1b113f2e2..9323c4d6dd 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.h +++ b/rpcs3/Emu/Cell/Modules/cellAudio.h @@ -187,49 +187,46 @@ struct audio_port struct cell_audio_config { - const std::shared_ptr backend = Emu.GetCallbacks().get_audio(); + std::shared_ptr backend = nullptr; - const u32 audio_channels = AudioBackend::get_channels(); - const u32 audio_sampling_rate = AudioBackend::get_sampling_rate(); - const u32 audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate; + u32 audio_channels = 0; + u32 audio_sampling_rate = 0; + u32 audio_block_period = 0; - const u32 audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels; - const u32 audio_buffer_size = audio_buffer_length * AudioBackend::get_sample_size(); + u32 audio_buffer_length = 0; + u32 audio_buffer_size = 0; /* * Buffering */ - const u64 desired_buffer_duration = g_cfg.audio.desired_buffer_duration * 1000llu; -private: - const bool raw_buffering_enabled = static_cast(g_cfg.audio.enable_buffering); -public: + + u64 desired_buffer_duration = 0; + // We need a non-blocking backend (implementing play/pause/flush) to be able to do buffering correctly // We also need to be able to query the current playing state - const bool buffering_enabled = raw_buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING); + 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) - const u64 maximum_block_period = (6 * audio_block_period) / 5; // the block period will not be dynamically increased above this value (usecs) + u64 minimum_block_period = 0; // the block period will not be dynamically lowered below 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(desired_buffer_duration / audio_block_period) + 3 : 2; - const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers + u32 desired_full_buffers = 0; + 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 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 - const u64 partially_untouched_timeout = 4 * audio_block_period; // timeout if the game has not touched all audio buffers yet + u64 fully_untouched_timeout = 0; // timeout if the game has not touched any audio buffer yet + u64 partially_untouched_timeout = 0; // timeout if the game has not touched all audio buffers yet /* * 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_scale = 0.9f; @@ -237,6 +234,11 @@ public: * Constructor */ cell_audio_config(); + + /* + * Config changes + */ + void reset(); }; class audio_ringbuffer @@ -337,6 +339,7 @@ public: class cell_audio_thread { +private: std::unique_ptr ringbuffer; void reset_ports(s32 offset = 0); @@ -351,8 +354,11 @@ class cell_audio_thread return (time_left > 350) ? time_left - 250 : 100; } + void update_config(); + public: cell_audio_config cfg; + atomic_t m_update_configuration = false; shared_mutex mutex; atomic_t init = 0; @@ -375,7 +381,7 @@ public: u64 m_counter = 0; u64 m_start_time = 0; u64 m_dynamic_period = 0; - f32 m_average_playtime; + f32 m_average_playtime = 0.0f; void operator()(); @@ -405,3 +411,8 @@ public: }; using cell_audio = named_thread; + +namespace audio +{ + void configure_audio(); +} diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 77227701ba..8fe08f762e 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -208,23 +208,23 @@ struct cfg_root : cfg::node cfg::_enum renderer{ this, "Renderer", #ifdef _WIN32 - audio_renderer::xaudio }; + audio_renderer::xaudio, true }; #elif HAVE_FAUDIO - audio_renderer::faudio }; + audio_renderer::faudio, true }; #else - audio_renderer::openal }; + audio_renderer::openal, true }; #endif cfg::_bool dump_to_file{ this, "Dump to file" }; - cfg::_bool convert_to_u16{ this, "Convert to 16 bit" }; - cfg::_enum audio_channel_downmix{ this, "Audio Channels", audio_channels::downmix_to_stereo }; - cfg::_int<1, 128> startt{ this, "Start Threshold", 1 }; // TODO: used only by ALSA, should probably be removed once ALSA is upgraded + cfg::_bool convert_to_u16{ this, "Convert to 16 bit", false, true }; + cfg::_enum audio_channel_downmix{ this, "Audio Channels", audio_channels::downmix_to_stereo, true }; + 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::_bool enable_buffering{ this, "Enable Buffering", true }; - cfg::_int <4, 250> desired_buffer_duration{ this, "Desired Audio Buffer Duration", 100 }; - cfg::_int<1, 1000> sampling_period_multiplier{ this, "Sampling Period Multiplier", 100 }; - cfg::_bool enable_time_stretching{ this, "Enable Time Stretching", false }; - cfg::_int<0, 100> time_stretching_threshold{ this, "Time Stretching Threshold", 75 }; + cfg::_bool enable_buffering{ this, "Enable Buffering", true, true }; + 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, true }; + cfg::_bool enable_time_stretching{ this, "Enable Time Stretching", false, true }; + cfg::_int<0, 100> time_stretching_threshold{ this, "Time Stretching Threshold", 75, true }; cfg::_enum microphone_type{ this, "Microphone Type", microphone_handler::null }; cfg::string microphone_devices{ this, "Microphone Devices", ";;;;" }; } audio{ this }; diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index df8bef4703..1cebf476d7 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -14,6 +14,7 @@ #include "_discord_utils.h" #endif +#include "Emu/Cell/Modules/cellAudio.h" #include "Emu/RSX/Overlays/overlay_perf_metrics.h" #include "trophy_notification_helper.h" #include "save_data_dialog.h" @@ -474,6 +475,7 @@ void gui_application::OnEmuSettingsChange() } Emu.ConfigureLogs(); + audio::configure_audio(); rsx::overlays::reset_performance_overlay(); }