From 042f8ac32539fec6eb90bbaacfac0db2be896e4e Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 1 Jun 2024 12:09:47 +0200 Subject: [PATCH] Add peak indicators (#7295) Add peak indicators to the mixer strips. They show the maximum peak value that was observed and can be reset by clicking on them. ## Implementation details The implementation works via a signal/slot mechanism. The `Fader` class has a new signal `peakChanged` which reports peak values as amplifications. A new class `PeakIndicator` is added which has a slot `updatePeak` which is connected to the new signal in `Fader`. The `PeakIndicator` inherits from `QLabel` and mainly deals with updating the label text from the current peak value. Add a `PeakIndicator` instance to `MixerChannelView`. Add a `reset` method to `MixerChannelView` so that the mixer channel can be reset on the loading of new projects, etc. The current implementation resets the peak indicator back to -inf dbFS. The `reset` method is called in `MixerView::clear`. Remove the clamping in `Fader::setPeak` so that all peaks are reported. Emit the new signal if the peak changes. --- data/themes/classic/style.css | 5 ++ data/themes/default/style.css | 5 ++ include/Fader.h | 3 ++ include/MixerChannelView.h | 5 ++ include/PeakIndicator.h | 60 ++++++++++++++++++++++ src/gui/CMakeLists.txt | 1 + src/gui/MixerChannelView.cpp | 10 ++++ src/gui/MixerView.cpp | 2 + src/gui/widgets/Fader.cpp | 4 +- src/gui/widgets/PeakIndicator.cpp | 84 +++++++++++++++++++++++++++++++ 10 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 include/PeakIndicator.h create mode 100644 src/gui/widgets/PeakIndicator.cpp diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 5489a7d21..95737ed3a 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -661,6 +661,11 @@ lmms--gui--MixerChannelView QGraphicsView { border-style: none; } +lmms--gui--PeakIndicator { + background-color: #111811; + font-size: 7pt; +} + /* persistent peak markers for fx peak meters */ lmms--gui--Fader { qproperty-peakOk: rgb( 74, 253, 133); diff --git a/data/themes/default/style.css b/data/themes/default/style.css index a4f94de09..ef98c0609 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -710,6 +710,11 @@ lmms--gui--MixerChannelView QGraphicsView { border-style: none; } +lmms--gui--PeakIndicator { + background-color: #111811; + font-size: 7pt; +} + /* persistent peak markers for fx peak meters */ lmms--gui--Fader { qproperty-peakOk: #0ad45c; diff --git a/include/Fader.h b/include/Fader.h index a3158a8b4..53e353a3d 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -105,6 +105,9 @@ public: setUnit(txt_after); } +signals: + void peakChanged(float peak); + private: void contextMenuEvent(QContextMenuEvent* me) override; void mousePressEvent(QMouseEvent* ev) override; diff --git a/include/MixerChannelView.h b/include/MixerChannelView.h index cbaf0ccc6..7ccb8a24f 100644 --- a/include/MixerChannelView.h +++ b/include/MixerChannelView.h @@ -45,6 +45,8 @@ namespace lmms namespace lmms::gui { + class PeakIndicator; + constexpr int MIXER_CHANNEL_INNER_BORDER_SIZE = 3; constexpr int MIXER_CHANNEL_OUTER_BORDER_SIZE = 1; @@ -90,6 +92,8 @@ namespace lmms::gui QColor strokeInnerInactive() const; void setStrokeInnerInactive(const QColor& c); + void reset(); + public slots: void renameChannel(); void resetColor(); @@ -119,6 +123,7 @@ namespace lmms::gui QLabel* m_receiveArrow; PixmapButton* m_muteButton; PixmapButton* m_soloButton; + PeakIndicator* m_peakIndicator = nullptr; Fader* m_fader; EffectRackView* m_effectRackView; MixerView* m_mixerView; diff --git a/include/PeakIndicator.h b/include/PeakIndicator.h new file mode 100644 index 000000000..2bc912292 --- /dev/null +++ b/include/PeakIndicator.h @@ -0,0 +1,60 @@ +/* + * PeakIndicator.h - Peak indicator widget + * + * Copyright (c) 2024- Michael Gregorius + * + * This file is part of LMMS - https://lmms.io + * + * This program 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 2 of the License, or (at your option) any later version. + * + * This program 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 this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef LMMS_GUI_PEAKINDICATOR_H +#define LMMS_GUI_PEAKINDICATOR_H + +#include "lmms_export.h" + +#include + + +namespace lmms::gui +{ + +class LMMS_EXPORT PeakIndicator : public QLabel +{ + Q_OBJECT +public: + PeakIndicator(QWidget* parent); + + void resetPeakToMinusInf(); + +public slots: + void updatePeak(float peak); + +protected: + void mousePressEvent(QMouseEvent* e) override; + +private: + void updatePeakDisplay(); + +private: + float m_peak; +} ; + +} // namespace lmms::gui + +#endif // LMMS_GUI_PEAKINDICATOR_H diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 2485b92d2..4195ec58c 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -117,6 +117,7 @@ SET(LMMS_SRCS gui/widgets/MixerChannelLcdSpinBox.cpp gui/widgets/NStateButton.cpp gui/widgets/Oscilloscope.cpp + gui/widgets/PeakIndicator.cpp gui/widgets/PixmapButton.cpp gui/widgets/SimpleTextFloat.cpp gui/widgets/TabBar.cpp diff --git a/src/gui/MixerChannelView.cpp b/src/gui/MixerChannelView.cpp index 0afdb684e..2a1fe0928 100644 --- a/src/gui/MixerChannelView.cpp +++ b/src/gui/MixerChannelView.cpp @@ -28,6 +28,7 @@ #include "Mixer.h" #include "MixerChannelView.h" #include "MixerView.h" +#include "PeakIndicator.h" #include "Song.h" #include "ConfigManager.h" @@ -121,6 +122,9 @@ namespace lmms::gui m_fader = new Fader{&mixerChannel->m_volumeModel, tr("Fader %1").arg(channelIndex), this}; + m_peakIndicator = new PeakIndicator(this); + connect(m_fader, &Fader::peakChanged, m_peakIndicator, &PeakIndicator::updatePeak); + m_effectRackView = new EffectRackView{&mixerChannel->m_fxChain, mixerView->m_racksWidget}; m_effectRackView->setFixedWidth(EffectRackView::DEFAULT_WIDTH); @@ -133,6 +137,7 @@ namespace lmms::gui mainLayout->addWidget(m_channelNumberLcd, 0, Qt::AlignHCenter); mainLayout->addWidget(m_renameLineEditView, 0, Qt::AlignHCenter); mainLayout->addLayout(soloMuteLayout, 0); + mainLayout->addWidget(m_peakIndicator); mainLayout->addWidget(m_fader, 1, Qt::AlignHCenter); connect(m_renameLineEdit, &QLineEdit::editingFinished, this, &MixerChannelView::renameFinished); @@ -340,6 +345,11 @@ namespace lmms::gui m_strokeInnerInactive = c; } + void MixerChannelView::reset() + { + m_peakIndicator->resetPeakToMinusInf(); + } + void MixerChannelView::renameChannel() { m_inRename = true; diff --git a/src/gui/MixerView.cpp b/src/gui/MixerView.cpp index b9a698a96..8152509f8 100644 --- a/src/gui/MixerView.cpp +++ b/src/gui/MixerView.cpp @@ -544,6 +544,8 @@ void MixerView::clear() for (auto i = m_mixerChannelViews.size() - 1; i > 0; --i) { deleteChannel(i); } getMixer()->clearChannel(0); + m_mixerChannelViews[0]->reset(); + refreshDisplay(); } diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index d2d7c1c2e..24b16bfe4 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -207,8 +207,6 @@ void Fader::wheelEvent (QWheelEvent* ev) /// void Fader::setPeak(float fPeak, float& targetPeak, float& persistentPeak, QElapsedTimer& lastPeakTimer) { - fPeak = std::clamp(fPeak, m_fMinPeak, m_fMaxPeak); - if (targetPeak != fPeak) { targetPeak = fPeak; @@ -216,6 +214,7 @@ void Fader::setPeak(float fPeak, float& targetPeak, float& persistentPeak, QElap { persistentPeak = targetPeak; lastPeakTimer.restart(); + emit peakChanged(persistentPeak); } update(); } @@ -223,6 +222,7 @@ void Fader::setPeak(float fPeak, float& targetPeak, float& persistentPeak, QElap if (persistentPeak > 0 && lastPeakTimer.elapsed() > 1500) { persistentPeak = qMax(0, persistentPeak-0.05); + emit peakChanged(persistentPeak); update(); } } diff --git a/src/gui/widgets/PeakIndicator.cpp b/src/gui/widgets/PeakIndicator.cpp new file mode 100644 index 000000000..e1278b7ff --- /dev/null +++ b/src/gui/widgets/PeakIndicator.cpp @@ -0,0 +1,84 @@ +/* + * PeakIndicator.cpp - Peak indicator widget + * + * Copyright (c) 2024- Michael Gregorius + * + * This file is part of LMMS - https://lmms.io + * + * This program 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 2 of the License, or (at your option) any later version. + * + * This program 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 this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "PeakIndicator.h" + +#include "lmms_math.h" + +#include +#include + + +namespace lmms::gui +{ + +PeakIndicator::PeakIndicator(QWidget* parent) : + QLabel(parent), + m_peak(0.f) +{ + setAlignment(Qt::AlignCenter); + + updatePeakDisplay(); +} + +void PeakIndicator::resetPeakToMinusInf() +{ + m_peak = 0; + updatePeakDisplay(); +} + +void PeakIndicator::updatePeak(float peak) +{ + if (peak > m_peak) + { + m_peak = peak; + updatePeakDisplay(); + } +} + +void PeakIndicator::mousePressEvent(QMouseEvent* e) +{ + if (e->buttons() & Qt::LeftButton) + { + resetPeakToMinusInf(); + } +} + +void PeakIndicator::updatePeakDisplay() +{ + // Treat everything below -144 dbFS as -inf. Otherwise some residual signals show up + // in the form of very small dbFS values, e.g. -857.1 dbFS. + // TODO Make the threshold configurable in the settings? + if (m_peak <= dbfsToAmp(-144.)) + { + setText(tr("-inf")); + } + else + { + auto dbfs = ampToDbfs(m_peak); + setText(QString::number(dbfs, 'f', 1)); + } +} + +} // namespace lmms::gui