diff --git a/rpcs3/Emu/Audio/AudioBackend.cpp b/rpcs3/Emu/Audio/AudioBackend.cpp index fc65f0520e..84627eaaac 100644 --- a/rpcs3/Emu/Audio/AudioBackend.cpp +++ b/rpcs3/Emu/Audio/AudioBackend.cpp @@ -100,59 +100,48 @@ void AudioBackend::normalize(u32 sample_cnt, const f32* src, f32* dst) } } -AudioChannelCnt AudioBackend::get_channel_count(audio_downmix downmix) +AudioChannelCnt AudioBackend::get_channel_count() { - 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); + 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) + switch (out.downmixer) + { + case CELL_AUDIO_OUT_DOWNMIXER_NONE: + { + switch (out.channels) { - 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); - } - } + case 2: return AudioChannelCnt::STEREO; + case 6: return AudioChannelCnt::SURROUND_5_1; + case 8: return AudioChannelCnt::SURROUND_7_1; default: - fmt::throw_exception("Unknown downmixer in cellAudioOut config: %d", out.downmixer); + 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 audio channel mode %s (%d)", downmix, static_cast(downmix)); + fmt::throw_exception("Unknown downmixer in cellAudioOut config: %d", out.downmixer); } } diff --git a/rpcs3/Emu/Audio/AudioBackend.h b/rpcs3/Emu/Audio/AudioBackend.h index 001c02c52b..6e09f36b52 100644 --- a/rpcs3/Emu/Audio/AudioBackend.h +++ b/rpcs3/Emu/Audio/AudioBackend.h @@ -37,8 +37,6 @@ enum class AudioChannelCnt : u32 SURROUND_7_1 = 8, }; -enum class audio_downmix; - class AudioBackend { public: @@ -140,7 +138,7 @@ public: /* * Returns the channel count based on the downmix mode. */ - static AudioChannelCnt get_channel_count(audio_downmix downmix); + static AudioChannelCnt get_channel_count(); /* * Downmix audio stream. diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index 3def75b2d8..c63cbb8d3d 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -66,7 +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 = AudioBackend::get_channel_count(raw.downmix); + const AudioChannelCnt ch_cnt = AudioBackend::get_channel_count(); const f64 cb_frame_len = backend->Open(freq, sample_size, ch_cnt) ? backend->GetCallbackFrameLen() : 0.0; audio_channels = static_cast(ch_cnt); @@ -526,7 +526,7 @@ namespace audio .time_stretching_threshold = g_cfg.audio.time_stretching_threshold, .convert_to_s16 = static_cast(g_cfg.audio.convert_to_s16), .dump_to_file = static_cast(g_cfg.audio.dump_to_file), - .downmix = g_cfg.audio.audio_channel_downmix, + .format = g_cfg.audio.format, .renderer = g_cfg.audio.renderer, .provider = g_cfg.audio.provider }; @@ -550,7 +550,7 @@ namespace audio raw.time_stretching_threshold != new_raw.time_stretching_threshold || raw.enable_time_stretching != new_raw.enable_time_stretching || raw.convert_to_s16 != new_raw.convert_to_s16 || - raw.downmix != new_raw.downmix || + raw.format != new_raw.format || raw.renderer != new_raw.renderer || raw.dump_to_file != new_raw.dump_to_file) { @@ -848,13 +848,13 @@ void cell_audio_thread::operator()() switch (cfg.audio_channels) { case 2: - mix(buf); + mix(buf); break; case 6: - mix(buf); + mix(buf); break; case 8: - mix(buf); + mix(buf); break; default: fmt::throw_exception("Unsupported number of audio channels: %u", cfg.audio_channels); @@ -884,12 +884,12 @@ audio_port* cell_audio_thread::open_port() return nullptr; } -template +template void cell_audio_thread::mix(float *out_buffer, s32 offset) { AUDIT(out_buffer != nullptr); - constexpr u32 channels = downmix == audio_downmix::no_downmix ? 8 : downmix == audio_downmix::downmix_to_5_1 ? 6 : 2; + constexpr u32 channels = static_cast(downmix); constexpr u32 out_buffer_sz = channels * AUDIO_BUFFER_SAMPLES; bool first_mix = true; @@ -941,14 +941,14 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset) out_buffer[out + 0] = left; out_buffer[out + 1] = right; - if constexpr (downmix != audio_downmix::downmix_to_stereo) + if constexpr (downmix != AudioChannelCnt::STEREO) { out_buffer[out + 2] = 0.0f; out_buffer[out + 3] = 0.0f; out_buffer[out + 4] = 0.0f; out_buffer[out + 5] = 0.0f; - if constexpr (downmix != audio_downmix::downmix_to_5_1) + if constexpr (downmix != AudioChannelCnt::SURROUND_5_1) { out_buffer[out + 6] = 0.0f; out_buffer[out + 7] = 0.0f; @@ -989,14 +989,14 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset) const float rear_left = buf[in + 6] * m; const float rear_right = buf[in + 7] * m; - if constexpr (downmix == audio_downmix::downmix_to_stereo) + if constexpr (downmix == AudioChannelCnt::STEREO) { // Don't mix in the lfe as per dolby specification and based on documentation const float mid = center * 0.5f; out_buffer[out + 0] = left * minus_3db + mid + side_left * 0.5f + rear_left * 0.5f; out_buffer[out + 1] = right * minus_3db + mid + side_right * 0.5f + rear_right * 0.5f; } - else if constexpr (downmix == audio_downmix::downmix_to_5_1) + else if constexpr (downmix == AudioChannelCnt::SURROUND_5_1) { out_buffer[out + 0] = left; out_buffer[out + 1] = right; @@ -1034,14 +1034,14 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset) const float rear_left = buf[in + 6] * m; const float rear_right = buf[in + 7] * m; - if constexpr (downmix == audio_downmix::downmix_to_stereo) + if constexpr (downmix == AudioChannelCnt::STEREO) { // Don't mix in the lfe as per dolby specification and based on documentation const float mid = center * 0.5f; out_buffer[out + 0] += left * minus_3db + mid + side_left * 0.5f + rear_left * 0.5f; out_buffer[out + 1] += right * minus_3db + mid + side_right * 0.5f + rear_right * 0.5f; } - else if constexpr (downmix == audio_downmix::downmix_to_5_1) + else if constexpr (downmix == AudioChannelCnt::SURROUND_5_1) { out_buffer[out + 0] += left; out_buffer[out + 1] += right; diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.h b/rpcs3/Emu/Cell/Modules/cellAudio.h index 4cd0c94aff..8dad8d9371 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.h +++ b/rpcs3/Emu/Cell/Modules/cellAudio.h @@ -201,7 +201,7 @@ struct cell_audio_config s64 time_stretching_threshold = 0; bool convert_to_s16 = false; bool dump_to_file = false; - audio_downmix downmix = audio_downmix::downmix_to_stereo; + audio_format format = audio_format::lpcm_2_48khz; audio_renderer renderer = audio_renderer::null; audio_provider provider = audio_provider::none; }; @@ -348,7 +348,7 @@ private: void reset_ports(s32 offset = 0); void advance(u64 timestamp); std::tuple count_port_buffer_tags(); - template + template void mix(float *out_buffer, s32 offset = 0); void finish_port_volume_stepping(); diff --git a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp index f095c4b84a..53c8700c2d 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp @@ -3,6 +3,7 @@ #include "Emu/Cell/lv2/sys_rsxaudio.h" #include "Emu/IdManager.h" #include "Emu/System.h" +#include "Loader/PSF.h" #include "cellAudioOut.h" #include "cellAudio.h" @@ -34,45 +35,137 @@ audio_out_configuration::audio_out_configuration() { CellAudioOutSoundMode mode{}; - mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; - mode.channel = CELL_AUDIO_OUT_CHNUM_8; - mode.fs = CELL_AUDIO_OUT_FS_48KHZ; - mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy; + // TODO: audio_format should be a bitmap, but we'll keep it simple for now (Linear PCM 2 Ch. 48 kHz should always exist) + // TODO: more formats: + // - Each LPCM with other sample frequencies (we currently only support 48 kHz) + // - AAC + // - Dolby Digital Plus + // - Dolby TrueHD + // - DTS-HD High Resolution Audio + // - DTS-HD Master Audio + // - ... + switch (g_cfg.audio.format) + { + case audio_format::automatic: // Automatic based on supported formats + { + s32 sound_format = (1 << 0); - out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); - out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + const psf::registry psf = psf::load_object(fs::file(Emu.GetSfoDir() + "/PARAM.SFO")); + if (psf.contains("SOUND_FORMAT")) sound_format = psf.at("SOUND_FORMAT").as_integer(); - mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; - mode.channel = CELL_AUDIO_OUT_CHNUM_6; - mode.fs = CELL_AUDIO_OUT_FS_48KHZ; - mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; + if (sound_format & (1 << 0)) // Linear PCM 2 Ch. + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; + mode.channel = CELL_AUDIO_OUT_CHNUM_2; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH; - out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); - out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + } - mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; - mode.channel = CELL_AUDIO_OUT_CHNUM_2; - mode.fs = CELL_AUDIO_OUT_FS_48KHZ; - mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH; + if (sound_format & (1 << 2)) // Linear PCM 5.1 Ch. + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; + mode.channel = CELL_AUDIO_OUT_CHNUM_6; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; - out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); - out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + } - mode.type = CELL_AUDIO_OUT_CODING_TYPE_DTS; - mode.channel = CELL_AUDIO_OUT_CHNUM_6; - mode.fs = CELL_AUDIO_OUT_FS_48KHZ; - mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; + if (sound_format & (1 << 4)) // Linear PCM 7.1 Ch. + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; + mode.channel = CELL_AUDIO_OUT_CHNUM_8; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy; - out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); - out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + } - mode.type = CELL_AUDIO_OUT_CODING_TYPE_AC3; - mode.channel = CELL_AUDIO_OUT_CHNUM_6; - mode.fs = CELL_AUDIO_OUT_FS_48KHZ; - mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; + if (sound_format & (1 << 8)) // DTS 5.1 Ch. + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_DTS; + mode.channel = CELL_AUDIO_OUT_CHNUM_6; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; - out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); - out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + } + + if (sound_format & (1 << 9)) // Dolby Digital 5.1 Ch. + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_AC3; + mode.channel = CELL_AUDIO_OUT_CHNUM_6; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; + + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + } + + break; + } + case audio_format::lpcm_2_48khz: // Linear PCM 2 Ch. 48 kHz + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; + mode.channel = CELL_AUDIO_OUT_CHNUM_2; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH; + + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + break; + } + case audio_format::lpcm_5_1_48khz: // Linear PCM 5.1 Ch. 48 kHz + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; + mode.channel = CELL_AUDIO_OUT_CHNUM_6; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; + + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + break; + } + case audio_format::lpcm_7_1_48khz: // Linear PCM 7.1 Ch. 48 kHz + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; + mode.channel = CELL_AUDIO_OUT_CHNUM_8; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy; + + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + break; + } + case audio_format::dts: // DTS 5.1 Ch. + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_DTS; + mode.channel = CELL_AUDIO_OUT_CHNUM_6; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; + + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + break; + } + case audio_format::ac3: // Dolby Digital 5.1 Ch. + { + mode.type = CELL_AUDIO_OUT_CODING_TYPE_AC3; + mode.channel = CELL_AUDIO_OUT_CHNUM_6; + mode.fs = CELL_AUDIO_OUT_FS_48KHZ; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; + + out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); + out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); + break; + } + } } error_code cellAudioOutGetNumberOfDevice(u32 audioOut); @@ -87,22 +180,6 @@ error_code cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 default: return not_an_error(0); } - switch (type) - { - case CELL_AUDIO_OUT_CODING_TYPE_LPCM: - { - switch (g_cfg.audio.audio_channel_downmix) - { - case audio_downmix::no_downmix: return not_an_error(8); - case audio_downmix::downmix_to_5_1: return not_an_error(6); - case audio_downmix::downmix_to_stereo: return not_an_error(2); - case audio_downmix::use_application_settings: break; - } - break; - } - default: break; - } - s32 available = 0; // Check if the requested audio parameters are available and find the max supported channel count @@ -131,22 +208,6 @@ error_code cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 default: return not_an_error(0); } - switch (type) - { - case CELL_AUDIO_OUT_CODING_TYPE_LPCM: - { - switch (g_cfg.audio.audio_channel_downmix) - { - case audio_downmix::no_downmix: return not_an_error(8); - case audio_downmix::downmix_to_5_1: return not_an_error(6); - case audio_downmix::downmix_to_stereo: return not_an_error(2); - case audio_downmix::use_application_settings: break; - } - break; - } - default: break; - } - // Check if the requested audio parameters are available audio_out_configuration& cfg = g_fxo->get(); std::lock_guard lock(cfg.mtx); @@ -203,7 +264,7 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptrget(); std::lock_guard lock(cfg.mtx); @@ -211,21 +272,7 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptr(channels); - case CELL_AUDIO_OUT_CODING_TYPE_AC3: - case CELL_AUDIO_OUT_CODING_TYPE_DTS: - return true; // We currently only have one possible sound mode for these types - default: - return false; - } - } - - return false; + return mode.type == out.encoder && mode.channel == static_cast(channels); }); ensure(it != out.sound_modes.cend()); @@ -289,8 +336,7 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr void { diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 78ba1f29f6..3881c8498f 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -254,7 +254,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr dirName else { // TODO: Is cellHddGameCheck really responsible for writing the information in get->getParam ? (If not, delete this else) - const auto& psf = psf::load_object(fs::file(local_dir +"/PARAM.SFO")); + const psf::registry psf = psf::load_object(fs::file(local_dir +"/PARAM.SFO")); // Some following fields may be zero in old FW 1.00 version PARAM.SFO if (psf.contains("PARENTAL_LEVEL")) get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer(); diff --git a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp index 6a1a9da6f4..b2a872aa73 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsxaudio.cpp @@ -1322,7 +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 = AudioBackend::get_channel_count(g_cfg.audio.audio_channel_downmix); + const AudioChannelCnt out_ch_cnt = AudioBackend::get_channel_count(); emu_audio_cfg cfg = { diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 29bf6e6c33..396e4ac9f7 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -235,7 +235,7 @@ struct cfg_root : cfg::node cfg::_enum rsxaudio_port{ this, "RSXAudio Avport", audio_avport::hdmi_0, true }; cfg::_bool dump_to_file{ this, "Dump to file", false, true }; cfg::_bool convert_to_s16{ this, "Convert to 16 bit", false, true }; - cfg::_enum audio_channel_downmix{ this, "Audio Channels", audio_downmix::downmix_to_stereo, true }; + cfg::_enum format{ this, "Audio Format", audio_format::automatic, false }; cfg::_int<0, 200> volume{ this, "Master Volume", 100, true }; cfg::_bool enable_buffering{ this, "Enable Buffering", true, true }; cfg::_int <4, 250> desired_buffer_duration{ this, "Desired Audio Buffer Duration", 100, true }; diff --git a/rpcs3/Emu/system_config_types.cpp b/rpcs3/Emu/system_config_types.cpp index 5c968c7d06..9f93ad820f 100644 --- a/rpcs3/Emu/system_config_types.cpp +++ b/rpcs3/Emu/system_config_types.cpp @@ -532,16 +532,18 @@ void fmt_class_string::format(std::string& out, u64 arg) } template <> -void fmt_class_string::format(std::string& out, u64 arg) +void fmt_class_string::format(std::string& out, u64 arg) { - format_enum(out, arg, [](audio_downmix value) + format_enum(out, arg, [](audio_format value) { switch (value) { - case audio_downmix::no_downmix: return "No downmix"; - case audio_downmix::downmix_to_stereo: return "Downmix to Stereo"; - case audio_downmix::downmix_to_5_1: return "Downmix to 5.1"; - case audio_downmix::use_application_settings: return "Use application settings"; + case audio_format::automatic: return "Automatic"; + case audio_format::lpcm_2_48khz: return "Linear PCM 2 Ch. 48 kHz"; + case audio_format::lpcm_5_1_48khz: return "Linear PCM 5.1 Ch. 48 kHz"; + case audio_format::lpcm_7_1_48khz: return "Linear PCM 7.1 Ch. 48 kHz"; + case audio_format::dts: return "DTS 5.1 Ch."; + case audio_format::ac3: return "Dolby Digital 5.1 Ch."; } return unknown; diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index dff7b5e41b..30eddabe7a 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -76,12 +76,14 @@ enum class audio_avport spdif_1 }; -enum class audio_downmix +enum class audio_format { - no_downmix, // Surround 7.1 - downmix_to_stereo, - downmix_to_5_1, - use_application_settings + automatic, + lpcm_2_48khz, + lpcm_5_1_48khz, + lpcm_7_1_48khz, + dts, + ac3, }; enum class music_handler diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index 26d2dba855..64365c15bd 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -1140,13 +1140,15 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ case enter_button_assign::cross: return tr("Enter with cross", "Enter button assignment"); } break; - case emu_settings_type::AudioChannels: - switch (static_cast(index)) + case emu_settings_type::AudioFormat: + switch (static_cast(index)) { - case audio_downmix::no_downmix: return tr("Surround 7.1", "Audio downmix"); - case audio_downmix::downmix_to_stereo: return tr("Downmix to Stereo", "Audio downmix"); - case audio_downmix::downmix_to_5_1: return tr("Downmix to 5.1", "Audio downmix"); - case audio_downmix::use_application_settings: return tr("Use application settings", "Audio downmix"); + case audio_format::automatic: return tr("Automatic", "Audio format"); + case audio_format::lpcm_2_48khz: return tr("Linear PCM 2 Ch. 48 kHz", "Audio format"); + case audio_format::lpcm_5_1_48khz: return tr("Linear PCM 5.1 Ch. 48 kHz", "Audio format"); + case audio_format::lpcm_7_1_48khz: return tr("Linear PCM 7.1 Ch. 48 kHz", "Audio format"); + case audio_format::dts: return tr("DTS 5.1 Ch.", "Audio format"); + case audio_format::ac3: return tr("Dolby Digital 5.1 Ch.", "Audio format"); } break; case emu_settings_type::LicenseArea: diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index bbd858d4a1..2e545c3e7c 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -121,7 +121,7 @@ enum class emu_settings_type AudioRenderer, DumpToFile, ConvertTo16Bit, - AudioChannels, + AudioFormat, AudioProvider, AudioAvport, MasterVolume, @@ -291,7 +291,7 @@ inline static const QMap settings_location = { emu_settings_type::AudioRenderer, { "Audio", "Renderer"}}, { emu_settings_type::DumpToFile, { "Audio", "Dump to file"}}, { emu_settings_type::ConvertTo16Bit, { "Audio", "Convert to 16 bit"}}, - { emu_settings_type::AudioChannels, { "Audio", "Audio Channels"}}, + { emu_settings_type::AudioFormat, { "Audio", "Audio Format"}}, { emu_settings_type::AudioProvider, { "Audio", "Audio Provider"}}, { emu_settings_type::AudioAvport, { "Audio", "RSXAudio Avport"}}, { emu_settings_type::MasterVolume, { "Audio", "Master Volume"}}, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 69c41c94a6..4be66e5c9a 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -444,7 +444,6 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceComboBox(ui->resBox, emu_settings_type::Resolution); SubscribeTooltip(ui->gb_default_resolution, tooltips.settings.resolution); // remove unsupported resolutions from the dropdown - const int saved_index = ui->resBox->currentIndex(); bool saved_index_removed = false; if (game && game->resolution > 0) { @@ -458,6 +457,8 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std // { 1 << 5, fmt::format("%s", video_resolution::_576p_16:9) }, }; + const int saved_index = ui->resBox->currentIndex(); + for (int i = ui->resBox->count() - 1; i >= 0; i--) { bool has_resolution = false; @@ -955,8 +956,63 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std #endif connect(ui->audioOutBox, QOverload::of(&QComboBox::currentIndexChanged), enable_buffering); - m_emu_settings->EnhanceComboBox(ui->combo_audio_downmix, emu_settings_type::AudioChannels); - SubscribeTooltip(ui->gb_audio_downmix, tooltips.settings.downmix); + m_emu_settings->EnhanceComboBox(ui->combo_audio_format, emu_settings_type::AudioFormat); + SubscribeTooltip(ui->gb_audio_format, tooltips.settings.audio_format); + bool saved_audio_format_index_removed = false; + if (game && game->sound_format > 0) + { + const std::map> formats + { + { 1 << 0, { audio_format::lpcm_2_48khz } }, + { 1 << 2, { audio_format::lpcm_5_1_48khz } }, + { 1 << 4, { audio_format::lpcm_7_1_48khz } }, + { 1 << 8, { audio_format::ac3 } }, + { 1 << 9, { audio_format::dts } }, + }; + + const int saved_index = ui->combo_audio_format->currentIndex(); + + for (int i = ui->combo_audio_format->count() - 1; i >= 0; i--) + { + const QVariantList var_list = ui->combo_audio_format->itemData(i).toList(); + ensure(var_list.size() == 2 && var_list[1].canConvert()); + + const audio_format format = static_cast(var_list[1].toInt()); + + bool has_format = false; + for (const auto& entry : formats) + { + if ((game->sound_format & entry.first) && std::find(entry.second.cbegin(), entry.second.cend(), format) != entry.second.cend()) + { + has_format = true; + break; + } + } + if (!has_format) + { + ui->combo_audio_format->removeItem(i); + if (i == saved_index) + { + saved_audio_format_index_removed = true; + } + } + } + } + // Set the current selection to the default if the original setting wasn't valid + if (saved_audio_format_index_removed) + { + for (int i = 0; i < ui->combo_audio_format->count(); i++) + { + const QVariantList var_list = ui->combo_audio_format->itemData(i).toList(); + ensure(var_list.size() == 2 && var_list[1].canConvert()); + + if (var_list[1].toInt() == static_cast(g_cfg.audio.format.def)) + { + ui->combo_audio_format->setCurrentIndex(i); + break; + } + } + } m_emu_settings->EnhanceComboBox(ui->audioProviderBox, emu_settings_type::AudioProvider); SubscribeTooltip(ui->gb_audio_provider, tooltips.settings.audio_provider); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 7bf079e980..423a6494f1 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -1031,13 +1031,13 @@ - + - Audio Channels + Audio Format - + - + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 3b5b516cfb..8eccf0c41e 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.\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 audio_format = tr("Determines the sound format.\nConfigure this setting if you want to switch between stereo and surround sound.\nChanging this value requires a restart of the game.\nUse automatic if you are unsure."); 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.");