diff options
Diffstat (limited to '')
-rw-r--r-- | src/audio_core/audio_out.cpp | 5 | ||||
-rw-r--r-- | src/audio_core/stream.cpp | 35 | ||||
-rw-r--r-- | src/core/settings.h | 5 | ||||
-rw-r--r-- | src/yuzu/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/yuzu/configuration/config.cpp | 13 | ||||
-rw-r--r-- | src/yuzu/configuration/configure.ui | 21 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_audio.cpp | 90 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_audio.h | 31 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_audio.ui | 130 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_dialog.cpp | 1 | ||||
-rw-r--r-- | src/yuzu_cmd/config.cpp | 5 | ||||
-rw-r--r-- | src/yuzu_cmd/default_ini.h | 12 |
12 files changed, 330 insertions, 21 deletions
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp index 77cedb6ba..0cabaa354 100644 --- a/src/audio_core/audio_out.cpp +++ b/src/audio_core/audio_out.cpp @@ -7,6 +7,7 @@ #include "audio_core/sink_details.h" #include "common/assert.h" #include "common/logging/log.h" +#include "core/settings.h" namespace AudioCore { @@ -29,8 +30,8 @@ static Stream::Format ChannelsToStreamFormat(u32 num_channels) { StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, Stream::ReleaseCallback&& release_callback) { if (!sink) { - const SinkDetails& sink_details = GetSinkDetails("auto"); - sink = sink_details.factory(""); + const SinkDetails& sink_details = GetSinkDetails(Settings::values.sink_id); + sink = sink_details.factory(Settings::values.audio_device_id); } return std::make_shared<Stream>(sample_rate, ChannelsToStreamFormat(num_channels), diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 689f51a1d..a0045b7a1 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -2,14 +2,17 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/core_timing.h" -#include "core/core_timing_util.h" +#include <algorithm> +#include <cmath> #include "audio_core/sink.h" #include "audio_core/sink_details.h" #include "audio_core/stream.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core_timing.h" +#include "core/core_timing_util.h" +#include "core/settings.h" namespace AudioCore { @@ -56,6 +59,24 @@ s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); } +static std::vector<s16> GetVolumeAdjustedSamples(const std::vector<u8>& data) { + std::vector<s16> samples(data.size() / sizeof(s16)); + std::memcpy(samples.data(), data.data(), data.size()); + const float volume{std::clamp(Settings::values.volume, 0.0f, 1.0f)}; + + if (volume == 1.0f) { + return samples; + } + + // Implementation of a volume slider with a dynamic range of 60 dB + const float volume_scale_factor{std::exp(6.90775f * volume) * 0.001f}; + for (auto& sample : samples) { + sample = static_cast<s16>(sample * volume_scale_factor); + } + + return samples; +} + void Stream::PlayNextBuffer() { if (!IsPlaying()) { // Ensure we are in playing state before playing the next buffer @@ -75,9 +96,9 @@ void Stream::PlayNextBuffer() { active_buffer = queued_buffers.front(); queued_buffers.pop(); - sink_stream.EnqueueSamples(GetNumChannels(), - reinterpret_cast<const s16*>(active_buffer->GetData().data()), - active_buffer->GetData().size() / GetSampleSize()); + const size_t sample_count{active_buffer->GetData().size() / GetSampleSize()}; + sink_stream.EnqueueSamples( + GetNumChannels(), GetVolumeAdjustedSamples(active_buffer->GetData()).data(), sample_count); CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); } diff --git a/src/core/settings.h b/src/core/settings.h index 7150d9755..8cc65e434 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -137,6 +137,11 @@ struct Values { std::string log_filter; + // Audio + std::string sink_id; + std::string audio_device_id; + float volume; + // Debugging bool use_gdbstub; u16 gdbstub_port; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 7de919a8e..475556806 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -11,6 +11,8 @@ add_executable(yuzu bootmanager.h configuration/config.cpp configuration/config.h + configuration/configure_audio.cpp + configuration/configure_audio.h configuration/configure_debug.cpp configuration/configure_debug.h configuration/configure_dialog.cpp @@ -55,6 +57,7 @@ add_executable(yuzu set(UIS aboutdialog.ui configuration/configure.ui + configuration/configure_audio.ui configuration/configure_debug.ui configuration/configure_general.ui configuration/configure_graphics.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 98969fe10..e8b3a9866 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -92,6 +92,13 @@ void Config::ReadValues() { Settings::values.bg_blue = qt_config->value("bg_blue", 0.0).toFloat(); qt_config->endGroup(); + qt_config->beginGroup("Audio"); + Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); + Settings::values.audio_device_id = + qt_config->value("output_device", "auto").toString().toStdString(); + Settings::values.volume = qt_config->value("volume", 1).toFloat(); + qt_config->endGroup(); + qt_config->beginGroup("Data Storage"); Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); qt_config->endGroup(); @@ -195,6 +202,12 @@ void Config::SaveValues() { qt_config->setValue("bg_blue", (double)Settings::values.bg_blue); qt_config->endGroup(); + qt_config->beginGroup("Audio"); + qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); + qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id)); + qt_config->setValue("volume", Settings::values.volume); + qt_config->endGroup(); + qt_config->beginGroup("Data Storage"); qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); qt_config->endGroup(); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index c5303851c..c8e0b88af 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -34,11 +34,16 @@ <string>Input</string> </attribute> </widget> - <widget class="ConfigureGraphics" name="graphicsTab"> - <attribute name="title"> - <string>Graphics</string> - </attribute> - </widget> + <widget class="ConfigureGraphics" name="graphicsTab"> + <attribute name="title"> + <string>Graphics</string> + </attribute> + </widget> + <widget class="ConfigureAudio" name="audioTab"> + <attribute name="title"> + <string>Audio</string> + </attribute> + </widget> <widget class="ConfigureDebug" name="debugTab"> <attribute name="title"> <string>Debug</string> @@ -69,6 +74,12 @@ <container>1</container> </customwidget> <customwidget> + <class>ConfigureAudio</class> + <extends>QWidget</extends> + <header>configuration/configure_audio.h</header> + <container>1</container> + </customwidget> + <customwidget> <class>ConfigureDebug</class> <extends>QWidget</extends> <header>configuration/configure_debug.h</header> diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp new file mode 100644 index 000000000..fbb813f6c --- /dev/null +++ b/src/yuzu/configuration/configure_audio.cpp @@ -0,0 +1,90 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <memory> + +#include "audio_core/sink.h" +#include "audio_core/sink_details.h" +#include "core/core.h" +#include "core/settings.h" +#include "ui_configure_audio.h" +#include "yuzu/configuration/configure_audio.h" + +ConfigureAudio::ConfigureAudio(QWidget* parent) + : QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()) { + ui->setupUi(this); + + ui->output_sink_combo_box->clear(); + ui->output_sink_combo_box->addItem("auto"); + for (const auto& sink_detail : AudioCore::g_sink_details) { + ui->output_sink_combo_box->addItem(sink_detail.id); + } + + connect(ui->volume_slider, &QSlider::valueChanged, [this] { + ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition())); + }); + + this->setConfiguration(); + connect(ui->output_sink_combo_box, + static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, + &ConfigureAudio::updateAudioDevices); + + ui->output_sink_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn()); + ui->audio_device_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn()); +} + +ConfigureAudio::~ConfigureAudio() = default; + +void ConfigureAudio::setConfiguration() { + int new_sink_index = 0; + for (int index = 0; index < ui->output_sink_combo_box->count(); index++) { + if (ui->output_sink_combo_box->itemText(index).toStdString() == Settings::values.sink_id) { + new_sink_index = index; + break; + } + } + ui->output_sink_combo_box->setCurrentIndex(new_sink_index); + + // The device list cannot be pre-populated (nor listed) until the output sink is known. + updateAudioDevices(new_sink_index); + + int new_device_index = -1; + for (int index = 0; index < ui->audio_device_combo_box->count(); index++) { + if (ui->audio_device_combo_box->itemText(index).toStdString() == + Settings::values.audio_device_id) { + new_device_index = index; + break; + } + } + ui->audio_device_combo_box->setCurrentIndex(new_device_index); + + ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum()); + ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition())); +} + +void ConfigureAudio::applyConfiguration() { + Settings::values.sink_id = + ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) + .toStdString(); + Settings::values.audio_device_id = + ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex()) + .toStdString(); + Settings::values.volume = + static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum(); +} + +void ConfigureAudio::updateAudioDevices(int sink_index) { + ui->audio_device_combo_box->clear(); + ui->audio_device_combo_box->addItem(AudioCore::auto_device_name); + + std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString(); + std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices(); + for (const auto& device : device_list) { + ui->audio_device_combo_box->addItem(device.c_str()); + } +} + +void ConfigureAudio::retranslateUi() { + ui->retranslateUi(this); +} diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h new file mode 100644 index 000000000..4f0af4163 --- /dev/null +++ b/src/yuzu/configuration/configure_audio.h @@ -0,0 +1,31 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <QWidget> + +namespace Ui { +class ConfigureAudio; +} + +class ConfigureAudio : public QWidget { + Q_OBJECT + +public: + explicit ConfigureAudio(QWidget* parent = nullptr); + ~ConfigureAudio(); + + void applyConfiguration(); + void retranslateUi(); + +public slots: + void updateAudioDevices(int sink_index); + +private: + void setConfiguration(); + + std::unique_ptr<Ui::ConfigureAudio> ui; +}; diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui new file mode 100644 index 000000000..ef67890dc --- /dev/null +++ b/src/yuzu/configuration/configure_audio.ui @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureAudio</class> + <widget class="QWidget" name="ConfigureAudio"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>188</width> + <height>246</height> + </rect> + </property> + <layout class="QVBoxLayout"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Audio</string> + </property> + <layout class="QVBoxLayout"> + <item> + <layout class="QHBoxLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Output Engine:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="output_sink_combo_box"/> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Audio Device:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="audio_device_combo_box"/> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="topMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Volume:</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QSlider" name="volume_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="pageStep"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="volume_indicator"> + <property name="minimumSize"> + <size> + <width>32</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>0 %</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>167</width> + <height>55</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 358f33005..f66abf870 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -21,6 +21,7 @@ void ConfigureDialog::applyConfiguration() { ui->systemTab->applyConfiguration(); ui->inputTab->applyConfiguration(); ui->graphicsTab->applyConfiguration(); + ui->audioTab->applyConfiguration(); ui->debugTab->applyConfiguration(); Settings::Apply(); } diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index cea1a5e62..c581e9699 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -105,6 +105,11 @@ void Config::ReadValues() { Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0); Settings::values.bg_blue = (float)sdl2_config->GetReal("Renderer", "bg_blue", 0.0); + // Audio + Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); + Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); + Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1); + // Data Storage Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 567f23417..6553c7814 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -143,19 +143,17 @@ swap_screen = [Audio] # Which audio output engine to use. -# auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) +# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (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 = - # Which audio device to use. # auto (default): Auto-select output_device = +# Output volume. +# 1.0 (default): 100%, 0.0; mute +volume = + [Data Storage] # Whether to create a virtual SD card. # 1 (default): Yes, 0: No |