cellAudio: use format instead of downmix

This commit is contained in:
Megamouse 2022-05-28 17:45:50 +02:00
parent c42ff338e7
commit 72e1e242a3
15 changed files with 271 additions and 176 deletions

View file

@ -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) audio_out_configuration& audio_out = g_fxo->get<audio_out_configuration>();
{ std::lock_guard lock(audio_out.mtx);
case audio_downmix::no_downmix: return AudioChannelCnt::SURROUND_7_1; ensure(!audio_out.out.empty());
case audio_downmix::downmix_to_5_1: return AudioChannelCnt::SURROUND_5_1; audio_out_configuration::audio_out& out = audio_out.out.at(CELL_AUDIO_OUT_PRIMARY);
case audio_downmix::downmix_to_stereo: return AudioChannelCnt::STEREO;
case audio_downmix::use_application_settings:
{
audio_out_configuration& audio_out = g_fxo->get<audio_out_configuration>();
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: case 2: return AudioChannelCnt::STEREO;
{ case 6: return AudioChannelCnt::SURROUND_5_1;
switch (out.channels) case 8: return AudioChannelCnt::SURROUND_7_1;
{
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: 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: default:
fmt::throw_exception("Unknown audio channel mode %s (%d)", downmix, static_cast<int>(downmix)); fmt::throw_exception("Unknown downmixer in cellAudioOut config: %d", out.downmixer);
} }
} }

View file

