Add audio stretching support
This commit is contained in:
parent
9cd79c25ed
commit
a6efff8b02
|
@ -31,3 +31,6 @@
|
||||||
[submodule "opus"]
|
[submodule "opus"]
|
||||||
path = externals/opus
|
path = externals/opus
|
||||||
url = https://github.com/ogniK5377/opus.git
|
url = https://github.com/ogniK5377/opus.git
|
||||||
|
[submodule "soundtouch"]
|
||||||
|
path = externals/soundtouch
|
||||||
|
url = https://github.com/citra-emu/ext-soundtouch.git
|
||||||
|
|
|
@ -47,6 +47,9 @@ target_include_directories(microprofile INTERFACE ./microprofile)
|
||||||
add_library(unicorn-headers INTERFACE)
|
add_library(unicorn-headers INTERFACE)
|
||||||
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
|
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
|
||||||
|
|
||||||
|
# SoundTouch
|
||||||
|
add_subdirectory(soundtouch)
|
||||||
|
|
||||||
# Xbyak
|
# Xbyak
|
||||||
if (ARCHITECTURE_x86_64)
|
if (ARCHITECTURE_x86_64)
|
||||||
# Defined before "dynarmic" above
|
# Defined before "dynarmic" above
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 060181eaf273180d3a7e87349895bd0cb6ccbf4a
|
|
@ -24,6 +24,7 @@ add_library(audio_core STATIC
|
||||||
create_target_directory_groups(audio_core)
|
create_target_directory_groups(audio_core)
|
||||||
|
|
||||||
target_link_libraries(audio_core PUBLIC common core)
|
target_link_libraries(audio_core PUBLIC common core)
|
||||||
|
target_link_libraries(audio_core PRIVATE SoundTouch)
|
||||||
|
|
||||||
if(ENABLE_CUBEB)
|
if(ENABLE_CUBEB)
|
||||||
target_link_libraries(audio_core PRIVATE cubeb)
|
target_link_libraries(audio_core PRIVATE cubeb)
|
||||||
|
|
|
@ -85,6 +85,13 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t SamplesInQueue(u32 num_channels) const {
|
||||||
|
if (!ctx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return queue.size() / num_channels;
|
||||||
|
}
|
||||||
|
|
||||||
u32 GetNumChannels() const {
|
u32 GetNumChannels() const {
|
||||||
return num_channels;
|
return num_channels;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ public:
|
||||||
private:
|
private:
|
||||||
struct NullSinkStreamImpl final : SinkStream {
|
struct NullSinkStreamImpl final : SinkStream {
|
||||||
void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {}
|
void EnqueueSamples(u32 /*num_channels*/, const std::vector<s16>& /*samples*/) override {}
|
||||||
|
|
||||||
|
size_t SamplesInQueue(u32 /*num_channels*/) const override {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
} null_sink_stream;
|
} null_sink_stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ public:
|
||||||
* @param samples Samples in interleaved stereo PCM16 format.
|
* @param samples Samples in interleaved stereo PCM16 format.
|
||||||
*/
|
*/
|
||||||
virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0;
|
virtual void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) = 0;
|
||||||
|
|
||||||
|
virtual std::size_t SamplesInQueue(u32 num_channels) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SinkStreamPtr = std::unique_ptr<SinkStream>;
|
using SinkStreamPtr = std::unique_ptr<SinkStream>;
|
||||||
|
|
|
@ -90,6 +90,7 @@ void Stream::PlayNextBuffer() {
|
||||||
queued_buffers.pop();
|
queued_buffers.pop();
|
||||||
|
|
||||||
VolumeAdjustSamples(active_buffer->Samples());
|
VolumeAdjustSamples(active_buffer->Samples());
|
||||||
|
|
||||||
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
|
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
|
||||||
|
|
||||||
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
|
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
|
||||||
|
|
|
@ -146,6 +146,7 @@ struct Values {
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
std::string sink_id;
|
std::string sink_id;
|
||||||
|
bool enable_audio_stretching;
|
||||||
std::string audio_device_id;
|
std::string audio_device_id;
|
||||||
float volume;
|
float volume;
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,9 @@ TelemetrySession::TelemetrySession() {
|
||||||
Telemetry::AppendOSInfo(field_collection);
|
Telemetry::AppendOSInfo(field_collection);
|
||||||
|
|
||||||
// Log user configuration information
|
// Log user configuration information
|
||||||
|
AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id);
|
||||||
|
AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",
|
||||||
|
Settings::values.enable_audio_stretching);
|
||||||
AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit);
|
AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit);
|
||||||
AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore",
|
AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore",
|
||||||
Settings::values.use_multi_core);
|
Settings::values.use_multi_core);
|
||||||
|
|
|
@ -95,6 +95,8 @@ void Config::ReadValues() {
|
||||||
|
|
||||||
qt_config->beginGroup("Audio");
|
qt_config->beginGroup("Audio");
|
||||||
Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
|
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();
|
||||||
Settings::values.audio_device_id =
|
Settings::values.audio_device_id =
|
||||||
qt_config->value("output_device", "auto").toString().toStdString();
|
qt_config->value("output_device", "auto").toString().toStdString();
|
||||||
Settings::values.volume = qt_config->value("volume", 1).toFloat();
|
Settings::values.volume = qt_config->value("volume", 1).toFloat();
|
||||||
|
@ -230,6 +232,7 @@ void Config::SaveValues() {
|
||||||
|
|
||||||
qt_config->beginGroup("Audio");
|
qt_config->beginGroup("Audio");
|
||||||
qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
|
qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
|
||||||
|
qt_config->setValue("enable_audio_stretching", Settings::values.enable_audio_stretching);
|
||||||
qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
|
qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
|
||||||
qt_config->setValue("volume", Settings::values.volume);
|
qt_config->setValue("volume", Settings::values.volume);
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
|
@ -46,6 +46,8 @@ void ConfigureAudio::setConfiguration() {
|
||||||
}
|
}
|
||||||
ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
|
ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
|
||||||
|
|
||||||
|
ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
|
||||||
|
|
||||||
// The device list cannot be pre-populated (nor listed) until the output sink is known.
|
// The device list cannot be pre-populated (nor listed) until the output sink is known.
|
||||||
updateAudioDevices(new_sink_index);
|
updateAudioDevices(new_sink_index);
|
||||||
|
|
||||||
|
@ -67,6 +69,7 @@ void ConfigureAudio::applyConfiguration() {
|
||||||
Settings::values.sink_id =
|
Settings::values.sink_id =
|
||||||
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
|
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
|
||||||
.toStdString();
|
.toStdString();
|
||||||
|
Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
|
||||||
Settings::values.audio_device_id =
|
Settings::values.audio_device_id =
|
||||||
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
|
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
|
||||||
.toStdString();
|
.toStdString();
|
||||||
|
|
|
@ -31,6 +31,16 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="toggle_audio_stretching">
|
||||||
|
<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>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable audio stretching</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -108,6 +108,8 @@ void Config::ReadValues() {
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
|
Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
|
||||||
|
Settings::values.enable_audio_stretching =
|
||||||
|
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
|
||||||
Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
|
Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
|
||||||
Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1);
|
Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1);
|
||||||
|
|
||||||
|
|
|
@ -150,6 +150,12 @@ swap_screen =
|
||||||
# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available)
|
# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available)
|
||||||
output_engine =
|
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 =
|
||||||
|
|
||||||
# Which audio device to use.
|
# Which audio device to use.
|
||||||
# auto (default): Auto-select
|
# auto (default): Auto-select
|
||||||
output_device =
|
output_device =
|
||||||
|
|
Loading…
Reference in New Issue