From e800b236aa9e7bc64ad072c9bb746b9c8c8a16f2 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sun, 27 Oct 2019 23:48:54 +0100 Subject: [PATCH] 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 --- src/core/mainwindow.cpp | 4 + src/core/player.cpp | 6 +- src/engine/enginebase.h | 6 +- src/engine/gstengine.cpp | 7 +- src/engine/gstengine.h | 20 +-- src/engine/gstenginepipeline.cpp | 291 ++++++++++++++++--------------- src/engine/gstenginepipeline.h | 29 ++- src/equalizer/equalizer.cpp | 16 +- src/equalizer/equalizer.h | 5 +- src/equalizer/equalizer.ui | 7 + tests/data/audio/strawberry.flac | Bin 41426 -> 37390 bytes 11 files changed, 207 insertions(+), 184 deletions(-) diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index 408416283..961c73a7b 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -1257,9 +1257,11 @@ void MainWindow::PlayIndex(const QModelIndex &index) { app_->playlist_manager()->SetActiveToCurrent(); app_->player()->PlayAt(row, Engine::Manual, true); + } void MainWindow::PlaylistDoubleClick(const QModelIndex &index) { + if (!index.isValid()) return; int row = index.row(); @@ -1284,6 +1286,7 @@ void MainWindow::PlaylistDoubleClick(const QModelIndex &index) { } break; } + } void MainWindow::VolumeWheelEvent(int delta) { @@ -1315,6 +1318,7 @@ void MainWindow::ToggleShowHide() { activateWindow(); raise(); } + } void MainWindow::StopAfterCurrent() { diff --git a/src/core/player.cpp b/src/core/player.cpp index bc90c9aa6..3b58e48a7 100644 --- a/src/core/player.cpp +++ b/src/core/player.cpp @@ -203,11 +203,11 @@ void Player::Init() { qLog(Debug) << "Creating equalizer"; connect(equalizer_, SIGNAL(ParametersChanged(int,QList)), app_->player()->engine(), SLOT(SetEqualizerParameters(int,QList))); 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_->SetStereoBalance(equalizer_->stereo_balance()); s.beginGroup(BackendSettingsPage::kSettingsGroup); volume_control_ = s.value("volume_control", true).toBool(); diff --git a/src/engine/enginebase.h b/src/engine/enginebase.h index d3640343e..0bb323798 100644 --- a/src/engine/enginebase.h +++ b/src/engine/enginebase.h @@ -128,7 +128,7 @@ public: public slots: virtual void SetEqualizerEnabled(const bool) {} virtual void SetEqualizerParameters(const int preamp, const QList &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: // Emitted when crossfading is enabled and the track is crossfade_duration_ away from finishing @@ -214,13 +214,13 @@ struct SimpleMetaBundle { QString album; QString comment; QString genre; - qlonglong length; + qint64 length; int year; int track; Song::FileType filetype; int samplerate; int bitdepth; - qlonglong bitrate; + qint64 bitrate; QString lyrics; }; diff --git a/src/engine/gstengine.cpp b/src/engine/gstengine.cpp index 967532cca..782f5778d 100644 --- a/src/engine/gstengine.cpp +++ b/src/engine/gstengine.cpp @@ -83,6 +83,7 @@ GstEngine::GstEngine(TaskManager *task_manager) task_manager_(task_manager), buffering_task_id_(-1), latest_buffer_(nullptr), + stereo_balancer_enabled_(false), stereo_balance_(0.0f), seek_timer_(new QTimer(this)), timer_id_(-1), @@ -174,7 +175,7 @@ bool GstEngine::Load(const QUrl &stream_url, const QUrl &original_url, Engine::T current_pipeline_ = pipeline; SetVolume(volume_); - SetStereoBalance(stereo_balance_); + SetStereoBalance(stereo_balancer_enabled_, stereo_balance_); SetEqualizerParameters(equalizer_preamp_, equalizer_gains_); // Maybe fade in this track @@ -441,11 +442,11 @@ void GstEngine::SetEqualizerParameters(const int preamp, const QList &band_ } -void GstEngine::SetStereoBalance(const float value) { +void GstEngine::SetStereoBalance(const bool enabled, const float value) { stereo_balance_ = value; - if (current_pipeline_) current_pipeline_->SetStereoBalance(value); + if (current_pipeline_) current_pipeline_->SetStereoBalance(enabled, value); } diff --git a/src/engine/gstengine.h b/src/engine/gstengine.h index f87f0c899..b305e8345 100644 --- a/src/engine/gstengine.h +++ b/src/engine/gstengine.h @@ -50,11 +50,6 @@ class TaskManager; class GstEnginePipeline; -#ifdef Q_OS_MACOS -struct _GTlsDatabase; -typedef struct _GTlsDatabase GTlsDatabase; -#endif - /** * @class GstEngine * @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); public slots: - void ReloadSettings(); /** Set whether equalizer is enabled */ @@ -108,15 +102,11 @@ class GstEngine : public Engine::Base, public GstBufferConsumer { void SetEqualizerParameters(const int preamp, const QList &bandGains); /** 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 RemoveBufferConsumer(GstBufferConsumer *consumer); -#ifdef Q_OS_MACOS - GTlsDatabase *tls_database() const { return tls_database_; } -#endif - protected: void timerEvent(QTimerEvent*); @@ -180,9 +170,11 @@ class GstEngine : public Engine::Base, public GstBufferConsumer { GstBuffer *latest_buffer_; + bool stereo_balancer_enabled_; + float stereo_balance_; + int equalizer_preamp_; QList equalizer_gains_; - float stereo_balance_; mutable bool can_decode_success_; mutable bool can_decode_last_; @@ -203,10 +195,6 @@ class GstEngine : public Engine::Base, public GstBufferConsumer { int scope_chunks_; QString buffer_format_; -#ifdef Q_OS_MACOS - GTlsDatabase* tls_database_; -#endif - }; #endif /* GSTENGINE_H */ diff --git a/src/engine/gstenginepipeline.cpp b/src/engine/gstenginepipeline.cpp index 0d09c0736..3c57021f8 100644 --- a/src/engine/gstenginepipeline.cpp +++ b/src/engine/gstenginepipeline.cpp @@ -67,9 +67,10 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine) id_(sId++), valid_(false), volume_control_(true), + stereo_balance_enabled_(false), + stereo_balance_(0.0f), eq_enabled_(false), eq_preamp_(0), - stereo_balance_(0.0f), rg_enabled_(false), rg_mode_(0), rg_preamp_(0.0), @@ -93,17 +94,11 @@ GstEnginePipeline::GstEnginePipeline(GstEngine *engine) use_fudge_timer_(false), pipeline_(nullptr), audiobin_(nullptr), - queue_(nullptr), - audioconvert_(nullptr), - audioconvert2_(nullptr), - audioscale_(nullptr), - audiosink_(nullptr), + audioqueue_(nullptr), volume_(nullptr), - audio_panorama_(nullptr), - equalizer_preamp_(nullptr), + audiopanorama_(nullptr), equalizer_(nullptr), - rgvolume_(nullptr), - rglimiter_(nullptr), + equalizer_preamp_(nullptr), discoverer_(nullptr), about_to_finish_cb_id_(-1), pad_added_cb_id_(-1), @@ -193,26 +188,26 @@ bool GstEnginePipeline::InitAudioBin() { if (!audiobin_) return false; // Create the sink - audiosink_ = engine_->CreateElement(output_, audiobin_); - if (!audiosink_) { + GstElement *audiosink = engine_->CreateElement(output_, audiobin_); + if (!audiosink) { gst_object_unref(GST_OBJECT(audiobin_)); 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()) { case QVariant::String: 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; 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; case QVariant::LongLong: - g_object_set(G_OBJECT(audiosink_), "device", device_.toLongLong(), nullptr); + g_object_set(G_OBJECT(audiosink), "device", device_.toLongLong(), nullptr); break; case QVariant::Int: - g_object_set(G_OBJECT(audiosink_), "device", device_.toInt(), nullptr); + g_object_set(G_OBJECT(audiosink), "device", device_.toInt(), nullptr); break; default: qLog(Warning) << "Unknown device type" << device_; @@ -222,133 +217,144 @@ bool GstEnginePipeline::InitAudioBin() { // Create all the other elements - queue_ = engine_->CreateElement("queue2", audiobin_); - audioconvert_ = engine_->CreateElement("audioconvert", audiobin_); - GstElement *audio_queue = engine_->CreateElement("queue", audiobin_); - audioscale_ = engine_->CreateElement("audioresample", audiobin_); - GstElement *convert = engine_->CreateElement("audioconvert", audiobin_); + audioqueue_ = engine_->CreateElement("queue2", audiobin_); + GstElement *audioconverter = engine_->CreateElement("audioconvert", audiobin_); - if (engine_->volume_control()) { - 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) { + if (!audioqueue_ || !audioconverter) { gst_object_unref(GST_OBJECT(audiobin_)); audiobin_ = nullptr; return false; } - // Create the replaygain 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. - // convert_sink is the element after the first audioconvert, which again will change. - GstElement *event_probe = audioconvert_; - GstElement *convert_sink = audio_queue; + // Create the volume elements if it's enabled. + if (volume_control_) { + volume_ = engine_->CreateElement("volume", audiobin_); + } + // 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_) { - rgvolume_ = engine_->CreateElement("rgvolume", audiobin_, false); - rglimiter_ = engine_->CreateElement("rglimiter", audiobin_, false); - audioconvert2_ = engine_->CreateElement("audioconvert", audiobin_, false); - if (rgvolume_ && rglimiter_ && audioconvert2_) { - event_probe = audioconvert2_; - convert_sink = rgvolume_; + rgvolume = engine_->CreateElement("rgvolume", audiobin_, false); + rglimiter = engine_->CreateElement("rglimiter", audiobin_, false); + audioconverter2 = engine_->CreateElement("audioconvert", audiobin_, false); + if (rgvolume && rglimiter && audioconverter2) { + eventprobe = audioconverter2; // Set replaygain settings - 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(rglimiter_), "enabled", int(rg_compression_), 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(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. - 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_object_unref(pad); // 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. - 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_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. // 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. - g_object_set(G_OBJECT(queue_), "max-size-buffers", 0, nullptr); - g_object_set(G_OBJECT(queue_), "max-size-bytes", 0, nullptr); - g_object_set(G_OBJECT(queue_), "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_), "max-size-buffers", 0, nullptr); + g_object_set(G_OBJECT(audioqueue_), "max-size-bytes", 0, nullptr); + g_object_set(G_OBJECT(audioqueue_), "max-size-time", buffer_duration_nanosec_, nullptr); + g_object_set(G_OBJECT(audioqueue_), "low-percent", buffer_min_fill_, nullptr); 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. - if (rg_enabled_ && rgvolume_ && rglimiter_ && audioconvert2_) { - gst_element_link_many(rgvolume_, rglimiter_, audioconvert2_, audio_queue, nullptr); + if (rg_enabled_ && rgvolume && rglimiter && audioconverter2) { + gst_element_link_many(next, rgvolume, rglimiter, audioconverter2, nullptr); + next = audioconverter2; } - if (eq_enabled_ && equalizer_ && equalizer_preamp_ && audio_panorama_) { - if (volume_) - gst_element_link_many(audio_queue, equalizer_preamp_, equalizer_, audio_panorama_, volume_, audioscale_, convert, nullptr); - else - gst_element_link_many(audio_queue, equalizer_preamp_, equalizer_, audio_panorama_, audioscale_, convert, nullptr); + // Link equalizer elements if enabled. + if (eq_enabled_ && equalizer_ && equalizer_preamp_) { + gst_element_link_many(next, equalizer_preamp_, equalizer_, nullptr); + next = equalizer_; } - else { - if (volume_) gst_element_link_many(audio_queue, volume_, audioscale_, convert, nullptr); - else gst_element_link_many(audio_queue, audioscale_, convert, nullptr); + + // Link equalizer elements if enabled. + 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. 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); // 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_object_unref(pad); @@ -665,7 +671,7 @@ void GstEnginePipeline::StateChangedMessageReceived(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. - if (GST_ELEMENT(GST_MESSAGE_SRC(msg)) != queue_) { + if (GST_ELEMENT(GST_MESSAGE_SRC(msg)) != audioqueue_) { return; } @@ -788,7 +794,7 @@ GstPadProbeReturn GstEnginePipeline::HandoffCallback(GstPad *pad, GstPadProbeInf int buf16_size = samples * sizeof(int16_t) * channels; int16_t *d = (int16_t*) g_malloc(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); } 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) { eq_enabled_ = enabled; @@ -988,11 +1032,10 @@ void GstEnginePipeline::SetEqualizerParams(const int preamp, const QList& b } -void GstEnginePipeline::SetStereoBalance(const float value) { - - stereo_balance_ = value; - UpdateStereoBalance(); - +void GstEnginePipeline::UpdateStereoBalance() { + if (audiopanorama_) { + g_object_set(G_OBJECT(audiopanorama_), "panorama", stereo_balance_, nullptr); + } } 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) { const int duration_msec = duration_nanosec / kNsecPerMsec; @@ -1167,7 +1186,7 @@ void GstEnginePipeline::StreamDiscovered(GstDiscoverer *, GstDiscovererInfo *inf bundle.stream_url = QUrl(discovered_url); 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.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); gchar *codec_description = gst_pb_utils_get_codec_description(caps); diff --git a/src/engine/gstenginepipeline.h b/src/engine/gstenginepipeline.h index e43a458ee..d84d0e36c 100644 --- a/src/engine/gstenginepipeline.h +++ b/src/engine/gstenginepipeline.h @@ -88,7 +88,7 @@ class GstEnginePipeline : public QObject { void SetEqualizerEnabled(const bool enabled); void SetEqualizerParams(const int preamp, const QList &band_gains); 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); // If this is set then it will be loaded automatically when playback finishes for gapless playback @@ -193,16 +193,17 @@ signals: QVariant device_; 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 bool eq_enabled_; int eq_preamp_; QList eq_band_gains_; - // Stereo balance. - // From -1.0 - 1.0 - // -1.0 is left, 1.0 is right. - float stereo_balance_; - // ReplayGain bool rg_enabled_; int rg_mode_; @@ -267,22 +268,12 @@ signals: bool use_fudge_timer_; GstElement *pipeline_; - - // The audiobin is either linked with a playbin or set as sink of the playbin pipeline. GstElement *audiobin_; - - // Elements in the audiobin. See comments in Init()'s definition. - GstElement *queue_; - GstElement *audioconvert_; - GstElement *audioconvert2_; - GstElement *audioscale_; - GstElement *audiosink_; + GstElement *audioqueue_; GstElement *volume_; - GstElement *audio_panorama_; - GstElement *equalizer_preamp_; + GstElement *audiopanorama_; GstElement *equalizer_; - GstElement *rgvolume_; - GstElement *rglimiter_; + GstElement *equalizer_preamp_; GstDiscoverer *discoverer_; int about_to_finish_cb_id_; diff --git a/src/equalizer/equalizer.cpp b/src/equalizer/equalizer.cpp index b89616450..cdf1ab495 100644 --- a/src/equalizer/equalizer.cpp +++ b/src/equalizer/equalizer.cpp @@ -80,6 +80,9 @@ Equalizer::Equalizer(QWidget *parent) connect(ui_->preset, SIGNAL(currentIndexChanged(int)), SLOT(PresetChanged(int))); connect(ui_->preset_save, SIGNAL(clicked()), SLOT(SavePreset())); 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))); QShortcut *close = new QShortcut(QKeySequence::Close, this); @@ -119,6 +122,10 @@ void Equalizer::ReloadSettings() { ui_->enable->setChecked(s.value("enabled", false).toBool()); 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(); ui_->balance_slider->setValue(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(); } @@ -298,6 +309,7 @@ void Equalizer::Save() { // Enabled? s.setValue("enabled", ui_->enable->isChecked()); + s.setValue("enable_stereo_balancer", ui_->enable_stereo_balancer->isChecked()); 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) { Q_UNUSED(value); - emit StereoBalanceChanged(stereo_balance()); + emit StereoBalanceChanged(is_stereo_balancer_enabled(), stereo_balance()); Save(); } diff --git a/src/equalizer/equalizer.h b/src/equalizer/equalizer.h index acce66651..36fd36790 100644 --- a/src/equalizer/equalizer.h +++ b/src/equalizer/equalizer.h @@ -61,7 +61,8 @@ class Equalizer : public QDialog { int gain[kBands]; }; - bool is_enabled() const; + bool is_equalizer_enabled() const; + bool is_stereo_balancer_enabled() const; int preamp_value() const; QList gain_values() const; Params current_params() const; @@ -70,7 +71,7 @@ class Equalizer : public QDialog { signals: void EnabledChanged(bool enabled); void ParametersChanged(int preamp, const QList &band_gains); - void StereoBalanceChanged(float balance); + void StereoBalanceChanged(bool enabled, float balance); protected: void closeEvent(QCloseEvent *); diff --git a/src/equalizer/equalizer.ui b/src/equalizer/equalizer.ui index 9dc7c0557..1e79d6619 100644 --- a/src/equalizer/equalizer.ui +++ b/src/equalizer/equalizer.ui @@ -81,6 +81,13 @@ + + + + Enable stereo balancer + + + diff --git a/tests/data/audio/strawberry.flac b/tests/data/audio/strawberry.flac index 571e1da1bdf8a2ee6dfad4e67bfda23982e5e14d..e4d1ca93fc81c6872cab92382bf2fc865c978240 100644 GIT binary patch delta 145 zcmca~n5l0G(*)i63SI^V2A{;TG*b&bBLh7{0|Pdo07%f;-#5V1$1%jy-_O>79Vp=9 z7~*QHYbXk2y81c$ySN6~qG;p-O1QiF1-aUWq!yQecp;u4J`f%sh!^DO?Clro>jc!O VYuL!Z|A~QNWAX?7%?S!cjR28WBTE1P delta 75 zcmeBM!gT2{(*#{3JzfR|2A{;TG*b&bBLh7{0|Q2&fG7~B<|XH+q!!ttNH#JkY~1*o Sf8&8W{1XpYZJr}g)Cd6kT^8v8