diff options
author | Owen Williams <owilliams@mixxx.org> | 2021-06-28 10:42:43 -0400 |
---|---|---|
committer | Owen Williams <owilliams@mixxx.org> | 2021-07-21 14:53:02 -0400 |
commit | f6e6b68bcd6216be39c27c7cdf0563d01df5b287 (patch) | |
tree | c75eea6f6f35370d956eb72d627dfec794c1f090 | |
parent | afbbe72b6d1a5d61f334647946376f9fb8885c7c (diff) |
Adjust ReplayGain: Allow user to update the replaygain value based on a deck pregain value.
Currently accessible by right clicking loaded decks, including preview deck
-rw-r--r-- | src/mixer/basetrackplayer.cpp | 18 | ||||
-rw-r--r-- | src/mixer/basetrackplayer.h | 3 | ||||
-rw-r--r-- | src/track/replaygain.h | 9 | ||||
-rw-r--r-- | src/track/track.cpp | 24 | ||||
-rw-r--r-- | src/track/track.h | 5 | ||||
-rw-r--r-- | src/widget/wtrackmenu.cpp | 32 | ||||
-rw-r--r-- | src/widget/wtrackmenu.h | 10 | ||||
-rw-r--r-- | src/widget/wtrackproperty.cpp | 7 | ||||
-rw-r--r-- | src/widget/wtracktext.cpp | 7 | ||||
-rw-r--r-- | src/widget/wtrackwidgetgroup.cpp | 5 |
10 files changed, 100 insertions, 20 deletions
diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 63313d16e2..355b29cc58 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -597,11 +597,23 @@ void BaseTrackPlayerImpl::slotCloneChannel(EngineChannel* pChannel) { slotLoadTrack(pTrack, false); } -void BaseTrackPlayerImpl::slotSetReplayGain(mixxx::ReplayGain replayGain) { +void BaseTrackPlayerImpl::slotSetReplayGain(mixxx::ReplayGain replayGain, + mixxx::ReplayGain::ReplayGainUpdateMode mode) { // Do not change replay gain when track is playing because // this may lead to an unexpected volume change - if (m_pPlay->get() == 0.0) { - setReplayGain(replayGain.getRatio()); + if (m_pPlay->get() == 0.0 || mode == mixxx::ReplayGain::UpdateAndAdjustGain) { + const double factor = m_pReplayGain->get() / replayGain.getRatio(); + const double newPregain = m_pPreGain->get() * factor; + // There is a very slight chance that there will be a buffer call in between these sets. + // Therefore, we first adjust the control that is being lowered before the control + // that is being raised. Worst case, the volume goes down briefly before rectifying. + if (newPregain <= replayGain.getRatio()) { + m_pPreGain->set(newPregain); + setReplayGain(replayGain.getRatio()); + } else { + setReplayGain(replayGain.getRatio()); + m_pPreGain->set(newPregain); + } } else { m_replaygainPending = true; } diff --git a/src/mixer/basetrackplayer.h b/src/mixer/basetrackplayer.h index 87bceec0b7..165dcd2c5e 100644 --- a/src/mixer/basetrackplayer.h +++ b/src/mixer/basetrackplayer.h @@ -81,7 +81,8 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer { void slotCloneDeck() final; void slotTrackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack); void slotLoadFailed(TrackPointer pTrack, const QString& reason); - void slotSetReplayGain(mixxx::ReplayGain replayGain); + void slotSetReplayGain(mixxx::ReplayGain replayGain, + mixxx::ReplayGain::ReplayGainUpdateMode mode); void slotSetTrackColor(const mixxx::RgbColor::optional_t& color); void slotPlayToggled(double); diff --git a/src/track/replaygain.h b/src/track/replaygain.h index 76c3e51fa5..a72af495c6 100644 --- a/src/track/replaygain.h +++ b/src/track/replaygain.h @@ -99,7 +99,12 @@ public: m_peak = normalizePeak(m_peak); } -private: + enum ReplayGainUpdateMode { + UpdateWhenStopped, + UpdateAndAdjustGain + }; + + private: double m_ratio; CSAMPLE m_peak; }; @@ -119,7 +124,7 @@ QDebug operator<<(QDebug dbg, const ReplayGain& arg) { return dbg << "ratio =" << arg.getRatio() << "/" << "peak =" << arg.getPeak(); } -} +} // namespace mixxx Q_DECLARE_TYPEINFO(mixxx::ReplayGain, Q_MOVABLE_TYPE); Q_DECLARE_METATYPE(mixxx::ReplayGain) diff --git a/src/track/track.cpp b/src/track/track.cpp index 2402aaf259..23f7b031f7 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -207,7 +207,7 @@ void Track::replaceMetadataFromSource( emit keyChanged(); } if (oldReplayGain != newReplayGain) { - emit replayGainUpdated(newReplayGain); + emit replayGainUpdated(newReplayGain, mixxx::ReplayGain::UpdateWhenStopped); } if (colorModified) { emit colorUpdated(newColor); @@ -305,7 +305,7 @@ bool Track::replaceRecord( emit keyChanged(); } if (oldReplayGain != newReplayGain) { - emit replayGainUpdated(newReplayGain); + emit replayGainUpdated(newReplayGain, mixxx::ReplayGain::UpdateWhenStopped); } if (oldColor != newColor) { emit colorUpdated(newColor); @@ -324,7 +324,25 @@ void Track::setReplayGain(const mixxx::ReplayGain& replayGain) { auto locked = lockMutex(&m_qMutex); if (compareAndSet(m_record.refMetadata().refTrackInfo().ptrReplayGain(), replayGain)) { markDirtyAndUnlock(&locked); - emit replayGainUpdated(replayGain); + emit replayGainUpdated(replayGain, mixxx::ReplayGain::UpdateWhenStopped); + } +} + +void Track::adjustReplayGainFromDeckGain(const QString& deckGroup) { + QMutexLocker lock(&m_qMutex); + mixxx::ReplayGain replayGain = m_record.getMetadata().getTrackInfo().getReplayGain(); + auto deckPregainCO = ControlProxy(deckGroup, "pregain"); + if (!deckPregainCO.valid()) { + qDebug() << "pregain CO not valid"; + return; + } + const double gain = deckPregainCO.get(); + qDebug() << "ADJUST REPLAYGAIN: old: " << replayGain.getRatio() + << " adjust " << gain << " so: " << replayGain.getRatio() * gain; + replayGain.setRatio(replayGain.getRatio() * gain); + if (compareAndSet(m_record.refMetadata().refTrackInfo().ptrReplayGain(), replayGain)) { + markDirtyAndUnlock(&lock); + emit replayGainUpdated(replayGain, mixxx::ReplayGain::UpdateAndAdjustGain); } } diff --git a/src/track/track.h b/src/track/track.h index 5dab8dd708..1f174eafa3 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -144,6 +144,8 @@ class Track : public QObject { // Set ReplayGain void setReplayGain(const mixxx::ReplayGain&); + // Adjust ReplayGain by the value from the given deck's pregain knob. + void adjustReplayGainFromDeckGain(const QString& deckGroup); // Returns ReplayGain mixxx::ReplayGain getReplayGain() const; @@ -409,7 +411,8 @@ class Track : public QObject { void waveformSummaryUpdated(); void coverArtUpdated(); void beatsUpdated(); - void replayGainUpdated(mixxx::ReplayGain replayGain); + void replayGainUpdated(mixxx::ReplayGain replayGain, + mixxx::ReplayGain::ReplayGainUpdateMode mode); void colorUpdated(const mixxx::RgbColor::optional_t& color); void cuesUpdated(); void analyzed(); diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 4fccccbc70..802078db30 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -340,6 +340,15 @@ void WTrackMenu::createActions() { &WTrackMenu::slotClearBeats); } + if (featureIsEnabled(Feature::UpdateReplayGain)) { + m_pUpdateReplayGain = + new QAction(tr("Update ReplayGain from Deck Gain"), m_pClearMetadataMenu); + connect(m_pUpdateReplayGain, + &QAction::triggered, + this, + &WTrackMenu::slotUpdateReplaygain); + } + if (featureIsEnabled(Feature::Color)) { ColorPaletteSettings colorPaletteSettings(m_pConfig); m_pColorPickerAction = new WColorPickerAction(WColorPicker::Option::AllowNoColor, @@ -473,6 +482,10 @@ void WTrackMenu::setupActions() { addMenu(m_pClearMetadataMenu); } + if (featureIsEnabled(Feature::UpdateReplayGain)) { + addAction(m_pUpdateReplayGain); + } + addSeparator(); if (featureIsEnabled(Feature::HideUnhidePurge)) { if (m_pTrackModel->hasCapabilities(TrackModel::Capability::Hide)) { @@ -701,6 +714,10 @@ void WTrackMenu::updateMenus() { } } + if (featureIsEnabled(Feature::UpdateReplayGain)) { + m_pUpdateReplayGain->setEnabled(!m_deckGroup.isEmpty()); + } + if (featureIsEnabled(Feature::Color)) { m_pColorPickerAction->setColorPalette( ColorPaletteSettings(m_pConfig).getTrackColorPalette()); @@ -736,7 +753,7 @@ void WTrackMenu::updateMenus() { } void WTrackMenu::loadTrack( - const TrackPointer& pTrack) { + const TrackPointer& pTrack, const QString& deckGroup) { // This asserts that this function is only accessible when a track model is not set, // thus maintaining only the TrackPointerList in state and avoiding storing // duplicate state with TrackIdList and QModelIndexList. @@ -751,6 +768,7 @@ void WTrackMenu::loadTrack( return; } m_pTrack = pTrack; + m_deckGroup = deckGroup; updateMenus(); } @@ -899,6 +917,17 @@ class ImportMetadataFromFileTagsTrackPointerOperation : public mixxx::TrackPoint } // anonymous namespace +void WTrackMenu::slotUpdateReplaygain() { + if (!m_pTrack) { + qDebug() << "track pointer nullptr, returning"; + return; + } + if (m_deckGroup.isEmpty()) { + qDebug() << "deck group not set"; + } + m_pTrack->adjustReplayGainFromDeckGain(m_deckGroup); +} + void WTrackMenu::slotImportMetadataFromFileTags() { const auto progressLabelText = tr("Importing metadata of %n track(s) from file tags", "", getTrackCount()); @@ -1723,6 +1752,7 @@ void WTrackMenu::slotPurge() { void WTrackMenu::clearTrackSelection() { m_pTrack = nullptr; + m_deckGroup.clear(); m_trackIndexList.clear(); } diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index 54c8fb465b..5e232d7c36 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -47,6 +47,7 @@ class WTrackMenu : public QMenu { FileBrowser = 1 << 10, Properties = 1 << 11, SearchRelated = 1 << 12, + UpdateReplayGain = 1 << 13, TrackModelFeatures = Remove | HideUnhidePurge, All = AutoDJ | LoadTo | Playlist | Crate | Remove | Metadata | Reset | BPM | Color | HideUnhidePurge | FileBrowser | Properties | @@ -69,7 +70,7 @@ class WTrackMenu : public QMenu { const QModelIndexList& trackIndexList); void loadTrack( - const TrackPointer& pTrack); + const TrackPointer& pTrack, const QString& deckGroup); // WARNING: This function hides non-virtual QMenu::popup(). // This has been done on purpose to ensure menu doesn't popup without loaded track(s). @@ -106,6 +107,7 @@ class WTrackMenu : public QMenu { void slotScaleBpm(mixxx::Beats::BpmScale scale); // Info and metadata + void slotUpdateReplaygain(); void slotShowDlgTagFetcher(); void slotImportMetadataFromFileTags(); void slotExportMetadataIntoFileTags(); @@ -188,6 +190,9 @@ class WTrackMenu : public QMenu { /// Track being referenced when TrackModel is not set. TrackPointer m_pTrack; + /// If the user right clicked on a track in a deck, this will record which + /// deck made the request. + QString m_deckGroup; const ControlProxy* m_pNumSamplers{}; const ControlProxy* m_pNumDecks{}; @@ -207,6 +212,9 @@ class WTrackMenu : public QMenu { WCoverArtMenu* m_pCoverMenu{}; parented_ptr<WSearchRelatedTracksMenu> m_pSearchRelatedMenu; + // Update Replaygain from Track + QAction* m_pUpdateReplayGain{}; + // Reload Track Metadata Action: QAction* m_pImportMetadataFromFileAct{}; QAction* m_pImportMetadataFromMusicBrainzAct{}; diff --git a/src/widget/wtrackproperty.cpp b/src/widget/wtrackproperty.cpp index 67cea1b497..c4705610a3 100644 --- a/src/widget/wtrackproperty.cpp +++ b/src/widget/wtrackproperty.cpp @@ -19,7 +19,8 @@ constexpr WTrackMenu::Features kTrackMenuFeatures = WTrackMenu::Feature::BPM | WTrackMenu::Feature::Color | WTrackMenu::Feature::FileBrowser | - WTrackMenu::Feature::Properties; + WTrackMenu::Feature::Properties | + WTrackMenu::Feature::UpdateReplayGain; } // namespace WTrackProperty::WTrackProperty( @@ -91,7 +92,7 @@ void WTrackProperty::mouseMoveEvent(QMouseEvent* event) { void WTrackProperty::mouseDoubleClickEvent(QMouseEvent* event) { Q_UNUSED(event); if (m_pCurrentTrack) { - m_pTrackMenu->loadTrack(m_pCurrentTrack); + m_pTrackMenu->loadTrack(m_pCurrentTrack, m_group); m_pTrackMenu->slotShowDlgTrackInfo(); } } @@ -107,7 +108,7 @@ void WTrackProperty::dropEvent(QDropEvent* event) { void WTrackProperty::contextMenuEvent(QContextMenuEvent* event) { event->accept(); if (m_pCurrentTrack) { - m_pTrackMenu->loadTrack(m_pCurrentTrack); + m_pTrackMenu->loadTrack(m_pCurrentTrack, m_group); // Create the right-click menu m_pTrackMenu->popup(event->globalPos()); } diff --git a/src/widget/wtracktext.cpp b/src/widget/wtracktext.cpp index 3c1ddcf7a4..93db0d62ff 100644 --- a/src/widget/wtracktext.cpp +++ b/src/widget/wtracktext.cpp @@ -19,7 +19,8 @@ constexpr WTrackMenu::Features kTrackMenuFeatures = WTrackMenu::Feature::BPM | WTrackMenu::Feature::Color | WTrackMenu::Feature::FileBrowser | - WTrackMenu::Feature::Properties; + WTrackMenu::Feature::Properties | + WTrackMenu::Feature::UpdateReplayGain; } // namespace WTrackText::WTrackText(QWidget* pParent, @@ -82,7 +83,7 @@ void WTrackText::mouseMoveEvent(QMouseEvent *event) { void WTrackText::mouseDoubleClickEvent(QMouseEvent* event) { Q_UNUSED(event); if (m_pCurrentTrack) { - m_pTrackMenu->loadTrack(m_pCurrentTrack); + m_pTrackMenu->loadTrack(m_pCurrentTrack, m_group); m_pTrackMenu->slotShowDlgTrackInfo(); } } @@ -98,7 +99,7 @@ void WTrackText::dropEvent(QDropEvent *event) { void WTrackText::contextMenuEvent(QContextMenuEvent* event) { event->accept(); if (m_pCurrentTrack) { - m_pTrackMenu->loadTrack(m_pCurrentTrack); + m_pTrackMenu->loadTrack(m_pCurrentTrack, m_group); // Create the right-click menu m_pTrackMenu->popup(event->globalPos()); } diff --git a/src/widget/wtrackwidgetgroup.cpp b/src/widget/wtrackwidgetgroup.cpp index df6fc93dad..ebdb9adfd3 100644 --- a/src/widget/wtrackwidgetgroup.cpp +++ b/src/widget/wtrackwidgetgroup.cpp @@ -23,7 +23,8 @@ constexpr WTrackMenu::Features kTrackMenuFeatures = WTrackMenu::Feature::BPM | WTrackMenu::Feature::Color | WTrackMenu::Feature::FileBrowser | - WTrackMenu::Feature::Properties; + WTrackMenu::Feature::Properties | + WTrackMenu::Feature::UpdateReplayGain; } // anonymous namespace @@ -121,7 +122,7 @@ void WTrackWidgetGroup::dropEvent(QDropEvent* event) { void WTrackWidgetGroup::contextMenuEvent(QContextMenuEvent* event) { event->accept(); if (m_pCurrentTrack) { - m_pTrackMenu->loadTrack(m_pCurrentTrack); + m_pTrackMenu->loadTrack(m_pCurrentTrack, m_group); // Create the right-click menu m_pTrackMenu->popup(event->globalPos()); } |