mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 22:05:38 +00:00
AudioStream: Make speed changes less poppy
This commit is contained in:
parent
f6ff7e48c1
commit
be5b979713
|
@ -2199,10 +2199,6 @@ void System::UpdateSpeedLimiterState()
|
||||||
|
|
||||||
if (IsValid())
|
if (IsValid())
|
||||||
{
|
{
|
||||||
s_target_speed = target_speed;
|
|
||||||
UpdateThrottlePeriod();
|
|
||||||
ResetThrottler();
|
|
||||||
|
|
||||||
AudioStream* stream = g_spu.GetOutputStream();
|
AudioStream* stream = g_spu.GetOutputStream();
|
||||||
if (g_settings.audio_fast_forward_volume != g_settings.audio_output_volume)
|
if (g_settings.audio_fast_forward_volume != g_settings.audio_output_volume)
|
||||||
stream->SetOutputVolume(GetAudioOutputVolume());
|
stream->SetOutputVolume(GetAudioOutputVolume());
|
||||||
|
@ -2211,10 +2207,16 @@ void System::UpdateSpeedLimiterState()
|
||||||
const bool rate_adjust =
|
const bool rate_adjust =
|
||||||
(syncing_to_host || g_settings.audio_stretch_mode == AudioStretchMode::Resample) && target_speed > 0.0f;
|
(syncing_to_host || g_settings.audio_stretch_mode == AudioStretchMode::Resample) && target_speed > 0.0f;
|
||||||
stream->SetNominalRate(rate_adjust ? target_speed : 1.0f);
|
stream->SetNominalRate(rate_adjust ? target_speed : 1.0f);
|
||||||
|
if (s_target_speed < target_speed)
|
||||||
|
stream->UpdateTargetTempo(target_speed);
|
||||||
|
|
||||||
// stream->SetSync(audio_sync_enabled);
|
// stream->SetSync(audio_sync_enabled);
|
||||||
// if (audio_sync_enabled)
|
// if (audio_sync_enabled)
|
||||||
// stream->EmptyBuffer();
|
// stream->EmptyBuffer();
|
||||||
|
|
||||||
|
s_target_speed = target_speed;
|
||||||
|
UpdateThrottlePeriod();
|
||||||
|
ResetThrottler();
|
||||||
}
|
}
|
||||||
|
|
||||||
g_host_display->SetDisplayMaxFPS(max_display_fps);
|
g_host_display->SetDisplayMaxFPS(max_display_fps);
|
||||||
|
|
|
@ -8,7 +8,12 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
Log_SetChannel(AudioStream);
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <stdlib.h> // alloca
|
||||||
|
#else
|
||||||
|
#include <malloc.h> // alloca
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_M_ARM64)
|
#if defined(_M_ARM64)
|
||||||
#include <arm64_neon.h>
|
#include <arm64_neon.h>
|
||||||
|
@ -18,6 +23,8 @@ Log_SetChannel(AudioStream);
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Log_SetChannel(AudioStream);
|
||||||
|
|
||||||
static constexpr bool LOG_TIMESTRETCH_STATS = false;
|
static constexpr bool LOG_TIMESTRETCH_STATS = false;
|
||||||
|
|
||||||
AudioStream::AudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch)
|
AudioStream::AudioStream(u32 sample_rate, u32 channels, u32 buffer_ms, AudioStretchMode stretch)
|
||||||
|
@ -136,9 +143,39 @@ void AudioStream::ReadFrames(s16* bData, u32 nFrames)
|
||||||
m_rpos.store(rpos, std::memory_order_release);
|
m_rpos.store(rpos, std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Bring back the crappy resampler?
|
|
||||||
if (silence_frames > 0)
|
if (silence_frames > 0)
|
||||||
std::memset(bData + frames_to_read, 0, sizeof(s32) * silence_frames);
|
{
|
||||||
|
if (frames_to_read > 0)
|
||||||
|
{
|
||||||
|
// super basic resampler - spread the input samples evenly across the output samples. will sound like ass and have
|
||||||
|
// aliasing, but better than popping by inserting silence.
|
||||||
|
const u32 increment =
|
||||||
|
static_cast<u32>(65536.0f * (static_cast<float>(frames_to_read / m_channels) / static_cast<float>(nFrames)));
|
||||||
|
|
||||||
|
s16* resample_ptr = static_cast<s16*>(alloca(sizeof(s16) * frames_to_read));
|
||||||
|
std::memcpy(resample_ptr, bData, sizeof(s16) * frames_to_read);
|
||||||
|
|
||||||
|
s16* out_ptr = bData;
|
||||||
|
const u32 copy_stride = sizeof(SampleType) * m_channels;
|
||||||
|
u32 resample_subpos = 0;
|
||||||
|
for (u32 i = 0; i < nFrames; i++)
|
||||||
|
{
|
||||||
|
std::memcpy(out_ptr, resample_ptr, copy_stride);
|
||||||
|
out_ptr += m_channels;
|
||||||
|
|
||||||
|
resample_subpos += increment;
|
||||||
|
resample_ptr += (resample_subpos >> 16) * m_channels;
|
||||||
|
resample_subpos %= 65536u;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log_VerbosePrintf("Audio buffer underflow, resampled %u frames to %u", frames_to_read, nFrames);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no data, fall back to silence
|
||||||
|
std::memset(bData + frames_to_read, 0, sizeof(s32) * silence_frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::InternalWriteFrames(s32* bData, u32 nSamples)
|
void AudioStream::InternalWriteFrames(s32* bData, u32 nSamples)
|
||||||
|
@ -228,6 +265,22 @@ void AudioStream::SetNominalRate(float tempo)
|
||||||
m_soundtouch->setRate(tempo);
|
m_soundtouch->setRate(tempo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioStream::UpdateTargetTempo(float tempo)
|
||||||
|
{
|
||||||
|
if (m_stretch_mode != AudioStretchMode::TimeStretch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// undo sqrt()
|
||||||
|
if (tempo)
|
||||||
|
tempo *= tempo;
|
||||||
|
|
||||||
|
m_average_position = AVERAGING_WINDOW;
|
||||||
|
m_average_available = AVERAGING_WINDOW;
|
||||||
|
std::fill_n(m_average_fullness.data(), AVERAGING_WINDOW, tempo);
|
||||||
|
m_soundtouch->setTempo(tempo);
|
||||||
|
m_stretch_reset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void AudioStream::SetStretchMode(AudioStretchMode mode)
|
void AudioStream::SetStretchMode(AudioStretchMode mode)
|
||||||
{
|
{
|
||||||
if (m_stretch_mode == mode)
|
if (m_stretch_mode == mode)
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
/// Nominal rate is used for both resampling and timestretching, input samples are assumed to be this amount faster
|
/// Nominal rate is used for both resampling and timestretching, input samples are assumed to be this amount faster
|
||||||
/// than the sample rate.
|
/// than the sample rate.
|
||||||
void SetNominalRate(float tempo);
|
void SetNominalRate(float tempo);
|
||||||
|
void UpdateTargetTempo(float tempo);
|
||||||
|
|
||||||
void SetStretchMode(AudioStretchMode mode);
|
void SetStretchMode(AudioStretchMode mode);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue