mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
cellAudio(Out): properly implement all downmixing modes (#12252)
This commit is contained in:
parent
0b14d785ca
commit
a6237e5473
@ -136,7 +136,7 @@ public:
|
||||
static void normalize(u32 sample_cnt, const f32* src, f32* dst);
|
||||
|
||||
/*
|
||||
* Returns the channel count and the downmix mode.
|
||||
* Returns the output channel count and downmix mode.
|
||||
*/
|
||||
static std::pair<AudioChannelCnt, AudioChannelCnt> get_channel_count_and_downmixer(u32 device_index);
|
||||
|
||||
|
@ -845,17 +845,55 @@ void cell_audio_thread::operator()()
|
||||
// Mix
|
||||
float* buf = ringbuffer->get_current_buffer();
|
||||
|
||||
switch (cfg.audio_channels)
|
||||
{
|
||||
case 2:
|
||||
switch (cfg.audio_downmix)
|
||||
{
|
||||
case AudioChannelCnt::SURROUND_7_1:
|
||||
mix<AudioChannelCnt::STEREO, AudioChannelCnt::SURROUND_7_1>(buf);
|
||||
break;
|
||||
case AudioChannelCnt::STEREO:
|
||||
mix<AudioChannelCnt::STEREO>(buf);
|
||||
mix<AudioChannelCnt::STEREO, AudioChannelCnt::STEREO>(buf);
|
||||
break;
|
||||
case AudioChannelCnt::SURROUND_5_1:
|
||||
mix<AudioChannelCnt::SURROUND_5_1>(buf);
|
||||
mix<AudioChannelCnt::STEREO, AudioChannelCnt::SURROUND_5_1>(buf);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
switch (cfg.audio_downmix)
|
||||
{
|
||||
case AudioChannelCnt::SURROUND_7_1:
|
||||
mix<AudioChannelCnt::SURROUND_7_1>(buf);
|
||||
mix<AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::SURROUND_7_1>(buf);
|
||||
break;
|
||||
case AudioChannelCnt::STEREO:
|
||||
mix<AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::STEREO>(buf);
|
||||
break;
|
||||
case AudioChannelCnt::SURROUND_5_1:
|
||||
mix<AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::SURROUND_5_1>(buf);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
switch (cfg.audio_downmix)
|
||||
{
|
||||
case AudioChannelCnt::SURROUND_7_1:
|
||||
mix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_7_1>(buf);
|
||||
break;
|
||||
case AudioChannelCnt::STEREO:
|
||||
mix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO>(buf);
|
||||
break;
|
||||
case AudioChannelCnt::SURROUND_5_1:
|
||||
mix<AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1>(buf);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count in cell_audio_config: %d", static_cast<u32>(cfg.audio_channels));
|
||||
}
|
||||
|
||||
// Enqueue
|
||||
@ -882,13 +920,13 @@ audio_port* cell_audio_thread::open_port()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <AudioChannelCnt downmix>
|
||||
template <AudioChannelCnt channels, AudioChannelCnt downmix>
|
||||
void cell_audio_thread::mix(float* out_buffer, s32 offset)
|
||||
{
|
||||
AUDIT(out_buffer != nullptr);
|
||||
|
||||
constexpr u32 channels = static_cast<u32>(downmix);
|
||||
constexpr u32 out_buffer_sz = channels * AUDIO_BUFFER_SAMPLES;
|
||||
constexpr u32 out_channels = static_cast<u32>(channels);
|
||||
constexpr u32 out_buffer_sz = out_channels * AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
const float master_volume = g_cfg.audio.volume / 100.0f;
|
||||
|
||||
@ -928,7 +966,7 @@ void cell_audio_thread::mix(float* out_buffer, s32 offset)
|
||||
|
||||
if (port.num_channels == 2)
|
||||
{
|
||||
for (u32 out = 0, in = 0; out < out_buffer_sz; out += channels, in += 2)
|
||||
for (u32 out = 0, in = 0; out < out_buffer_sz; out += out_channels, in += 2)
|
||||
{
|
||||
step_volume(port);
|
||||
|
||||
@ -941,7 +979,7 @@ void cell_audio_thread::mix(float* out_buffer, s32 offset)
|
||||
}
|
||||
else if (port.num_channels == 8)
|
||||
{
|
||||
for (u32 out = 0, in = 0; out < out_buffer_sz; out += channels, in += 8)
|
||||
for (u32 out = 0, in = 0; out < out_buffer_sz; out += out_channels, in += 8)
|
||||
{
|
||||
step_volume(port);
|
||||
|
||||
@ -965,17 +1003,41 @@ void cell_audio_thread::mix(float* out_buffer, s32 offset)
|
||||
{
|
||||
out_buffer[out + 0] += left;
|
||||
out_buffer[out + 1] += right;
|
||||
|
||||
if constexpr (out_channels >= 6) // Only mix the surround channels into the output if surround output is configured
|
||||
{
|
||||
out_buffer[out + 2] += center;
|
||||
out_buffer[out + 3] += low_freq;
|
||||
|
||||
if constexpr (out_channels == 6)
|
||||
{
|
||||
out_buffer[out + 4] += side_left + rear_left;
|
||||
out_buffer[out + 5] += side_right + rear_right;
|
||||
}
|
||||
else // When using 7.1 ouput, out_buffer[out + 4] and out_buffer[out + 5] are the rear channels, so the side channels need to be mixed into [out + 6] and [out + 7]
|
||||
{
|
||||
out_buffer[out + 6] += side_left + rear_left;
|
||||
out_buffer[out + 7] += side_right + rear_right;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_buffer[out + 0] += left;
|
||||
out_buffer[out + 1] += right;
|
||||
|
||||
if constexpr (out_channels >= 6) // Only mix the surround channels into the output if surround output is configured
|
||||
{
|
||||
out_buffer[out + 2] += center;
|
||||
out_buffer[out + 3] += low_freq;
|
||||
|
||||
if constexpr (out_channels == 6)
|
||||
{
|
||||
out_buffer[out + 4] += side_left;
|
||||
out_buffer[out + 5] += side_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_buffer[out + 4] += rear_left;
|
||||
out_buffer[out + 5] += rear_right;
|
||||
out_buffer[out + 6] += side_left;
|
||||
@ -983,6 +1045,8 @@ void cell_audio_thread::mix(float* out_buffer, s32 offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Unknown channel count (port=%u, channel=%d)", port.number, port.num_channels);
|
||||
|
@ -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 <AudioChannelCnt downmix>
|
||||
template <AudioChannelCnt channels, AudioChannelCnt downmix>
|
||||
void mix(float* out_buffer, s32 offset = 0);
|
||||
void finish_port_volume_stepping();
|
||||
|
||||
|
@ -180,42 +180,27 @@ audio_out_configuration::audio_out_configuration()
|
||||
|
||||
std::pair<AudioChannelCnt, AudioChannelCnt> audio_out_configuration::audio_out::get_channel_count_and_downmixer() const
|
||||
{
|
||||
std::pair<AudioChannelCnt, AudioChannelCnt> ret;
|
||||
|
||||
switch (sound_mode.channel)
|
||||
{
|
||||
case 2: ret.first = AudioChannelCnt::STEREO; break;
|
||||
case 6: ret.first = AudioChannelCnt::SURROUND_5_1; break;
|
||||
case 8: ret.first = AudioChannelCnt::SURROUND_7_1; break;
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count in cellAudioOut sound_mode: %d", sound_mode.channel);
|
||||
}
|
||||
|
||||
switch (downmixer)
|
||||
{
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_NONE:
|
||||
{
|
||||
switch (channels)
|
||||
{
|
||||
case 2: return { AudioChannelCnt::STEREO, AudioChannelCnt::STEREO };
|
||||
case 6: return { AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::SURROUND_5_1 };
|
||||
case 8: return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_7_1 };
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_NONE: ret.second = AudioChannelCnt::SURROUND_7_1; break;
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_A: ret.second = AudioChannelCnt::STEREO; break;
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_B: ret.second = AudioChannelCnt::SURROUND_5_1; break;
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count in cellAudioOut config: %d", channels);
|
||||
}
|
||||
}
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_A:
|
||||
{
|
||||
switch (channels)
|
||||
{
|
||||
case 2:
|
||||
return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_A in cellAudioOut config: %d", channels);
|
||||
}
|
||||
}
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_B:
|
||||
{
|
||||
switch (channels)
|
||||
{
|
||||
case 6:
|
||||
return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1 };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_B in cellAudioOut config: %d", channels);
|
||||
}
|
||||
}
|
||||
default:
|
||||
fmt::throw_exception("Unknown downmixer in cellAudioOut config: %d", downmixer);
|
||||
fmt::throw_exception("Unsupported downmixer in cellAudioOut config: %d", downmixer);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
error_code cellAudioOutGetNumberOfDevice(u32 audioOut);
|
||||
@ -361,34 +346,26 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
|
||||
audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
|
||||
|
||||
// Apparently the set config does not necessarily have to exist in the list of sound modes.
|
||||
// For example 8 channels are used if the downMixer is set even if the PS3 only supports 2 channel output.
|
||||
|
||||
if (out.channels != config->channel || out.encoder != config->encoder || out.downmixer != config->downMixer)
|
||||
{
|
||||
out.channels = config->channel;
|
||||
out.encoder = config->encoder;
|
||||
|
||||
if (config->downMixer > CELL_AUDIO_OUT_DOWNMIXER_TYPE_B) // PS3 ignores invalid downMixer values and keeps the previous valid one instead
|
||||
{
|
||||
cellSysutil.warning("cellAudioOutConfigure: Invalid downmixing mode configured: %d. Keeping old mode: downMixer=%d",
|
||||
config->downMixer, out.downmixer);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.downmixer = config->downMixer;
|
||||
}
|
||||
|
||||
// Try to find the best sound mode for this configuration
|
||||
const auto [channels, downmixer] = out.get_channel_count_and_downmixer();
|
||||
const auto it = std::find_if(out.sound_modes.cbegin(), out.sound_modes.cend(), [channels = channels, &out](const CellAudioOutSoundMode& mode)
|
||||
const auto it = std::find_if(out.sound_modes.cbegin(), out.sound_modes.cend(), [&out](const CellAudioOutSoundMode& mode)
|
||||
{
|
||||
if (mode.type != out.encoder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out.downmixer == CELL_AUDIO_OUT_DOWNMIXER_TYPE_A)
|
||||
{
|
||||
return mode.channel == CELL_AUDIO_OUT_CHNUM_2;
|
||||
}
|
||||
|
||||
if (out.downmixer == CELL_AUDIO_OUT_DOWNMIXER_TYPE_B)
|
||||
{
|
||||
return mode.channel == CELL_AUDIO_OUT_CHNUM_6;
|
||||
}
|
||||
|
||||
return mode.channel == static_cast<u8>(channels);
|
||||
return mode.type == out.encoder && mode.channel == out.channels;
|
||||
});
|
||||
|
||||
if (it != out.sound_modes.cend())
|
||||
@ -398,7 +375,7 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
|
||||
else
|
||||
{
|
||||
cellSysutil.warning("cellAudioOutConfigure: Could not find an ideal sound mode for %d channel output. Keeping old mode: channels=%d, encoder=%d, fs=%d",
|
||||
static_cast<u32>(channels), out.sound_mode.channel, out.sound_mode.type, out.sound_mode.fs);
|
||||
config->channel, out.sound_mode.channel, out.sound_mode.type, out.sound_mode.fs);
|
||||
}
|
||||
|
||||
needs_reset = true;
|
||||
|
Loading…
Reference in New Issue
Block a user