mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 20:15:27 +00:00
Audio: downmix to stereo
This commit is contained in:
parent
4c741e93c3
commit
77aa3142a9
7 changed files with 52 additions and 28 deletions
|
@ -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<g_al_buffers_count; ++i)
|
||||
{
|
||||
alBufferData(m_buffers[i], g_cfg_audio_convert_to_u16 ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32, src, m_buffer_size, 48000);
|
||||
alBufferData(m_buffers[i], m_format, src, m_buffer_size, 48000);
|
||||
checkForAlError("alBufferData");
|
||||
}
|
||||
|
||||
|
@ -137,7 +147,7 @@ void OpenALThread::AddData(const void* src, int size)
|
|||
|
||||
int bsize = size < m_buffer_size ? size : m_buffer_size;
|
||||
|
||||
alBufferData(buffer, g_cfg_audio_convert_to_u16 ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32, bsrc, bsize, 48000);
|
||||
alBufferData(buffer, m_format, bsrc, bsize, 48000);
|
||||
checkForAlError("alBufferData");
|
||||
|
||||
alSourceQueueBuffers(m_source, 1, &buffer);
|
||||
|
|
|
@ -8,6 +8,7 @@ class OpenALThread : public AudioThread
|
|||
private:
|
||||
static const uint g_al_buffers_count = 24;
|
||||
|
||||
ALint m_format;
|
||||
ALuint m_source;
|
||||
ALuint m_buffers[g_al_buffers_count];
|
||||
ALsizei m_buffer_size;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <alsa/asoundlib.h>
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<void>& _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<float[]> 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<audio_config>() && !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();
|
||||
|
|
|
@ -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<combobox_pad>(cfg_location{ "Audio", "Renderer" }, cbox_audio_out));
|
||||
pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Audio", "Dump to file" }, chbox_audio_dump));
|
||||
pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Audio", "Convert to 16 bit" }, chbox_audio_conv));
|
||||
pads.emplace_back(std::make_unique<checkbox_pad>(cfg_location{ "Audio", "Downmix to Stereo" }, chbox_audio_dnmx));
|
||||
|
||||
pads.emplace_back(std::make_unique<combobox_pad>(cfg_location{ "Input/Output", "Pad" }, cbox_pad_handler));
|
||||
pads.emplace_back(std::make_unique<combobox_pad>(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());
|
||||
|
|
Loading…
Add table
Reference in a new issue