summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_out.cpp5
-rw-r--r--src/audio_core/stream.cpp35
-rw-r--r--src/core/settings.h5
-rw-r--r--src/yuzu/CMakeLists.txt3
-rw-r--r--src/yuzu/configuration/config.cpp13
-rw-r--r--src/yuzu/configuration/configure.ui21
-rw-r--r--src/yuzu/configuration/configure_audio.cpp90
-rw-r--r--src/yuzu/configuration/configure_audio.h31
-rw-r--r--src/yuzu/configuration/configure_audio.ui130
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp1
-rw-r--r--src/yuzu_cmd/config.cpp5
-rw-r--r--src/yuzu_cmd/default_ini.h12
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 @@
7#include "audio_core/sink_details.h" 7#include "audio_core/sink_details.h"
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/settings.h"
10 11
11namespace AudioCore { 12namespace AudioCore {
12 13
@@ -29,8 +30,8 @@ static Stream::Format ChannelsToStreamFormat(u32 num_channels) {
29StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, 30StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels,
30 Stream::ReleaseCallback&& release_callback) { 31 Stream::ReleaseCallback&& release_callback) {
31 if (!sink) { 32 if (!sink) {
32 const SinkDetails& sink_details = GetSinkDetails("auto"); 33 const SinkDetails& sink_details = GetSinkDetails(Settings::values.sink_id);
33 sink = sink_details.factory(""); 34 sink = sink_details.factory(Settings::values.audio_device_id);
34 } 35 }
35 36
36 return std::make_shared<Stream>(sample_rate, ChannelsToStreamFormat(num_channels), 37 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 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h" 5#include <algorithm>
6#include "common/logging/log.h" 6#include <cmath>
7#include "core/core_timing.h"
8#include "core/core_timing_util.h"
9 7
10#include "audio_core/sink.h" 8#include "audio_core/sink.h"
11#include "audio_core/sink_details.h" 9#include "audio_core/sink_details.h"
12#include "audio_core/stream.h" 10#include "audio_core/stream.h"
11#include "common/assert.h"
12#include "common/logging/log.h"
13#include "core/core_timing.h"
14#include "core/core_timing_util.h"
15#include "core/settings.h"
13 16
14namespace AudioCore { 17namespace AudioCore {
15 18
@@ -56,6 +59,24 @@ s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
56 return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate); 59 return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
57} 60}
58 61
62static std::vector<s16> GetVolumeAdjustedSamples(const std::vector<u8>& data) {
63 std::vector<s16> samples(data.size() / sizeof(s16));
64 std::memcpy(samples.data(), data.data(), data.size());
65 const float volume{std::clamp(Settings::values.volume, 0.0f, 1.0f)};
66
67 if (volume == 1.0f) {
68 return samples;
69 }
70
71 // Implementation of a volume slider with a dynamic range of 60 dB
72 const float volume_scale_factor{std::exp(6.90775f * volume) * 0.001f};
73 for (auto& sample : samples) {
74 sample = static_cast<s16>(sample * volume_scale_factor);
75 }
76
77 return samples;
78}
79
59void Stream::PlayNextBuffer() { 80void Stream::PlayNextBuffer() {
60 if (!IsPlaying()) { 81 if (!IsPlaying()) {
61 // Ensure we are in playing state before playing the next buffer 82 // Ensure we are in playing state before playing the next buffer
@@ -75,9 +96,9 @@ void Stream::PlayNextBuffer() {
75 active_buffer = queued_buffers.front(); 96 active_buffer = queued_buffers.front();
76 queued_buffers.pop(); 97 queued_buffers.pop();
77 98
78 sink_stream.EnqueueSamples(GetNumChannels(), 99 const size_t sample_count{active_buffer->GetData().size() / GetSampleSize()};
79 reinterpret_cast<const s16*>(active_buffer->GetData().data()), 100 sink_stream.EnqueueSamples(
80 active_buffer->GetData().size() / GetSampleSize()); 101 GetNumChannels(), GetVolumeAdjustedSamples(active_buffer->GetData()).data(), sample_count);
81 102
82 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); 103 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
83} 104}
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 {
137 137
138 std::string log_filter; 138 std::string log_filter;
139 139
140 // Audio
141 std::string sink_id;
142 std::string audio_device_id;
143 float volume;
144
140 // Debugging 145 // Debugging
141 bool use_gdbstub; 146 bool use_gdbstub;
142 u16 gdbstub_port; 147 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
11 bootmanager.h 11 bootmanager.h
12 configuration/config.cpp 12 configuration/config.cpp
13 configuration/config.h 13 configuration/config.h
14 configuration/configure_audio.cpp
15 configuration/configure_audio.h
14 configuration/configure_debug.cpp 16 configuration/configure_debug.cpp
15 configuration/configure_debug.h 17 configuration/configure_debug.h
16 configuration/configure_dialog.cpp 18 configuration/configure_dialog.cpp
@@ -55,6 +57,7 @@ add_executable(yuzu
55set(UIS 57set(UIS
56 aboutdialog.ui 58 aboutdialog.ui
57 configuration/configure.ui 59 configuration/configure.ui
60 configuration/configure_audio.ui
58 configuration/configure_debug.ui 61 configuration/configure_debug.ui
59 configuration/configure_general.ui 62 configuration/configure_general.ui
60 configuration/configure_graphics.ui 63 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() {
92 Settings::values.bg_blue = qt_config->value("bg_blue", 0.0).toFloat(); 92 Settings::values.bg_blue = qt_config->value("bg_blue", 0.0).toFloat();
93 qt_config->endGroup(); 93 qt_config->endGroup();
94 94
95 qt_config->beginGroup("Audio");
96 Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
97 Settings::values.audio_device_id =
98 qt_config->value("output_device", "auto").toString().toStdString();
99 Settings::values.volume = qt_config->value("volume", 1).toFloat();
100 qt_config->endGroup();
101
95 qt_config->beginGroup("Data Storage"); 102 qt_config->beginGroup("Data Storage");
96 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); 103 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
97 qt_config->endGroup(); 104 qt_config->endGroup();
@@ -195,6 +202,12 @@ void Config::SaveValues() {
195 qt_config->setValue("bg_blue", (double)Settings::values.bg_blue); 202 qt_config->setValue("bg_blue", (double)Settings::values.bg_blue);
196 qt_config->endGroup(); 203 qt_config->endGroup();
197 204
205 qt_config->beginGroup("Audio");
206 qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
207 qt_config->setValue("output_device", QString::fromStdString(Settings::values.audio_device_id));
208 qt_config->setValue("volume", Settings::values.volume);
209 qt_config->endGroup();
210
198 qt_config->beginGroup("Data Storage"); 211 qt_config->beginGroup("Data Storage");
199 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); 212 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
200 qt_config->endGroup(); 213 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 @@
34 <string>Input</string> 34 <string>Input</string>
35 </attribute> 35 </attribute>
36 </widget> 36 </widget>
37 <widget class="ConfigureGraphics" name="graphicsTab"> 37 <widget class="ConfigureGraphics" name="graphicsTab">
38 <attribute name="title"> 38 <attribute name="title">
39 <string>Graphics</string> 39 <string>Graphics</string>
40 </attribute> 40 </attribute>
41 </widget> 41 </widget>
42 <widget class="ConfigureAudio" name="audioTab">
43 <attribute name="title">
44 <string>Audio</string>
45 </attribute>
46 </widget>
42 <widget class="ConfigureDebug" name="debugTab"> 47 <widget class="ConfigureDebug" name="debugTab">
43 <attribute name="title"> 48 <attribute name="title">
44 <string>Debug</string> 49 <string>Debug</string>
@@ -69,6 +74,12 @@
69 <container>1</container> 74 <container>1</container>
70 </customwidget> 75 </customwidget>
71 <customwidget> 76 <customwidget>
77 <class>ConfigureAudio</class>
78 <extends>QWidget</extends>
79 <header>configuration/configure_audio.h</header>
80 <container>1</container>
81 </customwidget>
82 <customwidget>
72 <class>ConfigureDebug</class> 83 <class>ConfigureDebug</class>
73 <extends>QWidget</extends> 84 <extends>QWidget</extends>
74 <header>configuration/configure_debug.h</header> 85 <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 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <memory>
6
7#include "audio_core/sink.h"
8#include "audio_core/sink_details.h"
9#include "core/core.h"
10#include "core/settings.h"
11#include "ui_configure_audio.h"
12#include "yuzu/configuration/configure_audio.h"
13
14ConfigureAudio::ConfigureAudio(QWidget* parent)
15 : QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()) {
16 ui->setupUi(this);
17
18 ui->output_sink_combo_box->clear();
19 ui->output_sink_combo_box->addItem("auto");
20 for (const auto& sink_detail : AudioCore::g_sink_details) {
21 ui->output_sink_combo_box->addItem(sink_detail.id);
22 }
23
24 connect(ui->volume_slider, &QSlider::valueChanged, [this] {
25 ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition()));
26 });
27
28 this->setConfiguration();
29 connect(ui->output_sink_combo_box,
30 static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
31 &ConfigureAudio::updateAudioDevices);
32
33 ui->output_sink_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
34 ui->audio_device_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
35}
36
37ConfigureAudio::~ConfigureAudio() = default;
38
39void ConfigureAudio::setConfiguration() {
40 int new_sink_index = 0;
41 for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
42 if (ui->output_sink_combo_box->itemText(index).toStdString() == Settings::values.sink_id) {
43 new_sink_index = index;
44 break;
45 }
46 }
47 ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
48
49 // The device list cannot be pre-populated (nor listed) until the output sink is known.
50 updateAudioDevices(new_sink_index);
51
52 int new_device_index = -1;
53 for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
54 if (ui->audio_device_combo_box->itemText(index).toStdString() ==
55 Settings::values.audio_device_id) {
56 new_device_index = index;
57 break;
58 }
59 }
60 ui->audio_device_combo_box->setCurrentIndex(new_device_index);
61
62 ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
63 ui->volume_indicator->setText(tr("%1 %").arg(ui->volume_slider->sliderPosition()));
64}
65
66void ConfigureAudio::applyConfiguration() {
67 Settings::values.sink_id =
68 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
69 .toStdString();
70 Settings::values.audio_device_id =
71 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
72 .toStdString();
73 Settings::values.volume =
74 static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
75}
76
77void ConfigureAudio::updateAudioDevices(int sink_index) {
78 ui->audio_device_combo_box->clear();
79 ui->audio_device_combo_box->addItem(AudioCore::auto_device_name);
80
81 std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
82 std::vector<std::string> device_list = AudioCore::GetSinkDetails(sink_id).list_devices();
83 for (const auto& device : device_list) {
84 ui->audio_device_combo_box->addItem(device.c_str());
85 }
86}
87
88void ConfigureAudio::retranslateUi() {
89 ui->retranslateUi(this);
90}
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 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9
10namespace Ui {
11class ConfigureAudio;
12}
13
14class ConfigureAudio : public QWidget {
15 Q_OBJECT
16
17public:
18 explicit ConfigureAudio(QWidget* parent = nullptr);
19 ~ConfigureAudio();
20
21 void applyConfiguration();
22 void retranslateUi();
23
24public slots:
25 void updateAudioDevices(int sink_index);
26
27private:
28 void setConfiguration();
29
30 std::unique_ptr<Ui::ConfigureAudio> ui;
31};
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 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureAudio</class>
4 <widget class="QWidget" name="ConfigureAudio">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>188</width>
10 <height>246</height>
11 </rect>
12 </property>
13 <layout class="QVBoxLayout">
14 <item>
15 <widget class="QGroupBox" name="groupBox">
16 <property name="title">
17 <string>Audio</string>
18 </property>
19 <layout class="QVBoxLayout">
20 <item>
21 <layout class="QHBoxLayout">
22 <item>
23 <widget class="QLabel" name="label">
24 <property name="text">
25 <string>Output Engine:</string>
26 </property>
27 </widget>
28 </item>
29 <item>
30 <widget class="QComboBox" name="output_sink_combo_box"/>
31 </item>
32 </layout>
33 </item>
34 <item>
35 <layout class="QHBoxLayout">
36 <item>
37 <widget class="QLabel" name="label">
38 <property name="text">
39 <string>Audio Device:</string>
40 </property>
41 </widget>
42 </item>
43 <item>
44 <widget class="QComboBox" name="audio_device_combo_box"/>
45 </item>
46 </layout>
47 </item>
48 <item>
49 <layout class="QHBoxLayout" name="horizontalLayout_2">
50 <property name="topMargin">
51 <number>0</number>
52 </property>
53 <item>
54 <widget class="QLabel" name="label">
55 <property name="text">
56 <string>Volume:</string>
57 </property>
58 </widget>
59 </item>
60 <item>
61 <spacer name="horizontalSpacer">
62 <property name="orientation">
63 <enum>Qt::Horizontal</enum>
64 </property>
65 <property name="sizeHint" stdset="0">
66 <size>
67 <width>40</width>
68 <height>20</height>
69 </size>
70 </property>
71 </spacer>
72 </item>
73 <item>
74 <widget class="QSlider" name="volume_slider">
75 <property name="sizePolicy">
76 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
77 <horstretch>0</horstretch>
78 <verstretch>0</verstretch>
79 </sizepolicy>
80 </property>
81 <property name="maximum">
82 <number>100</number>
83 </property>
84 <property name="pageStep">
85 <number>10</number>
86 </property>
87 <property name="orientation">
88 <enum>Qt::Horizontal</enum>
89 </property>
90 </widget>
91 </item>
92 <item>
93 <widget class="QLabel" name="volume_indicator">
94 <property name="minimumSize">
95 <size>
96 <width>32</width>
97 <height>0</height>
98 </size>
99 </property>
100 <property name="text">
101 <string>0 %</string>
102 </property>
103 <property name="alignment">
104 <set>Qt::AlignCenter</set>
105 </property>
106 </widget>
107 </item>
108 </layout>
109 </item>
110 </layout>
111 </widget>
112 </item>
113 <item>
114 <spacer>
115 <property name="orientation">
116 <enum>Qt::Vertical</enum>
117 </property>
118 <property name="sizeHint" stdset="0">
119 <size>
120 <width>167</width>
121 <height>55</height>
122 </size>
123 </property>
124 </spacer>
125 </item>
126 </layout>
127 </widget>
128 <resources/>
129 <connections/>
130</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() {
21 ui->systemTab->applyConfiguration(); 21 ui->systemTab->applyConfiguration();
22 ui->inputTab->applyConfiguration(); 22 ui->inputTab->applyConfiguration();
23 ui->graphicsTab->applyConfiguration(); 23 ui->graphicsTab->applyConfiguration();
24 ui->audioTab->applyConfiguration();
24 ui->debugTab->applyConfiguration(); 25 ui->debugTab->applyConfiguration();
25 Settings::Apply(); 26 Settings::Apply();
26} 27}
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() {
105 Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0); 105 Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 0.0);
106 Settings::values.bg_blue = (float)sdl2_config->GetReal("Renderer", "bg_blue", 0.0); 106 Settings::values.bg_blue = (float)sdl2_config->GetReal("Renderer", "bg_blue", 0.0);
107 107
108 // Audio
109 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
110 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
111 Settings::values.volume = sdl2_config->GetReal("Audio", "volume", 1);
112
108 // Data Storage 113 // Data Storage
109 Settings::values.use_virtual_sd = 114 Settings::values.use_virtual_sd =
110 sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); 115 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 =
143 143
144[Audio] 144[Audio]
145# Which audio output engine to use. 145# Which audio output engine to use.
146# auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) 146# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available)
147output_engine = 147output_engine =
148 148
149# Whether or not to enable the audio-stretching post-processing effect.
150# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter,
151# at the cost of increasing audio latency.
152# 0: No, 1 (default): Yes
153enable_audio_stretching =
154
155# Which audio device to use. 149# Which audio device to use.
156# auto (default): Auto-select 150# auto (default): Auto-select
157output_device = 151output_device =
158 152
153# Output volume.
154# 1.0 (default): 100%, 0.0; mute
155volume =
156
159[Data Storage] 157[Data Storage]
160# Whether to create a virtual SD card. 158# Whether to create a virtual SD card.
161# 1 (default): Yes, 0: No 159# 1 (default): Yes, 0: No