Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/duckstation-qt/audiosettingswidget.cpp
7447 views
1
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#include "audiosettingswidget.h"
5
#include "qthost.h"
6
#include "qtutils.h"
7
#include "settingswindow.h"
8
#include "settingwidgetbinder.h"
9
10
#include "core/core.h"
11
#include "core/spu.h"
12
13
#include "util/audio_stream.h"
14
15
#include <cmath>
16
17
#include "moc_audiosettingswidget.cpp"
18
19
AudioSettingsWidget::AudioSettingsWidget(SettingsWindow* dialog, QWidget* parent) : QWidget(parent), m_dialog(dialog)
20
{
21
SettingsInterface* sif = dialog->getSettingsInterface();
22
23
m_ui.setupUi(this);
24
25
SettingWidgetBinder::BindWidgetToEnumSetting(
26
sif, m_ui.audioBackend, "Audio", "Backend", &AudioStream::ParseBackendName, &AudioStream::GetBackendName,
27
&AudioStream::GetBackendDisplayName, AudioStream::DEFAULT_BACKEND, AudioBackend::Count);
28
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.stretchMode, "Audio", "StretchMode",
29
&CoreAudioStream::ParseStretchMode, &CoreAudioStream::GetStretchModeName,
30
&CoreAudioStream::GetStretchModeDisplayName,
31
AudioStreamParameters::DEFAULT_STRETCH_MODE, AudioStretchMode::Count);
32
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.bufferMS, "Audio", "BufferMS",
33
AudioStreamParameters::DEFAULT_BUFFER_MS);
34
QtUtils::BindLabelToSlider(m_ui.bufferMS, m_ui.bufferMSLabel, 1.0f, tr("%1 ms"));
35
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.outputLatencyMS, "Audio", "OutputLatencyMS",
36
AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MS);
37
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.outputLatencyMinimal, "Audio", "OutputLatencyMinimal",
38
AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MINIMAL);
39
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.sequenceLength, "Audio", "StretchSequenceLengthMS",
40
AudioStreamParameters::DEFAULT_STRETCH_SEQUENCE_LENGTH, 0);
41
QtUtils::BindLabelToSlider(m_ui.sequenceLength, m_ui.sequenceLengthLabel, 1.0f, tr("%1 ms"));
42
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.seekWindowSize, "Audio", "StretchSeekWindowMS",
43
AudioStreamParameters::DEFAULT_STRETCH_SEEKWINDOW, 0);
44
QtUtils::BindLabelToSlider(m_ui.seekWindowSize, m_ui.seekWindowSizeLabel, 1.0f, tr("%1 ms"));
45
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overlap, "Audio", "StretchOverlapMS",
46
AudioStreamParameters::DEFAULT_STRETCH_OVERLAP, 0);
47
QtUtils::BindLabelToSlider(m_ui.overlap, m_ui.overlapLabel, 1.0f, tr("%1 ms"));
48
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useQuickSeek, "Audio", "StretchUseQuickSeek",
49
AudioStreamParameters::DEFAULT_STRETCH_USE_QUICKSEEK);
50
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useAAFilter, "Audio", "StretchUseAAFilter",
51
AudioStreamParameters::DEFAULT_STRETCH_USE_AA_FILTER);
52
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.muteCDAudio, "CDROM", "MuteCDAudio", false);
53
54
connect(m_ui.audioBackend, &QComboBox::currentIndexChanged, this, &AudioSettingsWidget::updateDriverNames);
55
connect(m_ui.stretchMode, &QComboBox::currentIndexChanged, this, &AudioSettingsWidget::onStretchModeChanged);
56
connect(m_ui.outputLatencyMS, &QSlider::valueChanged, this, &AudioSettingsWidget::updateLatencyLabel);
57
connect(m_ui.outputLatencyMinimal, &QCheckBox::checkStateChanged, this,
58
[this]() { onMinimalOutputLatencyToggled(); });
59
connect(m_ui.bufferMS, &QSlider::valueChanged, this, &AudioSettingsWidget::updateMinimumLatencyLabel);
60
connect(m_ui.sequenceLength, &QSlider::valueChanged, this, &AudioSettingsWidget::updateMinimumLatencyLabel);
61
62
updateDriverNames();
63
onStretchModeChanged();
64
onMinimalOutputLatencyToggled(); // also calls updateLatencyLabel()
65
66
// for per-game, just use the normal path, since it needs to re-read/apply
67
if (!dialog->isPerGameSettings())
68
{
69
m_ui.volume->setValue(m_dialog->getEffectiveIntValue("Audio", "OutputVolume", 100));
70
m_ui.fastForwardVolume->setValue(m_dialog->getEffectiveIntValue("Audio", "FastForwardVolume", 100));
71
m_ui.muted->setChecked(m_dialog->getEffectiveBoolValue("Audio", "OutputMuted", false));
72
connect(m_ui.volume, &QSlider::valueChanged, this, &AudioSettingsWidget::onOutputVolumeChanged);
73
connect(m_ui.fastForwardVolume, &QSlider::valueChanged, this, &AudioSettingsWidget::onFastForwardVolumeChanged);
74
connect(m_ui.muted, &QCheckBox::checkStateChanged, this, &AudioSettingsWidget::onOutputMutedChanged);
75
updateVolumeLabel();
76
}
77
else
78
{
79
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(sif, m_ui.volume, m_ui.volumeLabel, tr("%"), "Audio",
80
"OutputVolume", 100);
81
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(sif, m_ui.fastForwardVolume, m_ui.fastForwardVolumeLabel,
82
tr("%"), "Audio", "FastForwardVolume", 100);
83
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.muted, "Audio", "OutputMuted", false);
84
}
85
connect(m_ui.resetVolume, &QPushButton::clicked, this, [this]() { resetVolume(false); });
86
connect(m_ui.resetFastForwardVolume, &QPushButton::clicked, this, [this]() { resetVolume(true); });
87
connect(m_ui.resetBufferSize, &QPushButton::clicked, this, &AudioSettingsWidget::onResetBufferSizeClicked);
88
connect(m_ui.resetSequenceLength, &QPushButton::clicked, this,
89
&AudioSettingsWidget::onResetStretchSequenceLengthClicked);
90
connect(m_ui.resetSeekWindowSize, &QPushButton::clicked, this, &AudioSettingsWidget::onResetStretchSeekWindowClicked);
91
connect(m_ui.resetOverlap, &QPushButton::clicked, this, &AudioSettingsWidget::onResetStretchOverlapClicked);
92
93
dialog->registerWidgetHelp(
94
m_ui.audioBackend, tr("Audio Backend"), QStringLiteral("Cubeb"),
95
tr("The audio backend determines how frames produced by the emulator are submitted to the host. Cubeb provides the "
96
"lowest latency, if you encounter issues, try the SDL backend. The null backend disables all host audio "
97
"output."));
98
dialog->registerWidgetHelp(
99
m_ui.bufferMS, tr("Buffer Size"), tr("%1 ms").arg(AudioStreamParameters::DEFAULT_BUFFER_MS),
100
tr("The buffer size determines the size of the chunks of audio which will be pulled by the "
101
"host. Smaller values reduce the output latency, but may cause hitches if the emulation "
102
"speed is inconsistent. Note that the Cubeb backend uses smaller chunks regardless of "
103
"this value, so using a low value here may not significantly change latency."));
104
dialog->registerWidgetHelp(
105
m_ui.outputLatencyMS, tr("Output Latency"), tr("%1 ms").arg(AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MS),
106
tr("Determines how much latency there is between the audio being picked up by the host API, and "
107
"played through speakers."));
108
dialog->registerWidgetHelp(m_ui.outputLatencyMinimal, tr("Minimal Output Latency"), tr("Unchecked"),
109
tr("When enabled, the minimum supported output latency will be used for the host API."));
110
dialog->registerWidgetHelp(m_ui.volume, tr("Output Volume"), "100%",
111
tr("Controls the volume of the audio played on the host."));
112
dialog->registerWidgetHelp(m_ui.fastForwardVolume, tr("Fast Forward Volume"), "100%",
113
tr("Controls the volume of the audio played on the host when fast forwarding."));
114
dialog->registerWidgetHelp(m_ui.muted, tr("Mute All Sound"), tr("Unchecked"),
115
tr("Prevents the emulator from producing any audible sound."));
116
dialog->registerWidgetHelp(m_ui.muteCDAudio, tr("Mute CD Audio"), tr("Unchecked"),
117
tr("Forcibly mutes both CD-DA and XA audio from the CD-ROM. Can be used to disable "
118
"background music in some games."));
119
dialog->registerWidgetHelp(
120
m_ui.stretchMode, tr("Stretch Mode"), tr("Time Stretching"),
121
tr("When running outside of 100% speed, adjusts the tempo on audio instead of dropping frames. Produces "
122
"much nicer fast forward/slowdown audio at a small cost to performance."));
123
dialog->registerWidgetHelp(m_ui.resetVolume, tr("Reset Volume"), tr("N/A"),
124
m_dialog->isPerGameSettings() ? tr("Resets volume back to the global/inherited setting.") :
125
tr("Resets volume back to the default, i.e. full."));
126
dialog->registerWidgetHelp(m_ui.resetFastForwardVolume, tr("Reset Fast Forward Volume"), tr("N/A"),
127
m_dialog->isPerGameSettings() ? tr("Resets volume back to the global/inherited setting.") :
128
tr("Resets volume back to the default, i.e. full."));
129
dialog->registerWidgetHelp(m_ui.sequenceLength, tr("Stretch Sequence Length"),
130
tr("%1 ms").arg(AudioStreamParameters::DEFAULT_STRETCH_SEQUENCE_LENGTH),
131
tr("Determines how long individual sequences are when the time-stretch algorithm chops "
132
"the audio. Longer sequences can improve quality but increase latency."));
133
dialog->registerWidgetHelp(
134
m_ui.seekWindowSize, tr("Stretch Seek Window"), tr("%1 ms").arg(AudioStreamParameters::DEFAULT_STRETCH_SEEKWINDOW),
135
tr("Controls how wide a window the algorithm searches for the best overlap position when joining "
136
"consecutive sequences. Larger windows may yield better joins at the cost of increased CPU work."));
137
dialog->registerWidgetHelp(m_ui.overlap, tr("Stretch Overlap Length"),
138
tr("%1 ms").arg(AudioStreamParameters::DEFAULT_STRETCH_OVERLAP),
139
tr("Specifies how long two consecutive sequences are overlapped when mixed back together. "
140
"Greater overlap can make transitions smoother but increases latency."));
141
dialog->registerWidgetHelp(m_ui.useQuickSeek, tr("Enable Quick Seek"),
142
AudioStreamParameters::DEFAULT_STRETCH_USE_QUICKSEEK ? tr("Checked") : tr("Unchecked"),
143
tr("Enables the quick seeking algorithm in the time-stretch routine. Reduces CPU usage at "
144
"a minor cost to audio quality."));
145
dialog->registerWidgetHelp(m_ui.useAAFilter, tr("Enable Anti-Alias Filter"),
146
AudioStreamParameters::DEFAULT_STRETCH_USE_AA_FILTER ? tr("Checked") : tr("Unchecked"),
147
tr("Enables an anti-aliasing filter used by the pitch transposer. Disabling it may reduce "
148
"quality when pitch shifting but can slightly reduce CPU usage."));
149
dialog->registerWidgetHelp(m_ui.resetSequenceLength, tr("Reset Sequence Length"), tr("N/A"),
150
m_dialog->isPerGameSettings() ? tr("Resets value back to the global/inherited setting.") :
151
tr("Resets value back to the default."));
152
dialog->registerWidgetHelp(m_ui.resetSeekWindowSize, tr("Reset Seek Window"), tr("N/A"),
153
m_dialog->isPerGameSettings() ? tr("Resets value back to the global/inherited setting.") :
154
tr("Resets value back to the default."));
155
dialog->registerWidgetHelp(m_ui.resetOverlap, tr("Reset Overlap"), tr("N/A"),
156
m_dialog->isPerGameSettings() ? tr("Resets value back to the global/inherited setting.") :
157
tr("Resets value back to the default."));
158
}
159
160
AudioSettingsWidget::~AudioSettingsWidget() = default;
161
162
void AudioSettingsWidget::onStretchModeChanged()
163
{
164
const AudioStretchMode stretch_mode =
165
CoreAudioStream::ParseStretchMode(
166
m_dialog
167
->getEffectiveStringValue("Audio", "StretchMode",
168
CoreAudioStream::GetStretchModeName(AudioStreamParameters::DEFAULT_STRETCH_MODE))
169
.c_str())
170
.value_or(AudioStreamParameters::DEFAULT_STRETCH_MODE);
171
m_ui.timeStretchGroup->setEnabled(stretch_mode == AudioStretchMode::TimeStretch);
172
updateMinimumLatencyLabel();
173
}
174
175
AudioBackend AudioSettingsWidget::getEffectiveBackend() const
176
{
177
return AudioStream::ParseBackendName(
178
m_dialog
179
->getEffectiveStringValue("Audio", "Backend", AudioStream::GetBackendName(AudioStream::DEFAULT_BACKEND))
180
.c_str())
181
.value_or(AudioStream::DEFAULT_BACKEND);
182
}
183
184
void AudioSettingsWidget::updateDriverNames()
185
{
186
const AudioBackend backend = getEffectiveBackend();
187
std::vector<std::pair<std::string, std::string>> names = AudioStream::GetDriverNames(backend);
188
189
SettingWidgetBinder::DisconnectWidget(m_ui.driver);
190
m_ui.driver->clear();
191
if (names.empty())
192
{
193
m_ui.driver->addItem(tr("Default"));
194
m_ui.driver->setVisible(false);
195
196
// I hate this so much but it's the only way to stop Qt leaving a gap on the edge.
197
// Of course could use a nested layout, but that breaks on MacOS.
198
m_ui.configurationLayout->removeWidget(m_ui.driver);
199
m_ui.configurationLayout->removeWidget(m_ui.audioBackend);
200
m_ui.configurationLayout->addWidget(m_ui.audioBackend, 0, 1, 1, 2);
201
}
202
else
203
{
204
m_ui.driver->setVisible(true);
205
m_ui.configurationLayout->removeWidget(m_ui.audioBackend);
206
m_ui.configurationLayout->removeWidget(m_ui.driver);
207
m_ui.configurationLayout->addWidget(m_ui.audioBackend, 0, 1, 1, 1);
208
m_ui.configurationLayout->addWidget(m_ui.driver, 0, 2, 1, 1);
209
210
for (const auto& [name, display_name] : names)
211
m_ui.driver->addItem(QString::fromStdString(display_name), QString::fromStdString(name));
212
213
SettingWidgetBinder::BindWidgetToStringSetting(m_dialog->getSettingsInterface(), m_ui.driver, "Audio", "Driver",
214
std::move(names.front().first));
215
connect(m_ui.driver, &QComboBox::currentIndexChanged, this, &AudioSettingsWidget::queueUpdateDeviceNames);
216
}
217
218
queueUpdateDeviceNames();
219
}
220
221
void AudioSettingsWidget::queueUpdateDeviceNames()
222
{
223
SettingWidgetBinder::DisconnectWidget(m_ui.outputDevice);
224
m_ui.outputDevice->clear();
225
m_ui.outputDevice->setEnabled(false);
226
m_output_device_latency = 0;
227
228
const AudioBackend backend = getEffectiveBackend();
229
std::string driver_name = m_dialog->getEffectiveStringValue("Audio", "Driver");
230
QtAsyncTask::create(this, [this, driver_name = std::move(driver_name), backend]() {
231
std::vector<AudioStream::DeviceInfo> devices =
232
AudioStream::GetOutputDevices(backend, driver_name, SPU::SAMPLE_RATE);
233
return [this, devices = std::move(devices), driver_name = std::move(driver_name), backend]() {
234
// just in case we executed out of order...
235
if (backend != getEffectiveBackend() || driver_name != m_dialog->getEffectiveStringValue("Audio", "Driver"))
236
return;
237
238
if (devices.empty())
239
{
240
m_ui.outputDevice->addItem(tr("Default"));
241
}
242
else
243
{
244
const std::string current_device = m_dialog->getEffectiveStringValue("Audio", "Device");
245
246
m_ui.outputDevice->setEnabled(true);
247
248
bool is_known_device = false;
249
for (const AudioStream::DeviceInfo& di : devices)
250
{
251
m_ui.outputDevice->addItem(QString::fromStdString(di.display_name), QString::fromStdString(di.name));
252
if (di.name == current_device)
253
{
254
m_output_device_latency = di.minimum_latency_frames;
255
is_known_device = true;
256
}
257
}
258
259
if (!is_known_device)
260
{
261
m_ui.outputDevice->addItem(tr("Unknown Device \"%1\"").arg(QString::fromStdString(current_device)),
262
QString::fromStdString(current_device));
263
}
264
265
SettingWidgetBinder::BindWidgetToStringSetting(m_dialog->getSettingsInterface(), m_ui.outputDevice, "Audio",
266
"OutputDevice", std::move(devices.front().name));
267
}
268
269
updateMinimumLatencyLabel();
270
};
271
});
272
}
273
274
void AudioSettingsWidget::updateLatencyLabel()
275
{
276
const bool minimal_output_latency = m_dialog->getEffectiveBoolValue(
277
"Audio", "OutputLatencyMinimal", AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MINIMAL);
278
const int config_output_latency_ms =
279
minimal_output_latency ?
280
0 :
281
m_dialog->getEffectiveIntValue("Audio", "OutputLatencyMS", AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MS);
282
283
m_ui.outputLatencyLabel->setText(minimal_output_latency ? tr("N/A") : tr("%1 ms").arg(config_output_latency_ms));
284
285
updateMinimumLatencyLabel();
286
}
287
288
void AudioSettingsWidget::updateMinimumLatencyLabel()
289
{
290
const AudioStretchMode stretch_mode =
291
CoreAudioStream::ParseStretchMode(m_dialog->getEffectiveStringValue("Audio", "StretchMode").c_str())
292
.value_or(AudioStreamParameters::DEFAULT_STRETCH_MODE);
293
const bool minimal_output_latency = m_dialog->getEffectiveBoolValue(
294
"Audio", "OutputLatencyMinimal", AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MINIMAL);
295
const int config_buffer_ms =
296
m_dialog->getEffectiveIntValue("Audio", "BufferMS", AudioStreamParameters::DEFAULT_BUFFER_MS);
297
const int config_output_latency_ms =
298
minimal_output_latency ?
299
0 :
300
m_dialog->getEffectiveIntValue("Audio", "OutputLatencyMS", AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MS);
301
const int stretch_sequence_length_ms =
302
(stretch_mode == AudioStretchMode::TimeStretch) ?
303
m_dialog->getEffectiveIntValue("Audio", "StretchSequenceLengthMS",
304
AudioStreamParameters::DEFAULT_STRETCH_SEQUENCE_LENGTH) :
305
0;
306
307
const int output_latency_ms =
308
minimal_output_latency ?
309
static_cast<int>(CoreAudioStream::GetMSForBufferSize(SPU::SAMPLE_RATE, m_output_device_latency)) :
310
config_output_latency_ms;
311
const int total_latency_ms = stretch_sequence_length_ms + config_buffer_ms + output_latency_ms;
312
if (output_latency_ms > 0)
313
{
314
if (stretch_sequence_length_ms > 0)
315
{
316
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms stretch + %3 ms buffer + %4 ms output)")
317
.arg(total_latency_ms)
318
.arg(stretch_sequence_length_ms)
319
.arg(config_buffer_ms)
320
.arg(output_latency_ms));
321
}
322
else
323
{
324
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms buffer + %3 ms output)")
325
.arg(total_latency_ms)
326
.arg(config_buffer_ms)
327
.arg(output_latency_ms));
328
}
329
}
330
else
331
{
332
if (stretch_sequence_length_ms > 0)
333
{
334
m_ui.bufferingLabel->setText(
335
tr("Maximum Latency: %1 ms (%2 ms stretch + %3 ms buffer, minimum output latency unknown)")
336
.arg(total_latency_ms)
337
.arg(stretch_sequence_length_ms)
338
.arg(config_buffer_ms));
339
}
340
else
341
{
342
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (minimum output latency unknown)").arg(config_buffer_ms));
343
}
344
}
345
}
346
347
void AudioSettingsWidget::updateVolumeLabel()
348
{
349
m_ui.volumeLabel->setText(tr("%1%").arg(m_ui.volume->value()));
350
m_ui.fastForwardVolumeLabel->setText(tr("%1%").arg(m_ui.fastForwardVolume->value()));
351
}
352
353
void AudioSettingsWidget::onMinimalOutputLatencyToggled()
354
{
355
const bool minimal = m_dialog->getEffectiveBoolValue("Audio", "OutputLatencyMinimal", false);
356
m_ui.outputLatencyMS->setEnabled(!minimal);
357
updateLatencyLabel();
358
}
359
360
void AudioSettingsWidget::onOutputVolumeChanged(int new_value)
361
{
362
// only called for base settings
363
DebugAssert(!m_dialog->isPerGameSettings());
364
Core::SetBaseIntSettingValue("Audio", "OutputVolume", new_value);
365
Host::CommitBaseSettingChanges();
366
g_core_thread->setAudioOutputVolume(new_value, m_ui.fastForwardVolume->value());
367
368
updateVolumeLabel();
369
}
370
371
void AudioSettingsWidget::onFastForwardVolumeChanged(int new_value)
372
{
373
// only called for base settings
374
DebugAssert(!m_dialog->isPerGameSettings());
375
Core::SetBaseIntSettingValue("Audio", "FastForwardVolume", new_value);
376
Host::CommitBaseSettingChanges();
377
g_core_thread->setAudioOutputVolume(m_ui.volume->value(), new_value);
378
379
updateVolumeLabel();
380
}
381
382
void AudioSettingsWidget::onOutputMutedChanged(int new_state)
383
{
384
// only called for base settings
385
DebugAssert(!m_dialog->isPerGameSettings());
386
387
const bool muted = (new_state != 0);
388
Core::SetBaseBoolSettingValue("Audio", "OutputMuted", muted);
389
Host::CommitBaseSettingChanges();
390
g_core_thread->setAudioOutputMuted(muted);
391
}
392
393
void AudioSettingsWidget::resetVolume(bool fast_forward)
394
{
395
const char* key = fast_forward ? "FastForwardVolume" : "OutputVolume";
396
QSlider* const slider = fast_forward ? m_ui.fastForwardVolume : m_ui.volume;
397
QLabel* const label = fast_forward ? m_ui.fastForwardVolumeLabel : m_ui.volumeLabel;
398
399
if (m_dialog->isPerGameSettings())
400
{
401
m_dialog->removeSettingValue("Audio", key);
402
403
const int value = m_dialog->getEffectiveIntValue("Audio", key, 100);
404
QSignalBlocker sb(slider);
405
slider->setValue(value);
406
label->setText(QStringLiteral("%1%2").arg(value).arg(tr("%")));
407
408
// remove bold font if it was previously overridden
409
QFont font(label->font());
410
font.setBold(false);
411
label->setFont(font);
412
}
413
else
414
{
415
slider->setValue(100);
416
}
417
}
418
419
void AudioSettingsWidget::onResetBufferSizeClicked()
420
{
421
m_dialog->setIntSettingValue(
422
"Audio", "BufferMS",
423
m_dialog->isPerGameSettings() ? std::nullopt : std::optional<int>(AudioStreamParameters::DEFAULT_BUFFER_MS));
424
SettingWidgetBinder::DisconnectWidget(m_ui.bufferMS);
425
SettingWidgetBinder::BindWidgetToIntSetting(m_dialog->getSettingsInterface(), m_ui.bufferMS, "Audio", "BufferMS",
426
AudioStreamParameters::DEFAULT_BUFFER_MS);
427
QtUtils::BindLabelToSlider(m_ui.bufferMS, m_ui.bufferMSLabel, 1.0f, tr("%1 ms"));
428
connect(m_ui.bufferMS, &QSlider::valueChanged, this, &AudioSettingsWidget::updateMinimumLatencyLabel);
429
updateMinimumLatencyLabel();
430
}
431
432
void AudioSettingsWidget::onResetStretchSequenceLengthClicked()
433
{
434
m_dialog->setIntSettingValue("Audio", "StretchSequenceLengthMS",
435
m_dialog->isPerGameSettings() ?
436
std::nullopt :
437
std::optional<int>(AudioStreamParameters::DEFAULT_STRETCH_SEQUENCE_LENGTH));
438
439
SettingWidgetBinder::DisconnectWidget(m_ui.sequenceLength);
440
SettingWidgetBinder::BindWidgetToIntSetting(m_dialog->getSettingsInterface(), m_ui.sequenceLength, "Audio",
441
"StretchSequenceLengthMS",
442
AudioStreamParameters::DEFAULT_STRETCH_SEQUENCE_LENGTH, 0);
443
QtUtils::BindLabelToSlider(m_ui.sequenceLength, m_ui.sequenceLengthLabel, 1.0f, tr("%1 ms"));
444
connect(m_ui.sequenceLength, &QSlider::valueChanged, this, &AudioSettingsWidget::updateMinimumLatencyLabel);
445
updateMinimumLatencyLabel();
446
}
447
448
void AudioSettingsWidget::onResetStretchSeekWindowClicked()
449
{
450
m_dialog->setIntSettingValue("Audio", "StretchSeekWindowMS",
451
m_dialog->isPerGameSettings() ?
452
std::nullopt :
453
std::optional<int>(AudioStreamParameters::DEFAULT_STRETCH_SEEKWINDOW));
454
455
SettingWidgetBinder::DisconnectWidget(m_ui.seekWindowSize);
456
SettingWidgetBinder::BindWidgetToIntSetting(m_dialog->getSettingsInterface(), m_ui.seekWindowSize, "Audio",
457
"StretchSeekWindowMS", AudioStreamParameters::DEFAULT_STRETCH_SEEKWINDOW,
458
0);
459
QtUtils::BindLabelToSlider(m_ui.seekWindowSize, m_ui.seekWindowSizeLabel, 1.0f, tr("%1 ms"));
460
}
461
462
void AudioSettingsWidget::onResetStretchOverlapClicked()
463
{
464
m_dialog->setIntSettingValue(
465
"Audio", "StretchOverlapMS",
466
m_dialog->isPerGameSettings() ? std::nullopt : std::optional<int>(AudioStreamParameters::DEFAULT_STRETCH_OVERLAP));
467
468
SettingWidgetBinder::DisconnectWidget(m_ui.overlap);
469
SettingWidgetBinder::BindWidgetToIntSetting(m_dialog->getSettingsInterface(), m_ui.overlap, "Audio",
470
"StretchOverlapMS", AudioStreamParameters::DEFAULT_STRETCH_OVERLAP, 0);
471
QtUtils::BindLabelToSlider(m_ui.overlap, m_ui.overlapLabel, 1.0f, tr("%1 ms"));
472
}
473
474