Simplify the pipeline
Fix issue where bitrate is updated incorrectly by stream discoverer Fixes issue #282 Also make it possible to enable stereo balancer without enabling the equalizer
This commit is contained in:
@@ -1257,9 +1257,11 @@ void MainWindow::PlayIndex(const QModelIndex &index) {
|
|||||||
|
|
||||||
app_->playlist_manager()->SetActiveToCurrent();
|
app_->playlist_manager()->SetActiveToCurrent();
|
||||||
app_->player()->PlayAt(row, Engine::Manual, true);
|
app_->player()->PlayAt(row, Engine::Manual, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::PlaylistDoubleClick(const QModelIndex &index) {
|
void MainWindow::PlaylistDoubleClick(const QModelIndex &index) {
|
||||||
|
|
||||||
if (!index.isValid()) return;
|
if (!index.isValid()) return;
|
||||||
|
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
@@ -1284,6 +1286,7 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &index) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::VolumeWheelEvent(int delta) {
|
void MainWindow::VolumeWheelEvent(int delta) {
|
||||||
@@ -1315,6 +1318,7 @@ void MainWindow::ToggleShowHide() {
|
|||||||
activateWindow();
|
activateWindow();
|
||||||
raise();
|
raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::StopAfterCurrent() {
|
void MainWindow::StopAfterCurrent() {
|
||||||
|
|||||||
@@ -203,11 +203,11 @@ void Player::Init() {
|
|||||||
qLog(Debug) << "Creating equalizer";
|
qLog(Debug) << "Creating equalizer";
|
||||||
connect(equalizer_, SIGNAL(ParametersChanged(int,QList<int>)), app_->player()->engine(), SLOT(SetEqualizerParameters(int,QList<int>)));
|
connect(equalizer_, SIGNAL(ParametersChanged(int,QList<int>)), app_->player()->engine(), SLOT(SetEqualizerParameters(int,QList<int>)));
|
||||||
connect(equalizer_, SIGNAL(EnabledChanged(bool)), app_->player()->engine(), SLOT(SetEqualizerEnabled(bool)));
|
connect(equalizer_, SIGNAL(EnabledChanged(bool)), app_->player()->engine(), SLOT(SetEqualizerEnabled(bool)));
|
||||||
connect(equalizer_, SIGNAL(StereoBalanceChanged(float)), app_->player()->engine(), SLOT(SetStereoBalance(float)));
|
connect(equalizer_, SIGNAL(StereoBalanceChanged(bool, float)), app_->player()->engine(), SLOT(SetStereoBalance(bool, float)));
|
||||||
|
|
||||||
engine_->SetEqualizerEnabled(equalizer_->is_enabled());
|
engine_->SetStereoBalance(equalizer_->is_stereo_balancer_enabled(), equalizer_->stereo_balance());
|
||||||
|
engine_->SetEqualizerEnabled(equalizer_->is_equalizer_enabled());
|
||||||
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
||||||
engine_->SetStereoBalance(equalizer_->stereo_balance());
|
|
||||||
|
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||||
volume_control_ = s.value("volume_control", true).toBool();
|
volume_control_ = s.value("volume_control", true).toBool();
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
virtual void SetEqualizerEnabled(const bool) {}
|
virtual void SetEqualizerEnabled(const bool) {}
|
||||||
virtual void SetEqualizerParameters(const int preamp, const QList<int> &bandGains) { Q_UNUSED(preamp); Q_UNUSED(bandGains); }
|
virtual void SetEqualizerParameters(const int preamp, const QList<int> &bandGains) { Q_UNUSED(preamp); Q_UNUSED(bandGains); }
|
||||||
virtual void SetStereoBalance(float value) { Q_UNUSED(value); }
|
virtual void SetStereoBalance(const bool enabled, const float value) { Q_UNUSED(enabled); Q_UNUSED(value); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// Emitted when crossfading is enabled and the track is crossfade_duration_ away from finishing
|
// Emitted when crossfading is enabled and the track is crossfade_duration_ away from finishing
|
||||||
@@ -214,13 +214,13 @@ struct SimpleMetaBundle {
|
|||||||
QString album;
|
QString album;
|
||||||
QString comment;
|
QString comment;
|
||||||
QString genre;
|
QString genre;
|
||||||
qlonglong length;
|
qint64 length;
|
||||||
int year;
|
int year;
|
||||||
int track;
|
int track;
|
||||||
Song::FileType filetype;
|
Song::FileType filetype;
|
||||||
int samplerate;
|
int samplerate;
|
||||||
int bitdepth;
|
int bitdepth;
|
||||||
qlonglong bitrate;
|
qint64 bitrate;
|
||||||
QString lyrics;
|
QString lyrics;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ GstEngine::GstEngine(TaskManager *task_manager)
|
|||||||
task_manager_(task_manager),
|
task_manager_(task_manager),
|
||||||
buffering_task_id_(-1),
|
buffering_task_id_(-1),
|
||||||
latest_buffer_(nullptr),
|
latest_buffer_(nullptr),
|
||||||
|
stereo_balancer_enabled_(false),
|
||||||
stereo_balance_(0.0f),
|
stereo_balance_(0.0f),
|
||||||
seek_timer_(new QTimer(this)),
|
seek_timer_(new QTimer(this)),
|
||||||
timer_id_(-1),
|
timer_id_(-1),
|
||||||
@@ -174,7 +175,7 @@ bool GstEngine::Load(const QUrl &stream_url, const QUrl &original_url, Engine::T
|
|||||||
current_pipeline_ = pipeline;
|
current_pipeline_ = pipeline;
|
||||||
|
|
||||||
SetVolume(volume_);
|
SetVolume(volume_);
|
||||||
SetStereoBalance(stereo_balance_);
|
SetStereoBalance(stereo_balancer_enabled_, stereo_balance_);
|
||||||
SetEqualizerParameters(equalizer_preamp_, equalizer_gains_);
|
SetEqualizerParameters(equalizer_preamp_, equalizer_gains_);
|
||||||
|
|
||||||
// Maybe fade in this track
|
// Maybe fade in this track
|
||||||
@@ -441,11 +442,11 @@ void GstEngine::SetEqualizerParameters(const int preamp, const QList<int> &band_
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEngine::SetStereoBalance(const float value) {
|
void GstEngine::SetStereoBalance(const bool enabled, const float value) {
|
||||||
|
|
||||||
stereo_balance_ = value;
|
stereo_balance_ = value;
|
||||||
|
|
||||||
if (current_pipeline_) current_pipeline_->SetStereoBalance(value);
|
if (current_pipeline_) current_pipeline_->SetStereoBalance(enabled, value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,11 +50,6 @@
|
|||||||
class TaskManager;
|
class TaskManager;
|
||||||
class GstEnginePipeline;
|
class GstEnginePipeline;
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
|
||||||
struct _GTlsDatabase;
|
|
||||||
typedef struct _GTlsDatabase GTlsDatabase;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class GstEngine
|
* @class GstEngine
|
||||||
* @short GStreamer engine plugin
|
* @short GStreamer engine plugin
|
||||||
@@ -98,7 +93,6 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
void ConsumeBuffer(GstBuffer *buffer, const int pipeline_id, const QString &format);
|
void ConsumeBuffer(GstBuffer *buffer, const int pipeline_id, const QString &format);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|
||||||
/** Set whether equalizer is enabled */
|
/** Set whether equalizer is enabled */
|
||||||
@@ -108,15 +102,11 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
void SetEqualizerParameters(const int preamp, const QList<int> &bandGains);
|
void SetEqualizerParameters(const int preamp, const QList<int> &bandGains);
|
||||||
|
|
||||||
/** Set Stereo balance, range -1.0f..1.0f */
|
/** Set Stereo balance, range -1.0f..1.0f */
|
||||||
void SetStereoBalance(const float value);
|
void SetStereoBalance(const bool enabled, const float value);
|
||||||
|
|
||||||
void AddBufferConsumer(GstBufferConsumer *consumer);
|
void AddBufferConsumer(GstBufferConsumer *consumer);
|
||||||
void RemoveBufferConsumer(GstBufferConsumer *consumer);
|
void RemoveBufferConsumer(GstBufferConsumer *consumer);
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
|
||||||
GTlsDatabase *tls_database() const { return tls_database_; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void timerEvent(QTimerEvent*);
|
void timerEvent(QTimerEvent*);
|
||||||
|
|
||||||
@@ -180,9 +170,11 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
|
|
||||||
GstBuffer *latest_buffer_;
|
GstBuffer *latest_buffer_;
|
||||||
|
|
||||||
|
bool stereo_balancer_enabled_;
|
||||||
|
float stereo_balance_;
|
||||||
|
|
||||||
int equalizer_preamp_;
|
int equalizer_preamp_;
|
||||||
QList<int> equalizer_gains_;
|
QList<int> equalizer_gains_;
|
||||||
float stereo_balance_;
|
|
||||||
|
|
||||||
mutable bool can_decode_success_;
|
mutable bool can_decode_success_;
|
||||||
mutable bool can_decode_last_;
|
mutable bool can_decode_last_;
|
||||||
@@ -203,10 +195,6 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
int scope_chunks_;
|
int scope_chunks_;
|
||||||
QString buffer_format_;
|
QString buffer_format_;
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
|
||||||
GTlsDatabase* tls_database_;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* GSTENGINE_H */
|
#endif /* GSTENGINE_H */
|
||||||
|
|||||||
@@ -67,9 +67,10 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine)
|
|||||||
id_(sId++),
|
id_(sId++),
|
||||||
valid_(false),
|
valid_(false),
|
||||||
volume_control_(true),
|
volume_control_(true),
|
||||||
|
stereo_balance_enabled_(false),
|
||||||
|
stereo_balance_(0.0f),
|
||||||
eq_enabled_(false),
|
eq_enabled_(false),
|
||||||
eq_preamp_(0),
|
eq_preamp_(0),
|
||||||
stereo_balance_(0.0f),
|
|
||||||
rg_enabled_(false),
|
rg_enabled_(false),
|
||||||
rg_mode_(0),
|
rg_mode_(0),
|
||||||
rg_preamp_(0.0),
|
rg_preamp_(0.0),
|
||||||
@@ -93,17 +94,11 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine)
|
|||||||
use_fudge_timer_(false),
|
use_fudge_timer_(false),
|
||||||
pipeline_(nullptr),
|
pipeline_(nullptr),
|
||||||
audiobin_(nullptr),
|
audiobin_(nullptr),
|
||||||
queue_(nullptr),
|
audioqueue_(nullptr),
|
||||||
audioconvert_(nullptr),
|
|
||||||
audioconvert2_(nullptr),
|
|
||||||
audioscale_(nullptr),
|
|
||||||
audiosink_(nullptr),
|
|
||||||
volume_(nullptr),
|
volume_(nullptr),
|
||||||
audio_panorama_(nullptr),
|
audiopanorama_(nullptr),
|
||||||
equalizer_preamp_(nullptr),
|
|
||||||
equalizer_(nullptr),
|
equalizer_(nullptr),
|
||||||
rgvolume_(nullptr),
|
equalizer_preamp_(nullptr),
|
||||||
rglimiter_(nullptr),
|
|
||||||
discoverer_(nullptr),
|
discoverer_(nullptr),
|
||||||
about_to_finish_cb_id_(-1),
|
about_to_finish_cb_id_(-1),
|
||||||
pad_added_cb_id_(-1),
|
pad_added_cb_id_(-1),
|
||||||
@@ -193,26 +188,26 @@ bool GstEnginePipeline::InitAudioBin() {
|
|||||||
if (!audiobin_) return false;
|
if (!audiobin_) return false;
|
||||||
|
|
||||||
// Create the sink
|
// Create the sink
|
||||||
audiosink_ = engine_->CreateElement(output_, audiobin_);
|
GstElement *audiosink = engine_->CreateElement(output_, audiobin_);
|
||||||
if (!audiosink_) {
|
if (!audiosink) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_.isValid() && g_object_class_find_property(G_OBJECT_GET_CLASS(audiosink_), "device")) {
|
if (device_.isValid() && g_object_class_find_property(G_OBJECT_GET_CLASS(audiosink), "device")) {
|
||||||
switch (device_.type()) {
|
switch (device_.type()) {
|
||||||
case QVariant::String:
|
case QVariant::String:
|
||||||
if (device_.toString().isEmpty()) break;
|
if (device_.toString().isEmpty()) break;
|
||||||
g_object_set(G_OBJECT(audiosink_), "device", device_.toString().toUtf8().constData(), nullptr);
|
g_object_set(G_OBJECT(audiosink), "device", device_.toString().toUtf8().constData(), nullptr);
|
||||||
break;
|
break;
|
||||||
case QVariant::ByteArray:
|
case QVariant::ByteArray:
|
||||||
g_object_set(G_OBJECT(audiosink_), "device", device_.toByteArray().constData(), nullptr);
|
g_object_set(G_OBJECT(audiosink), "device", device_.toByteArray().constData(), nullptr);
|
||||||
break;
|
break;
|
||||||
case QVariant::LongLong:
|
case QVariant::LongLong:
|
||||||
g_object_set(G_OBJECT(audiosink_), "device", device_.toLongLong(), nullptr);
|
g_object_set(G_OBJECT(audiosink), "device", device_.toLongLong(), nullptr);
|
||||||
break;
|
break;
|
||||||
case QVariant::Int:
|
case QVariant::Int:
|
||||||
g_object_set(G_OBJECT(audiosink_), "device", device_.toInt(), nullptr);
|
g_object_set(G_OBJECT(audiosink), "device", device_.toInt(), nullptr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qLog(Warning) << "Unknown device type" << device_;
|
qLog(Warning) << "Unknown device type" << device_;
|
||||||
@@ -222,133 +217,144 @@ bool GstEnginePipeline::InitAudioBin() {
|
|||||||
|
|
||||||
// Create all the other elements
|
// Create all the other elements
|
||||||
|
|
||||||
queue_ = engine_->CreateElement("queue2", audiobin_);
|
audioqueue_ = engine_->CreateElement("queue2", audiobin_);
|
||||||
audioconvert_ = engine_->CreateElement("audioconvert", audiobin_);
|
GstElement *audioconverter = engine_->CreateElement("audioconvert", audiobin_);
|
||||||
GstElement *audio_queue = engine_->CreateElement("queue", audiobin_);
|
|
||||||
audioscale_ = engine_->CreateElement("audioresample", audiobin_);
|
|
||||||
GstElement *convert = engine_->CreateElement("audioconvert", audiobin_);
|
|
||||||
|
|
||||||
if (engine_->volume_control()) {
|
if (!audioqueue_ || !audioconverter) {
|
||||||
volume_ = engine_->CreateElement("volume", audiobin_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eq_enabled_) {
|
|
||||||
audio_panorama_ = engine_->CreateElement("audiopanorama", audiobin_, false);
|
|
||||||
equalizer_preamp_ = engine_->CreateElement("volume", audiobin_, false);
|
|
||||||
equalizer_ = engine_->CreateElement("equalizer-nbands", audiobin_, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queue_ || !audioconvert_ || !audio_queue || !audioscale_ || !convert) {
|
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
audiobin_ = nullptr;
|
audiobin_ = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the replaygain elements if it's enabled.
|
// Create the volume elements if it's enabled.
|
||||||
// event_probe is the audioconvert element we attach the probe to, which will change depending on whether replaygain is enabled.
|
if (volume_control_) {
|
||||||
// convert_sink is the element after the first audioconvert, which again will change.
|
volume_ = engine_->CreateElement("volume", audiobin_);
|
||||||
GstElement *event_probe = audioconvert_;
|
}
|
||||||
GstElement *convert_sink = audio_queue;
|
|
||||||
|
|
||||||
|
// Create the stereo balancer elements if it's enabled.
|
||||||
|
if (stereo_balance_enabled_) {
|
||||||
|
audiopanorama_ = engine_->CreateElement("audiopanorama", audiobin_, false);
|
||||||
|
// Set the stereo balance.
|
||||||
|
if (audiopanorama_) g_object_set(G_OBJECT(audiopanorama_), "panorama", stereo_balance_, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the equalizer elements if it's enabled.
|
||||||
|
if (eq_enabled_) {
|
||||||
|
equalizer_preamp_ = engine_->CreateElement("volume", audiobin_, false);
|
||||||
|
equalizer_ = engine_->CreateElement("equalizer-nbands", audiobin_, false);
|
||||||
|
// Setting the equalizer bands:
|
||||||
|
//
|
||||||
|
// GStreamer's GstIirEqualizerNBands sets up shelve filters for the first and last bands as corner cases.
|
||||||
|
// That was causing the "inverted slider" bug.
|
||||||
|
// As a workaround, we create two dummy bands at both ends of the spectrum.
|
||||||
|
// This causes the actual first and last adjustable bands to be implemented using band-pass filters.
|
||||||
|
|
||||||
|
if (equalizer_) {
|
||||||
|
g_object_set(G_OBJECT(equalizer_), "num-bands", 10 + 2, nullptr);
|
||||||
|
|
||||||
|
// Dummy first band (bandwidth 0, cutting below 20Hz):
|
||||||
|
GstObject *first_band = GST_OBJECT(gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), 0));
|
||||||
|
g_object_set(G_OBJECT(first_band), "freq", 20.0, "bandwidth", 0, "gain", 0.0f, nullptr);
|
||||||
|
g_object_unref(G_OBJECT(first_band));
|
||||||
|
|
||||||
|
// Dummy last band (bandwidth 0, cutting over 20KHz):
|
||||||
|
GstObject *last_band = GST_OBJECT(gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), kEqBandCount + 1));
|
||||||
|
g_object_set(G_OBJECT(last_band), "freq", 20000.0, "bandwidth", 0, "gain", 0.0f, nullptr);
|
||||||
|
g_object_unref(G_OBJECT(last_band));
|
||||||
|
|
||||||
|
int last_band_frequency = 0;
|
||||||
|
for (int i = 0; i < kEqBandCount; ++i) {
|
||||||
|
const int index_in_eq = i + 1;
|
||||||
|
GstObject *band = GST_OBJECT(gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), index_in_eq));
|
||||||
|
|
||||||
|
const float frequency = kEqBandFrequencies[i];
|
||||||
|
const float bandwidth = frequency - last_band_frequency;
|
||||||
|
last_band_frequency = frequency;
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT(band), "freq", frequency, "bandwidth", bandwidth, "gain", 0.0f, nullptr);
|
||||||
|
g_object_unref(G_OBJECT(band));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the replaygain elements if it's enabled.
|
||||||
|
GstElement *eventprobe = audioqueue_;
|
||||||
|
GstElement *rgvolume = nullptr;
|
||||||
|
GstElement *rglimiter = nullptr;
|
||||||
|
GstElement *audioconverter2 = nullptr;
|
||||||
if (rg_enabled_) {
|
if (rg_enabled_) {
|
||||||
rgvolume_ = engine_->CreateElement("rgvolume", audiobin_, false);
|
rgvolume = engine_->CreateElement("rgvolume", audiobin_, false);
|
||||||
rglimiter_ = engine_->CreateElement("rglimiter", audiobin_, false);
|
rglimiter = engine_->CreateElement("rglimiter", audiobin_, false);
|
||||||
audioconvert2_ = engine_->CreateElement("audioconvert", audiobin_, false);
|
audioconverter2 = engine_->CreateElement("audioconvert", audiobin_, false);
|
||||||
if (rgvolume_ && rglimiter_ && audioconvert2_) {
|
if (rgvolume && rglimiter && audioconverter2) {
|
||||||
event_probe = audioconvert2_;
|
eventprobe = audioconverter2;
|
||||||
convert_sink = rgvolume_;
|
|
||||||
// Set replaygain settings
|
// Set replaygain settings
|
||||||
g_object_set(G_OBJECT(rgvolume_), "album-mode", rg_mode_, nullptr);
|
g_object_set(G_OBJECT(rgvolume), "album-mode", rg_mode_, nullptr);
|
||||||
g_object_set(G_OBJECT(rgvolume_), "pre-amp", double(rg_preamp_), nullptr);
|
g_object_set(G_OBJECT(rgvolume), "pre-amp", double(rg_preamp_), nullptr);
|
||||||
g_object_set(G_OBJECT(rglimiter_), "enabled", int(rg_compression_), nullptr);
|
g_object_set(G_OBJECT(rglimiter), "enabled", int(rg_compression_), nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a pad on the outside of the audiobin and connect it to the pad of the first element.
|
// Create a pad on the outside of the audiobin and connect it to the pad of the first element.
|
||||||
GstPad *pad = gst_element_get_static_pad(queue_, "sink");
|
GstPad *pad = gst_element_get_static_pad(audioqueue_, "sink");
|
||||||
gst_element_add_pad(audiobin_, gst_ghost_pad_new("sink", pad));
|
gst_element_add_pad(audiobin_, gst_ghost_pad_new("sink", pad));
|
||||||
gst_object_unref(pad);
|
gst_object_unref(pad);
|
||||||
|
|
||||||
// Add a data probe on the src pad of the audioconvert element for our scope.
|
// Add a data probe on the src pad of the audioconvert element for our scope.
|
||||||
// We do it here because we want pre-equalized and pre-volume samples so that our visualization are not be affected by them.
|
// We do it here because we want pre-equalized and pre-volume samples so that our visualization are not be affected by them.
|
||||||
pad = gst_element_get_static_pad(event_probe, "src");
|
pad = gst_element_get_static_pad(eventprobe, "src");
|
||||||
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, &EventHandoffCallback, this, nullptr);
|
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, &EventHandoffCallback, this, nullptr);
|
||||||
gst_object_unref(pad);
|
gst_object_unref(pad);
|
||||||
|
|
||||||
// Setting the equalizer bands:
|
|
||||||
//
|
|
||||||
// GStreamer's GstIirEqualizerNBands sets up shelve filters for the first and last bands as corner cases.
|
|
||||||
// That was causing the "inverted slider" bug.
|
|
||||||
// As a workaround, we create two dummy bands at both ends of the spectrum.
|
|
||||||
// This causes the actual first and last adjustable bands to be implemented using band-pass filters.
|
|
||||||
|
|
||||||
if (equalizer_) {
|
|
||||||
g_object_set(G_OBJECT(equalizer_), "num-bands", 10 + 2, nullptr);
|
|
||||||
|
|
||||||
// Dummy first band (bandwidth 0, cutting below 20Hz):
|
|
||||||
GstObject *first_band = GST_OBJECT(gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), 0));
|
|
||||||
g_object_set(G_OBJECT(first_band), "freq", 20.0, "bandwidth", 0, "gain", 0.0f, nullptr);
|
|
||||||
g_object_unref(G_OBJECT(first_band));
|
|
||||||
|
|
||||||
// Dummy last band (bandwidth 0, cutting over 20KHz):
|
|
||||||
GstObject *last_band = GST_OBJECT(gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), kEqBandCount + 1));
|
|
||||||
g_object_set(G_OBJECT(last_band), "freq", 20000.0, "bandwidth", 0, "gain", 0.0f, nullptr);
|
|
||||||
g_object_unref(G_OBJECT(last_band));
|
|
||||||
|
|
||||||
int last_band_frequency = 0;
|
|
||||||
for (int i = 0; i < kEqBandCount; ++i) {
|
|
||||||
const int index_in_eq = i + 1;
|
|
||||||
GstObject *band = GST_OBJECT(gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), index_in_eq));
|
|
||||||
|
|
||||||
const float frequency = kEqBandFrequencies[i];
|
|
||||||
const float bandwidth = frequency - last_band_frequency;
|
|
||||||
last_band_frequency = frequency;
|
|
||||||
|
|
||||||
g_object_set(G_OBJECT(band), "freq", frequency, "bandwidth", bandwidth, "gain", 0.0f, nullptr);
|
|
||||||
g_object_unref(G_OBJECT(band));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the stereo balance.
|
|
||||||
if (audio_panorama_) g_object_set(G_OBJECT(audio_panorama_), "panorama", stereo_balance_, nullptr);
|
|
||||||
|
|
||||||
// Set the buffer duration.
|
// Set the buffer duration.
|
||||||
// We set this on this queue instead of the playbin because setting it on the playbin only affects network sources.
|
// We set this on this queue instead of the playbin because setting it on the playbin only affects network sources.
|
||||||
// Disable the default buffer and byte limits, so we only buffer based on time.
|
// Disable the default buffer and byte limits, so we only buffer based on time.
|
||||||
|
|
||||||
g_object_set(G_OBJECT(queue_), "max-size-buffers", 0, nullptr);
|
g_object_set(G_OBJECT(audioqueue_), "max-size-buffers", 0, nullptr);
|
||||||
g_object_set(G_OBJECT(queue_), "max-size-bytes", 0, nullptr);
|
g_object_set(G_OBJECT(audioqueue_), "max-size-bytes", 0, nullptr);
|
||||||
g_object_set(G_OBJECT(queue_), "max-size-time", buffer_duration_nanosec_, nullptr);
|
g_object_set(G_OBJECT(audioqueue_), "max-size-time", buffer_duration_nanosec_, nullptr);
|
||||||
g_object_set(G_OBJECT(queue_), "low-percent", buffer_min_fill_, nullptr);
|
g_object_set(G_OBJECT(audioqueue_), "low-percent", buffer_min_fill_, nullptr);
|
||||||
if (buffer_duration_nanosec_ > 0) {
|
if (buffer_duration_nanosec_ > 0) {
|
||||||
g_object_set(G_OBJECT(queue_), "use-buffering", true, nullptr);
|
g_object_set(G_OBJECT(audioqueue_), "use-buffering", true, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_element_link_many(queue_, audioconvert_, convert_sink, nullptr);
|
// Link all elements
|
||||||
|
|
||||||
|
GstElement *next = audioqueue_; // The next element to link from.
|
||||||
|
|
||||||
// Link replaygain elements if enabled.
|
// Link replaygain elements if enabled.
|
||||||
if (rg_enabled_ && rgvolume_ && rglimiter_ && audioconvert2_) {
|
if (rg_enabled_ && rgvolume && rglimiter && audioconverter2) {
|
||||||
gst_element_link_many(rgvolume_, rglimiter_, audioconvert2_, audio_queue, nullptr);
|
gst_element_link_many(next, rgvolume, rglimiter, audioconverter2, nullptr);
|
||||||
|
next = audioconverter2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eq_enabled_ && equalizer_ && equalizer_preamp_ && audio_panorama_) {
|
// Link equalizer elements if enabled.
|
||||||
if (volume_)
|
if (eq_enabled_ && equalizer_ && equalizer_preamp_) {
|
||||||
gst_element_link_many(audio_queue, equalizer_preamp_, equalizer_, audio_panorama_, volume_, audioscale_, convert, nullptr);
|
gst_element_link_many(next, equalizer_preamp_, equalizer_, nullptr);
|
||||||
else
|
next = equalizer_;
|
||||||
gst_element_link_many(audio_queue, equalizer_preamp_, equalizer_, audio_panorama_, audioscale_, convert, nullptr);
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (volume_) gst_element_link_many(audio_queue, volume_, audioscale_, convert, nullptr);
|
// Link equalizer elements if enabled.
|
||||||
else gst_element_link_many(audio_queue, audioscale_, convert, nullptr);
|
if (stereo_balance_enabled_ && audiopanorama_) {
|
||||||
|
gst_element_link(next, audiopanorama_);
|
||||||
|
next = audiopanorama_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Link volume elements if enabled.
|
||||||
|
if (volume_control_ && volume_) {
|
||||||
|
gst_element_link(next, volume_);
|
||||||
|
next = volume_;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_element_link(next, audioconverter);
|
||||||
|
|
||||||
// Let the audio output of the tee autonegotiate the bit depth and format.
|
// Let the audio output of the tee autonegotiate the bit depth and format.
|
||||||
GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw");
|
GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw");
|
||||||
gst_element_link_filtered(convert, audiosink_, caps);
|
gst_element_link_filtered(audioconverter, audiosink, caps);
|
||||||
gst_caps_unref(caps);
|
gst_caps_unref(caps);
|
||||||
|
|
||||||
// Add probes and handlers.
|
// Add probes and handlers.
|
||||||
pad = gst_element_get_static_pad(audio_queue, "src");
|
pad = gst_element_get_static_pad(audioqueue_, "src");
|
||||||
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
|
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
|
||||||
gst_object_unref(pad);
|
gst_object_unref(pad);
|
||||||
|
|
||||||
@@ -665,7 +671,7 @@ void GstEnginePipeline::StateChangedMessageReceived(GstMessage *msg) {
|
|||||||
void GstEnginePipeline::BufferingMessageReceived(GstMessage *msg) {
|
void GstEnginePipeline::BufferingMessageReceived(GstMessage *msg) {
|
||||||
|
|
||||||
// Only handle buffering messages from the queue2 element in audiobin - not the one that's created automatically by playbin.
|
// Only handle buffering messages from the queue2 element in audiobin - not the one that's created automatically by playbin.
|
||||||
if (GST_ELEMENT(GST_MESSAGE_SRC(msg)) != queue_) {
|
if (GST_ELEMENT(GST_MESSAGE_SRC(msg)) != audioqueue_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,7 +794,7 @@ GstPadProbeReturn GstEnginePipeline::HandoffCallback(GstPad *pad, GstPadProbeInf
|
|||||||
int buf16_size = samples * sizeof(int16_t) * channels;
|
int buf16_size = samples * sizeof(int16_t) * channels;
|
||||||
int16_t *d = (int16_t*) g_malloc(buf16_size);
|
int16_t *d = (int16_t*) g_malloc(buf16_size);
|
||||||
memset(d, 0, buf16_size);
|
memset(d, 0, buf16_size);
|
||||||
for (int i = 0 ; i <= samples ; ++i) {
|
for (int i = 0 ; i < (samples * 2) ; ++i) {
|
||||||
d[i] = (int16_t) (s[i] >> 16);
|
d[i] = (int16_t) (s[i] >> 16);
|
||||||
}
|
}
|
||||||
gst_buffer_unmap(buf, &map_info);
|
gst_buffer_unmap(buf, &map_info);
|
||||||
@@ -973,6 +979,44 @@ bool GstEnginePipeline::Seek(const qint64 nanosec) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GstEnginePipeline::SetVolume(const int percent) {
|
||||||
|
|
||||||
|
if (!volume_) return;
|
||||||
|
|
||||||
|
volume_percent_ = percent;
|
||||||
|
UpdateVolume();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GstEnginePipeline::SetVolumeModifier(const qreal mod) {
|
||||||
|
|
||||||
|
if (!volume_) return;
|
||||||
|
volume_modifier_ = mod;
|
||||||
|
UpdateVolume();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GstEnginePipeline::UpdateVolume() {
|
||||||
|
|
||||||
|
if (!volume_) return;
|
||||||
|
float vol = double(volume_percent_) * 0.01 * volume_modifier_;
|
||||||
|
g_object_set(G_OBJECT(volume_), "volume", vol, nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GstEnginePipeline::SetStereoBalance(const bool enabled, const float value) {
|
||||||
|
|
||||||
|
stereo_balance_enabled_ = enabled;
|
||||||
|
if (enabled) {
|
||||||
|
stereo_balance_ = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stereo_balance_ = 0.0f;
|
||||||
|
}
|
||||||
|
UpdateStereoBalance();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::SetEqualizerEnabled(bool enabled) {
|
void GstEnginePipeline::SetEqualizerEnabled(bool enabled) {
|
||||||
|
|
||||||
eq_enabled_ = enabled;
|
eq_enabled_ = enabled;
|
||||||
@@ -988,11 +1032,10 @@ void GstEnginePipeline::SetEqualizerParams(const int preamp, const QList<int>& b
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::SetStereoBalance(const float value) {
|
void GstEnginePipeline::UpdateStereoBalance() {
|
||||||
|
if (audiopanorama_) {
|
||||||
stereo_balance_ = value;
|
g_object_set(G_OBJECT(audiopanorama_), "panorama", stereo_balance_, nullptr);
|
||||||
UpdateStereoBalance();
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::UpdateEqualizer() {
|
void GstEnginePipeline::UpdateEqualizer() {
|
||||||
@@ -1022,30 +1065,6 @@ void GstEnginePipeline::UpdateEqualizer() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::UpdateStereoBalance() {
|
|
||||||
if (audio_panorama_) {
|
|
||||||
g_object_set(G_OBJECT(audio_panorama_), "panorama", stereo_balance_, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GstEnginePipeline::SetVolume(const int percent) {
|
|
||||||
if (!volume_) return;
|
|
||||||
volume_percent_ = percent;
|
|
||||||
UpdateVolume();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GstEnginePipeline::SetVolumeModifier(const qreal mod) {
|
|
||||||
if (!volume_) return;
|
|
||||||
volume_modifier_ = mod;
|
|
||||||
UpdateVolume();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GstEnginePipeline::UpdateVolume() {
|
|
||||||
if (!volume_) return;
|
|
||||||
float vol = double(volume_percent_) * 0.01 * volume_modifier_;
|
|
||||||
g_object_set(G_OBJECT(volume_), "volume", vol, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GstEnginePipeline::StartFader(const qint64 duration_nanosec, const QTimeLine::Direction direction, const QTimeLine::CurveShape shape, const bool use_fudge_timer) {
|
void GstEnginePipeline::StartFader(const qint64 duration_nanosec, const QTimeLine::Direction direction, const QTimeLine::CurveShape shape, const bool use_fudge_timer) {
|
||||||
|
|
||||||
const int duration_msec = duration_nanosec / kNsecPerMsec;
|
const int duration_msec = duration_nanosec / kNsecPerMsec;
|
||||||
@@ -1167,7 +1186,7 @@ void GstEnginePipeline::StreamDiscovered(GstDiscoverer *, GstDiscovererInfo *inf
|
|||||||
bundle.stream_url = QUrl(discovered_url);
|
bundle.stream_url = QUrl(discovered_url);
|
||||||
bundle.samplerate = gst_discoverer_audio_info_get_sample_rate(GST_DISCOVERER_AUDIO_INFO(stream_info));
|
bundle.samplerate = gst_discoverer_audio_info_get_sample_rate(GST_DISCOVERER_AUDIO_INFO(stream_info));
|
||||||
bundle.bitdepth = gst_discoverer_audio_info_get_depth(GST_DISCOVERER_AUDIO_INFO(stream_info));
|
bundle.bitdepth = gst_discoverer_audio_info_get_depth(GST_DISCOVERER_AUDIO_INFO(stream_info));
|
||||||
bundle.bitrate = gst_discoverer_audio_info_get_bitrate(GST_DISCOVERER_AUDIO_INFO(stream_info));
|
bundle.bitrate = gst_discoverer_audio_info_get_bitrate(GST_DISCOVERER_AUDIO_INFO(stream_info)) / 1000;
|
||||||
|
|
||||||
GstCaps *caps = gst_discoverer_stream_info_get_caps(stream_info);
|
GstCaps *caps = gst_discoverer_stream_info_get_caps(stream_info);
|
||||||
gchar *codec_description = gst_pb_utils_get_codec_description(caps);
|
gchar *codec_description = gst_pb_utils_get_codec_description(caps);
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
void SetEqualizerEnabled(const bool enabled);
|
void SetEqualizerEnabled(const bool enabled);
|
||||||
void SetEqualizerParams(const int preamp, const QList<int> &band_gains);
|
void SetEqualizerParams(const int preamp, const QList<int> &band_gains);
|
||||||
void SetVolume(const int percent);
|
void SetVolume(const int percent);
|
||||||
void SetStereoBalance(const float value);
|
void SetStereoBalance(const bool enabled, const float value);
|
||||||
void StartFader(const qint64 duration_nanosec, const QTimeLine::Direction direction = QTimeLine::Forward, const QTimeLine::CurveShape shape = QTimeLine::LinearCurve, const bool use_fudge_timer = true);
|
void StartFader(const qint64 duration_nanosec, const QTimeLine::Direction direction = QTimeLine::Forward, const QTimeLine::CurveShape shape = QTimeLine::LinearCurve, const bool use_fudge_timer = true);
|
||||||
|
|
||||||
// If this is set then it will be loaded automatically when playback finishes for gapless playback
|
// If this is set then it will be loaded automatically when playback finishes for gapless playback
|
||||||
@@ -193,16 +193,17 @@ signals:
|
|||||||
QVariant device_;
|
QVariant device_;
|
||||||
bool volume_control_;
|
bool volume_control_;
|
||||||
|
|
||||||
|
// Stereo balance.
|
||||||
|
// From -1.0 - 1.0
|
||||||
|
// -1.0 is left, 1.0 is right.
|
||||||
|
bool stereo_balance_enabled_;
|
||||||
|
float stereo_balance_;
|
||||||
|
|
||||||
// Equalizer
|
// Equalizer
|
||||||
bool eq_enabled_;
|
bool eq_enabled_;
|
||||||
int eq_preamp_;
|
int eq_preamp_;
|
||||||
QList<int> eq_band_gains_;
|
QList<int> eq_band_gains_;
|
||||||
|
|
||||||
// Stereo balance.
|
|
||||||
// From -1.0 - 1.0
|
|
||||||
// -1.0 is left, 1.0 is right.
|
|
||||||
float stereo_balance_;
|
|
||||||
|
|
||||||
// ReplayGain
|
// ReplayGain
|
||||||
bool rg_enabled_;
|
bool rg_enabled_;
|
||||||
int rg_mode_;
|
int rg_mode_;
|
||||||
@@ -267,22 +268,12 @@ signals:
|
|||||||
bool use_fudge_timer_;
|
bool use_fudge_timer_;
|
||||||
|
|
||||||
GstElement *pipeline_;
|
GstElement *pipeline_;
|
||||||
|
|
||||||
// The audiobin is either linked with a playbin or set as sink of the playbin pipeline.
|
|
||||||
GstElement *audiobin_;
|
GstElement *audiobin_;
|
||||||
|
GstElement *audioqueue_;
|
||||||
// Elements in the audiobin. See comments in Init()'s definition.
|
|
||||||
GstElement *queue_;
|
|
||||||
GstElement *audioconvert_;
|
|
||||||
GstElement *audioconvert2_;
|
|
||||||
GstElement *audioscale_;
|
|
||||||
GstElement *audiosink_;
|
|
||||||
GstElement *volume_;
|
GstElement *volume_;
|
||||||
GstElement *audio_panorama_;
|
GstElement *audiopanorama_;
|
||||||
GstElement *equalizer_preamp_;
|
|
||||||
GstElement *equalizer_;
|
GstElement *equalizer_;
|
||||||
GstElement *rgvolume_;
|
GstElement *equalizer_preamp_;
|
||||||
GstElement *rglimiter_;
|
|
||||||
GstDiscoverer *discoverer_;
|
GstDiscoverer *discoverer_;
|
||||||
|
|
||||||
int about_to_finish_cb_id_;
|
int about_to_finish_cb_id_;
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ Equalizer::Equalizer(QWidget *parent)
|
|||||||
connect(ui_->preset, SIGNAL(currentIndexChanged(int)), SLOT(PresetChanged(int)));
|
connect(ui_->preset, SIGNAL(currentIndexChanged(int)), SLOT(PresetChanged(int)));
|
||||||
connect(ui_->preset_save, SIGNAL(clicked()), SLOT(SavePreset()));
|
connect(ui_->preset_save, SIGNAL(clicked()), SLOT(SavePreset()));
|
||||||
connect(ui_->preset_del, SIGNAL(clicked()), SLOT(DelPreset()));
|
connect(ui_->preset_del, SIGNAL(clicked()), SLOT(DelPreset()));
|
||||||
|
|
||||||
|
connect(ui_->enable_stereo_balancer, SIGNAL(toggled(bool)), SLOT(Save()));
|
||||||
|
connect(ui_->enable_stereo_balancer, SIGNAL(toggled(bool)), ui_->balance_slider, SLOT(setEnabled(bool)));
|
||||||
connect(ui_->balance_slider, SIGNAL(valueChanged(int)), SLOT(StereoSliderChanged(int)));
|
connect(ui_->balance_slider, SIGNAL(valueChanged(int)), SLOT(StereoSliderChanged(int)));
|
||||||
|
|
||||||
QShortcut *close = new QShortcut(QKeySequence::Close, this);
|
QShortcut *close = new QShortcut(QKeySequence::Close, this);
|
||||||
@@ -119,6 +122,10 @@ void Equalizer::ReloadSettings() {
|
|||||||
ui_->enable->setChecked(s.value("enabled", false).toBool());
|
ui_->enable->setChecked(s.value("enabled", false).toBool());
|
||||||
ui_->slider_container->setEnabled(ui_->enable->isChecked());
|
ui_->slider_container->setEnabled(ui_->enable->isChecked());
|
||||||
|
|
||||||
|
ui_->enable_stereo_balancer->setChecked(s.value("enable_stereo_balancer", false).toBool());
|
||||||
|
ui_->slider_label_layout->setEnabled(ui_->enable_stereo_balancer->isChecked());
|
||||||
|
ui_->balance_slider->setEnabled(ui_->enable_stereo_balancer->isChecked());
|
||||||
|
|
||||||
int stereo_balance = s.value("stereo_balance", 0).toInt();
|
int stereo_balance = s.value("stereo_balance", 0).toInt();
|
||||||
ui_->balance_slider->setValue(stereo_balance);
|
ui_->balance_slider->setValue(stereo_balance);
|
||||||
StereoSliderChanged(stereo_balance);
|
StereoSliderChanged(stereo_balance);
|
||||||
@@ -240,7 +247,11 @@ EqualizerSlider *Equalizer::AddSlider(const QString &label) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Equalizer::is_enabled() const {
|
bool Equalizer::is_stereo_balancer_enabled() const {
|
||||||
|
return ui_->enable_stereo_balancer->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Equalizer::is_equalizer_enabled() const {
|
||||||
return ui_->enable->isChecked();
|
return ui_->enable->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +309,7 @@ void Equalizer::Save() {
|
|||||||
// Enabled?
|
// Enabled?
|
||||||
s.setValue("enabled", ui_->enable->isChecked());
|
s.setValue("enabled", ui_->enable->isChecked());
|
||||||
|
|
||||||
|
s.setValue("enable_stereo_balancer", ui_->enable_stereo_balancer->isChecked());
|
||||||
s.setValue("stereo_balance", ui_->balance_slider->value());
|
s.setValue("stereo_balance", ui_->balance_slider->value());
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -347,7 +359,7 @@ bool Equalizer::Params::operator !=(const Equalizer::Params& other) const {
|
|||||||
|
|
||||||
void Equalizer::StereoSliderChanged(int value) {
|
void Equalizer::StereoSliderChanged(int value) {
|
||||||
Q_UNUSED(value);
|
Q_UNUSED(value);
|
||||||
emit StereoBalanceChanged(stereo_balance());
|
emit StereoBalanceChanged(is_stereo_balancer_enabled(), stereo_balance());
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ class Equalizer : public QDialog {
|
|||||||
int gain[kBands];
|
int gain[kBands];
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_enabled() const;
|
bool is_equalizer_enabled() const;
|
||||||
|
bool is_stereo_balancer_enabled() const;
|
||||||
int preamp_value() const;
|
int preamp_value() const;
|
||||||
QList<int> gain_values() const;
|
QList<int> gain_values() const;
|
||||||
Params current_params() const;
|
Params current_params() const;
|
||||||
@@ -70,7 +71,7 @@ class Equalizer : public QDialog {
|
|||||||
signals:
|
signals:
|
||||||
void EnabledChanged(bool enabled);
|
void EnabledChanged(bool enabled);
|
||||||
void ParametersChanged(int preamp, const QList<int> &band_gains);
|
void ParametersChanged(int preamp, const QList<int> &band_gains);
|
||||||
void StereoBalanceChanged(float balance);
|
void StereoBalanceChanged(bool enabled, float balance);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent *);
|
void closeEvent(QCloseEvent *);
|
||||||
|
|||||||
@@ -81,6 +81,13 @@
|
|||||||
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
|
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enable_stereo_balancer">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable stereo balancer</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="slider_label_layout">
|
<layout class="QHBoxLayout" name="slider_label_layout">
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user