mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 10:44:49 +01:00 
			
		
		
		
	Merge pull request #2035 from MerryMage/disable-stretch
User-configurable option to enable/disable time-stretching of audio
This commit is contained in:
		
						commit
						549d0c1715
					
				| @ -71,6 +71,10 @@ void SelectSink(std::string sink_id) { | ||||
|     DSP::HLE::SetSink(iter->factory()); | ||||
| } | ||||
| 
 | ||||
| void EnableStretching(bool enable) { | ||||
|     DSP::HLE::EnableStretching(enable); | ||||
| } | ||||
| 
 | ||||
| void Shutdown() { | ||||
|     CoreTiming::UnscheduleEvent(tick_event, 0); | ||||
|     DSP::HLE::Shutdown(); | ||||
|  | ||||
| @ -23,6 +23,9 @@ void AddAddressSpace(Kernel::VMManager& vm_manager); | ||||
| /// Select the sink to use based on sink id.
 | ||||
| void SelectSink(std::string sink_id); | ||||
| 
 | ||||
| /// Enable/Disable stretching.
 | ||||
| void EnableStretching(bool enable); | ||||
| 
 | ||||
| /// Shutdown Audio Core
 | ||||
| void Shutdown(); | ||||
| 
 | ||||
|  | ||||
| @ -85,12 +85,45 @@ static StereoFrame16 GenerateCurrentFrame() { | ||||
| 
 | ||||
| // Audio output
 | ||||
| 
 | ||||
| static bool perform_time_stretching = true; | ||||
| static std::unique_ptr<AudioCore::Sink> sink; | ||||
| static AudioCore::TimeStretcher time_stretcher; | ||||
| 
 | ||||
| static void FlushResidualStretcherAudio() { | ||||
|     time_stretcher.Flush(); | ||||
|     while (true) { | ||||
|         std::vector<s16> residual_audio = time_stretcher.Process(sink->SamplesInQueue()); | ||||
|         if (residual_audio.empty()) | ||||
|             break; | ||||
|         sink->EnqueueSamples(residual_audio.data(), residual_audio.size() / 2); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void OutputCurrentFrame(const StereoFrame16& frame) { | ||||
|     time_stretcher.AddSamples(&frame[0][0], frame.size()); | ||||
|     sink->EnqueueSamples(time_stretcher.Process(sink->SamplesInQueue())); | ||||
|     if (perform_time_stretching) { | ||||
|         time_stretcher.AddSamples(&frame[0][0], frame.size()); | ||||
|         std::vector<s16> stretched_samples = time_stretcher.Process(sink->SamplesInQueue()); | ||||
|         sink->EnqueueSamples(stretched_samples.data(), stretched_samples.size() / 2); | ||||
|     } else { | ||||
|         constexpr size_t maximum_sample_latency = 1024; // about 32 miliseconds
 | ||||
|         if (sink->SamplesInQueue() > maximum_sample_latency) { | ||||
|             // This can occur if we're running too fast and samples are starting to back up.
 | ||||
|             // Just drop the samples.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         sink->EnqueueSamples(&frame[0][0], frame.size()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void EnableStretching(bool enable) { | ||||
|     if (perform_time_stretching == enable) | ||||
|         return; | ||||
| 
 | ||||
|     if (!enable) { | ||||
|         FlushResidualStretcherAudio(); | ||||
|     } | ||||
|     perform_time_stretching = enable; | ||||
| } | ||||
| 
 | ||||
| // Public Interface
 | ||||
| @ -111,12 +144,8 @@ void Init() { | ||||
| } | ||||
| 
 | ||||
| void Shutdown() { | ||||
|     time_stretcher.Flush(); | ||||
|     while (true) { | ||||
|         std::vector<s16> residual_audio = time_stretcher.Process(sink->SamplesInQueue()); | ||||
|         if (residual_audio.empty()) | ||||
|             break; | ||||
|         sink->EnqueueSamples(residual_audio); | ||||
|     if (perform_time_stretching) { | ||||
|         FlushResidualStretcherAudio(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -544,5 +544,13 @@ bool Tick(); | ||||
|  */ | ||||
| void SetSink(std::unique_ptr<AudioCore::Sink> sink); | ||||
| 
 | ||||
| /**
 | ||||
|  * Enables/Disables audio-stretching. | ||||
|  * Audio stretching is an enhancement that stretches audio to match emulation | ||||
|  * speed to prevent stuttering at the cost of some audio latency. | ||||
|  * @param enable true to enable, false to disable. | ||||
|  */ | ||||
| void EnableStretching(bool enable); | ||||
| 
 | ||||
| } // namespace HLE
 | ||||
| } // namespace DSP
 | ||||
|  | ||||
| @ -19,7 +19,7 @@ public: | ||||
|         return native_sample_rate; | ||||
|     } | ||||
| 
 | ||||
|     void EnqueueSamples(const std::vector<s16>&) override {} | ||||
|     void EnqueueSamples(const s16*, size_t) override {} | ||||
| 
 | ||||
|     size_t SamplesInQueue() const override { | ||||
|         return 0; | ||||
|  | ||||
| @ -71,14 +71,12 @@ unsigned int SDL2Sink::GetNativeSampleRate() const { | ||||
|     return impl->sample_rate; | ||||
| } | ||||
| 
 | ||||
| void SDL2Sink::EnqueueSamples(const std::vector<s16>& samples) { | ||||
| void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) { | ||||
|     if (impl->audio_device_id <= 0) | ||||
|         return; | ||||
| 
 | ||||
|     ASSERT_MSG(samples.size() % 2 == 0, "Samples must be in interleaved stereo PCM16 format (size must be a multiple of two)"); | ||||
| 
 | ||||
|     SDL_LockAudioDevice(impl->audio_device_id); | ||||
|     impl->queue.emplace_back(samples); | ||||
|     impl->queue.emplace_back(samples, samples + sample_count * 2); | ||||
|     SDL_UnlockAudioDevice(impl->audio_device_id); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -18,7 +18,7 @@ public: | ||||
| 
 | ||||
|     unsigned int GetNativeSampleRate() const override; | ||||
| 
 | ||||
|     void EnqueueSamples(const std::vector<s16>& samples) override; | ||||
|     void EnqueueSamples(const s16* samples, size_t sample_count) override; | ||||
| 
 | ||||
|     size_t SamplesInQueue() const override; | ||||
| 
 | ||||
|  | ||||
| @ -23,9 +23,10 @@ public: | ||||
| 
 | ||||
|     /**
 | ||||
|      * Feed stereo samples to sink. | ||||
|      * @param samples Samples in interleaved stereo PCM16 format. Size of vector must be multiple of two. | ||||
|      * @param samples Samples in interleaved stereo PCM16 format. | ||||
|      * @param sample_count Number of samples. | ||||
|      */ | ||||
|     virtual void EnqueueSamples(const std::vector<s16>& samples) = 0; | ||||
|     virtual void EnqueueSamples(const s16* samples, size_t sample_count) = 0; | ||||
| 
 | ||||
|     /// Samples enqueued that have not been played yet.
 | ||||
|     virtual std::size_t SamplesInQueue() const = 0; | ||||
|  | ||||
| @ -78,6 +78,7 @@ void Config::ReadValues() { | ||||
| 
 | ||||
|     // Audio
 | ||||
|     Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); | ||||
|     Settings::values.enable_audio_stretching = sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true); | ||||
| 
 | ||||
|     // Data Storage
 | ||||
|     Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); | ||||
|  | ||||
| @ -66,6 +66,12 @@ bg_green = | ||||
| # auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) | ||||
| output_engine = | ||||
| 
 | ||||
| # Whether or not to enable the audio-stretching post-processing effect. | ||||
| # This effect adjusts audio speed to match emulation speed and helps prevent audio stutter, | ||||
| # at the cost of increasing audio latency. | ||||
| # 0: No, 1 (default): Yes | ||||
| enable_audio_stretching = | ||||
| 
 | ||||
| [Data Storage] | ||||
| # Whether to create a virtual SD card. | ||||
| # 1 (default): Yes, 0: No | ||||
|  | ||||
| @ -56,6 +56,7 @@ void Config::ReadValues() { | ||||
| 
 | ||||
|     qt_config->beginGroup("Audio"); | ||||
|     Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); | ||||
|     Settings::values.enable_audio_stretching = qt_config->value("enable_audio_stretching", true).toBool(); | ||||
|     qt_config->endGroup(); | ||||
| 
 | ||||
|     qt_config->beginGroup("Data Storage"); | ||||
| @ -148,6 +149,7 @@ void Config::SaveValues() { | ||||
| 
 | ||||
|     qt_config->beginGroup("Audio"); | ||||
|     qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); | ||||
|     qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching); | ||||
|     qt_config->endGroup(); | ||||
| 
 | ||||
|     qt_config->beginGroup("Data Storage"); | ||||
|  | ||||
| @ -36,9 +36,12 @@ void ConfigureAudio::setConfiguration() { | ||||
|         } | ||||
|     } | ||||
|     ui->output_sink_combo_box->setCurrentIndex(new_sink_index); | ||||
| 
 | ||||
|     ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching); | ||||
| } | ||||
| 
 | ||||
| void ConfigureAudio::applyConfiguration() { | ||||
|     Settings::values.sink_id = ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()).toStdString(); | ||||
|     Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked(); | ||||
|     Settings::Apply(); | ||||
| } | ||||
|  | ||||
| @ -25,6 +25,16 @@ | ||||
|         </item> | ||||
|        </layout> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QCheckBox" name="toggle_audio_stretching"> | ||||
|         <property name="text"> | ||||
|          <string>Enable audio stretching</string> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|  | ||||
| @ -24,6 +24,7 @@ void Apply() { | ||||
|     VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution; | ||||
| 
 | ||||
|     AudioCore::SelectSink(values.sink_id); | ||||
|     AudioCore::EnableStretching(values.enable_audio_stretching); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -81,6 +81,7 @@ struct Values { | ||||
| 
 | ||||
|     // Audio
 | ||||
|     std::string sink_id; | ||||
|     bool enable_audio_stretching; | ||||
| 
 | ||||
|     // Debugging
 | ||||
|     bool use_gdbstub; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user