@ -37,8 +37,6 @@ enum class AudioChannelCnt : u32
SURROUND_7_1 = 8, SURROUND_7_1 = 8,
}; };
enum class audio_downmix;
class AudioBackend class AudioBackend
{ {
public: public:
@ -140,7 +138,7 @@ public:
/* /*
* Returns the channel count based on the downmix mode. * 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. * Downmix audio stream.

View file

@ -66,7 +66,7 @@ void cell_audio_config::reset(bool backend_changed)
const AudioFreq freq = AudioFreq::FREQ_48K; const AudioFreq freq = AudioFreq::FREQ_48K;
const AudioSampleSize sample_size = raw.convert_to_s16 ? AudioSampleSize::S16 : AudioSampleSize::FLOAT; 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; const f64 cb_frame_len = backend->Open(freq, sample_size, ch_cnt) ? backend->GetCallbackFrameLen() : 0.0;
audio_channels = static_cast<u32>(ch_cnt); audio_channels = static_cast<u32>(ch_cnt);
@ -526,7 +526,7 @@ namespace audio
.time_stretching_threshold = g_cfg.audio.time_stretching_threshold, .time_stretching_threshold = g_cfg.audio.time_stretching_threshold,
.convert_to_s16 = static_cast<bool>(g_cfg.audio.convert_to_s16), .convert_to_s16 = static_cast<bool>(g_cfg.audio.convert_to_s16),
.dump_to_file = static_cast<bool>(g_cfg.audio.dump_to_file), .dump_to_file = static_cast<bool>(g_cfg.audio.dump_to_file),
.downmix = g_cfg.audio.audio_channel_downmix, .format = g_cfg.audio.format,
.renderer = g_cfg.audio.renderer, .renderer = g_cfg.audio.renderer,
.provider = g_cfg.audio.provider .provider = g_cfg.audio.provider
}; };
@ -550,7 +550,7 @@ namespace audio
raw.time_stretching_threshold != new_raw.time_stretching_threshold || raw.time_stretching_threshold != new_raw.time_stretching_threshold ||
raw.enable_time_stretching != new_raw.enable_time_stretching || raw.enable_time_stretching != new_raw.enable_time_stretching ||
raw.convert_to_s16 != new_raw.convert_to_s16 || 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.renderer != new_raw.renderer ||
raw.dump_to_file != new_raw.dump_to_file) raw.dump_to_file != new_raw.dump_to_file)
{ {
@ -848,13 +848,13 @@ void cell_audio_thread::operator()()
switch (cfg.audio_channels) switch (cfg.audio_channels)
{ {
case 2: case 2:
mix<audio_downmix::downmix_to_stereo>(buf); mix<AudioChannelCnt::STEREO>(buf);
break; break;
case 6: case 6:
mix<audio_downmix::downmix_to_5_1>(buf); mix<AudioChannelCnt::SURROUND_5_1>(buf);
break; break;
case 8: case 8:
mix<audio_downmix::no_downmix>(buf); mix<AudioChannelCnt::SURROUND_7_1>(buf);
break; break;
default: default:
fmt::throw_exception("Unsupported number of audio channels: %u", cfg.audio_channels); 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; return nullptr;
} }
template <audio_downmix downmix> template <AudioChannelCnt downmix>
void cell_audio_thread::mix(float *out_buffer, s32 offset) void cell_audio_thread::mix(float *out_buffer, s32 offset)
{ {
AUDIT(out_buffer != nullptr); 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<u32>(downmix);
constexpr u32 out_buffer_sz = channels * AUDIO_BUFFER_SAMPLES; constexpr u32 out_buffer_sz = channels * AUDIO_BUFFER_SAMPLES;
bool first_mix = true; 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 + 0] = left;
out_buffer[out + 1] = right; 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 + 2] = 0.0f;
out_buffer[out + 3] = 0.0f; out_buffer[out + 3] = 0.0f;
out_buffer[out + 4] = 0.0f; out_buffer[out + 4] = 0.0f;
out_buffer[out + 5] = 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 + 6] = 0.0f;
out_buffer[out + 7] = 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_left = buf[in + 6] * m;
const float rear_right = buf[in + 7] * 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 // Don't mix in the lfe as per dolby specification and based on documentation
const float mid = center * 0.5f; 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 + 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; 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 + 0] = left;
out_buffer[out + 1] = right; 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_left = buf[in + 6] * m;
const float rear_right = buf[in + 7] * 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 // Don't mix in the lfe as per dolby specification and based on documentation
const float mid = center * 0.5f; 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 + 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; 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 + 0] += left;
out_buffer[out + 1] += right; out_buffer[out + 1] += right;

View file

@ -201,7 +201,7 @@ struct cell_audio_config
s64 time_stretching_threshold = 0; s64 time_stretching_threshold = 0;
bool convert_to_s16 = false; bool convert_to_s16 = false;
bool dump_to_file = 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_renderer renderer = audio_renderer::null;
audio_provider provider = audio_provider::none; audio_provider provider = audio_provider::none;
}; };
@ -348,7 +348,7 @@ private:
void reset_ports(s32 offset = 0); void reset_ports(s32 offset = 0);
void advance(u64 timestamp); void advance(u64 timestamp);
std::tuple<u32, u32, u32, u32> count_port_buffer_tags(); std::tuple<u32, u32, u32, u32> count_port_buffer_tags();
template <audio_downmix downmix> template <AudioChannelCnt downmix>
void mix(float *out_buffer, s32 offset = 0); void mix(float *out_buffer, s32 offset = 0);
void finish_port_volume_stepping(); void finish_port_volume_stepping();

View file

@ -3,6 +3,7 @@
#include "Emu/Cell/lv2/sys_rsxaudio.h" #include "Emu/Cell/lv2/sys_rsxaudio.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Loader/PSF.h"
#include "cellAudioOut.h" #include "cellAudioOut.h"
#include "cellAudio.h" #include "cellAudio.h"
@ -34,45 +35,137 @@ audio_out_configuration::audio_out_configuration()
{ {
CellAudioOutSoundMode mode{}; CellAudioOutSoundMode mode{};
mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; // TODO: audio_format should be a bitmap, but we'll keep it simple for now (Linear PCM 2 Ch. 48 kHz should always exist)
mode.channel = CELL_AUDIO_OUT_CHNUM_8; // TODO: more formats:
mode.fs = CELL_AUDIO_OUT_FS_48KHZ; // - Each LPCM with other sample frequencies (we currently only support 48 kHz)
mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy; // - 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); const psf::registry psf = psf::load_object(fs::file(Emu.GetSfoDir() + "/PARAM.SFO"));
out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); if (psf.contains("SOUND_FORMAT")) sound_format = psf.at("SOUND_FORMAT").as_integer();
mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; if (sound_format & (1 << 0)) // Linear PCM 2 Ch.
mode.channel = CELL_AUDIO_OUT_CHNUM_6; {
mode.fs = CELL_AUDIO_OUT_FS_48KHZ; mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM;
mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; 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_PRIMARY).sound_modes.push_back(mode);
out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode);
}
mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; if (sound_format & (1 << 2)) // Linear PCM 5.1 Ch.
mode.channel = CELL_AUDIO_OUT_CHNUM_2; {
mode.fs = CELL_AUDIO_OUT_FS_48KHZ; mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM;
mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH; 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_PRIMARY).sound_modes.push_back(mode);
out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode);
}
mode.type = CELL_AUDIO_OUT_CODING_TYPE_DTS; if (sound_format & (1 << 4)) // Linear PCM 7.1 Ch.
mode.channel = CELL_AUDIO_OUT_CHNUM_6; {
mode.fs = CELL_AUDIO_OUT_FS_48KHZ; mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM;
mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; 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_PRIMARY).sound_modes.push_back(mode);
out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode); out.at(CELL_AUDIO_OUT_SECONDARY).sound_modes.push_back(mode);
}
mode.type = CELL_AUDIO_OUT_CODING_TYPE_AC3; if (sound_format & (1 << 8)) // DTS 5.1 Ch.
mode.channel = CELL_AUDIO_OUT_CHNUM_6; {
mode.fs = CELL_AUDIO_OUT_FS_48KHZ; mode.type = CELL_AUDIO_OUT_CODING_TYPE_DTS;
mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_6CH_LREClr; 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_PRIMARY).sound_modes.push_back(mode);
out.at(CELL_AUDIO_OUT_SECONDARY).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); 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); 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; s32 available = 0;
// Check if the requested audio parameters are available and find the max supported channel count // 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); 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 // Check if the requested audio parameters are available
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>(); audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx); std::lock_guard lock(cfg.mtx);
@ -203,7 +264,7 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptr<CellAudio
case CELL_AUDIO_OUT_PRIMARY: case CELL_AUDIO_OUT_PRIMARY:
case CELL_AUDIO_OUT_SECONDARY: case CELL_AUDIO_OUT_SECONDARY:
{ {
const AudioChannelCnt channels = AudioBackend::get_channel_count(g_cfg.audio.audio_channel_downmix); const AudioChannelCnt channels = AudioBackend::get_channel_count();
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>(); audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
std::lock_guard lock(cfg.mtx); std::lock_guard lock(cfg.mtx);
@ -211,21 +272,7 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptr<CellAudio
const auto it = std::find_if(out.sound_modes.cbegin(), out.sound_modes.cend(), [&channels, &out](const CellAudioOutSoundMode& mode) const auto it = std::find_if(out.sound_modes.cbegin(), out.sound_modes.cend(), [&channels, &out](const CellAudioOutSoundMode& mode)
{ {
if (mode.type == out.encoder) return mode.type == out.encoder && mode.channel == static_cast<u8>(channels);
{
switch (mode.type)
{
case CELL_AUDIO_OUT_CODING_TYPE_LPCM:
return mode.channel == static_cast<u8>(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;
}); });
ensure(it != out.sound_modes.cend()); ensure(it != out.sound_modes.cend());
@ -289,8 +336,7 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
out_new = out; out_new = out;
} }
if (g_cfg.audio.audio_channel_downmix == audio_downmix::use_application_settings && if (std::memcmp(&out_old, &out_new, sizeof(audio_out_configuration::audio_out)) != 0)
std::memcmp(&out_old, &out_new, sizeof(audio_out_configuration::audio_out)) != 0)
{ {
const auto reset_audio = [audioOut]() -> void const auto reset_audio = [audioOut]() -> void
{ {

View file

@ -254,7 +254,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
else else
{ {
// TODO: Is cellHddGameCheck really responsible for writing the information in get->getParam ? (If not, delete this 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 // 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(); if (psf.contains("PARENTAL_LEVEL")) get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer();

View file

@ -1322,7 +1322,7 @@ void rsxaudio_backend_thread::update_emu_cfg()
rsxaudio_backend_thread::emu_audio_cfg rsxaudio_backend_thread::get_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 = emu_audio_cfg cfg =
{ {

View file

@ -235,7 +235,7 @@ struct cfg_root : cfg::node
cfg::_enum<audio_avport> rsxaudio_port{ this, "RSXAudio Avport", audio_avport::hdmi_0, true }; cfg::_enum<audio_avport> rsxaudio_port{ this, "RSXAudio Avport", audio_avport::hdmi_0, true };
cfg::_bool dump_to_file{ this, "Dump to file", false, 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::_bool convert_to_s16{ this, "Convert to 16 bit", false, true };
cfg::_enum<audio_downmix> audio_channel_downmix{ this, "Audio Channels", audio_downmix::downmix_to_stereo, true }; cfg::_enum<audio_format> format{ this, "Audio Format", audio_format::automatic, false };
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, true }; 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 <4, 250> desired_buffer_duration{ this, "Desired Audio Buffer Duration", 100, true };

View file

@ -532,16 +532,18 @@ void fmt_class_string<audio_avport>::format(std::string& out, u64 arg)
} }
template <> template <>
void fmt_class_string<audio_downmix>::format(std::string& out, u64 arg) void fmt_class_string<audio_format>::format(std::string& out, u64 arg)
{ {
format_enum(out, arg, [](audio_downmix value) format_enum(out, arg, [](audio_format value)
{ {
switch (value) switch (value)
{ {
case audio_downmix::no_downmix: return "No downmix"; case audio_format::automatic: return "Automatic";
case audio_downmix::downmix_to_stereo: return "Downmix to Stereo"; case audio_format::lpcm_2_48khz: return "Linear PCM 2 Ch. 48 kHz";
case audio_downmix::downmix_to_5_1: return "Downmix to 5.1"; case audio_format::lpcm_5_1_48khz: return "Linear PCM 5.1 Ch. 48 kHz";
case audio_downmix::use_application_settings: return "Use application settings"; 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; return unknown;

View file

@ -76,12 +76,14 @@ enum class audio_avport
spdif_1 spdif_1
}; };
enum class audio_downmix enum class audio_format
{ {
no_downmix, // Surround 7.1 automatic,
downmix_to_stereo, lpcm_2_48khz,
downmix_to_5_1, lpcm_5_1_48khz,
use_application_settings lpcm_7_1_48khz,
dts,
ac3,
}; };
enum class music_handler enum class music_handler

View file

@ -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"); case enter_button_assign::cross: return tr("Enter with cross", "Enter button assignment");
} }
break; break;
case emu_settings_type::AudioChannels: case emu_settings_type::AudioFormat:
switch (static_cast<audio_downmix>(index)) switch (static_cast<audio_format>(index))
{ {
case audio_downmix::no_downmix: return tr("Surround 7.1", "Audio downmix"); case audio_format::automatic: return tr("Automatic", "Audio format");
case audio_downmix::downmix_to_stereo: return tr("Downmix to Stereo", "Audio downmix"); case audio_format::lpcm_2_48khz: return tr("Linear PCM 2 Ch. 48 kHz", "Audio format");
case audio_downmix::downmix_to_5_1: return tr("Downmix to 5.1", "Audio downmix"); case audio_format::lpcm_5_1_48khz: return tr("Linear PCM 5.1 Ch. 48 kHz", "Audio format");
case audio_downmix::use_application_settings: return tr("Use application settings", "Audio downmix"); 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; break;
case emu_settings_type::LicenseArea: case emu_settings_type::LicenseArea:

View file

@ -121,7 +121,7 @@ enum class emu_settings_type
AudioRenderer, AudioRenderer,
DumpToFile, DumpToFile,
ConvertTo16Bit, ConvertTo16Bit,
AudioChannels, AudioFormat,
AudioProvider, AudioProvider,
AudioAvport, AudioAvport,
MasterVolume, MasterVolume,
@ -291,7 +291,7 @@ inline static const QMap<emu_settings_type, cfg_location> settings_location =
{ emu_settings_type::AudioRenderer, { "Audio", "Renderer"}}, { emu_settings_type::AudioRenderer, { "Audio", "Renderer"}},
{ emu_settings_type::DumpToFile, { "Audio", "Dump to file"}}, { emu_settings_type::DumpToFile, { "Audio", "Dump to file"}},
{ emu_settings_type::ConvertTo16Bit, { "Audio", "Convert to 16 bit"}}, { 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::AudioProvider, { "Audio", "Audio Provider"}},
{ emu_settings_type::AudioAvport, { "Audio", "RSXAudio Avport"}}, { emu_settings_type::AudioAvport, { "Audio", "RSXAudio Avport"}},
{ emu_settings_type::MasterVolume, { "Audio", "Master Volume"}}, { emu_settings_type::MasterVolume, { "Audio", "Master Volume"}},

View file

@ -444,7 +444,6 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
m_emu_settings->EnhanceComboBox(ui->resBox, emu_settings_type::Resolution); m_emu_settings->EnhanceComboBox(ui->resBox, emu_settings_type::Resolution);
SubscribeTooltip(ui->gb_default_resolution, tooltips.settings.resolution); SubscribeTooltip(ui->gb_default_resolution, tooltips.settings.resolution);
// remove unsupported resolutions from the dropdown // remove unsupported resolutions from the dropdown
const int saved_index = ui->resBox->currentIndex();
bool saved_index_removed = false; bool saved_index_removed = false;
if (game && game->resolution > 0) if (game && game->resolution > 0)
{ {
@ -458,6 +457,8 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
// { 1 << 5, fmt::format("%s", video_resolution::_576p_16:9) }, // { 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--) for (int i = ui->resBox->count() - 1; i >= 0; i--)
{ {
bool has_resolution = false; bool has_resolution = false;
@ -955,8 +956,63 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
#endif #endif
connect(ui->audioOutBox, QOverload<int>::of(&QComboBox::currentIndexChanged), enable_buffering); connect(ui->audioOutBox, QOverload<int>::of(&QComboBox::currentIndexChanged), enable_buffering);
m_emu_settings->EnhanceComboBox(ui->combo_audio_downmix, emu_settings_type::AudioChannels); m_emu_settings->EnhanceComboBox(ui->combo_audio_format, emu_settings_type::AudioFormat);
SubscribeTooltip(ui->gb_audio_downmix, tooltips.settings.downmix); 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<u32, std::vector<audio_format>> 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<int>());
const audio_format format = static_cast<audio_format>(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<int>());
if (var_list[1].toInt() == static_cast<int>(g_cfg.audio.format.def))
{
ui->combo_audio_format->setCurrentIndex(i);
break;
}
}
}
m_emu_settings->EnhanceComboBox(ui->audioProviderBox, emu_settings_type::AudioProvider); m_emu_settings->EnhanceComboBox(ui->audioProviderBox, emu_settings_type::AudioProvider);
SubscribeTooltip(ui->gb_audio_provider, tooltips.settings.audio_provider); SubscribeTooltip(ui->gb_audio_provider, tooltips.settings.audio_provider);

View file

@ -1031,13 +1031,13 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_audio_downmix"> <widget class="QGroupBox" name="gb_audio_format">
<property name="title"> <property name="title">
<string>Audio Channels</string> <string>Audio Format</string>
</property> </property>
<layout class="QVBoxLayout" name="gb_audio_channels_layout"> <layout class="QVBoxLayout" name="gb_audio_format_layout">
<item> <item>
<widget class="QComboBox" name="combo_audio_downmix"/> <widget class="QComboBox" name="combo_audio_format"/>
</item> </item>
</layout> </layout>
</widget> </widget>

View file

@ -51,7 +51,7 @@ public:
const QString audio_avport = tr("Controls which avport is used to sample audio data from."); 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 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 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 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 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."); 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.");