diff --git a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp index 53c8700c2d..9f70a3d41f 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp @@ -35,6 +35,29 @@ audio_out_configuration::audio_out_configuration() { CellAudioOutSoundMode mode{}; + audio_out& primary_output = out.at(CELL_AUDIO_OUT_PRIMARY); + audio_out& secondary_output = out.at(CELL_AUDIO_OUT_SECONDARY); + + std::vector& primary_modes = primary_output.sound_modes; + std::vector& secondary_modes = secondary_output.sound_modes; + + s32 sound_format = (1 << 0); // Linear PCM 2 Ch. + + 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(); + + const bool supports_lpcm_2 = (sound_format & (1 << 0)); // Linear PCM 2 Ch. + const bool supports_lpcm_5_1 = (sound_format & (1 << 2)); // Linear PCM 5.1 Ch. + const bool supports_lpcm_7_1 = (sound_format & (1 << 4)); // Linear PCM 7.1 Ch. + const bool supports_dts = (sound_format & (1 << 8)); // DTS 5.1 Ch. + const bool supports_ac3 = (sound_format & (1 << 9)); // Dolby Digital 5.1 Ch. + + if (supports_lpcm_2) cellSysutil.notice("cellAudioOut: found support for Linear PCM 2 Ch."); + if (supports_lpcm_5_1) cellSysutil.notice("cellAudioOut: found support for Linear PCM 5.1 Ch."); + if (supports_lpcm_7_1) cellSysutil.notice("cellAudioOut: found support for Linear PCM 7.1 Ch."); + if (supports_dts) cellSysutil.notice("cellAudioOut: found support for DTS 5.1 Ch."); + if (supports_ac3) cellSysutil.notice("cellAudioOut: found support for Dolby Digital 5.1 Ch."); + // 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) @@ -48,124 +71,164 @@ audio_out_configuration::audio_out_configuration() { case audio_format::automatic: // Automatic based on supported formats { - s32 sound_format = (1 << 0); - - 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(); - - if (sound_format & (1 << 0)) // Linear PCM 2 Ch. + if (supports_lpcm_2) // 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); + primary_modes.push_back(mode); + secondary_modes.push_back(mode); } - if (sound_format & (1 << 2)) // Linear PCM 5.1 Ch. + if (supports_lpcm_5_1) // 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); + primary_modes.push_back(mode); + secondary_modes.push_back(mode); } - if (sound_format & (1 << 4)) // Linear PCM 7.1 Ch. + if (supports_lpcm_7_1) // 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); + primary_modes.push_back(mode); + secondary_modes.push_back(mode); } - if (sound_format & (1 << 8)) // DTS 5.1 Ch. + if (supports_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); + primary_modes.push_back(mode); + secondary_modes.push_back(mode); } - if (sound_format & (1 << 9)) // Dolby Digital 5.1 Ch. + if (supports_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); + primary_modes.push_back(mode); + secondary_modes.push_back(mode); } break; } case audio_format::lpcm_2_48khz: // Linear PCM 2 Ch. 48 kHz + { + if (supports_lpcm_2) + { + 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; + + primary_modes.push_back(mode); + secondary_modes.push_back(mode); + } + break; + } + case audio_format::lpcm_5_1_48khz: // Linear PCM 5.1 Ch. 48 kHz + { + if (supports_lpcm_5_1) + { + 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; + + primary_modes.push_back(mode); + secondary_modes.push_back(mode); + } + break; + } + case audio_format::lpcm_7_1_48khz: // Linear PCM 7.1 Ch. 48 kHz + { + if (supports_lpcm_7_1) + { + 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; + + primary_modes.push_back(mode); + secondary_modes.push_back(mode); + } + break; + } + case audio_format::dts: // DTS 5.1 Ch. + { + if (supports_dts) + { + 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; + + primary_modes.push_back(mode); + secondary_modes.push_back(mode); + } + break; + } + case audio_format::ac3: // Dolby Digital 5.1 Ch. + { + if (supports_ac3) + { + 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; + + primary_modes.push_back(mode); + secondary_modes.push_back(mode); + } + break; + } + } + + // Fallback to default sound mode if none was found + if (primary_modes.empty() || secondary_modes.empty()) { 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; + if (primary_modes.empty()) + { + primary_modes.push_back(mode); + cellSysutil.warning("cellAudioOut: using Linear PCM 2 Ch. fallback sound mode for primary output"); + } - out.at(CELL_AUDIO_OUT_PRIMARY).sound_modes.push_back(mode); - out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); - break; + if (secondary_modes.empty()) + { + secondary_modes.push_back(mode); + cellSysutil.warning("cellAudioOut: using Linear PCM 2 Ch. fallback sound mode for secondary output"); + } } - 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; + // Pre-select the first available sound mode + primary_output.channels = primary_modes.front().channel; + primary_output.encoder = primary_modes.front().type; + secondary_output.channels = secondary_modes.front().channel; + secondary_output.encoder = secondary_modes.front().type; - 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; - } - } + cellSysutil.notice("cellAudioOut: initial primary output configuration: channels=%d, encoder=%d, downmixer=%d", primary_output.channels, primary_output.encoder, primary_output.downmixer); + cellSysutil.notice("cellAudioOut: initial secondary output configuration: channels=%d, encoder=%d, downmixer=%d", secondary_output.channels, secondary_output.encoder, secondary_output.downmixer); } error_code cellAudioOutGetNumberOfDevice(u32 audioOut); diff --git a/rpcs3/Emu/Cell/Modules/cellAudioOut.h b/rpcs3/Emu/Cell/Modules/cellAudioOut.h index 6aad9e64d4..1c8fd642ed 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudioOut.h +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.h @@ -197,7 +197,7 @@ struct audio_out_configuration struct audio_out { u32 state = CELL_AUDIO_OUT_OUTPUT_STATE_ENABLED; - u32 channels = CELL_AUDIO_OUT_CHNUM_8; + u32 channels = CELL_AUDIO_OUT_CHNUM_2; 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; diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 396e4ac9f7..d1981071f8 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 format{ this, "Audio Format", audio_format::automatic, false }; + cfg::_enum format{ this, "Audio Format", audio_format::lpcm_2_48khz, 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.h b/rpcs3/Emu/system_config_types.h index 30eddabe7a..bb2d20bd14 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -78,12 +78,12 @@ enum class audio_avport enum class audio_format { - automatic, lpcm_2_48khz, lpcm_5_1_48khz, lpcm_7_1_48khz, dts, ac3, + automatic, }; enum class music_handler diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 8eccf0c41e..3dc25a4e20 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 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 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.\nThe automatic setting will let the game choose from all available formats."); 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.");