From 77aa3142a9095d26da3685c41004c2785a155c09 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 9 Apr 2017 23:43:53 +0300 Subject: [PATCH] Audio: downmix to stereo --- rpcs3/Emu/Audio/AL/OpenALThread.cpp | 14 ++++++-- rpcs3/Emu/Audio/AL/OpenALThread.h | 1 + rpcs3/Emu/Audio/ALSA/ALSAThread.cpp | 6 ++-- rpcs3/Emu/Audio/XAudio2/XAudio27Thread.cpp | 7 ++-- rpcs3/Emu/Audio/XAudio2/XAudio28Thread.cpp | 7 ++-- rpcs3/Emu/Cell/Modules/cellAudio.cpp | 42 ++++++++++++---------- rpcs3/Gui/SettingsDialog.cpp | 3 ++ 7 files changed, 52 insertions(+), 28 deletions(-) diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.cpp b/rpcs3/Emu/Audio/AL/OpenALThread.cpp index a81f612911..1f8056ed62 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALThread.cpp @@ -5,6 +5,7 @@ #include "OpenALThread.h" extern cfg::bool_entry g_cfg_audio_convert_to_u16; +extern cfg::bool_entry g_cfg_audio_downmix_to_2ch; #ifdef _MSC_VER #pragma comment(lib, "OpenAL32.lib") @@ -44,6 +45,15 @@ OpenALThread::OpenALThread() alcMakeContextCurrent(m_context); checkForAlcError("alcMakeContextCurrent"); + + if (g_cfg_audio_downmix_to_2ch) + { + m_format = g_cfg_audio_convert_to_u16 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32; + } + else + { + m_format = g_cfg_audio_convert_to_u16 ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32; + } } OpenALThread::~OpenALThread() @@ -102,7 +112,7 @@ void OpenALThread::Open(const void* src, int size) for (uint i = 0; i extern cfg::bool_entry g_cfg_audio_convert_to_u16; +extern cfg::bool_entry g_cfg_audio_downmix_to_2ch; thread_local static snd_pcm_t* s_tls_handle{nullptr}; @@ -59,7 +60,7 @@ ALSAThread::ALSAThread() if (!check(snd_pcm_hw_params_set_rate(s_tls_handle, hw_params, 48000, 0), "snd_pcm_hw_params_set_rate_near")) return; - if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, hw_params, 8), "snd_pcm_hw_params_set_channels")) + if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, hw_params, g_cfg_audio_downmix_to_2ch ? 2 : 8), "snd_pcm_hw_params_set_channels")) return; if (!check(snd_pcm_hw_params_set_buffer_size(s_tls_handle, hw_params, 64 * 256), "snd_pcm_hw_params_set_buffer_size")) @@ -105,7 +106,8 @@ void ALSAThread::Open(const void* src, int size) void ALSAThread::AddData(const void* src, int size) { - size /= g_cfg_audio_convert_to_u16 ? 2 * 8 : 4 * 8; + size /= g_cfg_audio_convert_to_u16 ? 2 : 4; + size /= g_cfg_audio_downmix_to_2ch ? 2 : 8; int res; diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio27Thread.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio27Thread.cpp index f020b6bd54..c14e0f4e2f 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio27Thread.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio27Thread.cpp @@ -9,6 +9,7 @@ #include "3rdparty/XAudio2_7/XAudio2.h" extern cfg::bool_entry g_cfg_audio_convert_to_u16; +extern cfg::bool_entry g_cfg_audio_downmix_to_2ch; static thread_local HMODULE s_tls_xaudio2_lib{}; static thread_local IXAudio2* s_tls_xaudio2_instance{}; @@ -37,7 +38,7 @@ void XAudio2Thread::xa27_init(void* lib2_7) return; } - hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, 8, 48000); + hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg_audio_downmix_to_2ch ? 2 : 8, 48000); if (FAILED(hr)) { LOG_ERROR(GENERAL, "XAudio2Thread : CreateMasteringVoice() failed(0x%08x)", (u32)hr); @@ -105,7 +106,7 @@ void XAudio2Thread::xa27_open() HRESULT hr; WORD sample_size = g_cfg_audio_convert_to_u16 ? sizeof(u16) : sizeof(float); - WORD channels = 8; + WORD channels = g_cfg_audio_downmix_to_2ch ? 2 : 8; WAVEFORMATEX waveformatex; waveformatex.wFormatTag = g_cfg_audio_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; @@ -124,7 +125,7 @@ void XAudio2Thread::xa27_open() return; } - s_tls_source_voice->SetVolume(4.0); + s_tls_source_voice->SetVolume(g_cfg_audio_downmix_to_2ch ? 1.0 : 4.0); } void XAudio2Thread::xa27_add(const void* src, int size) diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio28Thread.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio28Thread.cpp index 1869c3d81d..df50b1a967 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio28Thread.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio28Thread.cpp @@ -9,6 +9,7 @@ #include "3rdparty/minidx12/Include/xaudio2.h" extern cfg::bool_entry g_cfg_audio_convert_to_u16; +extern cfg::bool_entry g_cfg_audio_downmix_to_2ch; static thread_local HMODULE s_tls_xaudio2_lib{}; static thread_local IXAudio2* s_tls_xaudio2_instance{}; @@ -39,7 +40,7 @@ void XAudio2Thread::xa28_init(void* lib) return; } - hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, 8, 48000); + hr = s_tls_xaudio2_instance->CreateMasteringVoice(&s_tls_master_voice, g_cfg_audio_downmix_to_2ch ? 2 : 8, 48000); if (FAILED(hr)) { LOG_ERROR(GENERAL, "XAudio2Thread : CreateMasteringVoice() failed(0x%08x)", (u32)hr); @@ -107,7 +108,7 @@ void XAudio2Thread::xa28_open() HRESULT hr; WORD sample_size = g_cfg_audio_convert_to_u16 ? sizeof(u16) : sizeof(float); - WORD channels = 8; + WORD channels = g_cfg_audio_downmix_to_2ch ? 2 : 8; WAVEFORMATEX waveformatex; waveformatex.wFormatTag = g_cfg_audio_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; @@ -126,7 +127,7 @@ void XAudio2Thread::xa28_open() return; } - s_tls_source_voice->SetVolume(4.0); + s_tls_source_voice->SetVolume(g_cfg_audio_downmix_to_2ch ? 1.0 : 4.0); } void XAudio2Thread::xa28_add(const void* src, int size) diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp index d23dbd6186..d10be53b98 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudio.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -15,6 +15,7 @@ logs::channel cellAudio("cellAudio", logs::level::notice); cfg::bool_entry g_cfg_audio_dump_to_file(cfg::root.audio, "Dump to file"); cfg::bool_entry g_cfg_audio_convert_to_u16(cfg::root.audio, "Convert to 16 bit"); +cfg::bool_entry g_cfg_audio_downmix_to_2ch(cfg::root.audio, "Downmix to Stereo", true); void audio_config::on_init(const std::shared_ptr& _this) { @@ -38,17 +39,17 @@ void audio_config::on_task() float buf2ch[2 * BUFFER_SIZE]{}; // intermediate buffer for 2 channels float buf8ch[8 * BUFFER_SIZE]{}; // intermediate buffer for 8 channels - static const size_t out_buffer_size = 8 * BUFFER_SIZE; // output buffer for 8 channels + const u32 buf_sz = BUFFER_SIZE * (g_cfg_audio_convert_to_u16 ? 2 : 4) * (g_cfg_audio_downmix_to_2ch ? 2 : 8); std::unique_ptr out_buffer[BUFFER_NUM]; for (u32 i = 0; i < BUFFER_NUM; i++) { - out_buffer[i].reset(new float[out_buffer_size] {}); + out_buffer[i].reset(new float[8 * BUFFER_SIZE] {}); } const auto audio = Emu.GetCallbacks().get_audio(); - audio->Open(buf8ch, out_buffer_size * (g_cfg_audio_convert_to_u16 ? 2 : 4)); + audio->Open(buf8ch, buf_sz); while (fxm::check() && !Emu.IsStopped()) { @@ -225,16 +226,20 @@ void audio_config::on_task() if (!first_mix) { - // copy output data (2 ch) - //for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) - //{ - // out_buffer[out_pos][i] = buf2ch[i]; - //} - - // copy output data (8 ch) - for (u32 i = 0; i < (sizeof(buf8ch) / sizeof(float)); i++) + // Copy output data (2ch or 8ch) + if (g_cfg_audio_downmix_to_2ch) { - out_buffer[out_pos][i] = buf8ch[i]; + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + { + out_buffer[out_pos][i] = buf2ch[i]; + } + } + else + { + for (u32 i = 0; i < (sizeof(buf8ch) / sizeof(float)); i++) + { + out_buffer[out_pos][i] = buf8ch[i]; + } } } @@ -242,7 +247,7 @@ void audio_config::on_task() if (first_mix) { - memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); + std::memset(out_buffer[out_pos].get(), 0, 8 * BUFFER_SIZE * sizeof(float)); } if (g_cfg_audio_convert_to_u16) @@ -254,20 +259,21 @@ void audio_config::on_task() // 2x CVTPS2DQ (converts float to s32) // PACKSSDW (converts s32 to s16 with signed saturation) - u16 buf_u16[out_buffer_size]; - for (size_t i = 0; i < out_buffer_size; i += 8) + __m128i buf_u16[BUFFER_SIZE]; + + for (size_t i = 0; i < 8 * BUFFER_SIZE; i += 8) { const auto scale = _mm_set1_ps(0x8000); - (__m128i&)(buf_u16[i]) = _mm_packs_epi32( + buf_u16[i / 8] = _mm_packs_epi32( _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(out_buffer[out_pos].get() + i), scale)), _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(out_buffer[out_pos].get() + i + 4), scale))); } - audio->AddData(buf_u16, out_buffer_size * sizeof(u16)); + audio->AddData(buf_u16, buf_sz); } else { - audio->AddData(out_buffer[out_pos].get(), out_buffer_size * sizeof(float)); + audio->AddData(out_buffer[out_pos].get(), buf_sz); } const u64 stamp2 = get_system_time(); diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index b17962534e..6283068fee 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -325,6 +325,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent, const std::string& path) wxCheckBox* chbox_gs_gpu_texture_scaling = new wxCheckBox(p_graphics, wxID_ANY, "Use GPU texture scaling"); wxCheckBox* chbox_audio_dump = new wxCheckBox(p_audio, wxID_ANY, "Dump to file"); wxCheckBox* chbox_audio_conv = new wxCheckBox(p_audio, wxID_ANY, "Convert to 16 bit"); + wxCheckBox* chbox_audio_dnmx = new wxCheckBox(p_audio, wxID_ANY, "Downmix to Stereo"); wxCheckBox* chbox_hle_exitonstop = new wxCheckBox(p_misc, wxID_ANY, "Exit RPCS3 when process finishes"); wxCheckBox* chbox_hle_always_start = new wxCheckBox(p_misc, wxID_ANY, "Always start after boot"); wxCheckBox* chbox_dbg_ap_systemcall = new wxCheckBox(p_misc, wxID_ANY, "Auto Pause at System Call"); @@ -405,6 +406,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent, const std::string& path) pads.emplace_back(std::make_unique(cfg_location{ "Audio", "Renderer" }, cbox_audio_out)); pads.emplace_back(std::make_unique(cfg_location{ "Audio", "Dump to file" }, chbox_audio_dump)); pads.emplace_back(std::make_unique(cfg_location{ "Audio", "Convert to 16 bit" }, chbox_audio_conv)); + pads.emplace_back(std::make_unique(cfg_location{ "Audio", "Downmix to Stereo" }, chbox_audio_dnmx)); pads.emplace_back(std::make_unique(cfg_location{ "Input/Output", "Pad" }, cbox_pad_handler)); pads.emplace_back(std::make_unique(cfg_location{ "Input/Output", "Keyboard" }, cbox_keyboard_handler)); @@ -514,6 +516,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent, const std::string& path) s_subpanel_audio->Add(s_round_audio_out, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_audio->Add(chbox_audio_dump, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_audio->Add(chbox_audio_conv, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_audio->Add(chbox_audio_dnmx, wxSizerFlags().Border(wxALL, 5).Expand()); // Miscellaneous s_subpanel_misc->Add(chbox_hle_exitonstop, wxSizerFlags().Border(wxALL, 5).Expand());