summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOwen Williams <owilliams@mixxx.org>2021-06-28 10:42:43 -0400
committerOwen Williams <owilliams@mixxx.org>2021-07-21 14:53:02 -0400
commitf6e6b68bcd6216be39c27c7cdf0563d01df5b287 (patch)
treec75eea6f6f35370d956eb72d627dfec794c1f090
parentafbbe72b6d1a5d61f334647946376f9fb8885c7c (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.cpp18
-rw-r--r--src/mixer/basetrackplayer.h3
-rw-r--r--src/track/replaygain.h9
-rw-r--r--src/track/track.cpp24
-rw-r--r--src/track/track.h5
-rw-r--r--src/widget/wtrackmenu.cpp32
-rw-r--r--src/widget/wtrackmenu.h10
-rw-r--r--src/widget/wtrackproperty.cpp7
-rw-r--r--src/widget/wtracktext.cpp7
-rw-r--r--src/widget/wtrackwidgetgroup.cpp5
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());
}