strawberry-audio-player-win.../src/equalizer/equalizer.cpp

408 lines
12 KiB
C++
Raw Normal View History

2018-02-27 18:06:05 +01:00
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
2018-08-09 18:39:44 +02:00
*
2018-02-27 18:06:05 +01:00
*/
#include "config.h"
#include <algorithm>
#include <QtGlobal>
#include <QWidget>
#include <QDialog>
#include <QDataStream>
#include <QByteArray>
#include <QList>
#include <QVariant>
#include <QString>
#include <QFrame>
#include <QKeySequence>
#include <QLayout>
#include <QLineEdit>
#include <QShortcut>
#include <QSlider>
2018-02-27 18:06:05 +01:00
#include <QMessageBox>
#include <QInputDialog>
#include <QToolButton>
#include <QCheckBox>
#include <QComboBox>
2020-02-08 03:40:30 +01:00
#include <QBoxLayout>
2018-02-27 18:06:05 +01:00
#include <QSettings>
#include "core/iconloader.h"
#include "equalizer.h"
2018-02-27 18:06:05 +01:00
#include "equalizerslider.h"
#include "ui_equalizer.h"
2018-02-27 18:06:05 +01:00
const char *Equalizer::kGainText[] = { "60", "170", "310", "600", "1k", "3k", "6k", "12k", "14k", "16k" };
const char *Equalizer::kSettingsGroup = "Equalizer";
Equalizer::Equalizer(QWidget *parent)
2021-07-11 07:40:57 +02:00
: QDialog(parent),
ui_(new Ui_Equalizer),
loading_(false) {
2018-02-27 18:06:05 +01:00
ui_->setupUi(this);
// Icons
ui_->preset_del->setIcon(IconLoader::Load("list-remove"));
ui_->preset_save->setIcon(IconLoader::Load("document-save"));
preamp_ = AddSlider(tr("Pre-amp"));
QFrame *line = new QFrame(ui_->slider_container);
2018-02-27 18:06:05 +01:00
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
ui_->slider_container->layout()->addWidget(line);
for (int i = 0; i < kBands; ++i) gain_[i] = AddSlider(kGainText[i]);
// Must be done before the signals are connected
ReloadSettings();
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->enable_equalizer, &QCheckBox::toggled, this, &Equalizer::EqualizerEnabledChangedSlot);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->preset, QOverload<int>::of(&QComboBox::currentIndexChanged), this, QOverload<int>::of(&Equalizer::PresetChanged));
QObject::connect(ui_->preset_save, &QToolButton::clicked, this, &Equalizer::SavePreset);
QObject::connect(ui_->preset_del, &QToolButton::clicked, this, &Equalizer::DelPreset);
2021-01-26 16:48:04 +01:00
QObject::connect(ui_->enable_stereo_balancer, &QCheckBox::toggled, this, &Equalizer::StereoBalancerEnabledChangedSlot);
QObject::connect(ui_->stereo_balance_slider, &QSlider::valueChanged, this, &Equalizer::StereoBalanceSliderChanged);
2018-02-27 18:06:05 +01:00
QShortcut *close = new QShortcut(QKeySequence::Close, this);
2021-01-26 16:48:04 +01:00
QObject::connect(close, &QShortcut::activated, this, &Equalizer::close);
2018-02-27 18:06:05 +01:00
}
Equalizer::~Equalizer() {
delete ui_;
}
void Equalizer::ReloadSettings() {
QSettings s;
s.beginGroup(kSettingsGroup);
presets_.clear();
ui_->preset->clear();
// Load presets
int count = s.beginReadArray("presets");
for (int i = 0; i < count; ++i) {
s.setArrayIndex(i);
AddPreset(s.value("name").toString(), s.value("params").value<Equalizer::Params>());
}
s.endArray();
if (count == 0) LoadDefaultPresets();
// Selected preset
QString selected_preset = s.value("selected_preset", "Custom").toString();
QString selected_preset_display_name = QString(tr(qPrintable(selected_preset)));
int selected_index = ui_->preset->findText(selected_preset_display_name);
if (selected_index != -1) ui_->preset->setCurrentIndex(selected_index);
// Enabled?
ui_->enable_equalizer->setChecked(s.value("enabled", false).toBool());
ui_->slider_container->setEnabled(ui_->enable_equalizer->isChecked());
2018-02-27 18:06:05 +01:00
ui_->enable_stereo_balancer->setChecked(s.value("enable_stereo_balancer", false).toBool());
ui_->slider_label_layout->setEnabled(ui_->enable_stereo_balancer->isChecked());
ui_->stereo_balance_slider->setEnabled(ui_->enable_stereo_balancer->isChecked());
2018-02-27 18:06:05 +01:00
int stereo_balance = s.value("stereo_balance", 0).toInt();
ui_->stereo_balance_slider->setValue(stereo_balance);
StereoBalanceSliderChanged(stereo_balance);
2018-02-27 18:06:05 +01:00
PresetChanged(selected_preset);
}
void Equalizer::LoadDefaultPresets() {
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Custom"), Params(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Classical"), Params(0, 0, 0, 0, 0, 0, -40, -40, -40, -50));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Club"), Params(0, 0, 20, 30, 30, 30, 20, 0, 0, 0));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Dance"), Params(50, 35, 10, 0, 0, -30, -40, -40, 0, 0));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Full Bass"), Params(70, 70, 70, 40, 20, -45, -50, -55, -55, -55));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Full Treble"), Params(-50, -50, -50, -25, 15, 55, 80, 80, 80, 85));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Full Bass + Treble"), Params(35, 30, 0, -40, -25, 10, 45, 55, 60, 60));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Laptop/Headphones"), Params(25, 50, 25, -20, 0, -30, -40, -40, 0, 0));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Large Hall"), Params(50, 50, 30, 30, 0, -25, -25, -25, 0, 0));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Live"), Params(-25, 0, 20, 25, 30, 30, 20, 15, 15, 10));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Party"), Params(35, 35, 0, 0, 0, 0, 0, 0, 35, 35));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Pop"), Params(-10, 25, 35, 40, 25, -5, -15, -15, -10, -10));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Reggae"), Params(0, 0, -5, -30, 0, -35, -35, 0, 0, 0));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Rock"), Params(40, 25, -30, -40, -20, 20, 45, 55, 55, 55));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Soft"), Params(25, 10, -5, -15, -5, 20, 45, 50, 55, 60));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Ska"), Params(-15, -25, -25, -5, 20, 30, 45, 50, 55, 50));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Soft Rock"), Params(20, 20, 10, -5, -25, -30, -20, -5, 15, 45));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Techno"), Params(40, 30, 0, -30, -25, 0, 40, 50, 50, 45));
AddPreset(QT_TRANSLATE_NOOP("Equalizer", "Zero"), Params(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
}
2021-06-12 20:53:23 +02:00
void Equalizer::AddPreset(const QString &name, const Params &params) {
2018-02-27 18:06:05 +01:00
QString name_displayed = tr(qPrintable(name));
presets_[name] = params;
if (ui_->preset->findText(name_displayed) == -1) {
ui_->preset->addItem(name_displayed, // name to display (translated)
QVariant(name) // original name
);
}
}
2021-06-12 20:53:23 +02:00
void Equalizer::PresetChanged(const int index) {
2018-02-27 18:06:05 +01:00
PresetChanged(ui_->preset->itemData(index).toString());
}
2021-06-12 20:53:23 +02:00
void Equalizer::PresetChanged(const QString &name) {
2018-02-27 18:06:05 +01:00
if (presets_.contains(last_preset_)) {
if (presets_[last_preset_] != current_params()) {
SaveCurrentPreset();
}
}
last_preset_ = name;
2021-06-12 20:53:23 +02:00
Params &p = presets_[name];
2018-02-27 18:06:05 +01:00
loading_ = true;
preamp_->set_value(p.preamp);
for (int i = 0; i < kBands; ++i) gain_[i]->set_value(p.gain[i]);
loading_ = false;
EqualizerParametersChangedSlot();
2018-02-27 18:06:05 +01:00
Save();
}
void Equalizer::SavePreset() {
QString name = SaveCurrentPreset();
if (!name.isEmpty()) {
last_preset_ = name;
ui_->preset->setCurrentIndex(ui_->preset->findText(tr(qPrintable(name))));
}
}
QString Equalizer::SaveCurrentPreset() {
2021-07-11 09:49:38 +02:00
QString name = QInputDialog::getText(this, tr("Save preset"), tr("Name"), QLineEdit::Normal, tr(qPrintable(last_preset_)));
2021-08-23 21:21:08 +02:00
if (name.isEmpty()) {
2018-02-27 18:06:05 +01:00
return QString();
2021-08-23 21:21:08 +02:00
}
2018-02-27 18:06:05 +01:00
AddPreset(name, current_params());
Save();
return name;
}
void Equalizer::DelPreset() {
QString name = ui_->preset->itemData(ui_->preset->currentIndex()).toString();
QString name_displayed = ui_->preset->currentText();
if (!presets_.contains(name) || name.isEmpty()) return;
int ret = QMessageBox::question(
this, tr("Delete preset"),
tr("Are you sure you want to delete the \"%1\" preset?").arg(name_displayed),
QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::No) return;
presets_.remove(name);
ui_->preset->removeItem(ui_->preset->currentIndex());
Save();
}
EqualizerSlider *Equalizer::AddSlider(const QString &label) {
2018-02-27 18:06:05 +01:00
EqualizerSlider *ret = new EqualizerSlider(label, ui_->slider_container);
2018-02-27 18:06:05 +01:00
ui_->slider_container->layout()->addWidget(ret);
2021-01-26 16:48:04 +01:00
QObject::connect(ret, &EqualizerSlider::ValueChanged, this, &Equalizer::EqualizerParametersChangedSlot);
2018-02-27 18:06:05 +01:00
return ret;
}
bool Equalizer::is_stereo_balancer_enabled() const {
return ui_->enable_stereo_balancer->isChecked();
}
bool Equalizer::is_equalizer_enabled() const {
return ui_->enable_equalizer->isChecked();
2018-02-27 18:06:05 +01:00
}
int Equalizer::preamp_value() const {
return preamp_->value();
}
QList<int> Equalizer::gain_values() const {
2021-06-20 19:04:08 +02:00
2018-02-27 18:06:05 +01:00
QList<int> ret;
2021-06-20 19:04:08 +02:00
ret.reserve(kBands);
2018-02-27 18:06:05 +01:00
for (int i = 0; i < kBands; ++i) {
ret << gain_[i]->value();
}
return ret;
2021-06-20 19:04:08 +02:00
2018-02-27 18:06:05 +01:00
}
Equalizer::Params Equalizer::current_params() const {
QList<int> gains = gain_values();
Params ret;
ret.preamp = preamp_value();
std::copy(gains.begin(), gains.end(), ret.gain);
return ret;
}
float Equalizer::stereo_balance() const {
2021-06-20 23:49:04 +02:00
return qBound(-1.0F, static_cast<float>(ui_->stereo_balance_slider->value()) / 100.0F, 1.0F);
}
void Equalizer::StereoBalancerEnabledChangedSlot(const bool enabled) {
if (!enabled) {
ui_->stereo_balance_slider->setValue(0);
emit StereoBalanceChanged(stereo_balance());
}
ui_->stereo_balance_slider->setEnabled(enabled);
emit StereoBalancerEnabledChanged(enabled);
Save();
}
2021-06-12 20:53:23 +02:00
void Equalizer::StereoBalanceSliderChanged(const int) {
emit StereoBalanceChanged(stereo_balance());
Save();
}
void Equalizer::EqualizerEnabledChangedSlot(const bool enabled) {
emit EqualizerEnabledChanged(enabled);
ui_->slider_container->setEnabled(enabled);
Save();
2018-02-27 18:06:05 +01:00
}
void Equalizer::EqualizerParametersChangedSlot() {
2018-02-27 18:06:05 +01:00
if (loading_) return;
emit EqualizerParametersChanged(preamp_value(), gain_values());
2018-02-27 18:06:05 +01:00
}
void Equalizer::Save() {
QSettings s;
s.beginGroup(kSettingsGroup);
// Presets
2021-10-30 02:21:29 +02:00
s.beginWriteArray("presets", static_cast<int>(presets_.count()));
2018-02-27 18:06:05 +01:00
int i = 0;
2021-03-21 04:47:11 +01:00
QStringList presets = presets_.keys();
for (const QString &name : presets) {
2018-02-27 18:06:05 +01:00
s.setArrayIndex(i++);
s.setValue("name", name);
s.setValue("params", QVariant::fromValue(presets_[name]));
}
s.endArray();
// Selected preset
s.setValue("selected_preset", ui_->preset->itemData(ui_->preset->currentIndex()).toString());
// Enabled?
s.setValue("enabled", ui_->enable_equalizer->isChecked());
2018-02-27 18:06:05 +01:00
s.setValue("enable_stereo_balancer", ui_->enable_stereo_balancer->isChecked());
s.setValue("stereo_balance", ui_->stereo_balance_slider->value());
2018-02-27 18:06:05 +01:00
}
void Equalizer::closeEvent(QCloseEvent*) {
2019-09-15 20:27:32 +02:00
2018-02-27 18:06:05 +01:00
QString name = ui_->preset->currentText();
if (!presets_.contains(name)) return;
if (presets_[name] == current_params()) return;
SavePreset();
2019-09-15 20:27:32 +02:00
2018-02-27 18:06:05 +01:00
}
Equalizer::Params::Params() : preamp(0) {
for (int i = 0; i < Equalizer::kBands; ++i) gain[i] = 0;
}
Equalizer::Params::Params(int g0, int g1, int g2, int g3, int g4, int g5, int g6, int g7, int g8, int g9, int pre) : preamp(pre) {
2021-08-23 21:21:08 +02:00
2018-02-27 18:06:05 +01:00
gain[0] = g0;
gain[1] = g1;
gain[2] = g2;
gain[3] = g3;
gain[4] = g4;
gain[5] = g5;
gain[6] = g6;
gain[7] = g7;
gain[8] = g8;
gain[9] = g9;
2021-08-23 21:21:08 +02:00
2018-02-27 18:06:05 +01:00
}
2021-07-11 09:49:38 +02:00
bool Equalizer::Params::operator==(const Equalizer::Params &other) const {
2021-08-23 21:21:08 +02:00
2018-02-27 18:06:05 +01:00
if (preamp != other.preamp) return false;
for (int i = 0; i < Equalizer::kBands; ++i) {
if (gain[i] != other.gain[i]) return false;
}
return true;
}
2021-07-11 09:49:38 +02:00
bool Equalizer::Params::operator!=(const Equalizer::Params &other) const {
2022-03-22 21:09:05 +01:00
return !(*this == other);
2018-02-27 18:06:05 +01:00
}
2021-06-12 20:53:23 +02:00
QDataStream &operator<<(QDataStream &s, const Equalizer::Params &p) {
2021-08-23 21:21:08 +02:00
2018-02-27 18:06:05 +01:00
s << p.preamp;
for (int i = 0; i < Equalizer::kBands; ++i) s << p.gain[i];
return s;
2021-08-23 21:21:08 +02:00
2018-02-27 18:06:05 +01:00
}
2021-06-12 20:53:23 +02:00
QDataStream &operator>>(QDataStream &s, Equalizer::Params &p) {
2021-08-23 21:21:08 +02:00
2018-02-27 18:06:05 +01:00
s >> p.preamp;
for (int i = 0; i < Equalizer::kBands; ++i) s >> p.gain[i];
return s;
2021-08-23 21:21:08 +02:00
2018-02-27 18:06:05 +01:00
}