diff options
| author | 2016-08-31 22:19:38 -0400 | |
|---|---|---|
| committer | 2016-08-31 22:19:38 -0400 | |
| commit | 549d0c171563423f024de754a82ab033d31294d1 (patch) | |
| tree | 547ec290bfa04497c63f10603d801e473a0b1f84 /src | |
| parent | Merge pull request #2034 from JayFoxRox/avoid-glsl-error (diff) | |
| parent | configure_audio: User-configuratble option to enable/disable audio stretching (diff) | |
| download | yuzu-549d0c171563423f024de754a82ab033d31294d1.tar.gz yuzu-549d0c171563423f024de754a82ab033d31294d1.tar.xz yuzu-549d0c171563423f024de754a82ab033d31294d1.zip | |
Merge pull request #2035 from MerryMage/disable-stretch
User-configurable option to enable/disable time-stretching of audio
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio_core/audio_core.cpp | 4 | ||||
| -rw-r--r-- | src/audio_core/audio_core.h | 3 | ||||
| -rw-r--r-- | src/audio_core/hle/dsp.cpp | 45 | ||||
| -rw-r--r-- | src/audio_core/hle/dsp.h | 8 | ||||
| -rw-r--r-- | src/audio_core/null_sink.h | 2 | ||||
| -rw-r--r-- | src/audio_core/sdl2_sink.cpp | 6 | ||||
| -rw-r--r-- | src/audio_core/sdl2_sink.h | 2 | ||||
| -rw-r--r-- | src/audio_core/sink.h | 5 | ||||
| -rw-r--r-- | src/citra/config.cpp | 1 | ||||
| -rw-r--r-- | src/citra/default_ini.h | 6 | ||||
| -rw-r--r-- | src/citra_qt/config.cpp | 2 | ||||
| -rw-r--r-- | src/citra_qt/configure_audio.cpp | 3 | ||||
| -rw-r--r-- | src/citra_qt/configure_audio.ui | 10 | ||||
| -rw-r--r-- | src/core/settings.cpp | 1 | ||||
| -rw-r--r-- | src/core/settings.h | 1 |
15 files changed, 83 insertions, 16 deletions
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp index d42249ebd..8e19ec0c4 100644 --- a/src/audio_core/audio_core.cpp +++ b/src/audio_core/audio_core.cpp | |||
| @@ -71,6 +71,10 @@ void SelectSink(std::string sink_id) { | |||
| 71 | DSP::HLE::SetSink(iter->factory()); | 71 | DSP::HLE::SetSink(iter->factory()); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | void EnableStretching(bool enable) { | ||
| 75 | DSP::HLE::EnableStretching(enable); | ||
| 76 | } | ||
| 77 | |||
| 74 | void Shutdown() { | 78 | void Shutdown() { |
| 75 | CoreTiming::UnscheduleEvent(tick_event, 0); | 79 | CoreTiming::UnscheduleEvent(tick_event, 0); |
| 76 | DSP::HLE::Shutdown(); | 80 | DSP::HLE::Shutdown(); |
diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h index f618361f3..7e678aba5 100644 --- a/src/audio_core/audio_core.h +++ b/src/audio_core/audio_core.h | |||
| @@ -23,6 +23,9 @@ void AddAddressSpace(Kernel::VMManager& vm_manager); | |||
| 23 | /// Select the sink to use based on sink id. | 23 | /// Select the sink to use based on sink id. |
| 24 | void SelectSink(std::string sink_id); | 24 | void SelectSink(std::string sink_id); |
| 25 | 25 | ||
| 26 | /// Enable/Disable stretching. | ||
| 27 | void EnableStretching(bool enable); | ||
| 28 | |||
| 26 | /// Shutdown Audio Core | 29 | /// Shutdown Audio Core |
| 27 | void Shutdown(); | 30 | void Shutdown(); |
| 28 | 31 | ||
diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp index 0640e1eff..0cddeb82a 100644 --- a/src/audio_core/hle/dsp.cpp +++ b/src/audio_core/hle/dsp.cpp | |||
| @@ -85,12 +85,45 @@ static StereoFrame16 GenerateCurrentFrame() { | |||
| 85 | 85 | ||
| 86 | // Audio output | 86 | // Audio output |
| 87 | 87 | ||
| 88 | static bool perform_time_stretching = true; | ||
| 88 | static std::unique_ptr<AudioCore::Sink> sink; | 89 | static std::unique_ptr<AudioCore::Sink> sink; |
| 89 | static AudioCore::TimeStretcher time_stretcher; | 90 | static AudioCore::TimeStretcher time_stretcher; |
| 90 | 91 | ||
| 92 | static void FlushResidualStretcherAudio() { | ||
| 93 | time_stretcher.Flush(); | ||
| 94 | while (true) { | ||
| 95 | std::vector<s16> residual_audio = time_stretcher.Process(sink->SamplesInQueue()); | ||
| 96 | if (residual_audio.empty()) | ||
| 97 | break; | ||
| 98 | sink->EnqueueSamples(residual_audio.data(), residual_audio.size() / 2); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 91 | static void OutputCurrentFrame(const StereoFrame16& frame) { | 102 | static void OutputCurrentFrame(const StereoFrame16& frame) { |
| 92 | time_stretcher.AddSamples(&frame[0][0], frame.size()); | 103 | if (perform_time_stretching) { |
| 93 | sink->EnqueueSamples(time_stretcher.Process(sink->SamplesInQueue())); | 104 | time_stretcher.AddSamples(&frame[0][0], frame.size()); |
| 105 | std::vector<s16> stretched_samples = time_stretcher.Process(sink->SamplesInQueue()); | ||
| 106 | sink->EnqueueSamples(stretched_samples.data(), stretched_samples.size() / 2); | ||
| 107 | } else { | ||
| 108 | constexpr size_t maximum_sample_latency = 1024; // about 32 miliseconds | ||
| 109 | if (sink->SamplesInQueue() > maximum_sample_latency) { | ||
| 110 | // This can occur if we're running too fast and samples are starting to back up. | ||
| 111 | // Just drop the samples. | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | |||
| 115 | sink->EnqueueSamples(&frame[0][0], frame.size()); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | void EnableStretching(bool enable) { | ||
| 120 | if (perform_time_stretching == enable) | ||
| 121 | return; | ||
| 122 | |||
| 123 | if (!enable) { | ||
| 124 | FlushResidualStretcherAudio(); | ||
| 125 | } | ||
| 126 | perform_time_stretching = enable; | ||
| 94 | } | 127 | } |
| 95 | 128 | ||
| 96 | // Public Interface | 129 | // Public Interface |
| @@ -111,12 +144,8 @@ void Init() { | |||
| 111 | } | 144 | } |
| 112 | 145 | ||
| 113 | void Shutdown() { | 146 | void Shutdown() { |
| 114 | time_stretcher.Flush(); | 147 | if (perform_time_stretching) { |
| 115 | while (true) { | 148 | FlushResidualStretcherAudio(); |
| 116 | std::vector<s16> residual_audio = time_stretcher.Process(sink->SamplesInQueue()); | ||
| 117 | if (residual_audio.empty()) | ||
| 118 | break; | ||
| 119 | sink->EnqueueSamples(residual_audio); | ||
| 120 | } | 149 | } |
| 121 | } | 150 | } |
| 122 | 151 | ||
diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h index 9275cd7de..565f20b6f 100644 --- a/src/audio_core/hle/dsp.h +++ b/src/audio_core/hle/dsp.h | |||
| @@ -544,5 +544,13 @@ bool Tick(); | |||
| 544 | */ | 544 | */ |
| 545 | void SetSink(std::unique_ptr<AudioCore::Sink> sink); | 545 | void SetSink(std::unique_ptr<AudioCore::Sink> sink); |
| 546 | 546 | ||
| 547 | /** | ||
| 548 | * Enables/Disables audio-stretching. | ||
| 549 | * Audio stretching is an enhancement that stretches audio to match emulation | ||
| 550 | * speed to prevent stuttering at the cost of some audio latency. | ||
| 551 | * @param enable true to enable, false to disable. | ||
| 552 | */ | ||
| 553 | void EnableStretching(bool enable); | ||
| 554 | |||
| 547 | } // namespace HLE | 555 | } // namespace HLE |
| 548 | } // namespace DSP | 556 | } // namespace DSP |
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h index faf0ee4e1..9931c4778 100644 --- a/src/audio_core/null_sink.h +++ b/src/audio_core/null_sink.h | |||
| @@ -19,7 +19,7 @@ public: | |||
| 19 | return native_sample_rate; | 19 | return native_sample_rate; |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | void EnqueueSamples(const std::vector<s16>&) override {} | 22 | void EnqueueSamples(const s16*, size_t) override {} |
| 23 | 23 | ||
| 24 | size_t SamplesInQueue() const override { | 24 | size_t SamplesInQueue() const override { |
| 25 | return 0; | 25 | return 0; |
diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp index dc75c04ee..311dd5b59 100644 --- a/src/audio_core/sdl2_sink.cpp +++ b/src/audio_core/sdl2_sink.cpp | |||
| @@ -71,14 +71,12 @@ unsigned int SDL2Sink::GetNativeSampleRate() const { | |||
| 71 | return impl->sample_rate; | 71 | return impl->sample_rate; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | void SDL2Sink::EnqueueSamples(const std::vector<s16>& samples) { | 74 | void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) { |
| 75 | if (impl->audio_device_id <= 0) | 75 | if (impl->audio_device_id <= 0) |
| 76 | return; | 76 | return; |
| 77 | 77 | ||
| 78 | ASSERT_MSG(samples.size() % 2 == 0, "Samples must be in interleaved stereo PCM16 format (size must be a multiple of two)"); | ||
| 79 | |||
| 80 | SDL_LockAudioDevice(impl->audio_device_id); | 78 | SDL_LockAudioDevice(impl->audio_device_id); |
| 81 | impl->queue.emplace_back(samples); | 79 | impl->queue.emplace_back(samples, samples + sample_count * 2); |
| 82 | SDL_UnlockAudioDevice(impl->audio_device_id); | 80 | SDL_UnlockAudioDevice(impl->audio_device_id); |
| 83 | } | 81 | } |
| 84 | 82 | ||
diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h index 0f296b673..b13827214 100644 --- a/src/audio_core/sdl2_sink.h +++ b/src/audio_core/sdl2_sink.h | |||
| @@ -18,7 +18,7 @@ public: | |||
| 18 | 18 | ||
| 19 | unsigned int GetNativeSampleRate() const override; | 19 | unsigned int GetNativeSampleRate() const override; |
| 20 | 20 | ||
| 21 | void EnqueueSamples(const std::vector<s16>& samples) override; | 21 | void EnqueueSamples(const s16* samples, size_t sample_count) override; |
| 22 | 22 | ||
| 23 | size_t SamplesInQueue() const override; | 23 | size_t SamplesInQueue() const override; |
| 24 | 24 | ||
diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h index 1c881c3d2..a06fc3dcc 100644 --- a/src/audio_core/sink.h +++ b/src/audio_core/sink.h | |||
| @@ -23,9 +23,10 @@ public: | |||
| 23 | 23 | ||
| 24 | /** | 24 | /** |
| 25 | * Feed stereo samples to sink. | 25 | * Feed stereo samples to sink. |
| 26 | * @param samples Samples in interleaved stereo PCM16 format. Size of vector must be multiple of two. | 26 | * @param samples Samples in interleaved stereo PCM16 format. |
| 27 | * @param sample_count Number of samples. | ||
| 27 | */ | 28 | */ |
| 28 | virtual void EnqueueSamples(const std::vector<s16>& samples) = 0; | 29 | virtual void EnqueueSamples(const s16* samples, size_t sample_count) = 0; |
| 29 | 30 | ||
| 30 | /// Samples enqueued that have not been played yet. | 31 | /// Samples enqueued that have not been played yet. |
| 31 | virtual std::size_t SamplesInQueue() const = 0; | 32 | virtual std::size_t SamplesInQueue() const = 0; |
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index e832ec58d..f48386b9c 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -78,6 +78,7 @@ void Config::ReadValues() { | |||
| 78 | 78 | ||
| 79 | // Audio | 79 | // Audio |
| 80 | Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); | 80 | Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); |
| 81 | Settings::values.enable_audio_stretching = sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true); | ||
| 81 | 82 | ||
| 82 | // Data Storage | 83 | // Data Storage |
| 83 | Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); | 84 | Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); |
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 6249ef9e2..5b8ca12a0 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h | |||
| @@ -66,6 +66,12 @@ bg_green = | |||
| 66 | # auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) | 66 | # auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) |
| 67 | output_engine = | 67 | output_engine = |
| 68 | 68 | ||
| 69 | # Whether or not to enable the audio-stretching post-processing effect. | ||
| 70 | # This effect adjusts audio speed to match emulation speed and helps prevent audio stutter, | ||
| 71 | # at the cost of increasing audio latency. | ||
| 72 | # 0: No, 1 (default): Yes | ||
| 73 | enable_audio_stretching = | ||
| 74 | |||
| 69 | [Data Storage] | 75 | [Data Storage] |
| 70 | # Whether to create a virtual SD card. | 76 | # Whether to create a virtual SD card. |
| 71 | # 1 (default): Yes, 0: No | 77 | # 1 (default): Yes, 0: No |
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 93c6a6e41..ff3bfe1bd 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp | |||
| @@ -56,6 +56,7 @@ void Config::ReadValues() { | |||
| 56 | 56 | ||
| 57 | qt_config->beginGroup("Audio"); | 57 | qt_config->beginGroup("Audio"); |
| 58 | Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); | 58 | Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); |
| 59 | Settings::values.enable_audio_stretching = qt_config->value("enable_audio_stretching", true).toBool(); | ||
| 59 | qt_config->endGroup(); | 60 | qt_config->endGroup(); |
| 60 | 61 | ||
| 61 | qt_config->beginGroup("Data Storage"); | 62 | qt_config->beginGroup("Data Storage"); |
| @@ -148,6 +149,7 @@ void Config::SaveValues() { | |||
| 148 | 149 | ||
| 149 | qt_config->beginGroup("Audio"); | 150 | qt_config->beginGroup("Audio"); |
| 150 | qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); | 151 | qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); |
| 152 | qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching); | ||
| 151 | qt_config->endGroup(); | 153 | qt_config->endGroup(); |
| 152 | 154 | ||
| 153 | qt_config->beginGroup("Data Storage"); | 155 | qt_config->beginGroup("Data Storage"); |
diff --git a/src/citra_qt/configure_audio.cpp b/src/citra_qt/configure_audio.cpp index cedfa2f2a..7100be158 100644 --- a/src/citra_qt/configure_audio.cpp +++ b/src/citra_qt/configure_audio.cpp | |||
| @@ -36,9 +36,12 @@ void ConfigureAudio::setConfiguration() { | |||
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | ui->output_sink_combo_box->setCurrentIndex(new_sink_index); | 38 | ui->output_sink_combo_box->setCurrentIndex(new_sink_index); |
| 39 | |||
| 40 | ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching); | ||
| 39 | } | 41 | } |
| 40 | 42 | ||
| 41 | void ConfigureAudio::applyConfiguration() { | 43 | void ConfigureAudio::applyConfiguration() { |
| 42 | Settings::values.sink_id = ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()).toStdString(); | 44 | Settings::values.sink_id = ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()).toStdString(); |
| 45 | Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked(); | ||
| 43 | Settings::Apply(); | 46 | Settings::Apply(); |
| 44 | } | 47 | } |
diff --git a/src/citra_qt/configure_audio.ui b/src/citra_qt/configure_audio.ui index d7f6946ca..3e2b4635f 100644 --- a/src/citra_qt/configure_audio.ui +++ b/src/citra_qt/configure_audio.ui | |||
| @@ -25,6 +25,16 @@ | |||
| 25 | </item> | 25 | </item> |
| 26 | </layout> | 26 | </layout> |
| 27 | </item> | 27 | </item> |
| 28 | <item> | ||
| 29 | <widget class="QCheckBox" name="toggle_audio_stretching"> | ||
| 30 | <property name="text"> | ||
| 31 | <string>Enable audio stretching</string> | ||
| 32 | </property> | ||
| 33 | <property name="toolTip"> | ||
| 34 | <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string> | ||
| 35 | </property> | ||
| 36 | </widget> | ||
| 37 | </item> | ||
| 28 | </layout> | 38 | </layout> |
| 29 | </widget> | 39 | </widget> |
| 30 | </item> | 40 | </item> |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 77261eafe..1b6733a79 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -24,6 +24,7 @@ void Apply() { | |||
| 24 | VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution; | 24 | VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution; |
| 25 | 25 | ||
| 26 | AudioCore::SelectSink(values.sink_id); | 26 | AudioCore::SelectSink(values.sink_id); |
| 27 | AudioCore::EnableStretching(values.enable_audio_stretching); | ||
| 27 | 28 | ||
| 28 | } | 29 | } |
| 29 | 30 | ||
diff --git a/src/core/settings.h b/src/core/settings.h index f95e62390..0962a4ecf 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -81,6 +81,7 @@ struct Values { | |||
| 81 | 81 | ||
| 82 | // Audio | 82 | // Audio |
| 83 | std::string sink_id; | 83 | std::string sink_id; |
| 84 | bool enable_audio_stretching; | ||
| 84 | 85 | ||
| 85 | // Debugging | 86 | // Debugging |
| 86 | bool use_gdbstub; | 87 | bool use_gdbstub; |