diff --git a/rpcs3/Emu/Audio/AudioBackend.cpp b/rpcs3/Emu/Audio/AudioBackend.cpp index 3b971488c1..fc65f0520e 100644 --- a/rpcs3/Emu/Audio/AudioBackend.cpp +++ b/rpcs3/Emu/Audio/AudioBackend.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "AudioBackend.h" #include "Emu/system_config.h" +#include "Emu/IdManager.h" +#include "Emu//Cell/Modules/cellAudioOut.h" AudioBackend::AudioBackend() {} @@ -97,3 +99,60 @@ void AudioBackend::normalize(u32 sample_cnt, const f32* src, f32* dst) dst[i] = std::clamp(src[i], -1.0f, 1.0f); } } + +AudioChannelCnt AudioBackend::get_channel_count(audio_downmix downmix) +{ + switch (downmix) + { + case audio_downmix::no_downmix: return AudioChannelCnt::SURROUND_7_1; + case audio_downmix::downmix_to_5_1: return AudioChannelCnt::SURROUND_5_1; + case audio_downmix::downmix_to_stereo: return AudioChannelCnt::STEREO; + case audio_downmix::use_application_settings: + { + audio_out_configuration& audio_out = g_fxo->get(); + std::lock_guard lock(audio_out.mtx); + ensure(!audio_out.out.empty()); + audio_out_configuration::audio_out& out = audio_out.out.at(CELL_AUDIO_OUT_PRIMARY); + + switch (out.downmixer) + { + case CELL_AUDIO_OUT_DOWNMIXER_NONE: + { + switch (out.channels) + { + case 2: return AudioChannelCnt::STEREO; + case 6: return AudioChannelCnt::SURROUND_5_1; + case 8: return AudioChannelCnt::SURROUND_7_1; + default: + fmt::throw_exception("Unsupported channel count in cellAudioOut config: %d", out.channels); + } + } + case CELL_AUDIO_OUT_DOWNMIXER_TYPE_A: + { + switch (out.channels) + { + case 2: + return AudioChannelCnt::STEREO; + default: + fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_A in cellAudioOut config: %d", out.channels); + } + } + case CELL_AUDIO_OUT_DOWNMIXER_TYPE_B: + { + switch (out.channels) + { + case 6: + case 8: + return AudioChannelCnt::SURROUND_5_1; + default: + fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_B in cellAudioOut config: %d", out.channels); + } + } + default: + fmt::throw_exception("Unknown downmixer in cellAudioOut config: %d", out.downmixer); + } + } + default: + fmt::throw_exception("Unknown audio channel mode %s (%d)", downmix, static_cast(downmix)); + } +} diff --git a/rpcs3/Emu/Audio/AudioBackend.h b/rpcs3/Emu/Audio/AudioBackend.h index 8fd7052f2c..001c02c52b 100644 --- a/rpcs3/Emu/Audio/AudioBackend.h +++ b/rpcs3/Emu/Audio/AudioBackend.h @@ -37,6 +37,8 @@ enum class AudioChannelCnt : u32 SURROUND_7_1 = 8, }; +enum class audio_downmix; + class AudioBackend { public: @@ -130,6 +132,16 @@ public: */ static void apply_volume_static(f32 vol, u32 sample_cnt, const f32* src, f32* dst); + /* + * Normalize float samples in range from -1.0 to 1.0. + */ + static void normalize(u32 sample_cnt, const f32* src, f32* dst); + + /* + * Returns the channel count based on the downmix mode. + */ + static AudioChannelCnt get_channel_count(audio_downmix downmix); + /* * Downmix audio stream. */ @@ -188,11 +200,6 @@ public: } } - /* - * Normalize float samples in range from -1.0 to 1.0. - */ - static void normalize(u32 sample_cnt, const f32* src, f32* dst); - protected: AudioSampleSize m_sample_size = AudioSampleSize::FLOAT; AudioFreq m_sampling_rate = AudioFreq::FREQ_48K; diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index ec8aeb62a7..3def75b2d8 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -66,19 +66,7 @@ void cell_audio_config::reset(bool backend_changed) const AudioFreq freq = AudioFreq::FREQ_48K; const AudioSampleSize sample_size = raw.convert_to_s16 ? AudioSampleSize::S16 : AudioSampleSize::FLOAT; - const AudioChannelCnt ch_cnt = [&]() - { - switch (raw.downmix) - { - case audio_downmix::no_downmix: return AudioChannelCnt::SURROUND_7_1; - case audio_downmix::downmix_to_5_1: return AudioChannelCnt::SURROUND_5_1; - case audio_downmix::downmix_to_stereo: return AudioChannelCnt::STEREO; - case audio_downmix::use_application_settings: return AudioChannelCnt::STEREO; // TODO - default: - fmt::throw_exception("Unknown audio channel mode %s (%d)", raw.downmix, static_cast(raw.downmix)); - } - }(); - + const AudioChannelCnt ch_cnt = AudioBackend::get_channel_count(raw.downmix); const f64 cb_frame_len = backend->Open(freq, sample_size, ch_cnt) ? backend->GetCallbackFrameLen() : 0.0; audio_channels = static_cast(ch_cnt); diff --git a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp index 5f37624583..c875d4ec0c 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp @@ -1,7 +1,10 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/IdManager.h" #include "cellAudioOut.h" +#include "cellAudio.h" +#include "Emu/Cell/lv2/sys_rsxaudio.h" LOG_CHANNEL(cellSysutil); @@ -132,8 +135,7 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptr= num + 0u) { @@ -144,7 +146,7 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptrchannel) - { - //Emu.GetAudioManager().GetInfo().mode.channel = config->channel; - } - - //Emu.GetAudioManager().GetInfo().mode.encoder = config->encoder; - - if (config->downMixer) - { - //Emu.GetAudioManager().GetInfo().mode.downMixer = config->downMixer; - } - - return CELL_OK; - } - + break; case CELL_AUDIO_OUT_SECONDARY: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_AUDIO_OUT; - default: break; + default: + return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER; } - return CELL_AUDIO_OUT_ERROR_ILLEGAL_PARAMETER; + audio_out_configuration::audio_out out_old; + audio_out_configuration::audio_out out_new; + + { + audio_out_configuration& cfg = g_fxo->get(); + std::lock_guard lock(cfg.mtx); + + audio_out_configuration::audio_out& out = cfg.out.at(audioOut); + out_old = out; + + out.channels = config->channel; + out.encoder = config->encoder; + out.downmixer = config->downMixer; + + out_new = out; + } + + if (g_cfg.audio.audio_channel_downmix == audio_downmix::use_application_settings && + std::memcmp(&out_old, &out_new, sizeof(audio_out_configuration::audio_out)) != 0) + { + audio::configure_audio(); + audio::configure_rsxaudio(); + } + + cellSysutil.notice("cellAudioOutConfigure: channels=%d, encoder=%d, downMixer=%d", config->channel, config->encoder, config->downMixer); + + return CELL_OK; } error_code cellAudioOutGetConfiguration(u32 audioOut, vm::ptr config, vm::ptr option) @@ -220,26 +233,27 @@ error_code cellAudioOutGetConfiguration(u32 audioOut, vm::ptrget(); + std::lock_guard lock(cfg.mtx); + + CellAudioOutConfiguration _config{}; + + audio_out_configuration::audio_out& out = cfg.out.at(audioOut); + _config.channel = out.channels; + _config.encoder = out.encoder; + _config.downMixer = out.downmixer; + + *config = _config; return CELL_OK; } @@ -281,18 +295,17 @@ error_code cellAudioOutGetDeviceInfo(u32 audioOut, u32 deviceIndex, vm::ptrget(); + std::lock_guard lock(cfg.mtx); + + cfg.out.at(audioOut).copy_control = control; + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellAudioOut.h b/rpcs3/Emu/Cell/Modules/cellAudioOut.h index 7c52ec1147..34b26b42fb 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudioOut.h +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.h @@ -13,7 +13,6 @@ enum CellAudioOutError : u32 CELL_AUDIO_OUT_ERROR_CONDITION_BUSY = 0x8002b247, }; - enum CellAudioOut { CELL_AUDIO_OUT_PRIMARY = 0, @@ -187,3 +186,21 @@ struct CellAudioOutDeviceConfiguration { //(Omitted) }; + + +// FXO Object + +struct audio_out_configuration +{ + std::mutex mtx; + + struct audio_out + { + u32 channels = CELL_AUDIO_OUT_CHNUM_8; + u32 encoder = CELL_AUDIO_OUT_CODING_TYPE_LPCM; + u32 downmixer = CELL_AUDIO_OUT_DOWNMIXER_NONE; + u32 copy_control = CELL_AUDIO_OUT_COPY_CONTROL_COPY_FREE; + }; + + std::array out; +}; diff --git a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp index 38dc8d4e49..6a1a9da6f4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp @@ -1322,20 +1322,7 @@ void rsxaudio_backend_thread::update_emu_cfg() rsxaudio_backend_thread::emu_audio_cfg rsxaudio_backend_thread::get_emu_cfg() { - const AudioChannelCnt out_ch_cnt = [&]() - { - switch (g_cfg.audio.audio_channel_downmix) - { - case audio_downmix::use_application_settings: - case audio_downmix::downmix_to_stereo: return AudioChannelCnt::STEREO; - case audio_downmix::downmix_to_5_1: return AudioChannelCnt::SURROUND_5_1; - case audio_downmix::no_downmix: return AudioChannelCnt::SURROUND_7_1; - default: - { - fmt::throw_exception("Unsupported downmix level: %u", static_cast(g_cfg.audio.audio_channel_downmix.get())); - } - } - }(); + const AudioChannelCnt out_ch_cnt = AudioBackend::get_channel_count(g_cfg.audio.audio_channel_downmix); emu_audio_cfg cfg = { diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 96de405b6e..69c41c94a6 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -957,8 +957,6 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceComboBox(ui->combo_audio_downmix, emu_settings_type::AudioChannels); SubscribeTooltip(ui->gb_audio_downmix, tooltips.settings.downmix); - // TODO: enable this setting once cellAudioOutConfigure can change downmix on the fly - ui->combo_audio_downmix->removeItem(static_cast(audio_downmix::use_application_settings)); m_emu_settings->EnhanceComboBox(ui->audioProviderBox, emu_settings_type::AudioProvider); SubscribeTooltip(ui->gb_audio_provider, tooltips.settings.audio_provider); diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index d0882d20cb..3b5b516cfb 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -51,7 +51,7 @@ public: const QString audio_avport = tr("Controls which avport is used to sample audio data from."); const QString audio_dump = tr("Saves all audio as a raw wave file. If unsure, leave this unchecked."); const QString convert = tr("Uses 16-bit audio samples instead of default 32-bit floating point.\nUse with buggy audio drivers if you have no sound or completely broken sound."); - const QString downmix = tr("Uses chosen audio output instead of default 7.1 surround sound.\nUse downmix to stereo with stereo audio devices. Use 5.1 or higher only if you are using a surround sound audio system."); + const QString downmix = tr("Uses chosen audio output instead of default 7.1 surround sound.\nUse downmix to stereo with stereo audio devices.\nUse 5.1 or higher only if you are using a surround sound audio system.\nIf you want to let the game decide choose the application settings."); const QString master_volume = tr("Controls the overall volume of the emulation.\nValues above 100% might reduce the audio quality."); const QString enable_buffering = tr("Enables audio buffering, which reduces crackle/stutter but increases audio latency."); const QString audio_buffer_duration = tr("Target buffer duration in milliseconds.\nHigher values make the buffering algorithm's job easier, but may introduce noticeable audio latency.");