mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-12 04:14:35 +00:00
Try to make most audio configs dynamic
This commit is contained in:
parent
8ee953ef8e
commit
20d6664dc1
@ -12,8 +12,7 @@ LOG_CHANNEL(OpenAL);
|
||||
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
|
||||
|
||||
OpenALBackend::OpenALBackend()
|
||||
: m_sampling_rate(get_sampling_rate())
|
||||
, m_sample_size(get_sample_size())
|
||||
: AudioBackend()
|
||||
{
|
||||
ALCdevice* m_device = alcOpenDevice(nullptr);
|
||||
checkForAlcError("alcOpenDevice");
|
||||
@ -24,9 +23,7 @@ OpenALBackend::OpenALBackend()
|
||||
alcMakeContextCurrent(m_context);
|
||||
checkForAlcError("alcMakeContextCurrent");
|
||||
|
||||
const auto channels = get_channels();
|
||||
|
||||
switch (channels)
|
||||
switch (m_channels)
|
||||
{
|
||||
case 2:
|
||||
m_format = (m_sample_size == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32;
|
||||
|
@ -15,9 +15,6 @@ private:
|
||||
u32 m_next_buffer = 0;
|
||||
u32 m_num_unqueued = 0;
|
||||
|
||||
const u32 m_sampling_rate;
|
||||
const u32 m_sample_size;
|
||||
|
||||
void unqueue_processed();
|
||||
|
||||
public:
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_ALSA
|
||||
#ifndef HAVE_ALSA
|
||||
#error "ALSA support disabled but still being built."
|
||||
#endif
|
||||
|
||||
@ -26,6 +26,7 @@ static bool check(int err, const char* reason)
|
||||
}
|
||||
|
||||
ALSABackend::ALSABackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
}
|
||||
|
||||
@ -51,14 +52,14 @@ void ALSABackend::Open(u32 num_buffers)
|
||||
if (!check(snd_pcm_hw_params_set_access(tls_handle, tls_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_format(tls_handle, tls_hw_params, g_cfg.audio.convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
|
||||
if (!check(snd_pcm_hw_params_set_format(tls_handle, tls_hw_params, m_convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
|
||||
return;
|
||||
|
||||
uint rate = get_sampling_rate();
|
||||
uint rate = m_sampling_rate;
|
||||
if (!check(snd_pcm_hw_params_set_rate_near(tls_handle, tls_hw_params, &rate, nullptr), "snd_pcm_hw_params_set_rate_near"))
|
||||
return;
|
||||
|
||||
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, get_channels()), "snd_pcm_hw_params_set_channels"))
|
||||
if (!check(snd_pcm_hw_params_set_channels(tls_handle, tls_hw_params, m_channels), "snd_pcm_hw_params_set_channels"))
|
||||
return;
|
||||
|
||||
//uint period = 5333;
|
||||
@ -92,7 +93,7 @@ void ALSABackend::Open(u32 num_buffers)
|
||||
if (!check(snd_pcm_sw_params_current(tls_handle, tls_sw_params), "snd_pcm_sw_params_current"))
|
||||
return;
|
||||
|
||||
period_frames *= g_cfg.audio.startt;
|
||||
period_frames *= m_start_threshold;
|
||||
|
||||
if (!check(snd_pcm_sw_params_set_start_threshold(tls_handle, tls_sw_params, period_frames + 1), "snd_pcm_sw_params_set_start_threshold"))
|
||||
return;
|
||||
@ -132,7 +133,7 @@ void ALSABackend::Close()
|
||||
|
||||
bool ALSABackend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
u32 num_frames = num_samples / get_channels();
|
||||
u32 num_frames = num_samples / m_channels;
|
||||
|
||||
int res = snd_pcm_writei(tls_handle, src, num_frames);
|
||||
|
||||
|
@ -2,45 +2,69 @@
|
||||
#include "AudioBackend.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
u32 AudioBackend::get_sampling_rate()
|
||||
AudioBackend::AudioBackend()
|
||||
{
|
||||
m_convert_to_u16 = static_cast<bool>(g_cfg.audio.convert_to_u16);
|
||||
m_sample_size = m_convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||
m_start_threshold = g_cfg.audio.start_threshold;
|
||||
|
||||
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
|
||||
|
||||
if (sampling_period_multiplier_u32 == 100)
|
||||
return DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
{
|
||||
m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||
m_sampling_rate = static_cast<u32>(f32{ DEFAULT_AUDIO_SAMPLING_RATE } *sampling_rate_multiplier);
|
||||
}
|
||||
|
||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||
return static_cast<u32>(f32{DEFAULT_AUDIO_SAMPLING_RATE} * sampling_rate_multiplier);
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_sample_size()
|
||||
{
|
||||
return g_cfg.audio.convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_channels()
|
||||
{
|
||||
const audio_channels channels = g_cfg.audio.audio_channel_downmix.get();
|
||||
|
||||
switch (channels)
|
||||
{
|
||||
case audio_channels::use_application_settings:
|
||||
return 2; // TODO
|
||||
m_channels = 2; // TODO
|
||||
break;
|
||||
case audio_channels::downmix_to_stereo:
|
||||
return 2;
|
||||
m_channels = 2;
|
||||
break;
|
||||
case audio_channels::downmix_to_5_1:
|
||||
return 6;
|
||||
m_channels = 6;
|
||||
break;
|
||||
case audio_channels::surround_7_1:
|
||||
return 8;
|
||||
m_channels = 8;
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Unknown audio channel mode %s (%d)", channels, static_cast<int>(channels));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
u32 AudioBackend::get_sampling_rate() const
|
||||
{
|
||||
return m_sampling_rate;
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_sample_size() const
|
||||
{
|
||||
return m_sample_size;
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_channels() const
|
||||
{
|
||||
return m_channels;
|
||||
}
|
||||
|
||||
bool AudioBackend::get_convert_to_u16() const
|
||||
{
|
||||
return m_convert_to_u16;
|
||||
}
|
||||
|
||||
bool AudioBackend::has_capability(u32 cap) const
|
||||
{
|
||||
return (cap & GetCapabilities()) == cap;
|
||||
|
@ -20,6 +20,8 @@ public:
|
||||
SET_FREQUENCY_RATIO = 0x8, // Implements SetFrequencyRatio
|
||||
};
|
||||
|
||||
AudioBackend();
|
||||
|
||||
virtual ~AudioBackend() = default;
|
||||
|
||||
/*
|
||||
@ -94,13 +96,22 @@ public:
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
static u32 get_sampling_rate();
|
||||
u32 get_sampling_rate() const;
|
||||
|
||||
static u32 get_sample_size();
|
||||
u32 get_sample_size() const;
|
||||
|
||||
static u32 get_channels();
|
||||
u32 get_channels() const;
|
||||
|
||||
bool get_convert_to_u16() const;
|
||||
|
||||
bool has_capability(u32 cap) const;
|
||||
|
||||
void dump_capabilities(std::string& out) const;
|
||||
|
||||
protected:
|
||||
bool m_convert_to_u16 = false;
|
||||
u32 m_sample_size = sizeof(float);
|
||||
u32 m_sampling_rate = DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
u32 m_channels = 0;
|
||||
u32 m_start_threshold = 1;
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_FAUDIO
|
||||
#ifndef HAVE_FAUDIO
|
||||
#error "FAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
LOG_CHANNEL(FAudio_, "FAudio");
|
||||
|
||||
FAudioBackend::FAudioBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
u32 res;
|
||||
|
||||
@ -20,7 +21,7 @@ FAudioBackend::FAudioBackend()
|
||||
return;
|
||||
}
|
||||
|
||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000, 0, 0, nullptr);
|
||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, m_channels, 48000, 0, 0, nullptr);
|
||||
if (res)
|
||||
{
|
||||
FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||
@ -102,17 +103,13 @@ void FAudioBackend::Close()
|
||||
|
||||
void FAudioBackend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
FAudioWaveFormatEx waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.wFormatTag = m_convert_to_u16 ? FAUDIO_FORMAT_PCM : FAUDIO_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = m_channels;
|
||||
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<u32>(m_sampling_rate * m_channels * m_sample_size);
|
||||
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
|
||||
@ -140,7 +137,7 @@ bool FAudioBackend::AddData(const void* src, u32 num_samples)
|
||||
}
|
||||
|
||||
FAudioBuffer buffer;
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.AudioBytes = num_samples * m_sample_size;
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = FAUDIO_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef HAVE_PULSE
|
||||
#ifndef HAVE_PULSE
|
||||
#error "PulseAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <pulse/error.h>
|
||||
|
||||
PulseBackend::PulseBackend()
|
||||
: AudioBackend()
|
||||
{
|
||||
}
|
||||
|
||||
@ -19,7 +20,8 @@ PulseBackend::~PulseBackend()
|
||||
|
||||
void PulseBackend::Close()
|
||||
{
|
||||
if(this->connection) {
|
||||
if (this->connection)
|
||||
{
|
||||
pa_simple_free(this->connection);
|
||||
this->connection = nullptr;
|
||||
}
|
||||
@ -28,20 +30,30 @@ void PulseBackend::Close()
|
||||
void PulseBackend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
pa_sample_spec ss;
|
||||
ss.format = (get_sample_size() == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
||||
ss.rate = get_sampling_rate();
|
||||
ss.format = (m_sample_size == 2) ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
||||
ss.rate = m_sampling_rate;
|
||||
|
||||
pa_channel_map channel_map;
|
||||
|
||||
if (get_channels() == 2)
|
||||
if (m_channels == 2)
|
||||
{
|
||||
channel_map.channels = 2;
|
||||
channel_map.channels = 2;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
}
|
||||
else if (m_channels == 6)
|
||||
{
|
||||
channel_map.channels = 6;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||
channel_map.map[3] = PA_CHANNEL_POSITION_LFE;
|
||||
channel_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
|
||||
channel_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_map.channels = 8;
|
||||
channel_map.channels = 8;
|
||||
channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
|
||||
channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
|
||||
channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
|
||||
@ -55,7 +67,8 @@ void PulseBackend::Open(u32 /* num_buffers */)
|
||||
|
||||
int err;
|
||||
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, &channel_map, NULL, &err);
|
||||
if(!this->connection) {
|
||||
if (!this->connection)
|
||||
{
|
||||
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
|
||||
}
|
||||
}
|
||||
@ -65,10 +78,11 @@ bool PulseBackend::AddData(const void* src, u32 num_samples)
|
||||
AUDIT(this->connection);
|
||||
|
||||
int err;
|
||||
if(pa_simple_write(this->connection, src, num_samples * get_sample_size(), &err) < 0) {
|
||||
if (pa_simple_write(this->connection, src, num_samples * m_sample_size, &err) < 0)
|
||||
{
|
||||
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
LOG_CHANNEL(XAudio);
|
||||
|
||||
XAudio2Backend::XAudio2Backend()
|
||||
: AudioBackend()
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IXAudio2> instance;
|
||||
|
||||
@ -30,7 +31,7 @@ XAudio2Backend::XAudio2Backend()
|
||||
return;
|
||||
}
|
||||
|
||||
hr = instance->CreateMasteringVoice(&m_master_voice, get_channels(), 48000);
|
||||
hr = instance->CreateMasteringVoice(&m_master_voice, m_channels, 48000);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("CreateMasteringVoice() failed: %s (0x%08x)", std::system_category().message(hr), static_cast<u32>(hr));
|
||||
@ -94,17 +95,13 @@ void XAudio2Backend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
WAVEFORMATEX waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.wFormatTag = m_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = m_channels;
|
||||
waveformatex.nSamplesPerSec = m_sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(m_sampling_rate * m_channels * m_sample_size);
|
||||
waveformatex.nBlockAlign = m_channels * m_sample_size;
|
||||
waveformatex.wBitsPerSample = m_sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
@ -144,7 +141,7 @@ bool XAudio2Backend::AddData(const void* src, u32 num_samples)
|
||||
|
||||
XAUDIO2_BUFFER buffer;
|
||||
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.AudioBytes = num_samples * m_sample_size;
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
|
@ -44,6 +44,43 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
|
||||
|
||||
cell_audio_config::cell_audio_config()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void cell_audio_config::reset()
|
||||
{
|
||||
backend.reset();
|
||||
backend = Emu.GetCallbacks().get_audio();
|
||||
|
||||
audio_channels = backend->get_channels();
|
||||
audio_sampling_rate = backend->get_sampling_rate();
|
||||
audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
|
||||
|
||||
audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
|
||||
audio_buffer_size = audio_buffer_length * backend->get_sample_size();
|
||||
|
||||
desired_buffer_duration = g_cfg.audio.desired_buffer_duration * 1000llu;
|
||||
|
||||
const bool raw_buffering_enabled = static_cast<bool>(g_cfg.audio.enable_buffering);
|
||||
|
||||
buffering_enabled = raw_buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING);;
|
||||
|
||||
minimum_block_period = audio_block_period / 2;
|
||||
maximum_block_period = (6 * audio_block_period) / 5;
|
||||
|
||||
desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 3 : 2;
|
||||
num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS;
|
||||
|
||||
fully_untouched_timeout = static_cast<u64>(audio_block_period) * 2;
|
||||
partially_untouched_timeout = static_cast<u64>(audio_block_period) * 4;
|
||||
|
||||
const s64 raw_time_stretching_threshold = g_cfg.audio.time_stretching_threshold;
|
||||
const bool raw_time_stretching_enabled = buffering_enabled && g_cfg.audio.enable_time_stretching && (raw_time_stretching_threshold > 0);
|
||||
|
||||
time_stretching_enabled = raw_time_stretching_enabled && backend->has_capability(AudioBackend::SET_FREQUENCY_RATIO);
|
||||
|
||||
time_stretching_threshold = raw_time_stretching_threshold / 100.0f;
|
||||
|
||||
// Warn if audio backend does not support all requested features
|
||||
if (raw_buffering_enabled && !buffering_enabled)
|
||||
{
|
||||
@ -500,6 +537,31 @@ void cell_audio_thread::advance(u64 timestamp, bool reset)
|
||||
}
|
||||
}
|
||||
|
||||
namespace audio
|
||||
{
|
||||
void configure_audio()
|
||||
{
|
||||
if (const auto g_audio = g_fxo->get<cell_audio>())
|
||||
{
|
||||
g_audio->m_update_configuration = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cell_audio_thread::update_config()
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
// Clear ringbuffer
|
||||
ringbuffer.reset();
|
||||
|
||||
// Reload config
|
||||
cfg.reset();
|
||||
|
||||
// Allocate ringbuffer
|
||||
ringbuffer.reset(new audio_ringbuffer(cfg));
|
||||
}
|
||||
|
||||
void cell_audio_thread::operator()()
|
||||
{
|
||||
thread_ctrl::set_native_priority(1);
|
||||
@ -519,6 +581,12 @@ void cell_audio_thread::operator()()
|
||||
// Main cellAudio loop
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
if (m_update_configuration)
|
||||
{
|
||||
update_config();
|
||||
m_update_configuration = false;
|
||||
}
|
||||
|
||||
const u64 timestamp = ringbuffer->update();
|
||||
|
||||
if (Emu.IsPaused())
|
||||
@ -959,7 +1027,7 @@ void cell_audio_thread::mix(float *out_buffer, s32 offset)
|
||||
{
|
||||
std::memset(out_buffer, 0, out_buffer_sz * sizeof(float));
|
||||
}
|
||||
else if (g_cfg.audio.convert_to_u16)
|
||||
else if (cfg.backend->get_convert_to_u16())
|
||||
{
|
||||
// convert the data from float to u16 with clipping:
|
||||
// 2x MULPS
|
||||
|
@ -187,49 +187,46 @@ struct audio_port
|
||||
|
||||
struct cell_audio_config
|
||||
{
|
||||
const std::shared_ptr<AudioBackend> backend = Emu.GetCallbacks().get_audio();
|
||||
std::shared_ptr<AudioBackend> backend = nullptr;
|
||||
|
||||
const u32 audio_channels = AudioBackend::get_channels();
|
||||
const u32 audio_sampling_rate = AudioBackend::get_sampling_rate();
|
||||
const u32 audio_block_period = AUDIO_BUFFER_SAMPLES * 1000000 / audio_sampling_rate;
|
||||
u32 audio_channels = 0;
|
||||
u32 audio_sampling_rate = 0;
|
||||
u32 audio_block_period = 0;
|
||||
|
||||
const u32 audio_buffer_length = AUDIO_BUFFER_SAMPLES * audio_channels;
|
||||
const u32 audio_buffer_size = audio_buffer_length * AudioBackend::get_sample_size();
|
||||
u32 audio_buffer_length = 0;
|
||||
u32 audio_buffer_size = 0;
|
||||
|
||||
/*
|
||||
* Buffering
|
||||
*/
|
||||
const u64 desired_buffer_duration = g_cfg.audio.desired_buffer_duration * 1000llu;
|
||||
private:
|
||||
const bool raw_buffering_enabled = static_cast<bool>(g_cfg.audio.enable_buffering);
|
||||
public:
|
||||
|
||||
u64 desired_buffer_duration = 0;
|
||||
|
||||
// We need a non-blocking backend (implementing play/pause/flush) to be able to do buffering correctly
|
||||
// We also need to be able to query the current playing state
|
||||
const bool buffering_enabled = raw_buffering_enabled && backend->has_capability(AudioBackend::PLAY_PAUSE_FLUSH | AudioBackend::IS_PLAYING);
|
||||
bool buffering_enabled = false;
|
||||
|
||||
const u64 minimum_block_period = audio_block_period / 2; // the block period will not be dynamically lowered below this value (usecs)
|
||||
const u64 maximum_block_period = (6 * audio_block_period) / 5; // the block period will not be dynamically increased above this value (usecs)
|
||||
u64 minimum_block_period = 0; // the block period will not be dynamically lowered below this value (usecs)
|
||||
u64 maximum_block_period = 0; // the block period will not be dynamically increased above this value (usecs)
|
||||
|
||||
const u32 desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 3 : 2;
|
||||
const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers
|
||||
u32 desired_full_buffers = 0;
|
||||
u32 num_allocated_buffers = 0; // number of ringbuffer buffers
|
||||
|
||||
const f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average
|
||||
|
||||
const s64 period_comparison_margin = 250; // when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer
|
||||
|
||||
const u64 fully_untouched_timeout = 2 * audio_block_period; // timeout if the game has not touched any audio buffer yet
|
||||
const u64 partially_untouched_timeout = 4 * audio_block_period; // timeout if the game has not touched all audio buffers yet
|
||||
u64 fully_untouched_timeout = 0; // timeout if the game has not touched any audio buffer yet
|
||||
u64 partially_untouched_timeout = 0; // timeout if the game has not touched all audio buffers yet
|
||||
|
||||
/*
|
||||
* Time Stretching
|
||||
*/
|
||||
private:
|
||||
const bool raw_time_stretching_enabled = buffering_enabled && g_cfg.audio.enable_time_stretching && (g_cfg.audio.time_stretching_threshold > 0);
|
||||
public:
|
||||
// We need to be able to set a dynamic frequency ratio to be able to do time stretching
|
||||
const bool time_stretching_enabled = raw_time_stretching_enabled && backend->has_capability(AudioBackend::SET_FREQUENCY_RATIO);
|
||||
|
||||
const f32 time_stretching_threshold = g_cfg.audio.time_stretching_threshold / 100.0f; // we only apply time stretching below this buffer fill rate (adjusted for average period)
|
||||
// We need to be able to set a dynamic frequency ratio to be able to do time stretching
|
||||
bool time_stretching_enabled = false;
|
||||
|
||||
f32 time_stretching_threshold = 0.0f; // we only apply time stretching below this buffer fill rate (adjusted for average period)
|
||||
const f32 time_stretching_step = 0.1f; // will only reduce/increase the frequency ratio in steps of at least this value
|
||||
const f32 time_stretching_scale = 0.9f;
|
||||
|
||||
@ -237,6 +234,11 @@ public:
|
||||
* Constructor
|
||||
*/
|
||||
cell_audio_config();
|
||||
|
||||
/*
|
||||
* Config changes
|
||||
*/
|
||||
void reset();
|
||||
};
|
||||
|
||||
class audio_ringbuffer
|
||||
@ -337,6 +339,7 @@ public:
|
||||
|
||||
class cell_audio_thread
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<audio_ringbuffer> ringbuffer;
|
||||
|
||||
void reset_ports(s32 offset = 0);
|
||||
@ -351,8 +354,11 @@ class cell_audio_thread
|
||||
return (time_left > 350) ? time_left - 250 : 100;
|
||||
}
|
||||
|
||||
void update_config();
|
||||
|
||||
public:
|
||||
cell_audio_config cfg;
|
||||
atomic_t<bool> m_update_configuration = false;
|
||||
|
||||
shared_mutex mutex;
|
||||
atomic_t<u32> init = 0;
|
||||
@ -375,7 +381,7 @@ public:
|
||||
u64 m_counter = 0;
|
||||
u64 m_start_time = 0;
|
||||
u64 m_dynamic_period = 0;
|
||||
f32 m_average_playtime;
|
||||
f32 m_average_playtime = 0.0f;
|
||||
|
||||
void operator()();
|
||||
|
||||
@ -405,3 +411,8 @@ public:
|
||||
};
|
||||
|
||||
using cell_audio = named_thread<cell_audio_thread>;
|
||||
|
||||
namespace audio
|
||||
{
|
||||
void configure_audio();
|
||||
}
|
||||
|
@ -208,23 +208,23 @@ struct cfg_root : cfg::node
|
||||
|
||||
cfg::_enum<audio_renderer> renderer{ this, "Renderer",
|
||||
#ifdef _WIN32
|
||||
audio_renderer::xaudio };
|
||||
audio_renderer::xaudio, true };
|
||||
#elif HAVE_FAUDIO
|
||||
audio_renderer::faudio };
|
||||
audio_renderer::faudio, true };
|
||||
#else
|
||||
audio_renderer::openal };
|
||||
audio_renderer::openal, true };
|
||||
#endif
|
||||
|
||||
cfg::_bool dump_to_file{ this, "Dump to file" };
|
||||
cfg::_bool convert_to_u16{ this, "Convert to 16 bit" };
|
||||
cfg::_enum<audio_channels> audio_channel_downmix{ this, "Audio Channels", audio_channels::downmix_to_stereo };
|
||||
cfg::_int<1, 128> startt{ this, "Start Threshold", 1 }; // TODO: used only by ALSA, should probably be removed once ALSA is upgraded
|
||||
cfg::_bool convert_to_u16{ this, "Convert to 16 bit", false, true };
|
||||
cfg::_enum<audio_channels> audio_channel_downmix{ this, "Audio Channels", audio_channels::downmix_to_stereo, true };
|
||||
cfg::_int<1, 128> start_threshold{ this, "Start Threshold", 1, true }; // TODO: used only by ALSA, should probably be removed once ALSA is upgraded
|
||||
cfg::_int<0, 200> volume{ this, "Master Volume", 100, true };
|
||||
cfg::_bool enable_buffering{ this, "Enable Buffering", true };
|
||||
cfg::_int <4, 250> desired_buffer_duration{ this, "Desired Audio Buffer Duration", 100 };
|
||||
cfg::_int<1, 1000> sampling_period_multiplier{ this, "Sampling Period Multiplier", 100 };
|
||||
cfg::_bool enable_time_stretching{ this, "Enable Time Stretching", false };
|
||||
cfg::_int<0, 100> time_stretching_threshold{ this, "Time Stretching Threshold", 75 };
|
||||
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<1, 1000> sampling_period_multiplier{ this, "Sampling Period Multiplier", 100, true };
|
||||
cfg::_bool enable_time_stretching{ this, "Enable Time Stretching", false, true };
|
||||
cfg::_int<0, 100> time_stretching_threshold{ this, "Time Stretching Threshold", 75, true };
|
||||
cfg::_enum<microphone_handler> microphone_type{ this, "Microphone Type", microphone_handler::null };
|
||||
cfg::string microphone_devices{ this, "Microphone Devices", ";;;;" };
|
||||
} audio{ this };
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "_discord_utils.h"
|
||||
#endif
|
||||
|
||||
#include "Emu/Cell/Modules/cellAudio.h"
|
||||
#include "Emu/RSX/Overlays/overlay_perf_metrics.h"
|
||||
#include "trophy_notification_helper.h"
|
||||
#include "save_data_dialog.h"
|
||||
@ -474,6 +475,7 @@ void gui_application::OnEmuSettingsChange()
|
||||
}
|
||||
|
||||
Emu.ConfigureLogs();
|
||||
audio::configure_audio();
|
||||
rsx::overlays::reset_performance_overlay();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user