mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +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()) | ||||
|   { | ||||
|     s_target_speed = target_speed; | ||||
|     UpdateThrottlePeriod(); | ||||
|     ResetThrottler(); | ||||
| 
 | ||||
|     AudioStream* stream = g_spu.GetOutputStream(); | ||||
|     if (g_settings.audio_fast_forward_volume != g_settings.audio_output_volume) | ||||
|       stream->SetOutputVolume(GetAudioOutputVolume()); | ||||
|  | @ -2211,10 +2207,16 @@ void System::UpdateSpeedLimiterState() | |||
|     const bool rate_adjust = | ||||
|       (syncing_to_host || g_settings.audio_stretch_mode == AudioStretchMode::Resample) && target_speed > 0.0f; | ||||
|     stream->SetNominalRate(rate_adjust ? target_speed : 1.0f); | ||||
|     if (s_target_speed < target_speed) | ||||
|       stream->UpdateTargetTempo(target_speed); | ||||
| 
 | ||||
|     // stream->SetSync(audio_sync_enabled);
 | ||||
|     // if (audio_sync_enabled)
 | ||||
|     // stream->EmptyBuffer();
 | ||||
| 
 | ||||
|     s_target_speed = target_speed; | ||||
|     UpdateThrottlePeriod(); | ||||
|     ResetThrottler(); | ||||
|   } | ||||
| 
 | ||||
|   g_host_display->SetDisplayMaxFPS(max_display_fps); | ||||
|  |  | |||
|  | @ -8,7 +8,12 @@ | |||
| #include <algorithm> | ||||
| #include <cmath> | ||||
| #include <cstring> | ||||
| Log_SetChannel(AudioStream); | ||||
| 
 | ||||
| #ifdef __APPLE__ | ||||
| #include <stdlib.h> // alloca
 | ||||
| #else | ||||
| #include <malloc.h> // alloca
 | ||||
| #endif | ||||
| 
 | ||||
| #if defined(_M_ARM64) | ||||
| #include <arm64_neon.h> | ||||
|  | @ -18,6 +23,8 @@ Log_SetChannel(AudioStream); | |||
| #include <emmintrin.h> | ||||
| #endif | ||||
| 
 | ||||
| Log_SetChannel(AudioStream); | ||||
| 
 | ||||
| static constexpr bool LOG_TIMESTRETCH_STATS = false; | ||||
| 
 | ||||
| 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); | ||||
|   } | ||||
| 
 | ||||
|   // TODO: Bring back the crappy resampler?
 | ||||
|   if (silence_frames > 0) | ||||
|   { | ||||
|     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) | ||||
|  | @ -228,6 +265,22 @@ void AudioStream::SetNominalRate(float 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) | ||||
| { | ||||
|   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
 | ||||
|   /// than the sample rate.
 | ||||
|   void SetNominalRate(float tempo); | ||||
|   void UpdateTargetTempo(float tempo); | ||||
| 
 | ||||
|   void SetStretchMode(AudioStretchMode mode); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Connor McLaughlin
						Connor McLaughlin