summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2016-08-31 22:19:38 -0400
committerGravatar GitHub2016-08-31 22:19:38 -0400
commit549d0c171563423f024de754a82ab033d31294d1 (patch)
tree547ec290bfa04497c63f10603d801e473a0b1f84 /src
parentMerge pull request #2034 from JayFoxRox/avoid-glsl-error (diff)
parentconfigure_audio: User-configuratble option to enable/disable audio stretching (diff)
downloadyuzu-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.cpp4
-rw-r--r--src/audio_core/audio_core.h3
-rw-r--r--src/audio_core/hle/dsp.cpp45
-rw-r--r--src/audio_core/hle/dsp.h8
-rw-r--r--src/audio_core/null_sink.h2
-rw-r--r--src/audio_core/sdl2_sink.cpp6
-rw-r--r--src/audio_core/sdl2_sink.h2
-rw-r--r--src/audio_core/sink.h5
-rw-r--r--src/citra/config.cpp1
-rw-r--r--src/citra/default_ini.h6
-rw-r--r--src/citra_qt/config.cpp2
-rw-r--r--src/citra_qt/configure_audio.cpp3
-rw-r--r--src/citra_qt/configure_audio.ui10
-rw-r--r--src/core/settings.cpp1
-rw-r--r--src/core/settings.h1
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
74void EnableStretching(bool enable) {
75 DSP::HLE::EnableStretching(enable);
76}
77
74void Shutdown() { 78void 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.
24void SelectSink(std::string sink_id); 24void SelectSink(std::string sink_id);
25 25
26/// Enable/Disable stretching.
27void EnableStretching(bool enable);
28
26/// Shutdown Audio Core 29/// Shutdown Audio Core
27void Shutdown(); 30void 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
88static bool perform_time_stretching = true;
88static std::unique_ptr<AudioCore::Sink> sink; 89static std::unique_ptr<AudioCore::Sink> sink;
89static AudioCore::TimeStretcher time_stretcher; 90static AudioCore::TimeStretcher time_stretcher;
90 91
92static 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
91static void OutputCurrentFrame(const StereoFrame16& frame) { 102static 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
119void 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
113void Shutdown() { 146void 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 */
545void SetSink(std::unique_ptr<AudioCore::Sink> sink); 545void 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 */
553void 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
74void SDL2Sink::EnqueueSamples(const std::vector<s16>& samples) { 74void 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)
67output_engine = 67output_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
73enable_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
41void ConfigureAudio::applyConfiguration() { 43void 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;