Merge pull request #3831 from FearlessTobi/add-volume-slider
citra_qt: Add a volume slider
This commit is contained in:
commit
2f8c9c8126
9 changed files with 110 additions and 20 deletions
|
@ -7,6 +7,7 @@
|
||||||
#include "audio_core/sink.h"
|
#include "audio_core/sink.h"
|
||||||
#include "audio_core/sink_details.h"
|
#include "audio_core/sink_details.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
|
||||||
|
@ -39,10 +40,17 @@ void DspInterface::EnableStretching(bool enable) {
|
||||||
perform_time_stretching = enable;
|
perform_time_stretching = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspInterface::OutputFrame(const StereoFrame16& frame) {
|
void DspInterface::OutputFrame(StereoFrame16& frame) {
|
||||||
if (!sink)
|
if (!sink)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Implementation of the hardware volume slider with a dynamic range of 60 dB
|
||||||
|
float volume_scale_factor = std::exp(6.90775 * Settings::values.volume) * 0.001;
|
||||||
|
for (size_t i = 0; i < frame.size(); i++) {
|
||||||
|
frame[i][0] = static_cast<s16>(frame[i][0] * volume_scale_factor);
|
||||||
|
frame[i][1] = static_cast<s16>(frame[i][1] * volume_scale_factor);
|
||||||
|
}
|
||||||
|
|
||||||
if (perform_time_stretching) {
|
if (perform_time_stretching) {
|
||||||
time_stretcher.AddSamples(&frame[0][0], frame.size());
|
time_stretcher.AddSamples(&frame[0][0], frame.size());
|
||||||
std::vector<s16> stretched_samples = time_stretcher.Process(sink->SamplesInQueue());
|
std::vector<s16> stretched_samples = time_stretcher.Process(sink->SamplesInQueue());
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
void EnableStretching(bool enable);
|
void EnableStretching(bool enable);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OutputFrame(const StereoFrame16& frame);
|
void OutputFrame(StereoFrame16& frame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FlushResidualStretcherAudio();
|
void FlushResidualStretcherAudio();
|
||||||
|
|
|
@ -143,6 +143,7 @@ void Config::ReadValues() {
|
||||||
Settings::values.enable_audio_stretching =
|
Settings::values.enable_audio_stretching =
|
||||||
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
|
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);
|
||||||
|
|
||||||
// Data Storage
|
// Data Storage
|
||||||
Settings::values.use_virtual_sd =
|
Settings::values.use_virtual_sd =
|
||||||
|
|
|
@ -164,6 +164,10 @@ enable_audio_stretching =
|
||||||
# auto (default): Auto-select
|
# auto (default): Auto-select
|
||||||
output_device =
|
output_device =
|
||||||
|
|
||||||
|
# Output volume.
|
||||||
|
# 1.0 (default): 100%, 0.0; mute
|
||||||
|
volume =
|
||||||
|
|
||||||
[Data Storage]
|
[Data Storage]
|
||||||
# Whether to create a virtual SD card.
|
# Whether to create a virtual SD card.
|
||||||
# 1 (default): Yes, 0: No
|
# 1 (default): Yes, 0: No
|
||||||
|
|
|
@ -122,6 +122,7 @@ void Config::ReadValues() {
|
||||||
qt_config->value("enable_audio_stretching", true).toBool();
|
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();
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
using namespace Service::CAM;
|
using namespace Service::CAM;
|
||||||
|
@ -344,6 +345,7 @@ void Config::SaveValues() {
|
||||||
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("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->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
using namespace Service::CAM;
|
using namespace Service::CAM;
|
||||||
|
|
|
@ -19,6 +19,10 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
|
||||||
ui->output_sink_combo_box->addItem(sink_detail.id);
|
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();
|
this->setConfiguration();
|
||||||
connect(ui->output_sink_combo_box,
|
connect(ui->output_sink_combo_box,
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||||
|
@ -51,6 +55,9 @@ void ConfigureAudio::setConfiguration() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui->audio_device_combo_box->setCurrentIndex(new_device_index);
|
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() {
|
void ConfigureAudio::applyConfiguration() {
|
||||||
|
@ -61,6 +68,8 @@ void ConfigureAudio::applyConfiguration() {
|
||||||
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();
|
||||||
|
Settings::values.volume =
|
||||||
|
static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureAudio::updateAudioDevices(int sink_index) {
|
void ConfigureAudio::updateAudioDevices(int sink_index) {
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ConfigureAudio</class>
|
<class>ConfigureAudio</class>
|
||||||
<widget class="QWidget" name="ConfigureAudio">
|
<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">
|
<layout class="QVBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Audio</string>
|
<string>Audio</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -13,39 +20,99 @@
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Output Engine:</string>
|
<string>Output Engine:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="output_sink_combo_box">
|
<widget class="QComboBox" name="output_sink_combo_box"/>
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_audio_stretching">
|
<widget class="QCheckBox" name="toggle_audio_stretching">
|
||||||
<property name="text">
|
|
||||||
<string>Enable audio stretching</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
<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>
|
<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>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable audio stretching</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Audio Device:</string>
|
<string>Audio Device:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="audio_device_combo_box">
|
<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>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -60,8 +127,8 @@
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>20</width>
|
<width>167</width>
|
||||||
<height>40</height>
|
<height>55</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
|
|
|
@ -345,13 +345,11 @@ void Module::Interface::GetGyroscopeLowCalibrateParam(Kernel::HLERequestContext&
|
||||||
void Module::Interface::GetSoundVolume(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetSoundVolume(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx, 0x17, 0, 0};
|
IPC::RequestParser rp{ctx, 0x17, 0, 0};
|
||||||
|
|
||||||
const u8 volume = 0x3F; // TODO(purpasmart): Find out if this is the max value for the volume
|
const u8 volume = static_cast<u8>(0x3F * Settings::values.volume);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(volume);
|
rb.Push(volume);
|
||||||
|
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Module::Interface::Interface(std::shared_ptr<Module> hid, const char* name, u32 max_session)
|
Module::Interface::Interface(std::shared_ptr<Module> hid, const char* name, u32 max_session)
|
||||||
|
|
|
@ -139,6 +139,7 @@ struct Values {
|
||||||
std::string sink_id;
|
std::string sink_id;
|
||||||
bool enable_audio_stretching;
|
bool enable_audio_stretching;
|
||||||
std::string audio_device_id;
|
std::string audio_device_id;
|
||||||
|
float volume;
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
std::array<std::string, Service::CAM::NumCameras> camera_name;
|
std::array<std::string, Service::CAM::NumCameras> camera_name;
|
||||||
|
|
Loading…
Reference in a new issue