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)
{
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<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);
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:
{
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<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,
};
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.

View File

@ -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<u32>(ch_cnt);
@ -526,7 +526,7 @@ namespace audio
.time_stretching_threshold = g_cfg.audio.time_stretching_threshold,
.convert_to_s16 = static_cast<bool>(g_cfg.audio.convert_to_s16),
.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,
.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<audio_downmix::downmix_to_stereo>(buf);
mix<AudioChannelCnt::STEREO>(buf);
break;
case 6:
mix<audio_downmix::downmix_to_5_1>(buf);
mix<AudioChannelCnt::SURROUND_5_1>(buf);
break;
case 8:
mix<audio_downmix::no_downmix>(buf);
mix<AudioChannelCnt::SURROUND_7_1>(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 <audio_downmix downmix>
template <AudioChannelCnt downmix>
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<u32>(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;

View File

@ -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<u32, u32, u32, u32> count_port_buffer_tags();
template <audio_downmix downmix>
template <AudioChannelCnt downmix>
void mix(float *out_buffer, s32 offset = 0);
void finish_port_volume_stepping();

View File

@ -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<audio_out_configuration>();
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_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>();
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)
{
if (mode.type == out.encoder)
{
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;
return mode.type == out.encoder && mode.channel == static_cast<u8>(channels);
});
ensure(it != out.sound_modes.cend());
@ -289,8 +336,7 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
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)
if (std::memcmp(&out_old, &out_new, sizeof(audio_out_configuration::audio_out)) != 0)
{
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
{
// 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();

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()
{
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 =
{

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::_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_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::_bool enable_buffering{ this, "Enable Buffering", true, 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 <>
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)
{
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;

View File

@ -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

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");
}
break;
case emu_settings_type::AudioChannels:
switch (static_cast<audio_downmix>(index))
case emu_settings_type::AudioFormat:
switch (static_cast<audio_format>(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:

View File

@ -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<emu_settings_type, cfg_location> 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"}},

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);
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> 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> gui_settings, std
#endif
connect(ui->audioOutBox, QOverload<int>::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<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);
SubscribeTooltip(ui->gb_audio_provider, tooltips.settings.audio_provider);

View File

@ -1031,13 +1031,13 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_audio_downmix">
<widget class="QGroupBox" name="gb_audio_format">
<property name="title">
<string>Audio Channels</string>
<string>Audio Format</string>
</property>
<layout class="QVBoxLayout" name="gb_audio_channels_layout">
<layout class="QVBoxLayout" name="gb_audio_format_layout">
<item>
<widget class="QComboBox" name="combo_audio_downmix"/>
<widget class="QComboBox" name="combo_audio_format"/>
</item>
</layout>
</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_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.");