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