From 0147a4f38a2678a68d71a7a23cb44ebbabe13d0c Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 6 May 2019 16:53:20 -0500 Subject: [PATCH 001/198] make better use of intro/outro markers with AutoDJ and add a checkbox to revert to the old behavior that does not use the new intro/outro markers at all. With the box checked (which is the default), AutoDJ uses the outro of the outgoing track or the intro of the incoming track for the transition time, whichever is longer. If only one track has these marked, use that track's marked transition time. If neither track has the intro/outro range marked, fall back to the fixed number of seconds specified by the spinbox. If users do not want to interrupt the workflow they are accustomed to when upgrading to Mixxx 2.3, they can simply uncheck the new box. --- src/library/autodj/autodjprocessor.cpp | 156 +++++++++++++++++++------ src/library/autodj/autodjprocessor.h | 18 ++- src/library/autodj/dlgautodj.cpp | 4 + src/library/autodj/dlgautodj.ui | 15 ++- 4 files changed, 156 insertions(+), 37 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 627d7ec0e8a..2541059fb31 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -10,6 +10,7 @@ #define kConfigKey "[Auto DJ]" const char* kTransitionPreferenceName = "Transition"; +const char* kUseIntroOutroPreferenceName = "UseIntroOutroMarkers"; const double kTransitionPreferenceDefault = 10.0; const mixxx::AudioSignal::ChannelCount kChannelCount = mixxx::kEngineChannelCount; @@ -29,6 +30,7 @@ DeckAttributes::DeckAttributes(int index, m_repeat(group, "repeat"), m_seekOnLoadMode(group, "seekonload_mode"), m_introStartPos(group, "intro_start_position"), + m_introEndPos(group, "intro_end_position"), m_outroStartPos(group, "outro_start_position"), m_outroEndPos(group, "outro_end_position"), m_sampleRate(group, "track_samplerate"), @@ -43,6 +45,7 @@ DeckAttributes::DeckAttributes(int index, m_playPos.connectValueChanged(this, &DeckAttributes::slotPlayPosChanged); m_play.connectValueChanged(this, &DeckAttributes::slotPlayChanged); m_introStartPos.connectValueChanged(this, &DeckAttributes::slotIntroStartPositionChanged); + m_introEndPos.connectValueChanged(this, &DeckAttributes::slotIntroEndPositionChanged); m_outroStartPos.connectValueChanged(this, &DeckAttributes::slotOutroStartPositionChanged); m_outroEndPos.connectValueChanged(this, &DeckAttributes::slotOutroEndPositionChanged); } @@ -62,6 +65,10 @@ void DeckAttributes::slotIntroStartPositionChanged(double v) { emit(introStartPositionChanged(this, v)); } +void DeckAttributes::slotIntroEndPositionChanged(double v) { + emit(introEndPositionChanged(this, v)); +} + void DeckAttributes::slotOutroStartPositionChanged(double v) { emit(outroStartPositionChanged(this, v)); } @@ -97,7 +104,8 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, m_pPlayerManager(pPlayerManager), m_pAutoDJTableModel(NULL), m_eState(ADJ_DISABLED), - m_transitionTime(kTransitionPreferenceDefault) { + m_transitionTime(kTransitionPreferenceDefault), + m_bUseIntroOutro(true) { m_pAutoDJTableModel = new PlaylistTableModel(this, pTrackCollection, "mixxx.db.model.autodj"); m_pAutoDJTableModel->setTableModel(iAutoDJPlaylistId); @@ -148,6 +156,9 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, if (!str_autoDjTransition.isEmpty()) { m_transitionTime = str_autoDjTransition.toDouble(); } + + m_bUseIntroOutro = m_pConfig->getValue( + ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), true); } AutoDJProcessor::~AutoDJProcessor() { @@ -339,6 +350,11 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { connect(&deck2, &DeckAttributes::introStartPositionChanged, this, &AutoDJProcessor::playerIntroStartChanged); + connect(&deck1, &DeckAttributes::introEndPositionChanged, + this, &AutoDJProcessor::playerIntroEndChanged); + connect(&deck2, &DeckAttributes::introEndPositionChanged, + this, &AutoDJProcessor::playerIntroEndChanged); + connect(&deck1, &DeckAttributes::outroStartPositionChanged, this, &AutoDJProcessor::playerOutroStartChanged); connect(&deck2, &DeckAttributes::outroStartPositionChanged, @@ -749,6 +765,16 @@ void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, doubl } } +void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double position) { + if (sDebug) { + qDebug() << this << "playerIntroEndChanged" << pAttributes->group << position; + } + + if (!pAttributes->isPlaying()) { + calculateTransition(getOtherDeck(pAttributes, true), pAttributes); + } +} + void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, double position) { if (sDebug) { qDebug() << this << "playerOutroStartChanged" << pAttributes->group << position; @@ -778,6 +804,15 @@ double AutoDJProcessor::getIntroStartPosition(DeckAttributes* pDeck) { return position / samplerate; // Convert to seconds } +double AutoDJProcessor::getIntroEndPosition(DeckAttributes* pDeck) { + double position = pDeck->introEndPosition() / kChannelCount; + double samplerate = pDeck->sampleRate(); + if (position <= 0.0 || samplerate <= 0.0) { + return -1.0; + } + return position / samplerate; // Convert to seconds +} + double AutoDJProcessor::getOutroStartPosition(DeckAttributes* pDeck) { double position = pDeck->outroStartPosition() / kChannelCount; double samplerate = pDeck->sampleRate(); @@ -798,7 +833,7 @@ double AutoDJProcessor::getOutroEndPosition(DeckAttributes* pDeck) { void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck) { - if (pFromDeck == NULL) { + if (pFromDeck == nullptr) { return; } @@ -827,52 +862,86 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, fromTrackOutroEnd = fromTrackDuration; } + double fromTrackOutroLength = fromTrackOutroEnd - fromTrackOutroStart; + double toTrackIntroStart = getIntroStartPosition(pToDeck); if (toTrackIntroStart <= 0.0) { toTrackIntroStart = 0.0; } - if (m_transitionTime > 0.0) { // Crossfade transition - // Make sure length of selected outro is not negative. - double desiredTransitionTime = fromTrackOutroEnd - fromTrackOutroStart; - if (desiredTransitionTime <= 0.0) { - desiredTransitionTime = m_transitionTime; - } - - // Guard against tracks shorter than the desired transition period. - // Use a sensible cap. - double nextTransitionTime = math_min3(desiredTransitionTime, - fromTrackDuration / 2, - toTrackDuration / 2); + double toTrackIntroEnd = getIntroEndPosition(pToDeck); + if (toTrackIntroEnd <= 0.0) { + toTrackIntroEnd = 0.0; + } - double fromTrackStartFadeOut = fromTrackOutroEnd - nextTransitionTime; + double toTrackIntroLength = toTrackIntroEnd - toTrackIntroStart; - if (fromTrackDuration > 0.0) { - pFromDeck->posThreshold = fromTrackStartFadeOut / fromTrackDuration; - pFromDeck->fadeDuration = nextTransitionTime / fromTrackDuration; + if (m_bUseIntroOutro) { + if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { + if (fromTrackOutroLength > toTrackIntroLength) { + pFromDeck->posThreshold = fromTrackOutroStart; + if (fromTrackOutroLength < toTrackDuration) { + pFromDeck->fadeDuration = fromTrackOutroLength; + } else { + pFromDeck->fadeDuration = toTrackDuration; + } + } else if (fromTrackOutroLength < toTrackIntroLength) { + pFromDeck->posThreshold = fromTrackDuration - toTrackIntroLength; + pFromDeck->fadeDuration = toTrackIntroLength; + } + } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { + pFromDeck->posThreshold = fromTrackOutroStart; + if (fromTrackOutroLength < toTrackDuration) { + pFromDeck->fadeDuration = fromTrackOutroLength; + } else { + pFromDeck->fadeDuration = toTrackDuration; + } + } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { + pFromDeck->posThreshold = fromTrackDuration - toTrackIntroLength; + pFromDeck->fadeDuration = toTrackIntroLength; } else { - pFromDeck->posThreshold = 1.0; - pFromDeck->fadeDuration = 0.0; + double transitionTime = m_transitionTime; + if (m_transitionTime > toTrackDuration) { + transitionTime = toTrackDuration; + } + if (transitionTime >= 0) { + pFromDeck->posThreshold = fromTrackOutroEnd - transitionTime; + pFromDeck->fadeDuration = transitionTime; + } else { + pFromDeck->posThreshold = fromTrackOutroEnd; + pFromDeck->fadeDuration = transitionTime; + // Setting this is only required for negative transition times + pToDeck->startPos = toTrackIntroStart + transitionTime; + } } - - // We don't set pToDeck->startPos here because it is only needed - // for pause transition. - } else { // Pause transition (transition time <= 0) - if (fromTrackDuration > 0.0) { - pFromDeck->posThreshold = fromTrackOutroEnd / fromTrackDuration; - pFromDeck->fadeDuration = m_transitionTime / fromTrackDuration; - } else { - pFromDeck->posThreshold = 1.0; - pFromDeck->fadeDuration = 0.0; + } else { + double transitionTime = m_transitionTime; + if (m_transitionTime > toTrackDuration) { + transitionTime = toTrackDuration; } - - if (toTrackDuration > 0.0) { - // Transition time is negative here, so we need to add instead of subtract. - pToDeck->startPos = (toTrackIntroStart + m_transitionTime) / toTrackDuration; + if (transitionTime > 0.0) { + pFromDeck->posThreshold = fromTrackDuration - transitionTime; + pFromDeck->fadeDuration = transitionTime; } else { - pToDeck->startPos = 0.0; + pFromDeck->posThreshold = fromTrackDuration; + pFromDeck->fadeDuration = transitionTime; + // Setting this is only required for negative transition times + pToDeck->startPos = transitionTime; } } + + VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { + pFromDeck->posThreshold = fromTrackDuration; + pFromDeck->fadeDuration = 0; + } + VERIFY_OR_DEBUG_ASSERT(toTrackDuration > 0) { + pToDeck->startPos = 0; + } + + // These are expected to be a fraction of the track length. + pFromDeck->posThreshold /= fromTrackDuration; + pFromDeck->fadeDuration /= fromTrackDuration; + pToDeck->startPos /= toTrackDuration; } void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTrack) { @@ -969,6 +1038,23 @@ void AutoDJProcessor::setTransitionTime(int time) { } } +void AutoDJProcessor::setUseIntroOutro(bool checkboxState) { + m_pConfig->set(ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), + ConfigValue(checkboxState)); + m_bUseIntroOutro = checkboxState; + // Then re-calculate fade thresholds for the decks. + if (m_eState == ADJ_IDLE) { + DeckAttributes& leftDeck = *m_decks[0]; + DeckAttributes& rightDeck = *m_decks[1]; + if (leftDeck.isPlaying()) { + calculateTransition(&leftDeck, &rightDeck); + } + if (rightDeck.isPlaying()) { + calculateTransition(&rightDeck, &leftDeck); + } + } +} + DeckAttributes* AutoDJProcessor::getOtherDeck(DeckAttributes* pThisDeck, bool playing) { DeckAttributes* pOtherDeck = NULL; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index c24f17b2959..ddf65891774 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -74,6 +74,10 @@ class DeckAttributes : public QObject { return m_introStartPos.get(); } + double introEndPosition() const { + return m_introEndPos.get(); + } + double outroStartPosition() const { return m_outroStartPos.get(); } @@ -96,7 +100,8 @@ class DeckAttributes : public QObject { void playChanged(DeckAttributes* pDeck, bool playing); void playPositionChanged(DeckAttributes* pDeck, double playPosition); void introStartPositionChanged(DeckAttributes* pDeck, double introStartPosition); - void outroStartPositionChanged(DeckAttributes* pDeck, double introStartPosition); + void introEndPositionChanged(DeckAttributes* pDeck, double introEndPosition); + void outroStartPositionChanged(DeckAttributes* pDeck, double outtroStartPosition); void outroEndPositionChanged(DeckAttributes* pDeck, double outroEndPosition); void trackLoaded(DeckAttributes* pDeck, TrackPointer pTrack); void loadingTrack(DeckAttributes* pDeck, TrackPointer pNewTrack, TrackPointer pOldTrack); @@ -106,6 +111,7 @@ class DeckAttributes : public QObject { void slotPlayPosChanged(double v); void slotPlayChanged(double v); void slotIntroStartPositionChanged(double v); + void slotIntroEndPositionChanged(double v); void slotOutroStartPositionChanged(double v); void slotOutroEndPositionChanged(double v); void slotTrackLoaded(TrackPointer pTrack); @@ -126,6 +132,7 @@ class DeckAttributes : public QObject { ControlProxy m_repeat; ControlProxy m_seekOnLoadMode; ControlProxy m_introStartPos; + ControlProxy m_introEndPos; ControlProxy m_outroStartPos; ControlProxy m_outroEndPos; ControlProxy m_sampleRate; @@ -169,6 +176,10 @@ class AutoDJProcessor : public QObject { return m_transitionTime; } + bool getUseIntroOutro() const { + return m_bUseIntroOutro; + } + PlaylistTableModel* getTableModel() const { return m_pAutoDJTableModel; } @@ -178,6 +189,8 @@ class AutoDJProcessor : public QObject { public slots: void setTransitionTime(int seconds); + void setUseIntroOutro(bool checkboxState); + AutoDJError shufflePlaylist(const QModelIndexList& selectedIndices); AutoDJError skipNext(); void fadeNow(); @@ -203,6 +216,7 @@ class AutoDJProcessor : public QObject { void playerPositionChanged(DeckAttributes* pDeck, double position); void playerPlayChanged(DeckAttributes* pDeck, bool playing); void playerIntroStartChanged(DeckAttributes* pDeck, double position); + void playerIntroEndChanged(DeckAttributes* pDeck, double position); void playerOutroStartChanged(DeckAttributes* pDeck, double position); void playerOutroEndChanged(DeckAttributes* pDeck, double position); void playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTrack); @@ -225,6 +239,7 @@ class AutoDJProcessor : public QObject { // Following functions return seconds computed from samples or -1 if // track in deck has invalid sample rate (<= 0) double getIntroStartPosition(DeckAttributes* pDeck); + double getIntroEndPosition(DeckAttributes* pDeck); double getOutroStartPosition(DeckAttributes* pDeck); double getOutroEndPosition(DeckAttributes* pDeck); @@ -249,6 +264,7 @@ class AutoDJProcessor : public QObject { AutoDJState m_eState; double m_transitionTime; // the desired value set by the user + bool m_bUseIntroOutro; QList m_decks; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 6798d0a6183..29da88f357e 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -74,6 +74,10 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); + introOutroCheckbox->setChecked(m_pAutoDJProcessor->getUseIntroOutro()); + connect(introOutroCheckbox, &QCheckBox::stateChanged, + m_pAutoDJProcessor, &AutoDJProcessor::setUseIntroOutro); + // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in // mind that AutoDJ may already be active when DlgAutoDJ is created (due to // skin changes, etc.). diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index 35849293a74..22409480457 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -6,7 +6,7 @@ 0 0 - 560 + 879 399 @@ -138,6 +138,19 @@ If no track sources are configured, the track is added from the library instead. + + + + Use intro/outro markers + + + Use the intro of the incoming track or the +outro of the outgoing track for the transition time, +whichever is longer. If neither track has an intro or outro marked, +fall back to the specified transition time. + + + From 7163fd36c81e745d2a7a8aa291a67711fda69e79 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 6 May 2019 18:36:07 -0500 Subject: [PATCH 002/198] add option to choose shorter or longer of intro/outro for AutoDJ --- src/library/autodj/autodjprocessor.cpp | 59 ++++++++++++++++---------- src/library/autodj/autodjprocessor.h | 18 ++++++-- src/library/autodj/dlgautodj.cpp | 10 ++++- src/library/autodj/dlgautodj.ui | 14 +----- 4 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2541059fb31..f7652117f30 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -104,8 +104,7 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, m_pPlayerManager(pPlayerManager), m_pAutoDJTableModel(NULL), m_eState(ADJ_DISABLED), - m_transitionTime(kTransitionPreferenceDefault), - m_bUseIntroOutro(true) { + m_transitionTime(kTransitionPreferenceDefault) { m_pAutoDJTableModel = new PlaylistTableModel(this, pTrackCollection, "mixxx.db.model.autodj"); m_pAutoDJTableModel->setTableModel(iAutoDJPlaylistId); @@ -157,8 +156,10 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, m_transitionTime = str_autoDjTransition.toDouble(); } - m_bUseIntroOutro = m_pConfig->getValue( - ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), true); + int configMode = m_pConfig->getValue( + ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), + static_cast(IntroOutroUsage::Shorter)); + m_useIntroOutroMode = static_cast(configMode); } AutoDJProcessor::~AutoDJProcessor() { @@ -876,29 +877,27 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double toTrackIntroLength = toTrackIntroEnd - toTrackIntroStart; - if (m_bUseIntroOutro) { + if (m_useIntroOutroMode != IntroOutroUsage::None) { if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { if (fromTrackOutroLength > toTrackIntroLength) { - pFromDeck->posThreshold = fromTrackOutroStart; - if (fromTrackOutroLength < toTrackDuration) { - pFromDeck->fadeDuration = fromTrackOutroLength; - } else { - pFromDeck->fadeDuration = toTrackDuration; + if (m_useIntroOutroMode == IntroOutroUsage::Longer) { + useOutroFadeTime(pFromDeck, fromTrackOutroStart, + fromTrackOutroLength, toTrackDuration); + } else if (m_useIntroOutroMode == IntroOutroUsage::Shorter) { + useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); } } else if (fromTrackOutroLength < toTrackIntroLength) { - pFromDeck->posThreshold = fromTrackDuration - toTrackIntroLength; - pFromDeck->fadeDuration = toTrackIntroLength; + if (m_useIntroOutroMode == IntroOutroUsage::Longer) { + useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); + } else if (m_useIntroOutroMode == IntroOutroUsage::Shorter) { + useOutroFadeTime(pFromDeck, fromTrackOutroStart, + fromTrackOutroLength, toTrackDuration); + } } } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { - pFromDeck->posThreshold = fromTrackOutroStart; - if (fromTrackOutroLength < toTrackDuration) { - pFromDeck->fadeDuration = fromTrackOutroLength; - } else { - pFromDeck->fadeDuration = toTrackDuration; - } + useOutroFadeTime(pFromDeck, fromTrackOutroStart, fromTrackOutroLength, toTrackDuration); } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { - pFromDeck->posThreshold = fromTrackDuration - toTrackIntroLength; - pFromDeck->fadeDuration = toTrackIntroLength; + useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); } else { double transitionTime = m_transitionTime; if (m_transitionTime > toTrackDuration) { @@ -944,6 +943,22 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos /= toTrackDuration; } +void AutoDJProcessor::useOutroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroStart, + double fromTrackOutroLength, double toTrackDuration) { + pFromDeck->posThreshold = fromTrackOutroStart; + if (fromTrackOutroLength < toTrackDuration) { + pFromDeck->fadeDuration = fromTrackOutroLength; + } else { + pFromDeck->fadeDuration = toTrackDuration; + } +} + +void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroEnd, + double toTrackIntroLength) { + pFromDeck->posThreshold = fromTrackOutroEnd - toTrackIntroLength; + pFromDeck->fadeDuration = toTrackIntroLength; +} + void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTrack) { if (sDebug) { qDebug() << this << "playerTrackLoaded" << pDeck->group @@ -1038,10 +1053,10 @@ void AutoDJProcessor::setTransitionTime(int time) { } } -void AutoDJProcessor::setUseIntroOutro(bool checkboxState) { +void AutoDJProcessor::setUseIntroOutro(int checkboxState) { m_pConfig->set(ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), ConfigValue(checkboxState)); - m_bUseIntroOutro = checkboxState; + m_useIntroOutroMode = static_cast(checkboxState); // Then re-calculate fade thresholds for the decks. if (m_eState == ADJ_IDLE) { DeckAttributes& leftDeck = *m_decks[0]; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index ddf65891774..77bdda6791e 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -161,6 +161,12 @@ class AutoDJProcessor : public QObject { ADJ_NOT_TWO_DECKS }; + enum class IntroOutroUsage { + None = 0, + Shorter = 1, + Longer = 2 + }; + AutoDJProcessor(QObject* pParent, UserSettingsPointer pConfig, PlayerManagerInterface* pPlayerManager, @@ -176,8 +182,8 @@ class AutoDJProcessor : public QObject { return m_transitionTime; } - bool getUseIntroOutro() const { - return m_bUseIntroOutro; + IntroOutroUsage getUseIntroOutro() const { + return m_useIntroOutroMode; } PlaylistTableModel* getTableModel() const { @@ -189,7 +195,7 @@ class AutoDJProcessor : public QObject { public slots: void setTransitionTime(int seconds); - void setUseIntroOutro(bool checkboxState); + void setUseIntroOutro(int checkboxState); AutoDJError shufflePlaylist(const QModelIndexList& selectedIndices); AutoDJError skipNext(); @@ -247,6 +253,10 @@ class AutoDJProcessor : public QObject { bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); void calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); + void useOutroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroStart, + double fromTrackOutroLength, double toTrackDuration); + void useIntroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroEnd, + double toTrackIntroLength); DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, bool playing = false); @@ -264,7 +274,7 @@ class AutoDJProcessor : public QObject { AutoDJState m_eState; double m_transitionTime; // the desired value set by the user - bool m_bUseIntroOutro; + IntroOutroUsage m_useIntroOutroMode; QList m_decks; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 29da88f357e..3c57bad8b74 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -74,8 +74,14 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); - introOutroCheckbox->setChecked(m_pAutoDJProcessor->getUseIntroOutro()); - connect(introOutroCheckbox, &QCheckBox::stateChanged, + introOutroCombobox->addItem(tr("Do not use intro/outro markers"), + static_cast(AutoDJProcessor::IntroOutroUsage::None)); + introOutroCombobox->addItem(tr("Use intro/outro for transition time (whichever is shorter)"), + static_cast(AutoDJProcessor::IntroOutroUsage::Shorter)); + introOutroCombobox->addItem(tr("Use intro/outro for transition time (whichever is longer)"), + static_cast(AutoDJProcessor::IntroOutroUsage::Longer)); + introOutroCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getUseIntroOutro())); + connect(introOutroCombobox, QOverload::of(&QComboBox::currentIndexChanged), m_pAutoDJProcessor, &AutoDJProcessor::setUseIntroOutro); // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index 22409480457..8ba416aed0e 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -6,7 +6,7 @@ 0 0 - 879 + 913 399 @@ -139,17 +139,7 @@ If no track sources are configured, the track is added from the library instead. - - - Use intro/outro markers - - - Use the intro of the incoming track or the -outro of the outgoing track for the transition time, -whichever is longer. If neither track has an intro or outro marked, -fall back to the specified transition time. - - + From 7cfe38e18a7bd5bc9af45dbbc282a0486afcdaa5 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 6 May 2019 21:20:03 -0500 Subject: [PATCH 003/198] convert SeekOnLoadMode to enum class --- src/engine/controls/cuecontrol.cpp | 12 ++++----- src/engine/controls/cuecontrol.h | 17 +++++------- src/library/autodj/autodjprocessor.cpp | 8 +++--- src/library/autodj/autodjprocessor.h | 3 ++- src/test/autodjprocessor_test.cpp | 36 +++++++++++++------------- src/test/cuecontrol_test.cpp | 21 ++++++++++----- 6 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index e72308e6fa6..9c6052814b3 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -349,13 +349,13 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { // Seek track according to SeekOnLoadMode. SeekOnLoadMode seekOnLoadMode = getSeekOnLoadMode(); switch (seekOnLoadMode) { - case SEEK_ON_LOAD_ZERO_POS: + case SeekOnLoadMode::Beginning: seekExact(0.0); break; - case SEEK_ON_LOAD_MAIN_CUE: + case SeekOnLoadMode::MainCue: seekExact(m_pCuePoint->get()); break; - case SEEK_ON_LOAD_INTRO_CUE: + case SeekOnLoadMode::IntroStart: seekExact(m_pIntroStartPosition->get()); break; default: @@ -492,15 +492,15 @@ void CueControl::reloadCuesFromTrack() { // Make track follow the updated cues. SeekOnLoadMode seekOnLoadMode = getSeekOnLoadMode(); - if (seekOnLoadMode == SEEK_ON_LOAD_DEFAULT) { + if (seekOnLoadMode == SeekOnLoadMode::Default) { if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != -1.0 && isCueRecallEnabled()) { seekExact(cue); } - } else if (seekOnLoadMode == SEEK_ON_LOAD_MAIN_CUE) { + } else if (seekOnLoadMode == SeekOnLoadMode::MainCue) { if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != -1.0) { seekExact(cue); } - } else if (seekOnLoadMode == SEEK_ON_LOAD_INTRO_CUE) { + } else if (seekOnLoadMode == SeekOnLoadMode::IntroStart) { if ((wasTrackAtIntroCue || wasTrackAtZeroPos) && intro != -1.0) { seekExact(intro); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 97ba673afb3..95d636bb23b 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -18,21 +18,16 @@ class ControlObject; class ControlPushButton; class ControlIndicator; -enum SeekOnLoadMode { - SEEK_ON_LOAD_DEFAULT = 0, // Use CueRecall preference setting - SEEK_ON_LOAD_ZERO_POS = 1, // Use 0:00.000 - SEEK_ON_LOAD_MAIN_CUE = 2, // Use main cue point - SEEK_ON_LOAD_INTRO_CUE = 3, // Use intro cue point - SEEK_ON_LOAD_NUM_MODES +enum class SeekOnLoadMode { + Default = 0, // Use CueRecall preference setting + Beginning = 1, // Use 0:00.000 + MainCue = 2, // Use main cue point + IntroStart = 3, // Use intro start cue point }; inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { // msvs does not allow to cast from double to an enum - SeekOnLoadMode mode = static_cast(int(value)); - if (mode >= SEEK_ON_LOAD_NUM_MODES || mode < 0) { - return SEEK_ON_LOAD_DEFAULT; - } - return mode; + return static_cast(int(value));; } class HotcueControl : public QObject { diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index f7652117f30..633d299a2b3 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -333,8 +333,8 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ enabled"; - deck1.setSeekOnLoadMode(SEEK_ON_LOAD_INTRO_CUE); - deck2.setSeekOnLoadMode(SEEK_ON_LOAD_INTRO_CUE); + deck1.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + deck2.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); connect(&deck1, &DeckAttributes::playPositionChanged, this, &AutoDJProcessor::playerPositionChanged); @@ -424,8 +424,8 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ disabled"; m_eState = ADJ_DISABLED; - deck1.setSeekOnLoadMode(SEEK_ON_LOAD_DEFAULT); - deck2.setSeekOnLoadMode(SEEK_ON_LOAD_DEFAULT); + deck1.setSeekOnLoadMode(SeekOnLoadMode::Default); + deck2.setSeekOnLoadMode(SeekOnLoadMode::Default); deck1.disconnect(this); deck2.disconnect(this); m_pCOCrossfader->set(0); diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 77bdda6791e..6d73eb4a683 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -67,7 +67,8 @@ class DeckAttributes : public QObject { } void setSeekOnLoadMode(SeekOnLoadMode mode) { - m_seekOnLoadMode.set(mode); + m_seekOnLoadMode.set(static_cast( + static_cast(mode))); } double introStartPosition() const { diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 50dabd3efe0..ba67ffb608b 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -281,8 +281,8 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // Sets crossfader left and deck 1 playing. EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); // ADJ_ENABLE_P1LOADED logic does not set play directly. It waits for the @@ -337,8 +337,8 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // Sets crossfader left. EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); // ADJ_ENABLE_P1LOADED logic does not set play directly. It waits for the @@ -410,8 +410,8 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // Sets crossfader left. EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); // ADJ_ENABLE_P1LOADED logic does not set play directly. It waits for the @@ -488,8 +488,8 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); EXPECT_DOUBLE_EQ(-1, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); @@ -533,8 +533,8 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // No change to the crossfader or play states. EXPECT_DOUBLE_EQ(-1, master.crossfader.get()); @@ -591,8 +591,8 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // No change to the crossfader or play states. EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); @@ -637,8 +637,8 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // No change to the crossfader or play states. EXPECT_DOUBLE_EQ(1, master.crossfader.get()); @@ -682,8 +682,8 @@ TEST_F(AutoDJProcessorTest, EnabledDisabledSuccess) { EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_INTRO_CUE, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); err = pProcessor->toggleAutoDJ(false); EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); @@ -691,8 +691,8 @@ TEST_F(AutoDJProcessorTest, EnabledDisabledSuccess) { // Restores decks 1 and 2 to respect CueRecall preference option when // loading track. (This is default behaviour.) - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_DEFAULT, deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(SEEK_ON_LOAD_DEFAULT, deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::Default), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::Default), deck2.seekOnLoadMode.get()); } TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 24fc3875047..80a946d18b5 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -263,7 +263,8 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { } TEST_F(CueControlTest, SeekOnLoadDefault) { - m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_DEFAULT); + m_pSeekOnLoadMode->slotSet(static_cast( + static_cast(SeekOnLoadMode::Default))); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); @@ -282,7 +283,8 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { } TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { - m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_DEFAULT); + m_pSeekOnLoadMode->slotSet(static_cast( + static_cast(SeekOnLoadMode::Default))); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(-100.0, Cue::MANUAL)); @@ -301,7 +303,8 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { } TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { - m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_DEFAULT); + m_pSeekOnLoadMode->slotSet(static_cast( + static_cast(SeekOnLoadMode::Default))); TrackPointer pTrack = createTestTrack(); @@ -319,7 +322,8 @@ TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { } TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { - m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_DEFAULT); + m_pSeekOnLoadMode->slotSet(static_cast( + static_cast(SeekOnLoadMode::Default))); // Note: CueRecall uses inverse logic (0 means enabled). config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(1)); @@ -334,7 +338,8 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { } TEST_F(CueControlTest, SeekOnLoadZeroPos) { - m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_ZERO_POS); + m_pSeekOnLoadMode->slotSet(static_cast( + static_cast(SeekOnLoadMode::Beginning))); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); @@ -346,7 +351,8 @@ TEST_F(CueControlTest, SeekOnLoadZeroPos) { } TEST_F(CueControlTest, SeekOnLoadMainCue) { - m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_MAIN_CUE); + m_pSeekOnLoadMode->slotSet(static_cast( + static_cast(SeekOnLoadMode::MainCue))); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); @@ -365,7 +371,8 @@ TEST_F(CueControlTest, SeekOnLoadMainCue) { } TEST_F(CueControlTest, SeekOnLoadIntroCue) { - m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_INTRO_CUE); + m_pSeekOnLoadMode->slotSet(static_cast( + static_cast(SeekOnLoadMode::IntroStart))); TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); From febce9bf41907a378bdf97835418205c87a91eae Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 6 May 2019 22:03:59 -0500 Subject: [PATCH 004/198] don't load at intro start when not using intro/outro with AutoDJ This allows for completely ignoring the intro/outro markers with AutoDJ. --- src/library/autodj/autodjprocessor.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 633d299a2b3..bf659bd8996 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -333,8 +333,13 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ enabled"; - deck1.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); - deck2.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + if (m_useIntroOutroMode == IntroOutroUsage::None) { + deck1.setSeekOnLoadMode(SeekOnLoadMode::Beginning); + deck2.setSeekOnLoadMode(SeekOnLoadMode::Beginning); + } else { + deck1.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + deck2.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + } connect(&deck1, &DeckAttributes::playPositionChanged, this, &AutoDJProcessor::playerPositionChanged); @@ -1057,10 +1062,20 @@ void AutoDJProcessor::setUseIntroOutro(int checkboxState) { m_pConfig->set(ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), ConfigValue(checkboxState)); m_useIntroOutroMode = static_cast(checkboxState); + // Then re-calculate fade thresholds for the decks. if (m_eState == ADJ_IDLE) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; + + if (m_useIntroOutroMode == IntroOutroUsage::None) { + leftDeck.setSeekOnLoadMode(SeekOnLoadMode::Beginning); + rightDeck.setSeekOnLoadMode(SeekOnLoadMode::Beginning); + } else { + leftDeck.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + rightDeck.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + } + if (leftDeck.isPlaying()) { calculateTransition(&leftDeck, &rightDeck); } From 450d409bd9b3cd621857950ed1492e737e33f2f6 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 6 May 2019 23:31:14 -0500 Subject: [PATCH 005/198] add option to load tracks at intro start marker and rename some code for clarity --- src/engine/controls/cuecontrol.cpp | 54 +++++------ src/engine/controls/cuecontrol.h | 15 +-- src/library/autodj/autodjprocessor.cpp | 22 ++--- src/library/autodj/autodjprocessor.h | 8 +- src/preferences/dialog/dlgprefdeck.cpp | 47 ++++++---- src/preferences/dialog/dlgprefdeck.h | 5 +- src/preferences/dialog/dlgprefdeckdlg.ui | 112 +++++++++++++---------- src/test/autodjprocessor_test.cpp | 4 +- src/test/cuecontrol_test.cpp | 8 +- 9 files changed, 156 insertions(+), 119 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 9c6052814b3..c60ff7e0256 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -56,7 +56,9 @@ CueControl::CueControl(QString group, m_pCueMode = new ControlObject(ConfigKey(group, "cue_mode")); - m_pSeekOnLoadMode = new ControlObject(ConfigKey(group, "seekonload_mode")); + m_pSeekOnLoadModeAutoDjOverride = new ControlObject(ConfigKey(group, "seekonload_mode_autodj")); + m_pSeekOnLoadModeAutoDjOverride->set(static_cast( + static_cast(SeekOnLoadMode::UsePreference))); m_pCueSet = new ControlPushButton(ConfigKey(group, "cue_set")); m_pCueSet->setButtonMode(ControlPushButton::TRIGGER); @@ -207,7 +209,7 @@ CueControl::CueControl(QString group, CueControl::~CueControl() { delete m_pCuePoint; delete m_pCueMode; - delete m_pSeekOnLoadMode; + delete m_pSeekOnLoadModeAutoDjOverride; delete m_pCueSet; delete m_pCueClear; delete m_pCueGoto; @@ -347,10 +349,17 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { loadCuesFromTrack(); // Seek track according to SeekOnLoadMode. - SeekOnLoadMode seekOnLoadMode = getSeekOnLoadMode(); + SeekOnLoadMode seekOnLoadMode = getSeekOnLoadModeAutoDjOverride(); + if (seekOnLoadMode == SeekOnLoadMode::UsePreference) { + seekOnLoadMode = getSeekOnLoadPreference(); + } switch (seekOnLoadMode) { - case SeekOnLoadMode::Beginning: - seekExact(0.0); + case SeekOnLoadMode::Beginning: + // This allows users to load tracks and have the needle-drop be maintained. + if (!(m_pVinylControlEnabled->get() && + m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) { + seekExact(0.0); + } break; case SeekOnLoadMode::MainCue: seekExact(m_pCuePoint->get()); @@ -359,17 +368,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { seekExact(m_pIntroStartPosition->get()); break; default: - // Respect cue recall preference option. - if (isCueRecallEnabled() && m_pCuePoint->get() != -1.0) { - // If cue recall is ON and main cue point is set, seek to it. - seekExact(m_pCuePoint->get()); - } else if (!(m_pVinylControlEnabled->get() && - m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) { - // Otherwise, seek to zero unless vinylcontrol is on and - // set to absolute. This allows users to load tracks and - // have the needle-drop be maintained. - seekExact(0.0); - } + seekExact(0.0); break; } } @@ -491,12 +490,12 @@ void CueControl::reloadCuesFromTrack() { double intro = m_pIntroStartPosition->get(); // Make track follow the updated cues. - SeekOnLoadMode seekOnLoadMode = getSeekOnLoadMode(); - if (seekOnLoadMode == SeekOnLoadMode::Default) { - if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != -1.0 && isCueRecallEnabled()) { - seekExact(cue); - } - } else if (seekOnLoadMode == SeekOnLoadMode::MainCue) { + SeekOnLoadMode seekOnLoadMode = getSeekOnLoadModeAutoDjOverride(); + if (seekOnLoadMode == SeekOnLoadMode::UsePreference) { + seekOnLoadMode = getSeekOnLoadPreference(); + } + + if (seekOnLoadMode == SeekOnLoadMode::MainCue) { if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != -1.0) { seekExact(cue); } @@ -1631,13 +1630,14 @@ bool CueControl::isPlayingByPlayButton() { !m_iCurrentlyPreviewingHotcues && !m_bPreviewing; } -bool CueControl::isCueRecallEnabled() { - // Note that [Controls],CueRecall == 0 corresponds to "ON", not "OFF". - return getConfig()->getValue(ConfigKey("[Controls]", "CueRecall"), 0) == 0; +SeekOnLoadMode CueControl::getSeekOnLoadPreference() { + int configValue = getConfig()->getValue(ConfigKey("[Controls]", "CueRecall"), + static_cast(SeekOnLoadMode::IntroStart)); + return static_cast(configValue); } -SeekOnLoadMode CueControl::getSeekOnLoadMode() { - return seekOnLoadModeFromDouble(m_pSeekOnLoadMode->get()); +SeekOnLoadMode CueControl::getSeekOnLoadModeAutoDjOverride() { + return seekOnLoadModeFromDouble(m_pSeekOnLoadModeAutoDjOverride->get()); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 95d636bb23b..5da47fe0749 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -18,15 +18,16 @@ class ControlObject; class ControlPushButton; class ControlIndicator; +// This enum class is shared between the preference option in DlgPrefDeck +// and AutoDJ's override of that option from AutoDJProcessor. enum class SeekOnLoadMode { - Default = 0, // Use CueRecall preference setting + MainCue = 0, // Use main cue point Beginning = 1, // Use 0:00.000 - MainCue = 2, // Use main cue point - IntroStart = 3, // Use intro start cue point + IntroStart = 2, // Use intro start cue point + UsePreference = 3, // Use CueRecall preference setting }; inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { - // msvs does not allow to cast from double to an enum return static_cast(int(value));; } @@ -121,9 +122,9 @@ class CueControl : public EngineControl { void resetIndicators(); bool isPlayingByPlayButton(); bool getPlayFlashingAtPause(); - bool isCueRecallEnabled(); + SeekOnLoadMode getSeekOnLoadPreference(); void trackLoaded(TrackPointer pNewTrack) override; - SeekOnLoadMode getSeekOnLoadMode(); + SeekOnLoadMode getSeekOnLoadModeAutoDjOverride(); private slots: void quantizeChanged(double v); @@ -205,7 +206,7 @@ class CueControl : public EngineControl { ControlObject* m_pTrackSamples; ControlObject* m_pCuePoint; ControlObject* m_pCueMode; - ControlObject* m_pSeekOnLoadMode; + ControlObject* m_pSeekOnLoadModeAutoDjOverride; ControlPushButton* m_pCueSet; ControlPushButton* m_pCueClear; ControlPushButton* m_pCueCDJ; diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index bf659bd8996..dac56c9108f 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -28,7 +28,7 @@ DeckAttributes::DeckAttributes(int index, m_playPos(group, "playposition"), m_play(group, "play"), m_repeat(group, "repeat"), - m_seekOnLoadMode(group, "seekonload_mode"), + m_seekOnLoadModeOverride(group, "seekonload_mode_autodj"), m_introStartPos(group, "intro_start_position"), m_introEndPos(group, "intro_end_position"), m_outroStartPos(group, "outro_start_position"), @@ -334,11 +334,11 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { qDebug() << "Auto DJ enabled"; if (m_useIntroOutroMode == IntroOutroUsage::None) { - deck1.setSeekOnLoadMode(SeekOnLoadMode::Beginning); - deck2.setSeekOnLoadMode(SeekOnLoadMode::Beginning); + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); } else { - deck1.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); - deck2.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); } connect(&deck1, &DeckAttributes::playPositionChanged, @@ -429,8 +429,8 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ disabled"; m_eState = ADJ_DISABLED; - deck1.setSeekOnLoadMode(SeekOnLoadMode::Default); - deck2.setSeekOnLoadMode(SeekOnLoadMode::Default); + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); deck1.disconnect(this); deck2.disconnect(this); m_pCOCrossfader->set(0); @@ -1069,11 +1069,11 @@ void AutoDJProcessor::setUseIntroOutro(int checkboxState) { DeckAttributes& rightDeck = *m_decks[1]; if (m_useIntroOutroMode == IntroOutroUsage::None) { - leftDeck.setSeekOnLoadMode(SeekOnLoadMode::Beginning); - rightDeck.setSeekOnLoadMode(SeekOnLoadMode::Beginning); + leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); + rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); } else { - leftDeck.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); - rightDeck.setSeekOnLoadMode(SeekOnLoadMode::IntroStart); + leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); + rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); } if (leftDeck.isPlaying()) { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 6d73eb4a683..325a2e63481 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -63,11 +63,11 @@ class DeckAttributes : public QObject { } SeekOnLoadMode seekOnLoadMode() const { - return seekOnLoadModeFromDouble(m_seekOnLoadMode.get()); + return seekOnLoadModeFromDouble(m_seekOnLoadModeOverride.get()); } - void setSeekOnLoadMode(SeekOnLoadMode mode) { - m_seekOnLoadMode.set(static_cast( + void setSeekOnLoadModeOverride(SeekOnLoadMode mode) { + m_seekOnLoadModeOverride.set(static_cast( static_cast(mode))); } @@ -131,7 +131,7 @@ class DeckAttributes : public QObject { ControlProxy m_playPos; ControlProxy m_play; ControlProxy m_repeat; - ControlProxy m_seekOnLoadMode; + ControlProxy m_seekOnLoadModeOverride; ControlProxy m_introStartPos; ControlProxy m_introEndPos; ControlProxy m_outroStartPos; diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index f7ad5ed612f..f21c51775f3 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -159,12 +159,24 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, connect(checkBoxDisallowLoadToPlayingDeck, SIGNAL(toggled(bool)), this, SLOT(slotDisallowTrackLoadToPlayingDeckCheckbox(bool))); - // Jump to cue on track load - // The check box reflects the opposite of the config value - m_bJumpToCueOnTrackLoad = !m_pConfig->getValue(ConfigKey("[Controls]", "CueRecall"), false); - checkBoxSeekToCue->setChecked(m_bJumpToCueOnTrackLoad); - connect(checkBoxSeekToCue, SIGNAL(toggled(bool)), - this, SLOT(slotJumpToCueOnTrackLoadCheckbox(bool))); + int seekMode = m_pConfig->getValue(ConfigKey("[Controls]", "CueRecall"), + static_cast(SeekOnLoadMode::IntroStart)); + m_seekOnLoadMode = static_cast(seekMode); + switch (m_seekOnLoadMode) { + case SeekOnLoadMode::Beginning: + radioButtonBeginning->setChecked(true); + break; + case SeekOnLoadMode::MainCue: + radioButtonMainCue->setChecked(true); + break; + default: + radioButtonIntroStart->setChecked(true); + m_seekOnLoadMode = SeekOnLoadMode::IntroStart; + break; + } + connect(buttonGroupLoadPoint, + static_cast(&QButtonGroup::buttonClicked), + this, &DlgPrefDeck::slotSetTrackLoadMode); m_bRateInverted = m_pConfig->getValue(ConfigKey("[Controls]", "RateDir"), false); setRateDirectionForAllDecks(m_bRateInverted); @@ -332,9 +344,6 @@ void DlgPrefDeck::slotUpdate() { checkBoxDisallowLoadToPlayingDeck->setChecked(!m_pConfig->getValue( ConfigKey("[Controls]", "AllowTrackLoadToPlayingDeck"), false)); - checkBoxSeekToCue->setChecked(!m_pConfig->getValue( - ConfigKey("[Controls]", "CueRecall"), false)); - double deck1RateRange = m_rateRangeControls[0]->get(); int index = ComboBoxRateRange->findData(static_cast(deck1RateRange * 100)); if (index == -1) { @@ -408,8 +417,8 @@ void DlgPrefDeck::slotResetToDefaults() { // Mixxx cue mode ComboBoxCueMode->setCurrentIndex(0); - // Cue recall on. - checkBoxSeekToCue->setChecked(true); + // Load at intro start + radioButtonIntroStart->setChecked(true); // Rate-ramping default off. radioButtonRateRampModeStepping->setChecked(true); @@ -486,10 +495,6 @@ void DlgPrefDeck::slotCueModeCombobox(int index) { m_iCueMode = ComboBoxCueMode->itemData(index).toInt(); } -void DlgPrefDeck::slotJumpToCueOnTrackLoadCheckbox(bool checked) { - m_bJumpToCueOnTrackLoad = checked; -} - void DlgPrefDeck::slotSetTrackTimeDisplay(QAbstractButton* b) { if (b == radioButtonRemaining) { m_timeDisplayMode = TrackTime::DisplayMode::REMAINING; @@ -547,6 +552,16 @@ void DlgPrefDeck::slotTimeFormatChanged(double v) { comboBoxTimeFormat->findData(i)); } +void DlgPrefDeck::slotSetTrackLoadMode(QAbstractButton* pressedButton) { + if (pressedButton == radioButtonBeginning) { + m_seekOnLoadMode = SeekOnLoadMode::Beginning; + } else if (pressedButton == radioButtonMainCue) { + m_seekOnLoadMode = SeekOnLoadMode::MainCue; + } else { + m_seekOnLoadMode = SeekOnLoadMode::IntroStart; + } +} + void DlgPrefDeck::slotApply() { double timeDisplay = static_cast(m_timeDisplayMode); m_pConfig->set(ConfigKey("[Controls]","PositionDisplay"), ConfigValue(timeDisplay)); @@ -566,7 +581,7 @@ void DlgPrefDeck::slotApply() { m_pConfig->setValue(ConfigKey("[Controls]", "AllowTrackLoadToPlayingDeck"), !m_bDisallowTrackLoadToPlayingDeck); - m_pConfig->setValue(ConfigKey("[Controls]", "CueRecall"), !m_bJumpToCueOnTrackLoad); + m_pConfig->setValue(ConfigKey("[Controls]", "CueRecall"), static_cast(m_seekOnLoadMode)); // Set rate range setRateRangeForAllDecks(m_iRateRangePercent); diff --git a/src/preferences/dialog/dlgprefdeck.h b/src/preferences/dialog/dlgprefdeck.h index ebc77ce2a7d..a63d6db4c67 100644 --- a/src/preferences/dialog/dlgprefdeck.h +++ b/src/preferences/dialog/dlgprefdeck.h @@ -4,6 +4,7 @@ #include #include "engine/controls/ratecontrol.h" +#include "engine/controls/cuecontrol.h" #include "preferences/constants.h" #include "preferences/dialog/ui_dlgprefdeckdlg.h" #include "preferences/usersettings.h" @@ -72,7 +73,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { void slotSetTrackTimeDisplay(double); void slotDisallowTrackLoadToPlayingDeckCheckbox(bool); void slotCueModeCombobox(int); - void slotJumpToCueOnTrackLoadCheckbox(bool); + void slotSetTrackLoadMode(QAbstractButton*); void slotRateRampingModeLinearButton(bool); void slotRateRampSensitivitySlider(int); @@ -116,7 +117,6 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { int m_iCueMode; bool m_bDisallowTrackLoadToPlayingDeck; - bool m_bJumpToCueOnTrackLoad; int m_iRateRangePercent; bool m_bRateInverted; @@ -125,6 +125,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { bool m_pitchAutoReset; KeylockMode m_keylockMode; KeyunlockMode m_keyunlockMode; + SeekOnLoadMode m_seekOnLoadMode; RateControl::RampMode m_bRateRamping; int m_iRateRampSensitivity; diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index 4d83fe92c59..a0396433fb1 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -6,7 +6,7 @@ 0 0 - 562 + 710 723 @@ -23,16 +23,6 @@ 10 - - - - Auto cue - - - checkBoxSeekToCue - - - @@ -52,23 +42,8 @@ - - - - Do not load tracks into playing decks - - - - - - - Automatically seeks to the first saved cue point on track load. - If none exists, seeks to the beginning of the track. - - - Jump to main cue point on track load - - + + @@ -104,19 +79,6 @@ - - - - Cue mode - - - true - - - ComboBoxCueMode - - - @@ -142,6 +104,26 @@ CUP mode: + + + + Cue mode + + + true + + + ComboBoxCueMode + + + + + + + Track load point + + + @@ -152,6 +134,13 @@ CUP mode: + + + + Do not load tracks into playing decks + + + @@ -159,8 +148,39 @@ CUP mode: - - + + + + + + Beginning + + + buttonGroupLoadPoint + + + + + + + Intro Start + + + buttonGroupLoadPoint + + + + + + + Main Cue + + + buttonGroupLoadPoint + + + + @@ -617,7 +637,6 @@ CUP mode: radioButtonElapsed radioButtonRemaining radioButtonElapsedAndRemaining - checkBoxSeekToCue checkBoxDisallowLoadToPlayingDeck ComboBoxRateRange checkBoxInvertSpeedSlider @@ -768,14 +787,15 @@ CUP mode: + + + false - - diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index ba67ffb608b..ab7263cc2b1 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -691,8 +691,8 @@ TEST_F(AutoDJProcessorTest, EnabledDisabledSuccess) { // Restores decks 1 and 2 to respect CueRecall preference option when // loading track. (This is default behaviour.) - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::Default), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::Default), deck2.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::UsePreference), deck1.seekOnLoadMode.get()); + EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::UsePreference), deck2.seekOnLoadMode.get()); } TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 80a946d18b5..5e4587c06f9 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -264,7 +264,7 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { TEST_F(CueControlTest, SeekOnLoadDefault) { m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::Default))); + static_cast(SeekOnLoadMode::UsePreference))); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); @@ -284,7 +284,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::Default))); + static_cast(SeekOnLoadMode::UsePreference))); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(-100.0, Cue::MANUAL)); @@ -304,7 +304,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::Default))); + static_cast(SeekOnLoadMode::UsePreference))); TrackPointer pTrack = createTestTrack(); @@ -323,7 +323,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::Default))); + static_cast(SeekOnLoadMode::UsePreference))); // Note: CueRecall uses inverse logic (0 means enabled). config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(1)); From c45b27f6118d142ad590c25d5a73b46c672a6ab7 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 11:12:46 -0500 Subject: [PATCH 006/198] convert Cue::CueType to enum class --- src/analyzer/analyzersilence.cpp | 12 +++--- src/engine/controls/cuecontrol.cpp | 40 ++++++++++---------- src/engine/controls/vinylcontrolcontrol.cpp | 2 +- src/library/dao/cuedao.cpp | 6 +-- src/library/dlgtrackinfo.cpp | 12 +++--- src/mixer/basetrackplayer.cpp | 6 +-- src/test/analyzersilence_test.cpp | 28 +++++++------- src/test/cuecontrol_test.cpp | 42 ++++++++++----------- src/track/cue.cpp | 8 ++-- src/track/cue.h | 26 ++++++------- src/track/track.cpp | 16 ++++---- src/track/track.h | 4 +- src/widget/wtracktableview.cpp | 6 +-- 13 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index c2be74261ed..31284266763 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -37,12 +37,12 @@ bool AnalyzerSilence::isDisabledOrLoadStoredSuccess(TrackPointer tio) const { return false; } - CuePointer pIntroCue = tio->findCueByType(Cue::INTRO); + CuePointer pIntroCue = tio->findCueByType(Cue::Type::Intro); if (!pIntroCue || pIntroCue->getSource() != Cue::MANUAL) { return false; } - CuePointer pOutroCue = tio->findCueByType(Cue::OUTRO); + CuePointer pOutroCue = tio->findCueByType(Cue::Type::Outro); if (!pOutroCue || pOutroCue->getSource() != Cue::MANUAL) { return false; } @@ -97,10 +97,10 @@ void AnalyzerSilence::finalize(TrackPointer tio) { tio->setCuePoint(CuePosition(mixxx::kAnalysisChannels * m_iSignalStart, Cue::AUTOMATIC)); } - CuePointer pIntroCue = tio->findCueByType(Cue::INTRO); + CuePointer pIntroCue = tio->findCueByType(Cue::Type::Intro); if (!pIntroCue) { pIntroCue = tio->createAndAddCue(); - pIntroCue->setType(Cue::INTRO); + pIntroCue->setType(Cue::Type::Intro); pIntroCue->setSource(Cue::AUTOMATIC); pIntroCue->setPosition(mixxx::kAnalysisChannels * m_iSignalStart); pIntroCue->setLength(0.0); @@ -109,10 +109,10 @@ void AnalyzerSilence::finalize(TrackPointer tio) { pIntroCue->setLength(0.0); } - CuePointer pOutroCue = tio->findCueByType(Cue::OUTRO); + CuePointer pOutroCue = tio->findCueByType(Cue::Type::Outro); if (!pOutroCue) { pOutroCue = tio->createAndAddCue(); - pOutroCue->setType(Cue::OUTRO); + pOutroCue->setType(Cue::Type::Outro); pOutroCue->setSource(Cue::AUTOMATIC); pOutroCue->setPosition(-1.0); pOutroCue->setLength(mixxx::kAnalysisChannels * m_iSignalEnd); diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c60ff7e0256..4f7dbadc394 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -387,16 +387,16 @@ void CueControl::loadCuesFromTrack() { return; for (const CuePointer& pCue: m_pLoadedTrack->getCuePoints()) { - if (pCue->getType() == Cue::LOAD) { - DEBUG_ASSERT(!pLoadCue); // There should be only one LOAD cue + if (pCue->getType() == Cue::Type::MainCue) { + DEBUG_ASSERT(!pLoadCue); // There should be only one MainCue cue pLoadCue = pCue; - } else if (pCue->getType() == Cue::INTRO) { - DEBUG_ASSERT(!pIntroCue); // There should be only one INTRO cue + } else if (pCue->getType() == Cue::Type::Intro) { + DEBUG_ASSERT(!pIntroCue); // There should be only one Intro cue pIntroCue = pCue; - } else if (pCue->getType() == Cue::OUTRO) { - DEBUG_ASSERT(!pOutroCue); // There should be only one OUTRO cue + } else if (pCue->getType() == Cue::Type::Outro) { + DEBUG_ASSERT(!pOutroCue); // There should be only one Outro cue pOutroCue = pCue; - } else if (pCue->getType() == Cue::CUE && pCue->getHotCue() != -1) { + } else if (pCue->getType() == Cue::Type::Hotcue && pCue->getHotCue() != -1) { int hotcue = pCue->getHotCue(); HotcueControl* pControl = m_hotcueControls.value(hotcue, NULL); @@ -545,7 +545,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { pCue->setPosition(cuePosition); pCue->setHotCue(hotcue); pCue->setLabel(""); - pCue->setType(Cue::CUE); + pCue->setType(Cue::Type::Hotcue); pCue->setSource(Cue::MANUAL); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); @@ -1103,10 +1103,10 @@ void CueControl::introStartSet(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::INTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (!pCue) { pCue = pLoadedTrack->createAndAddCue(); - pCue->setType(Cue::INTRO); + pCue->setType(Cue::Type::Intro); } pCue->setSource(Cue::MANUAL); pCue->setPosition(position); @@ -1125,7 +1125,7 @@ void CueControl::introStartClear(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::INTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (introEnd != -1.0) { pCue->setPosition(-1.0); pCue->setLength(introEnd); @@ -1182,10 +1182,10 @@ void CueControl::introEndSet(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::INTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (!pCue) { pCue = pLoadedTrack->createAndAddCue(); - pCue->setType(Cue::INTRO); + pCue->setType(Cue::Type::Intro); } pCue->setSource(Cue::MANUAL); if (introStart != -1.0) { @@ -1209,7 +1209,7 @@ void CueControl::introEndClear(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::INTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (introStart != -1.0) { pCue->setPosition(introStart); pCue->setLength(0.0); @@ -1266,10 +1266,10 @@ void CueControl::outroStartSet(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::OUTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (!pCue) { pCue = pLoadedTrack->createAndAddCue(); - pCue->setType(Cue::OUTRO); + pCue->setType(Cue::Type::Outro); } pCue->setSource(Cue::MANUAL); pCue->setPosition(position); @@ -1288,7 +1288,7 @@ void CueControl::outroStartClear(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::OUTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (outroEnd != -1.0) { pCue->setPosition(-1.0); pCue->setLength(outroEnd); @@ -1345,10 +1345,10 @@ void CueControl::outroEndSet(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::OUTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (!pCue) { pCue = pLoadedTrack->createAndAddCue(); - pCue->setType(Cue::OUTRO); + pCue->setType(Cue::Type::Outro); } pCue->setSource(Cue::MANUAL); if (outroStart != -1.0) { @@ -1372,7 +1372,7 @@ void CueControl::outroEndClear(double v) { lock.unlock(); if (pLoadedTrack) { - CuePointer pCue = pLoadedTrack->findCueByType(Cue::OUTRO); + CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (outroStart != -1.0) { pCue->setPosition(outroStart); pCue->setLength(0.0); diff --git a/src/engine/controls/vinylcontrolcontrol.cpp b/src/engine/controls/vinylcontrolcontrol.cpp index 96174348c37..b5784787fe1 100644 --- a/src/engine/controls/vinylcontrolcontrol.cpp +++ b/src/engine/controls/vinylcontrolcontrol.cpp @@ -123,7 +123,7 @@ void VinylControlControl::slotControlVinylSeek(double fractionalPos) { QListIterator it(cuePoints); while (it.hasNext()) { CuePointer pCue(it.next()); - if (pCue->getType() != Cue::CUE || pCue->getHotCue() == -1) { + if (pCue->getType() != Cue::Type::Hotcue || pCue->getHotCue() == -1) { continue; } diff --git a/src/library/dao/cuedao.cpp b/src/library/dao/cuedao.cpp index 526ae19f6cb..40c6813165e 100644 --- a/src/library/dao/cuedao.cpp +++ b/src/library/dao/cuedao.cpp @@ -56,7 +56,7 @@ CuePointer CueDAO::cueFromRow(const QSqlQuery& query) const { QString label = record.value(record.indexOf("label")).toString(); int iColorId = record.value(record.indexOf("color")).toInt(); PredefinedColorPointer color = Color::kPredefinedColorsSet.predefinedColorFromId(iColorId); - CuePointer pCue(new Cue(id, trackId, (Cue::CueSource)source, (Cue::CueType)type, position, length, hotcue, label, color)); + CuePointer pCue(new Cue(id, trackId, (Cue::CueSource)source, (Cue::Type)type, position, length, hotcue, label, color)); m_cues[id] = pCue; return pCue; } @@ -144,7 +144,7 @@ bool CueDAO::saveCue(Cue* cue) { query.prepare("INSERT INTO " CUE_TABLE " (track_id, source, type, position, length, hotcue, label, color) VALUES (:track_id, :source, :type, :position, :length, :hotcue, :label, :color)"); query.bindValue(":track_id", cue->getTrackId().toVariant()); query.bindValue(":source", cue->getSource()); - query.bindValue(":type", cue->getType()); + query.bindValue(":type", static_cast(cue->getType())); query.bindValue(":position", cue->getPosition()); query.bindValue(":length", cue->getLength()); query.bindValue(":hotcue", cue->getHotCue()); @@ -174,7 +174,7 @@ bool CueDAO::saveCue(Cue* cue) { query.bindValue(":id", cue->getId()); query.bindValue(":track_id", cue->getTrackId().toVariant()); query.bindValue(":source", cue->getSource()); - query.bindValue(":type", cue->getType()); + query.bindValue(":type", static_cast(cue->getType())); query.bindValue(":position", cue->getPosition()); query.bindValue(":length", cue->getLength()); query.bindValue(":hotcue", cue->getHotCue()); diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 2edc68bdecd..ccdd3d6a5db 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -277,8 +277,8 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { QListIterator it(cuePoints); while (it.hasNext()) { CuePointer pCue = it.next(); - Cue::CueType type = pCue->getType(); - if (type == Cue::CUE || type == Cue::INTRO || type == Cue::OUTRO) { + Cue::Type type = pCue->getType(); + if (type == Cue::Type::Hotcue || type == Cue::Type::Intro || type == Cue::Type::Outro) { listPoints.push_back(pCue); } } @@ -325,16 +325,16 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { // Decode cue type to display text QString cueType; switch (pCue->getType()) { - case Cue::CUE: + case Cue::Type::Hotcue: cueType = "Hotcue"; break; - case Cue::INTRO: + case Cue::Type::Intro: cueType = "Intro"; break; - case Cue::OUTRO: + case Cue::Type::Outro: cueType = "Outro"; break; - default: + default: break; } diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index d01243771d6..12beeecf882 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -181,7 +181,7 @@ void BaseTrackPlayerImpl::loadTrack(TrackPointer pTrack) { QListIterator it(trackCues); while (it.hasNext()) { CuePointer pCue(it.next()); - if (pCue->getType() == Cue::LOOP) { + if (pCue->getType() == Cue::Type::Loop) { double loopStart = pCue->getPosition(); double loopEnd = loopStart + pCue->getLength(); if (loopStart != kNoTrigger && loopEnd != kNoTrigger && loopStart <= loopEnd) { @@ -220,14 +220,14 @@ TrackPointer BaseTrackPlayerImpl::unloadTrack() { QListIterator it(cuePoints); while (it.hasNext()) { CuePointer pCue(it.next()); - if (pCue->getType() == Cue::LOOP) { + if (pCue->getType() == Cue::Type::Loop) { pLoopCue = pCue; } } if (!pLoopCue) { pLoopCue = m_pLoadedTrack->createAndAddCue(); pLoopCue->setSource(Cue::MANUAL); - pLoopCue->setType(Cue::LOOP); + pLoopCue->setType(Cue::Type::Loop); } pLoopCue->setPosition(loopStart); pLoopCue->setLength(loopEnd - loopStart); diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 5580d98d2c8..32433ba47a5 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -54,12 +54,12 @@ TEST_F(AnalyzerSilenceTest, SilenceTrack) { EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); - CuePointer pIntroCue = pTrack->findCueByType(Cue::INTRO); + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); - CuePointer pOutroCue = pTrack->findCueByType(Cue::OUTRO); + CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); @@ -78,12 +78,12 @@ TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); - CuePointer pIntroCue = pTrack->findCueByType(Cue::INTRO); + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); - CuePointer pOutroCue = pTrack->findCueByType(Cue::OUTRO); + CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); @@ -112,12 +112,12 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, cue.getPosition()); EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); - CuePointer pIntroCue = pTrack->findCueByType(Cue::INTRO); + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); - CuePointer pOutroCue = pTrack->findCueByType(Cue::OUTRO); + CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(3 * nTrackSampleDataLength / 4, pOutroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); @@ -158,12 +158,12 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, cue.getPosition()); EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); - CuePointer pIntroCue = pTrack->findCueByType(Cue::INTRO); + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); - CuePointer pOutroCue = pTrack->findCueByType(Cue::OUTRO); + CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(4 * oneFifthOfTrackLength, pOutroCue->getLength()); EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); @@ -175,13 +175,13 @@ TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedCues) { pTrack->setCuePoint(CuePosition(100, Cue::AUTOMATIC)); // Arbitrary value CuePointer pIntroCue = pTrack->createAndAddCue(); - pIntroCue->setType(Cue::INTRO); + pIntroCue->setType(Cue::Type::Intro); pIntroCue->setSource(Cue::AUTOMATIC); pIntroCue->setPosition(1000); // Arbitrary value pIntroCue->setLength(0.0); CuePointer pOutroCue = pTrack->createAndAddCue(); - pOutroCue->setType(Cue::OUTRO); + pOutroCue->setType(Cue::Type::Outro); pOutroCue->setSource(Cue::AUTOMATIC); pOutroCue->setPosition(-1.0); pOutroCue->setLength(9000); // Arbitrary value @@ -216,13 +216,13 @@ TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedRangeCues) { int thirdTrackLength = nTrackSampleDataLength / 3; CuePointer pIntroCue = pTrack->createAndAddCue(); - pIntroCue->setType(Cue::INTRO); + pIntroCue->setType(Cue::Type::Intro); pIntroCue->setSource(Cue::AUTOMATIC); pIntroCue->setPosition(1500.0); // Arbitrary value pIntroCue->setLength(1000.0); // Arbitrary value CuePointer pOutroCue = pTrack->createAndAddCue(); - pOutroCue->setType(Cue::OUTRO); + pOutroCue->setType(Cue::Type::Outro); pOutroCue->setSource(Cue::AUTOMATIC); pOutroCue->setPosition(9000.0); // Arbitrary value pOutroCue->setLength(1000.0); // Arbitrary value @@ -263,13 +263,13 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { pTrack->setCuePoint(CuePosition(kManualCuePosition, Cue::MANUAL)); CuePointer pIntroCue = pTrack->createAndAddCue(); - pIntroCue->setType(Cue::INTRO); + pIntroCue->setType(Cue::Type::Intro); pIntroCue->setSource(Cue::MANUAL); pIntroCue->setPosition(kManualIntroPosition); pIntroCue->setLength(0.0); CuePointer pOutroCue = pTrack->createAndAddCue(); - pOutroCue->setType(Cue::OUTRO); + pOutroCue->setType(Cue::Type::Outro); pOutroCue->setSource(Cue::MANUAL); pOutroCue->setPosition(-1.0); pOutroCue->setLength(kManualOutroPosition); diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 5e4587c06f9..ceac483a494 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -79,12 +79,12 @@ TEST_F(CueControlTest, LoadUnloadTrack) { TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::INTRO); + pIntro->setType(Cue::Type::Intro); pIntro->setSource(Cue::MANUAL); pIntro->setPosition(150.0); pIntro->setLength(50.0); auto pOutro = pTrack->createAndAddCue(); - pOutro->setType(Cue::OUTRO); + pOutro->setType(Cue::Type::Outro); pOutro->setSource(Cue::MANUAL); pOutro->setPosition(250.0); pOutro->setLength(50.0); @@ -118,12 +118,12 @@ TEST_F(CueControlTest, LoadTrackWithDetectedCues) { TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::AUTOMATIC)); auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::INTRO); + pIntro->setType(Cue::Type::Intro); pIntro->setSource(Cue::AUTOMATIC); pIntro->setPosition(100.0); pIntro->setLength(0.0); auto pOutro = pTrack->createAndAddCue(); - pOutro->setType(Cue::OUTRO); + pOutro->setType(Cue::Type::Outro); pOutro->setSource(Cue::AUTOMATIC); pOutro->setPosition(-1.0); pOutro->setLength(200.0); @@ -144,12 +144,12 @@ TEST_F(CueControlTest, LoadTrackWithDetectedCues) { TEST_F(CueControlTest, LoadTrackWithIntroEndAndOutroStart) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::INTRO); + pIntro->setType(Cue::Type::Intro); pIntro->setSource(Cue::MANUAL); pIntro->setPosition(-1.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); - pOutro->setType(Cue::OUTRO); + pOutro->setType(Cue::Type::Outro); pOutro->setSource(Cue::MANUAL); pOutro->setPosition(250.0); pOutro->setLength(0.0); @@ -182,13 +182,13 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabled) { pTrack->setCuePoint(CuePosition(1.9 * beatLength, Cue::AUTOMATIC)); auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::INTRO); + pIntro->setType(Cue::Type::Intro); pIntro->setSource(Cue::AUTOMATIC); pIntro->setPosition(2.1 * beatLength); pIntro->setLength(1.2 * beatLength); auto pOutro = pTrack->createAndAddCue(); - pOutro->setType(Cue::OUTRO); + pOutro->setType(Cue::Type::Outro); pOutro->setSource(Cue::AUTOMATIC); pOutro->setPosition(11.1 * beatLength); pOutro->setLength(4.4 * beatLength); @@ -212,13 +212,13 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabledNoBeats) { pTrack->setCuePoint(CuePosition(100.0, Cue::AUTOMATIC)); auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::INTRO); + pIntro->setType(Cue::Type::Intro); pIntro->setSource(Cue::AUTOMATIC); pIntro->setPosition(250.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); - pOutro->setType(Cue::OUTRO); + pOutro->setType(Cue::Type::Outro); pOutro->setSource(Cue::AUTOMATIC); pOutro->setPosition(550.0); pOutro->setLength(250.0); @@ -242,13 +242,13 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { pTrack->setCuePoint(CuePosition(240.0, Cue::AUTOMATIC)); auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::INTRO); + pIntro->setType(Cue::Type::Intro); pIntro->setSource(Cue::AUTOMATIC); pIntro->setPosition(210.0); pIntro->setLength(120.0); auto pOutro = pTrack->createAndAddCue(); - pOutro->setType(Cue::OUTRO); + pOutro->setType(Cue::Type::Outro); pOutro->setSource(Cue::AUTOMATIC); pOutro->setPosition(770.0); pOutro->setLength(220.0); @@ -376,7 +376,7 @@ TEST_F(CueControlTest, SeekOnLoadIntroCue) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::INTRO); + pIntro->setType(Cue::Type::Intro); pIntro->setSource(Cue::MANUAL); pIntro->setPosition(200.0); @@ -405,7 +405,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(-1.0, m_pIntroEndPosition->get()); EXPECT_FALSE(m_pIntroEndEnabled->toBool()); - CuePointer pCue = pTrack->findCueByType(Cue::INTRO); + CuePointer pCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); @@ -422,7 +422,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(500.0, m_pIntroEndPosition->get()); EXPECT_TRUE(m_pIntroEndEnabled->toBool()); - pCue = pTrack->findCueByType(Cue::INTRO); + pCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); @@ -438,7 +438,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(500.0, m_pIntroEndPosition->get()); EXPECT_TRUE(m_pIntroEndEnabled->toBool()); - pCue = pTrack->findCueByType(Cue::INTRO); + pCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); @@ -454,7 +454,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(-1.0, m_pIntroEndPosition->get()); EXPECT_FALSE(m_pIntroEndEnabled->toBool()); - EXPECT_EQ(nullptr, pTrack->findCueByType(Cue::INTRO)); + EXPECT_EQ(nullptr, pTrack->findCueByType(Cue::Type::Intro)); } TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { @@ -469,7 +469,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(-1.0, m_pOutroEndPosition->get()); EXPECT_FALSE(m_pOutroEndEnabled->toBool()); - CuePointer pCue = pTrack->findCueByType(Cue::OUTRO); + CuePointer pCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); @@ -486,7 +486,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(1000.0, m_pOutroEndPosition->get()); EXPECT_TRUE(m_pOutroEndEnabled->toBool()); - pCue = pTrack->findCueByType(Cue::OUTRO); + pCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); @@ -502,7 +502,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(1000.0, m_pOutroEndPosition->get()); EXPECT_TRUE(m_pOutroEndEnabled->toBool()); - pCue = pTrack->findCueByType(Cue::OUTRO); + pCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); @@ -518,5 +518,5 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { EXPECT_DOUBLE_EQ(-1.0, m_pOutroEndPosition->get()); EXPECT_FALSE(m_pOutroEndEnabled->toBool()); - EXPECT_EQ(nullptr, pTrack->findCueByType(Cue::OUTRO)); + EXPECT_EQ(nullptr, pTrack->findCueByType(Cue::Type::Outro)); } diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 1d27df21c6d..3110634c85c 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -24,7 +24,7 @@ Cue::Cue(TrackId trackId) m_iId(-1), m_trackId(trackId), m_source(UNKNOWN), - m_type(INVALID), + m_type(Cue::Type::Invalid), m_samplePosition(-1.0), m_length(0.0), m_iHotCue(-1), @@ -33,7 +33,7 @@ Cue::Cue(TrackId trackId) DEBUG_ASSERT(!m_label.isNull()); } -Cue::Cue(int id, TrackId trackId, Cue::CueSource source, Cue::CueType type, double position, double length, +Cue::Cue(int id, TrackId trackId, Cue::CueSource source, Cue::Type type, double position, double length, int hotCue, QString label, PredefinedColorPointer color) : m_bDirty(false), m_iId(id), @@ -87,12 +87,12 @@ void Cue::setSource(CueSource source) { emit(updated()); } -Cue::CueType Cue::getType() const { +Cue::Type Cue::getType() const { QMutexLocker lock(&m_mutex); return m_type; } -void Cue::setType(Cue::CueType type) { +void Cue::setType(Cue::Type type) { QMutexLocker lock(&m_mutex); m_type = type; m_bDirty = true; diff --git a/src/track/cue.h b/src/track/cue.h index 6843dab1974..df7603f091a 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -23,15 +23,15 @@ class Cue : public QObject { MANUAL = 2, }; - enum CueType { - INVALID = 0, - CUE = 1, // hot cue - LOAD = 2, // the cue - BEAT = 3, - LOOP = 4, - JUMP = 5, - INTRO = 6, - OUTRO = 7, + enum class Type { + Invalid = 0, + Hotcue = 1, + MainCue = 2, + Beat = 3, // unused (what is this for?) + Loop = 4, + Jump = 5, + Intro = 6, + Outro = 7, }; ~Cue() override = default; @@ -43,8 +43,8 @@ class Cue : public QObject { CueSource getSource() const; void setSource(CueSource source); - CueType getType() const; - void setType(CueType type); + Cue::Type getType() const; + void setType(Cue::Type type); double getPosition() const; void setPosition(double samplePosition); @@ -68,7 +68,7 @@ class Cue : public QObject { private: explicit Cue(TrackId trackId); - Cue(int id, TrackId trackId, CueSource source, CueType type, double position, double length, + Cue(int id, TrackId trackId, CueSource source, Cue::Type type, double position, double length, int hotCue, QString label, PredefinedColorPointer color); void setDirty(bool dirty); void setId(int id); @@ -80,7 +80,7 @@ class Cue : public QObject { int m_iId; TrackId m_trackId; CueSource m_source; - CueType m_type; + Cue::Type m_type; double m_samplePosition; double m_length; int m_iHotCue; diff --git a/src/track/track.cpp b/src/track/track.cpp index 5e8559e0333..d5e21e7137d 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -732,13 +732,13 @@ void Track::setCuePoint(CuePosition cue) { } // Store the cue point in a load cue - CuePointer pLoadCue = findCueByType(Cue::LOAD); + CuePointer pLoadCue = findCueByType(Cue::Type::MainCue); Cue::CueSource source = cue.getSource(); double position = cue.getPosition(); if (position != 0.0 && position != -1.0) { if (!pLoadCue) { pLoadCue = CuePointer(new Cue(m_record.getId())); - pLoadCue->setType(Cue::LOAD); + pLoadCue->setType(Cue::Type::MainCue); connect(pLoadCue.get(), SIGNAL(updated()), this, SLOT(slotCueUpdated())); m_cuePoints.push_back(pLoadCue); @@ -775,10 +775,10 @@ CuePointer Track::createAndAddCue() { return pCue; } -CuePointer Track::findCueByType(Cue::CueType type) const { +CuePointer Track::findCueByType(Cue::Type type) const { // This method cannot be used for hotcues because there can be // multiple hotcues and this function returns only a single CuePointer. - DEBUG_ASSERT(type != Cue::CUE); + DEBUG_ASSERT(type != Cue::Type::Hotcue); QMutexLocker lock(&m_qMutex); for (const CuePointer& pCue: m_cuePoints) { if (pCue->getType() == type) { @@ -796,20 +796,20 @@ void Track::removeCue(const CuePointer& pCue) { QMutexLocker lock(&m_qMutex); disconnect(pCue.get(), 0, this, 0); m_cuePoints.removeOne(pCue); - if (pCue->getType() == Cue::LOAD) { + if (pCue->getType() == Cue::Type::MainCue) { m_record.setCuePoint(CuePosition()); } markDirtyAndUnlock(&lock); emit(cuesUpdated()); } -void Track::removeCuesOfType(Cue::CueType type) { +void Track::removeCuesOfType(Cue::Type type) { QMutexLocker lock(&m_qMutex); bool dirty = false; QMutableListIterator it(m_cuePoints); while (it.hasNext()) { CuePointer pCue = it.next(); - // FIXME: Why does this only work for the CUE CueType? + // FIXME: Why does this only work for the Hotcue Type? if (pCue->getType() == type) { disconnect(pCue.get(), 0, this, 0); it.remove(); @@ -843,7 +843,7 @@ void Track::setCuePoints(const QList& cuePoints) { connect(pCue.get(), SIGNAL(updated()), this, SLOT(slotCueUpdated())); // update main cue point - if (pCue->getType() == Cue::LOAD) { + if (pCue->getType() == Cue::Type::MainCue) { m_record.setCuePoint(CuePosition(pCue->getPosition(), pCue->getSource())); } } diff --git a/src/track/track.h b/src/track/track.h index cfdc2d3a4e6..21e1149acd8 100644 --- a/src/track/track.h +++ b/src/track/track.h @@ -250,9 +250,9 @@ class Track : public QObject { // Calls for managing the track's cue points CuePointer createAndAddCue(); - CuePointer findCueByType(Cue::CueType type) const; // NOTE: Cannot be used for hotcues. + CuePointer findCueByType(Cue::Type type) const; // NOTE: Cannot be used for hotcues. void removeCue(const CuePointer& pCue); - void removeCuesOfType(Cue::CueType); + void removeCuesOfType(Cue::Type); QList getCuePoints() const; void setCuePoints(const QList& cuePoints); diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 85024eb6847..dab0f17d8d5 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -1844,7 +1844,7 @@ void WTrackTableView::slotClearMainCue() { for (const QModelIndex& index : indices) { TrackPointer pTrack = trackModel->getTrack(index); if (pTrack) { - pTrack->removeCuesOfType(Cue::LOAD); + pTrack->removeCuesOfType(Cue::Type::MainCue); } } } @@ -1860,7 +1860,7 @@ void WTrackTableView::slotClearHotCues() { for (const QModelIndex& index : indices) { TrackPointer pTrack = trackModel->getTrack(index); if (pTrack) { - pTrack->removeCuesOfType(Cue::CUE); + pTrack->removeCuesOfType(Cue::Type::Hotcue); } } } @@ -1876,7 +1876,7 @@ void WTrackTableView::slotClearLoop() { for (const QModelIndex& index : indices) { TrackPointer pTrack = trackModel->getTrack(index); if (pTrack) { - pTrack->removeCuesOfType(Cue::LOOP); + pTrack->removeCuesOfType(Cue::Type::Loop); } } } From 580c20b045a6c820bddb895eb65f677bf9a938a9 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 11:50:22 -0500 Subject: [PATCH 007/198] convert Cue::CueSource to enum class --- src/analyzer/analyzersilence.cpp | 16 ++++---- src/engine/controls/cuecontrol.cpp | 22 +++++----- src/engine/controls/cuecontrol.h | 2 +- src/library/dao/cuedao.cpp | 6 +-- src/library/dao/trackdao.cpp | 2 +- src/mixer/basetrackplayer.cpp | 2 +- src/test/analyzersilence_test.cpp | 56 ++++++++++++------------- src/test/cuecontrol_test.cpp | 66 +++++++++++++++--------------- src/track/cue.cpp | 8 ++-- src/track/cue.h | 32 +++++++-------- src/track/track.cpp | 2 +- 11 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 31284266763..f952151eba8 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -38,12 +38,12 @@ bool AnalyzerSilence::isDisabledOrLoadStoredSuccess(TrackPointer tio) const { } CuePointer pIntroCue = tio->findCueByType(Cue::Type::Intro); - if (!pIntroCue || pIntroCue->getSource() != Cue::MANUAL) { + if (!pIntroCue || pIntroCue->getSource() != Cue::Source::Manual) { return false; } CuePointer pOutroCue = tio->findCueByType(Cue::Type::Outro); - if (!pOutroCue || pOutroCue->getSource() != Cue::MANUAL) { + if (!pOutroCue || pOutroCue->getSource() != Cue::Source::Manual) { return false; } @@ -94,17 +94,17 @@ void AnalyzerSilence::finalize(TrackPointer tio) { } if (shouldUpdateCue(tio->getCuePoint())) { - tio->setCuePoint(CuePosition(mixxx::kAnalysisChannels * m_iSignalStart, Cue::AUTOMATIC)); + tio->setCuePoint(CuePosition(mixxx::kAnalysisChannels * m_iSignalStart, Cue::Source::Automatic)); } CuePointer pIntroCue = tio->findCueByType(Cue::Type::Intro); if (!pIntroCue) { pIntroCue = tio->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::AUTOMATIC); + pIntroCue->setSource(Cue::Source::Automatic); pIntroCue->setPosition(mixxx::kAnalysisChannels * m_iSignalStart); pIntroCue->setLength(0.0); - } else if (pIntroCue->getSource() != Cue::MANUAL) { + } else if (pIntroCue->getSource() != Cue::Source::Manual) { pIntroCue->setPosition(mixxx::kAnalysisChannels * m_iSignalStart); pIntroCue->setLength(0.0); } @@ -113,15 +113,15 @@ void AnalyzerSilence::finalize(TrackPointer tio) { if (!pOutroCue) { pOutroCue = tio->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::AUTOMATIC); + pOutroCue->setSource(Cue::Source::Automatic); pOutroCue->setPosition(-1.0); pOutroCue->setLength(mixxx::kAnalysisChannels * m_iSignalEnd); - } else if (pOutroCue->getSource() != Cue::MANUAL) { + } else if (pOutroCue->getSource() != Cue::Source::Manual) { pOutroCue->setPosition(-1.0); pOutroCue->setLength(mixxx::kAnalysisChannels * m_iSignalEnd); } } bool AnalyzerSilence::shouldUpdateCue(CuePosition cue) { - return cue.getSource() != Cue::MANUAL || cue.getPosition() == -1.0 || cue.getPosition() == 0.0; + return cue.getSource() != Cue::Source::Manual || cue.getPosition() == -1.0 || cue.getPosition() == 0.0; } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 4f7dbadc394..44a1fac2d1e 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -426,7 +426,7 @@ void CueControl::loadCuesFromTrack() { if (pLoadCue) { double position = pLoadCue->getPosition(); - Cue::CueSource source = pLoadCue->getSource(); + Cue::Source source = pLoadCue->getSource(); m_pCuePoint->set(quantizeCuePoint(position, source, QuantizeMode::ClosestBeat)); } else { @@ -436,7 +436,7 @@ void CueControl::loadCuesFromTrack() { if (pIntroCue) { double startPosition = pIntroCue->getPosition(); double endPosition = pIntroCue->getEndPosition(); - Cue::CueSource source = pIntroCue->getSource(); + Cue::Source source = pIntroCue->getSource(); m_pIntroStartPosition->set(quantizeCuePoint(startPosition, source, QuantizeMode::PreviousBeat)); m_pIntroStartEnabled->forceSet(startPosition == -1.0 ? 0.0 : 1.0); @@ -452,7 +452,7 @@ void CueControl::loadCuesFromTrack() { if (pOutroCue) { double startPosition = pOutroCue->getPosition(); double endPosition = pOutroCue->getEndPosition(); - Cue::CueSource source = pOutroCue->getSource(); + Cue::Source source = pOutroCue->getSource(); m_pOutroStartPosition->set(quantizeCuePoint(startPosition, source, QuantizeMode::PreviousBeat)); m_pOutroStartEnabled->forceSet(startPosition == -1.0 ? 0.0 : 1.0); @@ -546,7 +546,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { pCue->setHotCue(hotcue); pCue->setLabel(""); pCue->setType(Cue::Type::Hotcue); - pCue->setSource(Cue::MANUAL); + pCue->setSource(Cue::Source::Manual); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); @@ -791,7 +791,7 @@ void CueControl::cueSet(double v) { // Store cue point in loaded track if (pLoadedTrack) { - pLoadedTrack->setCuePoint(CuePosition(cue, Cue::MANUAL)); + pLoadedTrack->setCuePoint(CuePosition(cue, Cue::Source::Manual)); } } @@ -1108,7 +1108,7 @@ void CueControl::introStartSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - pCue->setSource(Cue::MANUAL); + pCue->setSource(Cue::Source::Manual); pCue->setPosition(position); pCue->setLength(introEnd != -1.0 ? introEnd - position : 0.0); } @@ -1187,7 +1187,7 @@ void CueControl::introEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - pCue->setSource(Cue::MANUAL); + pCue->setSource(Cue::Source::Manual); if (introStart != -1.0) { pCue->setPosition(introStart); pCue->setLength(position - introStart); @@ -1271,7 +1271,7 @@ void CueControl::outroStartSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - pCue->setSource(Cue::MANUAL); + pCue->setSource(Cue::Source::Manual); pCue->setPosition(position); pCue->setLength(outroEnd != -1.0 ? outroEnd - position : 0.0); } @@ -1350,7 +1350,7 @@ void CueControl::outroEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - pCue->setSource(Cue::MANUAL); + pCue->setSource(Cue::Source::Manual); if (outroStart != -1.0) { pCue->setPosition(outroStart); pCue->setLength(position - outroStart); @@ -1586,9 +1586,9 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { } } -double CueControl::quantizeCuePoint(double position, Cue::CueSource source, QuantizeMode mode) { +double CueControl::quantizeCuePoint(double position, Cue::Source source, QuantizeMode mode) { // Don't quantize unset cues, manual cues or when quantization is disabled. - if (position == -1.0 || source == Cue::MANUAL || !m_pQuantizeEnabled->toBool()) { + if (position == -1.0 || source == Cue::Source::Manual || !m_pQuantizeEnabled->toBool()) { return position; } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 5da47fe0749..3e1f93c51b0 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -186,7 +186,7 @@ class CueControl : public EngineControl { void detachCue(int hotcueNumber); void loadCuesFromTrack(); void reloadCuesFromTrack(); - double quantizeCuePoint(double position, Cue::CueSource source, QuantizeMode mode); + double quantizeCuePoint(double position, Cue::Source source, QuantizeMode mode); double quantizeCurrentPosition(QuantizeMode mode); TrackAt getTrackAt() const; diff --git a/src/library/dao/cuedao.cpp b/src/library/dao/cuedao.cpp index 40c6813165e..89d4176449d 100644 --- a/src/library/dao/cuedao.cpp +++ b/src/library/dao/cuedao.cpp @@ -56,7 +56,7 @@ CuePointer CueDAO::cueFromRow(const QSqlQuery& query) const { QString label = record.value(record.indexOf("label")).toString(); int iColorId = record.value(record.indexOf("color")).toInt(); PredefinedColorPointer color = Color::kPredefinedColorsSet.predefinedColorFromId(iColorId); - CuePointer pCue(new Cue(id, trackId, (Cue::CueSource)source, (Cue::Type)type, position, length, hotcue, label, color)); + CuePointer pCue(new Cue(id, trackId, (Cue::Source)source, (Cue::Type)type, position, length, hotcue, label, color)); m_cues[id] = pCue; return pCue; } @@ -143,7 +143,7 @@ bool CueDAO::saveCue(Cue* cue) { QSqlQuery query(m_database); query.prepare("INSERT INTO " CUE_TABLE " (track_id, source, type, position, length, hotcue, label, color) VALUES (:track_id, :source, :type, :position, :length, :hotcue, :label, :color)"); query.bindValue(":track_id", cue->getTrackId().toVariant()); - query.bindValue(":source", cue->getSource()); + query.bindValue(":source", static_cast(cue->getSource())); query.bindValue(":type", static_cast(cue->getType())); query.bindValue(":position", cue->getPosition()); query.bindValue(":length", cue->getLength()); @@ -173,7 +173,7 @@ bool CueDAO::saveCue(Cue* cue) { " WHERE id = :id"); query.bindValue(":id", cue->getId()); query.bindValue(":track_id", cue->getTrackId().toVariant()); - query.bindValue(":source", cue->getSource()); + query.bindValue(":source", static_cast(cue->getSource())); query.bindValue(":type", static_cast(cue->getType())); query.bindValue(":position", cue->getPosition()); query.bindValue(":length", cue->getLength()); diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp index 2c842464d2d..ae683d9adfc 100644 --- a/src/library/dao/trackdao.cpp +++ b/src/library/dao/trackdao.cpp @@ -1036,7 +1036,7 @@ bool setTrackSampleRate(const QSqlRecord& record, const int column, bool setTrackCuePoint(const QSqlRecord& record, const int column, TrackPointer pTrack) { - pTrack->setCuePoint(CuePosition(record.value(column).toDouble(), Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(record.value(column).toDouble(), Cue::Source::Manual)); return false; } diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 12beeecf882..45c5da149c9 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -226,7 +226,7 @@ TrackPointer BaseTrackPlayerImpl::unloadTrack() { } if (!pLoopCue) { pLoopCue = m_pLoadedTrack->createAndAddCue(); - pLoopCue->setSource(Cue::MANUAL); + pLoopCue->setSource(Cue::Source::Manual); pLoopCue->setType(Cue::Type::Loop); } pLoopCue->setPosition(loopStart); diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 32433ba47a5..68cc97e24ad 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -52,17 +52,17 @@ TEST_F(AnalyzerSilenceTest, SilenceTrack) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); - EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); + EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { @@ -76,17 +76,17 @@ TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); - EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); + EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { @@ -110,17 +110,17 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, cue.getPosition()); - EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); + EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(3 * nTrackSampleDataLength / 4, pOutroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { @@ -156,33 +156,33 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, cue.getPosition()); - EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); + EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(4 * oneFifthOfTrackLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedCues) { int halfTrackLength = nTrackSampleDataLength / 2; - pTrack->setCuePoint(CuePosition(100, Cue::AUTOMATIC)); // Arbitrary value + pTrack->setCuePoint(CuePosition(100, Cue::Source::Automatic)); // Arbitrary value CuePointer pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::AUTOMATIC); + pIntroCue->setSource(Cue::Source::Automatic); pIntroCue->setPosition(1000); // Arbitrary value pIntroCue->setLength(0.0); CuePointer pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::AUTOMATIC); + pOutroCue->setSource(Cue::Source::Automatic); pOutroCue->setPosition(-1.0); pOutroCue->setLength(9000); // Arbitrary value @@ -201,15 +201,15 @@ TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedCues) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(halfTrackLength, cue.getPosition()); - EXPECT_EQ(Cue::AUTOMATIC, cue.getSource()); + EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); EXPECT_DOUBLE_EQ(halfTrackLength, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedRangeCues) { @@ -217,13 +217,13 @@ TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedRangeCues) { CuePointer pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::AUTOMATIC); + pIntroCue->setSource(Cue::Source::Automatic); pIntroCue->setPosition(1500.0); // Arbitrary value pIntroCue->setLength(1000.0); // Arbitrary value CuePointer pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::AUTOMATIC); + pOutroCue->setSource(Cue::Source::Automatic); pOutroCue->setPosition(9000.0); // Arbitrary value pOutroCue->setLength(1000.0); // Arbitrary value @@ -247,11 +247,11 @@ TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedRangeCues) { EXPECT_DOUBLE_EQ(thirdTrackLength, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pIntroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(2 * thirdTrackLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::AUTOMATIC, pOutroCue->getSource()); + EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, RespectUserEdits) { @@ -260,17 +260,17 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { const double kManualIntroPosition = 0.1 * nTrackSampleDataLength; const double kManualOutroPosition = 0.9 * nTrackSampleDataLength; - pTrack->setCuePoint(CuePosition(kManualCuePosition, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(kManualCuePosition, Cue::Source::Manual)); CuePointer pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::MANUAL); + pIntroCue->setSource(Cue::Source::Manual); pIntroCue->setPosition(kManualIntroPosition); pIntroCue->setLength(0.0); CuePointer pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::MANUAL); + pOutroCue->setSource(Cue::Source::Manual); pOutroCue->setPosition(-1.0); pOutroCue->setLength(kManualOutroPosition); @@ -289,15 +289,15 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(kManualCuePosition, cue.getPosition()); - EXPECT_EQ(Cue::MANUAL, cue.getSource()); + EXPECT_EQ(Cue::Source::Manual, cue.getSource()); EXPECT_DOUBLE_EQ(kManualIntroPosition, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::MANUAL, pIntroCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pIntroCue->getSource()); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(kManualOutroPosition, pOutroCue->getLength()); - EXPECT_EQ(Cue::MANUAL, pOutroCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pOutroCue->getSource()); } } diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index ceac483a494..4d7dd138e9f 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -77,15 +77,15 @@ class CueControlTest : public BaseSignalPathTest { TEST_F(CueControlTest, LoadUnloadTrack) { TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::MANUAL); + pIntro->setSource(Cue::Source::Manual); pIntro->setPosition(150.0); pIntro->setLength(50.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::MANUAL); + pOutro->setSource(Cue::Source::Manual); pOutro->setPosition(250.0); pOutro->setLength(50.0); @@ -116,15 +116,15 @@ TEST_F(CueControlTest, LoadUnloadTrack) { TEST_F(CueControlTest, LoadTrackWithDetectedCues) { TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::AUTOMATIC)); + pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Automatic)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::AUTOMATIC); + pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(100.0); pIntro->setLength(0.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::AUTOMATIC); + pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(-1.0); pOutro->setLength(200.0); @@ -145,12 +145,12 @@ TEST_F(CueControlTest, LoadTrackWithIntroEndAndOutroStart) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::MANUAL); + pIntro->setSource(Cue::Source::Manual); pIntro->setPosition(-1.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::MANUAL); + pOutro->setSource(Cue::Source::Manual); pOutro->setPosition(250.0); pOutro->setLength(0.0); @@ -179,17 +179,17 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabled) { const double bpm = pTrack->getBpm(); const double beatLength = (60.0 * sampleRate / bpm) * frameSize; - pTrack->setCuePoint(CuePosition(1.9 * beatLength, Cue::AUTOMATIC)); + pTrack->setCuePoint(CuePosition(1.9 * beatLength, Cue::Source::Automatic)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::AUTOMATIC); + pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(2.1 * beatLength); pIntro->setLength(1.2 * beatLength); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::AUTOMATIC); + pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(11.1 * beatLength); pOutro->setLength(4.4 * beatLength); @@ -209,17 +209,17 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabledNoBeats) { pTrack->setSampleRate(44100); pTrack->setBpm(0.0); - pTrack->setCuePoint(CuePosition(100.0, Cue::AUTOMATIC)); + pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Automatic)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::AUTOMATIC); + pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(250.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::AUTOMATIC); + pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(550.0); pOutro->setLength(250.0); @@ -239,17 +239,17 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { pTrack->setSampleRate(44100); pTrack->setBpm(120.0); - pTrack->setCuePoint(CuePosition(240.0, Cue::AUTOMATIC)); + pTrack->setCuePoint(CuePosition(240.0, Cue::Source::Automatic)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::AUTOMATIC); + pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(210.0); pIntro->setLength(120.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::AUTOMATIC); + pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(770.0); pOutro->setLength(220.0); @@ -267,7 +267,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { static_cast(SeekOnLoadMode::UsePreference))); TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); loadTrack(pTrack); @@ -275,7 +275,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { EXPECT_DOUBLE_EQ(100.0, getCurrentSample()); // Move cue and check if track is following it. - pTrack->setCuePoint(CuePosition(200.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(200.0, Cue::Source::Manual)); ProcessBuffer(); EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); @@ -287,7 +287,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { static_cast(SeekOnLoadMode::UsePreference))); TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(-100.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(-100.0, Cue::Source::Manual)); loadTrack(pTrack); @@ -295,7 +295,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { EXPECT_DOUBLE_EQ(-100.0, getCurrentSample()); // Move cue and check if track is following it. - pTrack->setCuePoint(CuePosition(-200.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(-200.0, Cue::Source::Manual)); ProcessBuffer(); EXPECT_DOUBLE_EQ(-200.0, m_pCuePoint->get()); @@ -314,7 +314,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { EXPECT_DOUBLE_EQ(0.0, getCurrentSample()); // Set cue and check if track is seeked to it. - pTrack->setCuePoint(CuePosition(200.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(200.0, Cue::Source::Manual)); ProcessBuffer(); EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); @@ -329,7 +329,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(1)); TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); loadTrack(pTrack); @@ -342,7 +342,7 @@ TEST_F(CueControlTest, SeekOnLoadZeroPos) { static_cast(SeekOnLoadMode::Beginning))); TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); loadTrack(pTrack); @@ -355,7 +355,7 @@ TEST_F(CueControlTest, SeekOnLoadMainCue) { static_cast(SeekOnLoadMode::MainCue))); TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); loadTrack(pTrack); @@ -363,7 +363,7 @@ TEST_F(CueControlTest, SeekOnLoadMainCue) { EXPECT_DOUBLE_EQ(100.0, getCurrentSample()); // Move cue and check if track is following it. - pTrack->setCuePoint(CuePosition(200.0, Cue::MANUAL)); + pTrack->setCuePoint(CuePosition(200.0, Cue::Source::Manual)); ProcessBuffer(); EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); @@ -377,7 +377,7 @@ TEST_F(CueControlTest, SeekOnLoadIntroCue) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::MANUAL); + pIntro->setSource(Cue::Source::Manual); pIntro->setPosition(200.0); loadTrack(pTrack); @@ -410,7 +410,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pCue->getLength()); - EXPECT_DOUBLE_EQ(Cue::MANUAL, pCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Set intro end cue @@ -427,7 +427,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(400.0, pCue->getLength()); - EXPECT_DOUBLE_EQ(Cue::MANUAL, pCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear intro start cue @@ -443,7 +443,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(500.0, pCue->getLength()); - EXPECT_DOUBLE_EQ(Cue::MANUAL, pCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear intro end cue @@ -474,7 +474,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pCue->getLength()); - EXPECT_DOUBLE_EQ(Cue::MANUAL, pCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Set outro end cue @@ -491,7 +491,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(250.0, pCue->getLength()); - EXPECT_DOUBLE_EQ(Cue::MANUAL, pCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear outro start cue @@ -507,7 +507,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(1000.0, pCue->getLength()); - EXPECT_DOUBLE_EQ(Cue::MANUAL, pCue->getSource()); + EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear outro end cue diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 3110634c85c..14ddf3a4011 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -23,7 +23,7 @@ Cue::Cue(TrackId trackId) : m_bDirty(false), m_iId(-1), m_trackId(trackId), - m_source(UNKNOWN), + m_source(Cue::Source::Unknown), m_type(Cue::Type::Invalid), m_samplePosition(-1.0), m_length(0.0), @@ -33,7 +33,7 @@ Cue::Cue(TrackId trackId) DEBUG_ASSERT(!m_label.isNull()); } -Cue::Cue(int id, TrackId trackId, Cue::CueSource source, Cue::Type type, double position, double length, +Cue::Cue(int id, TrackId trackId, Cue::Source source, Cue::Type type, double position, double length, int hotCue, QString label, PredefinedColorPointer color) : m_bDirty(false), m_iId(id), @@ -74,12 +74,12 @@ void Cue::setTrackId(TrackId trackId) { emit(updated()); } -Cue::CueSource Cue::getSource() const { +Cue::Source Cue::getSource() const { QMutexLocker lock(&m_mutex); return m_source; } -void Cue::setSource(CueSource source) { +void Cue::setSource(Cue::Source source) { QMutexLocker lock(&m_mutex); m_source = source; m_bDirty = true; diff --git a/src/track/cue.h b/src/track/cue.h index df7603f091a..4acd0de0516 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -17,10 +17,10 @@ class Cue : public QObject { Q_OBJECT public: - enum CueSource { - UNKNOWN = 0, - AUTOMATIC = 1, - MANUAL = 2, + enum class Source { + Unknown = 0, + Automatic = 1, + Manual = 2, }; enum class Type { @@ -40,8 +40,8 @@ class Cue : public QObject { int getId() const; TrackId getTrackId() const; - CueSource getSource() const; - void setSource(CueSource source); + Cue::Source getSource() const; + void setSource(Cue::Source source); Cue::Type getType() const; void setType(Cue::Type type); @@ -68,7 +68,7 @@ class Cue : public QObject { private: explicit Cue(TrackId trackId); - Cue(int id, TrackId trackId, CueSource source, Cue::Type type, double position, double length, + Cue(int id, TrackId trackId, Cue::Source source, Cue::Type type, double position, double length, int hotCue, QString label, PredefinedColorPointer color); void setDirty(bool dirty); void setId(int id); @@ -79,7 +79,7 @@ class Cue : public QObject { bool m_bDirty; int m_iId; TrackId m_trackId; - CueSource m_source; + Cue::Source m_source; Cue::Type m_type; double m_samplePosition; double m_length; @@ -105,8 +105,8 @@ class CuePointer: public std::shared_ptr { class CuePosition { public: CuePosition() - : m_position(0.0), m_source(Cue::UNKNOWN) {} - CuePosition(double position, Cue::CueSource source) + : m_position(0.0), m_source(Cue::Source::Unknown) {} + CuePosition(double position, Cue::Source source) : m_position(position), m_source(source) {} double getPosition() const { @@ -117,27 +117,27 @@ class CuePosition { m_position = position; } - Cue::CueSource getSource() const { + Cue::Source getSource() const { return m_source; } - void setSource(Cue::CueSource source) { + void setSource(Cue::Source source) { m_source = source; } - void set(double position, Cue::CueSource source) { + void set(double position, Cue::Source source) { m_position = position; m_source = source; } void reset() { m_position = 0.0; - m_source = Cue::UNKNOWN; + m_source = Cue::Source::Unknown; } private: double m_position; - Cue::CueSource m_source; + Cue::Source m_source; }; bool operator==(const CuePosition& lhs, const CuePosition& rhs); @@ -149,7 +149,7 @@ bool operator!=(const CuePosition& lhs, const CuePosition& rhs) { inline QDebug operator<<(QDebug dbg, const CuePosition& arg) { - return dbg << "position =" << arg.getPosition() << "/" << "source =" << arg.getSource(); + return dbg << "position =" << arg.getPosition() << "/" << "source =" << static_cast(arg.getSource()); } #endif // MIXXX_CUE_H diff --git a/src/track/track.cpp b/src/track/track.cpp index d5e21e7137d..8e4d0698827 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -733,7 +733,7 @@ void Track::setCuePoint(CuePosition cue) { // Store the cue point in a load cue CuePointer pLoadCue = findCueByType(Cue::Type::MainCue); - Cue::CueSource source = cue.getSource(); + Cue::Source source = cue.getSource(); double position = cue.getPosition(); if (position != 0.0 && position != -1.0) { if (!pLoadCue) { From bad1178038091b95012b5207906aac1b42f60bb2 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 11:53:22 -0500 Subject: [PATCH 008/198] rename tio -> pTrack in AnalyzerSilence "tio" was a legacy name for TrackInfoObject, which is now just Track --- src/analyzer/analyzersilence.cpp | 30 +++++++++++++++--------------- src/analyzer/analyzersilence.h | 10 +++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index f952151eba8..d5c18da884d 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -20,7 +20,7 @@ AnalyzerSilence::AnalyzerSilence(UserSettingsPointer pConfig) m_iSignalEnd(-1) { } -bool AnalyzerSilence::initialize(TrackPointer tio, int sampleRate, int totalSamples) { +bool AnalyzerSilence::initialize(TrackPointer pTrack, int sampleRate, int totalSamples) { Q_UNUSED(sampleRate); Q_UNUSED(totalSamples); @@ -29,20 +29,20 @@ bool AnalyzerSilence::initialize(TrackPointer tio, int sampleRate, int totalSamp m_iSignalStart = -1; m_iSignalEnd = -1; - return !isDisabledOrLoadStoredSuccess(tio); + return !isDisabledOrLoadStoredSuccess(pTrack); } -bool AnalyzerSilence::isDisabledOrLoadStoredSuccess(TrackPointer tio) const { - if (!shouldUpdateCue(tio->getCuePoint())) { +bool AnalyzerSilence::isDisabledOrLoadStoredSuccess(TrackPointer pTrack) const { + if (!shouldUpdateCue(pTrack->getCuePoint())) { return false; } - CuePointer pIntroCue = tio->findCueByType(Cue::Type::Intro); + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); if (!pIntroCue || pIntroCue->getSource() != Cue::Source::Manual) { return false; } - CuePointer pOutroCue = tio->findCueByType(Cue::Type::Outro); + CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); if (!pOutroCue || pOutroCue->getSource() != Cue::Source::Manual) { return false; } @@ -75,11 +75,11 @@ void AnalyzerSilence::process(const CSAMPLE* pIn, const int iLen) { m_iFramesProcessed += iLen / mixxx::kAnalysisChannels; } -void AnalyzerSilence::cleanup(TrackPointer tio) { - Q_UNUSED(tio); +void AnalyzerSilence::cleanup(TrackPointer pTrack) { + Q_UNUSED(pTrack); } -void AnalyzerSilence::finalize(TrackPointer tio) { +void AnalyzerSilence::finalize(TrackPointer pTrack) { if (m_iSignalStart < 0) { m_iSignalStart = 0; } @@ -93,13 +93,13 @@ void AnalyzerSilence::finalize(TrackPointer tio) { m_iSignalEnd = m_iFramesProcessed; } - if (shouldUpdateCue(tio->getCuePoint())) { - tio->setCuePoint(CuePosition(mixxx::kAnalysisChannels * m_iSignalStart, Cue::Source::Automatic)); + if (shouldUpdateCue(pTrack->getCuePoint())) { + pTrack->setCuePoint(CuePosition(mixxx::kAnalysisChannels * m_iSignalStart, Cue::Source::Automatic)); } - CuePointer pIntroCue = tio->findCueByType(Cue::Type::Intro); + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); if (!pIntroCue) { - pIntroCue = tio->createAndAddCue(); + pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); pIntroCue->setSource(Cue::Source::Automatic); pIntroCue->setPosition(mixxx::kAnalysisChannels * m_iSignalStart); @@ -109,9 +109,9 @@ void AnalyzerSilence::finalize(TrackPointer tio) { pIntroCue->setLength(0.0); } - CuePointer pOutroCue = tio->findCueByType(Cue::Type::Outro); + CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); if (!pOutroCue) { - pOutroCue = tio->createAndAddCue(); + pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); pOutroCue->setSource(Cue::Source::Automatic); pOutroCue->setPosition(-1.0); diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index b18aa5460b3..a71bb4a8f10 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -11,14 +11,14 @@ class AnalyzerSilence : public Analyzer { explicit AnalyzerSilence(UserSettingsPointer pConfig); ~AnalyzerSilence() override = default; - bool initialize(TrackPointer tio, int sampleRate, int totalSamples) override; - bool isDisabledOrLoadStoredSuccess(TrackPointer tio) const override; + bool initialize(TrackPointer pTrack, int sampleRate, int totalSamples) override; + bool isDisabledOrLoadStoredSuccess(TrackPointer pTrack) const override; void process(const CSAMPLE* pIn, const int iLen) override; - void finalize(TrackPointer tio) override; - void cleanup(TrackPointer tio) override; + void finalize(TrackPointer pTrack) override; + void cleanup(TrackPointer pTrack) override; private: - static bool shouldUpdateCue(CuePosition cuePosition); + static bool shouldUpdateCue(CuePosition cuePosipTrackn); UserSettingsPointer m_pConfig; float m_fThreshold; From 648aaa7fd8f6f21995a6d9569a882469f38478b2 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 14:22:47 -0500 Subject: [PATCH 009/198] add new FirstSound/LastSound cues separate from Intro/Outro This will allow for adding a new AutoDJ fade mode that skips silence regardless of where the intro/outro markers are. --- src/analyzer/analyzersilence.cpp | 32 ++++++++++++++++++++++++++++++ src/engine/controls/cuecontrol.cpp | 9 +++++++++ src/engine/controls/cuecontrol.h | 5 +++-- src/track/cue.h | 2 ++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index d5c18da884d..b6efb72d226 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -37,6 +37,16 @@ bool AnalyzerSilence::isDisabledOrLoadStoredSuccess(TrackPointer pTrack) const { return false; } + CuePointer pFirstSound = pTrack->findCueByType(Cue::Type::FirstSound); + if (!pFirstSound || pFirstSound->getSource() != Cue::Source::Manual) { + return false; + } + + CuePointer pLastSound = pTrack->findCueByType(Cue::Type::LastSound); + if (!pLastSound || pLastSound->getSource() != Cue::Source::Manual) { + return false; + } + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); if (!pIntroCue || pIntroCue->getSource() != Cue::Source::Manual) { return false; @@ -97,6 +107,28 @@ void AnalyzerSilence::finalize(TrackPointer pTrack) { pTrack->setCuePoint(CuePosition(mixxx::kAnalysisChannels * m_iSignalStart, Cue::Source::Automatic)); } + CuePointer pFirstSound = pTrack->findCueByType(Cue::Type::FirstSound); + if (pFirstSound == nullptr) { + qDebug() << "AnalyzerSilence placing FirstSound cue for" << pTrack.get(); + pFirstSound = pTrack->createAndAddCue(); + pFirstSound->setType(Cue::Type::FirstSound); + pFirstSound->setSource(Cue::Source::Automatic); + pFirstSound->setPosition(mixxx::kAnalysisChannels * m_iSignalStart); + } else if (pFirstSound->getSource() != Cue::Source::Manual) { + pFirstSound->setPosition(mixxx::kAnalysisChannels * m_iSignalStart); + } + + CuePointer pLastSound = pTrack->findCueByType(Cue::Type::LastSound); + if (pLastSound == nullptr) { + qDebug() << "AnalyzerSilence placing LastSound cue for" << pTrack.get(); + pLastSound = pTrack->createAndAddCue(); + pLastSound->setType(Cue::Type::LastSound); + pLastSound->setSource(Cue::Source::Automatic); + pLastSound->setPosition(mixxx::kAnalysisChannels * m_iSignalEnd); + } else if (pLastSound->getSource() != Cue::Source::Manual) { + pLastSound->setPosition(mixxx::kAnalysisChannels * m_iSignalEnd); + } + CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); if (!pIntroCue) { pIntroCue = pTrack->createAndAddCue(); diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 44a1fac2d1e..23a117686b2 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -353,6 +353,8 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { if (seekOnLoadMode == SeekOnLoadMode::UsePreference) { seekOnLoadMode = getSeekOnLoadPreference(); } + + CuePointer pFirstSound = m_pLoadedTrack->findCueByType(Cue::Type::FirstSound); switch (seekOnLoadMode) { case SeekOnLoadMode::Beginning: // This allows users to load tracks and have the needle-drop be maintained. @@ -361,6 +363,13 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { seekExact(0.0); } break; + case SeekOnLoadMode::FirstSound: + if (pFirstSound) { + seekExact(pFirstSound->getPosition()); + } else { + seekExact(0.0); + } + break; case SeekOnLoadMode::MainCue: seekExact(m_pCuePoint->get()); break; diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 3e1f93c51b0..1fd7dee1be4 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -23,8 +23,9 @@ class ControlIndicator; enum class SeekOnLoadMode { MainCue = 0, // Use main cue point Beginning = 1, // Use 0:00.000 - IntroStart = 2, // Use intro start cue point - UsePreference = 3, // Use CueRecall preference setting + FirstSound = 2, // Skip leading silence + IntroStart = 3, // Use intro start cue point + UsePreference = 4, // Use CueRecall preference setting }; inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { diff --git a/src/track/cue.h b/src/track/cue.h index 4acd0de0516..95bbbe58227 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -32,6 +32,8 @@ class Cue : public QObject { Jump = 5, Intro = 6, Outro = 7, + FirstSound = 8, // not shown to user + LastSound = 9, // not shown to user }; ~Cue() override = default; From 6532bd7d7e61802ad1953203cf30c5e90c252e3f Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 14:23:45 -0500 Subject: [PATCH 010/198] add new AutoDJ mode that skips silence with fixed fade time also some renaming and refactoring --- src/library/autodj/autodjprocessor.cpp | 84 ++++++++++++++++---------- src/library/autodj/autodjprocessor.h | 17 +++--- src/library/autodj/dlgautodj.cpp | 14 +++-- 3 files changed, 70 insertions(+), 45 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index dac56c9108f..7b51b7a6078 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -158,8 +158,8 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, int configMode = m_pConfig->getValue( ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), - static_cast(IntroOutroUsage::Shorter)); - m_useIntroOutroMode = static_cast(configMode); + static_cast(TransitionMode::IntroOutroShorter)); + m_transitionMode = static_cast(configMode); } AutoDJProcessor::~AutoDJProcessor() { @@ -333,9 +333,12 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ enabled"; - if (m_useIntroOutroMode == IntroOutroUsage::None) { + if (m_transitionMode == TransitionMode::FixedFullTrack) { deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); + } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); } else { deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); @@ -802,39 +805,37 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double } double AutoDJProcessor::getIntroStartPosition(DeckAttributes* pDeck) { - double position = pDeck->introStartPosition() / kChannelCount; - double samplerate = pDeck->sampleRate(); - if (position <= 0.0 || samplerate <= 0.0) { - return -1.0; - } - return position / samplerate; // Convert to seconds + return samplePositionToSeconds(pDeck->introStartPosition(), pDeck); } double AutoDJProcessor::getIntroEndPosition(DeckAttributes* pDeck) { - double position = pDeck->introEndPosition() / kChannelCount; - double samplerate = pDeck->sampleRate(); - if (position <= 0.0 || samplerate <= 0.0) { - return -1.0; - } - return position / samplerate; // Convert to seconds + return samplePositionToSeconds(pDeck->introEndPosition(), pDeck); } double AutoDJProcessor::getOutroStartPosition(DeckAttributes* pDeck) { - double position = pDeck->outroStartPosition() / kChannelCount; - double samplerate = pDeck->sampleRate(); - if (position <= 0.0 || samplerate <= 0.0) { - return -1.0; - } - return position / samplerate; // Convert to seconds + return samplePositionToSeconds(pDeck->outroStartPosition(), pDeck); } double AutoDJProcessor::getOutroEndPosition(DeckAttributes* pDeck) { - double position = pDeck->outroEndPosition() / kChannelCount; - double samplerate = pDeck->sampleRate(); - if (position <= 0.0 || samplerate <= 0.0) { + return samplePositionToSeconds(pDeck->outroEndPosition(), pDeck); +} + +double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { + CuePointer pFromTrackLastSound = pDeck->getLoadedTrack()->findCueByType(Cue::Type::LastSound); + if (pFromTrackLastSound) { + return samplePositionToSeconds(pFromTrackLastSound->getPosition(), pDeck); + } else { + return pDeck->duration(); + } +} + +double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck) { + samplePosition /= kChannelCount; + double sampleRate = pDeck->sampleRate(); + if (samplePosition <= 0.0 || sampleRate <= 0.0) { return -1.0; } - return position / samplerate; // Convert to seconds + return samplePosition / sampleRate; } void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, @@ -882,19 +883,20 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double toTrackIntroLength = toTrackIntroEnd - toTrackIntroStart; - if (m_useIntroOutroMode != IntroOutroUsage::None) { + if (m_transitionMode == TransitionMode::IntroOutroLonger + || m_transitionMode == TransitionMode::IntroOutroShorter) { if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { if (fromTrackOutroLength > toTrackIntroLength) { - if (m_useIntroOutroMode == IntroOutroUsage::Longer) { + if (m_transitionMode == TransitionMode::IntroOutroLonger) { useOutroFadeTime(pFromDeck, fromTrackOutroStart, fromTrackOutroLength, toTrackDuration); - } else if (m_useIntroOutroMode == IntroOutroUsage::Shorter) { + } else if (m_transitionMode == TransitionMode::IntroOutroShorter) { useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); } } else if (fromTrackOutroLength < toTrackIntroLength) { - if (m_useIntroOutroMode == IntroOutroUsage::Longer) { + if (m_transitionMode == TransitionMode::IntroOutroLonger) { useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); - } else if (m_useIntroOutroMode == IntroOutroUsage::Shorter) { + } else if (m_transitionMode == TransitionMode::IntroOutroShorter) { useOutroFadeTime(pFromDeck, fromTrackOutroStart, fromTrackOutroLength, toTrackDuration); } @@ -918,6 +920,21 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = toTrackIntroStart + transitionTime; } } + } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { + double fromTrackEndPoint = getLastSoundPosition(pFromDeck); + double transitionTime = m_transitionTime; + if (m_transitionTime > toTrackDuration) { + transitionTime = toTrackDuration; + } + if (transitionTime > 0.0) { + pFromDeck->posThreshold = fromTrackEndPoint - transitionTime; + pFromDeck->fadeDuration = transitionTime; + } else { + pFromDeck->posThreshold = fromTrackEndPoint; + pFromDeck->fadeDuration = transitionTime; + // Setting this is only required for negative transition times + pToDeck->startPos = transitionTime; + } } else { double transitionTime = m_transitionTime; if (m_transitionTime > toTrackDuration) { @@ -1061,16 +1078,19 @@ void AutoDJProcessor::setTransitionTime(int time) { void AutoDJProcessor::setUseIntroOutro(int checkboxState) { m_pConfig->set(ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), ConfigValue(checkboxState)); - m_useIntroOutroMode = static_cast(checkboxState); + m_transitionMode = static_cast(checkboxState); // Then re-calculate fade thresholds for the decks. if (m_eState == ADJ_IDLE) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; - if (m_useIntroOutroMode == IntroOutroUsage::None) { + if (m_transitionMode == TransitionMode::FixedFullTrack) { leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); + } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { + leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); + rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); } else { leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 325a2e63481..7eebf1c0f7d 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -162,10 +162,11 @@ class AutoDJProcessor : public QObject { ADJ_NOT_TWO_DECKS }; - enum class IntroOutroUsage { - None = 0, - Shorter = 1, - Longer = 2 + enum class TransitionMode { + FixedFullTrack = 0, + FixedSkipSilence = 1, + IntroOutroShorter = 2, + IntroOutroLonger = 3, }; AutoDJProcessor(QObject* pParent, @@ -183,8 +184,8 @@ class AutoDJProcessor : public QObject { return m_transitionTime; } - IntroOutroUsage getUseIntroOutro() const { - return m_useIntroOutroMode; + TransitionMode getUseIntroOutro() const { + return m_transitionMode; } PlaylistTableModel* getTableModel() const { @@ -249,6 +250,8 @@ class AutoDJProcessor : public QObject { double getIntroEndPosition(DeckAttributes* pDeck); double getOutroStartPosition(DeckAttributes* pDeck); double getOutroEndPosition(DeckAttributes* pDeck); + double getLastSoundPosition(DeckAttributes* pDeck); + double samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck); TrackPointer getNextTrackFromQueue(); bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); @@ -275,7 +278,7 @@ class AutoDJProcessor : public QObject { AutoDJState m_eState; double m_transitionTime; // the desired value set by the user - IntroOutroUsage m_useIntroOutroMode; + TransitionMode m_transitionMode; QList m_decks; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 3c57bad8b74..861a559a6e2 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -74,12 +74,14 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); - introOutroCombobox->addItem(tr("Do not use intro/outro markers"), - static_cast(AutoDJProcessor::IntroOutroUsage::None)); - introOutroCombobox->addItem(tr("Use intro/outro for transition time (whichever is shorter)"), - static_cast(AutoDJProcessor::IntroOutroUsage::Shorter)); - introOutroCombobox->addItem(tr("Use intro/outro for transition time (whichever is longer)"), - static_cast(AutoDJProcessor::IntroOutroUsage::Longer)); + introOutroCombobox->addItem(tr("Fixed time (full track)"), + static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); + introOutroCombobox->addItem(tr("Fixed time (skip silence)"), + static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); + introOutroCombobox->addItem(tr("Intro/outro (shorter)"), + static_cast(AutoDJProcessor::TransitionMode::IntroOutroShorter)); + introOutroCombobox->addItem(tr("Intro/outro (longer)"), + static_cast(AutoDJProcessor::TransitionMode::IntroOutroLonger)); introOutroCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getUseIntroOutro())); connect(introOutroCombobox, QOverload::of(&QComboBox::currentIndexChanged), m_pAutoDJProcessor, &AutoDJProcessor::setUseIntroOutro); From 3e11cf5798df31dad0177e56dc33ece881130e68 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 15:07:04 -0500 Subject: [PATCH 011/198] add "Fade mode" label to DlgAutoDJ --- src/library/autodj/dlgautodj.ui | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index 8ba416aed0e..9774a144e94 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -138,6 +138,13 @@ If no track sources are configured, the track is added from the library instead. + + + + Fade mode: + + + From 45f68e485e76f1b3b8bbbc79244bfb24d1279d96 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 15:08:02 -0500 Subject: [PATCH 012/198] add AutoDJ mode to start at cue point with fixed fade time --- src/library/autodj/autodjprocessor.cpp | 134 ++++++++++++++----------- src/library/autodj/autodjprocessor.h | 10 +- src/library/autodj/dlgautodj.cpp | 2 + 3 files changed, 84 insertions(+), 62 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 7b51b7a6078..71845a00ce7 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -333,16 +333,7 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ enabled"; - if (m_transitionMode == TransitionMode::FixedFullTrack) { - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); - } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); - } else { - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); - } + setSeekOnLoadModeOverrideForTransitionMode(); connect(&deck1, &DeckAttributes::playPositionChanged, this, &AutoDJProcessor::playerPositionChanged); @@ -820,6 +811,15 @@ double AutoDJProcessor::getOutroEndPosition(DeckAttributes* pDeck) { return samplePositionToSeconds(pDeck->outroEndPosition(), pDeck); } +double AutoDJProcessor::getFirstSoundPosition(DeckAttributes* pDeck) { + CuePointer pFromTrackFirstSound = pDeck->getLoadedTrack()->findCueByType(Cue::Type::FirstSound); + if (pFromTrackFirstSound) { + return samplePositionToSeconds(pFromTrackFirstSound->getPosition(), pDeck); + } else { + return 0; + } +} + double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { CuePointer pFromTrackLastSound = pDeck->getLoadedTrack()->findCueByType(Cue::Type::LastSound); if (pFromTrackLastSound) { @@ -829,6 +829,16 @@ double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { } } +double AutoDJProcessor::getMainCuePosition(DeckAttributes* pDeck) { + CuePointer pMainCue = pDeck->getLoadedTrack()->findCueByType(Cue::Type::MainCue); + if (pMainCue) { + return samplePositionToSeconds(pMainCue->getPosition(), pDeck); + } else { + return 0; + } +} + + double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck) { samplePosition /= kChannelCount; double sampleRate = pDeck->sampleRate(); @@ -906,49 +916,15 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); } else { - double transitionTime = m_transitionTime; - if (m_transitionTime > toTrackDuration) { - transitionTime = toTrackDuration; - } - if (transitionTime >= 0) { - pFromDeck->posThreshold = fromTrackOutroEnd - transitionTime; - pFromDeck->fadeDuration = transitionTime; - } else { - pFromDeck->posThreshold = fromTrackOutroEnd; - pFromDeck->fadeDuration = transitionTime; - // Setting this is only required for negative transition times - pToDeck->startPos = toTrackIntroStart + transitionTime; - } + useFixedFadeTime(pFromDeck, pToDeck, fromTrackOutroEnd, toTrackIntroStart); } } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { - double fromTrackEndPoint = getLastSoundPosition(pFromDeck); - double transitionTime = m_transitionTime; - if (m_transitionTime > toTrackDuration) { - transitionTime = toTrackDuration; - } - if (transitionTime > 0.0) { - pFromDeck->posThreshold = fromTrackEndPoint - transitionTime; - pFromDeck->fadeDuration = transitionTime; - } else { - pFromDeck->posThreshold = fromTrackEndPoint; - pFromDeck->fadeDuration = transitionTime; - // Setting this is only required for negative transition times - pToDeck->startPos = transitionTime; - } + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); + } else if (m_transitionMode == TransitionMode::FixedLoadAtCue) { + useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, getMainCuePosition(pToDeck)); } else { - double transitionTime = m_transitionTime; - if (m_transitionTime > toTrackDuration) { - transitionTime = toTrackDuration; - } - if (transitionTime > 0.0) { - pFromDeck->posThreshold = fromTrackDuration - transitionTime; - pFromDeck->fadeDuration = transitionTime; - } else { - pFromDeck->posThreshold = fromTrackDuration; - pFromDeck->fadeDuration = transitionTime; - // Setting this is only required for negative transition times - pToDeck->startPos = transitionTime; - } + useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); } VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { @@ -981,6 +957,25 @@ void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, double fromTra pFromDeck->fadeDuration = toTrackIntroLength; } +void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, + double endPoint, double startPoint) { + double transitionTime = m_transitionTime; + double toTrackDuration = pToDeck->duration(); + if (m_transitionTime > toTrackDuration) { + transitionTime = toTrackDuration; + } + + if (transitionTime > 0.0) { + pFromDeck->posThreshold = endPoint - transitionTime; + pFromDeck->fadeDuration = transitionTime; + } else { + pFromDeck->posThreshold = endPoint; + pFromDeck->fadeDuration = transitionTime; + // Setting this is only required for negative transition times + pToDeck->startPos = startPoint + transitionTime; + } +} + void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTrack) { if (sDebug) { qDebug() << this << "playerTrackLoaded" << pDeck->group @@ -1085,16 +1080,7 @@ void AutoDJProcessor::setUseIntroOutro(int checkboxState) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; - if (m_transitionMode == TransitionMode::FixedFullTrack) { - leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); - rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); - } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { - leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); - rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); - } else { - leftDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); - rightDeck.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); - } + setSeekOnLoadModeOverrideForTransitionMode(); if (leftDeck.isPlaying()) { calculateTransition(&leftDeck, &rightDeck); @@ -1105,6 +1091,34 @@ void AutoDJProcessor::setUseIntroOutro(int checkboxState) { } } +void AutoDJProcessor::setSeekOnLoadModeOverrideForTransitionMode() { + DeckAttributes& deck1 = *m_decks[0]; + DeckAttributes& deck2 = *m_decks[1]; + switch (m_transitionMode) { + case TransitionMode::FixedFullTrack: + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); + break; + case TransitionMode::FixedSkipSilence: + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); + break; + case TransitionMode::FixedLoadAtCue: + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::MainCue); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::MainCue); + break; + case TransitionMode::IntroOutroShorter: + case TransitionMode::IntroOutroLonger: + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); + break; + default: + deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); + deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); + break; + } +} + DeckAttributes* AutoDJProcessor::getOtherDeck(DeckAttributes* pThisDeck, bool playing) { DeckAttributes* pOtherDeck = NULL; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 7eebf1c0f7d..58107573d1b 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -165,8 +165,9 @@ class AutoDJProcessor : public QObject { enum class TransitionMode { FixedFullTrack = 0, FixedSkipSilence = 1, - IntroOutroShorter = 2, - IntroOutroLonger = 3, + FixedLoadAtCue = 2, + IntroOutroShorter = 3, + IntroOutroLonger = 4, }; AutoDJProcessor(QObject* pParent, @@ -250,7 +251,9 @@ class AutoDJProcessor : public QObject { double getIntroEndPosition(DeckAttributes* pDeck); double getOutroStartPosition(DeckAttributes* pDeck); double getOutroEndPosition(DeckAttributes* pDeck); + double getFirstSoundPosition(DeckAttributes* pDeck); double getLastSoundPosition(DeckAttributes* pDeck); + double getMainCuePosition(DeckAttributes* pDeck); double samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck); TrackPointer getNextTrackFromQueue(); @@ -261,6 +264,9 @@ class AutoDJProcessor : public QObject { double fromTrackOutroLength, double toTrackDuration); void useIntroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroEnd, double toTrackIntroLength); + void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, + double endPoint, double startPoint); + void setSeekOnLoadModeOverrideForTransitionMode(); DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, bool playing = false); diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 861a559a6e2..d16a18ca88b 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -78,6 +78,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); introOutroCombobox->addItem(tr("Fixed time (skip silence)"), static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); + introOutroCombobox->addItem(tr("Fixed time (start at cue)"), + static_cast(AutoDJProcessor::TransitionMode::FixedLoadAtCue)); introOutroCombobox->addItem(tr("Intro/outro (shorter)"), static_cast(AutoDJProcessor::TransitionMode::IntroOutroShorter)); introOutroCombobox->addItem(tr("Intro/outro (longer)"), From 04b02f7feb1a250c43317d5043ad4efe6a6ec6da Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 15:11:37 -0500 Subject: [PATCH 013/198] rename introOutroCombobox -> fadeModeCombobox --- src/library/autodj/dlgautodj.cpp | 14 +++++++------- src/library/autodj/dlgautodj.ui | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index d16a18ca88b..be3c0637bde 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -74,18 +74,18 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); - introOutroCombobox->addItem(tr("Fixed time (full track)"), + fadeModeCombobox->addItem(tr("Fixed time (full track)"), static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); - introOutroCombobox->addItem(tr("Fixed time (skip silence)"), + fadeModeCombobox->addItem(tr("Fixed time (skip silence)"), static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); - introOutroCombobox->addItem(tr("Fixed time (start at cue)"), + fadeModeCombobox->addItem(tr("Fixed time (start at cue)"), static_cast(AutoDJProcessor::TransitionMode::FixedLoadAtCue)); - introOutroCombobox->addItem(tr("Intro/outro (shorter)"), + fadeModeCombobox->addItem(tr("Intro/outro (shorter)"), static_cast(AutoDJProcessor::TransitionMode::IntroOutroShorter)); - introOutroCombobox->addItem(tr("Intro/outro (longer)"), + fadeModeCombobox->addItem(tr("Intro/outro (longer)"), static_cast(AutoDJProcessor::TransitionMode::IntroOutroLonger)); - introOutroCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getUseIntroOutro())); - connect(introOutroCombobox, QOverload::of(&QComboBox::currentIndexChanged), + fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getUseIntroOutro())); + connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), m_pAutoDJProcessor, &AutoDJProcessor::setUseIntroOutro); // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index 9774a144e94..e6e43b761dd 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -146,7 +146,7 @@ If no track sources are configured, the track is added from the library instead. - + From b1a74b5d58d041692acc0c6ac15f6d48333a8462 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 17:30:02 -0500 Subject: [PATCH 014/198] AutoDJProcessor refactor useIntro/OutroFadeTime functions --- src/library/autodj/autodjprocessor.cpp | 38 ++++++++++++-------------- src/library/autodj/autodjprocessor.h | 6 ++-- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 71845a00ce7..f0a1e364824 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -898,23 +898,21 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { if (fromTrackOutroLength > toTrackIntroLength) { if (m_transitionMode == TransitionMode::IntroOutroLonger) { - useOutroFadeTime(pFromDeck, fromTrackOutroStart, - fromTrackOutroLength, toTrackDuration); + useOutroFadeTime(pFromDeck, pToDeck); } else if (m_transitionMode == TransitionMode::IntroOutroShorter) { - useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); + useIntroFadeTime(pFromDeck, pToDeck); } } else if (fromTrackOutroLength < toTrackIntroLength) { if (m_transitionMode == TransitionMode::IntroOutroLonger) { - useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); + useIntroFadeTime(pFromDeck, pToDeck); } else if (m_transitionMode == TransitionMode::IntroOutroShorter) { - useOutroFadeTime(pFromDeck, fromTrackOutroStart, - fromTrackOutroLength, toTrackDuration); + useOutroFadeTime(pFromDeck, pToDeck); } } } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { - useOutroFadeTime(pFromDeck, fromTrackOutroStart, fromTrackOutroLength, toTrackDuration); + useOutroFadeTime(pFromDeck, pToDeck); } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { - useIntroFadeTime(pFromDeck, fromTrackOutroEnd, toTrackIntroLength); + useIntroFadeTime(pFromDeck, pToDeck); } else { useFixedFadeTime(pFromDeck, pToDeck, fromTrackOutroEnd, toTrackIntroStart); } @@ -941,20 +939,20 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos /= toTrackDuration; } -void AutoDJProcessor::useOutroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroStart, - double fromTrackOutroLength, double toTrackDuration) { - pFromDeck->posThreshold = fromTrackOutroStart; - if (fromTrackOutroLength < toTrackDuration) { - pFromDeck->fadeDuration = fromTrackOutroLength; - } else { - pFromDeck->fadeDuration = toTrackDuration; - } +void AutoDJProcessor::useOutroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck) { + double outroStart = getOutroStartPosition(pFromDeck); + double outroEnd = getOutroEndPosition(pFromDeck); + pFromDeck->posThreshold = outroStart; + pFromDeck->fadeDuration = outroEnd - outroStart; } -void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroEnd, - double toTrackIntroLength) { - pFromDeck->posThreshold = fromTrackOutroEnd - toTrackIntroLength; - pFromDeck->fadeDuration = toTrackIntroLength; +void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck) { + double outroEnd = getOutroEndPosition(pFromDeck); + double introStart = getIntroStartPosition(pToDeck); + double introEnd = getIntroEndPosition(pToDeck); + double introLength = introEnd - introStart; + pFromDeck->posThreshold = outroEnd - introLength; + pFromDeck->fadeDuration = introLength; } void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 58107573d1b..29a845a0b62 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -260,10 +260,8 @@ class AutoDJProcessor : public QObject { bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); void calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); - void useOutroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroStart, - double fromTrackOutroLength, double toTrackDuration); - void useIntroFadeTime(DeckAttributes* pFromDeck, double fromTrackOutroEnd, - double toTrackIntroLength); + void useOutroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); + void useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); void setSeekOnLoadModeOverrideForTransitionMode(); From 1fa74b0e94e8cdb6f63bed9554f0a7ee7dc68cec Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 17:31:35 -0500 Subject: [PATCH 015/198] remove hacky message passing via CO from AutoDJProcessor to CueControl Now AutoDJProcessor is responsible for seeking in the incoming track. --- src/engine/controls/cuecontrol.cpp | 19 +------- src/engine/controls/cuecontrol.h | 5 -- src/library/autodj/autodjprocessor.cpp | 65 ++++---------------------- src/library/autodj/autodjprocessor.h | 11 ----- src/test/autodjprocessor_test.cpp | 5 -- src/test/cuecontrol_test.cpp | 21 --------- 6 files changed, 10 insertions(+), 116 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 23a117686b2..99c1f3329c1 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -56,10 +56,6 @@ CueControl::CueControl(QString group, m_pCueMode = new ControlObject(ConfigKey(group, "cue_mode")); - m_pSeekOnLoadModeAutoDjOverride = new ControlObject(ConfigKey(group, "seekonload_mode_autodj")); - m_pSeekOnLoadModeAutoDjOverride->set(static_cast( - static_cast(SeekOnLoadMode::UsePreference))); - m_pCueSet = new ControlPushButton(ConfigKey(group, "cue_set")); m_pCueSet->setButtonMode(ControlPushButton::TRIGGER); connect(m_pCueSet, &ControlObject::valueChanged, @@ -209,7 +205,6 @@ CueControl::CueControl(QString group, CueControl::~CueControl() { delete m_pCuePoint; delete m_pCueMode; - delete m_pSeekOnLoadModeAutoDjOverride; delete m_pCueSet; delete m_pCueClear; delete m_pCueGoto; @@ -349,10 +344,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { loadCuesFromTrack(); // Seek track according to SeekOnLoadMode. - SeekOnLoadMode seekOnLoadMode = getSeekOnLoadModeAutoDjOverride(); - if (seekOnLoadMode == SeekOnLoadMode::UsePreference) { - seekOnLoadMode = getSeekOnLoadPreference(); - } + SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); CuePointer pFirstSound = m_pLoadedTrack->findCueByType(Cue::Type::FirstSound); switch (seekOnLoadMode) { @@ -499,10 +491,7 @@ void CueControl::reloadCuesFromTrack() { double intro = m_pIntroStartPosition->get(); // Make track follow the updated cues. - SeekOnLoadMode seekOnLoadMode = getSeekOnLoadModeAutoDjOverride(); - if (seekOnLoadMode == SeekOnLoadMode::UsePreference) { - seekOnLoadMode = getSeekOnLoadPreference(); - } + SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); if (seekOnLoadMode == SeekOnLoadMode::MainCue) { if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != -1.0) { @@ -1645,10 +1634,6 @@ SeekOnLoadMode CueControl::getSeekOnLoadPreference() { return static_cast(configValue); } -SeekOnLoadMode CueControl::getSeekOnLoadModeAutoDjOverride() { - return seekOnLoadModeFromDouble(m_pSeekOnLoadModeAutoDjOverride->get()); -} - ConfigKey HotcueControl::keyForControl(int hotcue, const char* name) { ConfigKey key; diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 1fd7dee1be4..402b84c7556 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -18,14 +18,11 @@ class ControlObject; class ControlPushButton; class ControlIndicator; -// This enum class is shared between the preference option in DlgPrefDeck -// and AutoDJ's override of that option from AutoDJProcessor. enum class SeekOnLoadMode { MainCue = 0, // Use main cue point Beginning = 1, // Use 0:00.000 FirstSound = 2, // Skip leading silence IntroStart = 3, // Use intro start cue point - UsePreference = 4, // Use CueRecall preference setting }; inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { @@ -125,7 +122,6 @@ class CueControl : public EngineControl { bool getPlayFlashingAtPause(); SeekOnLoadMode getSeekOnLoadPreference(); void trackLoaded(TrackPointer pNewTrack) override; - SeekOnLoadMode getSeekOnLoadModeAutoDjOverride(); private slots: void quantizeChanged(double v); @@ -207,7 +203,6 @@ class CueControl : public EngineControl { ControlObject* m_pTrackSamples; ControlObject* m_pCuePoint; ControlObject* m_pCueMode; - ControlObject* m_pSeekOnLoadModeAutoDjOverride; ControlPushButton* m_pCueSet; ControlPushButton* m_pCueClear; ControlPushButton* m_pCueCDJ; diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index f0a1e364824..79ae472a6b1 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -28,7 +28,6 @@ DeckAttributes::DeckAttributes(int index, m_playPos(group, "playposition"), m_play(group, "play"), m_repeat(group, "repeat"), - m_seekOnLoadModeOverride(group, "seekonload_mode_autodj"), m_introStartPos(group, "intro_start_position"), m_introEndPos(group, "intro_end_position"), m_outroStartPos(group, "outro_start_position"), @@ -333,8 +332,6 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ enabled"; - setSeekOnLoadModeOverrideForTransitionMode(); - connect(&deck1, &DeckAttributes::playPositionChanged, this, &AutoDJProcessor::playerPositionChanged); connect(&deck2, &DeckAttributes::playPositionChanged, @@ -423,8 +420,6 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ disabled"; m_eState = ADJ_DISABLED; - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); deck1.disconnect(this); deck2.disconnect(this); m_pCOCrossfader->set(0); @@ -575,28 +570,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (m_eState == ADJ_IDLE && (thisDeckPlaying || thisDeck.posThreshold >= 1.0)) { if (!otherDeckPlaying) { - // Setup the other deck's fade thresholds (since we use the - // fadeDuration next). calculateTransition(&otherDeck, &thisDeck); - - // For negative fade durations, jump back to insert a pause - // between the tracks. - // Note: This overrides the cue position - if (thisFadeDuration < 0.0) { - // Note: startPos is computed in calculateTransition(). - otherDeck.setPlayPosition(otherDeck.startPos); - } else { - // Guard against very short other tracks, or CUE points and - // seeks near end of track. - // The other track must not be finished before this track, - // otherwise Auto-DJ stops - double otherDeckPlaypos = otherDeck.playPosition(); - // We need 2 x fadeDuration, to fade in and out - double maxPlaypos = 1.0 - (otherDeck.fadeDuration * 2); - if (maxPlaypos < otherDeckPlaypos) { - otherDeck.setPlayPosition(maxPlaypos); - } - } + otherDeck.setPlayPosition(otherDeck.startPos); otherDeck.play(); } @@ -933,6 +908,10 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = 0; } + if (pFromDeck->fadeDuration > toTrackDuration) { + pFromDeck->fadeDuration = toTrackDuration; + } + // These are expected to be a fraction of the track length. pFromDeck->posThreshold /= fromTrackDuration; pFromDeck->fadeDuration /= fromTrackDuration; @@ -944,6 +923,7 @@ void AutoDJProcessor::useOutroFadeTime(DeckAttributes* pFromDeck, DeckAttributes double outroEnd = getOutroEndPosition(pFromDeck); pFromDeck->posThreshold = outroStart; pFromDeck->fadeDuration = outroEnd - outroStart; + pToDeck->startPos = getIntroStartPosition(pToDeck); } void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck) { @@ -953,6 +933,7 @@ void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes double introLength = introEnd - introStart; pFromDeck->posThreshold = outroEnd - introLength; pFromDeck->fadeDuration = introLength; + pToDeck->startPos = introStart; } void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, @@ -966,10 +947,10 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes if (transitionTime > 0.0) { pFromDeck->posThreshold = endPoint - transitionTime; pFromDeck->fadeDuration = transitionTime; + pToDeck->startPos = startPoint; } else { pFromDeck->posThreshold = endPoint; pFromDeck->fadeDuration = transitionTime; - // Setting this is only required for negative transition times pToDeck->startPos = startPoint + transitionTime; } } @@ -1078,8 +1059,6 @@ void AutoDJProcessor::setUseIntroOutro(int checkboxState) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; - setSeekOnLoadModeOverrideForTransitionMode(); - if (leftDeck.isPlaying()) { calculateTransition(&leftDeck, &rightDeck); } @@ -1089,34 +1068,6 @@ void AutoDJProcessor::setUseIntroOutro(int checkboxState) { } } -void AutoDJProcessor::setSeekOnLoadModeOverrideForTransitionMode() { - DeckAttributes& deck1 = *m_decks[0]; - DeckAttributes& deck2 = *m_decks[1]; - switch (m_transitionMode) { - case TransitionMode::FixedFullTrack: - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::Beginning); - break; - case TransitionMode::FixedSkipSilence: - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::FirstSound); - break; - case TransitionMode::FixedLoadAtCue: - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::MainCue); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::MainCue); - break; - case TransitionMode::IntroOutroShorter: - case TransitionMode::IntroOutroLonger: - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::IntroStart); - break; - default: - deck1.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); - deck2.setSeekOnLoadModeOverride(SeekOnLoadMode::UsePreference); - break; - } -} - DeckAttributes* AutoDJProcessor::getOtherDeck(DeckAttributes* pThisDeck, bool playing) { DeckAttributes* pOtherDeck = NULL; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 29a845a0b62..bf5fd2e6fa2 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -62,15 +62,6 @@ class DeckAttributes : public QObject { m_repeat.set(enabled ? 1.0 : 0.0); } - SeekOnLoadMode seekOnLoadMode() const { - return seekOnLoadModeFromDouble(m_seekOnLoadModeOverride.get()); - } - - void setSeekOnLoadModeOverride(SeekOnLoadMode mode) { - m_seekOnLoadModeOverride.set(static_cast( - static_cast(mode))); - } - double introStartPosition() const { return m_introStartPos.get(); } @@ -131,7 +122,6 @@ class DeckAttributes : public QObject { ControlProxy m_playPos; ControlProxy m_play; ControlProxy m_repeat; - ControlProxy m_seekOnLoadModeOverride; ControlProxy m_introStartPos; ControlProxy m_introEndPos; ControlProxy m_outroStartPos; @@ -264,7 +254,6 @@ class AutoDJProcessor : public QObject { void useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); - void setSeekOnLoadModeOverrideForTransitionMode(); DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, bool playing = false); diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index ab7263cc2b1..1d2e3659c50 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -688,11 +688,6 @@ TEST_F(AutoDJProcessorTest, EnabledDisabledSuccess) { err = pProcessor->toggleAutoDJ(false); EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_DISABLED, pProcessor->getState()); - - // Restores decks 1 and 2 to respect CueRecall preference option when - // loading track. (This is default behaviour.) - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::UsePreference), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::UsePreference), deck2.seekOnLoadMode.get()); } TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 4d7dd138e9f..9e8b31fc5aa 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -263,9 +263,6 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { } TEST_F(CueControlTest, SeekOnLoadDefault) { - m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::UsePreference))); - TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); @@ -283,9 +280,6 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { } TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { - m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::UsePreference))); - TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(-100.0, Cue::Source::Manual)); @@ -303,9 +297,6 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { } TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { - m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::UsePreference))); - TrackPointer pTrack = createTestTrack(); loadTrack(pTrack); @@ -322,9 +313,6 @@ TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { } TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { - m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::UsePreference))); - // Note: CueRecall uses inverse logic (0 means enabled). config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(1)); @@ -338,9 +326,6 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { } TEST_F(CueControlTest, SeekOnLoadZeroPos) { - m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::Beginning))); - TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); @@ -351,9 +336,6 @@ TEST_F(CueControlTest, SeekOnLoadZeroPos) { } TEST_F(CueControlTest, SeekOnLoadMainCue) { - m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::MainCue))); - TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); @@ -371,9 +353,6 @@ TEST_F(CueControlTest, SeekOnLoadMainCue) { } TEST_F(CueControlTest, SeekOnLoadIntroCue) { - m_pSeekOnLoadMode->slotSet(static_cast( - static_cast(SeekOnLoadMode::IntroStart))); - TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); From eec6bad04d0d33f2360600abfdcd53918a62a5b6 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 17:40:35 -0500 Subject: [PATCH 016/198] AutoDJProcessor: seek on track load, not at transition This allows the user to seek to a different point before the transition starts (regardless of what mode AutoDJ is in). --- src/library/autodj/autodjprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 79ae472a6b1..18cb9bc8d2b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -571,7 +571,6 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, thisDeck.posThreshold >= 1.0)) { if (!otherDeckPlaying) { calculateTransition(&otherDeck, &thisDeck); - otherDeck.setPlayPosition(otherDeck.startPos); otherDeck.play(); } @@ -973,6 +972,7 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } else { calculateTransition(getOtherDeck(pDeck, true), pDeck); + pDeck->setPlayPosition(pDeck->startPos); } } From d3748e984f16b08902d1805a520c7025ba5c2ff7 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 17:56:51 -0500 Subject: [PATCH 017/198] update outdated function names --- src/library/autodj/autodjprocessor.cpp | 2 +- src/library/autodj/autodjprocessor.h | 4 ++-- src/library/autodj/dlgautodj.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 18cb9bc8d2b..e3d59203e9b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1049,7 +1049,7 @@ void AutoDJProcessor::setTransitionTime(int time) { } } -void AutoDJProcessor::setUseIntroOutro(int checkboxState) { +void AutoDJProcessor::setTransitionMode(int checkboxState) { m_pConfig->set(ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), ConfigValue(checkboxState)); m_transitionMode = static_cast(checkboxState); diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index bf5fd2e6fa2..d2d73bc3a54 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -175,7 +175,7 @@ class AutoDJProcessor : public QObject { return m_transitionTime; } - TransitionMode getUseIntroOutro() const { + TransitionMode getTransitionMode() const { return m_transitionMode; } @@ -188,7 +188,7 @@ class AutoDJProcessor : public QObject { public slots: void setTransitionTime(int seconds); - void setUseIntroOutro(int checkboxState); + void setTransitionMode(int checkboxState); AutoDJError shufflePlaylist(const QModelIndexList& selectedIndices); AutoDJError skipNext(); diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index be3c0637bde..48630c109d8 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -84,9 +84,9 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::IntroOutroShorter)); fadeModeCombobox->addItem(tr("Intro/outro (longer)"), static_cast(AutoDJProcessor::TransitionMode::IntroOutroLonger)); - fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getUseIntroOutro())); + fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), - m_pAutoDJProcessor, &AutoDJProcessor::setUseIntroOutro); + m_pAutoDJProcessor, &AutoDJProcessor::setTransitionMode); // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in // mind that AutoDJ may already be active when DlgAutoDJ is created (due to From bc78357fbac25362d995ddedb1904fb028818b78 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 17:58:57 -0500 Subject: [PATCH 018/198] seek to correct start point when changing AutoDJ mode --- src/library/autodj/autodjprocessor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index e3d59203e9b..2f798eb42a2 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1061,9 +1061,11 @@ void AutoDJProcessor::setTransitionMode(int checkboxState) { if (leftDeck.isPlaying()) { calculateTransition(&leftDeck, &rightDeck); + rightDeck.setPlayPosition(rightDeck.startPos); } if (rightDeck.isPlaying()) { calculateTransition(&rightDeck, &leftDeck); + leftDeck.setPlayPosition(leftDeck.startPos); } } } From caaff2d79405d235bbdf5a2fa2a23255c4384bd3 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 18:02:48 -0500 Subject: [PATCH 019/198] rename posThreshold -> fadeBeginPos --- src/library/autodj/autodjprocessor.cpp | 30 +++++++++++++------------- src/library/autodj/autodjprocessor.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2f798eb42a2..97b801be002 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -22,7 +22,7 @@ DeckAttributes::DeckAttributes(int index, EngineChannel::ChannelOrientation orientation) : index(index), group(pPlayer->getGroup()), - posThreshold(1.0), + fadeBeginPos(1.0), fadeDuration(0.0), m_orientation(orientation), m_playPos(group, "playposition"), @@ -230,7 +230,7 @@ void AutoDJProcessor::fadeNow() { calculateTransition(&leftDeck, &rightDeck); // override posThreshold to start fade now - leftDeck.posThreshold = leftDeck.playPosition() - + leftDeck.fadeBeginPos = leftDeck.playPosition() - ((crossfader + 1.0) / 2 * (leftDeck.fadeDuration)); // Repeat is disabled by FadeNow but disables auto Fade leftDeck.setRepeat(false); @@ -239,7 +239,7 @@ void AutoDJProcessor::fadeNow() { calculateTransition(&rightDeck, &leftDeck); // override posThreshold to start fade now - rightDeck.posThreshold = rightDeck.playPosition() - + rightDeck.fadeBeginPos = rightDeck.playPosition() - ((1.0 - crossfader) / 2 * (rightDeck.fadeDuration)); // Repeat is disabled by FadeNow but disables auto Fade rightDeck.setRepeat(false); @@ -545,7 +545,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // Invalidate threshold calculated for the old otherDeck // This avoids starting a fade back before the new track is // loaded into the otherDeck - thisDeck.posThreshold = 1.0; + thisDeck.fadeBeginPos = 1.0; thisDeck.fadeDuration = 0.0; // Load the next track to otherDeck. loadNextTrackFromQueue(otherDeck); @@ -566,9 +566,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // TODO(rryan): We need to investigate the chain of events that occur when // the track we are fading to crosses its posThreshold before we are done // fading to it. - if (thisPlayPosition >= thisDeck.posThreshold) { + if (thisPlayPosition >= thisDeck.fadeBeginPos) { if (m_eState == ADJ_IDLE && (thisDeckPlaying || - thisDeck.posThreshold >= 1.0)) { + thisDeck.fadeBeginPos >= 1.0)) { if (!otherDeckPlaying) { calculateTransition(&otherDeck, &thisDeck); otherDeck.play(); @@ -583,7 +583,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, emitAutoDJStateChanged(m_eState); } - double posFadeEnd = math_min(1.0, thisDeck.posThreshold + thisFadeDuration); + double posFadeEnd = math_min(1.0, thisDeck.fadeBeginPos + thisFadeDuration); if (thisPlayPosition >= posFadeEnd) { // If this track has passed the end of its target fade then we stop // it. We don't handle mode switches here since that's handled by @@ -599,8 +599,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // adjustment. If thisDeck is right, the new value is 1.0 minus the // adjustment. double crossfadeEdgeValue = -1.0; - double adjustment = 2 * (thisPlayPosition - thisDeck.posThreshold) / - (posFadeEnd - thisDeck.posThreshold); + double adjustment = 2 * (thisPlayPosition - thisDeck.fadeBeginPos) / + (posFadeEnd - thisDeck.fadeBeginPos); bool isLeft = thisDeck.isLeft(); if (!isLeft) { crossfadeEdgeValue = 1.0; @@ -900,7 +900,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { - pFromDeck->posThreshold = fromTrackDuration; + pFromDeck->fadeBeginPos = fromTrackDuration; pFromDeck->fadeDuration = 0; } VERIFY_OR_DEBUG_ASSERT(toTrackDuration > 0) { @@ -912,7 +912,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } // These are expected to be a fraction of the track length. - pFromDeck->posThreshold /= fromTrackDuration; + pFromDeck->fadeBeginPos /= fromTrackDuration; pFromDeck->fadeDuration /= fromTrackDuration; pToDeck->startPos /= toTrackDuration; } @@ -920,7 +920,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, void AutoDJProcessor::useOutroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck) { double outroStart = getOutroStartPosition(pFromDeck); double outroEnd = getOutroEndPosition(pFromDeck); - pFromDeck->posThreshold = outroStart; + pFromDeck->fadeBeginPos = outroStart; pFromDeck->fadeDuration = outroEnd - outroStart; pToDeck->startPos = getIntroStartPosition(pToDeck); } @@ -930,7 +930,7 @@ void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes double introStart = getIntroStartPosition(pToDeck); double introEnd = getIntroEndPosition(pToDeck); double introLength = introEnd - introStart; - pFromDeck->posThreshold = outroEnd - introLength; + pFromDeck->fadeBeginPos = outroEnd - introLength; pFromDeck->fadeDuration = introLength; pToDeck->startPos = introStart; } @@ -944,11 +944,11 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes } if (transitionTime > 0.0) { - pFromDeck->posThreshold = endPoint - transitionTime; + pFromDeck->fadeBeginPos = endPoint - transitionTime; pFromDeck->fadeDuration = transitionTime; pToDeck->startPos = startPoint; } else { - pFromDeck->posThreshold = endPoint; + pFromDeck->fadeBeginPos = endPoint; pFromDeck->fadeDuration = transitionTime; pToDeck->startPos = startPoint + transitionTime; } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index d2d73bc3a54..18a6a66d5aa 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -114,7 +114,7 @@ class DeckAttributes : public QObject { int index; QString group; double startPos; - double posThreshold; + double fadeBeginPos; double fadeDuration; private: From b02feb0b0f7b2a6a6352243e6f81ab1059591064 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 7 May 2019 23:16:01 -0500 Subject: [PATCH 020/198] AutoDJ: add align intro/outro start/end modes I'm not sure if the align ends mode is really helpful... --- src/library/autodj/autodjprocessor.cpp | 38 ++++++++++++++++++++++++++ src/library/autodj/autodjprocessor.h | 2 ++ src/library/autodj/dlgautodj.cpp | 4 +++ 3 files changed, 44 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 97b801be002..0b3745b9ba3 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -890,6 +890,44 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else { useFixedFadeTime(pFromDeck, pToDeck, fromTrackOutroEnd, toTrackIntroStart); } + } else if (m_transitionMode == TransitionMode::AlignIntroOutroStart) { + if (toTrackIntroStart > 0) { + pToDeck->startPos = toTrackIntroStart; + } else { + pToDeck->startPos = getFirstSoundPosition(pToDeck); + } + + if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { + pFromDeck->fadeBeginPos = fromTrackOutroStart; + pFromDeck->fadeDuration = math_min(fromTrackOutroLength, toTrackIntroLength); + } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { + pFromDeck->fadeBeginPos = fromTrackOutroStart; + pFromDeck->fadeDuration = fromTrackOutroLength; + } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { + pFromDeck->fadeBeginPos = fromTrackOutroEnd - toTrackIntroLength; + pFromDeck->fadeDuration = toTrackIntroLength; + } else { + useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), pToDeck->startPos); + } + } else if (m_transitionMode == TransitionMode::AlignIntroOutroEnd) { + if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { + if (fromTrackOutroLength < toTrackIntroLength) { + pFromDeck->fadeBeginPos = fromTrackOutroStart; + pFromDeck->fadeDuration = fromTrackOutroLength; + pToDeck->startPos = toTrackIntroEnd - fromTrackOutroLength; + } else { + pFromDeck->fadeBeginPos = fromTrackOutroEnd - toTrackIntroLength; + pFromDeck->fadeDuration = toTrackIntroLength; + pToDeck->startPos = toTrackIntroStart; + } + } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { + useOutroFadeTime(pFromDeck, pToDeck); + } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { + useIntroFadeTime(pFromDeck, pToDeck); + } else { + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); + } } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 18a6a66d5aa..3cf9ae34c16 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -158,6 +158,8 @@ class AutoDJProcessor : public QObject { FixedLoadAtCue = 2, IntroOutroShorter = 3, IntroOutroLonger = 4, + AlignIntroOutroStart = 5, + AlignIntroOutroEnd = 6, }; AutoDJProcessor(QObject* pParent, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 48630c109d8..10230a36223 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -84,6 +84,10 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::IntroOutroShorter)); fadeModeCombobox->addItem(tr("Intro/outro (longer)"), static_cast(AutoDJProcessor::TransitionMode::IntroOutroLonger)); + fadeModeCombobox->addItem(tr("Align intro + outro start"), + static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); + fadeModeCombobox->addItem(tr("Align intro + outro end"), + static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), m_pAutoDJProcessor, &AutoDJProcessor::setTransitionMode); From c7cbebd77fe16f186acadd4e7113e928f3f861fe Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 09:49:34 -0500 Subject: [PATCH 021/198] remove debug messages --- src/analyzer/analyzersilence.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index b6efb72d226..c9da8f06daa 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -109,7 +109,6 @@ void AnalyzerSilence::finalize(TrackPointer pTrack) { CuePointer pFirstSound = pTrack->findCueByType(Cue::Type::FirstSound); if (pFirstSound == nullptr) { - qDebug() << "AnalyzerSilence placing FirstSound cue for" << pTrack.get(); pFirstSound = pTrack->createAndAddCue(); pFirstSound->setType(Cue::Type::FirstSound); pFirstSound->setSource(Cue::Source::Automatic); @@ -120,7 +119,6 @@ void AnalyzerSilence::finalize(TrackPointer pTrack) { CuePointer pLastSound = pTrack->findCueByType(Cue::Type::LastSound); if (pLastSound == nullptr) { - qDebug() << "AnalyzerSilence placing LastSound cue for" << pTrack.get(); pLastSound = pTrack->createAndAddCue(); pLastSound->setType(Cue::Type::LastSound); pLastSound->setSource(Cue::Source::Automatic); From 8a6dc26304f73f3427c1252514d062094f0632c9 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 09:56:52 -0500 Subject: [PATCH 022/198] change name of new ConfigKey to better match its function --- src/library/autodj/autodjprocessor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 0b3745b9ba3..2c682770d59 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -10,7 +10,7 @@ #define kConfigKey "[Auto DJ]" const char* kTransitionPreferenceName = "Transition"; -const char* kUseIntroOutroPreferenceName = "UseIntroOutroMarkers"; +const char* kTransitionModePreferenceName = "TransitionMode"; const double kTransitionPreferenceDefault = 10.0; const mixxx::AudioSignal::ChannelCount kChannelCount = mixxx::kEngineChannelCount; @@ -156,7 +156,7 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, } int configMode = m_pConfig->getValue( - ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), + ConfigKey(kConfigKey, kTransitionModePreferenceName), static_cast(TransitionMode::IntroOutroShorter)); m_transitionMode = static_cast(configMode); } @@ -1088,7 +1088,7 @@ void AutoDJProcessor::setTransitionTime(int time) { } void AutoDJProcessor::setTransitionMode(int checkboxState) { - m_pConfig->set(ConfigKey(kConfigKey, kUseIntroOutroPreferenceName), + m_pConfig->set(ConfigKey(kConfigKey, kTransitionModePreferenceName), ConfigValue(checkboxState)); m_transitionMode = static_cast(checkboxState); From 3971e4a61f84ab69ac36a4da6892bb349dd89d94 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 10:01:46 -0500 Subject: [PATCH 023/198] change default transition mode to align intro + outro start --- src/library/autodj/autodjprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2c682770d59..89c641fe039 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -157,7 +157,7 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, int configMode = m_pConfig->getValue( ConfigKey(kConfigKey, kTransitionModePreferenceName), - static_cast(TransitionMode::IntroOutroShorter)); + static_cast(TransitionMode::AlignIntroOutroStart)); m_transitionMode = static_cast(configMode); } From adb4b148aa8fa68996fa874b2298ef7071888c8f Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 10:26:11 -0500 Subject: [PATCH 024/198] AutoDJ: remove "Intro/outro" transition modes These modes are not intuitive to explain or use. --- src/library/autodj/autodjprocessor.cpp | 51 ++++---------------------- src/library/autodj/autodjprocessor.h | 8 +--- src/library/autodj/dlgautodj.cpp | 4 -- 3 files changed, 9 insertions(+), 54 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 89c641fe039..b689740a935 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -867,30 +867,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double toTrackIntroLength = toTrackIntroEnd - toTrackIntroStart; - if (m_transitionMode == TransitionMode::IntroOutroLonger - || m_transitionMode == TransitionMode::IntroOutroShorter) { - if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { - if (fromTrackOutroLength > toTrackIntroLength) { - if (m_transitionMode == TransitionMode::IntroOutroLonger) { - useOutroFadeTime(pFromDeck, pToDeck); - } else if (m_transitionMode == TransitionMode::IntroOutroShorter) { - useIntroFadeTime(pFromDeck, pToDeck); - } - } else if (fromTrackOutroLength < toTrackIntroLength) { - if (m_transitionMode == TransitionMode::IntroOutroLonger) { - useIntroFadeTime(pFromDeck, pToDeck); - } else if (m_transitionMode == TransitionMode::IntroOutroShorter) { - useOutroFadeTime(pFromDeck, pToDeck); - } - } - } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { - useOutroFadeTime(pFromDeck, pToDeck); - } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { - useIntroFadeTime(pFromDeck, pToDeck); - } else { - useFixedFadeTime(pFromDeck, pToDeck, fromTrackOutroEnd, toTrackIntroStart); - } - } else if (m_transitionMode == TransitionMode::AlignIntroOutroStart) { + if (m_transitionMode == TransitionMode::AlignIntroOutroStart) { if (toTrackIntroStart > 0) { pToDeck->startPos = toTrackIntroStart; } else { @@ -921,9 +898,13 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = toTrackIntroStart; } } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { - useOutroFadeTime(pFromDeck, pToDeck); + pFromDeck->fadeBeginPos = fromTrackOutroStart; + pFromDeck->fadeDuration = fromTrackOutroEnd - fromTrackOutroStart; + pToDeck->startPos = getIntroStartPosition(pToDeck); } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { - useIntroFadeTime(pFromDeck, pToDeck); + pFromDeck->fadeBeginPos = fromTrackOutroEnd - toTrackIntroLength; + pFromDeck->fadeDuration = toTrackIntroLength; + pToDeck->startPos = toTrackIntroStart; } else { useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); @@ -955,24 +936,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos /= toTrackDuration; } -void AutoDJProcessor::useOutroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck) { - double outroStart = getOutroStartPosition(pFromDeck); - double outroEnd = getOutroEndPosition(pFromDeck); - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeDuration = outroEnd - outroStart; - pToDeck->startPos = getIntroStartPosition(pToDeck); -} - -void AutoDJProcessor::useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck) { - double outroEnd = getOutroEndPosition(pFromDeck); - double introStart = getIntroStartPosition(pToDeck); - double introEnd = getIntroEndPosition(pToDeck); - double introLength = introEnd - introStart; - pFromDeck->fadeBeginPos = outroEnd - introLength; - pFromDeck->fadeDuration = introLength; - pToDeck->startPos = introStart; -} - void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint) { double transitionTime = m_transitionTime; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 3cf9ae34c16..7e6acb4aa57 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -156,10 +156,8 @@ class AutoDJProcessor : public QObject { FixedFullTrack = 0, FixedSkipSilence = 1, FixedLoadAtCue = 2, - IntroOutroShorter = 3, - IntroOutroLonger = 4, - AlignIntroOutroStart = 5, - AlignIntroOutroEnd = 6, + AlignIntroOutroStart = 3, + AlignIntroOutroEnd = 4, }; AutoDJProcessor(QObject* pParent, @@ -252,8 +250,6 @@ class AutoDJProcessor : public QObject { bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); void calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); - void useOutroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); - void useIntroFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 10230a36223..2149a58a2a7 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -80,10 +80,6 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->addItem(tr("Fixed time (start at cue)"), static_cast(AutoDJProcessor::TransitionMode::FixedLoadAtCue)); - fadeModeCombobox->addItem(tr("Intro/outro (shorter)"), - static_cast(AutoDJProcessor::TransitionMode::IntroOutroShorter)); - fadeModeCombobox->addItem(tr("Intro/outro (longer)"), - static_cast(AutoDJProcessor::TransitionMode::IntroOutroLonger)); fadeModeCombobox->addItem(tr("Align intro + outro start"), static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); fadeModeCombobox->addItem(tr("Align intro + outro end"), From 5df43f6647e6000c0949de7943326bfb893418d2 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 10:50:00 -0500 Subject: [PATCH 025/198] use QComboBox itemData in DlgAutoDJ Before the itemData for the "Align intro + outro end" transition mode was wrong but it worked by coincidence because the order of the items in the QComboBox happened to match the TransitionMode enum class. --- src/library/autodj/autodjprocessor.cpp | 6 +++--- src/library/autodj/autodjprocessor.h | 2 +- src/library/autodj/dlgautodj.cpp | 9 +++++++-- src/library/autodj/dlgautodj.h | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b689740a935..a966fb2b80f 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1050,10 +1050,10 @@ void AutoDJProcessor::setTransitionTime(int time) { } } -void AutoDJProcessor::setTransitionMode(int checkboxState) { +void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { m_pConfig->set(ConfigKey(kConfigKey, kTransitionModePreferenceName), - ConfigValue(checkboxState)); - m_transitionMode = static_cast(checkboxState); + ConfigValue(static_cast(newMode))); + m_transitionMode = newMode; // Then re-calculate fade thresholds for the decks. if (m_eState == ADJ_IDLE) { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 7e6acb4aa57..73f720452f6 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -188,7 +188,7 @@ class AutoDJProcessor : public QObject { public slots: void setTransitionTime(int seconds); - void setTransitionMode(int checkboxState); + void setTransitionMode(TransitionMode newMode); AutoDJError shufflePlaylist(const QModelIndexList& selectedIndices); AutoDJError skipNext(); diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 2149a58a2a7..838ecf61e01 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -83,10 +83,10 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, fadeModeCombobox->addItem(tr("Align intro + outro start"), static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); fadeModeCombobox->addItem(tr("Align intro + outro end"), - static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); + static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroEnd)); fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), - m_pAutoDJProcessor, &AutoDJProcessor::setTransitionMode); + this, &DlgAutoDJ::slotTransitionModeChanged); // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in // mind that AutoDJ may already be active when DlgAutoDJ is created (due to @@ -207,6 +207,11 @@ void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) { } } +void DlgAutoDJ::slotTransitionModeChanged(int comboboxIndex) { + m_pAutoDJProcessor->setTransitionMode(static_cast( + fadeModeCombobox->itemData(comboboxIndex).toInt())); +} + void DlgAutoDJ::updateSelectionInfo() { double duration = 0.0; diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index fd77900e061..d4f34d0f27d 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -41,6 +41,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { void transitionSliderChanged(int value); void autoDJStateChanged(AutoDJProcessor::AutoDJState state); void updateSelectionInfo(); + void slotTransitionModeChanged(int comboboxIndex); signals: void addRandomButton(bool buttonChecked); From cbe8b372023985947f3810e712574f462c064468 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 10:55:21 -0500 Subject: [PATCH 026/198] move "Align intro + outro start/end" modes to top of combobox --- src/library/autodj/autodjprocessor.h | 10 +++++----- src/library/autodj/dlgautodj.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 73f720452f6..10dd4deedc6 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -153,11 +153,11 @@ class AutoDJProcessor : public QObject { }; enum class TransitionMode { - FixedFullTrack = 0, - FixedSkipSilence = 1, - FixedLoadAtCue = 2, - AlignIntroOutroStart = 3, - AlignIntroOutroEnd = 4, + AlignIntroOutroStart = 0, + AlignIntroOutroEnd = 1, + FixedFullTrack = 2, + FixedSkipSilence = 3, + FixedLoadAtCue = 4, }; AutoDJProcessor(QObject* pParent, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 838ecf61e01..91af39c6781 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -74,16 +74,16 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); + fadeModeCombobox->addItem(tr("Align intro + outro start"), + static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); + fadeModeCombobox->addItem(tr("Align intro + outro end"), + static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroEnd)); fadeModeCombobox->addItem(tr("Fixed time (full track)"), static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); fadeModeCombobox->addItem(tr("Fixed time (skip silence)"), static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->addItem(tr("Fixed time (start at cue)"), static_cast(AutoDJProcessor::TransitionMode::FixedLoadAtCue)); - fadeModeCombobox->addItem(tr("Align intro + outro start"), - static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); - fadeModeCombobox->addItem(tr("Align intro + outro end"), - static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroEnd)); fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); From d3910ed5e5ae2cc3e420a876abbfed0180381626 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 11:09:25 -0500 Subject: [PATCH 027/198] shorten variable names for easier readability --- src/library/autodj/autodjprocessor.cpp | 82 +++++++++++++------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index a966fb2b80f..813c88e8ab0 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -843,68 +843,70 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double fromTrackDuration = pFromDeck->duration(); double toTrackDuration = pToDeck->duration(); - double fromTrackOutroStart = getOutroStartPosition(pFromDeck); - if (fromTrackOutroStart <= 0.0) { - fromTrackOutroStart = fromTrackDuration; + // Within this function, the outro refers to the outro of the currently + // playing track and the intro refers to the intro of the next track. + double outroStart = getOutroStartPosition(pFromDeck); + if (outroStart <= 0.0) { + outroStart = fromTrackDuration; } - double fromTrackOutroEnd = getOutroEndPosition(pFromDeck); - if (fromTrackOutroEnd <= 0.0) { - fromTrackOutroEnd = fromTrackDuration; + double outroEnd = getOutroEndPosition(pFromDeck); + if (outroEnd <= 0.0) { + outroEnd = fromTrackDuration; } - double fromTrackOutroLength = fromTrackOutroEnd - fromTrackOutroStart; + double outroLength = outroEnd - outroStart; - double toTrackIntroStart = getIntroStartPosition(pToDeck); - if (toTrackIntroStart <= 0.0) { - toTrackIntroStart = 0.0; + double introStart = getIntroStartPosition(pToDeck); + if (introStart <= 0.0) { + introStart = 0.0; } - double toTrackIntroEnd = getIntroEndPosition(pToDeck); - if (toTrackIntroEnd <= 0.0) { - toTrackIntroEnd = 0.0; + double introEnd = getIntroEndPosition(pToDeck); + if (introEnd <= 0.0) { + introEnd = 0.0; } - double toTrackIntroLength = toTrackIntroEnd - toTrackIntroStart; + double introLength = introEnd - introStart; if (m_transitionMode == TransitionMode::AlignIntroOutroStart) { - if (toTrackIntroStart > 0) { - pToDeck->startPos = toTrackIntroStart; + if (introStart > 0) { + pToDeck->startPos = introStart; } else { pToDeck->startPos = getFirstSoundPosition(pToDeck); } - if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { - pFromDeck->fadeBeginPos = fromTrackOutroStart; - pFromDeck->fadeDuration = math_min(fromTrackOutroLength, toTrackIntroLength); - } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { - pFromDeck->fadeBeginPos = fromTrackOutroStart; - pFromDeck->fadeDuration = fromTrackOutroLength; - } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { - pFromDeck->fadeBeginPos = fromTrackOutroEnd - toTrackIntroLength; - pFromDeck->fadeDuration = toTrackIntroLength; + if (outroLength > 0 && introLength > 0) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeDuration = math_min(outroLength, introLength); + } else if (outroLength > 0 && introLength <= 0) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeDuration = outroLength; + } else if (outroLength <= 0 && introLength > 0) { + pFromDeck->fadeBeginPos = outroEnd - introLength; + pFromDeck->fadeDuration = introLength; } else { useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), pToDeck->startPos); } } else if (m_transitionMode == TransitionMode::AlignIntroOutroEnd) { - if (fromTrackOutroLength > 0 && toTrackIntroLength > 0) { - if (fromTrackOutroLength < toTrackIntroLength) { - pFromDeck->fadeBeginPos = fromTrackOutroStart; - pFromDeck->fadeDuration = fromTrackOutroLength; - pToDeck->startPos = toTrackIntroEnd - fromTrackOutroLength; + if (outroLength > 0 && introLength > 0) { + if (outroLength < introLength) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeDuration = outroLength; + pToDeck->startPos = introEnd - outroLength; } else { - pFromDeck->fadeBeginPos = fromTrackOutroEnd - toTrackIntroLength; - pFromDeck->fadeDuration = toTrackIntroLength; - pToDeck->startPos = toTrackIntroStart; + pFromDeck->fadeBeginPos = outroEnd - introLength; + pFromDeck->fadeDuration = introLength; + pToDeck->startPos = introStart; } - } else if (fromTrackOutroLength > 0 && toTrackIntroLength <= 0) { - pFromDeck->fadeBeginPos = fromTrackOutroStart; - pFromDeck->fadeDuration = fromTrackOutroEnd - fromTrackOutroStart; + } else if (outroLength > 0 && introLength <= 0) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeDuration = outroEnd - outroStart; pToDeck->startPos = getIntroStartPosition(pToDeck); - } else if (fromTrackOutroLength <= 0 && toTrackIntroLength > 0) { - pFromDeck->fadeBeginPos = fromTrackOutroEnd - toTrackIntroLength; - pFromDeck->fadeDuration = toTrackIntroLength; - pToDeck->startPos = toTrackIntroStart; + } else if (outroLength <= 0 && introLength > 0) { + pFromDeck->fadeBeginPos = outroEnd - introLength; + pFromDeck->fadeDuration = introLength; + pToDeck->startPos = introStart; } else { useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); From 98d9daa7cce45b02a75ed42d2f3133ffba0832fd Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 11:19:29 -0500 Subject: [PATCH 028/198] use first/last sound as fallbacks for intro start/outro end in case intro start or outro end are not set --- src/library/autodj/autodjprocessor.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 813c88e8ab0..4c104eb3ba1 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -852,14 +852,14 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroEnd = getOutroEndPosition(pFromDeck); if (outroEnd <= 0.0) { - outroEnd = fromTrackDuration; + outroEnd = getLastSoundPosition(pFromDeck); } double outroLength = outroEnd - outroStart; double introStart = getIntroStartPosition(pToDeck); if (introStart <= 0.0) { - introStart = 0.0; + introStart = getFirstSoundPosition(pToDeck); } double introEnd = getIntroEndPosition(pToDeck); @@ -870,12 +870,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double introLength = introEnd - introStart; if (m_transitionMode == TransitionMode::AlignIntroOutroStart) { - if (introStart > 0) { - pToDeck->startPos = introStart; - } else { - pToDeck->startPos = getFirstSoundPosition(pToDeck); - } - + pToDeck->startPos = introStart; if (outroLength > 0 && introLength > 0) { pFromDeck->fadeBeginPos = outroStart; pFromDeck->fadeDuration = math_min(outroLength, introLength); @@ -886,7 +881,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeBeginPos = outroEnd - introLength; pFromDeck->fadeDuration = introLength; } else { - useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), pToDeck->startPos); + useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } } else if (m_transitionMode == TransitionMode::AlignIntroOutroEnd) { if (outroLength > 0 && introLength > 0) { @@ -908,8 +903,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeDuration = introLength; pToDeck->startPos = introStart; } else { - useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); + useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { useFixedFadeTime(pFromDeck, pToDeck, From e5571d7003d174961f1372121a6af4f8d5c40f72 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 11:26:54 -0500 Subject: [PATCH 029/198] simplify code a little --- src/library/autodj/autodjprocessor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 4c104eb3ba1..7142740166d 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -896,8 +896,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } } else if (outroLength > 0 && introLength <= 0) { pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeDuration = outroEnd - outroStart; - pToDeck->startPos = getIntroStartPosition(pToDeck); + pFromDeck->fadeDuration = outroLength; + pToDeck->startPos = introStart; } else if (outroLength <= 0 && introLength > 0) { pFromDeck->fadeBeginPos = outroEnd - introLength; pFromDeck->fadeDuration = introLength; From bf7a20c1c7bf57c3982a2c8932da947bd26a93bb Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 11:27:09 -0500 Subject: [PATCH 030/198] add comment explaining how fadeDuration is determined --- src/library/autodj/autodjprocessor.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 7142740166d..76f527b598a 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -869,6 +869,13 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double introLength = introEnd - introStart; + // For both the AlignIntroOutroStart & AlignIntroOutroEnd TransitionModes, + // fadeDuration is the intro or outro length, whichever is shorter. This + // is the best way to avoid clashing sounds overlapping. If only one track + // has an intro or outro range marked (not just one point of the range, but + // the full range with the end and beginning markers), use the length of + // that range as the transition time as a best guess. Only fall back to the + // fixed number of seconds from the spinbox as a last resort. if (m_transitionMode == TransitionMode::AlignIntroOutroStart) { pToDeck->startPos = introStart; if (outroLength > 0 && introLength > 0) { From 313e89444765525db26d17e5e02b165470824dbb Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 11:55:55 -0500 Subject: [PATCH 031/198] AutoDJ: improve error handling if next track is too short --- src/library/autodj/autodjprocessor.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 76f527b598a..0a6ceec5972 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -921,6 +921,17 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); } + // Guard against the next track being too short. This transition must finish + // before the next one starts. + double toDeckOutroStart = getOutroStartPosition(pToDeck); + if (toDeckOutroStart <= 0) { + toDeckOutroStart = getOutroEndPosition(pToDeck); + } + double maxFadeTime = toDeckOutroStart - pToDeck->startPos; + if (pFromDeck->fadeDuration > maxFadeTime) { + pFromDeck->fadeDuration = maxFadeTime; + } + VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { pFromDeck->fadeBeginPos = fromTrackDuration; pFromDeck->fadeDuration = 0; @@ -929,10 +940,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = 0; } - if (pFromDeck->fadeDuration > toTrackDuration) { - pFromDeck->fadeDuration = toTrackDuration; - } - // These are expected to be a fraction of the track length. pFromDeck->fadeBeginPos /= fromTrackDuration; pFromDeck->fadeDuration /= fromTrackDuration; From a38c0b3d05fe2f317806271d9c245489c296ddac Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 12:13:46 -0500 Subject: [PATCH 032/198] AutoDJ: remove redundant error handling if next track is too short --- src/library/autodj/autodjprocessor.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 0a6ceec5972..7cd684169c4 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -948,20 +948,14 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint) { - double transitionTime = m_transitionTime; - double toTrackDuration = pToDeck->duration(); - if (m_transitionTime > toTrackDuration) { - transitionTime = toTrackDuration; - } - - if (transitionTime > 0.0) { - pFromDeck->fadeBeginPos = endPoint - transitionTime; - pFromDeck->fadeDuration = transitionTime; + if (m_transitionTime > 0.0) { + pFromDeck->fadeBeginPos = endPoint - m_transitionTime; + pFromDeck->fadeDuration = m_transitionTime; pToDeck->startPos = startPoint; } else { pFromDeck->fadeBeginPos = endPoint; - pFromDeck->fadeDuration = transitionTime; - pToDeck->startPos = startPoint + transitionTime; + pFromDeck->fadeDuration = m_transitionTime; + pToDeck->startPos = startPoint + m_transitionTime; } } From 232064390521f81a71061c72a6de7c2df1d32bbf Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 12:15:32 -0500 Subject: [PATCH 033/198] AutoDJ: use last sound as end point with load at cue mode --- src/library/autodj/autodjprocessor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 7cd684169c4..f5f8e30447d 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -916,7 +916,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); } else if (m_transitionMode == TransitionMode::FixedLoadAtCue) { - useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, getMainCuePosition(pToDeck)); + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), getMainCuePosition(pToDeck)); } else { useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); } From 222a991a1356c8a2eda0d148cba9abca9afdbd0c Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 12:58:03 -0500 Subject: [PATCH 034/198] DlgPrefDeck: change load point selection from radio buttons to combobox --- src/preferences/dialog/dlgprefdeck.cpp | 35 ++++++++---------------- src/preferences/dialog/dlgprefdeck.h | 2 +- src/preferences/dialog/dlgprefdeckdlg.ui | 33 +--------------------- 3 files changed, 14 insertions(+), 56 deletions(-) diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index f21c51775f3..0cb79df29e8 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -159,23 +159,16 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, connect(checkBoxDisallowLoadToPlayingDeck, SIGNAL(toggled(bool)), this, SLOT(slotDisallowTrackLoadToPlayingDeckCheckbox(bool))); + comboBoxLoadPoint->addItem(tr("Intro start"), static_cast(SeekOnLoadMode::IntroStart)); + comboBoxLoadPoint->addItem(tr("Main cue"), static_cast(SeekOnLoadMode::MainCue)); + comboBoxLoadPoint->addItem(tr("First sound (skip silence)"), static_cast(SeekOnLoadMode::FirstSound)); + comboBoxLoadPoint->addItem(tr("Beginning of file"), static_cast(SeekOnLoadMode::Beginning)); int seekMode = m_pConfig->getValue(ConfigKey("[Controls]", "CueRecall"), static_cast(SeekOnLoadMode::IntroStart)); + comboBoxLoadPoint->setCurrentIndex( + comboBoxLoadPoint->findData(seekMode)); m_seekOnLoadMode = static_cast(seekMode); - switch (m_seekOnLoadMode) { - case SeekOnLoadMode::Beginning: - radioButtonBeginning->setChecked(true); - break; - case SeekOnLoadMode::MainCue: - radioButtonMainCue->setChecked(true); - break; - default: - radioButtonIntroStart->setChecked(true); - m_seekOnLoadMode = SeekOnLoadMode::IntroStart; - break; - } - connect(buttonGroupLoadPoint, - static_cast(&QButtonGroup::buttonClicked), + connect(comboBoxLoadPoint, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgPrefDeck::slotSetTrackLoadMode); m_bRateInverted = m_pConfig->getValue(ConfigKey("[Controls]", "RateDir"), false); @@ -418,7 +411,8 @@ void DlgPrefDeck::slotResetToDefaults() { ComboBoxCueMode->setCurrentIndex(0); // Load at intro start - radioButtonIntroStart->setChecked(true); + comboBoxLoadPoint->setCurrentIndex( + comboBoxLoadPoint->findData(static_cast(SeekOnLoadMode::IntroStart))); // Rate-ramping default off. radioButtonRateRampModeStepping->setChecked(true); @@ -552,14 +546,9 @@ void DlgPrefDeck::slotTimeFormatChanged(double v) { comboBoxTimeFormat->findData(i)); } -void DlgPrefDeck::slotSetTrackLoadMode(QAbstractButton* pressedButton) { - if (pressedButton == radioButtonBeginning) { - m_seekOnLoadMode = SeekOnLoadMode::Beginning; - } else if (pressedButton == radioButtonMainCue) { - m_seekOnLoadMode = SeekOnLoadMode::MainCue; - } else { - m_seekOnLoadMode = SeekOnLoadMode::IntroStart; - } +void DlgPrefDeck::slotSetTrackLoadMode(int comboboxIndex) { + m_seekOnLoadMode = static_cast( + comboBoxLoadPoint->itemData(comboboxIndex).toInt()); } void DlgPrefDeck::slotApply() { diff --git a/src/preferences/dialog/dlgprefdeck.h b/src/preferences/dialog/dlgprefdeck.h index a63d6db4c67..668e7918a28 100644 --- a/src/preferences/dialog/dlgprefdeck.h +++ b/src/preferences/dialog/dlgprefdeck.h @@ -73,7 +73,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { void slotSetTrackTimeDisplay(double); void slotDisallowTrackLoadToPlayingDeckCheckbox(bool); void slotCueModeCombobox(int); - void slotSetTrackLoadMode(QAbstractButton*); + void slotSetTrackLoadMode(int comboboxIndex); void slotRateRampingModeLinearButton(bool); void slotRateRampSensitivitySlider(int); diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index a0396433fb1..fed6cb510dd 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -149,38 +149,7 @@ CUP mode: - - - - - Beginning - - - buttonGroupLoadPoint - - - - - - - Intro Start - - - buttonGroupLoadPoint - - - - - - - Main Cue - - - buttonGroupLoadPoint - - - - + From 97597d3e75568a8d2537892bbc2f978ff02a27f0 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 13:04:51 -0500 Subject: [PATCH 035/198] add option to load new tracks at intro end point --- src/engine/controls/cuecontrol.cpp | 10 +++++++++- src/engine/controls/cuecontrol.h | 1 + src/preferences/dialog/dlgprefdeck.cpp | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 99c1f3329c1..4b93706ddd6 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -346,7 +346,8 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { // Seek track according to SeekOnLoadMode. SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); - CuePointer pFirstSound = m_pLoadedTrack->findCueByType(Cue::Type::FirstSound); + CuePointer pFirstSound = pNewTrack->findCueByType(Cue::Type::FirstSound); + double introEnd = m_pIntroEndPosition->get(); switch (seekOnLoadMode) { case SeekOnLoadMode::Beginning: // This allows users to load tracks and have the needle-drop be maintained. @@ -368,6 +369,13 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { case SeekOnLoadMode::IntroStart: seekExact(m_pIntroStartPosition->get()); break; + case SeekOnLoadMode::IntroEnd: + if (introEnd >= 0) { + seekExact(introEnd); + } else { + seekExact(m_pIntroStartPosition->get()); + } + break; default: seekExact(0.0); break; diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 402b84c7556..f1310f86d26 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -23,6 +23,7 @@ enum class SeekOnLoadMode { Beginning = 1, // Use 0:00.000 FirstSound = 2, // Skip leading silence IntroStart = 3, // Use intro start cue point + IntroEnd = 4, // Use intro end cue point }; inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 0cb79df29e8..74652d9d559 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -160,6 +160,7 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, this, SLOT(slotDisallowTrackLoadToPlayingDeckCheckbox(bool))); comboBoxLoadPoint->addItem(tr("Intro start"), static_cast(SeekOnLoadMode::IntroStart)); + comboBoxLoadPoint->addItem(tr("Intro end"), static_cast(SeekOnLoadMode::IntroEnd)); comboBoxLoadPoint->addItem(tr("Main cue"), static_cast(SeekOnLoadMode::MainCue)); comboBoxLoadPoint->addItem(tr("First sound (skip silence)"), static_cast(SeekOnLoadMode::FirstSound)); comboBoxLoadPoint->addItem(tr("Beginning of file"), static_cast(SeekOnLoadMode::Beginning)); From c1dd217e47a5fa21eee55d275d996794976068c2 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 9 May 2019 13:30:48 -0500 Subject: [PATCH 036/198] AutoDJ: improve error handling when next track is 0 length --- src/library/autodj/autodjprocessor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index f5f8e30447d..59c73bc88b9 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -938,6 +938,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeDuration = 0; } VERIFY_OR_DEBUG_ASSERT(toTrackDuration > 0) { + pFromDeck->fadeDuration = 0; pToDeck->startPos = 0; } From 6c7b33551345fa92d293305fc53dd7e2587122f4 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 25 May 2019 10:54:02 -0500 Subject: [PATCH 037/198] AutoDJ: add tooltip for fade mode combobox --- src/library/autodj/dlgautodj.cpp | 13 +++++++++++++ src/library/autodj/dlgautodj.ui | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 91af39c6781..270ae5ef37e 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -87,6 +87,19 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); + QString fadeModeTooltip = tr( + "Align intro + outro start: align the start of the intro of the next track with the\n" + "start of the outro of the current track. The length of the intro or outro range\n" + "is used as the transition time, whichever is shorter." + "\n\n" + "Align intro + outro end: align the end of the intro of the next track with the\n" + "end of the outro of the current track. The length of the intro or outro range\n" + "is used as the transition time, whichever is shorter." + "\n\n" + "Fixed time modes: use the selected number of seconds as the transition time" + ); + fadeModeCombobox->setToolTip(fadeModeTooltip); + fadeModeLabel->setToolTip(fadeModeTooltip); // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in // mind that AutoDJ may already be active when DlgAutoDJ is created (due to diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index e6e43b761dd..30f8e2d0c93 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -139,7 +139,7 @@ If no track sources are configured, the track is added from the library instead. - + Fade mode: From 5faf0de27c2b7be3f0a5d65a097ea81863dfb7d1 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 25 May 2019 11:24:53 -0500 Subject: [PATCH 038/198] AutoDJ: explicitly explain spinbox is not used in intro/outro modes --- src/library/autodj/dlgautodj.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 270ae5ef37e..6d19642de0d 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -88,15 +88,15 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( - "Align intro + outro start: align the start of the intro of the next track with the\n" - "start of the outro of the current track. The length of the intro or outro range\n" - "is used as the transition time, whichever is shorter." + "Align intro + outro start/end modes:\n" + "Align the start/end of the intro of the next track with the\n" + "start/end of the outro of the current track. The length of\n" + "the intro or outro range is used as the transition time,\n" + "whichever is shorter. The selected number of seconds is\n" + "only used if neither track has an intro or outro range marked." "\n\n" - "Align intro + outro end: align the end of the intro of the next track with the\n" - "end of the outro of the current track. The length of the intro or outro range\n" - "is used as the transition time, whichever is shorter." - "\n\n" - "Fixed time modes: use the selected number of seconds as the transition time" + "Fixed time modes:\n" + "Use the selected number of seconds as the transition time." ); fadeModeCombobox->setToolTip(fadeModeTooltip); fadeModeLabel->setToolTip(fadeModeTooltip); From fc5eb534079c1575ed57de8822fec30d553ebaaf Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 9 Jun 2019 18:14:26 -0500 Subject: [PATCH 039/198] fix segfaulting in AutoDJ tests --- src/library/autodj/autodjprocessor.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 59c73bc88b9..32604a0dd58 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -786,7 +786,12 @@ double AutoDJProcessor::getOutroEndPosition(DeckAttributes* pDeck) { } double AutoDJProcessor::getFirstSoundPosition(DeckAttributes* pDeck) { - CuePointer pFromTrackFirstSound = pDeck->getLoadedTrack()->findCueByType(Cue::Type::FirstSound); + TrackPointer pTrack = pDeck->getLoadedTrack(); + if (!pTrack) { + return 0; + } + + CuePointer pFromTrackFirstSound = pTrack->findCueByType(Cue::Type::FirstSound); if (pFromTrackFirstSound) { return samplePositionToSeconds(pFromTrackFirstSound->getPosition(), pDeck); } else { @@ -795,7 +800,12 @@ double AutoDJProcessor::getFirstSoundPosition(DeckAttributes* pDeck) { } double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { - CuePointer pFromTrackLastSound = pDeck->getLoadedTrack()->findCueByType(Cue::Type::LastSound); + TrackPointer pTrack = pDeck->getLoadedTrack(); + if (!pTrack) { + return 0; + } + + CuePointer pFromTrackLastSound = pTrack->findCueByType(Cue::Type::LastSound); if (pFromTrackLastSound) { return samplePositionToSeconds(pFromTrackLastSound->getPosition(), pDeck); } else { @@ -804,7 +814,12 @@ double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { } double AutoDJProcessor::getMainCuePosition(DeckAttributes* pDeck) { - CuePointer pMainCue = pDeck->getLoadedTrack()->findCueByType(Cue::Type::MainCue); + TrackPointer pTrack = pDeck->getLoadedTrack(); + if (!pTrack) { + return 0; + } + + CuePointer pMainCue = pTrack->findCueByType(Cue::Type::MainCue); if (pMainCue) { return samplePositionToSeconds(pMainCue->getPosition(), pDeck); } else { From 9c43bac5daa870ec90331ad6b4087cd03bbccfc0 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 17 Jun 2019 18:28:16 -0500 Subject: [PATCH 040/198] rename variable for clarity --- src/library/autodj/autodjprocessor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 32604a0dd58..bd208faf0c0 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -155,10 +155,10 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, m_transitionTime = str_autoDjTransition.toDouble(); } - int configMode = m_pConfig->getValue( + int configuredTransitionMode = m_pConfig->getValue( ConfigKey(kConfigKey, kTransitionModePreferenceName), static_cast(TransitionMode::AlignIntroOutroStart)); - m_transitionMode = static_cast(configMode); + m_transitionMode = static_cast(configuredTransitionMode); } AutoDJProcessor::~AutoDJProcessor() { From 4c035dc3ea2dfce9c8e0a5da82b5b6e3f1cf8bcc Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 17 Jun 2019 18:28:29 -0500 Subject: [PATCH 041/198] "Beginning of file" -> "Beginning of track" --- src/preferences/dialog/dlgprefdeck.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 748b05b7824..40cb5eb20ba 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -162,7 +162,7 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, comboBoxLoadPoint->addItem(tr("Intro end"), static_cast(SeekOnLoadMode::IntroEnd)); comboBoxLoadPoint->addItem(tr("Main cue"), static_cast(SeekOnLoadMode::MainCue)); comboBoxLoadPoint->addItem(tr("First sound (skip silence)"), static_cast(SeekOnLoadMode::FirstSound)); - comboBoxLoadPoint->addItem(tr("Beginning of file"), static_cast(SeekOnLoadMode::Beginning)); + comboBoxLoadPoint->addItem(tr("Beginning of track"), static_cast(SeekOnLoadMode::Beginning)); int seekMode = m_pConfig->getValue(ConfigKey("[Controls]", "CueRecall"), static_cast(SeekOnLoadMode::IntroStart)); comboBoxLoadPoint->setCurrentIndex( From 4393cc6e0368fe65fba7c722da97d5965254a314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 11 Jun 2019 20:22:08 +0200 Subject: [PATCH 042/198] Added missing includes --- src/library/autodj/dlgautodj.cpp | 1 + src/preferences/dialog/dlgprefdeck.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 51fd8cd87ac..2b327253183 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -6,6 +6,7 @@ #include "widget/wtracktableview.h" #include "util/assert.h" #include "util/duration.h" +#include "util/compatibility.h" DlgAutoDJ::DlgAutoDJ(QWidget* parent, UserSettingsPointer pConfig, diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 40cb5eb20ba..8a91a0b0671 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -20,6 +20,7 @@ #include "mixxx.h" #include "defs_urls.h" #include "util/duration.h" +#include "util/compatibility.h" namespace { constexpr int kDefaultRateRangePercent = 8; From fb7114ea7949fa828da67dbeeffcface0a57e107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 9 Jul 2019 23:18:30 +0200 Subject: [PATCH 043/198] Introduce kKeepPosition to allow not requeing the "to deck" --- src/library/autodj/autodjprocessor.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 052c62d2526..4383e05f669 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -12,6 +12,7 @@ const char* kTransitionPreferenceName = "Transition"; const char* kTransitionModePreferenceName = "TransitionMode"; const double kTransitionPreferenceDefault = 10.0; +const double kKeepPosition = -1.0; const mixxx::AudioSignal::ChannelCount kChannelCount = mixxx::kEngineChannelCount; @@ -994,7 +995,9 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } else { calculateTransition(getOtherDeck(pDeck, true), pDeck); - pDeck->setPlayPosition(pDeck->startPos); + if (pDeck->startPos != kKeepPosition) { + pDeck->setPlayPosition(pDeck->startPos); + } } } @@ -1083,11 +1086,15 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { if (leftDeck.isPlaying()) { calculateTransition(&leftDeck, &rightDeck); - rightDeck.setPlayPosition(rightDeck.startPos); + if (rightDeck.startPos != kKeepPosition) { + rightDeck.setPlayPosition(rightDeck.startPos); + } } if (rightDeck.isPlaying()) { calculateTransition(&rightDeck, &leftDeck); - leftDeck.setPlayPosition(leftDeck.startPos); + if (leftDeck.startPos != kKeepPosition) { + leftDeck.setPlayPosition(leftDeck.startPos); + } } } } From 0697e5adbd33c1fd803e9afa3e3d4c0f737237bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 9 Jul 2019 23:36:29 +0200 Subject: [PATCH 044/198] Improve assertions if the tracks have no duration --- src/library/autodj/autodjprocessor.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 4383e05f669..8e4c2dc8de7 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -859,6 +859,22 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double fromTrackDuration = pFromDeck->duration(); double toTrackDuration = pToDeck->duration(); + VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { + // Playing Track has no duration. This should not happen, because short + // tracks are skipped after load. Play ToDeck emmediately. + pFromDeck->fadeBeginPos = 0; + pFromDeck->fadeDuration = 0; + pToDeck->startPos = kKeepPosition; + return; + } + VERIFY_OR_DEBUG_ASSERT(toTrackDuration > 0) { + // Playing Track has no duration. This should not happen, because short + // tracks are skipped after load. + pToDeck->startPos = kKeepPosition; + // Disable AutoDJ. + toggleAutoDJ(false); + } + // Within this function, the outro refers to the outro of the currently // playing track and the intro refers to the intro of the next track. double outroStart = getOutroStartPosition(pFromDeck); @@ -949,15 +965,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeDuration = maxFadeTime; } - VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { - pFromDeck->fadeBeginPos = fromTrackDuration; - pFromDeck->fadeDuration = 0; - } - VERIFY_OR_DEBUG_ASSERT(toTrackDuration > 0) { - pFromDeck->fadeDuration = 0; - pToDeck->startPos = 0; - } - // These are expected to be a fraction of the track length. pFromDeck->fadeBeginPos /= fromTrackDuration; pFromDeck->fadeDuration /= fromTrackDuration; From 80557fc0d53b3a4b25272365af1561c635305fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 9 Jul 2019 23:49:57 +0200 Subject: [PATCH 045/198] Inhibit transition recalculation during loading a track --- src/library/autodj/autodjprocessor.cpp | 27 ++++++++++++++++---------- src/library/autodj/autodjprocessor.h | 1 + 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 8e4c2dc8de7..ac46cd26c9a 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -16,15 +16,17 @@ const double kKeepPosition = -1.0; const mixxx::AudioSignal::ChannelCount kChannelCount = mixxx::kEngineChannelCount; -static const bool sDebug = false; +static const bool sDebug = true; // false; DeckAttributes::DeckAttributes(int index, BaseTrackPlayer* pPlayer, EngineChannel::ChannelOrientation orientation) : index(index), group(pPlayer->getGroup()), + startPos(kKeepPosition), fadeBeginPos(1.0), fadeDuration(0.0), + loading(false), m_orientation(orientation), m_playPos(group, "playposition"), m_play(group, "play"), @@ -516,8 +518,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // playing. loadNextTrackFromQueue(rightDeck); - // Set crossfade thresholds for left deck. - calculateTransition(&leftDeck, &rightDeck); + // Note: calculateTransition() is called in playerTrackLoaded() } else { // At least right Deck is playing // Set crossfade thresholds for right deck. @@ -735,7 +736,7 @@ void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, doubl qDebug() << this << "playerIntroStartChanged" << pAttributes->group << position; } - if (!pAttributes->isPlaying()) { + if (!pAttributes->loading && !pAttributes->isPlaying()) { calculateTransition(getOtherDeck(pAttributes, true), pAttributes); } } @@ -745,7 +746,7 @@ void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double qDebug() << this << "playerIntroEndChanged" << pAttributes->group << position; } - if (!pAttributes->isPlaying()) { + if (!pAttributes->loading && !pAttributes->isPlaying()) { calculateTransition(getOtherDeck(pAttributes, true), pAttributes); } } @@ -755,7 +756,7 @@ void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, doubl qDebug() << this << "playerOutroStartChanged" << pAttributes->group << position; } - if (pAttributes->isPlaying()) { + if (!pAttributes->loading && pAttributes->isPlaying()) { calculateTransition(pAttributes, getOtherDeck(pAttributes, false)); } } @@ -765,7 +766,7 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double qDebug() << this << "playerOutroEndChanged" << pAttributes->group << position; } - if (pAttributes->isPlaying()) { + if (!pAttributes->loading && pAttributes->isPlaying()) { calculateTransition(pAttributes, getOtherDeck(pAttributes, false)); } } @@ -990,6 +991,8 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra << (pTrack ? pTrack->getLocation() : "(null)"); } + pDeck->loading = false; + double duration = pTrack->getDuration(); if (duration < 0.2) { qWarning() << "Skip track with" << duration << "Duration" @@ -1016,6 +1019,8 @@ void AutoDJProcessor::playerLoadingTrack(DeckAttributes* pDeck, << "old:"<< (pOldTrack ? pOldTrack->getLocation() : "(null)"); } + pDeck->loading = true; + // The Deck is loading an new track // There are four conditions under which we load a track. @@ -1091,17 +1096,19 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; - if (leftDeck.isPlaying()) { + if (leftDeck.isPlaying() && !rightDeck.isPlaying()) { calculateTransition(&leftDeck, &rightDeck); if (rightDeck.startPos != kKeepPosition) { rightDeck.setPlayPosition(rightDeck.startPos); } - } - if (rightDeck.isPlaying()) { + } else if (rightDeck.isPlaying() && !leftDeck.isPlaying()) { calculateTransition(&rightDeck, &leftDeck); if (leftDeck.startPos != kKeepPosition) { leftDeck.setPlayPosition(leftDeck.startPos); } + } else { + // user has manually started the other deck or dtopped both. + // don't know what to do. } } } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 10dd4deedc6..54331cf7448 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -116,6 +116,7 @@ class DeckAttributes : public QObject { double startPos; double fadeBeginPos; double fadeDuration; + bool loading; // The data is inconsitence during loading a deck private: EngineChannel::ChannelOrientation m_orientation; From cd3896c8c07882fceae326f36b686e759cc5cc10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 9 Jul 2019 23:57:05 +0200 Subject: [PATCH 046/198] Use switch in calculateTransition() --- src/library/autodj/autodjprocessor.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index ac46cd26c9a..90ffec9857f 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -909,7 +909,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // the full range with the end and beginning markers), use the length of // that range as the transition time as a best guess. Only fall back to the // fixed number of seconds from the spinbox as a last resort. - if (m_transitionMode == TransitionMode::AlignIntroOutroStart) { + switch (m_transitionMode) { + case TransitionMode::AlignIntroOutroStart: pToDeck->startPos = introStart; if (outroLength > 0 && introLength > 0) { pFromDeck->fadeBeginPos = outroStart; @@ -923,7 +924,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else { useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } - } else if (m_transitionMode == TransitionMode::AlignIntroOutroEnd) { + break; + case TransitionMode::AlignIntroOutroEnd: if (outroLength > 0 && introLength > 0) { if (outroLength < introLength) { pFromDeck->fadeBeginPos = outroStart; @@ -945,13 +947,16 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else { useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } - } else if (m_transitionMode == TransitionMode::FixedSkipSilence) { + break; + case TransitionMode::FixedSkipSilence: useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); - } else if (m_transitionMode == TransitionMode::FixedLoadAtCue) { + break; + case TransitionMode::FixedLoadAtCue: useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), getMainCuePosition(pToDeck)); - } else { + break; + default: useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); } From 422429aa79031f0c771fe2a24e4b1de7b89e60cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 10 Jul 2019 00:01:46 +0200 Subject: [PATCH 047/198] Clang-format: reorder includes --- src/library/autodj/dlgautodj.cpp | 4 ++-- src/preferences/dialog/dlgprefdeck.cpp | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 2b327253183..8389ee04de2 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -3,10 +3,10 @@ #include "library/autodj/dlgautodj.h" #include "library/playlisttablemodel.h" -#include "widget/wtracktableview.h" #include "util/assert.h" -#include "util/duration.h" #include "util/compatibility.h" +#include "util/duration.h" +#include "widget/wtracktableview.h" DlgAutoDJ::DlgAutoDJ(QWidget* parent, UserSettingsPointer pConfig, diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 8a91a0b0671..6112502412c 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -6,21 +6,20 @@ #include #include -#include "mixer/basetrackplayer.h" -#include "preferences/dialog/dlgprefdeck.h" -#include "preferences/usersettings.h" #include "control/controlobject.h" #include "control/controlproxy.h" -#include "widget/wnumberpos.h" -#include "engine/enginebuffer.h" +#include "defs_urls.h" #include "engine/controls/ratecontrol.h" -#include "mixer/playermanager.h" +#include "engine/enginebuffer.h" +#include "mixer/basetrackplayer.h" #include "mixer/playerinfo.h" -#include "control/controlobject.h" +#include "mixer/playermanager.h" #include "mixxx.h" -#include "defs_urls.h" -#include "util/duration.h" +#include "preferences/dialog/dlgprefdeck.h" +#include "preferences/usersettings.h" #include "util/compatibility.h" +#include "util/duration.h" +#include "widget/wnumberpos.h" namespace { constexpr int kDefaultRateRangePercent = 8; From 4492823a8215c01dec970a6b68383beb074c7048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 10 Jul 2019 00:17:23 +0200 Subject: [PATCH 048/198] Fix negative intro and outro length --- src/library/autodj/autodjprocessor.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 90ffec9857f..ca3cf64e87e 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -878,16 +878,17 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // Within this function, the outro refers to the outro of the currently // playing track and the intro refers to the intro of the next track. - double outroStart = getOutroStartPosition(pFromDeck); - if (outroStart <= 0.0) { - outroStart = fromTrackDuration; - } double outroEnd = getOutroEndPosition(pFromDeck); if (outroEnd <= 0.0) { outroEnd = getLastSoundPosition(pFromDeck); } + double outroStart = getOutroStartPosition(pFromDeck); + if (outroStart <= 0.0) { + outroStart = outroEnd; + } + double outroLength = outroEnd - outroStart; double introStart = getIntroStartPosition(pToDeck); @@ -897,7 +898,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double introEnd = getIntroEndPosition(pToDeck); if (introEnd <= 0.0) { - introEnd = 0.0; + introEnd = introStart; } double introLength = introEnd - introStart; From 9b562c95983b6817361cdb3e6005277855062812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 10 Jul 2019 23:27:34 +0200 Subject: [PATCH 049/198] Adjust autro in case of FadeNow --- src/library/autodj/autodjprocessor.cpp | 94 +++++++++++++++++--------- src/library/autodj/autodjprocessor.h | 3 +- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index ca3cf64e87e..586488808cb 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -230,20 +230,12 @@ void AutoDJProcessor::fadeNow() { if (leftDeck.isPlaying() && (!rightDeck.isPlaying() || crossfader < 0.0)) { // Make sure leftDeck.fadeDuration is up to date. - calculateTransition(&leftDeck, &rightDeck); - - // override posThreshold to start fade now - leftDeck.fadeBeginPos = leftDeck.playPosition() - - ((crossfader + 1.0) / 2 * (leftDeck.fadeDuration)); + calculateTransition(&leftDeck, &rightDeck, true); // Repeat is disabled by FadeNow but disables auto Fade leftDeck.setRepeat(false); } else if (rightDeck.isPlaying()) { // Make sure rightDeck.fadeDuration is up to date. - calculateTransition(&rightDeck, &leftDeck); - - // override posThreshold to start fade now - rightDeck.fadeBeginPos = rightDeck.playPosition() - - ((1.0 - crossfader) / 2 * (rightDeck.fadeDuration)); + calculateTransition(&rightDeck, &leftDeck, true); // Repeat is disabled by FadeNow but disables auto Fade rightDeck.setRepeat(false); } @@ -402,14 +394,14 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { m_eState = ADJ_IDLE; if (deck1Playing) { // Update fade thresholds for the left deck. - calculateTransition(&deck1, &deck2); + calculateTransition(&deck1, &deck2, false); // Load track into the right deck. emitLoadTrackToPlayer(nextTrack, deck2.group, false); // Move crossfader to the left. setCrossfader(-1.0, false); } else { // Update fade thresholds for the right deck. - calculateTransition(&deck2, &deck1); + calculateTransition(&deck2, &deck1, false); // Load track into the left deck. emitLoadTrackToPlayer(nextTrack, deck1.group, false); // Move crossfader to the right. @@ -522,7 +514,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } else { // At least right Deck is playing // Set crossfade thresholds for right deck. - calculateTransition(&rightDeck, &leftDeck); + calculateTransition(&rightDeck, &leftDeck, false); } emitAutoDJStateChanged(m_eState); } @@ -572,7 +564,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (m_eState == ADJ_IDLE && (thisDeckPlaying || thisDeck.fadeBeginPos >= 1.0)) { if (!otherDeckPlaying) { - calculateTransition(&otherDeck, &thisDeck); + calculateTransition(&otherDeck, &thisDeck, false); otherDeck.play(); } @@ -727,7 +719,7 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* pAttributes, bool playin // This is required because the user may have loaded a track or changed play // manually if (playing) { - calculateTransition(pAttributes, getOtherDeck(pAttributes)); + calculateTransition(pAttributes, getOtherDeck(pAttributes), false); } } @@ -737,7 +729,7 @@ void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, doubl } if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(getOtherDeck(pAttributes, true), pAttributes); + calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false); } } @@ -747,7 +739,7 @@ void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double } if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(getOtherDeck(pAttributes, true), pAttributes); + calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false); } } @@ -757,7 +749,7 @@ void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, doubl } if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(pAttributes, getOtherDeck(pAttributes, false)); + calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false); } } @@ -767,7 +759,7 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double } if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(pAttributes, getOtherDeck(pAttributes, false)); + calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false); } } @@ -840,7 +832,8 @@ double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttri } void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, - DeckAttributes* pToDeck) { + DeckAttributes* pToDeck, + bool fadeNow) { if (pFromDeck == nullptr) { return; } @@ -879,14 +872,27 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // Within this function, the outro refers to the outro of the currently // playing track and the intro refers to the intro of the next track. + double outroStart; + double outroEnd = getOutroEndPosition(pFromDeck); if (outroEnd <= 0.0) { outroEnd = getLastSoundPosition(pFromDeck); } - double outroStart = getOutroStartPosition(pFromDeck); - if (outroStart <= 0.0) { - outroStart = outroEnd; + if (fadeNow) { + // Assume that the outro starts now and equals the given transition time + // but do not pass the original outroEnd + outroStart = pFromDeck->playPosition() * fromTrackDuration; + if (outroEnd > outroStart) { + outroEnd = math_min(outroEnd, outroStart + m_transitionTime); + } else { + outroEnd = math_min(fromTrackDuration, outroStart + m_transitionTime); + } + } else { + outroStart = getOutroStartPosition(pFromDeck); + if (outroStart <= 0.0) { + outroStart = outroEnd; + } } double outroLength = outroEnd - outroStart; @@ -950,15 +956,37 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } break; case TransitionMode::FixedSkipSilence: - useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); + if (fadeNow) { + useFixedFadeTime(pFromDeck, + pToDeck, + outroEnd, + getFirstSoundPosition(pToDeck)); + } else { + useFixedFadeTime(pFromDeck, + pToDeck, + getLastSoundPosition(pFromDeck), + getFirstSoundPosition(pToDeck)); + } break; case TransitionMode::FixedLoadAtCue: - useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), getMainCuePosition(pToDeck)); + if (fadeNow) { + useFixedFadeTime(pFromDeck, + pToDeck, + outroEnd, + getMainCuePosition(pToDeck)); + } else { + useFixedFadeTime(pFromDeck, + pToDeck, + getLastSoundPosition(pFromDeck), + getMainCuePosition(pToDeck)); + } break; default: - useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); + if (fadeNow) { + useFixedFadeTime(pFromDeck, pToDeck, outroEnd, 0); + } else { + useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); + } } // Guard against the next track being too short. This transition must finish @@ -1010,7 +1038,7 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra // (ADJ_ENABLE_P1LOADED state) then play the track. loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } else { - calculateTransition(getOtherDeck(pDeck, true), pDeck); + calculateTransition(getOtherDeck(pDeck, true), pDeck, false); if (pDeck->startPos != kKeepPosition) { pDeck->setPlayPosition(pDeck->startPos); } @@ -1084,10 +1112,10 @@ void AutoDJProcessor::setTransitionTime(int time) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; if (leftDeck.isPlaying()) { - calculateTransition(&leftDeck, &rightDeck); + calculateTransition(&leftDeck, &rightDeck, false); } if (rightDeck.isPlaying()) { - calculateTransition(&rightDeck, &leftDeck); + calculateTransition(&rightDeck, &leftDeck, false); } } } @@ -1103,12 +1131,12 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { DeckAttributes& rightDeck = *m_decks[1]; if (leftDeck.isPlaying() && !rightDeck.isPlaying()) { - calculateTransition(&leftDeck, &rightDeck); + calculateTransition(&leftDeck, &rightDeck, false); if (rightDeck.startPos != kKeepPosition) { rightDeck.setPlayPosition(rightDeck.startPos); } } else if (rightDeck.isPlaying() && !leftDeck.isPlaying()) { - calculateTransition(&rightDeck, &leftDeck); + calculateTransition(&rightDeck, &leftDeck, false); if (leftDeck.startPos != kKeepPosition) { leftDeck.setPlayPosition(leftDeck.startPos); } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 54331cf7448..4e239af1576 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -250,7 +250,8 @@ class AutoDJProcessor : public QObject { TrackPointer getNextTrackFromQueue(); bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); void calculateTransition(DeckAttributes* pFromDeck, - DeckAttributes* pToDeck); + DeckAttributes* pToDeck, + bool fadeNow); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, From 06beddc696b37b2970cea3b3ab94fc66893ed177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 14 Jul 2019 00:24:22 +0200 Subject: [PATCH 050/198] imrove switch cases in calculateTransition() a bit --- src/library/autodj/autodjprocessor.cpp | 32 +++++++++++--------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 586488808cb..da0efd5572d 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -919,13 +919,14 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, switch (m_transitionMode) { case TransitionMode::AlignIntroOutroStart: pToDeck->startPos = introStart; - if (outroLength > 0 && introLength > 0) { + if (outroLength > 0) { pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeDuration = math_min(outroLength, introLength); - } else if (outroLength > 0 && introLength <= 0) { - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeDuration = outroLength; - } else if (outroLength <= 0 && introLength > 0) { + if (introLength > 0) { + pFromDeck->fadeDuration = math_min(outroLength, introLength); + } else { + pFromDeck->fadeDuration = outroLength; + } + } else if (introLength > 0) { pFromDeck->fadeBeginPos = outroEnd - introLength; pFromDeck->fadeDuration = introLength; } else { @@ -933,24 +934,18 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } break; case TransitionMode::AlignIntroOutroEnd: - if (outroLength > 0 && introLength > 0) { - if (outroLength < introLength) { - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeDuration = outroLength; - pToDeck->startPos = introEnd - outroLength; + if (introLength > 0) { + if (outroLength > 0) { + pFromDeck->fadeDuration = math_min(outroLength, introLength); } else { - pFromDeck->fadeBeginPos = outroEnd - introLength; pFromDeck->fadeDuration = introLength; - pToDeck->startPos = introStart; } - } else if (outroLength > 0 && introLength <= 0) { + pFromDeck->fadeBeginPos = outroEnd - pFromDeck->fadeDuration; + pToDeck->startPos = introEnd - pFromDeck->fadeDuration; + } else if (outroLength > 0) { pFromDeck->fadeBeginPos = outroStart; pFromDeck->fadeDuration = outroLength; pToDeck->startPos = introStart; - } else if (outroLength <= 0 && introLength > 0) { - pFromDeck->fadeBeginPos = outroEnd - introLength; - pFromDeck->fadeDuration = introLength; - pToDeck->startPos = introStart; } else { useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } @@ -981,6 +976,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getMainCuePosition(pToDeck)); } break; + case TransitionMode::FixedFullTrack: default: if (fadeNow) { useFixedFadeTime(pFromDeck, pToDeck, outroEnd, 0); From d80648ed8179d80f598a2f31b7783515633e6d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 14 Jul 2019 00:41:44 +0200 Subject: [PATCH 051/198] Clean up playerPositionChanged() --- src/library/autodj/autodjprocessor.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index da0efd5572d..b018825f722 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -457,12 +457,6 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, return; } - // 95% playback is when we crossfade and do stuff - // const double posThreshold = 0.95; - - // 0.05; // 5% playback is crossfade duration - const double thisFadeDuration = pAttributes->fadeDuration; - // qDebug() << "player" << pAttributes->group << "PositionChanged(" << value << ")"; if (m_eState == ADJ_DISABLED) { // nothing to do @@ -577,6 +571,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, emitAutoDJStateChanged(m_eState); } + const double thisFadeDuration = thisDeck.fadeDuration; double posFadeEnd = math_min(1.0, thisDeck.fadeBeginPos + thisFadeDuration); if (thisPlayPosition >= posFadeEnd) { // If this track has passed the end of its target fade then we stop From 29ab888eb793dc457016057e34f6a5a78155ef9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 14 Jul 2019 22:57:41 +0200 Subject: [PATCH 052/198] use fadeEndPos instead of fadeDuration, because it is more significant in case of user touching the xfader during automatic fade. --- src/library/autodj/autodjprocessor.cpp | 40 ++++++++++++-------------- src/library/autodj/autodjprocessor.h | 6 ++-- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b018825f722..fc87f3fde68 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -25,7 +25,7 @@ DeckAttributes::DeckAttributes(int index, group(pPlayer->getGroup()), startPos(kKeepPosition), fadeBeginPos(1.0), - fadeDuration(0.0), + fadeEndPos(1.0), loading(false), m_orientation(orientation), m_playPos(group, "playposition"), @@ -534,7 +534,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // This avoids starting a fade back before the new track is // loaded into the otherDeck thisDeck.fadeBeginPos = 1.0; - thisDeck.fadeDuration = 0.0; + thisDeck.fadeEndPos = 1.0; // Load the next track to otherDeck. loadNextTrackFromQueue(otherDeck); emitAutoDJStateChanged(m_eState); @@ -571,9 +571,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, emitAutoDJStateChanged(m_eState); } - const double thisFadeDuration = thisDeck.fadeDuration; - double posFadeEnd = math_min(1.0, thisDeck.fadeBeginPos + thisFadeDuration); - if (thisPlayPosition >= posFadeEnd) { + if (thisPlayPosition >= thisDeck.fadeEndPos) { // If this track has passed the end of its target fade then we stop // it. We don't handle mode switches here since that's handled by // the next playerPositionChanged call otherDeck (see the @@ -589,7 +587,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // adjustment. double crossfadeEdgeValue = -1.0; double adjustment = 2 * (thisPlayPosition - thisDeck.fadeBeginPos) / - (posFadeEnd - thisDeck.fadeBeginPos); + (thisDeck.fadeEndPos - thisDeck.fadeBeginPos); bool isLeft = thisDeck.isLeft(); if (!isLeft) { crossfadeEdgeValue = 1.0; @@ -852,7 +850,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // Playing Track has no duration. This should not happen, because short // tracks are skipped after load. Play ToDeck emmediately. pFromDeck->fadeBeginPos = 0; - pFromDeck->fadeDuration = 0; + pFromDeck->fadeEndPos = 0; pToDeck->startPos = kKeepPosition; return; } @@ -917,29 +915,29 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, if (outroLength > 0) { pFromDeck->fadeBeginPos = outroStart; if (introLength > 0) { - pFromDeck->fadeDuration = math_min(outroLength, introLength); + pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + math_min(outroLength, introLength); } else { - pFromDeck->fadeDuration = outroLength; + pFromDeck->fadeEndPos = outroEnd; } } else if (introLength > 0) { pFromDeck->fadeBeginPos = outroEnd - introLength; - pFromDeck->fadeDuration = introLength; + pFromDeck->fadeEndPos = outroEnd; } else { useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } break; case TransitionMode::AlignIntroOutroEnd: if (introLength > 0) { + pFromDeck->fadeEndPos = outroEnd; if (outroLength > 0) { - pFromDeck->fadeDuration = math_min(outroLength, introLength); + pFromDeck->fadeBeginPos = pFromDeck->fadeEndPos - math_min(outroLength, introLength); } else { - pFromDeck->fadeDuration = introLength; + pFromDeck->fadeBeginPos = math_max(pFromDeck->fadeEndPos - introLength, 0.0); } - pFromDeck->fadeBeginPos = outroEnd - pFromDeck->fadeDuration; - pToDeck->startPos = introEnd - pFromDeck->fadeDuration; + pToDeck->startPos = introEnd - (pFromDeck->fadeEndPos - pFromDeck->fadeBeginPos); } else if (outroLength > 0) { pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeDuration = outroLength; + pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else { useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); @@ -987,13 +985,13 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, toDeckOutroStart = getOutroEndPosition(pToDeck); } double maxFadeTime = toDeckOutroStart - pToDeck->startPos; - if (pFromDeck->fadeDuration > maxFadeTime) { - pFromDeck->fadeDuration = maxFadeTime; + if ((pFromDeck->fadeEndPos - pFromDeck->fadeBeginPos) > maxFadeTime) { + pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + maxFadeTime; } // These are expected to be a fraction of the track length. pFromDeck->fadeBeginPos /= fromTrackDuration; - pFromDeck->fadeDuration /= fromTrackDuration; + pFromDeck->fadeEndPos /= fromTrackDuration; pToDeck->startPos /= toTrackDuration; } @@ -1001,12 +999,12 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes double endPoint, double startPoint) { if (m_transitionTime > 0.0) { pFromDeck->fadeBeginPos = endPoint - m_transitionTime; - pFromDeck->fadeDuration = m_transitionTime; + pFromDeck->fadeEndPos = endPoint; pToDeck->startPos = startPoint; } else { pFromDeck->fadeBeginPos = endPoint; - pFromDeck->fadeDuration = m_transitionTime; - pToDeck->startPos = startPoint + m_transitionTime; + pFromDeck->fadeEndPos = endPoint + m_transitionTime;; + pToDeck->startPos = startPoint - m_transitionTime; } } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 4e239af1576..49c6ae8859e 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -113,9 +113,9 @@ class DeckAttributes : public QObject { public: int index; QString group; - double startPos; - double fadeBeginPos; - double fadeDuration; + double startPos; // Set in toDeck nature + double fadeBeginPos; // set in fromDeck nature + double fadeEndPos; // set in fromDeck nature bool loading; // The data is inconsitence during loading a deck private: From eaca9ffb00ddcb480fd616c9f9cd3da8123951c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 14 Jul 2019 23:30:19 +0200 Subject: [PATCH 053/198] improve debug --- src/library/autodj/autodjprocessor.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index fc87f3fde68..3b173381c26 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -448,8 +448,8 @@ void AutoDJProcessor::controlSkipNext(double value) { void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, double thisPlayPosition) { if (sDebug) { - qDebug() << this << "playerPositionChanged" << pAttributes->group - << thisPlayPosition; + //qDebug() << this << "playerPositionChanged" << pAttributes->group + // << thisPlayPosition; } // Auto-DJ needs at least two decks @@ -993,6 +993,11 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeBeginPos /= fromTrackDuration; pFromDeck->fadeEndPos /= fromTrackDuration; pToDeck->startPos /= toTrackDuration; + + if (sDebug) { + qDebug() << this << pFromDeck->fadeBeginPos << pFromDeck->fadeEndPos + << pToDeck->startPos; + } } void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, From f64084634a8d88c2339ececcc9a53f832c1cd3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 16 Jul 2019 22:36:29 +0200 Subject: [PATCH 054/198] Intergate short track checks into conditional blocks of fade modes --- src/library/autodj/autodjprocessor.cpp | 48 +++++++++++++++----------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 3b173381c26..d2f7463c5f5 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -914,8 +914,11 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = introStart; if (outroLength > 0) { pFromDeck->fadeBeginPos = outroStart; - if (introLength > 0) { - pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + math_min(outroLength, introLength); + if (introLength > 0 && introLength < outroLength) { + pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + introLength; + } else if (pToDeck->startPos + outroLength >= toTrackDuration) { + pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + + toTrackDuration - pToDeck->startPos; } else { pFromDeck->fadeEndPos = outroEnd; } @@ -936,9 +939,14 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } pToDeck->startPos = introEnd - (pFromDeck->fadeEndPos - pFromDeck->fadeBeginPos); } else if (outroLength > 0) { - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; + pFromDeck->fadeEndPos = outroEnd; + if (pToDeck->startPos + outroLength >= toTrackDuration) { + pFromDeck->fadeBeginPos = pFromDeck->fadeEndPos - + toTrackDuration + pToDeck->startPos; + } else { + pFromDeck->fadeBeginPos = outroStart; + } } else { useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } @@ -978,17 +986,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } } - // Guard against the next track being too short. This transition must finish - // before the next one starts. - double toDeckOutroStart = getOutroStartPosition(pToDeck); - if (toDeckOutroStart <= 0) { - toDeckOutroStart = getOutroEndPosition(pToDeck); - } - double maxFadeTime = toDeckOutroStart - pToDeck->startPos; - if ((pFromDeck->fadeEndPos - pFromDeck->fadeBeginPos) > maxFadeTime) { - pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + maxFadeTime; - } - // These are expected to be a fraction of the track length. pFromDeck->fadeBeginPos /= fromTrackDuration; pFromDeck->fadeEndPos /= fromTrackDuration; @@ -1000,16 +997,27 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } } -void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, - double endPoint, double startPoint) { +void AutoDJProcessor::useFixedFadeTime( + DeckAttributes* pFromDeck, + DeckAttributes* pToDeck, + double endPoint, + double startPoint) { if (m_transitionTime > 0.0) { - pFromDeck->fadeBeginPos = endPoint - m_transitionTime; + // Guard against the next track being too short. This transition must finish + // before the next one starts. + double toDeckOutroStart = getOutroStartPosition(pToDeck); + if (toDeckOutroStart <= 0) { + toDeckOutroStart = math_min(getOutroEndPosition(pToDeck), pToDeck->duration() / 2); + } + double transitionTime = math_min(toDeckOutroStart - startPoint, m_transitionTime); + + pFromDeck->fadeBeginPos = endPoint - transitionTime; pFromDeck->fadeEndPos = endPoint; pToDeck->startPos = startPoint; } else { pFromDeck->fadeBeginPos = endPoint; - pFromDeck->fadeEndPos = endPoint + m_transitionTime;; - pToDeck->startPos = startPoint - m_transitionTime; + pFromDeck->fadeEndPos = endPoint - m_transitionTime; + pToDeck->startPos = startPoint + m_transitionTime; } } From 6850e7f36e13c37e21a931c5cc3dcf039c1ff7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 16 Jul 2019 22:50:37 +0200 Subject: [PATCH 055/198] Rename ADJ_P1/2FADING to ADJ_LEFT/RIGHT_FADING --- src/library/autodj/autodjprocessor.cpp | 6 +-- src/library/autodj/autodjprocessor.h | 4 +- src/library/autodj/dlgautodj.cpp | 4 +- src/test/autodjprocessor_test.cpp | 58 +++++++++++++------------- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index d2f7463c5f5..134e5493000 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -519,8 +519,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // from (P1 or P2) to stop playing. Once we are playing and the other deck // is not playing -- we switch the crossfader fully to this deck's side, // switch to IDLE mode and load the next track into the other deck. - if ((m_eState == ADJ_P1FADING && thisDeck.isRight()) || - (m_eState == ADJ_P2FADING && thisDeck.isLeft())) { + if ((m_eState == ADJ_LEFT_FADING && thisDeck.isRight()) || + (m_eState == ADJ_RIGHT_FADING && thisDeck.isLeft())) { // Once P1 or P2 has stopped switch out of fading mode to idle. if (thisDeckPlaying && !otherDeckPlaying) { // Force crossfader all the way to this side. @@ -567,7 +567,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, removeLoadedTrackFromTopOfQueue(otherDeck); // Set the state as FADING. - m_eState = thisDeck.isLeft() ? ADJ_P1FADING : ADJ_P2FADING; + m_eState = thisDeck.isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; emitAutoDJStateChanged(m_eState); } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 49c6ae8859e..be4dbffb236 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -137,8 +137,8 @@ class AutoDJProcessor : public QObject { public: enum AutoDJState { ADJ_IDLE = 0, - ADJ_P1FADING, - ADJ_P2FADING, + ADJ_LEFT_FADING, + ADJ_RIGHT_FADING, ADJ_ENABLE_P1LOADED, ADJ_ENABLE_P1PLAYING, ADJ_DISABLED diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 8389ee04de2..566df0cc25f 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -208,8 +208,8 @@ void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) { pushButtonAutoDJ->setText(tr("Disable Auto DJ")); // If fading, you can't hit fade now. - if (state == AutoDJProcessor::ADJ_P1FADING || - state == AutoDJProcessor::ADJ_P2FADING || + if (state == AutoDJProcessor::ADJ_LEFT_FADING || + state == AutoDJProcessor::ADJ_RIGHT_FADING || state == AutoDJProcessor::ADJ_ENABLE_P1LOADED) { pushButtonFadeNow->setEnabled(false); } else { diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 1d2e3659c50..715dcdd56dd 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -733,13 +733,13 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); - // Expect that we will transition into P2FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P2FADING)); + // Expect that we will transition into RIGHT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_RIGHT_FADING)); // Pretend the track is over (should trigger an instant-fade). deck2.playposition.set(1.0); - EXPECT_EQ(AutoDJProcessor::ADJ_P2FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_RIGHT_FADING, pProcessor->getState()); EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); @@ -815,13 +815,13 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); - // Expect that we will transition into P2FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P2FADING)); + // Expect that we will transition into RIGHT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_RIGHT_FADING)); // Pretend the track is over (should trigger an instant-fade). deck2.playposition.set(1.0); - EXPECT_EQ(AutoDJProcessor::ADJ_P2FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_RIGHT_FADING, pProcessor->getState()); EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); @@ -909,13 +909,13 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - // Expect that we will transition into P1FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P1FADING)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Pretend the track is over (should trigger an instant-fade). deck1.playposition.set(1.0); - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); @@ -991,13 +991,13 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - // Expect that we will transition into P1FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P1FADING)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Pretend the track is over (should trigger an instant-fade). deck1.playposition.set(1.0); - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); @@ -1090,12 +1090,12 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - // Expect that we will transition into P1FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P1FADING)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Seek track to 55 % it should fade deck1.playposition.set(0.55); - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); EXPECT_LT(-1.0, master.crossfader.get()); @@ -1107,7 +1107,7 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { // Seek track to End deck1.playposition.set(1.0); - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); qDebug() << "master.crossfader.get()" << master.crossfader.get(); @@ -1163,14 +1163,14 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - // Expect that we will transition into P1FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P1FADING)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Seek track in deck1 to its end. deck1.playposition.set(1.0); - // We should have transitioned into P1FADING. - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + // We should have transitioned into LEFT_FADING. + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); // The track should have been seeked back by the duration of transition. EXPECT_DOUBLE_EQ(-0.1, deck2.playposition.get()); @@ -1227,13 +1227,13 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { // Seek deck 2 to the very end 99 % deck2.playposition.set(0.99); - // Expect that we will transition into P1FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P1FADING)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Seek track to 99 % it should fade // not 100 % because the final step is done by deck2 deck1.playposition.set(0.99); - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); EXPECT_LT(-1.0, master.crossfader.get()); @@ -1295,12 +1295,12 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectIntroCue) { EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - // Expect that we will transition into P1FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P1FADING)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Seek the outgoing track to where outro end cue is placed. It should fade. deck1.playposition.set(0.9); - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); // The incoming track should have been seeked back. EXPECT_DOUBLE_EQ(-0.15, deck2.playposition.get()); @@ -1371,12 +1371,12 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectOutroCue) { EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - // Expect that we will transition into P1FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_P1FADING)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Seek track to 55 %. It should fade. deck1.playposition.set(0.55); - EXPECT_EQ(AutoDJProcessor::ADJ_P1FADING, pProcessor->getState()); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); EXPECT_LT(-1.0, master.crossfader.get()); From 499146a8ddb155f9e6b97dd44b3df1298a8fde79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 17 Jul 2019 00:20:45 +0200 Subject: [PATCH 056/198] stop transition if toDeck track OR fromDeck track is too short. --- src/library/autodj/autodjprocessor.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 134e5493000..7011fb69f26 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -515,16 +515,17 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, return; } - // In P1FADING/P2FADING states, we are waiting for the deck we are fading - // from (P1 or P2) to stop playing. Once we are playing and the other deck - // is not playing -- we switch the crossfader fully to this deck's side, + // In FADING states, we expect that both tracks are playing. + // Normally the the fading fromDeck stops after the transition is over and + // we need to replace it with a new track from the cue. In the rare case the + // toDeck stops first, we replace this one and stop the transition. + // Than we switch the crossfader fully to the new track side, // switch to IDLE mode and load the next track into the other deck. - if ((m_eState == ADJ_LEFT_FADING && thisDeck.isRight()) || - (m_eState == ADJ_RIGHT_FADING && thisDeck.isLeft())) { + if (m_eState == ADJ_LEFT_FADING || m_eState == ADJ_RIGHT_FADING) { // Once P1 or P2 has stopped switch out of fading mode to idle. - if (thisDeckPlaying && !otherDeckPlaying) { - // Force crossfader all the way to this side. - if (thisDeck.isLeft()) { + if (!otherDeckPlaying) { + // Force crossfader all the way to the (non fading) toDeck. + if (m_eState == ADJ_RIGHT_FADING) { setCrossfader(-1.0, false); } else { setCrossfader(1.0, true); From 6f98fd42a2cd0653b8780dc5f00f15545ea27eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 20 Jul 2019 22:10:32 +0200 Subject: [PATCH 057/198] Respect manual xfader changes in case of Auto DJ is fading as well. Fixing lp995982 --- src/library/autodj/autodjprocessor.cpp | 95 +++++++++++++------------- src/library/autodj/autodjprocessor.h | 3 +- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 7011fb69f26..a2e2fc9a505 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -97,15 +97,16 @@ TrackPointer DeckAttributes::getLoadedTrack() const { } AutoDJProcessor::AutoDJProcessor(QObject* pParent, - UserSettingsPointer pConfig, - PlayerManagerInterface* pPlayerManager, - int iAutoDJPlaylistId, - TrackCollection* pTrackCollection) + UserSettingsPointer pConfig, + PlayerManagerInterface* pPlayerManager, + int iAutoDJPlaylistId, + TrackCollection* pTrackCollection) : QObject(pParent), m_pConfig(pConfig), m_pPlayerManager(pPlayerManager), m_pAutoDJTableModel(NULL), m_eState(ADJ_DISABLED), + m_transitionProgress(0.0), m_transitionTime(kTransitionPreferenceDefault) { m_pAutoDJTableModel = new PlaylistTableModel(this, pTrackCollection, "mixxx.db.model.autodj"); @@ -185,23 +186,11 @@ double AutoDJProcessor::getCrossfader() const { return m_pCOCrossfader->get(); } -void AutoDJProcessor::setCrossfader(double value, bool right) { +void AutoDJProcessor::setCrossfader(double value) { if (m_pCOCrossfaderReverse->get() > 0.0) { value *= -1.0; - right = !right; - } - double current_value = m_pCOCrossfader->get(); - if (right) { - // ignore if we move slider left - if (value > current_value) { - m_pCOCrossfader->set(value); - } - } else { - // ignore if we move slider right - if (value < current_value) { - m_pCOCrossfader->set(value); - } } + m_pCOCrossfader->set(value); } AutoDJProcessor::AutoDJError AutoDJProcessor::shufflePlaylist( @@ -382,7 +371,7 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { m_eState = ADJ_ENABLE_P1LOADED; // Move crossfader to the left. - setCrossfader(-1.0, false); + setCrossfader(-1.0); // Load track into the left deck and play. Once it starts playing, // we will receive a playerPositionChanged update for deck 1 which @@ -398,14 +387,14 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { // Load track into the right deck. emitLoadTrackToPlayer(nextTrack, deck2.group, false); // Move crossfader to the left. - setCrossfader(-1.0, false); + setCrossfader(-1.0); } else { // Update fade thresholds for the right deck. calculateTransition(&deck2, &deck1, false); // Load track into the left deck. emitLoadTrackToPlayer(nextTrack, deck1.group, false); // Move crossfader to the right. - setCrossfader(1.0, true); + setCrossfader(1.0); } } emitAutoDJStateChanged(m_eState); @@ -526,9 +515,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (!otherDeckPlaying) { // Force crossfader all the way to the (non fading) toDeck. if (m_eState == ADJ_RIGHT_FADING) { - setCrossfader(-1.0, false); + setCrossfader(-1.0); } else { - setCrossfader(1.0, true); + setCrossfader(1.0); } m_eState = ADJ_IDLE; // Invalidate threshold calculated for the old otherDeck @@ -539,8 +528,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // Load the next track to otherDeck. loadNextTrackFromQueue(otherDeck); emitAutoDJStateChanged(m_eState); + return; } - return; } if (m_eState == ADJ_IDLE && thisDeck.isRepeat()) { @@ -550,16 +539,12 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // If we are past this deck's posThreshold then: // - transition into fading mode, play the other deck and fade to it. - // - check if we've passed the fade end point and stop the deck + // - check if fading is done and stop the deck // - update the crossfader - // TODO(rryan): We need to investigate the chain of events that occur when - // the track we are fading to crosses its posThreshold before we are done - // fading to it. if (thisPlayPosition >= thisDeck.fadeBeginPos) { if (m_eState == ADJ_IDLE && (thisDeckPlaying || - thisDeck.fadeBeginPos >= 1.0)) { + thisPlayPosition >= 1.0)) { if (!otherDeckPlaying) { - calculateTransition(&otherDeck, &thisDeck, false); otherDeck.play(); } @@ -567,34 +552,50 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // that was "on deck" from the top of the queue. removeLoadedTrackFromTopOfQueue(otherDeck); + m_transitionProgress = 0.0; // Set the state as FADING. m_eState = thisDeck.isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; emitAutoDJStateChanged(m_eState); } - if (thisPlayPosition >= thisDeck.fadeEndPos) { - // If this track has passed the end of its target fade then we stop - // it. We don't handle mode switches here since that's handled by + double crossfaderTarget; + if (m_eState == ADJ_LEFT_FADING) { + crossfaderTarget = 1.0; + } else if (m_eState == ADJ_RIGHT_FADING) { + crossfaderTarget = -1.0; + } else { + // this happens if the not playing track is cued into the autro region, + // calulated for the swapped rolls. + return; + } + + double currentCrossfader = getCrossfader(); + + if (currentCrossfader == crossfaderTarget) { + // We are done, the fading (from) track is silenced. + // We don't handle mode switches here since that's handled by // the next playerPositionChanged call otherDeck (see the // P1/P2FADING case above). thisDeck.stop(); } else { - // We are past this deck's posThreshold but before its - // posThreshold+fadeDuration, we move the crossfader linearly with - // movements in this track's play position. - - // If thisDeck is left, the new crossfade value is -1 plus the - // adjustment. If thisDeck is right, the new value is 1.0 minus the - // adjustment. - double crossfadeEdgeValue = -1.0; - double adjustment = 2 * (thisPlayPosition - thisDeck.fadeBeginPos) / + // We are in Fading state. + // Calcuate the current transitionProgress, the place between begin + // and end position and the step we have taken since the last call + double transitionProgress = (thisPlayPosition - thisDeck.fadeBeginPos) / (thisDeck.fadeEndPos - thisDeck.fadeBeginPos); - bool isLeft = thisDeck.isLeft(); - if (!isLeft) { - crossfadeEdgeValue = 1.0; - adjustment *= -1.0; + double transitionStep = transitionProgress - m_transitionProgress; + if (transitionStep > 0.0) { + // We have made progress. Beackwards seek pause the transitions + // forward seeks speed up the transitions. Seeks > EndPos end the + // transition immediately + double remainingCrossfader = crossfaderTarget - currentCrossfader; + double adjustment = remainingCrossfader / + (1.0 - m_transitionProgress) * transitionStep; + // we move the crossfader linearly with + // movements in this track's play position. + setCrossfader(currentCrossfader + adjustment); } - setCrossfader(crossfadeEdgeValue + adjustment, isLeft); + m_transitionProgress = transitionProgress; } } } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index be4dbffb236..ca629b768c5 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -234,7 +234,7 @@ class AutoDJProcessor : public QObject { // right side. (prevents AutoDJ logic from having to check for hamster mode // every time) double getCrossfader() const; - void setCrossfader(double value, bool right); + void setCrossfader(double value); // Following functions return seconds computed from samples or -1 if // track in deck has invalid sample rate (<= 0) @@ -270,6 +270,7 @@ class AutoDJProcessor : public QObject { PlaylistTableModel* m_pAutoDJTableModel; AutoDJState m_eState; + double m_transitionProgress; double m_transitionTime; // the desired value set by the user TransitionMode m_transitionMode; From 825912c00dd4e9b5fac66cacd6ea0665437db084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 21 Jul 2019 22:32:50 +0200 Subject: [PATCH 058/198] Adopt current position as new fade start point in case of manual cue-ing of the paused deck. --- src/library/autodj/autodjprocessor.cpp | 85 ++++++++++++++------------ src/library/autodj/autodjprocessor.h | 3 +- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index a2e2fc9a505..5f84ac3400a 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -219,12 +219,12 @@ void AutoDJProcessor::fadeNow() { if (leftDeck.isPlaying() && (!rightDeck.isPlaying() || crossfader < 0.0)) { // Make sure leftDeck.fadeDuration is up to date. - calculateTransition(&leftDeck, &rightDeck, true); + calculateTransition(&leftDeck, &rightDeck, true, false); // Repeat is disabled by FadeNow but disables auto Fade leftDeck.setRepeat(false); } else if (rightDeck.isPlaying()) { // Make sure rightDeck.fadeDuration is up to date. - calculateTransition(&rightDeck, &leftDeck, true); + calculateTransition(&rightDeck, &leftDeck, true, false); // Repeat is disabled by FadeNow but disables auto Fade rightDeck.setRepeat(false); } @@ -382,15 +382,11 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { // until the playing deck crosses posThreshold to start fading. m_eState = ADJ_IDLE; if (deck1Playing) { - // Update fade thresholds for the left deck. - calculateTransition(&deck1, &deck2, false); // Load track into the right deck. emitLoadTrackToPlayer(nextTrack, deck2.group, false); // Move crossfader to the left. setCrossfader(-1.0); } else { - // Update fade thresholds for the right deck. - calculateTransition(&deck2, &deck1, false); // Load track into the left deck. emitLoadTrackToPlayer(nextTrack, deck1.group, false); // Move crossfader to the right. @@ -495,9 +491,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // Note: calculateTransition() is called in playerTrackLoaded() } else { - // At least right Deck is playing + // At least right deck is playing // Set crossfade thresholds for right deck. - calculateTransition(&rightDeck, &leftDeck, false); + calculateTransition(&rightDeck, &leftDeck, false, false); } emitAutoDJStateChanged(m_eState); } @@ -532,9 +528,15 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } } - if (m_eState == ADJ_IDLE && thisDeck.isRepeat()) { - // repeat pauses auto DJ - return; + if (m_eState == ADJ_IDLE) { + if (!thisDeckPlaying) { + // this is a cueing seek, recalculate the transition, from the + // new position + calculateTransition(&otherDeck, &thisDeck, false, false); + } else if (thisDeck.isRepeat()) { + // repeat pauses auto DJ + return; + } } // If we are past this deck's posThreshold then: @@ -542,20 +544,21 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // - check if fading is done and stop the deck // - update the crossfader if (thisPlayPosition >= thisDeck.fadeBeginPos) { - if (m_eState == ADJ_IDLE && (thisDeckPlaying || - thisPlayPosition >= 1.0)) { - if (!otherDeckPlaying) { - otherDeck.play(); - } + if (m_eState == ADJ_IDLE) { + if (thisDeckPlaying || thisPlayPosition >= 1.0) { + if (!otherDeckPlaying) { + otherDeck.play(); + } - // Now that we have started the other deck playing, remove the track - // that was "on deck" from the top of the queue. - removeLoadedTrackFromTopOfQueue(otherDeck); + // Now that we have started the other deck playing, remove the track + // that was "on deck" from the top of the queue. + removeLoadedTrackFromTopOfQueue(otherDeck); - m_transitionProgress = 0.0; - // Set the state as FADING. - m_eState = thisDeck.isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; - emitAutoDJStateChanged(m_eState); + m_transitionProgress = 0.0; + // Set the state as FADING. + m_eState = thisDeck.isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; + emitAutoDJStateChanged(m_eState); + } } double crossfaderTarget; @@ -714,7 +717,7 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* pAttributes, bool playin // This is required because the user may have loaded a track or changed play // manually if (playing) { - calculateTransition(pAttributes, getOtherDeck(pAttributes), false); + calculateTransition(pAttributes, getOtherDeck(pAttributes), false, false); } } @@ -724,7 +727,7 @@ void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, doubl } if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false); + calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false, false); } } @@ -734,7 +737,7 @@ void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double } if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false); + calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false, false); } } @@ -744,7 +747,7 @@ void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, doubl } if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false); + calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false, false); } } @@ -754,7 +757,7 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double } if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false); + calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false, false); } } @@ -828,7 +831,8 @@ double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttri void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, - bool fadeNow) { + bool fadeNow, + bool seek) { if (pFromDeck == nullptr) { return; } @@ -892,13 +896,18 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroLength = outroEnd - outroStart; - double introStart = getIntroStartPosition(pToDeck); - if (introStart <= 0.0) { - introStart = getFirstSoundPosition(pToDeck); + double introStart; + if (seek) { + introStart = getIntroStartPosition(pToDeck); + if (introStart <= 0.0) { + introStart = getFirstSoundPosition(pToDeck); + } + } else { + introStart = pToDeck->playPosition() * toTrackDuration; } double introEnd = getIntroEndPosition(pToDeck); - if (introEnd <= 0.0) { + if (introEnd < introStart) { introEnd = introStart; } @@ -1042,7 +1051,7 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra // (ADJ_ENABLE_P1LOADED state) then play the track. loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } else { - calculateTransition(getOtherDeck(pDeck, true), pDeck, false); + calculateTransition(getOtherDeck(pDeck, true), pDeck, false, true); if (pDeck->startPos != kKeepPosition) { pDeck->setPlayPosition(pDeck->startPos); } @@ -1116,10 +1125,10 @@ void AutoDJProcessor::setTransitionTime(int time) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; if (leftDeck.isPlaying()) { - calculateTransition(&leftDeck, &rightDeck, false); + calculateTransition(&leftDeck, &rightDeck, false, false); } if (rightDeck.isPlaying()) { - calculateTransition(&rightDeck, &leftDeck, false); + calculateTransition(&rightDeck, &leftDeck, false, false); } } } @@ -1135,12 +1144,12 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { DeckAttributes& rightDeck = *m_decks[1]; if (leftDeck.isPlaying() && !rightDeck.isPlaying()) { - calculateTransition(&leftDeck, &rightDeck, false); + calculateTransition(&leftDeck, &rightDeck, false, true); if (rightDeck.startPos != kKeepPosition) { rightDeck.setPlayPosition(rightDeck.startPos); } } else if (rightDeck.isPlaying() && !leftDeck.isPlaying()) { - calculateTransition(&rightDeck, &leftDeck, false); + calculateTransition(&rightDeck, &leftDeck, false, true); if (leftDeck.startPos != kKeepPosition) { leftDeck.setPlayPosition(leftDeck.startPos); } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index ca629b768c5..9560b4829c3 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -251,7 +251,8 @@ class AutoDJProcessor : public QObject { bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); void calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, - bool fadeNow); + bool fadeNow, + bool seek); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, From 6e7f17177d2c060d040833ea72415368e583baba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 22 Jul 2019 21:50:23 +0200 Subject: [PATCH 059/198] fix typos --- src/library/autodj/autodjprocessor.cpp | 16 ++++++++-------- src/library/autodj/autodjprocessor.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 5f84ac3400a..f6f86b66e3a 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -502,9 +502,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // In FADING states, we expect that both tracks are playing. // Normally the the fading fromDeck stops after the transition is over and - // we need to replace it with a new track from the cue. In the rare case the + // we need to replace it with a new track from the queue. In the rare case the // toDeck stops first, we replace this one and stop the transition. - // Than we switch the crossfader fully to the new track side, + // Then we switch the crossfader fully to the new track side, // switch to IDLE mode and load the next track into the other deck. if (m_eState == ADJ_LEFT_FADING || m_eState == ADJ_RIGHT_FADING) { // Once P1 or P2 has stopped switch out of fading mode to idle. @@ -567,8 +567,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } else if (m_eState == ADJ_RIGHT_FADING) { crossfaderTarget = -1.0; } else { - // this happens if the not playing track is cued into the autro region, - // calulated for the swapped rolls. + // this happens if the not playing track is cued into the outro region, + // calculated for the swapped roles. return; } @@ -582,13 +582,13 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, thisDeck.stop(); } else { // We are in Fading state. - // Calcuate the current transitionProgress, the place between begin + // Calculate the current transitionProgress, the place between begin // and end position and the step we have taken since the last call double transitionProgress = (thisPlayPosition - thisDeck.fadeBeginPos) / (thisDeck.fadeEndPos - thisDeck.fadeBeginPos); double transitionStep = transitionProgress - m_transitionProgress; if (transitionStep > 0.0) { - // We have made progress. Beackwards seek pause the transitions + // We have made progress. Backwards seek pause the transitions // forward seeks speed up the transitions. Seeks > EndPos end the // transition immediately double remainingCrossfader = crossfaderTarget - currentCrossfader; @@ -854,7 +854,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { // Playing Track has no duration. This should not happen, because short - // tracks are skipped after load. Play ToDeck emmediately. + // tracks are skipped after load. Play ToDeck immediately. pFromDeck->fadeBeginPos = 0; pFromDeck->fadeEndPos = 0; pToDeck->startPos = kKeepPosition; @@ -1154,7 +1154,7 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { leftDeck.setPlayPosition(leftDeck.startPos); } } else { - // user has manually started the other deck or dtopped both. + // user has manually started the other deck or stopped both. // don't know what to do. } } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 9560b4829c3..a5fd6dbcd22 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -116,7 +116,7 @@ class DeckAttributes : public QObject { double startPos; // Set in toDeck nature double fadeBeginPos; // set in fromDeck nature double fadeEndPos; // set in fromDeck nature - bool loading; // The data is inconsitence during loading a deck + bool loading; // The data is inconsistent during loading a deck private: EngineChannel::ChannelOrientation m_orientation; From 71c7acf243cd0b2970245227397cb4ea6573d380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 22 Jul 2019 22:05:34 +0200 Subject: [PATCH 060/198] improve comments --- src/library/autodj/autodjprocessor.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index f6f86b66e3a..3103402285c 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -588,9 +588,10 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, (thisDeck.fadeEndPos - thisDeck.fadeBeginPos); double transitionStep = transitionProgress - m_transitionProgress; if (transitionStep > 0.0) { - // We have made progress. Backwards seek pause the transitions - // forward seeks speed up the transitions. Seeks > EndPos end the - // transition immediately + // We have made progress. + // Backward seeks pause the transitions; forward seeks speed up + // the transitions. If there has been a seek beyond endPos, end + // the transition immediately." double remainingCrossfader = crossfaderTarget - currentCrossfader; double adjustment = remainingCrossfader / (1.0 - m_transitionProgress) * transitionStep; @@ -890,6 +891,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else { outroStart = getOutroStartPosition(pFromDeck); if (outroStart <= 0.0) { + // Assume a zero length outro. + // The outroEnd is automatically placed by AnalyzerSilence, so use + // that as a fallback if the user has not placed outroStart". outroStart = outroEnd; } } @@ -908,6 +912,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double introEnd = getIntroEndPosition(pToDeck); if (introEnd < introStart) { + // introEnd is invalid. Assume a zero length intro. + // The introStart is automatically placed by AnalyzerSilence, so use + // that as a fallback if the user has not placed introEnd. introEnd = introStart; } From 032dc1f876cb8006fd7e53f7308defeb02e74703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 22 Jul 2019 22:53:59 +0200 Subject: [PATCH 061/198] remove stray " --- src/library/autodj/autodjprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 3103402285c..ca4a4d4eb11 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -591,7 +591,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // We have made progress. // Backward seeks pause the transitions; forward seeks speed up // the transitions. If there has been a seek beyond endPos, end - // the transition immediately." + // the transition immediately. double remainingCrossfader = crossfaderTarget - currentCrossfader; double adjustment = remainingCrossfader / (1.0 - m_transitionProgress) * transitionStep; From d212dd9086824ecf07f441f1af414abe6f9786a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 23 Jul 2019 00:12:32 +0200 Subject: [PATCH 062/198] Fix issue that Woverview displays an outdated playposition --- src/widget/woverview.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index fcd9e4c47cd..63a32bd8b76 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -170,16 +170,21 @@ void WOverview::setup(const QDomNode& node, const SkinContext& context) { } void WOverview::onConnectedControlChanged(double dParameter, double dValue) { + Q_UNUSED(dParameter); Q_UNUSED(dValue); if (!m_bDrag) { + // Use fresh value, in case the value received by this slot is already outdated + ControlParameterWidgetConnection* defaultConnection = m_connections.at(0); + double parameter = defaultConnection->getControlParameter(); + // Calculate handle position. Clamp the value within 0-1 because that's // all we represent with this widget. - dParameter = math_clamp(dParameter, 0.0, 1.0); + parameter = math_clamp(parameter, 0.0, 1.0); - int iPos = valueToPosition(dParameter); + int iPos = valueToPosition(parameter); if (iPos != m_iPos) { m_iPos = iPos; - //qDebug() << "WOverview::onConnectedControlChanged" << dParameter << ">>" << m_iPos; + qDebug() << "WOverview::onConnectedControlChanged" << parameter << ">>" << m_iPos; update(); } } From e109bf18e0d970dd530734628a4f06a75e80ae0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 23 Jul 2019 00:23:31 +0200 Subject: [PATCH 063/198] Improve comments more --- src/library/autodj/autodjprocessor.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index ca4a4d4eb11..b94c6df8acc 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -531,7 +531,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (m_eState == ADJ_IDLE) { if (!thisDeckPlaying) { // this is a cueing seek, recalculate the transition, from the - // new position + // new position. + // This can be our own seek to startPos or a random seek by a user. + // we need to call calculateTransition() because we are not sure. calculateTransition(&otherDeck, &thisDeck, false, false); } else if (thisDeck.isRepeat()) { // repeat pauses auto DJ @@ -893,7 +895,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, if (outroStart <= 0.0) { // Assume a zero length outro. // The outroEnd is automatically placed by AnalyzerSilence, so use - // that as a fallback if the user has not placed outroStart". + // that as a fallback if the user has not placed outroStart. outroStart = outroEnd; } } @@ -1060,6 +1062,8 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra } else { calculateTransition(getOtherDeck(pDeck, true), pDeck, false, true); if (pDeck->startPos != kKeepPosition) { + // Note: this seek will trigger the playerPositionChanged slot + // which may calls the calculateTransition() again without seek = true; pDeck->setPlayPosition(pDeck->startPos); } } @@ -1153,11 +1157,15 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { if (leftDeck.isPlaying() && !rightDeck.isPlaying()) { calculateTransition(&leftDeck, &rightDeck, false, true); if (rightDeck.startPos != kKeepPosition) { + // Note: this seek will trigger the playerPositionChanged slot + // which may calls the calculateTransition() again without seek = true; rightDeck.setPlayPosition(rightDeck.startPos); } } else if (rightDeck.isPlaying() && !leftDeck.isPlaying()) { calculateTransition(&rightDeck, &leftDeck, false, true); if (leftDeck.startPos != kKeepPosition) { + // Note: this seek will trigger the playerPositionChanged slot + // which may calls the calculateTransition() again without seek = true; leftDeck.setPlayPosition(leftDeck.startPos); } } else { From c7a1d1d03a640bada335a35ba3fcdc0da780fd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 23 Jul 2019 08:17:38 +0200 Subject: [PATCH 064/198] rename parameter seek to seekToStartPoint --- src/library/autodj/autodjprocessor.cpp | 4 ++-- src/library/autodj/autodjprocessor.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b94c6df8acc..b713de8cedf 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -835,7 +835,7 @@ double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttri void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, bool fadeNow, - bool seek) { + bool seekToStartPoint) { if (pFromDeck == nullptr) { return; } @@ -903,7 +903,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroLength = outroEnd - outroStart; double introStart; - if (seek) { + if (seekToStartPoint) { introStart = getIntroStartPosition(pToDeck); if (introStart <= 0.0) { introStart = getFirstSoundPosition(pToDeck); diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index a5fd6dbcd22..026d64a088e 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -252,7 +252,7 @@ class AutoDJProcessor : public QObject { void calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, bool fadeNow, - bool seek); + bool seekToStartPoint); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, From d87db38e9a520734b8886ad16775b185462a74f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 23 Jul 2019 08:51:17 +0200 Subject: [PATCH 065/198] delete removed "seekonload_mode" CO from tests --- src/test/autodjprocessor_test.cpp | 31 ------------------------------- src/test/cuecontrol_test.cpp | 2 -- 2 files changed, 33 deletions(-) diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 715dcdd56dd..16db1b8efd5 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -44,7 +44,6 @@ class FakeDeck : public BaseTrackPlayer { playposition(ConfigKey(group, "playposition"), 0.0, 1.0, 0, 0, true), play(ConfigKey(group, "play")), repeat(ConfigKey(group, "repeat")), - seekOnLoadMode(ConfigKey(group, "seekonload_mode")), introStartPos(ConfigKey(group, "intro_start_position")), outroStartPos(ConfigKey(group, "outro_start_position")), outroEndPos(ConfigKey(group, "outro_end_position")) { @@ -98,7 +97,6 @@ class FakeDeck : public BaseTrackPlayer { ControlLinPotmeter playposition; ControlPushButton play; ControlPushButton repeat; - ControlObject seekOnLoadMode; ControlObject introStartPos; ControlObject outroStartPos; ControlObject outroEndPos; @@ -280,9 +278,6 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped) { AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // Sets crossfader left and deck 1 playing. EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); // ADJ_ENABLE_P1LOADED logic does not set play directly. It waits for the @@ -336,9 +331,6 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFails) { AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // Sets crossfader left. EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); // ADJ_ENABLE_P1LOADED logic does not set play directly. It waits for the @@ -409,9 +401,6 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_DecksStopped_TrackLoadFailsRightDeck) AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); // Sets crossfader left. EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); // ADJ_ENABLE_P1LOADED logic does not set play directly. It waits for the @@ -487,10 +476,6 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(-1, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); @@ -532,10 +517,6 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck1_TrackLoadFailed) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); - // No change to the crossfader or play states. EXPECT_DOUBLE_EQ(-1, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); @@ -590,10 +571,6 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); - // No change to the crossfader or play states. EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); @@ -636,10 +613,6 @@ TEST_F(AutoDJProcessorTest, EnabledSuccess_PlayingDeck2_TrackLoadFailed) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); - // No change to the crossfader or play states. EXPECT_DOUBLE_EQ(1, master.crossfader.get()); EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); @@ -681,10 +654,6 @@ TEST_F(AutoDJProcessorTest, EnabledDisabledSuccess) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_ENABLE_P1LOADED, pProcessor->getState()); - // Makes decks 1 and 2 load tracks at intro cue point. - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck1.seekOnLoadMode.get()); - EXPECT_DOUBLE_EQ(static_cast(SeekOnLoadMode::IntroStart), deck2.seekOnLoadMode.get()); - err = pProcessor->toggleAutoDJ(false); EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_DISABLED, pProcessor->getState()); diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 9e8b31fc5aa..63291afb718 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -7,7 +7,6 @@ class CueControlTest : public BaseSignalPathTest { BaseSignalPathTest::SetUp(); m_pQuantizeEnabled = std::make_unique(m_sGroup1, "quantize"); - m_pSeekOnLoadMode = std::make_unique(m_sGroup1, "seekonload_mode"); m_pCuePoint = std::make_unique(m_sGroup1, "cue_point"); m_pIntroStartPosition = std::make_unique(m_sGroup1, "intro_start_position"); m_pIntroStartEnabled = std::make_unique(m_sGroup1, "intro_start_enabled"); @@ -55,7 +54,6 @@ class CueControlTest : public BaseSignalPathTest { } std::unique_ptr m_pQuantizeEnabled; - std::unique_ptr m_pSeekOnLoadMode; std::unique_ptr m_pCuePoint; std::unique_ptr m_pIntroStartPosition; std::unique_ptr m_pIntroStartEnabled; From 33ac5c5dcc803624e0c82532b37d85d6319ebc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 28 Jul 2019 11:50:43 +0200 Subject: [PATCH 066/198] minor code style --- src/library/autodj/autodjprocessor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 026d64a088e..c2dfa59b7e9 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -116,7 +116,7 @@ class DeckAttributes : public QObject { double startPos; // Set in toDeck nature double fadeBeginPos; // set in fromDeck nature double fadeEndPos; // set in fromDeck nature - bool loading; // The data is inconsistent during loading a deck + bool loading; // The data is inconsistent during loading a deck private: EngineChannel::ChannelOrientation m_orientation; From 7b8aade8d25ad6e664bac9af2572f643d2fb8813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 3 Aug 2019 23:18:55 +0200 Subject: [PATCH 067/198] Introduce a new LimitedIntroOutroStart transition mode --- src/library/autodj/autodjprocessor.cpp | 92 +++++++++++++++++++++++++- src/library/autodj/autodjprocessor.h | 1 + src/library/autodj/dlgautodj.cpp | 2 + src/widget/woverview.cpp | 2 +- 4 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b713de8cedf..e4d8e74a4ca 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -885,10 +885,12 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // Assume that the outro starts now and equals the given transition time // but do not pass the original outroEnd outroStart = pFromDeck->playPosition() * fromTrackDuration; + // if one uses fadeNow with a gap transition we take this time for fading here + double transitionTime = fabs(m_transitionTime); if (outroEnd > outroStart) { - outroEnd = math_min(outroEnd, outroStart + m_transitionTime); + outroEnd = math_min(outroEnd, outroStart + transitionTime); } else { - outroEnd = math_min(fromTrackDuration, outroStart + m_transitionTime); + outroEnd = math_min(fromTrackDuration, outroStart + transitionTime); } } else { outroStart = getOutroStartPosition(pFromDeck); @@ -997,6 +999,92 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getMainCuePosition(pToDeck)); } break; + case TransitionMode::LimitedIntroOutroStart: + // Uses a simple set of rules: + // * outro start starts fade if set + // * intro length is limited by transition time + // * fade time is the minimum of all + // no re-cuing of "to track" if no intro end is set. (legacy mode) + + // Use cases: + // + // By default only intro start and outro end are set. In this case fade + // starts at outro end - transitionTime. The new track is not recued, + // the deck preferences are used to set the start point. + // + // If the track has for instance a boring long outro the user can + // manually set the outro start. This set the fade start in any case. + // The fade time is now set by the outo length or the tranitonTime. + // The shorter is selected. + // + // If the track has a poisend end or something the user can adjust the + // outro end. It is never played bejond that point. + // + // The user can override the deck track load preferences by setting a + // intro end point and adjust the intro start. Fading starts at intro + // start or intro end - transitionTime, depending on which is shorter. + // The transition is always finished before passing intro out. + // This can for instance be useful to ensure that fading is over before + // vocals start. + + // outro xxxxxxx + // intro xxxxx + // transitionTime xxxxxxx + // fade xxxxx + + // outro xxx + // intro xxxxxxx + // transitionTime xxxxx + // fade xxx + + // outro xxxxxxx + // intro xxxxx + // transitionTime xxx + // fade xxx + + // outro xxx + // intro xxx + // negativeTime ----- + // fade xxxxx + + // Negative transitionTimes are working but not too reasonable. + // Note: In the negative transitionTime case we play bejond outro end. + // TODO: It would be nice to fade out the last beat outro, add the silence gap + // and fade in the first beat into. + + if (m_transitionTime <= 0) { + // play track including full intro and outro with an adjustable gap + useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); + } else { + double fadeLength = m_transitionTime; + if (outroLength > 0 && outroLength < fadeLength) { + fadeLength = outroLength; + } + if (introLength == 0) { + // Intro not set, don't re-cue the track + pToDeck->startPos = kKeepPosition; + } else if (introLength > m_transitionTime) { + // Intro is too long, cut some time from the beginning + pToDeck->startPos = introEnd - m_transitionTime; + } else { + // Intro is fine, play entirely + pToDeck->startPos = introStart; + if (introLength < fadeLength) { + // Use full intro for fading if it is the shortest time. + // This guarantees not to fade beyond intro end. + fadeLength = introLength; + } + } + if (outroLength > 0) { + // If an outroStart cue is set: Us it! + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroStart + fadeLength; + } else { + pFromDeck->fadeBeginPos = outroEnd - fadeLength; + pFromDeck->fadeEndPos = outroEnd; + } + } + break; case TransitionMode::FixedFullTrack: default: if (fadeNow) { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index c2dfa59b7e9..e29b5cf8994 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -159,6 +159,7 @@ class AutoDJProcessor : public QObject { FixedFullTrack = 2, FixedSkipSilence = 3, FixedLoadAtCue = 4, + LimitedIntroOutroStart = 5 }; AutoDJProcessor(QObject* pParent, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 566df0cc25f..b229c60957a 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -85,6 +85,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->addItem(tr("Fixed time (start at cue)"), static_cast(AutoDJProcessor::TransitionMode::FixedLoadAtCue)); + fadeModeCombobox->addItem(tr("Limited intro + outro start"), + static_cast(AutoDJProcessor::TransitionMode::LimitedIntroOutroStart)); fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 63a32bd8b76..ca3e2f072f2 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -184,7 +184,7 @@ void WOverview::onConnectedControlChanged(double dParameter, double dValue) { int iPos = valueToPosition(parameter); if (iPos != m_iPos) { m_iPos = iPos; - qDebug() << "WOverview::onConnectedControlChanged" << parameter << ">>" << m_iPos; + // qDebug() << "WOverview::onConnectedControlChanged" << parameter << ">>" << m_iPos; update(); } } From a4d8b4eaae87b0f4e361e16acc977f9966baf70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 4 Aug 2019 00:56:30 +0200 Subject: [PATCH 068/198] getOutroEndPosition() always returns a valid value --- src/library/autodj/autodjprocessor.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index e4d8e74a4ca..5610956e749 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -777,7 +777,11 @@ double AutoDJProcessor::getOutroStartPosition(DeckAttributes* pDeck) { } double AutoDJProcessor::getOutroEndPosition(DeckAttributes* pDeck) { - return samplePositionToSeconds(pDeck->outroEndPosition(), pDeck); + double outroEnd = samplePositionToSeconds(pDeck->outroEndPosition(), pDeck); + if (outroEnd <= 0.0) { + outroEnd = getLastSoundPosition(pDeck); + } + return outroEnd; } double AutoDJProcessor::getFirstSoundPosition(DeckAttributes* pDeck) { @@ -877,9 +881,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroStart; double outroEnd = getOutroEndPosition(pFromDeck); - if (outroEnd <= 0.0) { - outroEnd = getLastSoundPosition(pFromDeck); - } if (fadeNow) { // Assume that the outro starts now and equals the given transition time @@ -1099,6 +1100,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeEndPos /= fromTrackDuration; pToDeck->startPos /= toTrackDuration; + DEBUG_ASSERT(pFromDeck->fadeBeginPos <= 1); + if (sDebug) { qDebug() << this << pFromDeck->fadeBeginPos << pFromDeck->fadeEndPos << pToDeck->startPos; From adcbc3a61e97547e7263a4507e38c1c3ece51296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 4 Aug 2019 01:00:24 +0200 Subject: [PATCH 069/198] getIntroStartPosition() alwasy returns a valid value --- src/library/autodj/autodjprocessor.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 5610956e749..10f6201255a 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -765,7 +765,11 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double } double AutoDJProcessor::getIntroStartPosition(DeckAttributes* pDeck) { - return samplePositionToSeconds(pDeck->introStartPosition(), pDeck); + double introStart = samplePositionToSeconds(pDeck->introStartPosition(), pDeck); + if (introStart <= 0.0) { + introStart = getFirstSoundPosition(pDeck); + } + return introStart; } double AutoDJProcessor::getIntroEndPosition(DeckAttributes* pDeck) { @@ -908,9 +912,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double introStart; if (seekToStartPoint) { introStart = getIntroStartPosition(pToDeck); - if (introStart <= 0.0) { - introStart = getFirstSoundPosition(pToDeck); - } } else { introStart = pToDeck->playPosition() * toTrackDuration; } From a5d3b9f06291e2fc820c31cb9374ceb8fc9e6c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 4 Aug 2019 02:00:32 +0200 Subject: [PATCH 070/198] Adjust tests for new crossfader handling --- src/library/autodj/autodjprocessor.cpp | 3 ++ src/test/autodjprocessor_test.cpp | 40 ++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 10f6201255a..50256d9204c 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -582,6 +582,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // the next playerPositionChanged call otherDeck (see the // P1/P2FADING case above). thisDeck.stop(); + m_transitionProgress = 1.0; } else { // We are in Fading state. // Calculate the current transitionProgress, the place between begin @@ -602,6 +603,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, setCrossfader(currentCrossfader + adjustment); } m_transitionProgress = transitionProgress; + // if we are at 1.0 here, we need an additional callback until the last + // step is processed and we can stop the deck. } } } diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 16db1b8efd5..52a76ad26b2 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -709,8 +709,15 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadSuccess) { deck2.playposition.set(1.0); EXPECT_EQ(AutoDJProcessor::ADJ_RIGHT_FADING, pProcessor->getState()); - EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); + EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + // Deck is still playing, because the crossfader is processed in the next audio + // calback. + EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + + // Fake a final callback, normally in this case the engine + // stops the deck + deck2.playposition.set(9.9999); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Expect that we will transition into IDLE mode and receive a track-load @@ -791,8 +798,15 @@ TEST_F(AutoDJProcessorTest, FadeToDeck1_LoadOnDeck2_TrackLoadFailed) { deck2.playposition.set(1.0); EXPECT_EQ(AutoDJProcessor::ADJ_RIGHT_FADING, pProcessor->getState()); - EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); + EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + // Deck is still playing, because the crossfader is processed in the next audio + // calback. + EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + + // Fake a final callback, normally in this case the engine + // stops the deck + deck2.playposition.set(9.9999); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); // Expect that we will transition into IDLE mode and receive a track-load @@ -885,10 +899,17 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadSuccess) { deck1.playposition.set(1.0); EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); + // Deck is still playing, because the crossfader is processed in the next audio + // calback. + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + // Fake a final callback, normally in this case the engine + // stops the deck + deck1.playposition.set(9.9999); + EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + // Expect that we will transition into IDLE mode and receive a track-load // request for deck 1 after deck 2 starts playing. EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); @@ -967,10 +988,17 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { deck1.playposition.set(1.0); EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); + // Deck is still playing, because the crossfader is processed in the next audio + // calback. + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + // Fake a final callback, normally in this case the engine + // stops the deck + deck1.playposition.set(9.9999); + EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + // Expect that we will transition into IDLE mode and receive a track-load // request for deck 1 after deck 2 starts playing. EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); From 8e4669c6b3b5a0e24c540621215cf2eb1c136dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 5 Aug 2019 00:17:56 +0200 Subject: [PATCH 071/198] fix more AutoDJ tets --- src/library/autodj/autodjprocessor.cpp | 26 +++++---- src/test/autodjprocessor_test.cpp | 73 ++++++++++++++++++-------- 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 50256d9204c..76c26f47411 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1112,19 +1112,27 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } } -void AutoDJProcessor::useFixedFadeTime( - DeckAttributes* pFromDeck, - DeckAttributes* pToDeck, - double endPoint, - double startPoint) { +void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, + DeckAttributes* pToDeck, double endPoint, double startPoint) { if (m_transitionTime > 0.0) { // Guard against the next track being too short. This transition must finish - // before the next one starts. + // before the next transition starts. double toDeckOutroStart = getOutroStartPosition(pToDeck); - if (toDeckOutroStart <= 0) { - toDeckOutroStart = math_min(getOutroEndPosition(pToDeck), pToDeck->duration() / 2); + if (toDeckOutroStart <= startPoint) { + // we are already to late + double end = getOutroEndPosition(pToDeck); + if (end <= startPoint) { + end = pToDeck->duration(); + VERIFY_OR_DEBUG_ASSERT(end > startPoint) { + // as last resort move start point + startPoint = pToDeck->duration() - 1; + } + } + // use the remaining time for fad to this dack ende fade to the next + toDeckOutroStart = (end - startPoint) / 2 + startPoint; } - double transitionTime = math_min(toDeckOutroStart - startPoint, m_transitionTime); + double transitionTime = math_min(toDeckOutroStart - startPoint, + m_transitionTime); pFromDeck->fadeBeginPos = endPoint - transitionTime; pFromDeck->fadeEndPos = endPoint; diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 52a76ad26b2..c19609c1f42 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -1065,6 +1065,10 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + // Pretend the track load succeeds. + deck2.slotLoadTrack(pTrack, false); + deck2.fakeTrackLoadedEvent(pTrack); + // Set a long transition time // The test tracks are only 30s pProcessor->setTransitionTime(60); @@ -1072,10 +1076,6 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { // We expect that fading starts at the middle of the track // And Auto-DJ should keep running - // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); - deck2.fakeTrackLoadedEvent(pTrack); - // No change to the mode, crossfader or play states. EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); @@ -1106,12 +1106,18 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { deck1.playposition.set(1.0); EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - qDebug() << "master.crossfader.get()" << master.crossfader.get(); - // EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); + // Deck is still playing, because the crossfader is processed in the next audio + // calback. + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + // Fake a final callback, normally in this case the engine + // stops the deck + deck1.playposition.set(9.9999); + EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + // Expect that we will transition into IDLE mode and receive a track-load // request for deck 1 after deck 2 starts playing. EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); @@ -1147,13 +1153,27 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + // Pretend the track load succeeds. + deck2.slotLoadTrack(pTrack, false); + deck2.fakeTrackLoadedEvent(pTrack); + + // The track should have been cued at 0.0. + EXPECT_DOUBLE_EQ(0.0, deck2.playposition.get()); + // Pause transition. Set a negative transition time. pProcessor->setTransitionTime(-12); + // changing the transition time does not re-cue the track + // The user may has adjusted the cue-ing of the track manually in the mean time + EXPECT_DOUBLE_EQ(0.0, deck2.playposition.get()); + // Pretend the track load succeeds. deck2.slotLoadTrack(pTrack, false); deck2.fakeTrackLoadedEvent(pTrack); + // The newly loaded track should have been seeked back by the duration of transition. + EXPECT_DOUBLE_EQ(-0.1, deck2.playposition.get()); + // No change to the mode, crossfader or play states. EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); @@ -1169,12 +1189,15 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { // We should have transitioned into LEFT_FADING. EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - // The track should have been seeked back by the duration of transition. - EXPECT_DOUBLE_EQ(-0.1, deck2.playposition.get()); - - EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + // Deck is still playing, because the crossfader is processed in the next audio + // calback. + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + // Fake a final callback, normally in this case the engine + // stops the deck + deck1.play.set(0.0); + // Expect that we will transition into IDLE mode and request a track load // on deck1. EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); @@ -1227,18 +1250,15 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { // Expect that we will transition into LEFT_FADING mode. EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); - // Seek track to 99 % it should fade + // Seek track to 99.9 % it should fade // not 100 % because the final step is done by deck2 - deck1.playposition.set(0.99); + deck1.playposition.set(0.999); EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); EXPECT_LT(-1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); - - // Deck 2 should been seeked back to a suitable position for crossfade - EXPECT_GT(0.99, deck2.playposition.get()); } TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectIntroCue) { @@ -1268,6 +1288,10 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectIntroCue) { EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + // Pretend the track load succeeds. + deck2.slotLoadTrack(pTrack, false); + deck2.fakeTrackLoadedEvent(pTrack); + // Pause transition. Set a negative transition time. pProcessor->setTransitionTime(-25); @@ -1282,16 +1306,19 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectIntroCue) { deck2.introStartPos.set(kIntroStartPositionSamples); deck2.outroEndPos.set(kOutroEndPositionSamples); - // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); - deck2.fakeTrackLoadedEvent(pTrack); - // No change to the mode, crossfader or play states. EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); + // The incoming track should have not bee seeked back yet. + EXPECT_DOUBLE_EQ(0.0, deck2.playposition.get()); + + // .. but after reload + deck2.fakeTrackLoadedEvent(pTrack); + EXPECT_DOUBLE_EQ(-0.15, deck2.playposition.get()); + // Expect that we will transition into LEFT_FADING mode. EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); @@ -1299,12 +1326,14 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectIntroCue) { deck1.playposition.set(0.9); EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - // The incoming track should have been seeked back. EXPECT_DOUBLE_EQ(-0.15, deck2.playposition.get()); - EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + deck1.playposition.set(1); + deck1.play.set(0.0); + // Expect that we will transition into IDLE mode and request a track load on deck1. EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); From 689b5a05c5cc332b654b975858feb2cd7bc2dd63 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 8 Aug 2019 23:20:10 -0500 Subject: [PATCH 072/198] use fadeLength instead of m_transitionTime --- src/library/autodj/autodjprocessor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 76c26f47411..b75d158a311 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1068,9 +1068,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, if (introLength == 0) { // Intro not set, don't re-cue the track pToDeck->startPos = kKeepPosition; - } else if (introLength > m_transitionTime) { + } else if (introLength > fadeLength) { // Intro is too long, cut some time from the beginning - pToDeck->startPos = introEnd - m_transitionTime; + pToDeck->startPos = introEnd - fadeLength; } else { // Intro is fine, play entirely pToDeck->startPos = introStart; From 79c1b00727679e2aa332270cb3d160e74fc44c0a Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 8 Aug 2019 23:28:29 -0500 Subject: [PATCH 073/198] edit comments for typos and clarity --- src/library/autodj/autodjprocessor.cpp | 29 +++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b75d158a311..978492af1ec 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1006,31 +1006,32 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, break; case TransitionMode::LimitedIntroOutroStart: // Uses a simple set of rules: - // * outro start starts fade if set - // * intro length is limited by transition time - // * fade time is the minimum of all - // no re-cuing of "to track" if no intro end is set. (legacy mode) + // * Fading starts at outro end if that is set. + // * Fade time is the outro length, intro length, or transition time, + // whichever is shortest. + // * Always finish fading before the intro end if that is set. + // Do not re-cue "to track" if no intro end is set. (legacy mode) // Use cases: // // By default only intro start and outro end are set. In this case fade - // starts at outro end - transitionTime. The new track is not recued, - // the deck preferences are used to set the start point. + // starts at outro end - transitionTime. The new track is not recued; + // the deck load preference is used to set the start point. // // If the track has for instance a boring long outro the user can - // manually set the outro start. This set the fade start in any case. - // The fade time is now set by the outo length or the tranitonTime. + // manually set the outro start. Fading starts there in any case. + // The fade time is now set by the outro length or the transitonTime. // The shorter is selected. // - // If the track has a poisend end or something the user can adjust the - // outro end. It is never played bejond that point. + // If the track has an ugly ending or something the user can adjust the + // outro end to cut it off. It is never played beyond that point. // - // The user can override the deck track load preferences by setting a + // The user can override the deck track load preference by setting an // intro end point and adjust the intro start. Fading starts at intro // start or intro end - transitionTime, depending on which is shorter. // The transition is always finished before passing intro out. // This can for instance be useful to ensure that fading is over before - // vocals start. + // drums or vocals start. // outro xxxxxxx // intro xxxxx @@ -1119,7 +1120,7 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, // before the next transition starts. double toDeckOutroStart = getOutroStartPosition(pToDeck); if (toDeckOutroStart <= startPoint) { - // we are already to late + // we are already too late double end = getOutroEndPosition(pToDeck); if (end <= startPoint) { end = pToDeck->duration(); @@ -1128,7 +1129,7 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, startPoint = pToDeck->duration() - 1; } } - // use the remaining time for fad to this dack ende fade to the next + // use the remaining time for fading toDeckOutroStart = (end - startPoint) / 2 + startPoint; } double transitionTime = math_min(toDeckOutroStart - startPoint, From d315f0cd279e91d2f15410f1decfce5843ce9787 Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 15:13:18 -0500 Subject: [PATCH 074/198] AutoDJ: add intro/outro smooth and quick modes --- src/library/autodj/autodjprocessor.cpp | 62 ++++++++++++++++++++++++++ src/library/autodj/autodjprocessor.h | 10 +++-- src/library/autodj/dlgautodj.cpp | 4 ++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 978492af1ec..7d017a0cd3b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1004,6 +1004,68 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getMainCuePosition(pToDeck)); } break; + // Let the full outro and intro play; do not cut off any part of either. + // Use the outroLength or introLength as the transition time, whichever is + // shorter. If only the outro or intro length is marked but not both, use + // the one that is marked for the transition time. If neither is marked, + // fall back to the transition time from the spinbox. + case TransitionMode::IntroOutroSmooth: + if (outroLength > 0 && introLength > 0) { + if (outroLength > introLength) { + pFromDeck->fadeBeginPos = outroEnd - introLength; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } else { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } + } else if (outroLength > 0 && introLength <= 0) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } else if (introLength > 0 && outroLength <= 0) { + pFromDeck->fadeBeginPos = outroEnd - introLength; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } else { + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), + getFirstSoundPosition(pToDeck)); + } + break; + // Start fading at the outroStart and end fading at the introEnd, cutting + // off some of the outro or intro (whichever is longer) to minimize the + // transition time. + // Use the outroLength or introLength as the transition time, whichever is + // shorter. If only the outro or intro length is marked but not both, use + // the one that is marked for the transition time. If neither is marked, + // fall back to the transition time from the spinbox. + case TransitionMode::IntroOutroQuick: + if (outroLength > 0 && introLength > 0) { + if (outroLength > introLength) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroStart + introLength; + pToDeck->startPos = introStart; + } else { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introEnd - outroLength; + } + } else if (outroLength > 0 && introLength <= 0) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } else if (introLength < 0 && outroLength <= 0) { + pFromDeck->fadeBeginPos = outroEnd - introLength; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } else { + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), + getFirstSoundPosition(pToDeck)); + } + break; case TransitionMode::LimitedIntroOutroStart: // Uses a simple set of rules: // * Fading starts at outro end if that is set. diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index e29b5cf8994..ee3ec609879 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -156,10 +156,12 @@ class AutoDJProcessor : public QObject { enum class TransitionMode { AlignIntroOutroStart = 0, AlignIntroOutroEnd = 1, - FixedFullTrack = 2, - FixedSkipSilence = 3, - FixedLoadAtCue = 4, - LimitedIntroOutroStart = 5 + IntroOutroSmooth = 2, + IntroOutroQuick = 3, + LimitedIntroOutroStart = 4, + FixedFullTrack = 5, + FixedSkipSilence = 6, + FixedLoadAtCue = 7 }; AutoDJProcessor(QObject* pParent, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index b229c60957a..464c1546f55 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -79,6 +79,10 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); fadeModeCombobox->addItem(tr("Align intro + outro end"), static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroEnd)); + fadeModeCombobox->addItem(tr("Intro/Outro (smooth transition)"), + static_cast(AutoDJProcessor::TransitionMode::IntroOutroSmooth)); + fadeModeCombobox->addItem(tr("Intro/Outro (quick transition)"), + static_cast(AutoDJProcessor::TransitionMode::IntroOutroQuick)); fadeModeCombobox->addItem(tr("Fixed time (full track)"), static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); fadeModeCombobox->addItem(tr("Fixed time (skip silence)"), From a1174e0c21d1184db87286ae41a08bced127e322 Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 15:21:38 -0500 Subject: [PATCH 075/198] AutoDJ: set default transition mode to "Intro/Outro (smooth transition)" --- src/library/autodj/autodjprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 7d017a0cd3b..0c436181070 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -161,7 +161,7 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, int configuredTransitionMode = m_pConfig->getValue( ConfigKey(kConfigKey, kTransitionModePreferenceName), - static_cast(TransitionMode::AlignIntroOutroStart)); + static_cast(TransitionMode::IntroOutroSmooth)); m_transitionMode = static_cast(configuredTransitionMode); } From b52de8a66216b8f5ed84232726e8496fb69c2b37 Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 15:15:38 -0500 Subject: [PATCH 076/198] AutoDJ: remove align intro/outro start/end modes --- src/library/autodj/autodjprocessor.cpp | 41 -------------------------- src/library/autodj/autodjprocessor.h | 14 ++++----- src/library/autodj/dlgautodj.cpp | 4 --- 3 files changed, 6 insertions(+), 53 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 0c436181070..25b8f74fa52 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -937,47 +937,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // that range as the transition time as a best guess. Only fall back to the // fixed number of seconds from the spinbox as a last resort. switch (m_transitionMode) { - case TransitionMode::AlignIntroOutroStart: - pToDeck->startPos = introStart; - if (outroLength > 0) { - pFromDeck->fadeBeginPos = outroStart; - if (introLength > 0 && introLength < outroLength) { - pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + introLength; - } else if (pToDeck->startPos + outroLength >= toTrackDuration) { - pFromDeck->fadeEndPos = pFromDeck->fadeBeginPos + - toTrackDuration - pToDeck->startPos; - } else { - pFromDeck->fadeEndPos = outroEnd; - } - } else if (introLength > 0) { - pFromDeck->fadeBeginPos = outroEnd - introLength; - pFromDeck->fadeEndPos = outroEnd; - } else { - useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); - } - break; - case TransitionMode::AlignIntroOutroEnd: - if (introLength > 0) { - pFromDeck->fadeEndPos = outroEnd; - if (outroLength > 0) { - pFromDeck->fadeBeginPos = pFromDeck->fadeEndPos - math_min(outroLength, introLength); - } else { - pFromDeck->fadeBeginPos = math_max(pFromDeck->fadeEndPos - introLength, 0.0); - } - pToDeck->startPos = introEnd - (pFromDeck->fadeEndPos - pFromDeck->fadeBeginPos); - } else if (outroLength > 0) { - pToDeck->startPos = introStart; - pFromDeck->fadeEndPos = outroEnd; - if (pToDeck->startPos + outroLength >= toTrackDuration) { - pFromDeck->fadeBeginPos = pFromDeck->fadeEndPos - - toTrackDuration + pToDeck->startPos; - } else { - pFromDeck->fadeBeginPos = outroStart; - } - } else { - useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); - } - break; case TransitionMode::FixedSkipSilence: if (fadeNow) { useFixedFadeTime(pFromDeck, diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index ee3ec609879..a385c6b582d 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -154,14 +154,12 @@ class AutoDJProcessor : public QObject { }; enum class TransitionMode { - AlignIntroOutroStart = 0, - AlignIntroOutroEnd = 1, - IntroOutroSmooth = 2, - IntroOutroQuick = 3, - LimitedIntroOutroStart = 4, - FixedFullTrack = 5, - FixedSkipSilence = 6, - FixedLoadAtCue = 7 + IntroOutroSmooth = 1, + IntroOutroQuick = 2, + LimitedIntroOutroStart = 3, + FixedFullTrack = 4, + FixedSkipSilence = 5, + FixedLoadAtCue = 6 }; AutoDJProcessor(QObject* pParent, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 464c1546f55..d9e069b9bb6 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -75,10 +75,6 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); - fadeModeCombobox->addItem(tr("Align intro + outro start"), - static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); - fadeModeCombobox->addItem(tr("Align intro + outro end"), - static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroEnd)); fadeModeCombobox->addItem(tr("Intro/Outro (smooth transition)"), static_cast(AutoDJProcessor::TransitionMode::IntroOutroSmooth)); fadeModeCombobox->addItem(tr("Intro/Outro (quick transition)"), From c3108c6cb123cc149b712d46bb07e5ef9a808312 Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 15:16:58 -0500 Subject: [PATCH 077/198] AutoDJ: remove "Limited intro + outro start" mode --- src/library/autodj/autodjprocessor.cpp | 87 -------------------------- src/library/autodj/autodjprocessor.h | 7 +-- src/library/autodj/dlgautodj.cpp | 2 - 3 files changed, 3 insertions(+), 93 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 25b8f74fa52..2e7ea92dd5b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1025,93 +1025,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; - case TransitionMode::LimitedIntroOutroStart: - // Uses a simple set of rules: - // * Fading starts at outro end if that is set. - // * Fade time is the outro length, intro length, or transition time, - // whichever is shortest. - // * Always finish fading before the intro end if that is set. - // Do not re-cue "to track" if no intro end is set. (legacy mode) - - // Use cases: - // - // By default only intro start and outro end are set. In this case fade - // starts at outro end - transitionTime. The new track is not recued; - // the deck load preference is used to set the start point. - // - // If the track has for instance a boring long outro the user can - // manually set the outro start. Fading starts there in any case. - // The fade time is now set by the outro length or the transitonTime. - // The shorter is selected. - // - // If the track has an ugly ending or something the user can adjust the - // outro end to cut it off. It is never played beyond that point. - // - // The user can override the deck track load preference by setting an - // intro end point and adjust the intro start. Fading starts at intro - // start or intro end - transitionTime, depending on which is shorter. - // The transition is always finished before passing intro out. - // This can for instance be useful to ensure that fading is over before - // drums or vocals start. - - // outro xxxxxxx - // intro xxxxx - // transitionTime xxxxxxx - // fade xxxxx - - // outro xxx - // intro xxxxxxx - // transitionTime xxxxx - // fade xxx - - // outro xxxxxxx - // intro xxxxx - // transitionTime xxx - // fade xxx - - // outro xxx - // intro xxx - // negativeTime ----- - // fade xxxxx - - // Negative transitionTimes are working but not too reasonable. - // Note: In the negative transitionTime case we play bejond outro end. - // TODO: It would be nice to fade out the last beat outro, add the silence gap - // and fade in the first beat into. - - if (m_transitionTime <= 0) { - // play track including full intro and outro with an adjustable gap - useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); - } else { - double fadeLength = m_transitionTime; - if (outroLength > 0 && outroLength < fadeLength) { - fadeLength = outroLength; - } - if (introLength == 0) { - // Intro not set, don't re-cue the track - pToDeck->startPos = kKeepPosition; - } else if (introLength > fadeLength) { - // Intro is too long, cut some time from the beginning - pToDeck->startPos = introEnd - fadeLength; - } else { - // Intro is fine, play entirely - pToDeck->startPos = introStart; - if (introLength < fadeLength) { - // Use full intro for fading if it is the shortest time. - // This guarantees not to fade beyond intro end. - fadeLength = introLength; - } - } - if (outroLength > 0) { - // If an outroStart cue is set: Us it! - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeEndPos = outroStart + fadeLength; - } else { - pFromDeck->fadeBeginPos = outroEnd - fadeLength; - pFromDeck->fadeEndPos = outroEnd; - } - } - break; case TransitionMode::FixedFullTrack: default: if (fadeNow) { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index a385c6b582d..c1e4f5f4355 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -156,10 +156,9 @@ class AutoDJProcessor : public QObject { enum class TransitionMode { IntroOutroSmooth = 1, IntroOutroQuick = 2, - LimitedIntroOutroStart = 3, - FixedFullTrack = 4, - FixedSkipSilence = 5, - FixedLoadAtCue = 6 + FixedFullTrack = 3, + FixedSkipSilence = 4, + FixedLoadAtCue = 5 }; AutoDJProcessor(QObject* pParent, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index d9e069b9bb6..f4d56e515d1 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -85,8 +85,6 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->addItem(tr("Fixed time (start at cue)"), static_cast(AutoDJProcessor::TransitionMode::FixedLoadAtCue)); - fadeModeCombobox->addItem(tr("Limited intro + outro start"), - static_cast(AutoDJProcessor::TransitionMode::LimitedIntroOutroStart)); fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); From c48afb089b69205bb22b4a8a66892e3950e2ad6f Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 15:18:45 -0500 Subject: [PATCH 078/198] AutoDJ: remove "Fixed time (start at cue)" mode --- src/library/autodj/autodjprocessor.cpp | 13 ------------- src/library/autodj/autodjprocessor.h | 3 +-- src/library/autodj/dlgautodj.cpp | 2 -- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2e7ea92dd5b..31c7d3f9a95 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -950,19 +950,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; - case TransitionMode::FixedLoadAtCue: - if (fadeNow) { - useFixedFadeTime(pFromDeck, - pToDeck, - outroEnd, - getMainCuePosition(pToDeck)); - } else { - useFixedFadeTime(pFromDeck, - pToDeck, - getLastSoundPosition(pFromDeck), - getMainCuePosition(pToDeck)); - } - break; // Let the full outro and intro play; do not cut off any part of either. // Use the outroLength or introLength as the transition time, whichever is // shorter. If only the outro or intro length is marked but not both, use diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index c1e4f5f4355..cd31ac6d29d 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -157,8 +157,7 @@ class AutoDJProcessor : public QObject { IntroOutroSmooth = 1, IntroOutroQuick = 2, FixedFullTrack = 3, - FixedSkipSilence = 4, - FixedLoadAtCue = 5 + FixedSkipSilence = 4 }; AutoDJProcessor(QObject* pParent, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index f4d56e515d1..87a9fd5125a 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -83,8 +83,6 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); fadeModeCombobox->addItem(tr("Fixed time (skip silence)"), static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); - fadeModeCombobox->addItem(tr("Fixed time (start at cue)"), - static_cast(AutoDJProcessor::TransitionMode::FixedLoadAtCue)); fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); From f8c56337b5d07c3c2b315320ca470aa2b36bc37b Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 16:13:16 -0500 Subject: [PATCH 079/198] improve comments with diagrams --- src/library/autodj/autodjprocessor.cpp | 52 ++++++++++++++++++++------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 31c7d3f9a95..dc8de35ace5 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -950,12 +950,26 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; - // Let the full outro and intro play; do not cut off any part of either. - // Use the outroLength or introLength as the transition time, whichever is - // shorter. If only the outro or intro length is marked but not both, use - // the one that is marked for the transition time. If neither is marked, - // fall back to the transition time from the spinbox. case TransitionMode::IntroOutroSmooth: + // Let the full outro and intro play; do not cut off any part of either. + // + // In the diagrams below, + // - is part of a track outside the outro/intro, + // o is part of the outro + // i is part of the intro + // | marks the boundaries of the transition + // + // When outro > intro: + // ------ooo|ooo| + // |iii|------ + // + // When outro < intro: + // ------|ooo| + // |iii|iii----- + // + // If only the outro or intro length is marked but not both, use the one + // that is marked for the transition time. If neither is marked, fall + // back to the transition time from the spinbox. if (outroLength > 0 && introLength > 0) { if (outroLength > introLength) { pFromDeck->fadeBeginPos = outroEnd - introLength; @@ -980,14 +994,28 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; - // Start fading at the outroStart and end fading at the introEnd, cutting - // off some of the outro or intro (whichever is longer) to minimize the - // transition time. - // Use the outroLength or introLength as the transition time, whichever is - // shorter. If only the outro or intro length is marked but not both, use - // the one that is marked for the transition time. If neither is marked, - // fall back to the transition time from the spinbox. case TransitionMode::IntroOutroQuick: + // Start fading at the outroStart and end fading at the introEnd, + // cutting off some of the outro or intro (whichever is longer) to + // minimize the transition time. + // + // In the diagrams below, + // - is part of a track outside the outro/intro, + // o is part of the outro + // i is part of the intro + // | marks the boundaries of the transition + // + // When outro > intro: + // ------|ooo|ooo + // |iii|------ + // + // When outro < intro: + // ------|ooo| + // iii|iii|------ + // + // If only the outro or intro length is marked but not both, use the one + // that is marked for the transition time. If neither is marked, fall + // back to the transition time from the spinbox. if (outroLength > 0 && introLength > 0) { if (outroLength > introLength) { pFromDeck->fadeBeginPos = outroStart; From f6153cc20b036f7d8fdc1bb5b3f0c96b63bb165f Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 16:14:53 -0500 Subject: [PATCH 080/198] rearrange code --- src/library/autodj/autodjprocessor.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index dc8de35ace5..0f033fe9da6 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -937,19 +937,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // that range as the transition time as a best guess. Only fall back to the // fixed number of seconds from the spinbox as a last resort. switch (m_transitionMode) { - case TransitionMode::FixedSkipSilence: - if (fadeNow) { - useFixedFadeTime(pFromDeck, - pToDeck, - outroEnd, - getFirstSoundPosition(pToDeck)); - } else { - useFixedFadeTime(pFromDeck, - pToDeck, - getLastSoundPosition(pFromDeck), - getFirstSoundPosition(pToDeck)); - } - break; case TransitionMode::IntroOutroSmooth: // Let the full outro and intro play; do not cut off any part of either. // @@ -1040,6 +1027,19 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; + case TransitionMode::FixedSkipSilence: + if (fadeNow) { + useFixedFadeTime(pFromDeck, + pToDeck, + outroEnd, + getFirstSoundPosition(pToDeck)); + } else { + useFixedFadeTime(pFromDeck, + pToDeck, + getLastSoundPosition(pFromDeck), + getFirstSoundPosition(pToDeck)); + } + break; case TransitionMode::FixedFullTrack: default: if (fadeNow) { From 3fc81c7e13a5fd1854e6b01b348fa399f7f0d09d Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 9 Aug 2019 18:03:46 -0500 Subject: [PATCH 081/198] move AutoDJ repeat playlist option to main window from preferences --- src/library/autodj/dlgautodj.cpp | 18 +++++++++++- src/library/autodj/dlgautodj.h | 2 ++ src/library/autodj/dlgautodj.ui | 10 +++++++ src/preferences/dialog/dlgprefautodj.cpp | 23 --------------- src/preferences/dialog/dlgprefautodj.h | 1 - src/preferences/dialog/dlgprefautodjdlg.ui | 33 ++++++---------------- 6 files changed, 37 insertions(+), 50 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 87a9fd5125a..2e1cad49bb8 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -8,6 +8,11 @@ #include "util/duration.h" #include "widget/wtracktableview.h" +namespace { +const char* kPreferenceGroupName = "[Auto DJ]"; +const char* kRepeatPlaylistPreference = "Requeue"; +} // anonymous namespace + DlgAutoDJ::DlgAutoDJ(QWidget* parent, UserSettingsPointer pConfig, Library* pLibrary, @@ -20,7 +25,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, // no sorting m_pTrackTableView(new WTrackTableView(this, pConfig, pTrackCollection, false)), - m_pAutoDJTableModel(NULL) { + m_pAutoDJTableModel(nullptr), + m_pConfig(pConfig) { setupUi(this); m_pTrackTableView->installEventFilter(pKeyboard); @@ -100,6 +106,11 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, fadeModeCombobox->setToolTip(fadeModeTooltip); fadeModeLabel->setToolTip(fadeModeTooltip); + repeatPlaylistCheckbox->setChecked(m_pConfig->getValue( + ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference))); + connect(repeatPlaylistCheckbox, &QCheckBox::stateChanged, + this, &DlgAutoDJ::slotRepeatPlaylistChanged); + // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in // mind that AutoDJ may already be active when DlgAutoDJ is created (due to // skin changes, etc.). @@ -224,6 +235,11 @@ void DlgAutoDJ::slotTransitionModeChanged(int comboboxIndex) { fadeModeCombobox->itemData(comboboxIndex).toInt())); } +void DlgAutoDJ::slotRepeatPlaylistChanged(int checkState) { + m_pConfig->setValue(ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference), + static_cast(checkState)); +} + void DlgAutoDJ::updateSelectionInfo() { double duration = 0.0; diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index d4f34d0f27d..849e66b9121 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -42,6 +42,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { void autoDJStateChanged(AutoDJProcessor::AutoDJState state); void updateSelectionInfo(); void slotTransitionModeChanged(int comboboxIndex); + void slotRepeatPlaylistChanged(int checkedState); signals: void addRandomButton(bool buttonChecked); @@ -53,6 +54,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { AutoDJProcessor* m_pAutoDJProcessor; WTrackTableView* m_pTrackTableView; PlaylistTableModel* m_pAutoDJTableModel; + UserSettingsPointer m_pConfig; }; #endif //DLGAUTODJ_H diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index 30f8e2d0c93..6d74010c772 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -148,6 +148,16 @@ If no track sources are configured, the track is added from the library instead. + + + + + + + Repeat playlist + + + diff --git a/src/preferences/dialog/dlgprefautodj.cpp b/src/preferences/dialog/dlgprefautodj.cpp index 69598433264..2700df93d44 100644 --- a/src/preferences/dialog/dlgprefautodj.cpp +++ b/src/preferences/dialog/dlgprefautodj.cpp @@ -6,13 +6,6 @@ DlgPrefAutoDJ::DlgPrefAutoDJ(QWidget* pParent, m_pConfig(pConfig) { setupUi(this); - // Re-queue tracks in Auto DJ - ComboBoxAutoDjRequeue->addItem(tr("Off")); - ComboBoxAutoDjRequeue->addItem(tr("On")); - ComboBoxAutoDjRequeue->setCurrentIndex(m_pConfig->getValueString(ConfigKey("[Auto DJ]", "Requeue")).toInt()); - connect(ComboBoxAutoDjRequeue, SIGNAL(activated(int)), - this, SLOT(slotSetAutoDjRequeue(int))); - // The minimum available for randomly-selected tracks autoDjMinimumAvailableSpinBox->setValue( m_pConfig->getValue( @@ -51,9 +44,6 @@ DlgPrefAutoDJ::DlgPrefAutoDJ(QWidget* pParent, slotEnableAutoDJRandomQueue( m_pConfig->getValue( ConfigKey("[Auto DJ]", "EnableRandomQueue"))); - // Be ready to enable disable the random enqueue as reque is modified - connect(ComboBoxAutoDjRequeue, SIGNAL(activated(int)), this, - SLOT(slotEnableAutoDJRandomQueueComboBox(int))); // Be ready to enable and modify the minimum number and enable disable the spinbox connect(ComboBoxAutoDjRandomQueue, SIGNAL(activated(int)), this, SLOT(slotEnableAutoDJRandomQueue(int))); @@ -69,8 +59,6 @@ void DlgPrefAutoDJ::slotUpdate() { void DlgPrefAutoDJ::slotApply() { //Copy from Buffer to actual values - m_pConfig->setValue(ConfigKey("[Auto DJ]", "Requeue"), - m_pConfig->getValue(ConfigKey("[Auto DJ]", "RequeueBuff"), 0)); m_pConfig->setValue(ConfigKey("[Auto DJ]","MinimumAvailable"), m_pConfig->getValue( ConfigKey("[Auto DJ]", "MinimumAvailableBuff"), 20)); @@ -92,10 +80,6 @@ void DlgPrefAutoDJ::slotApply() { void DlgPrefAutoDJ::slotCancel() { // Load actual values and reset Buffer Values where ever needed - ComboBoxAutoDjRequeue->setCurrentIndex( - m_pConfig->getValue(ConfigKey("[Auto DJ]", "Requeue"), 0)); - m_pConfig->setValue(ConfigKey("[Auto DJ]", "RequeueBuff"), - m_pConfig->getValue(ConfigKey("[Auto DJ]", "Requeue"), 0)); autoDjMinimumAvailableSpinBox->setValue( m_pConfig->getValue( ConfigKey("[Auto DJ]", "MinimumAvailable"), 20)); @@ -132,8 +116,6 @@ void DlgPrefAutoDJ::slotCancel() { void DlgPrefAutoDJ::slotResetToDefaults() { // Re-queue tracks in AutoDJ - ComboBoxAutoDjRequeue->setCurrentIndex(0); - m_pConfig->set(ConfigKey("[Auto DJ]", "RequeueBuff"),ConfigValue(0)); autoDjMinimumAvailableSpinBox->setValue(20); autoDjIgnoreTimeEdit->setTime(QTime::fromString( @@ -149,11 +131,6 @@ void DlgPrefAutoDJ::slotResetToDefaults() { ComboBoxAutoDjRandomQueue->setEnabled(true); } -void DlgPrefAutoDJ::slotSetAutoDjRequeue(int) { - m_pConfig->set(ConfigKey("[Auto DJ]", "RequeueBuff"), - ConfigValue(ComboBoxAutoDjRequeue->currentIndex())); -} - void DlgPrefAutoDJ::slotSetAutoDjMinimumAvailable(int a_iValue) { QString str; str.setNum(a_iValue); diff --git a/src/preferences/dialog/dlgprefautodj.h b/src/preferences/dialog/dlgprefautodj.h index 60a451ee1a6..e0838c2d135 100644 --- a/src/preferences/dialog/dlgprefautodj.h +++ b/src/preferences/dialog/dlgprefautodj.h @@ -20,7 +20,6 @@ class DlgPrefAutoDJ : public DlgPreferencePage, public Ui::DlgPrefAutoDJDlg { void slotCancel() ; private slots: - void slotSetAutoDjRequeue(int); void slotSetAutoDjMinimumAvailable(int); void slotSetAutoDjUseIgnoreTime(int); void slotSetAutoDjIgnoreTime(const QTime &a_rTime); diff --git a/src/preferences/dialog/dlgprefautodjdlg.ui b/src/preferences/dialog/dlgprefautodjdlg.ui index dbfc3e63b02..71fc515e91c 100644 --- a/src/preferences/dialog/dlgprefautodjdlg.ui +++ b/src/preferences/dialog/dlgprefautodjdlg.ui @@ -17,30 +17,13 @@ - - - Re-queue tracks after playback - - - ComboBoxAutoDjRequeue - - - - - - - Add a track to the end of the Auto DJ queue once it is played, instead of removing it. - - - - Minimum available tracks in Track Source - + This percentage of tracks are always available for selecting, regardless of when they were last played. @@ -56,7 +39,7 @@ - + Uncheck, to ignore all played tracks. @@ -66,14 +49,14 @@ - + Suspension period for track selection - + Duration after which a track is eligible for selection by Auto DJ again @@ -86,7 +69,7 @@ - + Enable random track addition to queue @@ -96,21 +79,21 @@ - + Add random tracks from Track Source if the specified minimum tracks remain - + Minimum allowed tracks before addition - + true From 8784be7a225195ddc0db9e58831f81d22cf9543c Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 09:33:00 -0500 Subject: [PATCH 082/198] fix reloading of AutoDJ transition mode on startup Before, DlgAutoDJ assumed that the items in the transition mode combobox were in the same order as the TransitionMode enum class and that the enum class was 0 indexed. This commit removes both those assumptions. --- src/library/autodj/dlgautodj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 2e1cad49bb8..4994a3aa0ed 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -89,7 +89,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); fadeModeCombobox->addItem(tr("Fixed time (skip silence)"), static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); - fadeModeCombobox->setCurrentIndex(static_cast(m_pAutoDJProcessor->getTransitionMode())); + fadeModeCombobox->setCurrentIndex( + fadeModeCombobox->findData(static_cast(m_pAutoDJProcessor->getTransitionMode()))); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( From 73089e55ac0868f26629cba7f04f2b1d8ee516df Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 09:38:20 -0500 Subject: [PATCH 083/198] make AutoDJ TransitionMode enum class 0 indexed --- src/library/autodj/autodjprocessor.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index cd31ac6d29d..3534e7e4442 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -154,10 +154,10 @@ class AutoDJProcessor : public QObject { }; enum class TransitionMode { - IntroOutroSmooth = 1, - IntroOutroQuick = 2, - FixedFullTrack = 3, - FixedSkipSilence = 4 + IntroOutroSmooth, + IntroOutroQuick, + FixedFullTrack, + FixedSkipSilence }; AutoDJProcessor(QObject* pParent, From 932c48c7f3caa1ed4829bbdaf43b991e9e8286c6 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 11:20:22 -0500 Subject: [PATCH 084/198] replace FirstSound & LastSound cue types with one AudibleSound range cue I suggest running delete from cues where type = 9; in the SQLite shell if you used a commit between 648aaa7fd8f6f21995a6d9569a882469f38478b2 and this. --- src/analyzer/analyzersilence.cpp | 30 ++++++++------------------ src/engine/controls/cuecontrol.cpp | 6 +++--- src/library/autodj/autodjprocessor.cpp | 14 ++++++------ src/track/cue.h | 4 ++-- 4 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 2b1214218e8..49b2d16f9ef 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -36,10 +36,9 @@ bool needsOutroCueEnd(const Cue& outroCue) { bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); - CuePointer pFirstSound = pTrack->findCueByType(Cue::Type::FirstSound); - CuePointer pLastSound = pTrack->findCueByType(Cue::Type::LastSound); + CuePointer pAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); - if (!pIntroCue || !pOutroCue || !pFirstSound || !pLastSound) { + if (!pIntroCue || !pOutroCue || !pAudibleSound || pAudibleSound->getLength() <= 0) { return true; } return needsIntroCueStart(*pIntroCue) || needsOutroCueEnd(*pOutroCue); @@ -143,23 +142,12 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pOutroCue->setLength(outroEnd); } - CuePointer pFirstSound = pTrack->findCueByType(Cue::Type::FirstSound); - if (pFirstSound == nullptr) { - pFirstSound = pTrack->createAndAddCue(); - pFirstSound->setType(Cue::Type::FirstSound); - pFirstSound->setSource(Cue::Source::Automatic); - pFirstSound->setPosition(introStart); - } else if (pFirstSound->getSource() != Cue::Source::Manual) { - pFirstSound->setPosition(introStart); - } - - CuePointer pLastSound = pTrack->findCueByType(Cue::Type::LastSound); - if (pLastSound == nullptr) { - pLastSound = pTrack->createAndAddCue(); - pLastSound->setType(Cue::Type::LastSound); - pLastSound->setSource(Cue::Source::Automatic); - pLastSound->setPosition(outroEnd); - } else if (pLastSound->getSource() != Cue::Source::Manual) { - pLastSound->setPosition(outroEnd); + CuePointer pAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); + if (pAudibleSound == nullptr || pAudibleSound->getLength() <= 0) { + pAudibleSound = pTrack->createAndAddCue(); + pAudibleSound->setType(Cue::Type::AudibleSound); + pAudibleSound->setSource(Cue::Source::Automatic); + pAudibleSound->setPosition(introStart); + pAudibleSound->setLength(outroEnd - introStart); } } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 5fc504c20fe..140f7600489 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -346,7 +346,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { // Seek track according to SeekOnLoadMode. SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); - CuePointer pFirstSound = pNewTrack->findCueByType(Cue::Type::FirstSound); + CuePointer pAudibleSound = pNewTrack->findCueByType(Cue::Type::AudibleSound); double introEnd = m_pIntroEndPosition->get(); switch (seekOnLoadMode) { case SeekOnLoadMode::Beginning: @@ -357,8 +357,8 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::FirstSound: - if (pFirstSound) { - seekExact(pFirstSound->getPosition()); + if (pAudibleSound) { + seekExact(pAudibleSound->getPosition()); } else { seekExact(0.0); } diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 0f033fe9da6..bdfaca9a875 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -797,9 +797,9 @@ double AutoDJProcessor::getFirstSoundPosition(DeckAttributes* pDeck) { return 0; } - CuePointer pFromTrackFirstSound = pTrack->findCueByType(Cue::Type::FirstSound); - if (pFromTrackFirstSound) { - return samplePositionToSeconds(pFromTrackFirstSound->getPosition(), pDeck); + CuePointer pFromTrackAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); + if (pFromTrackAudibleSound) { + return samplePositionToSeconds(pFromTrackAudibleSound->getPosition(), pDeck); } else { return 0; } @@ -811,9 +811,11 @@ double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { return 0; } - CuePointer pFromTrackLastSound = pTrack->findCueByType(Cue::Type::LastSound); - if (pFromTrackLastSound) { - return samplePositionToSeconds(pFromTrackLastSound->getPosition(), pDeck); + CuePointer pFromTrackAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); + if (pFromTrackAudibleSound && pFromTrackAudibleSound->getLength() > 0) { + return samplePositionToSeconds( + pFromTrackAudibleSound->getPosition() + pFromTrackAudibleSound->getLength(), + pDeck); } else { return pDeck->duration(); } diff --git a/src/track/cue.h b/src/track/cue.h index 95bbbe58227..fd38d13a570 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -32,8 +32,8 @@ class Cue : public QObject { Jump = 5, Intro = 6, Outro = 7, - FirstSound = 8, // not shown to user - LastSound = 9, // not shown to user + AudibleSound = 8, // range that covers beginning and end of audible sound; + // not shown to user }; ~Cue() override = default; From 1263b461c8578f531acb2e4be7a8d262851192ff Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 14:11:28 -0500 Subject: [PATCH 085/198] fix CueControl tests Delete obsolete tests and update others --- src/test/cuecontrol_test.cpp | 95 ++++++++---------------------------- 1 file changed, 19 insertions(+), 76 deletions(-) diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 63291afb718..0a7a7c9d77d 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -261,79 +261,23 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { } TEST_F(CueControlTest, SeekOnLoadDefault) { + // Default is to load at the intro start TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); - - loadTrack(pTrack); - - EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(100.0, getCurrentSample()); - - // Move cue and check if track is following it. - pTrack->setCuePoint(CuePosition(200.0, Cue::Source::Manual)); - ProcessBuffer(); - - EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(200.0, getCurrentSample()); -} - -TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { - TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(-100.0, Cue::Source::Manual)); - - loadTrack(pTrack); - - EXPECT_DOUBLE_EQ(-100.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(-100.0, getCurrentSample()); - - // Move cue and check if track is following it. - pTrack->setCuePoint(CuePosition(-200.0, Cue::Source::Manual)); - ProcessBuffer(); - - EXPECT_DOUBLE_EQ(-200.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(-200.0, getCurrentSample()); -} - -TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { - TrackPointer pTrack = createTestTrack(); - - loadTrack(pTrack); - - EXPECT_DOUBLE_EQ(-1.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(0.0, getCurrentSample()); - - // Set cue and check if track is seeked to it. - pTrack->setCuePoint(CuePosition(200.0, Cue::Source::Manual)); - ProcessBuffer(); - - EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(200.0, getCurrentSample()); -} - -TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { - // Note: CueRecall uses inverse logic (0 means enabled). - config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(1)); - - TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); - - loadTrack(pTrack); - - EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(0.0, getCurrentSample()); -} - -TEST_F(CueControlTest, SeekOnLoadZeroPos) { - TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); + auto pIntro = pTrack->createAndAddCue(); + pIntro->setType(Cue::Type::Intro); + pIntro->setSource(Cue::Source::Automatic); + pIntro->setPosition(250.0); + pIntro->setLength(150.0); loadTrack(pTrack); - EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(0.0, getCurrentSample()); + EXPECT_DOUBLE_EQ(250.0, m_pIntroStartPosition->get()); + EXPECT_DOUBLE_EQ(250.0, getCurrentSample()); } TEST_F(CueControlTest, SeekOnLoadMainCue) { + config()->set(ConfigKey("[Controls]", "CueRecall"), + ConfigValue(static_cast(SeekOnLoadMode::MainCue))); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); @@ -350,24 +294,23 @@ TEST_F(CueControlTest, SeekOnLoadMainCue) { EXPECT_DOUBLE_EQ(200.0, getCurrentSample()); } -TEST_F(CueControlTest, SeekOnLoadIntroCue) { +TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { + config()->set(ConfigKey("[Controls]", "CueRecall"), + ConfigValue(static_cast(SeekOnLoadMode::MainCue))); TrackPointer pTrack = createTestTrack(); - auto pIntro = pTrack->createAndAddCue(); - pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Manual); - pIntro->setPosition(200.0); + pTrack->setCuePoint(CuePosition(-100.0, Cue::Source::Manual)); loadTrack(pTrack); - EXPECT_DOUBLE_EQ(200.0, m_pIntroStartPosition->get()); - EXPECT_DOUBLE_EQ(200.0, getCurrentSample()); + EXPECT_DOUBLE_EQ(-100.0, m_pCuePoint->get()); + EXPECT_DOUBLE_EQ(-100.0, getCurrentSample()); // Move cue and check if track is following it. - pIntro->setPosition(400.0); + pTrack->setCuePoint(CuePosition(-200.0, Cue::Source::Manual)); ProcessBuffer(); - EXPECT_DOUBLE_EQ(400.0, m_pIntroStartPosition->get()); - EXPECT_DOUBLE_EQ(400.0, getCurrentSample()); + EXPECT_DOUBLE_EQ(-200.0, m_pCuePoint->get()); + EXPECT_DOUBLE_EQ(-200.0, getCurrentSample()); } TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { From e69c34bc326828a76a2070892094e1c3a92640cf Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 14:24:57 -0500 Subject: [PATCH 086/198] fix engine tests --- src/engine/controls/cuecontrol.cpp | 39 ++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 140f7600489..167384a50b4 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -115,7 +115,7 @@ CueControl::CueControl(QString group, m_pPlayIndicator = new ControlIndicator(ConfigKey(group, "play_indicator")); m_pIntroStartPosition = new ControlObject(ConfigKey(group, "intro_start_position")); - m_pIntroStartPosition->set(-1.0); + m_pIntroStartPosition->set(kNoTrigger); m_pIntroStartEnabled = new ControlObject(ConfigKey(group, "intro_start_enabled")); m_pIntroStartEnabled->setReadOnly(); @@ -136,7 +136,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pIntroEndPosition = new ControlObject(ConfigKey(group, "intro_end_position")); - m_pIntroEndPosition->set(-1.0); + m_pIntroEndPosition->set(kNoTrigger); m_pIntroEndEnabled = new ControlObject(ConfigKey(group, "intro_end_enabled")); m_pIntroEndEnabled->setReadOnly(); @@ -157,7 +157,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pOutroStartPosition = new ControlObject(ConfigKey(group, "outro_start_position")); - m_pOutroStartPosition->set(-1.0); + m_pOutroStartPosition->set(kNoTrigger); m_pOutroStartEnabled = new ControlObject(ConfigKey(group, "outro_start_enabled")); m_pOutroStartEnabled->setReadOnly(); @@ -178,7 +178,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pOutroEndPosition = new ControlObject(ConfigKey(group, "outro_end_position")); - m_pOutroEndPosition->set(-1.0); + m_pOutroEndPosition->set(kNoTrigger); m_pOutroEndEnabled = new ControlObject(ConfigKey(group, "outro_end_enabled")); m_pOutroEndEnabled->setReadOnly(); @@ -347,7 +347,16 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); CuePointer pAudibleSound = pNewTrack->findCueByType(Cue::Type::AudibleSound); + double firstSound = kNoTrigger; + if (pAudibleSound) { + firstSound = pAudibleSound->getPosition(); + } + + double introStart = m_pIntroStartPosition->get(); double introEnd = m_pIntroEndPosition->get(); + + double mainCue = m_pCuePoint->get(); + switch (seekOnLoadMode) { case SeekOnLoadMode::Beginning: // This allows users to load tracks and have the needle-drop be maintained. @@ -357,23 +366,33 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::FirstSound: - if (pAudibleSound) { - seekExact(pAudibleSound->getPosition()); + if (firstSound != kNoTrigger) { + seekExact(firstSound); } else { seekExact(0.0); } break; case SeekOnLoadMode::MainCue: - seekExact(m_pCuePoint->get()); + if (mainCue != kNoTrigger) { + seekExact(mainCue); + } else { + seekExact(0.0); + } break; case SeekOnLoadMode::IntroStart: - seekExact(m_pIntroStartPosition->get()); + if (introStart != kNoTrigger) { + seekExact(introStart); + } else { + seekExact(0.0); + } break; case SeekOnLoadMode::IntroEnd: - if (introEnd >= 0) { + if (introEnd != kNoTrigger) { seekExact(introEnd); + } else if (introStart != kNoTrigger) { + seekExact(introStart); } else { - seekExact(m_pIntroStartPosition->get()); + seekExact(0.0); } break; default: From 461b7cafa90dd1f034f546b2a95960825bf2f60c Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 14:48:44 -0500 Subject: [PATCH 087/198] AutoDJ: update transition mode tooltip --- src/library/autodj/dlgautodj.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 4994a3aa0ed..d0f1e5f4aa0 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -94,15 +94,17 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( - "Align intro + outro start/end modes:\n" - "Align the start/end of the intro of the next track with the\n" - "start/end of the outro of the current track. The length of\n" - "the intro or outro range is used as the transition time,\n" - "whichever is shorter. The selected number of seconds is\n" - "only used if neither track has an intro or outro range marked." - "\n\n" + "Intro/Outro (smooth transition):\n" + "Play the full intro and outro. The intro or outro time is\n" + "used as the crossfade time, whichever is shorter.\n" + "\n" + "Intro/Outro (quick transition):\n" + "Cut off part of the intro or outro, whichever is longer.\n" + "The intro or outro time is used as the crossfade time,\n" + "whichever is shorter.\n" + "\n" "Fixed time modes:\n" - "Use the selected number of seconds as the transition time." + "Use the selected number of seconds as the crossfade time." ); fadeModeCombobox->setToolTip(fadeModeTooltip); fadeModeLabel->setToolTip(fadeModeTooltip); From f846e679ae46dc2844b2c856a3652c1313bcd0dc Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 17:53:07 -0500 Subject: [PATCH 088/198] remove "Intro/Outro (quick transition)" mode; leave only the smooth mode --- src/library/autodj/autodjprocessor.cpp | 61 +++----------------------- src/library/autodj/autodjprocessor.h | 3 +- src/library/autodj/dlgautodj.cpp | 13 ++---- 3 files changed, 9 insertions(+), 68 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index bdfaca9a875..d102f06f2d9 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -161,7 +161,7 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, int configuredTransitionMode = m_pConfig->getValue( ConfigKey(kConfigKey, kTransitionModePreferenceName), - static_cast(TransitionMode::IntroOutroSmooth)); + static_cast(TransitionMode::IntroOutro)); m_transitionMode = static_cast(configuredTransitionMode); } @@ -931,16 +931,11 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double introLength = introEnd - introStart; - // For both the AlignIntroOutroStart & AlignIntroOutroEnd TransitionModes, - // fadeDuration is the intro or outro length, whichever is shorter. This - // is the best way to avoid clashing sounds overlapping. If only one track - // has an intro or outro range marked (not just one point of the range, but - // the full range with the end and beginning markers), use the length of - // that range as the transition time as a best guess. Only fall back to the - // fixed number of seconds from the spinbox as a last resort. switch (m_transitionMode) { - case TransitionMode::IntroOutroSmooth: - // Let the full outro and intro play; do not cut off any part of either. + case TransitionMode::IntroOutro: + // Use the outro or intro length for the transition time, whichever is + // shorter. Let the full outro and intro play; do not cut off any part + // of either. // // In the diagrams below, // - is part of a track outside the outro/intro, @@ -983,52 +978,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; - case TransitionMode::IntroOutroQuick: - // Start fading at the outroStart and end fading at the introEnd, - // cutting off some of the outro or intro (whichever is longer) to - // minimize the transition time. - // - // In the diagrams below, - // - is part of a track outside the outro/intro, - // o is part of the outro - // i is part of the intro - // | marks the boundaries of the transition - // - // When outro > intro: - // ------|ooo|ooo - // |iii|------ - // - // When outro < intro: - // ------|ooo| - // iii|iii|------ - // - // If only the outro or intro length is marked but not both, use the one - // that is marked for the transition time. If neither is marked, fall - // back to the transition time from the spinbox. - if (outroLength > 0 && introLength > 0) { - if (outroLength > introLength) { - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeEndPos = outroStart + introLength; - pToDeck->startPos = introStart; - } else { - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeEndPos = outroEnd; - pToDeck->startPos = introEnd - outroLength; - } - } else if (outroLength > 0 && introLength <= 0) { - pFromDeck->fadeBeginPos = outroStart; - pFromDeck->fadeEndPos = outroEnd; - pToDeck->startPos = introStart; - } else if (introLength < 0 && outroLength <= 0) { - pFromDeck->fadeBeginPos = outroEnd - introLength; - pFromDeck->fadeEndPos = outroEnd; - pToDeck->startPos = introStart; - } else { - useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), - getFirstSoundPosition(pToDeck)); - } - break; case TransitionMode::FixedSkipSilence: if (fadeNow) { useFixedFadeTime(pFromDeck, diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 3534e7e4442..d507842e0b2 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -154,8 +154,7 @@ class AutoDJProcessor : public QObject { }; enum class TransitionMode { - IntroOutroSmooth, - IntroOutroQuick, + IntroOutro, FixedFullTrack, FixedSkipSilence }; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index d0f1e5f4aa0..650f2f8611f 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -81,10 +81,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); - fadeModeCombobox->addItem(tr("Intro/Outro (smooth transition)"), - static_cast(AutoDJProcessor::TransitionMode::IntroOutroSmooth)); - fadeModeCombobox->addItem(tr("Intro/Outro (quick transition)"), - static_cast(AutoDJProcessor::TransitionMode::IntroOutroQuick)); + fadeModeCombobox->addItem(tr("Intro/Outro"), + static_cast(AutoDJProcessor::TransitionMode::IntroOutro)); fadeModeCombobox->addItem(tr("Fixed time (full track)"), static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); fadeModeCombobox->addItem(tr("Fixed time (skip silence)"), @@ -94,12 +92,7 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( - "Intro/Outro (smooth transition):\n" - "Play the full intro and outro. The intro or outro time is\n" - "used as the crossfade time, whichever is shorter.\n" - "\n" - "Intro/Outro (quick transition):\n" - "Cut off part of the intro or outro, whichever is longer.\n" + "Intro/Outro:\n" "The intro or outro time is used as the crossfade time,\n" "whichever is shorter.\n" "\n" From bd39923bdf5eb212fab885cf80fa3511aa27e79b Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 19:25:50 -0500 Subject: [PATCH 089/198] remove option to load decks at intro end We could not think of a use case for this. --- src/engine/controls/cuecontrol.cpp | 11 ----------- src/engine/controls/cuecontrol.h | 1 - src/preferences/dialog/dlgprefdeck.cpp | 1 - 3 files changed, 13 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 167384a50b4..0c1cafe804f 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -353,8 +353,6 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } double introStart = m_pIntroStartPosition->get(); - double introEnd = m_pIntroEndPosition->get(); - double mainCue = m_pCuePoint->get(); switch (seekOnLoadMode) { @@ -386,15 +384,6 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { seekExact(0.0); } break; - case SeekOnLoadMode::IntroEnd: - if (introEnd != kNoTrigger) { - seekExact(introEnd); - } else if (introStart != kNoTrigger) { - seekExact(introStart); - } else { - seekExact(0.0); - } - break; default: seekExact(0.0); break; diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index f1310f86d26..402b84c7556 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -23,7 +23,6 @@ enum class SeekOnLoadMode { Beginning = 1, // Use 0:00.000 FirstSound = 2, // Skip leading silence IntroStart = 3, // Use intro start cue point - IntroEnd = 4, // Use intro end cue point }; inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 6112502412c..173ec8086fd 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -159,7 +159,6 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, this, SLOT(slotDisallowTrackLoadToPlayingDeckCheckbox(bool))); comboBoxLoadPoint->addItem(tr("Intro start"), static_cast(SeekOnLoadMode::IntroStart)); - comboBoxLoadPoint->addItem(tr("Intro end"), static_cast(SeekOnLoadMode::IntroEnd)); comboBoxLoadPoint->addItem(tr("Main cue"), static_cast(SeekOnLoadMode::MainCue)); comboBoxLoadPoint->addItem(tr("First sound (skip silence)"), static_cast(SeekOnLoadMode::FirstSound)); comboBoxLoadPoint->addItem(tr("Beginning of track"), static_cast(SeekOnLoadMode::Beginning)); From 7cdb5ed17e816408dce0305a6d11e950a5e05037 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 19:26:38 -0500 Subject: [PATCH 090/198] reimplement Align Intro + Outro Start mode --- src/library/autodj/autodjprocessor.cpp | 45 ++++++++++++++++++++++++++ src/library/autodj/autodjprocessor.h | 1 + src/library/autodj/dlgautodj.cpp | 18 +++++++---- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index d102f06f2d9..edc8a2ebb8b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -978,6 +978,51 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; + case TransitionMode::AlignIntroOutroStart: + // Use the outro or intro length for the transition time, whichever is + // shorter. If the outro is longer than the intro, cut off the end + // of the outro. + // + // In the diagrams below, + // - is part of a track outside the outro/intro, + // o is part of the outro + // i is part of the intro + // | marks the boundaries of the transition + // + // When outro > intro: + // ------|ooo|ooo + // |iii|------ + // + // When outro < intro: + // ------|ooo| + // |iii|iii----- + // + // If only the outro or intro length is marked but not both, use the one + // that is marked for the transition time. If neither is marked, fall + // back to the transition time from the spinbox. + if (outroLength > 0 && introLength > 0) { + pFromDeck->fadeBeginPos = outroStart; + if (outroLength > introLength) { + // Cut off end of outro + pFromDeck->fadeEndPos = outroStart + introLength; + } else { + pFromDeck->fadeEndPos = outroEnd; + } + pToDeck->startPos = introStart; + } else if (outroLength > 0 && introLength <= 0) { + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } else if (introLength > 0 && outroLength <= 0) { + pFromDeck->fadeBeginPos = outroEnd - introLength; + pFromDeck->fadeEndPos = outroEnd; + pToDeck->startPos = introStart; + } else { + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), + getFirstSoundPosition(pToDeck)); + } + break; case TransitionMode::FixedSkipSilence: if (fadeNow) { useFixedFadeTime(pFromDeck, diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index d507842e0b2..428ce3a835f 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -155,6 +155,7 @@ class AutoDJProcessor : public QObject { enum class TransitionMode { IntroOutro, + AlignIntroOutroStart, FixedFullTrack, FixedSkipSilence }; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 650f2f8611f..cb01c90bd9a 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -81,22 +81,26 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); - fadeModeCombobox->addItem(tr("Intro/Outro"), + fadeModeCombobox->addItem(tr("Intro + Outro"), static_cast(AutoDJProcessor::TransitionMode::IntroOutro)); - fadeModeCombobox->addItem(tr("Fixed time (full track)"), + fadeModeCombobox->addItem(tr("Align Intro + Outro Start"), + static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); + fadeModeCombobox->addItem(tr("Fixed Time (full track)"), static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); - fadeModeCombobox->addItem(tr("Fixed time (skip silence)"), + fadeModeCombobox->addItem(tr("Fixed Time (skip silence)"), static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->setCurrentIndex( fadeModeCombobox->findData(static_cast(m_pAutoDJProcessor->getTransitionMode()))); connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( - "Intro/Outro:\n" - "The intro or outro time is used as the crossfade time,\n" - "whichever is shorter.\n" + "Intro + Outro and Align Intro + Outro Start:\n" + "Both modes use the intro or outro time as the crossfade time,\n" + "whichever is shorter. Intro + Outro mode plays the whole\n" + "intro and outro every time; Align Intro + Outro Start cuts off\n" + "the end of the outro when the outro is longer than the intro.\n" "\n" - "Fixed time modes:\n" + "Fixed Time modes:\n" "Use the selected number of seconds as the crossfade time." ); fadeModeCombobox->setToolTip(fadeModeTooltip); From 429da1296eee2125a0dc476fbdaa3663058ca493 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 19:38:03 -0500 Subject: [PATCH 091/198] AutoDJ: edit transition mode tooltip --- src/library/autodj/dlgautodj.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index cb01c90bd9a..1b2763a41a3 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -94,11 +94,14 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( - "Intro + Outro and Align Intro + Outro Start:\n" - "Both modes use the intro or outro time as the crossfade time,\n" - "whichever is shorter. Intro + Outro mode plays the whole\n" - "intro and outro every time; Align Intro + Outro Start cuts off\n" - "the end of the outro when the outro is longer than the intro.\n" + "Intro + Outro:\n" + "Use the intro or outro length as the crossfade time, whichever\n" + "is shorter. Always play the full intro and outro.\n" + "\n" + "Align Intro + Outro Start:\n" + "Use the intro or outro length as the crossfade time, whichever\n" + "is shorter. Cut off the end of the outro when the outro is\n" + "longer than the intro.\n" "\n" "Fixed Time modes:\n" "Use the selected number of seconds as the crossfade time." From 611503c54a49d3df672e20fc69da651fe873abe0 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 23:27:27 -0500 Subject: [PATCH 092/198] AutoDJ: let user seek to end of next deck to set outro cues --- src/library/autodj/autodjprocessor.cpp | 60 +++++++++++++++++++------- src/library/autodj/autodjprocessor.h | 1 + 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index edc8a2ebb8b..559deb0aded 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -26,6 +26,7 @@ DeckAttributes::DeckAttributes(int index, startPos(kKeepPosition), fadeBeginPos(1.0), fadeEndPos(1.0), + isFromDeck(false), loading(false), m_orientation(orientation), m_playPos(group, "playposition"), @@ -545,7 +546,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // - transition into fading mode, play the other deck and fade to it. // - check if fading is done and stop the deck // - update the crossfader - if (thisPlayPosition >= thisDeck.fadeBeginPos) { + if (thisPlayPosition >= thisDeck.fadeBeginPos && thisDeck.isFromDeck) { if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { if (!otherDeckPlaying) { @@ -711,20 +712,16 @@ bool AutoDJProcessor::removeTrackFromTopOfQueue(TrackPointer pTrack) { return true; } -void AutoDJProcessor::playerPlayChanged(DeckAttributes* pAttributes, bool playing) { +void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) { if (sDebug) { - qDebug() << this << "playerPlayChanged" << pAttributes->group << playing; + qDebug() << this << "playerPlayChanged" << thisDeck->group << playing; } - // We may want to do more than just calculate fade thresholds when playing - // state changes so keep these two as separate methods for now. - - // This will calculate the Transition to the already loaded, in most cases - // already played other track. - // This is required because the user may have loaded a track or changed play - // manually - if (playing) { - calculateTransition(pAttributes, getOtherDeck(pAttributes), false, false); + // In case both decks were stopped and now this one just started, make this + // deck the "from deck". + if (playing && !getOtherDeck(thisDeck)->isPlaying()) { + calculateTransition(thisDeck, getOtherDeck(thisDeck), false, false); } + } void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, double position) { @@ -732,8 +729,15 @@ void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, doubl qDebug() << this << "playerIntroStartChanged" << pAttributes->group << position; } + DeckAttributes* fromDeck; + if (pAttributes->isFromDeck) { + fromDeck = pAttributes; + } else { + fromDeck = getOtherDeck(pAttributes); + } + if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false, false); } } @@ -742,8 +746,15 @@ void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double qDebug() << this << "playerIntroEndChanged" << pAttributes->group << position; } + DeckAttributes* fromDeck; + if (pAttributes->isFromDeck) { + fromDeck = pAttributes; + } else { + fromDeck = getOtherDeck(pAttributes); + } + if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(getOtherDeck(pAttributes, true), pAttributes, false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false, false); } } @@ -752,8 +763,15 @@ void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, doubl qDebug() << this << "playerOutroStartChanged" << pAttributes->group << position; } + DeckAttributes* fromDeck; + if (pAttributes->isFromDeck) { + fromDeck = pAttributes; + } else { + fromDeck = getOtherDeck(pAttributes); + } + if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false, false); } } @@ -762,8 +780,15 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double qDebug() << this << "playerOutroEndChanged" << pAttributes->group << position; } + DeckAttributes* fromDeck; + if (pAttributes->isFromDeck) { + fromDeck = pAttributes; + } else { + fromDeck = getOtherDeck(pAttributes); + } + if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(pAttributes, getOtherDeck(pAttributes, false), false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false, false); } } @@ -1050,6 +1075,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeEndPos /= fromTrackDuration; pToDeck->startPos /= toTrackDuration; + pFromDeck->isFromDeck = true; + pToDeck->isFromDeck = false; + DEBUG_ASSERT(pFromDeck->fadeBeginPos <= 1); if (sDebug) { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 428ce3a835f..bfb871e7dac 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -116,6 +116,7 @@ class DeckAttributes : public QObject { double startPos; // Set in toDeck nature double fadeBeginPos; // set in fromDeck nature double fadeEndPos; // set in fromDeck nature + bool isFromDeck; bool loading; // The data is inconsistent during loading a deck private: From 8e6268b384df616dcd312a26a9adde96ac21508b Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 23:28:40 -0500 Subject: [PATCH 093/198] AutoDJ: if the "to deck" is played to the end, seek back to the start --- src/library/autodj/autodjprocessor.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 559deb0aded..ac089a9e117 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -722,6 +722,16 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) calculateTransition(thisDeck, getOtherDeck(thisDeck), false, false); } + // If the user manually pressed play on the "to deck" before fading, for + // example to adjust the intro/outro cues, and lets the deck play until the + // end, seek back to the start point instead of keeping the deck stopped at + // the end. + if (!playing && thisDeck->playPosition() == 1.0 && !thisDeck->isFromDeck) { + if (thisDeck->startPos == kKeepPosition) { + calculateTransition(getOtherDeck(thisDeck), thisDeck, false, true); + } + thisDeck->setPlayPosition(thisDeck->startPos); + } } void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, double position) { From 2e045d32adb3b10bb1c3f40f675ab5f6d981dc32 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 10 Aug 2019 23:36:06 -0500 Subject: [PATCH 094/198] fix segfault in AutoDJ tests --- src/library/autodj/autodjprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index ac089a9e117..4e4d1bf967b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -884,7 +884,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, bool fadeNow, bool seekToStartPoint) { - if (pFromDeck == nullptr) { + if (pFromDeck == nullptr || pToDeck == nullptr) { return; } From 888464b44302277f4dc2548fb253f71b36c92a2d Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 11 Aug 2019 00:08:00 -0500 Subject: [PATCH 095/198] AutoDJ: workaround to avoid weird state with deck cloning feature --- src/library/autodj/autodjprocessor.cpp | 11 ++++++++++- src/library/autodj/autodjprocessor.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 4e4d1bf967b..faa22e88af5 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -644,6 +644,15 @@ TrackPointer AutoDJProcessor::getNextTrackFromQueue() { bool AutoDJProcessor::loadNextTrackFromQueue(const DeckAttributes& deck, bool play) { TrackPointer nextTrack = getNextTrackFromQueue(); + // Don't try to mix a track into itself. This can get AutoDJ into a weird + // state when combined with the deck cloning feature. This situation can + // happen if the user repeatedly presses the "Skip track" button with the + // repeat playlist feature enabled. + if (nextTrack == getOtherDeck(&deck)->getLoadedTrack()) { + removeTrackFromTopOfQueue(nextTrack); + nextTrack = getNextTrackFromQueue(); + } + // We ran out of tracks in the queue. if (!nextTrack) { // Disable AutoDJ. @@ -1262,7 +1271,7 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { } } -DeckAttributes* AutoDJProcessor::getOtherDeck(DeckAttributes* pThisDeck, +DeckAttributes* AutoDJProcessor::getOtherDeck(const DeckAttributes* pThisDeck, bool playing) { DeckAttributes* pOtherDeck = NULL; if (pThisDeck->isLeft()) { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index bfb871e7dac..3fed47a133a 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -255,7 +255,7 @@ class AutoDJProcessor : public QObject { bool seekToStartPoint); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); - DeckAttributes* getOtherDeck(DeckAttributes* pFromDeck, + DeckAttributes* getOtherDeck(const DeckAttributes* pFromDeck, bool playing = false); // Removes the track loaded to the player group from the top of the AutoDJ From 05beecf5b12b7d8a3f52c9d79299be508034d981 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 12 Aug 2019 12:53:05 -0500 Subject: [PATCH 096/198] AutoDJ: fix transitions with a transition time of 0 --- src/library/autodj/autodjprocessor.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index faa22e88af5..1786e598574 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -586,6 +586,14 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, m_transitionProgress = 1.0; } else { // We are in Fading state. + + // The math below will not work with a transition time of 0. + if (thisDeck.fadeBeginPos == thisDeck.fadeEndPos) { + setCrossfader(crossfaderTarget); + m_transitionProgress = 1.0; + return; + } + // Calculate the current transitionProgress, the place between begin // and end position and the step we have taken since the last call double transitionProgress = (thisPlayPosition - thisDeck.fadeBeginPos) / From 620e5f67599131718c36eba9db0370391916f5cc Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 12 Aug 2019 13:31:35 -0500 Subject: [PATCH 097/198] AutoDJ: use intro length as transition time for "Fade now" button ... when using the transition modes which use the intro & outro markers. Also, separate the "Fade now" button logic from the calculateTransition function. --- src/library/autodj/autodjprocessor.cpp | 164 +++++++++++++++---------- src/library/autodj/autodjprocessor.h | 1 - 2 files changed, 96 insertions(+), 69 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 1786e598574..7b19e8778b7 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -215,22 +215,75 @@ void AutoDJProcessor::fadeNow() { } double crossfader = getCrossfader(); - DeckAttributes& leftDeck = *m_decks[0]; - DeckAttributes& rightDeck = *m_decks[1]; - if (leftDeck.isPlaying() && - (!rightDeck.isPlaying() || crossfader < 0.0)) { - // Make sure leftDeck.fadeDuration is up to date. - calculateTransition(&leftDeck, &rightDeck, true, false); - // Repeat is disabled by FadeNow but disables auto Fade - leftDeck.setRepeat(false); - } else if (rightDeck.isPlaying()) { - // Make sure rightDeck.fadeDuration is up to date. - calculateTransition(&rightDeck, &leftDeck, true, false); - // Repeat is disabled by FadeNow but disables auto Fade - rightDeck.setRepeat(false); - } - //else { - // No deck playing, do not know what to do + DeckAttributes* pLeftDeck = m_decks[0]; + DeckAttributes* pRightDeck = m_decks[1]; + DeckAttributes* pFromDeck; + DeckAttributes* pToDeck; + + if (pLeftDeck->isPlaying() && + (!pRightDeck->isPlaying() || crossfader < 0.0)) { + pFromDeck = pLeftDeck; + pToDeck = pRightDeck; + } else if (pRightDeck->isPlaying()) { + pFromDeck = pRightDeck; + pToDeck = pLeftDeck; + } else { + // Both decks are playing or no decks are playing; + // fading now makes no sense. + return; + } + + pFromDeck->setRepeat(false); + pFromDeck->isFromDeck = true; + pToDeck->isFromDeck = false; + + double fromDeckCurrentPosition = pFromDeck->playPosition() * pFromDeck->duration(); + double toDeckCurrentPosition = pToDeck->playPosition() * pToDeck->duration(); + + pFromDeck->fadeBeginPos = fromDeckCurrentPosition; + // Do not seek to a calculated start point; start the to deck from wherever + // it is if the user has seeked since loading the track. + pToDeck->startPos = toDeckCurrentPosition; + + // If the user presses "Fade now", assume they want to fade *now*, not later. + // So if the spinbox time is negative, do not insert silence. + double spinboxTime = fabs(m_transitionTime); + + double fadeTime; + if (m_transitionMode == TransitionMode::IntroOutro + || m_transitionMode == TransitionMode::AlignIntroOutroStart) { + // Use the intro length as the transition time. If the user has seeked + // away from the intro start since the track was loaded, start from + // there and do not seek back to the intro start. If they have seeked + // past the introEnd or the introEnd is not marked, fall back to the + // spinbox time. + double outroEnd = getOutroEndPosition(pFromDeck); + double introEnd = getIntroEndPosition(pToDeck); + + if (toDeckCurrentPosition <= introEnd && introEnd >= 0) { + double introLength = introEnd - toDeckCurrentPosition; + if (outroEnd >= 0) { + // The fade must end by the outro end at the latest. + double timeUntilOutroEnd = outroEnd - fromDeckCurrentPosition; + fadeTime = math_min(introLength, timeUntilOutroEnd); + } else { + fadeTime = introLength; + } + } else { + fadeTime = spinboxTime; + } + } else { + fadeTime = spinboxTime; + } + + double timeUntilEndOfFromTrack = pFromDeck->duration() - fromDeckCurrentPosition; + fadeTime = math_min(fadeTime, timeUntilEndOfFromTrack); + pFromDeck->fadeEndPos = fromDeckCurrentPosition + fadeTime; + + // These are expected to be a fraction of the track length. + pFromDeck->fadeBeginPos /= pFromDeck->duration(); + pFromDeck->fadeEndPos /= pFromDeck->duration(); + pToDeck->startPos /= pToDeck->duration(); } AutoDJProcessor::AutoDJError AutoDJProcessor::skipNext() { @@ -494,7 +547,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } else { // At least right deck is playing // Set crossfade thresholds for right deck. - calculateTransition(&rightDeck, &leftDeck, false, false); + calculateTransition(&rightDeck, &leftDeck, false); } emitAutoDJStateChanged(m_eState); } @@ -535,7 +588,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // new position. // This can be our own seek to startPos or a random seek by a user. // we need to call calculateTransition() because we are not sure. - calculateTransition(&otherDeck, &thisDeck, false, false); + calculateTransition(&otherDeck, &thisDeck, false); } else if (thisDeck.isRepeat()) { // repeat pauses auto DJ return; @@ -613,7 +666,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } m_transitionProgress = transitionProgress; // if we are at 1.0 here, we need an additional callback until the last - // step is processed and we can stop the deck. + // step is processed and we can stop the deck. } } } @@ -736,7 +789,7 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) // In case both decks were stopped and now this one just started, make this // deck the "from deck". if (playing && !getOtherDeck(thisDeck)->isPlaying()) { - calculateTransition(thisDeck, getOtherDeck(thisDeck), false, false); + calculateTransition(thisDeck, getOtherDeck(thisDeck), false); } // If the user manually pressed play on the "to deck" before fading, for @@ -745,7 +798,7 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) // the end. if (!playing && thisDeck->playPosition() == 1.0 && !thisDeck->isFromDeck) { if (thisDeck->startPos == kKeepPosition) { - calculateTransition(getOtherDeck(thisDeck), thisDeck, false, true); + calculateTransition(getOtherDeck(thisDeck), thisDeck, true); } thisDeck->setPlayPosition(thisDeck->startPos); } @@ -764,7 +817,7 @@ void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, doubl } if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false); } } @@ -781,7 +834,7 @@ void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double } if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false); } } @@ -798,7 +851,7 @@ void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, doubl } if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false); } } @@ -815,7 +868,7 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double } if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false, false); + calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false); } } @@ -899,7 +952,6 @@ double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttri void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, - bool fadeNow, bool seekToStartPoint) { if (pFromDeck == nullptr || pToDeck == nullptr) { return; @@ -939,31 +991,18 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // Within this function, the outro refers to the outro of the currently // playing track and the intro refers to the intro of the next track. - double outroStart; - double outroEnd = getOutroEndPosition(pFromDeck); - - if (fadeNow) { - // Assume that the outro starts now and equals the given transition time - // but do not pass the original outroEnd - outroStart = pFromDeck->playPosition() * fromTrackDuration; - // if one uses fadeNow with a gap transition we take this time for fading here - double transitionTime = fabs(m_transitionTime); - if (outroEnd > outroStart) { - outroEnd = math_min(outroEnd, outroStart + transitionTime); - } else { - outroEnd = math_min(fromTrackDuration, outroStart + transitionTime); - } - } else { - outroStart = getOutroStartPosition(pFromDeck); - if (outroStart <= 0.0) { - // Assume a zero length outro. - // The outroEnd is automatically placed by AnalyzerSilence, so use - // that as a fallback if the user has not placed outroStart. + double outroStart = getOutroStartPosition(pFromDeck); + if (outroStart <= 0.0) { + // Assume a zero length outro. + // The outroEnd is automatically placed by AnalyzerSilence, so use + // that as a fallback if the user has not placed outroStart. + if (outroEnd >= 0) { outroStart = outroEnd; + } else { + outroEnd = fromTrackDuration; } } - double outroLength = outroEnd - outroStart; double introStart; @@ -1076,25 +1115,14 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } break; case TransitionMode::FixedSkipSilence: - if (fadeNow) { - useFixedFadeTime(pFromDeck, - pToDeck, - outroEnd, - getFirstSoundPosition(pToDeck)); - } else { - useFixedFadeTime(pFromDeck, - pToDeck, - getLastSoundPosition(pFromDeck), - getFirstSoundPosition(pToDeck)); - } + useFixedFadeTime(pFromDeck, + pToDeck, + getLastSoundPosition(pFromDeck), + getFirstSoundPosition(pToDeck)); break; case TransitionMode::FixedFullTrack: default: - if (fadeNow) { - useFixedFadeTime(pFromDeck, pToDeck, outroEnd, 0); - } else { - useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); - } + useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); } // These are expected to be a fraction of the track length. @@ -1164,7 +1192,7 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra // (ADJ_ENABLE_P1LOADED state) then play the track. loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } else { - calculateTransition(getOtherDeck(pDeck, true), pDeck, false, true); + calculateTransition(getOtherDeck(pDeck, true), pDeck, true); if (pDeck->startPos != kKeepPosition) { // Note: this seek will trigger the playerPositionChanged slot // which may calls the calculateTransition() again without seek = true; @@ -1240,10 +1268,10 @@ void AutoDJProcessor::setTransitionTime(int time) { DeckAttributes& leftDeck = *m_decks[0]; DeckAttributes& rightDeck = *m_decks[1]; if (leftDeck.isPlaying()) { - calculateTransition(&leftDeck, &rightDeck, false, false); + calculateTransition(&leftDeck, &rightDeck, false); } if (rightDeck.isPlaying()) { - calculateTransition(&rightDeck, &leftDeck, false, false); + calculateTransition(&rightDeck, &leftDeck, false); } } } @@ -1259,14 +1287,14 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { DeckAttributes& rightDeck = *m_decks[1]; if (leftDeck.isPlaying() && !rightDeck.isPlaying()) { - calculateTransition(&leftDeck, &rightDeck, false, true); + calculateTransition(&leftDeck, &rightDeck, true); if (rightDeck.startPos != kKeepPosition) { // Note: this seek will trigger the playerPositionChanged slot // which may calls the calculateTransition() again without seek = true; rightDeck.setPlayPosition(rightDeck.startPos); } } else if (rightDeck.isPlaying() && !leftDeck.isPlaying()) { - calculateTransition(&rightDeck, &leftDeck, false, true); + calculateTransition(&rightDeck, &leftDeck, true); if (leftDeck.startPos != kKeepPosition) { // Note: this seek will trigger the playerPositionChanged slot // which may calls the calculateTransition() again without seek = true; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 3fed47a133a..7666c5c9b21 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -251,7 +251,6 @@ class AutoDJProcessor : public QObject { bool loadNextTrackFromQueue(const DeckAttributes& pDeck, bool play = false); void calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, - bool fadeNow, bool seekToStartPoint); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double endPoint, double startPoint); From 107c61d270ebd6350825fa3a2a67d9ed5ed24dbb Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 12 Aug 2019 15:34:30 -0500 Subject: [PATCH 098/198] remove useless tracking of automatic vs manually placed cues This was introduced in PR #1242 but is no longer used. --- res/schema.xml | 11 +-- src/analyzer/analyzersilence.cpp | 24 +------ src/engine/controls/cuecontrol.cpp | 25 +++---- src/engine/controls/cuecontrol.h | 2 +- src/library/dao/cuedao.cpp | 8 +-- src/library/dao/trackdao.cpp | 2 +- src/mixer/basetrackplayer.cpp | 1 - src/test/analyzersilence_test.cpp | 104 +---------------------------- src/test/cuecontrol_test.cpp | 37 +++------- src/track/cue.cpp | 20 +----- src/track/cue.h | 33 ++------- src/track/track.cpp | 4 +- 12 files changed, 40 insertions(+), 231 deletions(-) diff --git a/res/schema.xml b/res/schema.xml index 8b9040538e7..fc6cc4ca890 100644 --- a/res/schema.xml +++ b/res/schema.xml @@ -440,11 +440,12 @@ METADATA - Add source to cue. Default is MANUAL. - + This was used in the development of 2.3 to track whether cues were placed + manually or automatically. However, this turned out to be unnecessary. + This version is left as a placeholder so users who were using the master + branch will have their database updated correctly for the subsequent + schema change. - - ALTER TABLE cues ADD COLUMN source INTEGER DEFAULT 2 NOT NULL; - + diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 49b2d16f9ef..423ddef5881 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -10,8 +10,7 @@ constexpr float kSilenceThreshold = 0.001; //constexpr float kSilenceThreshold = db2ratio(-60.0f); bool shouldUpdateMainCue(CuePosition mainCue) { - return mainCue.getSource() != Cue::Source::Manual || - mainCue.getPosition() == -1.0 || + return mainCue.getPosition() == -1.0 || mainCue.getPosition() == 0.0; } @@ -23,16 +22,6 @@ bool hasOutroCueEnd(const Cue& outroCue) { return outroCue.getEndPosition() > 0.0; } -bool needsIntroCueStart(const Cue& introCue) { - return introCue.getSource() != Cue::Source::Manual && - !hasIntroCueStart(introCue); -} - -bool needsOutroCueEnd(const Cue& outroCue) { - return outroCue.getSource() != Cue::Source::Manual && - !hasOutroCueEnd(outroCue); -} - bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); @@ -41,7 +30,7 @@ bool shouldAnalyze(TrackPointer pTrack) { if (!pIntroCue || !pOutroCue || !pAudibleSound || pAudibleSound->getLength() <= 0) { return true; } - return needsIntroCueStart(*pIntroCue) || needsOutroCueEnd(*pOutroCue); + return !hasIntroCueStart(*pIntroCue) || !hasOutroCueEnd(*pOutroCue); } } // anonymous namespace @@ -117,16 +106,13 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { double outroEnd = mixxx::kAnalysisChannels * m_iSignalEnd; if (shouldUpdateMainCue(pTrack->getCuePoint())) { - pTrack->setCuePoint(CuePosition(introStart, Cue::Source::Automatic)); + pTrack->setCuePoint(CuePosition(introStart)); } CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); if (!pIntroCue) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::Source::Automatic); - } - if (pIntroCue->getSource() != Cue::Source::Manual) { pIntroCue->setPosition(introStart); pIntroCue->setLength(0.0); } @@ -135,9 +121,6 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { if (!pOutroCue) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::Source::Automatic); - } - if (pOutroCue->getSource() != Cue::Source::Manual) { pOutroCue->setPosition(-1.0); pOutroCue->setLength(outroEnd); } @@ -146,7 +129,6 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { if (pAudibleSound == nullptr || pAudibleSound->getLength() <= 0) { pAudibleSound = pTrack->createAndAddCue(); pAudibleSound->setType(Cue::Type::AudibleSound); - pAudibleSound->setSource(Cue::Source::Automatic); pAudibleSound->setPosition(introStart); pAudibleSound->setLength(outroEnd - introStart); } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 0c1cafe804f..c37e17d898d 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -443,9 +443,7 @@ void CueControl::loadCuesFromTrack() { if (pLoadCue) { double position = pLoadCue->getPosition(); - Cue::Source source = pLoadCue->getSource(); - - m_pCuePoint->set(quantizeCuePoint(position, source, QuantizeMode::ClosestBeat)); + m_pCuePoint->set(quantizeCuePoint(position, QuantizeMode::ClosestBeat)); } else { m_pCuePoint->set(-1.0); } @@ -453,11 +451,10 @@ void CueControl::loadCuesFromTrack() { if (pIntroCue) { double startPosition = pIntroCue->getPosition(); double endPosition = pIntroCue->getEndPosition(); - Cue::Source source = pIntroCue->getSource(); - m_pIntroStartPosition->set(quantizeCuePoint(startPosition, source, QuantizeMode::PreviousBeat)); + m_pIntroStartPosition->set(quantizeCuePoint(startPosition, QuantizeMode::PreviousBeat)); m_pIntroStartEnabled->forceSet(startPosition == -1.0 ? 0.0 : 1.0); - m_pIntroEndPosition->set(quantizeCuePoint(endPosition, source, QuantizeMode::NextBeat)); + m_pIntroEndPosition->set(quantizeCuePoint(endPosition, QuantizeMode::NextBeat)); m_pIntroEndEnabled->forceSet(endPosition == -1.0 ? 0.0 : 1.0); } else { m_pIntroStartPosition->set(-1.0); @@ -469,11 +466,10 @@ void CueControl::loadCuesFromTrack() { if (pOutroCue) { double startPosition = pOutroCue->getPosition(); double endPosition = pOutroCue->getEndPosition(); - Cue::Source source = pOutroCue->getSource(); - m_pOutroStartPosition->set(quantizeCuePoint(startPosition, source, QuantizeMode::PreviousBeat)); + m_pOutroStartPosition->set(quantizeCuePoint(startPosition, QuantizeMode::PreviousBeat)); m_pOutroStartEnabled->forceSet(startPosition == -1.0 ? 0.0 : 1.0); - m_pOutroEndPosition->set(quantizeCuePoint(endPosition, source, QuantizeMode::NextBeat)); + m_pOutroEndPosition->set(quantizeCuePoint(endPosition, QuantizeMode::NextBeat)); m_pOutroEndEnabled->forceSet(endPosition == -1.0 ? 0.0 : 1.0); } else { m_pOutroStartPosition->set(-1.0); @@ -560,7 +556,6 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { pCue->setHotCue(hotcue); pCue->setLabel(""); pCue->setType(Cue::Type::Hotcue); - pCue->setSource(Cue::Source::Manual); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); @@ -810,7 +805,7 @@ void CueControl::cueSet(double v) { // Store cue point in loaded track if (pLoadedTrack) { - pLoadedTrack->setCuePoint(CuePosition(cue, Cue::Source::Manual)); + pLoadedTrack->setCuePoint(CuePosition(cue)); } } @@ -1127,7 +1122,6 @@ void CueControl::introStartSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - pCue->setSource(Cue::Source::Manual); pCue->setPosition(position); pCue->setLength(introEnd != -1.0 ? introEnd - position : 0.0); } @@ -1206,7 +1200,6 @@ void CueControl::introEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - pCue->setSource(Cue::Source::Manual); if (introStart != -1.0) { pCue->setPosition(introStart); pCue->setLength(position - introStart); @@ -1290,7 +1283,6 @@ void CueControl::outroStartSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - pCue->setSource(Cue::Source::Manual); pCue->setPosition(position); pCue->setLength(outroEnd != -1.0 ? outroEnd - position : 0.0); } @@ -1369,7 +1361,6 @@ void CueControl::outroEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - pCue->setSource(Cue::Source::Manual); if (outroStart != -1.0) { pCue->setPosition(outroStart); pCue->setLength(position - outroStart); @@ -1605,9 +1596,9 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { } } -double CueControl::quantizeCuePoint(double position, Cue::Source source, QuantizeMode mode) { +double CueControl::quantizeCuePoint(double position, QuantizeMode mode) { // Don't quantize unset cues, manual cues or when quantization is disabled. - if (position == -1.0 || source == Cue::Source::Manual || !m_pQuantizeEnabled->toBool()) { + if (position == -1.0 || !m_pQuantizeEnabled->toBool()) { return position; } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 402b84c7556..86b2c95e345 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -183,7 +183,7 @@ class CueControl : public EngineControl { void detachCue(int hotcueNumber); void loadCuesFromTrack(); void reloadCuesFromTrack(); - double quantizeCuePoint(double position, Cue::Source source, QuantizeMode mode); + double quantizeCuePoint(double position, QuantizeMode mode); double quantizeCurrentPosition(QuantizeMode mode); TrackAt getTrackAt() const; diff --git a/src/library/dao/cuedao.cpp b/src/library/dao/cuedao.cpp index 89d4176449d..3cd97414ca2 100644 --- a/src/library/dao/cuedao.cpp +++ b/src/library/dao/cuedao.cpp @@ -48,7 +48,6 @@ CuePointer CueDAO::cueFromRow(const QSqlQuery& query) const { QSqlRecord record = query.record(); int id = record.value(record.indexOf("id")).toInt(); TrackId trackId(record.value(record.indexOf("track_id"))); - int source = record.value(record.indexOf("source")).toInt(); int type = record.value(record.indexOf("type")).toInt(); int position = record.value(record.indexOf("position")).toInt(); int length = record.value(record.indexOf("length")).toInt(); @@ -56,7 +55,7 @@ CuePointer CueDAO::cueFromRow(const QSqlQuery& query) const { QString label = record.value(record.indexOf("label")).toString(); int iColorId = record.value(record.indexOf("color")).toInt(); PredefinedColorPointer color = Color::kPredefinedColorsSet.predefinedColorFromId(iColorId); - CuePointer pCue(new Cue(id, trackId, (Cue::Source)source, (Cue::Type)type, position, length, hotcue, label, color)); + CuePointer pCue(new Cue(id, trackId, (Cue::Type)type, position, length, hotcue, label, color)); m_cues[id] = pCue; return pCue; } @@ -141,9 +140,8 @@ bool CueDAO::saveCue(Cue* cue) { if (cue->getId() == -1) { // New cue QSqlQuery query(m_database); - query.prepare("INSERT INTO " CUE_TABLE " (track_id, source, type, position, length, hotcue, label, color) VALUES (:track_id, :source, :type, :position, :length, :hotcue, :label, :color)"); + query.prepare("INSERT INTO " CUE_TABLE " (track_id, type, position, length, hotcue, label, color) VALUES (:track_id, :type, :position, :length, :hotcue, :label, :color)"); query.bindValue(":track_id", cue->getTrackId().toVariant()); - query.bindValue(":source", static_cast(cue->getSource())); query.bindValue(":type", static_cast(cue->getType())); query.bindValue(":position", cue->getPosition()); query.bindValue(":length", cue->getLength()); @@ -163,7 +161,6 @@ bool CueDAO::saveCue(Cue* cue) { QSqlQuery query(m_database); query.prepare("UPDATE " CUE_TABLE " SET " "track_id = :track_id," - "source = :source," "type = :type," "position = :position," "length = :length," @@ -173,7 +170,6 @@ bool CueDAO::saveCue(Cue* cue) { " WHERE id = :id"); query.bindValue(":id", cue->getId()); query.bindValue(":track_id", cue->getTrackId().toVariant()); - query.bindValue(":source", static_cast(cue->getSource())); query.bindValue(":type", static_cast(cue->getType())); query.bindValue(":position", cue->getPosition()); query.bindValue(":length", cue->getLength()); diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp index afcaa07be58..b4eeefb2d53 100644 --- a/src/library/dao/trackdao.cpp +++ b/src/library/dao/trackdao.cpp @@ -1039,7 +1039,7 @@ bool setTrackSampleRate(const QSqlRecord& record, const int column, bool setTrackCuePoint(const QSqlRecord& record, const int column, TrackPointer pTrack) { - pTrack->setCuePoint(CuePosition(record.value(column).toDouble(), Cue::Source::Manual)); + pTrack->setCuePoint(CuePosition(record.value(column).toDouble())); return false; } diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 36a851afeb5..bb946899f89 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -226,7 +226,6 @@ TrackPointer BaseTrackPlayerImpl::unloadTrack() { } if (!pLoopCue) { pLoopCue = m_pLoadedTrack->createAndAddCue(); - pLoopCue->setSource(Cue::Source::Manual); pLoopCue->setType(Cue::Type::Loop); } pLoopCue->setPosition(loopStart); diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 0140dc27913..265c57fad80 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -53,17 +53,14 @@ TEST_F(AnalyzerSilenceTest, SilenceTrack) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); - EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { @@ -77,17 +74,14 @@ TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(0.0, cue.getPosition()); - EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { @@ -111,17 +105,14 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, cue.getPosition()); - EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(nTrackSampleDataLength / 4, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(3 * nTrackSampleDataLength / 4, pOutroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { @@ -157,102 +148,14 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, cue.getPosition()); - EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_DOUBLE_EQ(oneFifthOfTrackLength, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(4 * oneFifthOfTrackLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); -} - -TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedCues) { - int halfTrackLength = nTrackSampleDataLength / 2; - - pTrack->setCuePoint(CuePosition(100, Cue::Source::Automatic)); // Arbitrary value - - CuePointer pIntroCue = pTrack->createAndAddCue(); - pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::Source::Automatic); - pIntroCue->setPosition(1000); // Arbitrary value - pIntroCue->setLength(0.0); - - CuePointer pOutroCue = pTrack->createAndAddCue(); - pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::Source::Automatic); - pOutroCue->setPosition(-1.0); - pOutroCue->setLength(9000); // Arbitrary value - - // Fill the first half with silence - for (int i = 0; i < halfTrackLength; i++) { - pTrackSampleData[i] = 0.0; - } - - // Fill the second half with 1 kHz tone - double omega = 2.0 * M_PI * kTonePitchHz / pTrack->getSampleRate(); - for (int i = halfTrackLength; i < nTrackSampleDataLength; i++) { - pTrackSampleData[i] = sin(i / kChannelCount * omega); - } - - analyzeTrack(); - - CuePosition cue = pTrack->getCuePoint(); - EXPECT_DOUBLE_EQ(halfTrackLength, cue.getPosition()); - EXPECT_EQ(Cue::Source::Automatic, cue.getSource()); - - EXPECT_DOUBLE_EQ(halfTrackLength, pIntroCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); - - EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); - EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); -} - -TEST_F(AnalyzerSilenceTest, UpdateNonUserAdjustedRangeCues) { - int thirdTrackLength = nTrackSampleDataLength / 3; - - CuePointer pIntroCue = pTrack->createAndAddCue(); - pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::Source::Automatic); - pIntroCue->setPosition(1500.0); // Arbitrary value - pIntroCue->setLength(1000.0); // Arbitrary value - - CuePointer pOutroCue = pTrack->createAndAddCue(); - pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::Source::Automatic); - pOutroCue->setPosition(9000.0); // Arbitrary value - pOutroCue->setLength(1000.0); // Arbitrary value - - // Fill the first third with silence - for (int i = 0; i < thirdTrackLength; i++) { - pTrackSampleData[i] = 0.0; - } - - // Fill the second third with 1 kHz tone - double omega = 2.0 * M_PI * kTonePitchHz / pTrack->getSampleRate(); - for (int i = thirdTrackLength; i < 2 * thirdTrackLength; i++) { - pTrackSampleData[i] = sin(i / kChannelCount * omega); - } - - // Fill the last third with silence - for (int i = 2 * thirdTrackLength; i < nTrackSampleDataLength; i++) { - pTrackSampleData[i] = 0.0; - } - - analyzeTrack(); - - EXPECT_DOUBLE_EQ(thirdTrackLength, pIntroCue->getPosition()); - EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pIntroCue->getSource()); - - EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); - EXPECT_DOUBLE_EQ(2 * thirdTrackLength, pOutroCue->getLength()); - EXPECT_EQ(Cue::Source::Automatic, pOutroCue->getSource()); } TEST_F(AnalyzerSilenceTest, RespectUserEdits) { @@ -261,17 +164,15 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { const double kManualIntroPosition = 0.1 * nTrackSampleDataLength; const double kManualOutroPosition = 0.9 * nTrackSampleDataLength; - pTrack->setCuePoint(CuePosition(kManualCuePosition, Cue::Source::Manual)); + pTrack->setCuePoint(CuePosition(kManualCuePosition)); CuePointer pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setSource(Cue::Source::Manual); pIntroCue->setPosition(kManualIntroPosition); pIntroCue->setLength(0.0); CuePointer pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setSource(Cue::Source::Manual); pOutroCue->setPosition(-1.0); pOutroCue->setLength(kManualOutroPosition); @@ -290,15 +191,12 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { CuePosition cue = pTrack->getCuePoint(); EXPECT_DOUBLE_EQ(kManualCuePosition, cue.getPosition()); - EXPECT_EQ(Cue::Source::Manual, cue.getSource()); EXPECT_DOUBLE_EQ(kManualIntroPosition, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pIntroCue->getSource()); EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(kManualOutroPosition, pOutroCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pOutroCue->getSource()); } } // namespace diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 0a7a7c9d77d..f89459f9858 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -75,15 +75,13 @@ class CueControlTest : public BaseSignalPathTest { TEST_F(CueControlTest, LoadUnloadTrack) { TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); + pTrack->setCuePoint(CuePosition(100.0)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Manual); pIntro->setPosition(150.0); pIntro->setLength(50.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::Source::Manual); pOutro->setPosition(250.0); pOutro->setLength(50.0); @@ -114,15 +112,13 @@ TEST_F(CueControlTest, LoadUnloadTrack) { TEST_F(CueControlTest, LoadTrackWithDetectedCues) { TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Automatic)); + pTrack->setCuePoint(CuePosition(100.0)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(100.0); pIntro->setLength(0.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(-1.0); pOutro->setLength(200.0); @@ -143,12 +139,10 @@ TEST_F(CueControlTest, LoadTrackWithIntroEndAndOutroStart) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Manual); pIntro->setPosition(-1.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::Source::Manual); pOutro->setPosition(250.0); pOutro->setLength(0.0); @@ -177,17 +171,15 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabled) { const double bpm = pTrack->getBpm(); const double beatLength = (60.0 * sampleRate / bpm) * frameSize; - pTrack->setCuePoint(CuePosition(1.9 * beatLength, Cue::Source::Automatic)); + pTrack->setCuePoint(CuePosition(1.9 * beatLength)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(2.1 * beatLength); pIntro->setLength(1.2 * beatLength); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(11.1 * beatLength); pOutro->setLength(4.4 * beatLength); @@ -207,17 +199,15 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabledNoBeats) { pTrack->setSampleRate(44100); pTrack->setBpm(0.0); - pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Automatic)); + pTrack->setCuePoint(CuePosition(100.0)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(250.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(550.0); pOutro->setLength(250.0); @@ -237,17 +227,15 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { pTrack->setSampleRate(44100); pTrack->setBpm(120.0); - pTrack->setCuePoint(CuePosition(240.0, Cue::Source::Automatic)); + pTrack->setCuePoint(CuePosition(240.0)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(210.0); pIntro->setLength(120.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setSource(Cue::Source::Automatic); pOutro->setPosition(770.0); pOutro->setLength(220.0); @@ -265,7 +253,6 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setSource(Cue::Source::Automatic); pIntro->setPosition(250.0); pIntro->setLength(150.0); @@ -279,7 +266,7 @@ TEST_F(CueControlTest, SeekOnLoadMainCue) { config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(static_cast(SeekOnLoadMode::MainCue))); TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(100.0, Cue::Source::Manual)); + pTrack->setCuePoint(CuePosition(100.0)); loadTrack(pTrack); @@ -287,7 +274,7 @@ TEST_F(CueControlTest, SeekOnLoadMainCue) { EXPECT_DOUBLE_EQ(100.0, getCurrentSample()); // Move cue and check if track is following it. - pTrack->setCuePoint(CuePosition(200.0, Cue::Source::Manual)); + pTrack->setCuePoint(CuePosition(200.0)); ProcessBuffer(); EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); @@ -298,7 +285,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(static_cast(SeekOnLoadMode::MainCue))); TrackPointer pTrack = createTestTrack(); - pTrack->setCuePoint(CuePosition(-100.0, Cue::Source::Manual)); + pTrack->setCuePoint(CuePosition(-100.0)); loadTrack(pTrack); @@ -306,7 +293,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault_CueInPreroll) { EXPECT_DOUBLE_EQ(-100.0, getCurrentSample()); // Move cue and check if track is following it. - pTrack->setCuePoint(CuePosition(-200.0, Cue::Source::Manual)); + pTrack->setCuePoint(CuePosition(-200.0)); ProcessBuffer(); EXPECT_DOUBLE_EQ(-200.0, m_pCuePoint->get()); @@ -330,7 +317,6 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Set intro end cue @@ -347,7 +333,6 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(100.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(400.0, pCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear intro start cue @@ -363,7 +348,6 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(500.0, pCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear intro end cue @@ -394,7 +378,6 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Set outro end cue @@ -411,7 +394,6 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(750.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(250.0, pCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear outro start cue @@ -427,7 +409,6 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { if (pCue != nullptr) { EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); EXPECT_DOUBLE_EQ(1000.0, pCue->getLength()); - EXPECT_EQ(Cue::Source::Manual, pCue->getSource()); } // Clear outro end cue diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 14ddf3a4011..dec0d8f1c4c 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -23,7 +23,6 @@ Cue::Cue(TrackId trackId) : m_bDirty(false), m_iId(-1), m_trackId(trackId), - m_source(Cue::Source::Unknown), m_type(Cue::Type::Invalid), m_samplePosition(-1.0), m_length(0.0), @@ -33,12 +32,11 @@ Cue::Cue(TrackId trackId) DEBUG_ASSERT(!m_label.isNull()); } -Cue::Cue(int id, TrackId trackId, Cue::Source source, Cue::Type type, double position, double length, +Cue::Cue(int id, TrackId trackId, Cue::Type type, double position, double length, int hotCue, QString label, PredefinedColorPointer color) : m_bDirty(false), m_iId(id), m_trackId(trackId), - m_source(source), m_type(type), m_samplePosition(position), m_length(length), @@ -74,19 +72,6 @@ void Cue::setTrackId(TrackId trackId) { emit(updated()); } -Cue::Source Cue::getSource() const { - QMutexLocker lock(&m_mutex); - return m_source; -} - -void Cue::setSource(Cue::Source source) { - QMutexLocker lock(&m_mutex); - m_source = source; - m_bDirty = true; - lock.unlock(); - emit(updated()); -} - Cue::Type Cue::getType() const { QMutexLocker lock(&m_mutex); return m_type; @@ -190,6 +175,5 @@ double Cue::getEndPosition() const { } bool operator==(const CuePosition& lhs, const CuePosition& rhs) { - return lhs.getPosition() == rhs.getPosition() && - lhs.getSource() == rhs.getSource(); + return lhs.getPosition() == rhs.getPosition(); } diff --git a/src/track/cue.h b/src/track/cue.h index fd38d13a570..3dfefa12632 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -17,12 +17,6 @@ class Cue : public QObject { Q_OBJECT public: - enum class Source { - Unknown = 0, - Automatic = 1, - Manual = 2, - }; - enum class Type { Invalid = 0, Hotcue = 1, @@ -42,9 +36,6 @@ class Cue : public QObject { int getId() const; TrackId getTrackId() const; - Cue::Source getSource() const; - void setSource(Cue::Source source); - Cue::Type getType() const; void setType(Cue::Type type); @@ -70,7 +61,7 @@ class Cue : public QObject { private: explicit Cue(TrackId trackId); - Cue(int id, TrackId trackId, Cue::Source source, Cue::Type type, double position, double length, + Cue(int id, TrackId trackId, Cue::Type type, double position, double length, int hotCue, QString label, PredefinedColorPointer color); void setDirty(bool dirty); void setId(int id); @@ -81,7 +72,6 @@ class Cue : public QObject { bool m_bDirty; int m_iId; TrackId m_trackId; - Cue::Source m_source; Cue::Type m_type; double m_samplePosition; double m_length; @@ -107,9 +97,9 @@ class CuePointer: public std::shared_ptr { class CuePosition { public: CuePosition() - : m_position(0.0), m_source(Cue::Source::Unknown) {} - CuePosition(double position, Cue::Source source) - : m_position(position), m_source(source) {} + : m_position(0.0) {} + CuePosition(double position) + : m_position(position) {} double getPosition() const { return m_position; @@ -119,27 +109,16 @@ class CuePosition { m_position = position; } - Cue::Source getSource() const { - return m_source; - } - - void setSource(Cue::Source source) { - m_source = source; - } - - void set(double position, Cue::Source source) { + void set(double position) { m_position = position; - m_source = source; } void reset() { m_position = 0.0; - m_source = Cue::Source::Unknown; } private: double m_position; - Cue::Source m_source; }; bool operator==(const CuePosition& lhs, const CuePosition& rhs); @@ -151,7 +130,7 @@ bool operator!=(const CuePosition& lhs, const CuePosition& rhs) { inline QDebug operator<<(QDebug dbg, const CuePosition& arg) { - return dbg << "position =" << arg.getPosition() << "/" << "source =" << static_cast(arg.getSource()); + return dbg << "position =" << arg.getPosition(); } #endif // MIXXX_CUE_H diff --git a/src/track/track.cpp b/src/track/track.cpp index a191e6ba224..d9ee885858c 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -653,7 +653,6 @@ void Track::setCuePoint(CuePosition cue) { // Store the cue point in a load cue CuePointer pLoadCue = findCueByType(Cue::Type::MainCue); - Cue::Source source = cue.getSource(); double position = cue.getPosition(); if (position != 0.0 && position != -1.0) { if (!pLoadCue) { @@ -666,7 +665,6 @@ void Track::setCuePoint(CuePosition cue) { m_cuePoints.push_back(pLoadCue); } pLoadCue->setPosition(position); - pLoadCue->setSource(source); } else if (pLoadCue) { disconnect(pLoadCue.get(), 0, this, 0); m_cuePoints.removeOne(pLoadCue); @@ -764,7 +762,7 @@ void Track::setCuePoints(const QList& cuePoints) { connect(pCue.get(), &Cue::updated, this, &Track::slotCueUpdated); // update main cue point if (pCue->getType() == Cue::Type::MainCue) { - m_record.setCuePoint(CuePosition(pCue->getPosition(), pCue->getSource())); + m_record.setCuePoint(CuePosition(pCue->getPosition())); } } markDirtyAndUnlock(&lock); From aa058711191642084bf2a5df16eb2deb21404f5b Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 12 Aug 2019 15:38:40 -0500 Subject: [PATCH 099/198] clarify code with a named constant --- src/analyzer/analyzersilence.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 423ddef5881..9ff9ac40ff5 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -9,13 +9,15 @@ constexpr float kSilenceThreshold = 0.001; // TODO: Change the above line to: //constexpr float kSilenceThreshold = db2ratio(-60.0f); +const double kCueNotSet = -1.0; + bool shouldUpdateMainCue(CuePosition mainCue) { - return mainCue.getPosition() == -1.0 || + return mainCue.getPosition() == kCueNotSet || mainCue.getPosition() == 0.0; } bool hasIntroCueStart(const Cue& introCue) { - return introCue.getPosition() != -1.0; + return introCue.getPosition() != kCueNotSet; } bool hasOutroCueEnd(const Cue& outroCue) { @@ -121,7 +123,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { if (!pOutroCue) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setPosition(-1.0); + pOutroCue->setPosition(kCueNotSet); pOutroCue->setLength(outroEnd); } From 654e984cbc01d35f00064a0f20905cdc8f296392 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 13 Aug 2019 01:16:52 -0500 Subject: [PATCH 100/198] AutoDJ: rename "Intro + Outro" transition mode to "Full Intro + Outro" --- src/library/autodj/autodjprocessor.cpp | 6 +++--- src/library/autodj/autodjprocessor.h | 2 +- src/library/autodj/dlgautodj.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 7b19e8778b7..eb80d4897e6 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -162,7 +162,7 @@ AutoDJProcessor::AutoDJProcessor(QObject* pParent, int configuredTransitionMode = m_pConfig->getValue( ConfigKey(kConfigKey, kTransitionModePreferenceName), - static_cast(TransitionMode::IntroOutro)); + static_cast(TransitionMode::FullIntroOutro)); m_transitionMode = static_cast(configuredTransitionMode); } @@ -250,7 +250,7 @@ void AutoDJProcessor::fadeNow() { double spinboxTime = fabs(m_transitionTime); double fadeTime; - if (m_transitionMode == TransitionMode::IntroOutro + if (m_transitionMode == TransitionMode::FullIntroOutro || m_transitionMode == TransitionMode::AlignIntroOutroStart) { // Use the intro length as the transition time. If the user has seeked // away from the intro start since the track was loaded, start from @@ -1023,7 +1023,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double introLength = introEnd - introStart; switch (m_transitionMode) { - case TransitionMode::IntroOutro: + case TransitionMode::FullIntroOutro: // Use the outro or intro length for the transition time, whichever is // shorter. Let the full outro and intro play; do not cut off any part // of either. diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 7666c5c9b21..b3a5ed5136c 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -155,7 +155,7 @@ class AutoDJProcessor : public QObject { }; enum class TransitionMode { - IntroOutro, + FullIntroOutro, AlignIntroOutroStart, FixedFullTrack, FixedSkipSilence diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 1b2763a41a3..6add7900275 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -81,8 +81,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), this, SLOT(toggleAutoDJButton(bool))); - fadeModeCombobox->addItem(tr("Intro + Outro"), - static_cast(AutoDJProcessor::TransitionMode::IntroOutro)); + fadeModeCombobox->addItem(tr("Full Intro + Outro"), + static_cast(AutoDJProcessor::TransitionMode::FullIntroOutro)); fadeModeCombobox->addItem(tr("Align Intro + Outro Start"), static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); fadeModeCombobox->addItem(tr("Fixed Time (full track)"), @@ -94,7 +94,7 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( - "Intro + Outro:\n" + "Full Intro + Outro:\n" "Use the intro or outro length as the crossfade time, whichever\n" "is shorter. Always play the full intro and outro.\n" "\n" From 1ed918c6ce2249affde2f3698939c4e3aae64d3e Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 13 Aug 2019 01:30:36 -0500 Subject: [PATCH 101/198] AutoDJ: edit transition mode tooltip --- src/library/autodj/dlgautodj.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 6add7900275..ab854b34067 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -95,13 +95,13 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( "Full Intro + Outro:\n" - "Use the intro or outro length as the crossfade time, whichever\n" - "is shorter. Always play the full intro and outro.\n" + "Play the full intro and outro. Use the intro or outro length\n" + "as the crossfade time, whichever is shorter.\n" "\n" "Align Intro + Outro Start:\n" - "Use the intro or outro length as the crossfade time, whichever\n" - "is shorter. Cut off the end of the outro when the outro is\n" - "longer than the intro.\n" + "Start crossfading at the outro start. If the outro is longer\n" + "than the intro, cut off the end of the outro. Use the intro or\n" + "outro length as the crossfade time, whichever is shorter.\n" "\n" "Fixed Time modes:\n" "Use the selected number of seconds as the crossfade time." From 9d66c636e6fe9ebe6a5f6bbe811ce359bd84b322 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 20 Aug 2019 09:18:32 -0500 Subject: [PATCH 102/198] move workaround for AutoDJ cloning decks to PlayerManager --- src/library/autodj/autodjprocessor.cpp | 9 --------- src/mixer/playermanager.cpp | 19 +++++++++++++++++-- src/mixer/playermanager.h | 1 + 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index eb80d4897e6..b7b02b62113 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -705,15 +705,6 @@ TrackPointer AutoDJProcessor::getNextTrackFromQueue() { bool AutoDJProcessor::loadNextTrackFromQueue(const DeckAttributes& deck, bool play) { TrackPointer nextTrack = getNextTrackFromQueue(); - // Don't try to mix a track into itself. This can get AutoDJ into a weird - // state when combined with the deck cloning feature. This situation can - // happen if the user repeatedly presses the "Skip track" button with the - // repeat playlist feature enabled. - if (nextTrack == getOtherDeck(&deck)->getLoadedTrack()) { - removeTrackFromTopOfQueue(nextTrack); - nextTrack = getNextTrackFromQueue(); - } - // We ran out of tracks in the queue. if (!nextTrack) { // Disable AutoDJ. diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index e73bf8e6f5d..b03728d0f16 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -65,7 +65,8 @@ PlayerManager::PlayerManager(UserSettingsPointer pConfig, ConfigKey("[Master]", "num_microphones"), true, true)), m_pCONumAuxiliaries(new ControlObject( ConfigKey("[Master]", "num_auxiliaries"), true, true)), - m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()) { + m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), + m_pAutoDjEnabled(std::make_unique("[AutoDJ]", "enabled", this)) { m_pCONumDecks->connectValueChangeRequest(this, &PlayerManager::slotChangeNumDecks, Qt::DirectConnection); m_pCONumSamplers->connectValueChangeRequest(this, @@ -584,7 +585,21 @@ void PlayerManager::slotLoadTrackToPlayer(TrackPointer pTrack, QString group, bo // If not present in the config, use & set the default value bool cloneOnDoubleTap = m_pConfig->getValue( ConfigKey("[Controls]", "CloneDeckOnLoadDoubleTap"), kDefaultCloneDeckOnLoad); - if (cloneOnDoubleTap && m_lastLoadedPlayer == group && elapsed < mixxx::Duration::fromSeconds(0.5)) { + + // If AutoDJ is enabled, prevent it from cloning decks if the same track + // is in the AutoDJ queue twice in a row. This can happen when the option to + // repeat the AutoDJ queue is enabled and the user presses the "Skip now" + // button repeatedly. + // AutoDJProcessor is initialized after PlayerManager, so check that the + // ControlProxy is pointing to the real ControlObject. + if (!m_pAutoDjEnabled->valid()) { + m_pAutoDjEnabled->initialize(ConfigKey("[AutoDJ]", "enabled")); + } + bool autoDjSkipClone = m_pAutoDjEnabled->get() && (pPlayer == m_decks.at(0) || pPlayer == m_decks.at(1)); + + if (cloneOnDoubleTap && m_lastLoadedPlayer == group + && elapsed < mixxx::Duration::fromSeconds(0.5) + && !autoDjSkipClone) { // load was pressed twice quickly while [Controls],CloneDeckOnLoadDoubleTap is TRUE, // so clone another playing deck instead of loading the selected track pPlayer->slotCloneDeck(); diff --git a/src/mixer/playermanager.h b/src/mixer/playermanager.h index 629428e1dc9..38890e84a1d 100644 --- a/src/mixer/playermanager.h +++ b/src/mixer/playermanager.h @@ -265,6 +265,7 @@ class PlayerManager : public QObject, public PlayerManagerInterface { ControlObject* m_pCONumPreviewDecks; ControlObject* m_pCONumMicrophones; ControlObject* m_pCONumAuxiliaries; + std::unique_ptr m_pAutoDjEnabled; TrackAnalysisScheduler::Pointer m_pTrackAnalysisScheduler; From ddd872ba498fa22fdc809fcd3c74b00803f57165 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 27 Aug 2019 11:29:05 -0500 Subject: [PATCH 103/198] add option to move intro start with main cue This also moves the intro start to main cue on track load if the main cue had been set previously. --- src/engine/controls/cuecontrol.cpp | 12 ++- src/preferences/dialog/dlgprefdeck.cpp | 15 +++ src/preferences/dialog/dlgprefdeck.h | 2 + src/preferences/dialog/dlgprefdeckdlg.ui | 126 +++++++++++++---------- 4 files changed, 101 insertions(+), 54 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c37e17d898d..f8a45135f0a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -352,8 +352,14 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { firstSound = pAudibleSound->getPosition(); } - double introStart = m_pIntroStartPosition->get(); double mainCue = m_pCuePoint->get(); + if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStart"), false)) { + if (mainCue != kNoTrigger && mainCue != 0) { + m_pIntroStartPosition->set(mainCue); + } + } + + double introStart = m_pIntroStartPosition->get(); switch (seekOnLoadMode) { case SeekOnLoadMode::Beginning: @@ -807,6 +813,10 @@ void CueControl::cueSet(double v) { if (pLoadedTrack) { pLoadedTrack->setCuePoint(CuePosition(cue)); } + + if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStart"), false)) { + introStartSet(cue); + } } void CueControl::cueClear(double v) { diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index 97f603d1620..af7db61d170 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -76,6 +76,12 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, } connect(ComboBoxCueMode, SIGNAL(activated(int)), this, SLOT(slotCueModeCombobox(int))); + m_bMoveIntroStartWithMainCue = m_pConfig->getValue(ConfigKey("[Controls]", + "MoveIntroStart"), false); + checkBoxIntroStartMove->setChecked(m_bMoveIntroStartWithMainCue); + connect(checkBoxIntroStartMove, &QCheckBox::toggled, + this, &DlgPrefDeck::slotMoveIntroStartCheckbox); + // Track time display configuration m_pControlTrackTimeDisplay = new ControlObject( ConfigKey("[Controls]", "ShowDurationRemaining")); @@ -346,6 +352,9 @@ DlgPrefDeck::~DlgPrefDeck() { } void DlgPrefDeck::slotUpdate() { + checkBoxIntroStartMove->setChecked(m_pConfig->getValue( + ConfigKey("[Controls]", "MoveIntroStart"), false)); + slotSetTrackTimeDisplay(m_pControlTrackTimeDisplay->get()); checkBoxDisallowLoadToPlayingDeck->setChecked(!m_pConfig->getValue( @@ -454,6 +463,10 @@ void DlgPrefDeck::slotResetToDefaults() { radioButtonResetUnlockedKey->setChecked(true); } +void DlgPrefDeck::slotMoveIntroStartCheckbox(bool checked) { + m_bMoveIntroStartWithMainCue = checked; +} + void DlgPrefDeck::slotRateRangeComboBox(int index) { m_iRateRangePercent = ComboBoxRateRange->itemData(index).toInt(); } @@ -582,6 +595,8 @@ void DlgPrefDeck::slotSetTrackLoadMode(int comboboxIndex) { } void DlgPrefDeck::slotApply() { + m_pConfig->set(ConfigKey("[Controls]", "MoveIntroStart"), ConfigValue(m_bMoveIntroStartWithMainCue)); + double timeDisplay = static_cast(m_timeDisplayMode); m_pConfig->set(ConfigKey("[Controls]","PositionDisplay"), ConfigValue(timeDisplay)); m_pControlTrackTimeDisplay->set(timeDisplay); diff --git a/src/preferences/dialog/dlgprefdeck.h b/src/preferences/dialog/dlgprefdeck.h index b06d5abf562..757749c75ae 100644 --- a/src/preferences/dialog/dlgprefdeck.h +++ b/src/preferences/dialog/dlgprefdeck.h @@ -65,6 +65,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { void slotApply(); void slotResetToDefaults(); + void slotMoveIntroStartCheckbox(bool checked); void slotRateRangeComboBox(int index); void slotRateInversionCheckbox(bool invert); void slotKeyLockModeSelected(QAbstractButton*); @@ -122,6 +123,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { int m_iCueMode; + bool m_bMoveIntroStartWithMainCue; bool m_bDisallowTrackLoadToPlayingDeck; bool m_bCloneDeckOnLoadDoubleTap; bool m_bAssignHotcueColors; diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index f27544ab26e..3e560cf4076 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -23,7 +23,65 @@ 10 + + + + Cue mode + + + true + + + ComboBoxCueMode + + + + + + + Mixxx mode: +- Cue button while pause at cue point = preview +- Cue button while pause not at cue point = set cue point +- Cue button while playing = pause at cue point +Mixxx mode (no blinking): +- Same as Mixxx mode but with no blinking indicators +Pioneer mode: +- Same as Mixxx mode with a flashing play button +Denon mode: +- Cue button at cue point = preview +- Cue button not at cue point = pause at cue point +- Play = set cue point +Numark mode: +- Same as Denon mode, but without a flashing play button +CUP mode: +- Cue button while pause at cue point = play after release +- Cue button while pause not at cue point = set cue point and play after release +- Cue button while playing = go to cue point and play after release + + + + + + + Intro start + + + ComboBoxCueMode + + + + + + + Automatically moves the intro start cue when the main cue moves. + + + Move intro start with main cue + + + + true @@ -42,10 +100,7 @@ - - - - + @@ -79,55 +134,27 @@ - - - - Mixxx mode: -- Cue button while pause at cue point = preview -- Cue button while pause not at cue point = set cue point -- Cue button while playing = pause at cue point -Mixxx mode (no blinking): -- Same as Mixxx mode but with no blinking indicators -Pioneer mode: -- Same as Mixxx mode with a flashing play button -Denon mode: -- Cue button at cue point = preview -- Cue button not at cue point = pause at cue point -- Play = set cue point -Numark mode: -- Same as Denon mode, but without a flashing play button -CUP mode: -- Cue button while pause at cue point = play after release -- Cue button while pause not at cue point = set cue point and play after release -- Cue button while playing = go to cue point and play after release - - - - - - + + - Cue mode - - - true - - - ComboBoxCueMode + Time Format - + + + + Track load point - + - + Auto hot cue colors @@ -137,7 +164,7 @@ CUP mode: - + Automatically assigns a predefined color to a newly created hot cue point, based on its index. @@ -147,7 +174,7 @@ CUP mode: - + Playing track protection @@ -157,14 +184,14 @@ CUP mode: - + Do not load tracks into playing decks - + Clone deck @@ -174,7 +201,7 @@ CUP mode: - + Create a playing clone of the first playing deck by double-tapping a Load button on a controller or keyboard. @@ -185,13 +212,6 @@ You can always drag-and-drop tracks on screen to clone a deck. - - - - Time Format - - - From 1f93568a06c999d8dbe0bb1238a95acb89f30756 Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 30 Aug 2019 22:51:04 -0500 Subject: [PATCH 104/198] create enum class for CueMode --- src/engine/controls/cuecontrol.cpp | 16 ++++++++-------- src/engine/controls/cuecontrol.h | 9 +++++++++ src/preferences/dialog/dlgprefdeck.cpp | 24 +++++++++++------------- src/preferences/dialog/dlgprefdeck.h | 2 +- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index f8a45135f0a..9288b888e29 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1420,8 +1420,8 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) //qDebug() << "updateIndicatorsAndModifyPlay" << newPlay << playPossible // << m_iCurrentlyPreviewingHotcues << m_bPreviewing; QMutexLocker lock(&m_mutex); - double cueMode = m_pCueMode->get(); - if ((cueMode == CUE_MODE_DENON || cueMode == CUE_MODE_NUMARK) && + CueMode cueMode = static_cast(static_cast(m_pCueMode->get())); + if ((cueMode == CueMode::Denon || cueMode == CueMode::Numark) && newPlay && playPossible && !m_pPlay->toBool() && !m_bypassCueSetByPlay) { @@ -1459,15 +1459,15 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) } else { // Pause: m_pStopButton->set(1.0); - if (cueMode == CUE_MODE_DENON) { + if (cueMode == CueMode::Denon) { if (trackAt == TrackAt::Cue || previewing) { m_pPlayIndicator->setBlinkValue(ControlIndicator::OFF); } else { // Flashing indicates that a following play would move cue point m_pPlayIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_500MS); } - } else if (cueMode == CUE_MODE_MIXXX || cueMode == CUE_MODE_MIXXX_NO_BLINK || - cueMode == CUE_MODE_NUMARK) { + } else if (cueMode == CueMode::Mixxx || cueMode == CueMode::MixxxNoBlinking || + cueMode == CueMode::Numark) { m_pPlayIndicator->setBlinkValue(ControlIndicator::OFF); } else { // Flashing indicates that play is possible in Pioneer mode @@ -1475,13 +1475,13 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) } } - if (cueMode != CUE_MODE_DENON && cueMode != CUE_MODE_NUMARK) { + if (cueMode != CueMode::Denon && cueMode != CueMode::Numark) { if (m_pCuePoint->get() != -1) { if (newPlay == 0.0 && trackAt == TrackAt::ElseWhere) { - if (cueMode == CUE_MODE_MIXXX) { + if (cueMode == CueMode::Mixxx) { // in Mixxx mode Cue Button is flashing slow if CUE will move Cue point m_pCueIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_500MS); - } else if (cueMode == CUE_MODE_MIXXX_NO_BLINK) { + } else if (cueMode == CueMode::MixxxNoBlinking) { m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); } else { // in Pioneer mode Cue Button is flashing fast if CUE will move Cue point diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 86b2c95e345..5b6740c0195 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -18,6 +18,15 @@ class ControlObject; class ControlPushButton; class ControlIndicator; +enum class CueMode { + Mixxx, + Pioneer, + Denon, + Numark, + MixxxNoBlinking, + CueAndPlay +}; + enum class SeekOnLoadMode { MainCue = 0, // Use main cue point Beginning = 1, // Use 0:00.000 diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index af7db61d170..e469ee95a4f 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -58,21 +58,19 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, int cueDefaultValue = m_pConfig->getValue( ConfigKey("[Controls]", "CueDefault"), 0); + // Update combo box - // The itemData values are out of order to avoid breaking configurations - // when Mixxx mode (no blinking) was introduced. - // TODO: replace magic numbers with an enum class - ComboBoxCueMode->addItem(tr("Mixxx mode"), 0); - ComboBoxCueMode->addItem(tr("Mixxx mode (no blinking)"), 4); - ComboBoxCueMode->addItem(tr("Pioneer mode"), 1); - ComboBoxCueMode->addItem(tr("Denon mode"), 2); - ComboBoxCueMode->addItem(tr("Numark mode"), 3); - ComboBoxCueMode->addItem(tr("CUP mode"), 5); + ComboBoxCueMode->addItem(tr("Mixxx mode"), static_cast(CueMode::Mixxx)); + ComboBoxCueMode->addItem(tr("Mixxx mode (no blinking)"), static_cast(CueMode::MixxxNoBlinking)); + ComboBoxCueMode->addItem(tr("Pioneer mode"), static_cast(CueMode::Pioneer)); + ComboBoxCueMode->addItem(tr("Denon mode"), static_cast(CueMode::Denon)); + ComboBoxCueMode->addItem(tr("Numark mode"), static_cast(CueMode::Numark)); + ComboBoxCueMode->addItem(tr("CUP mode"), static_cast(CueMode::CueAndPlay)); const int cueModeIndex = cueDefaultIndexByData(cueDefaultValue); ComboBoxCueMode->setCurrentIndex(cueModeIndex); slotCueModeCombobox(cueModeIndex); for (ControlProxy* pControl : m_cueControls) { - pControl->set(m_iCueMode); + pControl->set(static_cast(m_cueMode)); } connect(ComboBoxCueMode, SIGNAL(activated(int)), this, SLOT(slotCueModeCombobox(int))); @@ -521,7 +519,7 @@ void DlgPrefDeck::slotDisallowTrackLoadToPlayingDeckCheckbox(bool checked) { } void DlgPrefDeck::slotCueModeCombobox(int index) { - m_iCueMode = ComboBoxCueMode->itemData(index).toInt(); + m_cueMode = static_cast(ComboBoxCueMode->itemData(index).toInt()); } void DlgPrefDeck::slotCloneDeckOnLoadDoubleTapCheckbox(bool checked) { @@ -608,9 +606,9 @@ void DlgPrefDeck::slotApply() { // Set cue mode for every deck for (ControlProxy* pControl : m_cueControls) { - pControl->set(m_iCueMode); + pControl->set(static_cast(m_cueMode)); } - m_pConfig->setValue(ConfigKey("[Controls]", "CueDefault"), m_iCueMode); + m_pConfig->setValue(ConfigKey("[Controls]", "CueDefault"), static_cast(m_cueMode)); m_pConfig->setValue(ConfigKey("[Controls]", "AllowTrackLoadToPlayingDeck"), !m_bDisallowTrackLoadToPlayingDeck); diff --git a/src/preferences/dialog/dlgprefdeck.h b/src/preferences/dialog/dlgprefdeck.h index 757749c75ae..408315cf925 100644 --- a/src/preferences/dialog/dlgprefdeck.h +++ b/src/preferences/dialog/dlgprefdeck.h @@ -121,7 +121,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { TrackTime::DisplayMode m_timeDisplayMode; - int m_iCueMode; + CueMode m_cueMode; bool m_bMoveIntroStartWithMainCue; bool m_bDisallowTrackLoadToPlayingDeck; From 0a5c8d6bf277fdc425f7969a4140f676c9e1ada5 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 31 Aug 2019 10:38:22 -0500 Subject: [PATCH 105/198] move intro start with main cue if not using Denon or Numark modes --- src/engine/controls/cuecontrol.cpp | 4 ++-- src/preferences/dialog/dlgprefdeck.cpp | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 9288b888e29..c14c278d5e3 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -353,7 +353,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } double mainCue = m_pCuePoint->get(); - if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStart"), false)) { + if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), false)) { if (mainCue != kNoTrigger && mainCue != 0) { m_pIntroStartPosition->set(mainCue); } @@ -814,7 +814,7 @@ void CueControl::cueSet(double v) { pLoadedTrack->setCuePoint(CuePosition(cue)); } - if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStart"), false)) { + if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), false)) { introStartSet(cue); } } diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index e469ee95a4f..f617b60d932 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -74,12 +74,6 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, } connect(ComboBoxCueMode, SIGNAL(activated(int)), this, SLOT(slotCueModeCombobox(int))); - m_bMoveIntroStartWithMainCue = m_pConfig->getValue(ConfigKey("[Controls]", - "MoveIntroStart"), false); - checkBoxIntroStartMove->setChecked(m_bMoveIntroStartWithMainCue); - connect(checkBoxIntroStartMove, &QCheckBox::toggled, - this, &DlgPrefDeck::slotMoveIntroStartCheckbox); - // Track time display configuration m_pControlTrackTimeDisplay = new ControlObject( ConfigKey("[Controls]", "ShowDurationRemaining")); @@ -168,6 +162,7 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, comboBoxLoadPoint->addItem(tr("Main cue"), static_cast(SeekOnLoadMode::MainCue)); comboBoxLoadPoint->addItem(tr("First sound (skip silence)"), static_cast(SeekOnLoadMode::FirstSound)); comboBoxLoadPoint->addItem(tr("Beginning of track"), static_cast(SeekOnLoadMode::Beginning)); + bool seekModeExisted = m_pConfig->exists(ConfigKey("[Controls]", "CueRecall")); int seekMode = m_pConfig->getValue(ConfigKey("[Controls]", "CueRecall"), static_cast(SeekOnLoadMode::IntroStart)); comboBoxLoadPoint->setCurrentIndex( @@ -176,6 +171,24 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, connect(comboBoxLoadPoint, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgPrefDeck::slotSetTrackLoadMode); + // This option was introduced in Mixxx 2.3 with the intro & outro cues. + // If the user has set main cue points with the intention of starting tracks + // from those points, enable this option. With Denon and Numark CueModes, + // it is not safe to assume that the user wants to start tracks from the + // main cue point because it is very easy to move the main cue point without + // explicitly intending to in those modes (the main cue point moves whenever + // the deck is not at the main cue point and play is pressed). + bool introStartMoveDefault = (m_seekOnLoadMode == SeekOnLoadMode::MainCue || !seekModeExisted) + && !(m_cueMode == CueMode::Denon || m_cueMode == CueMode::Numark); + m_bMoveIntroStartWithMainCue = m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), + introStartMoveDefault); + // This is an ugly hack to ensure CueControl does not override the default value + // when it first accesses the ConfigKey and mixxx.cfg is empty. + m_pConfig->setValue(ConfigKey("[Controls]", "MoveIntroStart"), m_bMoveIntroStartWithMainCue); + checkBoxIntroStartMove->setChecked(m_bMoveIntroStartWithMainCue); + connect(checkBoxIntroStartMove, &QCheckBox::toggled, + this, &DlgPrefDeck::slotMoveIntroStartCheckbox); + // Double-tap Load to clone a deck via keyboard or controller ([ChannelN],LoadSelectedTrack) m_bCloneDeckOnLoadDoubleTap = m_pConfig->getValue( ConfigKey("[Controls]", "CloneDeckOnLoadDoubleTap"), true); From f62e4ee7e51e2537395e157231d6d7d8e3ca9994 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 27 Aug 2019 00:17:10 -0500 Subject: [PATCH 106/198] update AutoDJ tests for new intro/outro transition modes --- src/test/autodjprocessor_test.cpp | 464 ++++++++++++++++++++---------- 1 file changed, 314 insertions(+), 150 deletions(-) diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index c19609c1f42..3bb00b73640 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -45,6 +45,7 @@ class FakeDeck : public BaseTrackPlayer { play(ConfigKey(group, "play")), repeat(ConfigKey(group, "repeat")), introStartPos(ConfigKey(group, "intro_start_position")), + introEndPos(ConfigKey(group, "intro_end_position")), outroStartPos(ConfigKey(group, "outro_start_position")), outroEndPos(ConfigKey(group, "outro_end_position")) { play.setButtonMode(ControlPushButton::TOGGLE); @@ -98,6 +99,7 @@ class FakeDeck : public BaseTrackPlayer { ControlPushButton play; ControlPushButton repeat; ControlObject introStartPos; + ControlObject introEndPos; ControlObject outroStartPos; ControlObject outroEndPos; }; @@ -222,6 +224,313 @@ class AutoDJProcessorTest : public LibraryTest { QScopedPointer pProcessor; }; + +TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::FullIntroOutro); + + TrackId testId = addTrackToCollection(kTrackLocationTest); + ASSERT_TRUE(testId.isValid()); + + // Crossfader starts on the left. + master.crossfader.set(-1.0); + // Pretend a track is playing on deck 1. + TrackPointer pTrack(newTestTrack(nextTrackId(testId))); + // Pretend that track is 1 minute and 40 seconds long. + pTrack->setDuration(100); + // Load track and mark it playing. + deck1.slotLoadTrack(pTrack, true); + // Indicate the track loaded successfully. + deck1.fakeTrackLoadedEvent(pTrack); + + PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel(); + pAutoDJTableModel->appendTrack(testId); + + EXPECT_EQ(AutoDJProcessor::ADJ_DISABLED, pProcessor->getState()); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); + + // Enable AutoDJ, we immediately transition into IDLE and request a track + // load on deck2. + AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); + EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + + // Pretend the track load succeeds. + deck2.slotLoadTrack(pTrack, false); + + // Set intro + outro cues. Outro is 10 seconds long; intro is 30 seconds. + const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); + deck1.outroStartPos.set(60 * kSamplesPerSecond); + deck1.outroEndPos.set(70 * kSamplesPerSecond); + deck2.introStartPos.set(10 * kSamplesPerSecond); + deck2.introEndPos.set(40 * kSamplesPerSecond); + + // AutoDJProcessor calculates the transition when the newTrackLoaded signal + // is emitted. + deck2.fakeTrackLoadedEvent(pTrack); + // The incoming track should seek to the intro start + EXPECT_DOUBLE_EQ(0.1, deck2.playposition.get()); + + // No change to the mode, crossfader or play states. + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); + + // Seek the outgoing track to where outro start cue is placed. It should + // start fading. + deck1.playposition.set(0.6); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); + + EXPECT_DOUBLE_EQ(0.1, deck2.playposition.get()); + + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + + deck1.playposition.set(0.7); + deck1.play.set(0.0); + + // Expect that we will transition into IDLE mode and request a track load on deck1. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); + + // Advance track to the point where crossfading should be over (intro end) + deck2.playposition.set(0.4); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); +} + +TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::FullIntroOutro); + + TrackId testId = addTrackToCollection(kTrackLocationTest); + ASSERT_TRUE(testId.isValid()); + + // Crossfader starts on the left. + master.crossfader.set(-1.0); + // Pretend a track is playing on deck 1. + TrackPointer pTrack(newTestTrack(nextTrackId(testId))); + // Pretend that track is 1 minute and 40 seconds long. + pTrack->setDuration(100); + // Load track and mark it playing. + deck1.slotLoadTrack(pTrack, true); + // Indicate the track loaded successfully. + deck1.fakeTrackLoadedEvent(pTrack); + + PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel(); + pAutoDJTableModel->appendTrack(testId); + + EXPECT_EQ(AutoDJProcessor::ADJ_DISABLED, pProcessor->getState()); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); + + // Enable AutoDJ, we immediately transition into IDLE and request a track + // load on deck2. + AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); + EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + + // Pretend the track load succeeds. + deck2.slotLoadTrack(pTrack, false); + + // Set intro + outro cues. Outro is 20 seconds long; intro is 10 seconds. + const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); + deck1.outroStartPos.set(70 * kSamplesPerSecond); + deck1.outroEndPos.set(90 * kSamplesPerSecond); + deck2.introStartPos.set(10 * kSamplesPerSecond); + deck2.introEndPos.set(20 * kSamplesPerSecond); + + // AutoDJProcessor calculates the transition when the newTrackLoaded signal + // is emitted. + deck2.fakeTrackLoadedEvent(pTrack); + + // The incoming track should be at intro start + EXPECT_DOUBLE_EQ(0.1, deck2.playposition.get()); + + // No change to the mode, crossfader or play states. + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); + + // Seek the outgoing track to where outro start cue is placed. It should not + // be fading yet. + deck1.playposition.set(0.7); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + + // Seek the outgoing track to where the transition should start + // outro end (90 s) - intro length (10 s) + deck1.playposition.set(0.8); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); + + EXPECT_DOUBLE_EQ(0.1, deck2.playposition.get()); + + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + + deck1.playposition.set(0.9); + deck1.play.set(0.0); + + // Expect that we will transition into IDLE mode and request a track load on deck1. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); + + // Advance track to the point where crossfading should be over. + deck2.playposition.set(0.2); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); +} + +TEST_F(AutoDJProcessorTest, AlignIntroOutroStart_LongerIntro) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::AlignIntroOutroStart); + + TrackId testId = addTrackToCollection(kTrackLocationTest); + ASSERT_TRUE(testId.isValid()); + + // Crossfader starts on the left. + master.crossfader.set(-1.0); + // Pretend a track is playing on deck 1. + TrackPointer pTrack(newTestTrack(nextTrackId(testId))); + // Pretend that track is 1 minute and 40 seconds long. + pTrack->setDuration(100); + // Load track and mark it playing. + deck1.slotLoadTrack(pTrack, true); + // Indicate the track loaded successfully. + deck1.fakeTrackLoadedEvent(pTrack); + + PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel(); + pAutoDJTableModel->appendTrack(testId); + + EXPECT_EQ(AutoDJProcessor::ADJ_DISABLED, pProcessor->getState()); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); + + // Enable AutoDJ, we immediately transition into IDLE and request a track + // load on deck2. + AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); + EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + + // Pretend the track load succeeds. + deck2.slotLoadTrack(pTrack, false); + + // Set intro + outro cues. Outro is 10 seconds long; intro is 20 seconds. + const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); + deck1.outroStartPos.set(80 * kSamplesPerSecond); + deck1.outroEndPos.set(90 * kSamplesPerSecond); + deck2.introStartPos.set(10 * kSamplesPerSecond); + deck2.introEndPos.set(30 * kSamplesPerSecond); + + // AutoDJProcessor calculates the transition when the newTrackLoaded signal + // is emitted. + deck2.fakeTrackLoadedEvent(pTrack); + + // The incoming track should be at intro start + EXPECT_DOUBLE_EQ(0.1, deck2.playposition.get()); + + // No change to the mode, crossfader or play states. + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); + + // Seek the outgoing track to where outro start cue is placed. It should + // start fading. + deck1.playposition.set(0.8); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); + + EXPECT_DOUBLE_EQ(0.1, deck2.playposition.get()); + + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + + // Seek the outgoing track to where fading should end + deck1.playposition.set(0.90); + deck1.play.set(0.0); + + // Expect that we will transition into IDLE mode and request a track load on deck1. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); + + // Advance track to the point where crossfading should be over. + deck2.playposition.set(0.3); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); +} + +TEST_F(AutoDJProcessorTest, AlignIntroOutroStart_LongerOutro) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::AlignIntroOutroStart); + + TrackId testId = addTrackToCollection(kTrackLocationTest); + ASSERT_TRUE(testId.isValid()); + + // Crossfader starts on the left. + master.crossfader.set(-1.0); + // Pretend a track is playing on deck 1. + TrackPointer pTrack(newTestTrack(nextTrackId(testId))); + // Pretend that track is 1 minute and 40 seconds long. + pTrack->setDuration(100); + // Load track and mark it playing. + deck1.slotLoadTrack(pTrack, true); + // Indicate the track loaded successfully. + deck1.fakeTrackLoadedEvent(pTrack); + + PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel(); + pAutoDJTableModel->appendTrack(testId); + + EXPECT_EQ(AutoDJProcessor::ADJ_DISABLED, pProcessor->getState()); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); + + // Enable AutoDJ, we immediately transition into IDLE and request a track + // load on deck2. + AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); + EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + + // Pretend the track load succeeds. + deck2.slotLoadTrack(pTrack, false); + + // Set intro + outro cues. Outro is 20 seconds long; intro is 10 seconds. + const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); + deck1.outroStartPos.set(60 * kSamplesPerSecond); + deck1.outroEndPos.set(80 * kSamplesPerSecond); + deck2.introStartPos.set(10 * kSamplesPerSecond); + deck2.introEndPos.set(20 * kSamplesPerSecond); + + // AutoDJProcessor calculates the transition when the newTrackLoaded signal + // is emitted. + deck2.fakeTrackLoadedEvent(pTrack); + + // The incoming track should be at intro start + EXPECT_DOUBLE_EQ(0.1, deck2.playposition.get()); + + // No change to the mode, crossfader or play states. + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); + + // Seek the outgoing track to where outro start cue is placed. It should + // start fading. + deck1.playposition.set(0.6); + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); + + EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + + // Seek the outgoing track to where fading should end. The rest of the outro + // should be cut off. + deck1.playposition.set(0.7); + deck1.play.set(0.0); + + // Expect that we will transition into IDLE mode and request a track load on deck1. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); + + // Advance track to the point where crossfading should be over. + deck2.playposition.set(0.2); + + EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); + EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); +} + TEST_F(AutoDJProcessorTest, TransitionTimeLoadedFromConfig) { EXPECT_EQ(kDefaultTransitionTime, pProcessor->getTransitionTime()); config()->set(ConfigKey("[Auto DJ]", "Transition"), QString("25")); @@ -1041,6 +1350,8 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_LoadOnDeck1_TrackLoadFailed) { TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::FixedFullTrack); + TrackId testId = addTrackToCollection(kTrackLocationTest); ASSERT_TRUE(testId.isValid()); @@ -1127,6 +1438,8 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { } TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::FixedFullTrack); + TrackId testId = addTrackToCollection(kTrackLocationTest); ASSERT_TRUE(testId.isValid()); @@ -1261,155 +1574,6 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekEnd) { EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); } -TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectIntroCue) { - TrackId testId = addTrackToCollection(kTrackLocationTest); - ASSERT_TRUE(testId.isValid()); - - // Crossfader starts on the left. - master.crossfader.set(-1.0); - // Pretend a track is playing on deck 1. - TrackPointer pTrack(newTestTrack(nextTrackId(testId))); - // Pretend that track is 1 minute and 40 seconds long. - pTrack->setDuration(100); - // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); - // Indicate the track loaded successfully. - deck1.fakeTrackLoadedEvent(pTrack); - - PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel(); - pAutoDJTableModel->appendTrack(testId); - - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); - EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); - - // Enable AutoDJ, we immediately transition into IDLE and request a track - // load on deck2. - AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); - EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); - EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - - // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); - deck2.fakeTrackLoadedEvent(pTrack); - - // Pause transition. Set a negative transition time. - pProcessor->setTransitionTime(-25); - - // Set Intro Start and Outro End cue points. - const double kIntroStartPositionSeconds = 10; - const double kOutroEndPositionSeconds = 90; - const double kSamplesPerSecond = kChannelCount * pTrack->getSampleRate(); - const double kIntroStartPositionSamples = kIntroStartPositionSeconds * kSamplesPerSecond; - const double kOutroEndPositionSamples = kOutroEndPositionSeconds * kSamplesPerSecond; - deck1.introStartPos.set(kIntroStartPositionSamples); - deck1.outroEndPos.set(kOutroEndPositionSamples); - deck2.introStartPos.set(kIntroStartPositionSamples); - deck2.outroEndPos.set(kOutroEndPositionSamples); - - // No change to the mode, crossfader or play states. - EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); - EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - - // The incoming track should have not bee seeked back yet. - EXPECT_DOUBLE_EQ(0.0, deck2.playposition.get()); - - // .. but after reload - deck2.fakeTrackLoadedEvent(pTrack); - EXPECT_DOUBLE_EQ(-0.15, deck2.playposition.get()); - - // Expect that we will transition into LEFT_FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); - - // Seek the outgoing track to where outro end cue is placed. It should fade. - deck1.playposition.set(0.9); - EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - - EXPECT_DOUBLE_EQ(-0.15, deck2.playposition.get()); - - EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); - EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); - - deck1.playposition.set(1); - deck1.play.set(0.0); - - // Expect that we will transition into IDLE mode and request a track load on deck1. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); - EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); - - // Advance track to the point where crossfading should be over. - deck2.playposition.set(0.1); - EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); -} - -TEST_F(AutoDJProcessorTest, FadeToDeck2_RespectOutroCue) { - TrackId testId = addTrackToCollection(kTrackLocationTest); - ASSERT_TRUE(testId.isValid()); - - // Crossfader starts on the left. - master.crossfader.set(-1.0); - // Pretend a track is playing on deck 1. - TrackPointer pTrack(newTestTrack(nextTrackId(testId))); - // Pretend that track is 2 minutes long. - pTrack->setDuration(120); - // Load track and mark it playing. - deck1.slotLoadTrack(pTrack, true); - // Indicate the track loaded successfully. - deck1.fakeTrackLoadedEvent(pTrack); - - PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel(); - pAutoDJTableModel->appendTrack(testId); - - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); - EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); - - // Enable AutoDJ, we immediately transition into IDLE and request a track - // load on deck2. - AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ(true); - EXPECT_EQ(AutoDJProcessor::ADJ_OK, err); - EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - - // Pretend the track load succeeds. - deck2.slotLoadTrack(pTrack, false); - deck2.fakeTrackLoadedEvent(pTrack); - - // Set transition time to 30 seconds (one quarter of track duration). - pProcessor->setTransitionTime(30); - - // Place outro cue on 00:01:30 in order to make fading start - // at the middle of the track. - const double kOutroCuePositionSeconds = 90; - const double kOutroCuePositionSamples = kOutroCuePositionSeconds * - kChannelCount * pTrack->getSampleRate(); - deck1.outroEndPos.set(kOutroCuePositionSamples); - EXPECT_EQ(kOutroCuePositionSamples, deck1.outroEndPos.get()); - - // No change to the mode, crossfader or play states. - EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); - EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - - // Seek track to 45 %. It should not fade. - deck1.playposition.set(0.45); - EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); - EXPECT_DOUBLE_EQ(-1.0, master.crossfader.get()); - - // Expect that we will transition into LEFT_FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); - - // Seek track to 55 %. It should fade. - deck1.playposition.set(0.55); - EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - - EXPECT_LT(-1.0, master.crossfader.get()); - - EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); - EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); -} - TEST_F(AutoDJProcessorTest, TrackZeroLength) { TrackId testId = addTrackToCollection(kTrackLocationTest); ASSERT_TRUE(testId.isValid()); @@ -1446,4 +1610,4 @@ TEST_F(AutoDJProcessorTest, TrackZeroLength) { // Expect that the track is rejected an a new one is loaded // Signal that the request to load pTrack succeeded. deck1.fakeTrackLoadedEvent(pTrack); - } +} From 651b620c3469bc947be08d1856c7f339823f9d25 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 31 Aug 2019 20:16:06 -0500 Subject: [PATCH 107/198] AutoDJ: disable debugging output Also wrap file-specific constants in an anonymous namespace. --- src/library/autodj/autodjprocessor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b7b02b62113..93ce6f881d1 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -9,6 +9,7 @@ #include "mixer/basetrackplayer.h" #define kConfigKey "[Auto DJ]" +namespace { const char* kTransitionPreferenceName = "Transition"; const char* kTransitionModePreferenceName = "TransitionMode"; const double kTransitionPreferenceDefault = 10.0; @@ -16,7 +17,8 @@ const double kKeepPosition = -1.0; const mixxx::AudioSignal::ChannelCount kChannelCount = mixxx::kEngineChannelCount; -static const bool sDebug = true; // false; +static const bool sDebug = false; +} // anonymous namespace DeckAttributes::DeckAttributes(int index, BaseTrackPlayer* pPlayer, From 561bc5e9df9fcf4050904250c349af3671d84aa2 Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Sep 2019 19:01:12 -0500 Subject: [PATCH 108/198] DlgAutoDJ: remove "Fade mode" label for combobox The items in the box should be enough to explain what the combobox is. --- src/library/autodj/dlgautodj.cpp | 1 - src/library/autodj/dlgautodj.ui | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index ab854b34067..00197da7092 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -107,7 +107,6 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, "Use the selected number of seconds as the crossfade time." ); fadeModeCombobox->setToolTip(fadeModeTooltip); - fadeModeLabel->setToolTip(fadeModeTooltip); repeatPlaylistCheckbox->setChecked(m_pConfig->getValue( ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference))); diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index 6d74010c772..ad67982dce8 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -138,13 +138,6 @@ If no track sources are configured, the track is added from the library instead. - - - - Fade mode: - - - From e2b5dba43d108080ee4739ef5c2cad71850af030 Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Sep 2019 19:15:02 -0500 Subject: [PATCH 109/198] AutoDJ: rename transition modes and revise transition mode tooltip --- src/library/autodj/autodjprocessor.cpp | 4 ++-- src/library/autodj/autodjprocessor.h | 2 +- src/library/autodj/dlgautodj.cpp | 33 ++++++++++++++++---------- src/test/autodjprocessor_test.cpp | 8 +++---- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 93ce6f881d1..c0568dc999e 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -253,7 +253,7 @@ void AutoDJProcessor::fadeNow() { double fadeTime; if (m_transitionMode == TransitionMode::FullIntroOutro - || m_transitionMode == TransitionMode::AlignIntroOutroStart) { + || m_transitionMode == TransitionMode::FadeAtOutroStart) { // Use the intro length as the transition time. If the user has seeked // away from the intro start since the track was loaded, start from // there and do not seek back to the intro start. If they have seeked @@ -1062,7 +1062,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, getFirstSoundPosition(pToDeck)); } break; - case TransitionMode::AlignIntroOutroStart: + case TransitionMode::FadeAtOutroStart: // Use the outro or intro length for the transition time, whichever is // shorter. If the outro is longer than the intro, cut off the end // of the outro. diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index b3a5ed5136c..6004556065f 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -156,7 +156,7 @@ class AutoDJProcessor : public QObject { enum class TransitionMode { FullIntroOutro, - AlignIntroOutroStart, + FadeAtOutroStart, FixedFullTrack, FixedSkipSilence }; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 00197da7092..5d4ea5203ce 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -83,11 +83,11 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, fadeModeCombobox->addItem(tr("Full Intro + Outro"), static_cast(AutoDJProcessor::TransitionMode::FullIntroOutro)); - fadeModeCombobox->addItem(tr("Align Intro + Outro Start"), - static_cast(AutoDJProcessor::TransitionMode::AlignIntroOutroStart)); - fadeModeCombobox->addItem(tr("Fixed Time (full track)"), + fadeModeCombobox->addItem(tr("Fade At Outro Start"), + static_cast(AutoDJProcessor::TransitionMode::FadeAtOutroStart)); + fadeModeCombobox->addItem(tr("Full Track"), static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); - fadeModeCombobox->addItem(tr("Fixed Time (skip silence)"), + fadeModeCombobox->addItem(tr("Skip Silence"), static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->setCurrentIndex( fadeModeCombobox->findData(static_cast(m_pAutoDJProcessor->getTransitionMode()))); @@ -95,16 +95,25 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( "Full Intro + Outro:\n" - "Play the full intro and outro. Use the intro or outro length\n" - "as the crossfade time, whichever is shorter.\n" + "Play the full intro and outro. Use the intro or outro length as the\n" + "crossfade time, whichever is shorter. If no intro or outro are marked,\n" + "use the selected crossfade time.\n" "\n" - "Align Intro + Outro Start:\n" - "Start crossfading at the outro start. If the outro is longer\n" - "than the intro, cut off the end of the outro. Use the intro or\n" - "outro length as the crossfade time, whichever is shorter.\n" + "Fade At Outro Start:\n" + "Start crossfading at the outro start. If the outro is longer than the\n" + "intro, cut off the end of the outro. Use the intro or outro length as\n" + "the crossfade time, whichever is shorter. If no intro or outro are\n" + "marked, use the selected crossfade time.\n" "\n" - "Fixed Time modes:\n" - "Use the selected number of seconds as the crossfade time." + "Full Track:\n" + "Play the whole track. Begin crossfading from the selected number of\n" + "seconds before the end of the track. A negative crossfade time adds\n" + "silence between tracks.\n" + "\n" + "Skip Silence:\n" + "Play the whole track except for silence at the beginning and end.\n" + "Begin crossfading from the selected number of seconds before the\n" + "last sound." ); fadeModeCombobox->setToolTip(fadeModeTooltip); diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 3bb00b73640..44939b219fd 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -379,8 +379,8 @@ TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerOutro) { EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); } -TEST_F(AutoDJProcessorTest, AlignIntroOutroStart_LongerIntro) { - pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::AlignIntroOutroStart); +TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerIntro) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::FadeAtOutroStart); TrackId testId = addTrackToCollection(kTrackLocationTest); ASSERT_TRUE(testId.isValid()); @@ -455,8 +455,8 @@ TEST_F(AutoDJProcessorTest, AlignIntroOutroStart_LongerIntro) { EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); } -TEST_F(AutoDJProcessorTest, AlignIntroOutroStart_LongerOutro) { - pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::AlignIntroOutroStart); +TEST_F(AutoDJProcessorTest, FadeAtOutroStart_LongerOutro) { + pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::FadeAtOutroStart); TrackId testId = addTrackToCollection(kTrackLocationTest); ASSERT_TRUE(testId.isValid()); From 0bf4166688d4d2c17aac4099de720fb141e4d6f6 Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Sep 2019 19:46:02 -0500 Subject: [PATCH 110/198] Cue::Type::Hotcue -> Cue::Type::HotCue --- src/engine/controls/cuecontrol.cpp | 4 ++-- src/engine/controls/vinylcontrolcontrol.cpp | 2 +- src/library/dlgtrackinfo.cpp | 4 ++-- src/track/cue.h | 2 +- src/track/track.cpp | 2 +- src/widget/wtracktableview.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c14c278d5e3..4d30380430a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -419,7 +419,7 @@ void CueControl::loadCuesFromTrack() { } else if (pCue->getType() == Cue::Type::Outro) { DEBUG_ASSERT(!pOutroCue); // There should be only one Outro cue pOutroCue = pCue; - } else if (pCue->getType() == Cue::Type::Hotcue && pCue->getHotCue() != -1) { + } else if (pCue->getType() == Cue::Type::HotCue && pCue->getHotCue() != -1) { int hotcue = pCue->getHotCue(); HotcueControl* pControl = m_hotcueControls.value(hotcue, NULL); @@ -561,7 +561,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { pCue->setPosition(cuePosition); pCue->setHotCue(hotcue); pCue->setLabel(""); - pCue->setType(Cue::Type::Hotcue); + pCue->setType(Cue::Type::HotCue); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); diff --git a/src/engine/controls/vinylcontrolcontrol.cpp b/src/engine/controls/vinylcontrolcontrol.cpp index b5784787fe1..fbd3d12945d 100644 --- a/src/engine/controls/vinylcontrolcontrol.cpp +++ b/src/engine/controls/vinylcontrolcontrol.cpp @@ -123,7 +123,7 @@ void VinylControlControl::slotControlVinylSeek(double fractionalPos) { QListIterator it(cuePoints); while (it.hasNext()) { CuePointer pCue(it.next()); - if (pCue->getType() != Cue::Type::Hotcue || pCue->getHotCue() == -1) { + if (pCue->getType() != Cue::Type::HotCue || pCue->getHotCue() == -1) { continue; } diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 75e2c7a44b9..a508ca1e55c 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -278,7 +278,7 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { while (it.hasNext()) { CuePointer pCue = it.next(); Cue::Type type = pCue->getType(); - if (type == Cue::Type::Hotcue || type == Cue::Type::Intro || type == Cue::Type::Outro) { + if (type == Cue::Type::HotCue || type == Cue::Type::Intro || type == Cue::Type::Outro) { listPoints.push_back(pCue); } } @@ -325,7 +325,7 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { // Decode cue type to display text QString cueType; switch (pCue->getType()) { - case Cue::Type::Hotcue: + case Cue::Type::HotCue: cueType = "Hotcue"; break; case Cue::Type::Intro: diff --git a/src/track/cue.h b/src/track/cue.h index 3dfefa12632..2fa33aaa6b7 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -19,7 +19,7 @@ class Cue : public QObject { public: enum class Type { Invalid = 0, - Hotcue = 1, + HotCue = 1, MainCue = 2, Beat = 3, // unused (what is this for?) Loop = 4, diff --git a/src/track/track.cpp b/src/track/track.cpp index 10eebfe2d80..710aa761568 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -698,7 +698,7 @@ CuePointer Track::createAndAddCue() { CuePointer Track::findCueByType(Cue::Type type) const { // This method cannot be used for hotcues because there can be // multiple hotcues and this function returns only a single CuePointer. - DEBUG_ASSERT(type != Cue::Type::Hotcue); + DEBUG_ASSERT(type != Cue::Type::HotCue); QMutexLocker lock(&m_qMutex); for (const CuePointer& pCue: m_cuePoints) { if (pCue->getType() == type) { diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 21d1b85b773..d1799f535b4 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -1895,7 +1895,7 @@ void WTrackTableView::slotClearHotCues() { for (const QModelIndex& index : indices) { TrackPointer pTrack = trackModel->getTrack(index); if (pTrack) { - pTrack->removeCuesOfType(Cue::Type::Hotcue); + pTrack->removeCuesOfType(Cue::Type::HotCue); } } } From 4f753c942d7573d6e0304a24637ccf0aeacc72ca Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Sep 2019 20:08:14 -0500 Subject: [PATCH 111/198] AutoDJ: use outroEnd/introStart as fallbacks instead of first/last sound --- src/library/autodj/autodjprocessor.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index c0568dc999e..9234a644c14 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1057,9 +1057,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else { - useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), - getFirstSoundPosition(pToDeck)); + useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } break; case TransitionMode::FadeAtOutroStart: @@ -1102,14 +1100,11 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else { - useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), - getFirstSoundPosition(pToDeck)); + useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); } break; case TransitionMode::FixedSkipSilence: - useFixedFadeTime(pFromDeck, - pToDeck, + useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), getFirstSoundPosition(pToDeck)); break; From 7fd8e719ed4e08b5ccbe9dbcdf9db16fa4a19002 Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Sep 2019 20:38:18 -0500 Subject: [PATCH 112/198] AutoDJ: improve handling of edge case with Fade Now button --- src/library/autodj/autodjprocessor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 9234a644c14..3469de7c8f5 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -261,18 +261,18 @@ void AutoDJProcessor::fadeNow() { // spinbox time. double outroEnd = getOutroEndPosition(pFromDeck); double introEnd = getIntroEndPosition(pToDeck); + double timeUntilOutroEnd = outroEnd - fromDeckCurrentPosition; if (toDeckCurrentPosition <= introEnd && introEnd >= 0) { double introLength = introEnd - toDeckCurrentPosition; if (outroEnd >= 0) { // The fade must end by the outro end at the latest. - double timeUntilOutroEnd = outroEnd - fromDeckCurrentPosition; fadeTime = math_min(introLength, timeUntilOutroEnd); } else { fadeTime = introLength; } } else { - fadeTime = spinboxTime; + fadeTime = math_min(spinboxTime, timeUntilOutroEnd); } } else { fadeTime = spinboxTime; From 8d26c08d6730f9a6c3420a4497e36daa6b98d75f Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Sep 2019 20:40:15 -0500 Subject: [PATCH 113/198] AutoDJ: simplify redundant code --- src/library/autodj/autodjprocessor.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 3469de7c8f5..1b976c43333 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -989,12 +989,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, if (outroStart <= 0.0) { // Assume a zero length outro. // The outroEnd is automatically placed by AnalyzerSilence, so use - // that as a fallback if the user has not placed outroStart. - if (outroEnd >= 0) { - outroStart = outroEnd; - } else { - outroEnd = fromTrackDuration; - } + // that as a fallback if the user has not placed outroStart. If it has + // not been placed, getOutroEndPosition will return the end of the track. + outroStart = outroEnd; } double outroLength = outroEnd - outroStart; From 05351e651e423130a3fa2bf93121c57a192968fc Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 1 Sep 2019 23:46:57 -0500 Subject: [PATCH 114/198] AutoDJ: load next track if user crossfades manually --- src/library/autodj/autodjprocessor.cpp | 33 ++++++++++++++++++++++++++ src/library/autodj/autodjprocessor.h | 1 + 2 files changed, 34 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 1b976c43333..1aff9e917d0 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -372,6 +372,8 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ enabled"; + m_pCOCrossfader->connectValueChanged(this, &AutoDJProcessor::crossfaderChanged); + connect(&deck1, &DeckAttributes::playPositionChanged, this, &AutoDJProcessor::playerPositionChanged); connect(&deck2, &DeckAttributes::playPositionChanged, @@ -456,6 +458,8 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ disabled"; m_eState = ADJ_DISABLED; + disconnect(m_pCOCrossfader, &ControlProxy::valueChanged, + this, &AutoDJProcessor::crossfaderChanged); deck1.disconnect(this); deck2.disconnect(this); m_pCOCrossfader->set(0); @@ -486,6 +490,35 @@ void AutoDJProcessor::controlSkipNext(double value) { } } +void AutoDJProcessor::crossfaderChanged(double value) { + if (m_eState == ADJ_IDLE) { + // The user is changing the crossfader manually. If the user has + // moved it all the way to the other side, make the deck faded away + // from the new "to deck" by loading the next track into it. + DeckAttributes* leftDeck = m_decks.at(0); + DeckAttributes* rightDeck = m_decks.at(1); + DeckAttributes* newToDeck = nullptr; + DeckAttributes* newFromDeck = nullptr; + + double crossfaderPosition = value * (m_pCOCrossfaderReverse->toBool() ? -1 : 1); + if (crossfaderPosition == 1.0 && leftDeck->isFromDeck) { // crossfader right + newFromDeck = rightDeck; + newToDeck = leftDeck; + } else if (crossfaderPosition == -1.0 && rightDeck->isFromDeck) { // crossfader left + newFromDeck = leftDeck; + newToDeck = rightDeck; + } + + if (newToDeck != nullptr && newFromDeck != nullptr) { + newToDeck->stop(); + removeLoadedTrackFromTopOfQueue(*newFromDeck); + loadNextTrackFromQueue(*newToDeck); + calculateTransition(newFromDeck, newToDeck, false); + newFromDeck->play(); + } + } +} + void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, double thisPlayPosition) { if (sDebug) { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 6004556065f..50a0398bd5d 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -213,6 +213,7 @@ class AutoDJProcessor : public QObject { void randomTrackRequested(int tracksToAdd); private slots: + void crossfaderChanged(double value); void playerPositionChanged(DeckAttributes* pDeck, double position); void playerPlayChanged(DeckAttributes* pDeck, bool playing); void playerIntroStartChanged(DeckAttributes* pDeck, double position); From 29c31f40dee988fe5c8085388c3f94efa44fc814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 3 Sep 2019 23:01:47 +0200 Subject: [PATCH 115/198] Style Auto DJ dialog --- res/skins/Shade/style.qss | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss index 2b07f6abe0f..72a1aeba3a1 100644 --- a/res/skins/Shade/style.qss +++ b/res/skins/Shade/style.qss @@ -19,8 +19,6 @@ padding: 5px 0px; } - - WBeatSpinBox, /* For some mysterious reason #DlgAutoDJ QSpinBox wouldn't style the respective spinbox in Shade (anymore), @@ -62,7 +60,7 @@ WBeatSpinBox::down-button, image: url(skin:/btn/btn_spin_down.png) no-repeat; } - +#fadeModeCombobox, WEffectSelector { color: #060613; background-color: #aab2b7; @@ -74,11 +72,13 @@ WEffectSelector { font: 13px; } +#fadeModeCombobox::drop-down, WEffectSelector::drop-down { /* This causes the Qt theme's widget style to magically not apply. Go figure. */ border: 0; } +#fadeModeCombobox::down-arrow, WEffectSelector::down-arrow { height: 20px; border-style: solid; @@ -87,6 +87,14 @@ WEffectSelector::down-arrow { image: url(skin:/btn/btn_spin_down.png) no-repeat; } + +#fadeModeCombobox { + height: 20px; + background-color: #99a0a4; + border: 1px solid #191919; + margin-bottom: 2px; +} + WEffectSelector QAbstractItemView { color: #060613; background-color: #aab2b7; @@ -396,7 +404,11 @@ The general rule when it comes to stylesheets is always to remember that if you /* transition time in Auto DJ tab*/ QSpinBox:editable, /* or addressed directly */ -#spinBoxTransition {} +#spinBoxTransition { + height: 20px; + border: 1px solid #191919; + background-color: #99a0a4; +} /* Cover Art*/ WCoverArt { From be583584cff4d1f2d4437237b9d200cf4c68185b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 3 Sep 2019 23:44:31 +0200 Subject: [PATCH 116/198] Group transition time with transition mode combobox. --- res/skins/Shade/style.qss | 1 + src/library/autodj/dlgautodj.ui | 92 ++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 31 deletions(-) diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss index 72a1aeba3a1..6c864bd4d5e 100644 --- a/res/skins/Shade/style.qss +++ b/res/skins/Shade/style.qss @@ -93,6 +93,7 @@ WEffectSelector::down-arrow { background-color: #99a0a4; border: 1px solid #191919; margin-bottom: 2px; + margin-left: 10px; } WEffectSelector QAbstractItemView { diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index ad67982dce8..2ff6e68c339 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -6,7 +6,7 @@ 0 0 - 913 + 885 399 @@ -48,6 +48,12 @@ + + + 0 + 0 + + Turn Auto DJ on or off. @@ -60,39 +66,13 @@ - + - + 0 0 - - Determines the duration of the transition. - - - false - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - -9 - - - - - - - Seconds - - - sec. - - - - - Trigger the transition to the next track. @@ -103,6 +83,12 @@ + + + 0 + 0 + + Skip the next track in the Auto DJ queue. @@ -116,6 +102,12 @@ + + + 0 + 0 + + Shuffle the content of the Auto DJ queue. @@ -129,6 +121,12 @@ + + + 0 + 0 + + Adds a random track from track sources (crates) to the Auto DJ queue. If no track sources are configured, the track is added from the library instead. @@ -142,7 +140,39 @@ If no track sources are configured, the track is added from the library instead. - + + + + 0 + 0 + + + + Determines the duration of the transition. + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + -9 + + + + + + + Seconds + + + sec. + + + + + @@ -183,7 +213,7 @@ If no track sources are configured, the track is added from the library instead. - + From af9a2ff42195e2cdc2dff6cb6921d1654dfd187c Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 9 Sep 2019 19:46:03 -0500 Subject: [PATCH 117/198] add SkinButton class and use it for WLibrary This allows for skins to set graphics for the buttons in the library. --- src/skin/legacyskinparser.cpp | 1 + src/skin/skinbutton.h | 69 +++++++++++++++++++++++++++++++++++ src/widget/wlibrary.cpp | 4 ++ src/widget/wlibrary.h | 5 +++ 4 files changed, 79 insertions(+) create mode 100644 src/skin/skinbutton.h diff --git a/src/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp index f9a699d07fb..bce74c9abb6 100644 --- a/src/skin/legacyskinparser.cpp +++ b/src/skin/legacyskinparser.cpp @@ -1318,6 +1318,7 @@ QWidget* LegacySkinParser::parseLibrary(const QDomElement& node) { WLibrary* pLibraryWidget = new WLibrary(m_pParent); pLibraryWidget->installEventFilter(m_pKeyboard); pLibraryWidget->installEventFilter(m_pControllerManager->getControllerLearningEventFilter()); + pLibraryWidget->setup(node, *m_pContext); // Connect Library search signals to the WLibrary connect(m_pLibrary, SIGNAL(search(const QString&)), diff --git a/src/skin/skinbutton.h b/src/skin/skinbutton.h new file mode 100644 index 00000000000..72d408eab50 --- /dev/null +++ b/src/skin/skinbutton.h @@ -0,0 +1,69 @@ +#pragma once +#include "skin/skincontext.h" + +// These classes provide a way for skins to specify pixmap paths for the +// icons in complex widgets, for example the buttons in DlgAutoDJ. The skin XML +// for the widget would have a Buttons element like: +// +// +// +// +// +// Call ButtonIcon::parseIcons in the widget's setup method and store the result +// in a member variable. + +class SkinButtonState { + public: + QString name; + PixmapSource pixmapSource; +}; + +class SkinButton { + public: + QString name; + QMap states; + + void addState(SkinButtonState state) { + states.insert(state.name, state); + } + + static QMap parseIcons( + const QDomNode& node, const SkinContext& context) { + + QMap icons; + QDomElement buttonIconsList = context.selectElement(node, "Buttons"); + QDomNode buttonIconNode = context.selectNode(buttonIconsList, "Button"); + while (!buttonIconNode.isNull()) { + if (buttonIconNode.isElement() && buttonIconNode.nodeName() == "Button") { + SkinButton buttonIcon; + QString buttonName = buttonIconNode.toElement().attribute("name"); + if (buttonName.isEmpty()) { + buttonIconNode = buttonIconNode.nextSibling(); + continue; + } + buttonIcon.name = buttonName; + + QDomNode buttonStateNode = context.selectNode(buttonIconNode, "State"); + while (!buttonStateNode.isNull()) { + if (buttonStateNode.isElement() && buttonStateNode.nodeName() == "State") { + SkinButtonState buttonIconState; + QString buttonIconStateName = buttonStateNode.toElement().attribute("name"); + if (!buttonIconStateName.isEmpty()) { + buttonIconState.name = buttonIconStateName; + buttonIconState.pixmapSource = context.getPixmapSource(buttonStateNode); + buttonIcon.addState(buttonIconState); + } + } + buttonStateNode = buttonStateNode.nextSibling(); + } + + icons.insert(buttonName, buttonIcon); + } + buttonIconNode = buttonIconNode.nextSibling(); + } + return icons; + } +}; diff --git a/src/widget/wlibrary.cpp b/src/widget/wlibrary.cpp index 0fd97bf8760..3b64e62fcb1 100644 --- a/src/widget/wlibrary.cpp +++ b/src/widget/wlibrary.cpp @@ -15,6 +15,10 @@ WLibrary::WLibrary(QWidget* parent) m_mutex(QMutex::Recursive) { } +void WLibrary::setup(const QDomNode& node, const SkinContext& context) { + icons = SkinButton::parseIcons(node, context); +} + bool WLibrary::registerView(QString name, QWidget* view) { QMutexLocker lock(&m_mutex); if (m_viewMap.contains(name)) { diff --git a/src/widget/wlibrary.h b/src/widget/wlibrary.h index 4df3060963b..50ca8e44a43 100644 --- a/src/widget/wlibrary.h +++ b/src/widget/wlibrary.h @@ -11,6 +11,8 @@ #include #include "library/libraryview.h" +#include "skin/skinbutton.h" +#include "skin/skincontext.h" #include "widget/wbasewidget.h" class KeyboardEventFilter; @@ -20,6 +22,9 @@ class WLibrary : public QStackedWidget, public WBaseWidget { public: explicit WLibrary(QWidget* parent); + void setup(const QDomNode& node, const SkinContext& context); + QMap icons; + // registerView is used to add a view to the LibraryWidget which the widget // can display on request via showView(). To switch to a given view, call // showView with the name provided here. WLibraryWidget takes ownership of From bcc8d16fde0d3415db6c282d956c57b7ac2ba90c Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 9 Sep 2019 19:51:13 -0500 Subject: [PATCH 118/198] AutoDJ: change Repeat playlist checkbox to button with icon --- src/library/autodj/autodjfeature.cpp | 3 ++- src/library/autodj/dlgautodj.cpp | 26 ++++++++++++++++++++------ src/library/autodj/dlgautodj.h | 5 ++++- src/library/autodj/dlgautodj.ui | 16 +++++++++++----- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index 3ec62d7d6ba..b7d7a54c569 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -109,7 +109,8 @@ void AutoDJFeature::bindWidget(WLibrary* libraryWidget, m_pLibrary, m_pAutoDJProcessor, m_pTrackCollection, - keyboard); + keyboard, + libraryWidget->icons); libraryWidget->registerView(m_sAutoDJViewName, m_pAutoDJView); connect(m_pAutoDJView, SIGNAL(loadTrack(TrackPointer)), this, SIGNAL(loadTrack(TrackPointer))); diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 5d4ea5203ce..e2df5f3de56 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -11,6 +11,7 @@ namespace { const char* kPreferenceGroupName = "[Auto DJ]"; const char* kRepeatPlaylistPreference = "Requeue"; +const char* kRepeatButtonName = "AutoDjRepeatPlaylist"; } // anonymous namespace DlgAutoDJ::DlgAutoDJ(QWidget* parent, @@ -18,7 +19,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, Library* pLibrary, AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, - KeyboardEventFilter* pKeyboard) + KeyboardEventFilter* pKeyboard, + QMap icons) : QWidget(parent), Ui::DlgAutoDJ(), m_pAutoDJProcessor(pProcessor), @@ -26,7 +28,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, m_pTrackTableView(new WTrackTableView(this, pConfig, pTrackCollection, false)), m_pAutoDJTableModel(nullptr), - m_pConfig(pConfig) { + m_pConfig(pConfig), + m_icons(icons) { setupUi(this); m_pTrackTableView->installEventFilter(pKeyboard); @@ -117,10 +120,12 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, ); fadeModeCombobox->setToolTip(fadeModeTooltip); - repeatPlaylistCheckbox->setChecked(m_pConfig->getValue( - ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference))); - connect(repeatPlaylistCheckbox, &QCheckBox::stateChanged, + connect(pushButtonRepeatPlaylist, &QPushButton::toggled, this, &DlgAutoDJ::slotRepeatPlaylistChanged); + bool repeatPlaylist = m_pConfig->getValue( + ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference)); + pushButtonRepeatPlaylist->setChecked(repeatPlaylist); + slotRepeatPlaylistChanged(repeatPlaylist); // Setup DlgAutoDJ UI based on the current AutoDJProcessor state. Keep in // mind that AutoDJ may already be active when DlgAutoDJ is created (due to @@ -247,8 +252,17 @@ void DlgAutoDJ::slotTransitionModeChanged(int comboboxIndex) { } void DlgAutoDJ::slotRepeatPlaylistChanged(int checkState) { + bool checked = static_cast(checkState); m_pConfig->setValue(ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference), - static_cast(checkState)); + checked); + QString stateName = checked ? "On" : "Off"; + QString pixmapPath = m_icons.value(kRepeatButtonName).states.value(stateName).pixmapSource.getPath(); + qDebug () << "DlgAutoDJ::slotRepeatPlaylistChanged" << pixmapPath; + if (pixmapPath.isEmpty()) { + pushButtonRepeatPlaylist->setText(tr("Repeat")); + } else { + pushButtonRepeatPlaylist->setIcon(QIcon(pixmapPath)); + } } void DlgAutoDJ::updateSelectionInfo() { diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index 849e66b9121..2a25bc121b2 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -6,6 +6,7 @@ #include "library/autodj/ui_dlgautodj.h" #include "preferences/usersettings.h" +#include "skin/skinbutton.h" #include "track/track.h" #include "library/libraryview.h" #include "library/library.h" @@ -22,7 +23,8 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { DlgAutoDJ(QWidget* parent, UserSettingsPointer pConfig, Library* pLibrary, AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, - KeyboardEventFilter* pKeyboard); + KeyboardEventFilter* pKeyboard, + QMap icons); ~DlgAutoDJ() override; void onShow() override; @@ -55,6 +57,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { WTrackTableView* m_pTrackTableView; PlaylistTableModel* m_pAutoDJTableModel; UserSettingsPointer m_pConfig; + QMap m_icons; }; #endif //DLGAUTODJ_H diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index 2ff6e68c339..ed8be0299fd 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -172,13 +172,19 @@ If no track sources are configured, the track is added from the library instead. - - - - - + + + + 0 + 0 + + + Repeat playlist + + true + From 0bcd3f4dc4c8f9c3f9164ebab54275351c1262f3 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 9 Sep 2019 20:15:20 -0500 Subject: [PATCH 119/198] reuse looping icons for AutoDJ repeat playlist button --- res/skins/Deere/library.xml | 6 ++ .../btn_autodj_repeat_playlist_off.svg | 65 ++++++++++++++++++ .../buttons/btn_autodj_repeat_playlist_on.svg | 65 ++++++++++++++++++ res/skins/LateNight/library.xml | 6 ++ .../Shade/btn/btn_autodj_repeat_playlist.png | Bin 0 -> 228 bytes res/skins/Shade/skin.xml | 9 ++- res/skins/Tango/library.xml | 6 ++ 7 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg create mode 100644 res/skins/Shade/btn/btn_autodj_repeat_playlist.png diff --git a/res/skins/Deere/library.xml b/res/skins/Deere/library.xml index e6464a2671b..d5dc406fadc 100644 --- a/res/skins/Deere/library.xml +++ b/res/skins/Deere/library.xml @@ -63,6 +63,12 @@ + + + diff --git a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg new file mode 100644 index 00000000000..a51c483b930 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg new file mode 100644 index 00000000000..1bb45260402 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/res/skins/LateNight/library.xml b/res/skins/LateNight/library.xml index c955e5591a7..e682ba50d26 100644 --- a/res/skins/LateNight/library.xml +++ b/res/skins/LateNight/library.xml @@ -66,6 +66,12 @@ #585858 #eece33 + + + diff --git a/res/skins/Shade/btn/btn_autodj_repeat_playlist.png b/res/skins/Shade/btn/btn_autodj_repeat_playlist.png new file mode 100644 index 0000000000000000000000000000000000000000..c64bd1c57f87937ff3a8cd2c7576148066975236 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`j)5C}6~x?A@LC^*g2 z#WBR9_w6KGzC#8)Zu3{)WAvJ6Bk-S2|$&T;P3Ir~<7TFv>Z613+iSMApKv$&m;QkeN9U;I#vFL`QR zaHUx2*QfUCQZ*gF$BP7<*SYWbb-L@~@dJDUVksFs9|arpO{!Yw&ePfce16DpPU*|S YKlW*?k^ZH*2vertical me,me - + + + + + diff --git a/res/skins/Tango/library.xml b/res/skins/Tango/library.xml index 2581d3521e1..2e46192287b 100644 --- a/res/skins/Tango/library.xml +++ b/res/skins/Tango/library.xml @@ -95,6 +95,12 @@ Description: #585858 #eece33 + + + From 2e6f6fd9702b44dddda17a21bd383b58f2b26b4a Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 10 Sep 2019 14:38:17 -0500 Subject: [PATCH 120/198] DlgAutoDJ: use Qt5 function pointer signal-slot syntax --- src/library/autodj/dlgautodj.cpp | 62 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index e2df5f3de56..97ac1f3d83b 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -33,21 +33,21 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, setupUi(this); m_pTrackTableView->installEventFilter(pKeyboard); - connect(m_pTrackTableView, SIGNAL(loadTrack(TrackPointer)), - this, SIGNAL(loadTrack(TrackPointer))); - connect(m_pTrackTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)), - this, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool))); - connect(m_pTrackTableView, SIGNAL(trackSelected(TrackPointer)), - this, SIGNAL(trackSelected(TrackPointer))); - connect(m_pTrackTableView, SIGNAL(trackSelected(TrackPointer)), - this, SLOT(updateSelectionInfo())); - - connect(pLibrary, SIGNAL(setTrackTableFont(QFont)), - m_pTrackTableView, SLOT(setTrackTableFont(QFont))); - connect(pLibrary, SIGNAL(setTrackTableRowHeight(int)), - m_pTrackTableView, SLOT(setTrackTableRowHeight(int))); - connect(pLibrary, SIGNAL(setSelectedClick(bool)), - m_pTrackTableView, SLOT(setSelectedClick(bool))); + connect(m_pTrackTableView, &WTrackTableView::loadTrack, + this, &DlgAutoDJ::loadTrack); + connect(m_pTrackTableView, &WTrackTableView::loadTrackToPlayer, + this, &DlgAutoDJ::loadTrackToPlayer); + connect(m_pTrackTableView, &WTrackTableView::trackSelected, + this, &DlgAutoDJ::trackSelected); + connect(m_pTrackTableView, &WTrackTableView::trackSelected, + this, &DlgAutoDJ::updateSelectionInfo); + + connect(pLibrary, &Library::setTrackTableFont, + m_pTrackTableView, &WTrackTableView::setTrackTableFont); + connect(pLibrary, &Library::setTrackTableRowHeight, + m_pTrackTableView, &WTrackTableView::setTrackTableRowHeight); + connect(pLibrary, &Library::setSelectedClick, + m_pTrackTableView, &WTrackTableView::setSelectedClick); QBoxLayout* box = dynamic_cast(layout()); VERIFY_OR_DEBUG_ASSERT(box) { //Assumes the form layout is a QVBox/QHBoxLayout! @@ -66,23 +66,23 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, // Do not set this because it disables auto-scrolling //m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove); - connect(pushButtonShuffle, SIGNAL(clicked(bool)), - this, SLOT(shufflePlaylistButton(bool))); + connect(pushButtonShuffle, &QPushButton::clicked, + this, &DlgAutoDJ::shufflePlaylistButton); - connect(pushButtonSkipNext, SIGNAL(clicked(bool)), - this, SLOT(skipNextButton(bool))); + connect(pushButtonSkipNext, &QPushButton::clicked, + this, &DlgAutoDJ::skipNextButton); - connect(pushButtonAddRandom, SIGNAL(clicked(bool)), - this, SIGNAL(addRandomButton(bool))); + connect(pushButtonAddRandom, &QPushButton::clicked, + this, &DlgAutoDJ::addRandomButton); - connect(pushButtonFadeNow, SIGNAL(clicked(bool)), - this, SLOT(fadeNowButton(bool))); + connect(pushButtonFadeNow, &QPushButton::clicked, + this, &DlgAutoDJ::fadeNowButton); - connect(spinBoxTransition, SIGNAL(valueChanged(int)), - this, SLOT(transitionSliderChanged(int))); + connect(spinBoxTransition, QOverload::of(&QSpinBox::valueChanged), + this, &DlgAutoDJ::transitionSliderChanged); - connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), - this, SLOT(toggleAutoDJButton(bool))); + connect(pushButtonAutoDJ, &QPushButton::toggled, + this, &DlgAutoDJ::toggleAutoDJButton); fadeModeCombobox->addItem(tr("Full Intro + Outro"), static_cast(AutoDJProcessor::TransitionMode::FullIntroOutro)); @@ -131,10 +131,10 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, // mind that AutoDJ may already be active when DlgAutoDJ is created (due to // skin changes, etc.). spinBoxTransition->setValue(m_pAutoDJProcessor->getTransitionTime()); - connect(m_pAutoDJProcessor, SIGNAL(transitionTimeChanged(int)), - this, SLOT(transitionTimeChanged(int))); - connect(m_pAutoDJProcessor, SIGNAL(autoDJStateChanged(AutoDJProcessor::AutoDJState)), - this, SLOT(autoDJStateChanged(AutoDJProcessor::AutoDJState))); + connect(m_pAutoDJProcessor, &AutoDJProcessor::transitionTimeChanged, + this, &DlgAutoDJ::transitionTimeChanged); + connect(m_pAutoDJProcessor, &AutoDJProcessor::autoDJStateChanged, + this, &DlgAutoDJ::autoDJStateChanged); autoDJStateChanged(m_pAutoDJProcessor->getState()); updateSelectionInfo(); From 5f3bc70f2874a264724b8fc362f1573ab9d30e5c Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 10 Sep 2019 15:05:40 -0500 Subject: [PATCH 121/198] remove debug message --- src/library/autodj/dlgautodj.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 97ac1f3d83b..6c8b935d321 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -257,7 +257,6 @@ void DlgAutoDJ::slotRepeatPlaylistChanged(int checkState) { checked); QString stateName = checked ? "On" : "Off"; QString pixmapPath = m_icons.value(kRepeatButtonName).states.value(stateName).pixmapSource.getPath(); - qDebug () << "DlgAutoDJ::slotRepeatPlaylistChanged" << pixmapPath; if (pixmapPath.isEmpty()) { pushButtonRepeatPlaylist->setText(tr("Repeat")); } else { From 4b6567f9beb0d5a815aeb15c88b04fdb8508b5cb Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 10 Sep 2019 15:06:14 -0500 Subject: [PATCH 122/198] DlgAutoDJ: let skins specify icons for rest of buttons --- src/library/autodj/dlgautodj.cpp | 50 ++++++++++++++++++++++---------- src/library/autodj/dlgautodj.h | 3 ++ src/library/autodj/dlgautodj.ui | 15 ---------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 6c8b935d321..074a3775cd7 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -11,6 +11,11 @@ namespace { const char* kPreferenceGroupName = "[Auto DJ]"; const char* kRepeatPlaylistPreference = "Requeue"; +const char* kEnableButtonName = "AutoDjEnable"; +const char* kShuffleButtonName = "AutoDjShuffle"; +const char* kSkipButtonName = "AutoDjSkip"; +const char* kAddRandomButtonName = "AutoDjAddRandom"; +const char* kFadeNowButtonName = "AutoDjFadeNow"; const char* kRepeatButtonName = "AutoDjRepeatPlaylist"; } // anonymous namespace @@ -66,24 +71,21 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, // Do not set this because it disables auto-scrolling //m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove); - connect(pushButtonShuffle, &QPushButton::clicked, - this, &DlgAutoDJ::shufflePlaylistButton); - - connect(pushButtonSkipNext, &QPushButton::clicked, - this, &DlgAutoDJ::skipNextButton); - - connect(pushButtonAddRandom, &QPushButton::clicked, - this, &DlgAutoDJ::addRandomButton); + connect(pushButtonAutoDJ, &QPushButton::toggled, + this, &DlgAutoDJ::toggleAutoDJButton); - connect(pushButtonFadeNow, &QPushButton::clicked, - this, &DlgAutoDJ::fadeNowButton); + setupActionButton(pushButtonShuffle, &DlgAutoDJ::shufflePlaylistButton, + kShuffleButtonName, tr("Shuffle")); + setupActionButton(pushButtonSkipNext, &DlgAutoDJ::skipNextButton, + kSkipButtonName, tr("Skip")); + setupActionButton(pushButtonAddRandom, &DlgAutoDJ::addRandomButton, + kAddRandomButtonName, tr("Random")); + setupActionButton(pushButtonFadeNow, &DlgAutoDJ::fadeNowButton, + kFadeNowButtonName, tr("Fade")); connect(spinBoxTransition, QOverload::of(&QSpinBox::valueChanged), this, &DlgAutoDJ::transitionSliderChanged); - connect(pushButtonAutoDJ, &QPushButton::toggled, - this, &DlgAutoDJ::toggleAutoDJButton); - fadeModeCombobox->addItem(tr("Full Intro + Outro"), static_cast(AutoDJProcessor::TransitionMode::FullIntroOutro)); fadeModeCombobox->addItem(tr("Fade At Outro Start"), @@ -148,6 +150,17 @@ DlgAutoDJ::~DlgAutoDJ() { delete m_pTrackTableView; } +void DlgAutoDJ::setupActionButton(QPushButton* pButton, void (DlgAutoDJ::*pSlot)(bool), + QString skinButtonName, QString fallbackText) { + connect(pButton, &QPushButton::clicked, this, pSlot); + QString iconPath = m_icons.value(skinButtonName).states.value("Off").pixmapSource.getPath(); + if (iconPath.isEmpty()) { + pButton->setText(fallbackText); + } else { + pButton->setIcon(QIcon(iconPath)); + } +} + void DlgAutoDJ::onShow() { m_pAutoDJTableModel->select(); } @@ -220,17 +233,18 @@ void DlgAutoDJ::transitionSliderChanged(int value) { } void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) { + QString stateName; if (state == AutoDJProcessor::ADJ_DISABLED) { pushButtonAutoDJ->setChecked(false); pushButtonAutoDJ->setToolTip(tr("Enable Auto DJ")); - pushButtonAutoDJ->setText(tr("Enable Auto DJ")); + stateName = "Off"; pushButtonFadeNow->setEnabled(false); pushButtonSkipNext->setEnabled(false); } else { // No matter the mode, you can always disable once it is enabled. pushButtonAutoDJ->setChecked(true); pushButtonAutoDJ->setToolTip(tr("Disable Auto DJ")); - pushButtonAutoDJ->setText(tr("Disable Auto DJ")); + stateName = "On"; // If fading, you can't hit fade now. if (state == AutoDJProcessor::ADJ_LEFT_FADING || @@ -244,6 +258,12 @@ void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) { // You can always skip the next track if we are enabled. pushButtonSkipNext->setEnabled(true); } + QString pixmapPath = m_icons.value(kEnableButtonName).states.value(stateName).pixmapSource.getPath(); + if (pixmapPath.isEmpty()) { + pushButtonAutoDJ->setText((state == AutoDJProcessor::ADJ_DISABLED) ? tr("Enable") : tr("Disable")); + } else { + pushButtonAutoDJ->setIcon(QIcon(pixmapPath)); + } } void DlgAutoDJ::slotTransitionModeChanged(int comboboxIndex) { diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index 2a25bc121b2..351fd6d3a10 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -53,6 +53,9 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { void trackSelected(TrackPointer pTrack); private: + void setupActionButton(QPushButton* pButton, void (DlgAutoDJ::*pSlot)(bool), + QString skinButtonName, QString fallbackText); + AutoDJProcessor* m_pAutoDJProcessor; WTrackTableView* m_pTrackTableView; PlaylistTableModel* m_pAutoDJTableModel; diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index ed8be0299fd..d47312d6f67 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -57,9 +57,6 @@ Turn Auto DJ on or off. - - Enable Auto DJ - true @@ -76,9 +73,6 @@ Trigger the transition to the next track. - - Fade Now - @@ -92,9 +86,6 @@ Skip the next track in the Auto DJ queue. - - Skip Track - false @@ -111,9 +102,6 @@ Shuffle the content of the Auto DJ queue. - - Shuffle - false @@ -131,9 +119,6 @@ Adds a random track from track sources (crates) to the Auto DJ queue. If no track sources are configured, the track is added from the library instead. - - Add Random - From 4a6dab25317f5ccb59ca1ecc0e9bc52f2a1bbd5c Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 10 Sep 2019 15:10:51 -0500 Subject: [PATCH 123/198] WLibrary: make m_icons private and add const getter function --- src/library/autodj/autodjfeature.cpp | 2 +- src/library/autodj/dlgautodj.cpp | 2 +- src/library/autodj/dlgautodj.h | 4 ++-- src/widget/wlibrary.cpp | 2 +- src/widget/wlibrary.h | 6 +++++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index b7d7a54c569..6551201684d 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -110,7 +110,7 @@ void AutoDJFeature::bindWidget(WLibrary* libraryWidget, m_pAutoDJProcessor, m_pTrackCollection, keyboard, - libraryWidget->icons); + libraryWidget->icons()); libraryWidget->registerView(m_sAutoDJViewName, m_pAutoDJView); connect(m_pAutoDJView, SIGNAL(loadTrack(TrackPointer)), this, SIGNAL(loadTrack(TrackPointer))); diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 074a3775cd7..af06944836a 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -25,7 +25,7 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard, - QMap icons) + const QMap icons) : QWidget(parent), Ui::DlgAutoDJ(), m_pAutoDJProcessor(pProcessor), diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index 351fd6d3a10..422acdeefd5 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -24,7 +24,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { Library* pLibrary, AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard, - QMap icons); + const QMap icons); ~DlgAutoDJ() override; void onShow() override; @@ -60,7 +60,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { WTrackTableView* m_pTrackTableView; PlaylistTableModel* m_pAutoDJTableModel; UserSettingsPointer m_pConfig; - QMap m_icons; + const QMap m_icons; }; #endif //DLGAUTODJ_H diff --git a/src/widget/wlibrary.cpp b/src/widget/wlibrary.cpp index 3b64e62fcb1..6c672d4a240 100644 --- a/src/widget/wlibrary.cpp +++ b/src/widget/wlibrary.cpp @@ -16,7 +16,7 @@ WLibrary::WLibrary(QWidget* parent) } void WLibrary::setup(const QDomNode& node, const SkinContext& context) { - icons = SkinButton::parseIcons(node, context); + m_icons = SkinButton::parseIcons(node, context); } bool WLibrary::registerView(QString name, QWidget* view) { diff --git a/src/widget/wlibrary.h b/src/widget/wlibrary.h index 50ca8e44a43..c0f83639e85 100644 --- a/src/widget/wlibrary.h +++ b/src/widget/wlibrary.h @@ -23,7 +23,6 @@ class WLibrary : public QStackedWidget, public WBaseWidget { explicit WLibrary(QWidget* parent); void setup(const QDomNode& node, const SkinContext& context); - QMap icons; // registerView is used to add a view to the LibraryWidget which the widget // can display on request via showView(). To switch to a given view, call @@ -35,6 +34,10 @@ class WLibrary : public QStackedWidget, public WBaseWidget { LibraryView* getActiveView() const; + const QMap icons() const { + return m_icons; + } + public slots: // Show the view registered with the given name. Does nothing if the current // view is the specified view, or if the name does not specify any @@ -49,6 +52,7 @@ class WLibrary : public QStackedWidget, public WBaseWidget { private: QMutex m_mutex; QMap m_viewMap; + QMap m_icons; }; #endif /* WLIBRARY_H */ From d15eee1c8fb895849ddaa22ec4f906cbfb8c7b40 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 19 Sep 2019 13:02:33 -0500 Subject: [PATCH 124/198] use more accurate local variable name --- src/library/autodj/autodjprocessor.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 1aff9e917d0..2e63794ae7e 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -264,12 +264,12 @@ void AutoDJProcessor::fadeNow() { double timeUntilOutroEnd = outroEnd - fromDeckCurrentPosition; if (toDeckCurrentPosition <= introEnd && introEnd >= 0) { - double introLength = introEnd - toDeckCurrentPosition; + double timeUntilIntroEnd = introEnd - toDeckCurrentPosition; if (outroEnd >= 0) { // The fade must end by the outro end at the latest. - fadeTime = math_min(introLength, timeUntilOutroEnd); + fadeTime = math_min(timeUntilIntroEnd, timeUntilOutroEnd); } else { - fadeTime = introLength; + fadeTime = timeUntilIntroEnd; } } else { fadeTime = math_min(spinboxTime, timeUntilOutroEnd); @@ -1012,6 +1012,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = kKeepPosition; // Disable AutoDJ. toggleAutoDJ(false); + return; } // Within this function, the outro refers to the outro of the currently From cdb8148b13ad39d1342832b1ac796dead9cbabc3 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 19 Sep 2019 16:56:25 -0500 Subject: [PATCH 125/198] AutoDJ: don't skip to next track when pausing during a transition --- src/library/autodj/autodjprocessor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2e63794ae7e..6bc840ac15c 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -597,7 +597,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // switch to IDLE mode and load the next track into the other deck. if (m_eState == ADJ_LEFT_FADING || m_eState == ADJ_RIGHT_FADING) { // Once P1 or P2 has stopped switch out of fading mode to idle. - if (!otherDeckPlaying) { + // If the user stops the toDeck during a fade, let the fade continue + // and do not load the next track. + if (!otherDeckPlaying && otherDeck.isFromDeck) { // Force crossfader all the way to the (non fading) toDeck. if (m_eState == ADJ_RIGHT_FADING) { setCrossfader(-1.0); From 0fd21f99e599085f85d80f6428c6136aff7c0e03 Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 19 Sep 2019 17:13:57 -0500 Subject: [PATCH 126/198] AutoDJ: use spinbox time for Fade Now if before intro start --- src/library/autodj/autodjprocessor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 6bc840ac15c..adc467d4e46 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -261,9 +261,11 @@ void AutoDJProcessor::fadeNow() { // spinbox time. double outroEnd = getOutroEndPosition(pFromDeck); double introEnd = getIntroEndPosition(pToDeck); + double introStart = getIntroStartPosition(pToDeck); double timeUntilOutroEnd = outroEnd - fromDeckCurrentPosition; - if (toDeckCurrentPosition <= introEnd && introEnd >= 0) { + if (toDeckCurrentPosition >= introStart && introStart >= 0 + && toDeckCurrentPosition <= introEnd && introEnd >= 0) { double timeUntilIntroEnd = introEnd - toDeckCurrentPosition; if (outroEnd >= 0) { // The fade must end by the outro end at the latest. From f13bb5df5e7c6fac2c76901675b014f141c781ee Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 26 Sep 2019 09:51:30 -0500 Subject: [PATCH 127/198] AutoDJ: skip track if its duration is <= 0 --- src/library/autodj/autodjprocessor.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index adc467d4e46..b7a469e5331 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1010,12 +1010,10 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = kKeepPosition; return; } - VERIFY_OR_DEBUG_ASSERT(toTrackDuration > 0) { + if (toTrackDuration <= 0) { // Playing Track has no duration. This should not happen, because short // tracks are skipped after load. - pToDeck->startPos = kKeepPosition; - // Disable AutoDJ. - toggleAutoDJ(false); + loadNextTrackFromQueue(*pToDeck, false); return; } From d5b11cfc547ee24f0a7836ca3bed26fbd0a2f686 Mon Sep 17 00:00:00 2001 From: Be Date: Sat, 5 Oct 2019 18:46:18 -0500 Subject: [PATCH 128/198] AutoDJProcessor: improve debug message in calculateTransition --- src/library/autodj/autodjprocessor.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b7a469e5331..2917c41d581 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -987,10 +987,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, return; } - if (sDebug) { - qDebug() << this << "calculateFadeThresholds" << pFromDeck->group; - } - //qDebug() << "player" << pAttributes->group << "PlayChanged(" << playing << ")"; // We require ADJ_IDLE to prevent changing the thresholds in the middle of a @@ -1157,7 +1153,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, DEBUG_ASSERT(pFromDeck->fadeBeginPos <= 1); if (sDebug) { - qDebug() << this << pFromDeck->fadeBeginPos << pFromDeck->fadeEndPos + qDebug() << this << "calculateTransition" << pFromDeck->group + << pFromDeck->fadeBeginPos << pFromDeck->fadeEndPos << pToDeck->startPos; } } From 27c0b6d38414e172d09d0f4ec6cdc19d2b9dd87a Mon Sep 17 00:00:00 2001 From: Be Date: Sun, 6 Oct 2019 07:21:28 -0500 Subject: [PATCH 129/198] AutoDJProcessor: fix Full Track mode with transtion time 0 --- src/library/autodj/autodjprocessor.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2917c41d581..8a7e0d91649 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -622,11 +622,14 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } if (m_eState == ADJ_IDLE) { - if (!thisDeckPlaying) { + if (!thisDeckPlaying && thisPlayPosition < 1) { // this is a cueing seek, recalculate the transition, from the // new position. // This can be our own seek to startPos or a random seek by a user. // we need to call calculateTransition() because we are not sure. + // If using the full track mode with a transition time of 0, + // thisDeckPlaying will be false but the transition should not be + // recalculated here. calculateTransition(&otherDeck, &thisDeck, false); } else if (thisDeck.isRepeat()) { // repeat pauses auto DJ @@ -683,6 +686,16 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (thisDeck.fadeBeginPos == thisDeck.fadeEndPos) { setCrossfader(crossfaderTarget); m_transitionProgress = 1.0; + // Usually code above will take care of these steps when the + // playposition updates again, however this does not occur when + // using the Full Track mode with a fade time of 0 because the + // toDeck stops. + if (thisPlayPosition >= 1) { + otherDeck.play(); + loadNextTrackFromQueue(thisDeck); + m_eState = ADJ_IDLE; + emitAutoDJStateChanged(m_eState); + } return; } From d6353295216e28d3d09b793ac62f9c3ffd65d816 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 12:12:00 -0500 Subject: [PATCH 130/198] AutoDJProcessor: remove superfluous if condition --- src/library/autodj/autodjprocessor.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 8a7e0d91649..c9b75cf72e8 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -267,12 +267,8 @@ void AutoDJProcessor::fadeNow() { if (toDeckCurrentPosition >= introStart && introStart >= 0 && toDeckCurrentPosition <= introEnd && introEnd >= 0) { double timeUntilIntroEnd = introEnd - toDeckCurrentPosition; - if (outroEnd >= 0) { - // The fade must end by the outro end at the latest. - fadeTime = math_min(timeUntilIntroEnd, timeUntilOutroEnd); - } else { - fadeTime = timeUntilIntroEnd; - } + // The fade must end by the outro end at the latest. + fadeTime = math_min(timeUntilIntroEnd, timeUntilOutroEnd); } else { fadeTime = math_min(spinboxTime, timeUntilOutroEnd); } From 36e31e5d90cb1dad006c73ba98f68a3327ac1376 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 12:20:31 -0500 Subject: [PATCH 131/198] CueControl: move local variable declaration closer to usage --- src/engine/controls/cuecontrol.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 70d73132b8a..43e606e5168 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -386,7 +386,6 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } } - double introStart = m_pIntroStartPosition->get(); switch (seekOnLoadMode) { case SeekOnLoadMode::Beginning: @@ -411,12 +410,15 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::IntroStart: - if (introStart != kNoTrigger) { - seekExact(introStart); - } else { - seekExact(0.0); + { + double introStart = m_pIntroStartPosition->get(); + if (introStart != kNoTrigger) { + seekExact(introStart); + } else { + seekExact(0.0); + } + break; } - break; default: seekExact(0.0); break; From d284d5ef4c79d5b9e6832690a351b6cd02171c07 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 12:21:27 -0500 Subject: [PATCH 132/198] use ControlProxy::toBool --- src/library/autodj/autodjprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index c9b75cf72e8..6b2d261030b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -190,7 +190,7 @@ double AutoDJProcessor::getCrossfader() const { } void AutoDJProcessor::setCrossfader(double value) { - if (m_pCOCrossfaderReverse->get() > 0.0) { + if (m_pCOCrossfaderReverse->toBool()) { value *= -1.0; } m_pCOCrossfader->set(value); From 200396600c6394afeea77236f284e9aa186b2b63 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 12:34:02 -0500 Subject: [PATCH 133/198] use parented_ptr for ControlProxy --- src/mixer/playermanager.cpp | 2 +- src/mixer/playermanager.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index b03728d0f16..b71ddc7ada2 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -66,7 +66,7 @@ PlayerManager::PlayerManager(UserSettingsPointer pConfig, m_pCONumAuxiliaries(new ControlObject( ConfigKey("[Master]", "num_auxiliaries"), true, true)), m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), - m_pAutoDjEnabled(std::make_unique("[AutoDJ]", "enabled", this)) { + m_pAutoDjEnabled(make_parented("[AutoDJ]", "enabled", this)) { m_pCONumDecks->connectValueChangeRequest(this, &PlayerManager::slotChangeNumDecks, Qt::DirectConnection); m_pCONumSamplers->connectValueChangeRequest(this, diff --git a/src/mixer/playermanager.h b/src/mixer/playermanager.h index 191e73e4e96..82981671848 100644 --- a/src/mixer/playermanager.h +++ b/src/mixer/playermanager.h @@ -12,6 +12,7 @@ #include "analyzer/trackanalysisscheduler.h" #include "preferences/usersettings.h" #include "track/track.h" +#include "util/parented_ptr.h" #include "util/performancetimer.h" class Auxiliary; @@ -265,7 +266,7 @@ class PlayerManager : public QObject, public PlayerManagerInterface { ControlObject* m_pCONumPreviewDecks; ControlObject* m_pCONumMicrophones; ControlObject* m_pCONumAuxiliaries; - std::unique_ptr m_pAutoDjEnabled; + parented_ptr m_pAutoDjEnabled; TrackAnalysisScheduler::Pointer m_pTrackAnalysisScheduler; From 3d7320b6958f90b32136844241b2ac87b058dafb Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 12:34:59 -0500 Subject: [PATCH 134/198] PlayerManager: fix initialization order --- src/mixer/playermanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mixer/playermanager.cpp b/src/mixer/playermanager.cpp index b71ddc7ada2..5240f71210d 100644 --- a/src/mixer/playermanager.cpp +++ b/src/mixer/playermanager.cpp @@ -65,8 +65,8 @@ PlayerManager::PlayerManager(UserSettingsPointer pConfig, ConfigKey("[Master]", "num_microphones"), true, true)), m_pCONumAuxiliaries(new ControlObject( ConfigKey("[Master]", "num_auxiliaries"), true, true)), - m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()), - m_pAutoDjEnabled(make_parented("[AutoDJ]", "enabled", this)) { + m_pAutoDjEnabled(make_parented("[AutoDJ]", "enabled", this)), + m_pTrackAnalysisScheduler(TrackAnalysisScheduler::NullPointer()) { m_pCONumDecks->connectValueChangeRequest(this, &PlayerManager::slotChangeNumDecks, Qt::DirectConnection); m_pCONumSamplers->connectValueChangeRequest(this, From f576021589625ad57477225f76b14c3c853f5e21 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 13:20:11 -0500 Subject: [PATCH 135/198] CueControl: move setting intro start with main cue to loadCuesFromTrack --- src/engine/controls/cuecontrol.cpp | 51 ++++++++++++++---------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 43e606e5168..8ee76e7ab60 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -333,11 +333,11 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { this, &CueControl::trackBeatsUpdated, Qt::DirectConnection); - CuePointer pLoadCue; + CuePointer pMainCue; for (const CuePointer& pCue: m_pLoadedTrack->getCuePoints()) { if (pCue->getType() == Cue::Type::MainCue) { - DEBUG_ASSERT(!pLoadCue); - pLoadCue = pCue; + DEBUG_ASSERT(!pMainCue); + pMainCue = pCue; } } @@ -350,22 +350,22 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { // Because of legacy, we store the (load) cue point twice and need to // sync both values. // The Cue::Type::MainCue from getCuePoints() has the priority - CuePosition cuePoint; - if (pLoadCue) { - cuePoint.setPosition(pLoadCue->getPosition()); + CuePosition mainCuePoint; + if (pMainCue) { + mainCuePoint.setPosition(pMainCue->getPosition()); // adjust the track cue accordingly - pNewTrack->setCuePoint(cuePoint); + pNewTrack->setCuePoint(mainCuePoint); } else { // If no load cue point is stored, read from track // Note: This is 0:00 for new tracks - cuePoint = pNewTrack->getCuePoint(); + mainCuePoint = pNewTrack->getCuePoint(); // Than add the load cue to the list of cue CuePointer pCue(pNewTrack->createAndAddCue()); - pCue->setPosition(cuePoint.getPosition()); + pCue->setPosition(mainCuePoint.getPosition()); pCue->setHotCue(-1); pCue->setType(Cue::Type::MainCue); } - m_pCuePoint->set(cuePoint.getPosition()); + m_pCuePoint->set(mainCuePoint.getPosition()); // Update COs with cues from track. loadCuesFromTrack(); @@ -379,14 +379,6 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { firstSound = pAudibleSound->getPosition(); } - double mainCue = m_pCuePoint->get(); - if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), false)) { - if (mainCue != kNoTrigger && mainCue != 0) { - m_pIntroStartPosition->set(mainCue); - } - } - - switch (seekOnLoadMode) { case SeekOnLoadMode::Beginning: // This allows users to load tracks and have the needle-drop be maintained. @@ -403,8 +395,8 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::MainCue: - if (mainCue != kNoTrigger) { - seekExact(mainCue); + if (mainCuePoint.getPosition() != kNoTrigger) { + seekExact(mainCuePoint.getPosition()); } else { seekExact(0.0); } @@ -473,13 +465,6 @@ void CueControl::loadCuesFromTrack() { } } - if (pLoadCue) { - double position = pLoadCue->getPosition(); - m_pCuePoint->set(quantizeCuePoint(position, QuantizeMode::ClosestBeat)); - } else { - m_pCuePoint->set(-1.0); - } - if (pIntroCue) { double startPosition = pIntroCue->getPosition(); double endPosition = pIntroCue->getEndPosition(); @@ -510,6 +495,18 @@ void CueControl::loadCuesFromTrack() { m_pOutroEndEnabled->forceSet(0.0); } + if (pLoadCue) { + double position = pLoadCue->getPosition(); + m_pCuePoint->set(quantizeCuePoint(position, QuantizeMode::ClosestBeat)); + // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. + if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), false) + && position != kNoTrigger && position != 0) { + m_pIntroStartPosition->set(position); + } + } else { + m_pCuePoint->set(-1.0); + } + // Detach all hotcues that are no longer present for (int hotCue = 0; hotCue < m_iNumHotCues; ++hotCue) { if (!active_hotcues.contains(hotCue)) { From 6a4ea7cc6a2da665d12bdd8c4d5cb1f8c94859a1 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 13:27:15 -0500 Subject: [PATCH 136/198] DlgAutoDJ: add header to fade mode tooltip --- src/library/autodj/dlgautodj.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index af06944836a..4b5fd02ef68 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -99,6 +99,8 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), this, &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( + "AutoDJ Fade Modes\n" + "\n" "Full Intro + Outro:\n" "Play the full intro and outro. Use the intro or outro length as the\n" "crossfade time, whichever is shorter. If no intro or outro are marked,\n" From 11ce9392e90c196e6daa83647b247d58ba73276f Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 14 Oct 2019 13:58:37 -0500 Subject: [PATCH 137/198] AutoDJProcessor: correct comment --- src/library/autodj/autodjprocessor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 6b2d261030b..e2f614dde07 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -230,8 +230,7 @@ void AutoDJProcessor::fadeNow() { pFromDeck = pRightDeck; pToDeck = pLeftDeck; } else { - // Both decks are playing or no decks are playing; - // fading now makes no sense. + // Neither deck is playing. Fading now makes no sense. return; } From f97d31ee6b56e208c026dce22a17da1d8b7c163e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 16 Oct 2019 22:42:57 +0200 Subject: [PATCH 138/198] Fix stalled auto DJ when track is seeked to the very end and the user forgets about it. We now seek to the calucalted cue position, as we do when the "to" track has been played until the end. --- src/library/autodj/autodjprocessor.cpp | 54 ++++++++++++++++++++------ 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index e2f614dde07..23cd94118d4 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -617,7 +617,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } if (m_eState == ADJ_IDLE) { - if (!thisDeckPlaying && thisPlayPosition < 1) { + if (!thisDeckPlaying) { // this is a cueing seek, recalculate the transition, from the // new position. // This can be our own seek to startPos or a random seek by a user. @@ -640,6 +640,10 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { if (!otherDeckPlaying) { + // Re-cue the track if the user has seeked it to the very end + if (otherDeck.playPosition() >= 1.0) { + otherDeck.setPlayPosition(otherDeck.startPos); + } otherDeck.play(); } @@ -834,10 +838,10 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) // example to adjust the intro/outro cues, and lets the deck play until the // end, seek back to the start point instead of keeping the deck stopped at // the end. - if (!playing && thisDeck->playPosition() == 1.0 && !thisDeck->isFromDeck) { - if (thisDeck->startPos == kKeepPosition) { - calculateTransition(getOtherDeck(thisDeck), thisDeck, true); - } + if (!playing && thisDeck->playPosition() >= 1.0 && !thisDeck->isFromDeck) { + // Deck has stopped at the end. Recalculate the transition, because + // it has been done from a now irrelevant previous position. + calculateTransition(getOtherDeck(thisDeck), thisDeck, true); thisDeck->setPlayPosition(thisDeck->startPos); } } @@ -995,7 +999,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, return; } - //qDebug() << "player" << pAttributes->group << "PlayChanged(" << playing << ")"; + qDebug() << "player" << pFromDeck->group << "calculateTransition()"; // We require ADJ_IDLE to prevent changing the thresholds in the middle of a // fade. @@ -1036,7 +1040,10 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroLength = outroEnd - outroStart; double introStart; - if (seekToStartPoint) { + if (seekToStartPoint || pToDeck->playPosition() >= 1) { + // pToDeck->playPosition() >= 1 happens when the user has seeked + // or played the track to the very end and forgets about it. + // In this case we recue the track just before the transition. introStart = getIntroStartPosition(pToDeck); } else { introStart = pToDeck->playPosition() * toTrackDuration; @@ -1141,13 +1148,37 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } break; case TransitionMode::FixedSkipSilence: - useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), - getFirstSoundPosition(pToDeck)); + { + double startPoint; + if (seekToStartPoint || pToDeck->playPosition() >= 1) { + // pToDeck->playPosition() >= 1 happens when the user has seeked + // or played the track to the very end and forgets about it. + // In this case we recue the track just before the transition. + startPoint = getFirstSoundPosition(pToDeck); + } else { + startPoint = pToDeck->playPosition() * toTrackDuration; + } + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), + startPoint); + } break; case TransitionMode::FixedFullTrack: default: - useFixedFadeTime(pFromDeck, pToDeck, fromTrackDuration, 0); + { + double startPoint; + if (seekToStartPoint || pToDeck->playPosition() >= 1) { + // pToDeck->playPosition() >= 0 happens when the user has seeked + // or played the track to the very end and forgets about it. + // In this case we recue the track just before the transition. + startPoint = 0; + } else { + startPoint = pToDeck->playPosition() * toTrackDuration; + } + useFixedFadeTime(pFromDeck, pToDeck, + getLastSoundPosition(pFromDeck), + startPoint); + } } // These are expected to be a fraction of the track length. @@ -1180,6 +1211,7 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, end = pToDeck->duration(); VERIFY_OR_DEBUG_ASSERT(end > startPoint) { // as last resort move start point + // The caller makes sures that this never happens startPoint = pToDeck->duration() - 1; } } From a44daca5accea35fc5df8bccdd1eb2f169024463 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 21 Oct 2019 01:07:21 -0500 Subject: [PATCH 139/198] move setting of intro start to main cue point to AnalyzerSilence and remove the option to keep moving the intro start point whenever the main cue is moved. --- src/analyzer/analyzersilence.cpp | 31 ++++++++++++------------ src/engine/controls/cuecontrol.cpp | 9 ------- src/preferences/dialog/dlgprefdeck.cpp | 18 ++++++++------ src/preferences/dialog/dlgprefdeck.h | 2 +- src/preferences/dialog/dlgprefdeckdlg.ui | 2 +- 5 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 9ff9ac40ff5..257df09bed3 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -11,11 +11,6 @@ constexpr float kSilenceThreshold = 0.001; const double kCueNotSet = -1.0; -bool shouldUpdateMainCue(CuePosition mainCue) { - return mainCue.getPosition() == kCueNotSet || - mainCue.getPosition() == 0.0; -} - bool hasIntroCueStart(const Cue& introCue) { return introCue.getPosition() != kCueNotSet; } @@ -107,11 +102,25 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { double introStart = mixxx::kAnalysisChannels * m_iSignalStart; double outroEnd = mixxx::kAnalysisChannels * m_iSignalEnd; - if (shouldUpdateMainCue(pTrack->getCuePoint())) { - pTrack->setCuePoint(CuePosition(introStart)); + CuePointer pAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); + if (pAudibleSound == nullptr || pAudibleSound->getLength() <= 0) { + pAudibleSound = pTrack->createAndAddCue(); + pAudibleSound->setType(Cue::Type::AudibleSound); + pAudibleSound->setPosition(introStart); + pAudibleSound->setLength(outroEnd - introStart); } CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); + + double oldMainCue = pTrack->getCuePoint().getPosition(); + // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. + if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) + && pIntroCue == nullptr && oldMainCue != kCueNotSet && oldMainCue != 0.0) { + introStart = oldMainCue; + } else if (oldMainCue == kCueNotSet) { + pTrack->setCuePoint(CuePosition(introStart)); + } + if (!pIntroCue) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); @@ -126,12 +135,4 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pOutroCue->setPosition(kCueNotSet); pOutroCue->setLength(outroEnd); } - - CuePointer pAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); - if (pAudibleSound == nullptr || pAudibleSound->getLength() <= 0) { - pAudibleSound = pTrack->createAndAddCue(); - pAudibleSound->setType(Cue::Type::AudibleSound); - pAudibleSound->setPosition(introStart); - pAudibleSound->setLength(outroEnd - introStart); - } } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 8ee76e7ab60..d809813a916 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -498,11 +498,6 @@ void CueControl::loadCuesFromTrack() { if (pLoadCue) { double position = pLoadCue->getPosition(); m_pCuePoint->set(quantizeCuePoint(position, QuantizeMode::ClosestBeat)); - // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. - if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), false) - && position != kNoTrigger && position != 0) { - m_pIntroStartPosition->set(position); - } } else { m_pCuePoint->set(-1.0); } @@ -840,10 +835,6 @@ void CueControl::cueSet(double v) { if (pLoadedTrack) { pLoadedTrack->setCuePoint(CuePosition(cue)); } - - if (m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), false)) { - introStartSet(cue); - } } void CueControl::cueClear(double v) { diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index f617b60d932..a94afe56420 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -180,12 +180,13 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, // the deck is not at the main cue point and play is pressed). bool introStartMoveDefault = (m_seekOnLoadMode == SeekOnLoadMode::MainCue || !seekModeExisted) && !(m_cueMode == CueMode::Denon || m_cueMode == CueMode::Numark); - m_bMoveIntroStartWithMainCue = m_pConfig->getValue(ConfigKey("[Controls]", "MoveIntroStartWithMainCue"), + m_bSetIntroStartAtMainCue = m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), introStartMoveDefault); - // This is an ugly hack to ensure CueControl does not override the default value - // when it first accesses the ConfigKey and mixxx.cfg is empty. - m_pConfig->setValue(ConfigKey("[Controls]", "MoveIntroStart"), m_bMoveIntroStartWithMainCue); - checkBoxIntroStartMove->setChecked(m_bMoveIntroStartWithMainCue); + // This is an ugly hack to ensure AnalyzerSilence gets the correct default + // value because ConfigValue::getValue does not set the value of the ConfigValue + // in case no value had been set previously (when mixxx.cfg is empty). + m_pConfig->setValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), m_bSetIntroStartAtMainCue); + checkBoxIntroStartMove->setChecked(m_bSetIntroStartAtMainCue); connect(checkBoxIntroStartMove, &QCheckBox::toggled, this, &DlgPrefDeck::slotMoveIntroStartCheckbox); @@ -364,7 +365,7 @@ DlgPrefDeck::~DlgPrefDeck() { void DlgPrefDeck::slotUpdate() { checkBoxIntroStartMove->setChecked(m_pConfig->getValue( - ConfigKey("[Controls]", "MoveIntroStart"), false)); + ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false)); slotSetTrackTimeDisplay(m_pControlTrackTimeDisplay->get()); @@ -475,7 +476,7 @@ void DlgPrefDeck::slotResetToDefaults() { } void DlgPrefDeck::slotMoveIntroStartCheckbox(bool checked) { - m_bMoveIntroStartWithMainCue = checked; + m_bSetIntroStartAtMainCue = checked; } void DlgPrefDeck::slotRateRangeComboBox(int index) { @@ -606,7 +607,8 @@ void DlgPrefDeck::slotSetTrackLoadMode(int comboboxIndex) { } void DlgPrefDeck::slotApply() { - m_pConfig->set(ConfigKey("[Controls]", "MoveIntroStart"), ConfigValue(m_bMoveIntroStartWithMainCue)); + m_pConfig->set(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), + ConfigValue(m_bSetIntroStartAtMainCue)); double timeDisplay = static_cast(m_timeDisplayMode); m_pConfig->set(ConfigKey("[Controls]","PositionDisplay"), ConfigValue(timeDisplay)); diff --git a/src/preferences/dialog/dlgprefdeck.h b/src/preferences/dialog/dlgprefdeck.h index 408315cf925..7cb5d5b3885 100644 --- a/src/preferences/dialog/dlgprefdeck.h +++ b/src/preferences/dialog/dlgprefdeck.h @@ -123,7 +123,7 @@ class DlgPrefDeck : public DlgPreferencePage, public Ui::DlgPrefDeckDlg { CueMode m_cueMode; - bool m_bMoveIntroStartWithMainCue; + bool m_bSetIntroStartAtMainCue; bool m_bDisallowTrackLoadToPlayingDeck; bool m_bCloneDeckOnLoadDoubleTap; bool m_bAssignHotcueColors; diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index 3e560cf4076..de562948bf3 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -77,7 +77,7 @@ CUP mode: Automatically moves the intro start cue when the main cue moves. - Move intro start with main cue + Set intro start to main cue for newly analyzed tracks From 8d23116e1dce382c7b82d374b4af41053000309a Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 21 Oct 2019 10:30:41 -0500 Subject: [PATCH 140/198] AnalyzerSilence: don't run if user has unset intro start or outro end --- src/analyzer/analyzersilence.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 257df09bed3..f94b8e05633 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -11,14 +11,6 @@ constexpr float kSilenceThreshold = 0.001; const double kCueNotSet = -1.0; -bool hasIntroCueStart(const Cue& introCue) { - return introCue.getPosition() != kCueNotSet; -} - -bool hasOutroCueEnd(const Cue& outroCue) { - return outroCue.getEndPosition() > 0.0; -} - bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); @@ -27,7 +19,7 @@ bool shouldAnalyze(TrackPointer pTrack) { if (!pIntroCue || !pOutroCue || !pAudibleSound || pAudibleSound->getLength() <= 0) { return true; } - return !hasIntroCueStart(*pIntroCue) || !hasOutroCueEnd(*pOutroCue); + return false; } } // anonymous namespace From ece016160208652bf84313ef4407a7ec994a6eec Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 21 Oct 2019 11:17:01 -0500 Subject: [PATCH 141/198] AnalyzerSilence: only add AudibleSound cue if it does not exist already There should never be multiple AudibleSound cues. The pAudibleSound->getLength() <= 0 condition was only for users who tested earlier versions of PR #2103 before it was merged, when separate FirstSound and LastSound cues were used instead of one AudibleSound range cue. But there is no need to keep that condition for merging into master. --- src/analyzer/analyzersilence.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index f94b8e05633..0259632e3c9 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -95,7 +95,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { double outroEnd = mixxx::kAnalysisChannels * m_iSignalEnd; CuePointer pAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); - if (pAudibleSound == nullptr || pAudibleSound->getLength() <= 0) { + if (pAudibleSound == nullptr) { pAudibleSound = pTrack->createAndAddCue(); pAudibleSound->setType(Cue::Type::AudibleSound); pAudibleSound->setPosition(introStart); From 5ab052d70f761e6854a5ee5dee683c8ee6a0a943 Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 21 Oct 2019 11:20:00 -0500 Subject: [PATCH 142/198] AnalyzerSilence: rename oldMainCue -> mainCue --- src/analyzer/analyzersilence.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 0259632e3c9..ff241d839a9 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -104,12 +104,12 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); - double oldMainCue = pTrack->getCuePoint().getPosition(); + double mainCue = pTrack->getCuePoint().getPosition(); // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) - && pIntroCue == nullptr && oldMainCue != kCueNotSet && oldMainCue != 0.0) { - introStart = oldMainCue; - } else if (oldMainCue == kCueNotSet) { + && pIntroCue == nullptr && mainCue != kCueNotSet && mainCue != 0.0) { + introStart = mainCue; + } else if (mainCue == kCueNotSet) { pTrack->setCuePoint(CuePosition(introStart)); } From 77d25ad9c203045b584bff8e7405283a1ab947cf Mon Sep 17 00:00:00 2001 From: Be Date: Mon, 21 Oct 2019 12:54:20 -0500 Subject: [PATCH 143/198] DlgPrefDeck: improve wording/tooltip for intro start option --- src/preferences/dialog/dlgprefdeckdlg.ui | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/preferences/dialog/dlgprefdeckdlg.ui b/src/preferences/dialog/dlgprefdeckdlg.ui index de562948bf3..ccb35ebf986 100644 --- a/src/preferences/dialog/dlgprefdeckdlg.ui +++ b/src/preferences/dialog/dlgprefdeckdlg.ui @@ -74,10 +74,14 @@ CUP mode: - Automatically moves the intro start cue when the main cue moves. + When the analyzer places the intro start point automatically, +it will place it at the main cue point if the main cue point has been set previously. +This may be helpful for upgrading to Mixxx 2.3 from earlier versions. + +If this option is disabled, the intro start point is automatically placed at the first sound. - Set intro start to main cue for newly analyzed tracks + Set intro start to main cue when analyzing tracks From 0b79250fa6113e175487a4b590ee70781a17124a Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 01:48:46 -0500 Subject: [PATCH 144/198] AnalyzerSilence: better name for local variables --- src/analyzer/analyzersilence.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index ff241d839a9..998d3f10202 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -91,15 +91,15 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { m_iSignalEnd = m_iFramesProcessed; } - double introStart = mixxx::kAnalysisChannels * m_iSignalStart; - double outroEnd = mixxx::kAnalysisChannels * m_iSignalEnd; + double firstSound = mixxx::kAnalysisChannels * m_iSignalStart; + double lastSound = mixxx::kAnalysisChannels * m_iSignalEnd; CuePointer pAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); if (pAudibleSound == nullptr) { pAudibleSound = pTrack->createAndAddCue(); pAudibleSound->setType(Cue::Type::AudibleSound); - pAudibleSound->setPosition(introStart); - pAudibleSound->setLength(outroEnd - introStart); + pAudibleSound->setPosition(firstSound); + pAudibleSound->setLength(lastSound - firstSound); } CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); @@ -108,15 +108,15 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) && pIntroCue == nullptr && mainCue != kCueNotSet && mainCue != 0.0) { - introStart = mainCue; + firstSound = mainCue; } else if (mainCue == kCueNotSet) { - pTrack->setCuePoint(CuePosition(introStart)); + pTrack->setCuePoint(CuePosition(firstSound)); } if (!pIntroCue) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setPosition(introStart); + pIntroCue->setPosition(firstSound); pIntroCue->setLength(0.0); } @@ -125,6 +125,6 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); pOutroCue->setPosition(kCueNotSet); - pOutroCue->setLength(outroEnd); + pOutroCue->setLength(lastSound); } } From b2d35ef210d77003fa3ea01846dfcc2cfba70242 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 01:58:30 -0500 Subject: [PATCH 145/198] AnalyzerSilence: simplify conditional logic --- src/analyzer/analyzersilence.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 998d3f10202..e3906e7c2d3 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -105,12 +105,12 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); double mainCue = pTrack->getCuePoint().getPosition(); + if (mainCue == kCueNotSet) { + pTrack->setCuePoint(CuePosition(firstSound)); // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. - if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) - && pIntroCue == nullptr && mainCue != kCueNotSet && mainCue != 0.0) { + } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) + && pIntroCue == nullptr && mainCue != 0.0) { firstSound = mainCue; - } else if (mainCue == kCueNotSet) { - pTrack->setCuePoint(CuePosition(firstSound)); } if (!pIntroCue) { From 187024ffcdac5a15a7d6dad051b27193f6118866 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 02:04:15 -0500 Subject: [PATCH 146/198] AnalyzerSilence: improve local variable naming again --- src/analyzer/analyzersilence.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index e3906e7c2d3..7108de3900f 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -105,18 +105,19 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); double mainCue = pTrack->getCuePoint().getPosition(); + double introStart = firstSound; if (mainCue == kCueNotSet) { pTrack->setCuePoint(CuePosition(firstSound)); // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) && pIntroCue == nullptr && mainCue != 0.0) { - firstSound = mainCue; + introStart = mainCue; } if (!pIntroCue) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setPosition(firstSound); + pIntroCue->setPosition(introStart); pIntroCue->setLength(0.0); } From b2d8bdd3db0f316505ed2eca215573b29a9cf5f9 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 02:33:38 -0500 Subject: [PATCH 147/198] AnalyzerSilence: reimplement moving default cue point to first sound when upgrading --- src/analyzer/analyzersilence.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 7108de3900f..3947e8b5425 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -106,11 +106,17 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { double mainCue = pTrack->getCuePoint().getPosition(); double introStart = firstSound; - if (mainCue == kCueNotSet) { + // Before Mixxx 2.3, the default position for the main cue was 0.0. In this + // case, move the main cue point to the first sound. This case can be + // distinguished from a user intentionally setting the main cue position + // to 0.0 at a later time after analysis because in that case the intro cue + // would have already been created by this analyzer. + bool upgradingWithMainCueAtDefault = (mainCue == 0.0 && pIntroCue == nullptr); + if (mainCue == kCueNotSet || upgradingWithMainCueAtDefault) { pTrack->setCuePoint(CuePosition(firstSound)); // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) - && pIntroCue == nullptr && mainCue != 0.0) { + && pIntroCue == nullptr) { introStart = mainCue; } From 0a2fda2fc2841dadb4a9624930cafbabb0cacc4d Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 03:13:58 -0500 Subject: [PATCH 148/198] Cue: rename setPosition to setStartPosition --- src/analyzer/analyzersilence.cpp | 6 +++--- src/engine/controls/cuecontrol.cpp | 26 +++++++++++++------------- src/mixer/basetrackplayer.cpp | 2 +- src/test/analyzersilence_test.cpp | 4 ++-- src/test/cuecontrol_test.cpp | 26 +++++++++++++------------- src/track/cue.cpp | 2 +- src/track/cue.h | 2 +- src/track/track.cpp | 2 +- 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 3947e8b5425..0f8850786ab 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -98,7 +98,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { if (pAudibleSound == nullptr) { pAudibleSound = pTrack->createAndAddCue(); pAudibleSound->setType(Cue::Type::AudibleSound); - pAudibleSound->setPosition(firstSound); + pAudibleSound->setStartPosition(firstSound); pAudibleSound->setLength(lastSound - firstSound); } @@ -123,7 +123,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { if (!pIntroCue) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setPosition(introStart); + pIntroCue->setStartPosition(introStart); pIntroCue->setLength(0.0); } @@ -131,7 +131,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { if (!pOutroCue) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setPosition(kCueNotSet); + pOutroCue->setStartPosition(kCueNotSet); pOutroCue->setLength(lastSound); } } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index d809813a916..afd7769191e 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -361,7 +361,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { mainCuePoint = pNewTrack->getCuePoint(); // Than add the load cue to the list of cue CuePointer pCue(pNewTrack->createAndAddCue()); - pCue->setPosition(mainCuePoint.getPosition()); + pCue->setStartPosition(mainCuePoint.getPosition()); pCue->setHotCue(-1); pCue->setType(Cue::Type::MainCue); } @@ -577,7 +577,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { double cuePosition = (m_pQuantizeEnabled->toBool() && closestBeat != -1) ? closestBeat : getSampleOfTrack().current; - pCue->setPosition(cuePosition); + pCue->setStartPosition(cuePosition); pCue->setHotCue(hotcue); pCue->setLabel(""); pCue->setType(Cue::Type::HotCue); @@ -788,7 +788,7 @@ void CueControl::hotcuePositionChanged(HotcueControl* pControl, double newPositi if (newPosition == -1) { detachCue(pControl); } else if (newPosition > 0 && newPosition < m_pTrackSamples->get()) { - pCue->setPosition(newPosition); + pCue->setStartPosition(newPosition); } } } @@ -1150,7 +1150,7 @@ void CueControl::introStartSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - pCue->setPosition(position); + pCue->setStartPosition(position); pCue->setLength(introEnd != -1.0 ? introEnd - position : 0.0); } } @@ -1168,7 +1168,7 @@ void CueControl::introStartClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (introEnd != -1.0) { - pCue->setPosition(-1.0); + pCue->setStartPosition(-1.0); pCue->setLength(introEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); @@ -1229,10 +1229,10 @@ void CueControl::introEndSet(double v) { pCue->setType(Cue::Type::Intro); } if (introStart != -1.0) { - pCue->setPosition(introStart); + pCue->setStartPosition(introStart); pCue->setLength(position - introStart); } else { - pCue->setPosition(-1.0); + pCue->setStartPosition(-1.0); pCue->setLength(position); } } @@ -1251,7 +1251,7 @@ void CueControl::introEndClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (introStart != -1.0) { - pCue->setPosition(introStart); + pCue->setStartPosition(introStart); pCue->setLength(0.0); } else if (pCue) { pLoadedTrack->removeCue(pCue); @@ -1311,7 +1311,7 @@ void CueControl::outroStartSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - pCue->setPosition(position); + pCue->setStartPosition(position); pCue->setLength(outroEnd != -1.0 ? outroEnd - position : 0.0); } } @@ -1329,7 +1329,7 @@ void CueControl::outroStartClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (outroEnd != -1.0) { - pCue->setPosition(-1.0); + pCue->setStartPosition(-1.0); pCue->setLength(outroEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); @@ -1390,10 +1390,10 @@ void CueControl::outroEndSet(double v) { pCue->setType(Cue::Type::Outro); } if (outroStart != -1.0) { - pCue->setPosition(outroStart); + pCue->setStartPosition(outroStart); pCue->setLength(position - outroStart); } else { - pCue->setPosition(-1.0); + pCue->setStartPosition(-1.0); pCue->setLength(position); } } @@ -1412,7 +1412,7 @@ void CueControl::outroEndClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (outroStart != -1.0) { - pCue->setPosition(outroStart); + pCue->setStartPosition(outroStart); pCue->setLength(0.0); } else if (pCue) { pLoadedTrack->removeCue(pCue); diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index bb946899f89..8e55acd58be 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -228,7 +228,7 @@ TrackPointer BaseTrackPlayerImpl::unloadTrack() { pLoopCue = m_pLoadedTrack->createAndAddCue(); pLoopCue->setType(Cue::Type::Loop); } - pLoopCue->setPosition(loopStart); + pLoopCue->setStartPosition(loopStart); pLoopCue->setLength(loopEnd - loopStart); } diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 265c57fad80..1c877e4e72b 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -168,12 +168,12 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { CuePointer pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); - pIntroCue->setPosition(kManualIntroPosition); + pIntroCue->setStartPosition(kManualIntroPosition); pIntroCue->setLength(0.0); CuePointer pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setPosition(-1.0); + pOutroCue->setStartPosition(-1.0); pOutroCue->setLength(kManualOutroPosition); // Fill the first half with silence diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index c3e8bb882b4..50ee9e753fe 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -78,11 +78,11 @@ TEST_F(CueControlTest, LoadUnloadTrack) { pTrack->setCuePoint(CuePosition(100.0)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setPosition(150.0); + pIntro->setStartPosition(150.0); pIntro->setLength(50.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setPosition(250.0); + pOutro->setStartPosition(250.0); pOutro->setLength(50.0); loadTrack(pTrack); @@ -115,11 +115,11 @@ TEST_F(CueControlTest, LoadTrackWithDetectedCues) { pTrack->setCuePoint(CuePosition(100.0)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setPosition(100.0); + pIntro->setStartPosition(100.0); pIntro->setLength(0.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setPosition(-1.0); + pOutro->setStartPosition(-1.0); pOutro->setLength(200.0); loadTrack(pTrack); @@ -139,11 +139,11 @@ TEST_F(CueControlTest, LoadTrackWithIntroEndAndOutroStart) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setPosition(-1.0); + pIntro->setStartPosition(-1.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setPosition(250.0); + pOutro->setStartPosition(250.0); pOutro->setLength(0.0); loadTrack(pTrack); @@ -175,12 +175,12 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabled) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setPosition(2.1 * beatLength); + pIntro->setStartPosition(2.1 * beatLength); pIntro->setLength(1.2 * beatLength); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setPosition(11.1 * beatLength); + pOutro->setStartPosition(11.1 * beatLength); pOutro->setLength(4.4 * beatLength); loadTrack(pTrack); @@ -203,12 +203,12 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabledNoBeats) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setPosition(250.0); + pIntro->setStartPosition(250.0); pIntro->setLength(150.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setPosition(550.0); + pOutro->setStartPosition(550.0); pOutro->setLength(250.0); loadTrack(pTrack); @@ -231,12 +231,12 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setPosition(210.0); + pIntro->setStartPosition(210.0); pIntro->setLength(120.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setPosition(770.0); + pOutro->setStartPosition(770.0); pOutro->setLength(220.0); loadTrack(pTrack); @@ -253,7 +253,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setPosition(250.0); + pIntro->setStartPosition(250.0); pIntro->setLength(150.0); loadTrack(pTrack); diff --git a/src/track/cue.cpp b/src/track/cue.cpp index dec0d8f1c4c..85ddeb144ba 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -90,7 +90,7 @@ double Cue::getPosition() const { return m_samplePosition; } -void Cue::setPosition(double samplePosition) { +void Cue::setStartPosition(double samplePosition) { QMutexLocker lock(&m_mutex); m_samplePosition = samplePosition; m_bDirty = true; diff --git a/src/track/cue.h b/src/track/cue.h index 2fa33aaa6b7..83f00f96782 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -40,7 +40,7 @@ class Cue : public QObject { void setType(Cue::Type type); double getPosition() const; - void setPosition(double samplePosition); + void setStartPosition(double samplePosition); double getLength() const; void setLength(double length); diff --git a/src/track/track.cpp b/src/track/track.cpp index ae3026cb408..06e2e06dd19 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -665,7 +665,7 @@ void Track::setCuePoint(CuePosition cue) { &Track::slotCueUpdated); m_cuePoints.push_back(pLoadCue); } - pLoadCue->setPosition(position); + pLoadCue->setStartPosition(position); } else if (pLoadCue) { disconnect(pLoadCue.get(), 0, this, 0); m_cuePoints.removeOne(pLoadCue); From 4970f0b76da59574c984400dbe37fd7544c5ce5a Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 03:39:12 -0500 Subject: [PATCH 149/198] Cue: add setEndPosition method It is easier to think about a start and end point than a start point and length. This new method allows hiding the length as an implementation detail of the database format. --- src/track/cue.cpp | 26 ++++++++++++++++++++------ src/track/cue.h | 3 ++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 85ddeb144ba..db49b6756dd 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -24,7 +24,7 @@ Cue::Cue(TrackId trackId) m_iId(-1), m_trackId(trackId), m_type(Cue::Type::Invalid), - m_samplePosition(-1.0), + m_sampleStartPosition(-1.0), m_length(0.0), m_iHotCue(-1), m_label(kDefaultLabel), @@ -38,7 +38,7 @@ Cue::Cue(int id, TrackId trackId, Cue::Type type, double position, double length m_iId(id), m_trackId(trackId), m_type(type), - m_samplePosition(position), + m_sampleStartPosition(position), m_length(length), m_iHotCue(hotCue), m_label(label), @@ -87,12 +87,26 @@ void Cue::setType(Cue::Type type) { double Cue::getPosition() const { QMutexLocker lock(&m_mutex); - return m_samplePosition; + return m_sampleStartPosition; } void Cue::setStartPosition(double samplePosition) { QMutexLocker lock(&m_mutex); - m_samplePosition = samplePosition; + m_sampleStartPosition = samplePosition; + m_bDirty = true; + lock.unlock(); + emit(updated()); +} + +void Cue::setEndPosition(double samplePosition) { + QMutexLocker lock(&m_mutex); + if (samplePosition == -1.0) { + m_length = 0; + } else if (m_sampleStartPosition == -1.0) { + m_length = samplePosition; + } else { + m_length = samplePosition - m_sampleStartPosition; + } m_bDirty = true; lock.unlock(); emit(updated()); @@ -165,12 +179,12 @@ void Cue::setDirty(bool dirty) { double Cue::getEndPosition() const { QMutexLocker lock(&m_mutex); - if (m_samplePosition == -1.0) { + if (m_sampleStartPosition == -1.0) { return m_length; } else if (m_length == 0.0) { return -1.0; } else { - return m_samplePosition + m_length; + return m_sampleStartPosition + m_length; } } diff --git a/src/track/cue.h b/src/track/cue.h index 83f00f96782..53afaa0fa6e 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -41,6 +41,7 @@ class Cue : public QObject { double getPosition() const; void setStartPosition(double samplePosition); + void setEndPosition(double samplePosition); double getLength() const; void setLength(double length); @@ -73,7 +74,7 @@ class Cue : public QObject { int m_iId; TrackId m_trackId; Cue::Type m_type; - double m_samplePosition; + double m_sampleStartPosition; double m_length; int m_iHotCue; QString m_label; From dd7703092663d397997636866e171fd745068e87 Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 03:39:54 -0500 Subject: [PATCH 150/198] AnalyzerSilence: use Cue::setEndPosition instead of Cue::setLength to make the code easier to understand --- src/analyzer/analyzersilence.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 0f8850786ab..3268365a3fe 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -99,7 +99,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pAudibleSound = pTrack->createAndAddCue(); pAudibleSound->setType(Cue::Type::AudibleSound); pAudibleSound->setStartPosition(firstSound); - pAudibleSound->setLength(lastSound - firstSound); + pAudibleSound->setEndPosition(lastSound); } CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); @@ -124,7 +124,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); pIntroCue->setStartPosition(introStart); - pIntroCue->setLength(0.0); + pIntroCue->setEndPosition(kCueNotSet); } CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); @@ -132,6 +132,6 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); pOutroCue->setStartPosition(kCueNotSet); - pOutroCue->setLength(lastSound); + pOutroCue->setEndPosition(lastSound); } } From 0bc70f682b35f45b2f49b8cfbcbb6202ee6e828f Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 10:10:13 -0500 Subject: [PATCH 151/198] WTrackTableView: add clear Intro/Outro actions to Reset metadata menu This can be used to force a reanalysis with AnalyzerSilence. --- src/widget/wtracktableview.cpp | 46 ++++++++++++++++++++++++++++++++++ src/widget/wtracktableview.h | 4 +++ 2 files changed, 50 insertions(+) diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index f5ab4b30d02..b1b9482c269 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -189,6 +189,8 @@ WTrackTableView::~WTrackTableView() { delete m_pClearPlayCountAction; delete m_pClearMainCueAction; delete m_pClearHotCuesAction; + delete m_pClearIntroCueAction; + delete m_pClearOutroCueAction; delete m_pClearLoopAction; delete m_pClearReplayGainAction; delete m_pClearWaveformAction; @@ -526,6 +528,14 @@ void WTrackTableView::createActions( connect(m_pClearHotCuesAction, SIGNAL(triggered()), this, SLOT(slotClearHotCues())); + m_pClearIntroCueAction = new QAction(tr("Intro"), this); + connect(m_pClearIntroCueAction, SIGNAL(triggered()), + this, SLOT(slotClearIntroCue())); + + m_pClearOutroCueAction = new QAction(tr("Outro"), this); + connect(m_pClearOutroCueAction, SIGNAL(triggered()), + this, SLOT(slotClearOutroCue())); + m_pClearLoopAction = new QAction(tr("Loop"), this); connect(m_pClearLoopAction, SIGNAL(triggered()), this, SLOT(slotClearLoop())); @@ -990,6 +1000,8 @@ void WTrackTableView::contextMenuEvent(QContextMenuEvent* event) { // FIXME: Why is clearing the loop not working? m_pClearMetadataMenu->addAction(m_pClearMainCueAction); m_pClearMetadataMenu->addAction(m_pClearHotCuesAction); + m_pClearMetadataMenu->addAction(m_pClearIntroCueAction); + m_pClearMetadataMenu->addAction(m_pClearOutroCueAction); //m_pClearMetadataMenu->addAction(m_pClearLoopAction); m_pClearMetadataMenu->addAction(m_pClearKeyAction); m_pClearMetadataMenu->addAction(m_pClearReplayGainAction); @@ -1985,6 +1997,38 @@ void WTrackTableView::slotClearHotCues() { } } +void WTrackTableView::slotClearIntroCue() { + QModelIndexList indices = selectionModel()->selectedRows(); + TrackModel* trackModel = getTrackModel(); + + if (trackModel == nullptr) { + return; + } + + for (const QModelIndex& index : indices) { + TrackPointer pTrack = trackModel->getTrack(index); + if (pTrack) { + pTrack->removeCuesOfType(Cue::Type::Intro); + } + } +} + +void WTrackTableView::slotClearOutroCue() { + QModelIndexList indices = selectionModel()->selectedRows(); + TrackModel* trackModel = getTrackModel(); + + if (trackModel == nullptr) { + return; + } + + for (const QModelIndex& index : indices) { + TrackPointer pTrack = trackModel->getTrack(index); + if (pTrack) { + pTrack->removeCuesOfType(Cue::Type::Outro); + } + } +} + void WTrackTableView::slotClearLoop() { QModelIndexList indices = selectionModel()->selectedRows(); TrackModel* trackModel = getTrackModel(); @@ -2056,6 +2100,8 @@ void WTrackTableView::slotClearAllMetadata() { slotClearBeats(); slotClearMainCue(); slotClearHotCues(); + slotClearIntroCue(); + slotClearOutroCue(); slotClearLoop(); slotClearKey(); slotClearReplayGain(); diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index 36cc1ab3b93..d588162d8a1 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -88,6 +88,8 @@ class WTrackTableView : public WLibraryTableView { void slotClearPlayCount(); void slotClearMainCue(); void slotClearHotCues(); + void slotClearIntroCue(); + void slotClearOutroCue(); void slotClearLoop(); void slotClearKey(); void slotClearReplayGain(); @@ -204,6 +206,8 @@ class WTrackTableView : public WLibraryTableView { QAction* m_pClearPlayCountAction; QAction* m_pClearMainCueAction; QAction* m_pClearHotCuesAction; + QAction* m_pClearIntroCueAction; + QAction* m_pClearOutroCueAction; QAction* m_pClearLoopAction; QAction* m_pClearWaveformAction; QAction* m_pClearKeyAction; From 61e2e28824f2cd153eee4a2c044865be2c88085f Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 10:10:54 -0500 Subject: [PATCH 152/198] AnalyzerSilence: always set AudibleSound start/end point even if the AudibleSound Cue already exists --- src/analyzer/analyzersilence.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 3268365a3fe..642fcc3c3c2 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -98,9 +98,15 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { if (pAudibleSound == nullptr) { pAudibleSound = pTrack->createAndAddCue(); pAudibleSound->setType(Cue::Type::AudibleSound); - pAudibleSound->setStartPosition(firstSound); - pAudibleSound->setEndPosition(lastSound); } + // The user has no way to directly edit the AudibleSound cue. If the user + // has deleted the Intro or Outro Cue, this analysis will be rerun when + // the track is loaded again. In this case, adjust the AudibleSound Cue's + // positions. This could be helpful, for example, when the track length + // is changed in a different program, or the silence detection threshold + // is changed. + pAudibleSound->setStartPosition(firstSound); + pAudibleSound->setEndPosition(lastSound); CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); From 65fc8d03ec71fc758d7a27778017d52e004b73bf Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 10:11:02 -0500 Subject: [PATCH 153/198] explicitly compare to nullptr --- src/analyzer/analyzersilence.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 642fcc3c3c2..e91ec3e14cd 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -126,7 +126,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { introStart = mainCue; } - if (!pIntroCue) { + if (pIntroCue == nullptr) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); pIntroCue->setStartPosition(introStart); @@ -134,7 +134,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { } CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); - if (!pOutroCue) { + if (pOutroCue == nullptr) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); pOutroCue->setStartPosition(kCueNotSet); From 1d97fb61f9f1dae4cb210715e79d4c4a5e9c201d Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 13:04:20 -0500 Subject: [PATCH 154/198] replace in skin XML for DlgAutoDJ with option This allows skins to define the icons in QSS and size them as appropriate for the skin. --- res/skins/Deere/library.xml | 6 --- res/skins/LateNight/library.xml | 6 --- res/skins/Shade/skin.xml | 6 --- res/skins/Tango/library.xml | 6 --- src/library/autodj/autodjfeature.cpp | 2 +- src/library/autodj/dlgautodj.cpp | 51 +++++++------------- src/library/autodj/dlgautodj.h | 7 ++- src/skin/skinbutton.h | 69 ---------------------------- src/widget/wlibrary.cpp | 5 +- src/widget/wlibrary.h | 8 ++-- 10 files changed, 28 insertions(+), 138 deletions(-) delete mode 100644 src/skin/skinbutton.h diff --git a/res/skins/Deere/library.xml b/res/skins/Deere/library.xml index d5dc406fadc..e6464a2671b 100644 --- a/res/skins/Deere/library.xml +++ b/res/skins/Deere/library.xml @@ -63,12 +63,6 @@ - - - diff --git a/res/skins/LateNight/library.xml b/res/skins/LateNight/library.xml index e682ba50d26..c955e5591a7 100644 --- a/res/skins/LateNight/library.xml +++ b/res/skins/LateNight/library.xml @@ -66,12 +66,6 @@ #585858 #eece33 - - - diff --git a/res/skins/Shade/skin.xml b/res/skins/Shade/skin.xml index 8dfa6662f58..3d913043e71 100644 --- a/res/skins/Shade/skin.xml +++ b/res/skins/Shade/skin.xml @@ -498,12 +498,6 @@ me,me - - - diff --git a/res/skins/Tango/library.xml b/res/skins/Tango/library.xml index 2e46192287b..2581d3521e1 100644 --- a/res/skins/Tango/library.xml +++ b/res/skins/Tango/library.xml @@ -95,12 +95,6 @@ Description: #585858 #eece33 - - - diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index bf24c33306e..20c5bd29b2d 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -123,7 +123,7 @@ void AutoDJFeature::bindWidget(WLibrary* libraryWidget, m_pAutoDJProcessor, m_pTrackCollection, keyboard, - libraryWidget->icons()); + libraryWidget->getShowButtonText()); libraryWidget->registerView(m_sAutoDJViewName, m_pAutoDJView); connect(m_pAutoDJView, &DlgAutoDJ::loadTrack, diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 4b5fd02ef68..fe8b24ec676 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -11,12 +11,6 @@ namespace { const char* kPreferenceGroupName = "[Auto DJ]"; const char* kRepeatPlaylistPreference = "Requeue"; -const char* kEnableButtonName = "AutoDjEnable"; -const char* kShuffleButtonName = "AutoDjShuffle"; -const char* kSkipButtonName = "AutoDjSkip"; -const char* kAddRandomButtonName = "AutoDjAddRandom"; -const char* kFadeNowButtonName = "AutoDjFadeNow"; -const char* kRepeatButtonName = "AutoDjRepeatPlaylist"; } // anonymous namespace DlgAutoDJ::DlgAutoDJ(QWidget* parent, @@ -25,7 +19,7 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard, - const QMap icons) + bool showButtonText) : QWidget(parent), Ui::DlgAutoDJ(), m_pAutoDJProcessor(pProcessor), @@ -34,7 +28,7 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, pTrackCollection, false)), m_pAutoDJTableModel(nullptr), m_pConfig(pConfig), - m_icons(icons) { + m_bShowButtonText(showButtonText) { setupUi(this); m_pTrackTableView->installEventFilter(pKeyboard); @@ -75,13 +69,13 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, this, &DlgAutoDJ::toggleAutoDJButton); setupActionButton(pushButtonShuffle, &DlgAutoDJ::shufflePlaylistButton, - kShuffleButtonName, tr("Shuffle")); + tr("Shuffle")); setupActionButton(pushButtonSkipNext, &DlgAutoDJ::skipNextButton, - kSkipButtonName, tr("Skip")); + tr("Skip")); setupActionButton(pushButtonAddRandom, &DlgAutoDJ::addRandomButton, - kAddRandomButtonName, tr("Random")); + tr("Random")); setupActionButton(pushButtonFadeNow, &DlgAutoDJ::fadeNowButton, - kFadeNowButtonName, tr("Fade")); + tr("Fade")); connect(spinBoxTransition, QOverload::of(&QSpinBox::valueChanged), this, &DlgAutoDJ::transitionSliderChanged); @@ -126,6 +120,9 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, connect(pushButtonRepeatPlaylist, &QPushButton::toggled, this, &DlgAutoDJ::slotRepeatPlaylistChanged); + if (m_bShowButtonText) { + pushButtonRepeatPlaylist->setText(tr("Repeat")); + } bool repeatPlaylist = m_pConfig->getValue( ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference)); pushButtonRepeatPlaylist->setChecked(repeatPlaylist); @@ -152,14 +149,10 @@ DlgAutoDJ::~DlgAutoDJ() { delete m_pTrackTableView; } -void DlgAutoDJ::setupActionButton(QPushButton* pButton, void (DlgAutoDJ::*pSlot)(bool), - QString skinButtonName, QString fallbackText) { +void DlgAutoDJ::setupActionButton(QPushButton* pButton, void (DlgAutoDJ::*pSlot)(bool), QString fallbackText) { connect(pButton, &QPushButton::clicked, this, pSlot); - QString iconPath = m_icons.value(skinButtonName).states.value("Off").pixmapSource.getPath(); - if (iconPath.isEmpty()) { + if (m_bShowButtonText) { pButton->setText(fallbackText); - } else { - pButton->setIcon(QIcon(iconPath)); } } @@ -235,18 +228,21 @@ void DlgAutoDJ::transitionSliderChanged(int value) { } void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) { - QString stateName; if (state == AutoDJProcessor::ADJ_DISABLED) { pushButtonAutoDJ->setChecked(false); pushButtonAutoDJ->setToolTip(tr("Enable Auto DJ")); - stateName = "Off"; + if (m_bShowButtonText) { + pushButtonAutoDJ->setText(tr("Enable")); + } pushButtonFadeNow->setEnabled(false); pushButtonSkipNext->setEnabled(false); } else { // No matter the mode, you can always disable once it is enabled. pushButtonAutoDJ->setChecked(true); pushButtonAutoDJ->setToolTip(tr("Disable Auto DJ")); - stateName = "On"; + if (m_bShowButtonText) { + pushButtonAutoDJ->setText(tr("Disable")); + } // If fading, you can't hit fade now. if (state == AutoDJProcessor::ADJ_LEFT_FADING || @@ -260,12 +256,6 @@ void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) { // You can always skip the next track if we are enabled. pushButtonSkipNext->setEnabled(true); } - QString pixmapPath = m_icons.value(kEnableButtonName).states.value(stateName).pixmapSource.getPath(); - if (pixmapPath.isEmpty()) { - pushButtonAutoDJ->setText((state == AutoDJProcessor::ADJ_DISABLED) ? tr("Enable") : tr("Disable")); - } else { - pushButtonAutoDJ->setIcon(QIcon(pixmapPath)); - } } void DlgAutoDJ::slotTransitionModeChanged(int comboboxIndex) { @@ -277,13 +267,6 @@ void DlgAutoDJ::slotRepeatPlaylistChanged(int checkState) { bool checked = static_cast(checkState); m_pConfig->setValue(ConfigKey(kPreferenceGroupName, kRepeatPlaylistPreference), checked); - QString stateName = checked ? "On" : "Off"; - QString pixmapPath = m_icons.value(kRepeatButtonName).states.value(stateName).pixmapSource.getPath(); - if (pixmapPath.isEmpty()) { - pushButtonRepeatPlaylist->setText(tr("Repeat")); - } else { - pushButtonRepeatPlaylist->setIcon(QIcon(pixmapPath)); - } } void DlgAutoDJ::updateSelectionInfo() { diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index 422acdeefd5..7324e86eeec 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -6,7 +6,6 @@ #include "library/autodj/ui_dlgautodj.h" #include "preferences/usersettings.h" -#include "skin/skinbutton.h" #include "track/track.h" #include "library/libraryview.h" #include "library/library.h" @@ -24,7 +23,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { Library* pLibrary, AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard, - const QMap icons); + bool showButtonText); ~DlgAutoDJ() override; void onShow() override; @@ -54,13 +53,13 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { private: void setupActionButton(QPushButton* pButton, void (DlgAutoDJ::*pSlot)(bool), - QString skinButtonName, QString fallbackText); + QString fallbackText); AutoDJProcessor* m_pAutoDJProcessor; WTrackTableView* m_pTrackTableView; PlaylistTableModel* m_pAutoDJTableModel; UserSettingsPointer m_pConfig; - const QMap m_icons; + bool m_bShowButtonText; }; #endif //DLGAUTODJ_H diff --git a/src/skin/skinbutton.h b/src/skin/skinbutton.h deleted file mode 100644 index 72d408eab50..00000000000 --- a/src/skin/skinbutton.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include "skin/skincontext.h" - -// These classes provide a way for skins to specify pixmap paths for the -// icons in complex widgets, for example the buttons in DlgAutoDJ. The skin XML -// for the widget would have a Buttons element like: -// -// -// -// -// -// Call ButtonIcon::parseIcons in the widget's setup method and store the result -// in a member variable. - -class SkinButtonState { - public: - QString name; - PixmapSource pixmapSource; -}; - -class SkinButton { - public: - QString name; - QMap states; - - void addState(SkinButtonState state) { - states.insert(state.name, state); - } - - static QMap parseIcons( - const QDomNode& node, const SkinContext& context) { - - QMap icons; - QDomElement buttonIconsList = context.selectElement(node, "Buttons"); - QDomNode buttonIconNode = context.selectNode(buttonIconsList, "Button"); - while (!buttonIconNode.isNull()) { - if (buttonIconNode.isElement() && buttonIconNode.nodeName() == "Button") { - SkinButton buttonIcon; - QString buttonName = buttonIconNode.toElement().attribute("name"); - if (buttonName.isEmpty()) { - buttonIconNode = buttonIconNode.nextSibling(); - continue; - } - buttonIcon.name = buttonName; - - QDomNode buttonStateNode = context.selectNode(buttonIconNode, "State"); - while (!buttonStateNode.isNull()) { - if (buttonStateNode.isElement() && buttonStateNode.nodeName() == "State") { - SkinButtonState buttonIconState; - QString buttonIconStateName = buttonStateNode.toElement().attribute("name"); - if (!buttonIconStateName.isEmpty()) { - buttonIconState.name = buttonIconStateName; - buttonIconState.pixmapSource = context.getPixmapSource(buttonStateNode); - buttonIcon.addState(buttonIconState); - } - } - buttonStateNode = buttonStateNode.nextSibling(); - } - - icons.insert(buttonName, buttonIcon); - } - buttonIconNode = buttonIconNode.nextSibling(); - } - return icons; - } -}; diff --git a/src/widget/wlibrary.cpp b/src/widget/wlibrary.cpp index 6c672d4a240..0fb9b780273 100644 --- a/src/widget/wlibrary.cpp +++ b/src/widget/wlibrary.cpp @@ -12,11 +12,12 @@ WLibrary::WLibrary(QWidget* parent) : QStackedWidget(parent), WBaseWidget(this), - m_mutex(QMutex::Recursive) { + m_mutex(QMutex::Recursive), + m_bShowButtonText(true) { } void WLibrary::setup(const QDomNode& node, const SkinContext& context) { - m_icons = SkinButton::parseIcons(node, context); + m_bShowButtonText = context.selectBool(node, "ShowButtonText", true); } bool WLibrary::registerView(QString name, QWidget* view) { diff --git a/src/widget/wlibrary.h b/src/widget/wlibrary.h index c0f83639e85..b7d1ad6dcb3 100644 --- a/src/widget/wlibrary.h +++ b/src/widget/wlibrary.h @@ -11,7 +11,6 @@ #include #include "library/libraryview.h" -#include "skin/skinbutton.h" #include "skin/skincontext.h" #include "widget/wbasewidget.h" @@ -34,8 +33,8 @@ class WLibrary : public QStackedWidget, public WBaseWidget { LibraryView* getActiveView() const; - const QMap icons() const { - return m_icons; + bool getShowButtonText() const { + return m_bShowButtonText; } public slots: @@ -52,7 +51,8 @@ class WLibrary : public QStackedWidget, public WBaseWidget { private: QMutex m_mutex; QMap m_viewMap; - QMap m_icons; + bool m_bShowButtonText; }; #endif /* WLIBRARY_H */ + From 33adf4b04b2851477aa36ce47e59cfadced6ebf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 22 Oct 2019 23:09:13 +0200 Subject: [PATCH 155/198] Use Cue::kPositionNotDefined for unset cue positions. --- src/analyzer/analyzersilence.cpp | 8 +- src/engine/controls/cuecontrol.cpp | 114 ++++++++++++++--------------- 2 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index e91ec3e14cd..6f5321ee915 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -9,8 +9,6 @@ constexpr float kSilenceThreshold = 0.001; // TODO: Change the above line to: //constexpr float kSilenceThreshold = db2ratio(-60.0f); -const double kCueNotSet = -1.0; - bool shouldAnalyze(TrackPointer pTrack) { CuePointer pIntroCue = pTrack->findCueByType(Cue::Type::Intro); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); @@ -118,7 +116,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { // to 0.0 at a later time after analysis because in that case the intro cue // would have already been created by this analyzer. bool upgradingWithMainCueAtDefault = (mainCue == 0.0 && pIntroCue == nullptr); - if (mainCue == kCueNotSet || upgradingWithMainCueAtDefault) { + if (mainCue == Cue::kPositionNotDefined || upgradingWithMainCueAtDefault) { pTrack->setCuePoint(CuePosition(firstSound)); // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) @@ -130,14 +128,14 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); pIntroCue->setStartPosition(introStart); - pIntroCue->setEndPosition(kCueNotSet); + pIntroCue->setEndPosition(Cue::kPositionNotDefined); } CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); if (pOutroCue == nullptr) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setStartPosition(kCueNotSet); + pOutroCue->setStartPosition(Cue::kPositionNotDefined); pOutroCue->setEndPosition(lastSound); } } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index afd7769191e..5a563451c66 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -52,7 +52,7 @@ CueControl::CueControl(QString group, m_pClosestBeat = ControlObject::getControl(ConfigKey(group, "beat_closest")); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); - m_pCuePoint->set(-1.0); + m_pCuePoint->set(Cue::kPositionNotDefined); m_pCueMode = new ControlObject(ConfigKey(group, "cue_mode")); @@ -115,7 +115,7 @@ CueControl::CueControl(QString group, m_pPlayIndicator = new ControlIndicator(ConfigKey(group, "play_indicator")); m_pIntroStartPosition = new ControlObject(ConfigKey(group, "intro_start_position")); - m_pIntroStartPosition->set(kNoTrigger); + m_pIntroStartPosition->set(Cue::kPositionNotDefined); m_pIntroStartEnabled = new ControlObject(ConfigKey(group, "intro_start_enabled")); m_pIntroStartEnabled->setReadOnly(); @@ -136,7 +136,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pIntroEndPosition = new ControlObject(ConfigKey(group, "intro_end_position")); - m_pIntroEndPosition->set(kNoTrigger); + m_pIntroEndPosition->set(Cue::kPositionNotDefined); m_pIntroEndEnabled = new ControlObject(ConfigKey(group, "intro_end_enabled")); m_pIntroEndEnabled->setReadOnly(); @@ -157,7 +157,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pOutroStartPosition = new ControlObject(ConfigKey(group, "outro_start_position")); - m_pOutroStartPosition->set(kNoTrigger); + m_pOutroStartPosition->set(Cue::kPositionNotDefined); m_pOutroStartEnabled = new ControlObject(ConfigKey(group, "outro_start_enabled")); m_pOutroStartEnabled->setReadOnly(); @@ -178,7 +178,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pOutroEndPosition = new ControlObject(ConfigKey(group, "outro_end_position")); - m_pOutroEndPosition->set(kNoTrigger); + m_pOutroEndPosition->set(Cue::kPositionNotDefined); m_pOutroEndEnabled = new ControlObject(ConfigKey(group, "outro_end_enabled")); m_pOutroEndEnabled->setReadOnly(); @@ -308,14 +308,14 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); - m_pCuePoint->set(-1.0); - m_pIntroStartPosition->set(-1.0); + m_pCuePoint->set(Cue::kPositionNotDefined); + m_pIntroStartPosition->set(Cue::kPositionNotDefined); m_pIntroStartEnabled->forceSet(0.0); - m_pIntroEndPosition->set(-1.0); + m_pIntroEndPosition->set(Cue::kPositionNotDefined); m_pIntroEndEnabled->forceSet(0.0); - m_pOutroStartPosition->set(-1.0); + m_pOutroStartPosition->set(Cue::kPositionNotDefined); m_pOutroStartEnabled->forceSet(0.0); - m_pOutroEndPosition->set(-1.0); + m_pOutroEndPosition->set(Cue::kPositionNotDefined); m_pOutroEndEnabled->forceSet(0.0); m_pLoadedTrack.reset(); } @@ -374,7 +374,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); CuePointer pAudibleSound = pNewTrack->findCueByType(Cue::Type::AudibleSound); - double firstSound = kNoTrigger; + double firstSound = Cue::kPositionNotDefined; if (pAudibleSound) { firstSound = pAudibleSound->getPosition(); } @@ -388,14 +388,14 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::FirstSound: - if (firstSound != kNoTrigger) { + if (firstSound != Cue::kPositionNotDefined) { seekExact(firstSound); } else { seekExact(0.0); } break; case SeekOnLoadMode::MainCue: - if (mainCuePoint.getPosition() != kNoTrigger) { + if (mainCuePoint.getPosition() != Cue::kPositionNotDefined) { seekExact(mainCuePoint.getPosition()); } else { seekExact(0.0); @@ -404,7 +404,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { case SeekOnLoadMode::IntroStart: { double introStart = m_pIntroStartPosition->get(); - if (introStart != kNoTrigger) { + if (introStart != Cue::kPositionNotDefined) { seekExact(introStart); } else { seekExact(0.0); @@ -470,13 +470,13 @@ void CueControl::loadCuesFromTrack() { double endPosition = pIntroCue->getEndPosition(); m_pIntroStartPosition->set(quantizeCuePoint(startPosition, QuantizeMode::PreviousBeat)); - m_pIntroStartEnabled->forceSet(startPosition == -1.0 ? 0.0 : 1.0); + m_pIntroStartEnabled->forceSet(startPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); m_pIntroEndPosition->set(quantizeCuePoint(endPosition, QuantizeMode::NextBeat)); - m_pIntroEndEnabled->forceSet(endPosition == -1.0 ? 0.0 : 1.0); + m_pIntroEndEnabled->forceSet(endPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); } else { - m_pIntroStartPosition->set(-1.0); + m_pIntroStartPosition->set(Cue::kPositionNotDefined); m_pIntroStartEnabled->forceSet(0.0); - m_pIntroEndPosition->set(-1.0); + m_pIntroEndPosition->set(Cue::kPositionNotDefined); m_pIntroEndEnabled->forceSet(0.0); } @@ -485,13 +485,13 @@ void CueControl::loadCuesFromTrack() { double endPosition = pOutroCue->getEndPosition(); m_pOutroStartPosition->set(quantizeCuePoint(startPosition, QuantizeMode::PreviousBeat)); - m_pOutroStartEnabled->forceSet(startPosition == -1.0 ? 0.0 : 1.0); + m_pOutroStartEnabled->forceSet(startPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); m_pOutroEndPosition->set(quantizeCuePoint(endPosition, QuantizeMode::NextBeat)); - m_pOutroEndEnabled->forceSet(endPosition == -1.0 ? 0.0 : 1.0); + m_pOutroEndEnabled->forceSet(endPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); } else { - m_pOutroStartPosition->set(-1.0); + m_pOutroStartPosition->set(Cue::kPositionNotDefined); m_pOutroStartEnabled->forceSet(0.0); - m_pOutroEndPosition->set(-1.0); + m_pOutroEndPosition->set(Cue::kPositionNotDefined); m_pOutroEndEnabled->forceSet(0.0); } @@ -499,7 +499,7 @@ void CueControl::loadCuesFromTrack() { double position = pLoadCue->getPosition(); m_pCuePoint->set(quantizeCuePoint(position, QuantizeMode::ClosestBeat)); } else { - m_pCuePoint->set(-1.0); + m_pCuePoint->set(Cue::kPositionNotDefined); } // Detach all hotcues that are no longer present @@ -531,11 +531,11 @@ void CueControl::reloadCuesFromTrack() { SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); if (seekOnLoadMode == SeekOnLoadMode::MainCue) { - if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != -1.0) { + if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != Cue::kPositionNotDefined) { seekExact(cue); } } else if (seekOnLoadMode == SeekOnLoadMode::IntroStart) { - if ((wasTrackAtIntroCue || wasTrackAtZeroPos) && intro != -1.0) { + if ((wasTrackAtIntroCue || wasTrackAtZeroPos) && intro != Cue::kPositionNotDefined) { seekExact(intro); } } @@ -843,7 +843,7 @@ void CueControl::cueClear(double v) { } QMutexLocker lock(&m_mutex); - m_pCuePoint->set(-1.0); + m_pCuePoint->set(Cue::kPositionNotDefined); TrackPointer pLoadedTrack = m_pLoadedTrack; lock.unlock(); @@ -1128,15 +1128,15 @@ void CueControl::introStartSet(double v) { double introEnd = m_pIntroEndPosition->get(); double outroStart = m_pOutroStartPosition->get(); double outroEnd = m_pOutroEndPosition->get(); - if (introEnd != -1.0 && position >= introEnd) { + if (introEnd != Cue::kPositionNotDefined && position >= introEnd) { qWarning() << "Trying to place intro start cue on or after intro end cue."; return; } - if (outroStart != -1.0 && position >= outroStart) { + if (outroStart != Cue::kPositionNotDefined && position >= outroStart) { qWarning() << "Trying to place intro start cue on or after outro start cue."; return; } - if (outroEnd != -1.0 && position >= outroEnd) { + if (outroEnd != Cue::kPositionNotDefined && position >= outroEnd) { qWarning() << "Trying to place intro start cue on or after outro end cue."; return; } @@ -1151,7 +1151,7 @@ void CueControl::introStartSet(double v) { pCue->setType(Cue::Type::Intro); } pCue->setStartPosition(position); - pCue->setLength(introEnd != -1.0 ? introEnd - position : 0.0); + pCue->setLength(introEnd != Cue::kPositionNotDefined ? introEnd - position : 0.0); } } @@ -1167,8 +1167,8 @@ void CueControl::introStartClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); - if (introEnd != -1.0) { - pCue->setStartPosition(-1.0); + if (introEnd != Cue::kPositionNotDefined) { + pCue->setStartPosition(Cue::kPositionNotDefined); pCue->setLength(introEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); @@ -1182,7 +1182,7 @@ void CueControl::introStartActivate(double v) { double introStart = m_pIntroStartPosition->get(); lock.unlock(); - if (introStart == -1.0) { + if (introStart == Cue::kPositionNotDefined) { introStartSet(1.0); } else { seekAbs(introStart); @@ -1206,15 +1206,15 @@ void CueControl::introEndSet(double v) { double introStart = m_pIntroStartPosition->get(); double outroStart = m_pOutroStartPosition->get(); double outroEnd = m_pOutroEndPosition->get(); - if (introStart != -1.0 && position <= introStart) { + if (introStart != Cue::kPositionNotDefined && position <= introStart) { qWarning() << "Trying to place intro end cue on or before intro start cue."; return; } - if (outroStart != -1.0 && position >= outroStart) { + if (outroStart != Cue::kPositionNotDefined && position >= outroStart) { qWarning() << "Trying to place intro end cue on or after outro start cue."; return; } - if (outroEnd != -1.0 && position >= outroEnd) { + if (outroEnd != Cue::kPositionNotDefined && position >= outroEnd) { qWarning() << "Trying to place intro end cue on or after outro end cue."; return; } @@ -1228,11 +1228,11 @@ void CueControl::introEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - if (introStart != -1.0) { + if (introStart != Cue::kPositionNotDefined) { pCue->setStartPosition(introStart); pCue->setLength(position - introStart); } else { - pCue->setStartPosition(-1.0); + pCue->setStartPosition(Cue::kPositionNotDefined); pCue->setLength(position); } } @@ -1250,7 +1250,7 @@ void CueControl::introEndClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); - if (introStart != -1.0) { + if (introStart != Cue::kPositionNotDefined) { pCue->setStartPosition(introStart); pCue->setLength(0.0); } else if (pCue) { @@ -1265,7 +1265,7 @@ void CueControl::introEndActivate(double v) { double introEnd = m_pIntroEndPosition->get(); lock.unlock(); - if (introEnd == -1.0) { + if (introEnd == Cue::kPositionNotDefined) { introEndSet(1.0); } else { seekAbs(introEnd); @@ -1289,15 +1289,15 @@ void CueControl::outroStartSet(double v) { double introStart = m_pIntroStartPosition->get(); double introEnd = m_pIntroEndPosition->get(); double outroEnd = m_pOutroEndPosition->get(); - if (introStart != -1.0 && position <= introStart) { + if (introStart != Cue::kPositionNotDefined && position <= introStart) { qWarning() << "Trying to place outro start cue on or before intro start cue."; return; } - if (introEnd != -1.0 && position <= introEnd) { + if (introEnd != Cue::kPositionNotDefined && position <= introEnd) { qWarning() << "Trying to place outro start cue on or before intro end cue."; return; } - if (outroEnd != -1.0 && position >= outroEnd) { + if (outroEnd != Cue::kPositionNotDefined && position >= outroEnd) { qWarning() << "Trying to place outro start cue on or after outro end cue."; return; } @@ -1312,7 +1312,7 @@ void CueControl::outroStartSet(double v) { pCue->setType(Cue::Type::Outro); } pCue->setStartPosition(position); - pCue->setLength(outroEnd != -1.0 ? outroEnd - position : 0.0); + pCue->setLength(outroEnd != Cue::kPositionNotDefined ? outroEnd - position : 0.0); } } @@ -1328,8 +1328,8 @@ void CueControl::outroStartClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); - if (outroEnd != -1.0) { - pCue->setStartPosition(-1.0); + if (outroEnd != Cue::kPositionNotDefined) { + pCue->setStartPosition(Cue::kPositionNotDefined); pCue->setLength(outroEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); @@ -1343,7 +1343,7 @@ void CueControl::outroStartActivate(double v) { double outroStart = m_pOutroStartPosition->get(); lock.unlock(); - if (outroStart == -1.0) { + if (outroStart == Cue::kPositionNotDefined) { outroStartSet(1.0); } else { seekAbs(outroStart); @@ -1367,15 +1367,15 @@ void CueControl::outroEndSet(double v) { double introStart = m_pIntroStartPosition->get(); double introEnd = m_pIntroEndPosition->get(); double outroStart = m_pOutroStartPosition->get(); - if (introStart != -1.0 && position <= introStart) { + if (introStart != Cue::kPositionNotDefined && position <= introStart) { qWarning() << "Trying to place outro end cue on or before intro start cue."; return; } - if (introEnd != -1.0 && position <= introEnd) { + if (introEnd != Cue::kPositionNotDefined && position <= introEnd) { qWarning() << "Trying to place outro end cue on or before intro end cue."; return; } - if (outroStart != -1.0 && position <= outroStart) { + if (outroStart != Cue::kPositionNotDefined && position <= outroStart) { qWarning() << "Trying to place outro end cue on or before outro start cue."; return; } @@ -1389,11 +1389,11 @@ void CueControl::outroEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - if (outroStart != -1.0) { + if (outroStart != Cue::kPositionNotDefined) { pCue->setStartPosition(outroStart); pCue->setLength(position - outroStart); } else { - pCue->setStartPosition(-1.0); + pCue->setStartPosition(Cue::kPositionNotDefined); pCue->setLength(position); } } @@ -1411,7 +1411,7 @@ void CueControl::outroEndClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); - if (outroStart != -1.0) { + if (outroStart != Cue::kPositionNotDefined) { pCue->setStartPosition(outroStart); pCue->setLength(0.0); } else if (pCue) { @@ -1426,7 +1426,7 @@ void CueControl::outroEndActivate(double v) { double outroEnd = m_pOutroEndPosition->get(); lock.unlock(); - if (outroEnd == -1.0) { + if (outroEnd == Cue::kPositionNotDefined) { outroEndSet(1.0); } else { seekAbs(outroEnd); @@ -1626,7 +1626,7 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { double CueControl::quantizeCuePoint(double position, QuantizeMode mode) { // Don't quantize unset cues, manual cues or when quantization is disabled. - if (position == -1.0 || !m_pQuantizeEnabled->toBool()) { + if (position == Cue::kPositionNotDefined || !m_pQuantizeEnabled->toBool()) { return position; } @@ -1815,10 +1815,10 @@ void HotcueControl::resetCue() { // clear pCue first because we have a null check for valid data else where // in the code m_pCue.reset(); - setPosition(-1.0); + setPosition(Cue::kPositionNotDefined); } void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); - m_hotcueEnabled->forceSet(position == -1.0 ? 0.0 : 1.0); + m_hotcueEnabled->forceSet(position == Cue::kPositionNotDefined ? 0.0 : 1.0); } From cba9dce02279b6d40219e2b6686fea763532a26b Mon Sep 17 00:00:00 2001 From: Be Date: Tue, 22 Oct 2019 17:33:03 -0500 Subject: [PATCH 156/198] rename Cue::kPositionNotDefined -> Cue::kNoPosition --- src/analyzer/analyzersilence.cpp | 6 +- src/engine/controls/cuecontrol.cpp | 114 ++++++++++++++--------------- src/track/cue.h | 2 +- src/widget/woverview.cpp | 4 +- 4 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 6f5321ee915..961c72b14be 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -116,7 +116,7 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { // to 0.0 at a later time after analysis because in that case the intro cue // would have already been created by this analyzer. bool upgradingWithMainCueAtDefault = (mainCue == 0.0 && pIntroCue == nullptr); - if (mainCue == Cue::kPositionNotDefined || upgradingWithMainCueAtDefault) { + if (mainCue == Cue::kNoPosition || upgradingWithMainCueAtDefault) { pTrack->setCuePoint(CuePosition(firstSound)); // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) @@ -128,14 +128,14 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); pIntroCue->setStartPosition(introStart); - pIntroCue->setEndPosition(Cue::kPositionNotDefined); + pIntroCue->setEndPosition(Cue::kNoPosition); } CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); if (pOutroCue == nullptr) { pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setStartPosition(Cue::kPositionNotDefined); + pOutroCue->setStartPosition(Cue::kNoPosition); pOutroCue->setEndPosition(lastSound); } } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 5a563451c66..ac0c49826f9 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -52,7 +52,7 @@ CueControl::CueControl(QString group, m_pClosestBeat = ControlObject::getControl(ConfigKey(group, "beat_closest")); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); - m_pCuePoint->set(Cue::kPositionNotDefined); + m_pCuePoint->set(Cue::kNoPosition); m_pCueMode = new ControlObject(ConfigKey(group, "cue_mode")); @@ -115,7 +115,7 @@ CueControl::CueControl(QString group, m_pPlayIndicator = new ControlIndicator(ConfigKey(group, "play_indicator")); m_pIntroStartPosition = new ControlObject(ConfigKey(group, "intro_start_position")); - m_pIntroStartPosition->set(Cue::kPositionNotDefined); + m_pIntroStartPosition->set(Cue::kNoPosition); m_pIntroStartEnabled = new ControlObject(ConfigKey(group, "intro_start_enabled")); m_pIntroStartEnabled->setReadOnly(); @@ -136,7 +136,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pIntroEndPosition = new ControlObject(ConfigKey(group, "intro_end_position")); - m_pIntroEndPosition->set(Cue::kPositionNotDefined); + m_pIntroEndPosition->set(Cue::kNoPosition); m_pIntroEndEnabled = new ControlObject(ConfigKey(group, "intro_end_enabled")); m_pIntroEndEnabled->setReadOnly(); @@ -157,7 +157,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pOutroStartPosition = new ControlObject(ConfigKey(group, "outro_start_position")); - m_pOutroStartPosition->set(Cue::kPositionNotDefined); + m_pOutroStartPosition->set(Cue::kNoPosition); m_pOutroStartEnabled = new ControlObject(ConfigKey(group, "outro_start_enabled")); m_pOutroStartEnabled->setReadOnly(); @@ -178,7 +178,7 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pOutroEndPosition = new ControlObject(ConfigKey(group, "outro_end_position")); - m_pOutroEndPosition->set(Cue::kPositionNotDefined); + m_pOutroEndPosition->set(Cue::kNoPosition); m_pOutroEndEnabled = new ControlObject(ConfigKey(group, "outro_end_enabled")); m_pOutroEndEnabled->setReadOnly(); @@ -308,14 +308,14 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); - m_pCuePoint->set(Cue::kPositionNotDefined); - m_pIntroStartPosition->set(Cue::kPositionNotDefined); + m_pCuePoint->set(Cue::kNoPosition); + m_pIntroStartPosition->set(Cue::kNoPosition); m_pIntroStartEnabled->forceSet(0.0); - m_pIntroEndPosition->set(Cue::kPositionNotDefined); + m_pIntroEndPosition->set(Cue::kNoPosition); m_pIntroEndEnabled->forceSet(0.0); - m_pOutroStartPosition->set(Cue::kPositionNotDefined); + m_pOutroStartPosition->set(Cue::kNoPosition); m_pOutroStartEnabled->forceSet(0.0); - m_pOutroEndPosition->set(Cue::kPositionNotDefined); + m_pOutroEndPosition->set(Cue::kNoPosition); m_pOutroEndEnabled->forceSet(0.0); m_pLoadedTrack.reset(); } @@ -374,7 +374,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); CuePointer pAudibleSound = pNewTrack->findCueByType(Cue::Type::AudibleSound); - double firstSound = Cue::kPositionNotDefined; + double firstSound = Cue::kNoPosition; if (pAudibleSound) { firstSound = pAudibleSound->getPosition(); } @@ -388,14 +388,14 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::FirstSound: - if (firstSound != Cue::kPositionNotDefined) { + if (firstSound != Cue::kNoPosition) { seekExact(firstSound); } else { seekExact(0.0); } break; case SeekOnLoadMode::MainCue: - if (mainCuePoint.getPosition() != Cue::kPositionNotDefined) { + if (mainCuePoint.getPosition() != Cue::kNoPosition) { seekExact(mainCuePoint.getPosition()); } else { seekExact(0.0); @@ -404,7 +404,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { case SeekOnLoadMode::IntroStart: { double introStart = m_pIntroStartPosition->get(); - if (introStart != Cue::kPositionNotDefined) { + if (introStart != Cue::kNoPosition) { seekExact(introStart); } else { seekExact(0.0); @@ -470,13 +470,13 @@ void CueControl::loadCuesFromTrack() { double endPosition = pIntroCue->getEndPosition(); m_pIntroStartPosition->set(quantizeCuePoint(startPosition, QuantizeMode::PreviousBeat)); - m_pIntroStartEnabled->forceSet(startPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); + m_pIntroStartEnabled->forceSet(startPosition == Cue::kNoPosition ? 0.0 : 1.0); m_pIntroEndPosition->set(quantizeCuePoint(endPosition, QuantizeMode::NextBeat)); - m_pIntroEndEnabled->forceSet(endPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); + m_pIntroEndEnabled->forceSet(endPosition == Cue::kNoPosition ? 0.0 : 1.0); } else { - m_pIntroStartPosition->set(Cue::kPositionNotDefined); + m_pIntroStartPosition->set(Cue::kNoPosition); m_pIntroStartEnabled->forceSet(0.0); - m_pIntroEndPosition->set(Cue::kPositionNotDefined); + m_pIntroEndPosition->set(Cue::kNoPosition); m_pIntroEndEnabled->forceSet(0.0); } @@ -485,13 +485,13 @@ void CueControl::loadCuesFromTrack() { double endPosition = pOutroCue->getEndPosition(); m_pOutroStartPosition->set(quantizeCuePoint(startPosition, QuantizeMode::PreviousBeat)); - m_pOutroStartEnabled->forceSet(startPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); + m_pOutroStartEnabled->forceSet(startPosition == Cue::kNoPosition ? 0.0 : 1.0); m_pOutroEndPosition->set(quantizeCuePoint(endPosition, QuantizeMode::NextBeat)); - m_pOutroEndEnabled->forceSet(endPosition == Cue::kPositionNotDefined ? 0.0 : 1.0); + m_pOutroEndEnabled->forceSet(endPosition == Cue::kNoPosition ? 0.0 : 1.0); } else { - m_pOutroStartPosition->set(Cue::kPositionNotDefined); + m_pOutroStartPosition->set(Cue::kNoPosition); m_pOutroStartEnabled->forceSet(0.0); - m_pOutroEndPosition->set(Cue::kPositionNotDefined); + m_pOutroEndPosition->set(Cue::kNoPosition); m_pOutroEndEnabled->forceSet(0.0); } @@ -499,7 +499,7 @@ void CueControl::loadCuesFromTrack() { double position = pLoadCue->getPosition(); m_pCuePoint->set(quantizeCuePoint(position, QuantizeMode::ClosestBeat)); } else { - m_pCuePoint->set(Cue::kPositionNotDefined); + m_pCuePoint->set(Cue::kNoPosition); } // Detach all hotcues that are no longer present @@ -531,11 +531,11 @@ void CueControl::reloadCuesFromTrack() { SeekOnLoadMode seekOnLoadMode = getSeekOnLoadPreference(); if (seekOnLoadMode == SeekOnLoadMode::MainCue) { - if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != Cue::kPositionNotDefined) { + if ((trackAt == TrackAt::Cue || wasTrackAtZeroPos) && cue != Cue::kNoPosition) { seekExact(cue); } } else if (seekOnLoadMode == SeekOnLoadMode::IntroStart) { - if ((wasTrackAtIntroCue || wasTrackAtZeroPos) && intro != Cue::kPositionNotDefined) { + if ((wasTrackAtIntroCue || wasTrackAtZeroPos) && intro != Cue::kNoPosition) { seekExact(intro); } } @@ -843,7 +843,7 @@ void CueControl::cueClear(double v) { } QMutexLocker lock(&m_mutex); - m_pCuePoint->set(Cue::kPositionNotDefined); + m_pCuePoint->set(Cue::kNoPosition); TrackPointer pLoadedTrack = m_pLoadedTrack; lock.unlock(); @@ -1128,15 +1128,15 @@ void CueControl::introStartSet(double v) { double introEnd = m_pIntroEndPosition->get(); double outroStart = m_pOutroStartPosition->get(); double outroEnd = m_pOutroEndPosition->get(); - if (introEnd != Cue::kPositionNotDefined && position >= introEnd) { + if (introEnd != Cue::kNoPosition && position >= introEnd) { qWarning() << "Trying to place intro start cue on or after intro end cue."; return; } - if (outroStart != Cue::kPositionNotDefined && position >= outroStart) { + if (outroStart != Cue::kNoPosition && position >= outroStart) { qWarning() << "Trying to place intro start cue on or after outro start cue."; return; } - if (outroEnd != Cue::kPositionNotDefined && position >= outroEnd) { + if (outroEnd != Cue::kNoPosition && position >= outroEnd) { qWarning() << "Trying to place intro start cue on or after outro end cue."; return; } @@ -1151,7 +1151,7 @@ void CueControl::introStartSet(double v) { pCue->setType(Cue::Type::Intro); } pCue->setStartPosition(position); - pCue->setLength(introEnd != Cue::kPositionNotDefined ? introEnd - position : 0.0); + pCue->setLength(introEnd != Cue::kNoPosition ? introEnd - position : 0.0); } } @@ -1167,8 +1167,8 @@ void CueControl::introStartClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); - if (introEnd != Cue::kPositionNotDefined) { - pCue->setStartPosition(Cue::kPositionNotDefined); + if (introEnd != Cue::kNoPosition) { + pCue->setStartPosition(Cue::kNoPosition); pCue->setLength(introEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); @@ -1182,7 +1182,7 @@ void CueControl::introStartActivate(double v) { double introStart = m_pIntroStartPosition->get(); lock.unlock(); - if (introStart == Cue::kPositionNotDefined) { + if (introStart == Cue::kNoPosition) { introStartSet(1.0); } else { seekAbs(introStart); @@ -1206,15 +1206,15 @@ void CueControl::introEndSet(double v) { double introStart = m_pIntroStartPosition->get(); double outroStart = m_pOutroStartPosition->get(); double outroEnd = m_pOutroEndPosition->get(); - if (introStart != Cue::kPositionNotDefined && position <= introStart) { + if (introStart != Cue::kNoPosition && position <= introStart) { qWarning() << "Trying to place intro end cue on or before intro start cue."; return; } - if (outroStart != Cue::kPositionNotDefined && position >= outroStart) { + if (outroStart != Cue::kNoPosition && position >= outroStart) { qWarning() << "Trying to place intro end cue on or after outro start cue."; return; } - if (outroEnd != Cue::kPositionNotDefined && position >= outroEnd) { + if (outroEnd != Cue::kNoPosition && position >= outroEnd) { qWarning() << "Trying to place intro end cue on or after outro end cue."; return; } @@ -1228,11 +1228,11 @@ void CueControl::introEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - if (introStart != Cue::kPositionNotDefined) { + if (introStart != Cue::kNoPosition) { pCue->setStartPosition(introStart); pCue->setLength(position - introStart); } else { - pCue->setStartPosition(Cue::kPositionNotDefined); + pCue->setStartPosition(Cue::kNoPosition); pCue->setLength(position); } } @@ -1250,7 +1250,7 @@ void CueControl::introEndClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); - if (introStart != Cue::kPositionNotDefined) { + if (introStart != Cue::kNoPosition) { pCue->setStartPosition(introStart); pCue->setLength(0.0); } else if (pCue) { @@ -1265,7 +1265,7 @@ void CueControl::introEndActivate(double v) { double introEnd = m_pIntroEndPosition->get(); lock.unlock(); - if (introEnd == Cue::kPositionNotDefined) { + if (introEnd == Cue::kNoPosition) { introEndSet(1.0); } else { seekAbs(introEnd); @@ -1289,15 +1289,15 @@ void CueControl::outroStartSet(double v) { double introStart = m_pIntroStartPosition->get(); double introEnd = m_pIntroEndPosition->get(); double outroEnd = m_pOutroEndPosition->get(); - if (introStart != Cue::kPositionNotDefined && position <= introStart) { + if (introStart != Cue::kNoPosition && position <= introStart) { qWarning() << "Trying to place outro start cue on or before intro start cue."; return; } - if (introEnd != Cue::kPositionNotDefined && position <= introEnd) { + if (introEnd != Cue::kNoPosition && position <= introEnd) { qWarning() << "Trying to place outro start cue on or before intro end cue."; return; } - if (outroEnd != Cue::kPositionNotDefined && position >= outroEnd) { + if (outroEnd != Cue::kNoPosition && position >= outroEnd) { qWarning() << "Trying to place outro start cue on or after outro end cue."; return; } @@ -1312,7 +1312,7 @@ void CueControl::outroStartSet(double v) { pCue->setType(Cue::Type::Outro); } pCue->setStartPosition(position); - pCue->setLength(outroEnd != Cue::kPositionNotDefined ? outroEnd - position : 0.0); + pCue->setLength(outroEnd != Cue::kNoPosition ? outroEnd - position : 0.0); } } @@ -1328,8 +1328,8 @@ void CueControl::outroStartClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); - if (outroEnd != Cue::kPositionNotDefined) { - pCue->setStartPosition(Cue::kPositionNotDefined); + if (outroEnd != Cue::kNoPosition) { + pCue->setStartPosition(Cue::kNoPosition); pCue->setLength(outroEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); @@ -1343,7 +1343,7 @@ void CueControl::outroStartActivate(double v) { double outroStart = m_pOutroStartPosition->get(); lock.unlock(); - if (outroStart == Cue::kPositionNotDefined) { + if (outroStart == Cue::kNoPosition) { outroStartSet(1.0); } else { seekAbs(outroStart); @@ -1367,15 +1367,15 @@ void CueControl::outroEndSet(double v) { double introStart = m_pIntroStartPosition->get(); double introEnd = m_pIntroEndPosition->get(); double outroStart = m_pOutroStartPosition->get(); - if (introStart != Cue::kPositionNotDefined && position <= introStart) { + if (introStart != Cue::kNoPosition && position <= introStart) { qWarning() << "Trying to place outro end cue on or before intro start cue."; return; } - if (introEnd != Cue::kPositionNotDefined && position <= introEnd) { + if (introEnd != Cue::kNoPosition && position <= introEnd) { qWarning() << "Trying to place outro end cue on or before intro end cue."; return; } - if (outroStart != Cue::kPositionNotDefined && position <= outroStart) { + if (outroStart != Cue::kNoPosition && position <= outroStart) { qWarning() << "Trying to place outro end cue on or before outro start cue."; return; } @@ -1389,11 +1389,11 @@ void CueControl::outroEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - if (outroStart != Cue::kPositionNotDefined) { + if (outroStart != Cue::kNoPosition) { pCue->setStartPosition(outroStart); pCue->setLength(position - outroStart); } else { - pCue->setStartPosition(Cue::kPositionNotDefined); + pCue->setStartPosition(Cue::kNoPosition); pCue->setLength(position); } } @@ -1411,7 +1411,7 @@ void CueControl::outroEndClear(double v) { if (pLoadedTrack) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); - if (outroStart != Cue::kPositionNotDefined) { + if (outroStart != Cue::kNoPosition) { pCue->setStartPosition(outroStart); pCue->setLength(0.0); } else if (pCue) { @@ -1426,7 +1426,7 @@ void CueControl::outroEndActivate(double v) { double outroEnd = m_pOutroEndPosition->get(); lock.unlock(); - if (outroEnd == Cue::kPositionNotDefined) { + if (outroEnd == Cue::kNoPosition) { outroEndSet(1.0); } else { seekAbs(outroEnd); @@ -1626,7 +1626,7 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { double CueControl::quantizeCuePoint(double position, QuantizeMode mode) { // Don't quantize unset cues, manual cues or when quantization is disabled. - if (position == Cue::kPositionNotDefined || !m_pQuantizeEnabled->toBool()) { + if (position == Cue::kNoPosition || !m_pQuantizeEnabled->toBool()) { return position; } @@ -1815,10 +1815,10 @@ void HotcueControl::resetCue() { // clear pCue first because we have a null check for valid data else where // in the code m_pCue.reset(); - setPosition(Cue::kPositionNotDefined); + setPosition(Cue::kNoPosition); } void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); - m_hotcueEnabled->forceSet(position == Cue::kPositionNotDefined ? 0.0 : 1.0); + m_hotcueEnabled->forceSet(position == Cue::kNoPosition ? 0.0 : 1.0); } diff --git a/src/track/cue.h b/src/track/cue.h index edbac30799c..09d5279fd88 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -30,7 +30,7 @@ class Cue : public QObject { // not shown to user }; - static constexpr double kPositionNotDefined = -1.0; + static constexpr double kNoPosition = -1.0; ~Cue() override = default; diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index d93034968c9..09acfc450aa 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -341,7 +341,7 @@ void WOverview::updateCues(const QList &loadedCues) { const WaveformMarkPointer pMark = m_marks.getHotCueMark(currentCue->getHotCue()); if (pMark != nullptr && pMark->isValid() && pMark->isVisible() - && pMark->getSamplePosition() != Cue::kPositionNotDefined) { + && pMark->getSamplePosition() != Cue::kNoPosition) { QColor newColor = m_predefinedColorsRepresentation.representationFor(currentCue->getColor()); if (newColor != pMark->fillColor() || newColor != pMark->m_textColor) { pMark->setBaseColor(newColor); @@ -370,7 +370,7 @@ void WOverview::updateCues(const QList &loadedCues) { for (const auto& pMark : m_marks) { if (!m_marksToRender.contains(pMark) && pMark->isValid() - && pMark->getSamplePosition() != Cue::kPositionNotDefined + && pMark->getSamplePosition() != Cue::kNoPosition && pMark->isVisible()) { m_marksToRender.append(pMark); } From a15169e0c06b6d722629488baa72998fc316201c Mon Sep 17 00:00:00 2001 From: Be Date: Wed, 23 Oct 2019 06:36:13 -0500 Subject: [PATCH 157/198] move kNoHotCue constant from WaveformMark to Cue --- src/track/cue.h | 1 + src/waveform/renderers/waveformmark.cpp | 4 ++-- src/waveform/renderers/waveformmark.h | 13 ++++++------- src/waveform/renderers/waveformrendermark.cpp | 2 +- src/widget/woverview.cpp | 8 ++++---- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/track/cue.h b/src/track/cue.h index 09d5279fd88..1e0ac94893f 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -31,6 +31,7 @@ class Cue : public QObject { }; static constexpr double kNoPosition = -1.0; + static const int kNoHotCue = -1; ~Cue() override = default; diff --git a/src/waveform/renderers/waveformmark.cpp b/src/waveform/renderers/waveformmark.cpp index 0f2db81adad..5d8e7d1164f 100644 --- a/src/waveform/renderers/waveformmark.cpp +++ b/src/waveform/renderers/waveformmark.cpp @@ -52,7 +52,7 @@ WaveformMark::WaveformMark(const QString& group, int hotCue) : m_iHotCue(hotCue) { QString control; - if (hotCue != kNoHotCue) { + if (hotCue != Cue::kNoHotCue) { control = "hotcue_" + QString::number(hotCue + 1) + "_position"; } else { control = context.selectString(node, "Control"); @@ -88,7 +88,7 @@ WaveformMark::WaveformMark(const QString& group, m_align = decodeAlignmentFlags(markAlign, Qt::AlignBottom | Qt::AlignHCenter); // Hotcue text is set by the cue's label in the database, not by the skin. - if (hotCue == WaveformMark::kNoHotCue) { + if (hotCue == Cue::kNoHotCue) { m_text = context.selectString(node, "Text"); } diff --git a/src/waveform/renderers/waveformmark.h b/src/waveform/renderers/waveformmark.h index ab11862df18..caf652adaaa 100644 --- a/src/waveform/renderers/waveformmark.h +++ b/src/waveform/renderers/waveformmark.h @@ -4,11 +4,11 @@ #include #include -#include "waveform/waveformmarklabel.h" +#include "control/controlobject.h" #include "control/controlproxy.h" +#include "track/cue.h" #include "util/memory.h" - -#include "control/controlobject.h" +#include "waveform/waveformmarklabel.h" class SkinContext; class WaveformSignalColors; @@ -17,13 +17,12 @@ class WOverview; class WaveformMark { public: - static const int kNoHotCue = -1; WaveformMark( const QString& group, const QDomNode& node, const SkinContext& context, const WaveformSignalColors& signalColors, - int hotCue = kNoHotCue); + int hotCue = Cue::kNoHotCue); // Disable copying WaveformMark(const WaveformMark&) = delete; @@ -99,9 +98,9 @@ inline bool operator<(const WaveformMarkPointer& lhs, const WaveformMarkPointer& if (leftPosition == rightPosition) { // Sort WaveformMarks without hotcues before those with hotcues; // if both have hotcues, sort numerically by hotcue number. - if (leftHotcue == WaveformMark::kNoHotCue && rightHotcue != WaveformMark::kNoHotCue) { + if (leftHotcue == Cue::kNoHotCue && rightHotcue != Cue::kNoHotCue) { return true; - } else if (leftHotcue != WaveformMark::kNoHotCue && rightHotcue == WaveformMark::kNoHotCue) { + } else if (leftHotcue != Cue::kNoHotCue && rightHotcue == Cue::kNoHotCue) { return false; } else { return leftHotcue < rightHotcue; diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 8c4a05e3490..ffd8a76531a 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -115,7 +115,7 @@ void WaveformRenderMark::slotCuesUpdated() { QList loadedCues = trackInfo->getCuePoints(); for (const CuePointer pCue: loadedCues) { int hotCue = pCue->getHotCue(); - if (hotCue == WaveformMark::kNoHotCue) { + if (hotCue == Cue::kNoHotCue) { continue; } diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 09acfc450aa..6ebe13489cf 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -348,7 +348,7 @@ void WOverview::updateCues(const QList &loadedCues) { } int hotcueNumber = currentCue->getHotCue(); - if (currentCue->getType() == Cue::Type::HotCue && hotcueNumber != WaveformMark::kNoHotCue) { + if (currentCue->getType() == Cue::Type::HotCue && hotcueNumber != Cue::kNoHotCue) { // Prepend the hotcue number to hotcues' labels QString newLabel = currentCue->getLabel(); if (newLabel.isEmpty()) { @@ -461,7 +461,7 @@ void WOverview::mousePressEvent(QMouseEvent* e) { if (m_pHoveredMark == nullptr) { m_bTimeRulerActive = true; m_timeRulerPos = e->pos(); - } else if (m_pHoveredMark->getHotCue() != WaveformMark::kNoHotCue) { + } else if (m_pHoveredMark->getHotCue() != Cue::kNoHotCue) { // Currently the only way WaveformMarks can be associated // with their respective Cue objects is by using the hotcue // number. If cues without assigned hotcue are drawn on @@ -743,7 +743,7 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga bool otherAtSameHeight = valign == (otherMark->m_align & Qt::AlignVertical_Mask); // Hotcues always show at least their number. bool otherHasLabel = !otherMark->m_text.isEmpty() - || otherMark->getHotCue() != WaveformMark::kNoHotCue; + || otherMark->getHotCue() != Cue::kNoHotCue; if (otherAtSameHeight && otherHasLabel) { nextMarkPosition = offset + otherMark->getSamplePosition() * gain; break; @@ -757,7 +757,7 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga // elipsis character, so always show at least the hotcue number if // the label does not fit. if ((text.isEmpty() || text == "…") - && pMark->getHotCue() != WaveformMark::kNoHotCue) { + && pMark->getHotCue() != Cue::kNoHotCue) { text = QString::number(pMark->getHotCue()+1); } From b2043424cd975ad54cf755e4b770b7d81e4b28e4 Mon Sep 17 00:00:00 2001 From: Be Date: Wed, 23 Oct 2019 06:42:24 -0500 Subject: [PATCH 158/198] use Cue::kNoHotCue constant --- src/engine/controls/cuecontrol.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index ac0c49826f9..68e9da5521b 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -362,7 +362,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { // Than add the load cue to the list of cue CuePointer pCue(pNewTrack->createAndAddCue()); pCue->setStartPosition(mainCuePoint.getPosition()); - pCue->setHotCue(-1); + pCue->setHotCue(Cue::kNoHotCue); pCue->setType(Cue::Type::MainCue); } m_pCuePoint->set(mainCuePoint.getPosition()); @@ -440,7 +440,7 @@ void CueControl::loadCuesFromTrack() { } else if (pCue->getType() == Cue::Type::Outro) { DEBUG_ASSERT(!pOutroCue); // There should be only one Outro cue pOutroCue = pCue; - } else if (pCue->getType() == Cue::Type::HotCue && pCue->getHotCue() != -1) { + } else if (pCue->getType() == Cue::Type::HotCue && pCue->getHotCue() != Cue::kNoHotCue) { int hotcue = pCue->getHotCue(); HotcueControl* pControl = m_hotcueControls.value(hotcue, NULL); From ee9cfccac82e3937f1c58fe94e542d6b283f115c Mon Sep 17 00:00:00 2001 From: Be Date: Wed, 23 Oct 2019 06:43:33 -0500 Subject: [PATCH 159/198] CueControl: use Cue::kNoPosition constant in more places --- src/engine/controls/cuecontrol.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 68e9da5521b..ae252c45dde 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -616,7 +616,7 @@ void CueControl::hotcueGoto(HotcueControl* pControl, double v) { if (pCue) { int position = pCue->getPosition(); - if (position != -1) { + if (position != Cue::kNoPosition) { seekAbs(position); } } @@ -637,7 +637,7 @@ void CueControl::hotcueGotoAndStop(HotcueControl* pControl, double v) { if (pCue) { int position = pCue->getPosition(); - if (position != -1) { + if (position != Cue::kNoPosition) { m_pPlay->set(0.0); seekExact(position); } @@ -660,7 +660,7 @@ void CueControl::hotcueGotoAndPlay(HotcueControl* pControl, double v) { if (pCue) { int position = pCue->getPosition(); - if (position != -1) { + if (position != Cue::kNoPosition) { seekAbs(position); if (!isPlayingByPlayButton()) { // cueGoto is processed asynchrony. @@ -690,7 +690,7 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { if (pCue) { if (v) { - if (pCue->getPosition() == -1) { + if (pCue->getPosition() == Cue::kNoPosition) { hotcueSet(pControl, v); } else { if (isPlayingByPlayButton()) { @@ -700,7 +700,7 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { } } } else { - if (pCue->getPosition() != -1) { + if (pCue->getPosition() != Cue::kNoPosition) { hotcueActivatePreview(pControl, v); } } @@ -727,7 +727,7 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { CuePointer pCue(pControl->getCue()); if (v) { - if (pCue && pCue->getPosition() != -1) { + if (pCue && pCue->getPosition() != Cue::kNoPosition) { m_iCurrentlyPreviewingHotcues++; double position = pCue->getPosition(); m_bypassCueSetByPlay = true; @@ -747,7 +747,7 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { // Mark this hotcue as not previewing. double position = pControl->getPreviewingPosition(); pControl->setPreviewing(false); - pControl->setPreviewingPosition(-1); + pControl->setPreviewingPosition(Cue::kNoPosition); // If this is the last hotcue to leave preview. if (--m_iCurrentlyPreviewingHotcues == 0 && !m_bPreviewing) { @@ -784,8 +784,8 @@ void CueControl::hotcuePositionChanged(HotcueControl* pControl, double newPositi CuePointer pCue(pControl->getCue()); if (pCue) { - // Setting the position to -1 is the same as calling hotcue_x_clear - if (newPosition == -1) { + // Setting the position to Cue::kNoPosition is the same as calling hotcue_x_clear + if (newPosition == Cue::kNoPosition) { detachCue(pControl); } else if (newPosition > 0 && newPosition < m_pTrackSamples->get()) { pCue->setStartPosition(newPosition); @@ -808,7 +808,7 @@ void CueControl::hintReader(HintVector* pHintList) { // constructor and getPosition()->get() is a ControlObject for (const auto& pControl: m_hotcueControls) { double position = pControl->getPosition(); - if (position != -1) { + if (position != Cue::kNoPosition) { cue_hint.frame = SampleUtil::floorPlayPosToFrame(position); cue_hint.frameCount = Hint::kFrameCountForward; cue_hint.priority = 10; @@ -1494,7 +1494,7 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) } if (cueMode != CueMode::Denon && cueMode != CueMode::Numark) { - if (m_pCuePoint->get() != -1) { + if (m_pCuePoint->get() != Cue::kNoPosition) { if (newPlay == 0.0 && trackAt == TrackAt::ElseWhere) { if (cueMode == CueMode::Mixxx) { // in Mixxx mode Cue Button is flashing slow if CUE will move Cue point @@ -1590,7 +1590,7 @@ CueControl::TrackAt CueControl::getTrackAt() const { return TrackAt::End; } double cue = m_pCuePoint->get(); - if (cue != -1 && fabs(sot.current - cue) < 1.0f) { + if (cue != Cue::kNoPosition && fabs(sot.current - cue) < 1.0f) { return TrackAt::Cue; } return TrackAt::ElseWhere; @@ -1693,7 +1693,7 @@ HotcueControl::HotcueControl(QString group, int i) connect(m_hotcuePosition, &ControlObject::valueChanged, this, &HotcueControl::slotHotcuePositionChanged, Qt::DirectConnection); - m_hotcuePosition->set(-1); + m_hotcuePosition->set(Cue::kNoPosition); m_hotcueEnabled = new ControlObject(keyForControl(i, "enabled")); m_hotcueEnabled->setReadOnly(); @@ -1784,7 +1784,7 @@ void HotcueControl::slotHotcueClear(double v) { } void HotcueControl::slotHotcuePositionChanged(double newPosition) { - m_hotcueEnabled->forceSet(newPosition == -1 ? 0.0 : 1.0); + m_hotcueEnabled->forceSet(newPosition == Cue::kNoPosition ? 0.0 : 1.0); emit(hotcuePositionChanged(this, newPosition)); } From 28d5066485202f301a9e3ce577cf1f78287829a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 23 Oct 2019 23:51:32 +0200 Subject: [PATCH 160/198] Seek to start if the to deck is already behind the fade start of the transition after next. --- src/library/autodj/autodjprocessor.cpp | 41 ++++++++++++++++---------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 23cd94118d4..cb295f4831b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -641,7 +641,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (thisDeckPlaying || thisPlayPosition >= 1.0) { if (!otherDeckPlaying) { // Re-cue the track if the user has seeked it to the very end - if (otherDeck.playPosition() >= 1.0) { + if (otherDeck.playPosition() >= otherDeck.fadeBeginPos) { otherDeck.setPlayPosition(otherDeck.startPos); } otherDeck.play(); @@ -1039,14 +1039,18 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } double outroLength = outroEnd - outroStart; + double toDeckPosition = pToDeck->playPosition() * toTrackDuration; + pToDeck->fadeBeginPos = getOutroStartPosition(pToDeck); + double introStart; - if (seekToStartPoint || pToDeck->playPosition() >= 1) { - // pToDeck->playPosition() >= 1 happens when the user has seeked - // or played the track to the very end and forgets about it. + if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { + // toDeckPosition >= pToDeck->fadeBeginPos happens when the + // user has seeked or played the to track behind fadeBeginPos of + // the fade after the next. // In this case we recue the track just before the transition. introStart = getIntroStartPosition(pToDeck); } else { - introStart = pToDeck->playPosition() * toTrackDuration; + introStart = toDeckPosition; } double introEnd = getIntroEndPosition(pToDeck); @@ -1150,13 +1154,15 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, case TransitionMode::FixedSkipSilence: { double startPoint; - if (seekToStartPoint || pToDeck->playPosition() >= 1) { - // pToDeck->playPosition() >= 1 happens when the user has seeked - // or played the track to the very end and forgets about it. - // In this case we recue the track just before the transition. + pToDeck->fadeBeginPos = getLastSoundPosition(pToDeck); + if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { + // toDeckPosition >= pToDeck->fadeBeginPos happens when the + // user has seeked or played the to track behind fadeBeginPos of + // the fade after the next. + // In this case we recue the track just before the transition. startPoint = getFirstSoundPosition(pToDeck); } else { - startPoint = pToDeck->playPosition() * toTrackDuration; + startPoint = toDeckPosition; } useFixedFadeTime(pFromDeck, pToDeck, getLastSoundPosition(pFromDeck), @@ -1167,16 +1173,18 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, default: { double startPoint; - if (seekToStartPoint || pToDeck->playPosition() >= 1) { - // pToDeck->playPosition() >= 0 happens when the user has seeked - // or played the track to the very end and forgets about it. - // In this case we recue the track just before the transition. + pToDeck->fadeBeginPos = pToDeck->duration(); + if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { + // toDeckPosition >= pToDeck->fadeBeginPos happens when the + // user has seeked or played the to track behind fadeBeginPos of + // the fade after the next. + // In this case we recue the track just before the transition. startPoint = 0; } else { - startPoint = pToDeck->playPosition() * toTrackDuration; + startPoint = toDeckPosition; } useFixedFadeTime(pFromDeck, pToDeck, - getLastSoundPosition(pFromDeck), + pFromDeck->duration(), startPoint); } } @@ -1185,6 +1193,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeBeginPos /= fromTrackDuration; pFromDeck->fadeEndPos /= fromTrackDuration; pToDeck->startPos /= toTrackDuration; + pToDeck->fadeBeginPos /= toTrackDuration; pFromDeck->isFromDeck = true; pToDeck->isFromDeck = false; From d855e3786332f024cf53fd93bfbca953faead00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 24 Oct 2019 00:25:59 +0200 Subject: [PATCH 161/198] Use transition time when starting autoDJ with fromDeck behind the outro cue. --- src/library/autodj/autodjprocessor.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index cb295f4831b..d14e6c41158 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1030,6 +1030,8 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroEnd = getOutroEndPosition(pFromDeck); double outroStart = getOutroStartPosition(pFromDeck); + double fromDeckPosition = pFromDeck->playPosition() * pFromDeck->duration(); + if (outroStart <= 0.0) { // Assume a zero length outro. // The outroEnd is automatically placed by AnalyzerSilence, so use @@ -1037,6 +1039,14 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // not been placed, getOutroEndPosition will return the end of the track. outroStart = outroEnd; } + if (fromDeckPosition > outroStart) { + // We have already passed outroStart + // This can happen if we have just enabled auto DJ + outroStart = fromDeckPosition; + if (fromDeckPosition > outroEnd) { + outroEnd = math_min(outroStart + fabs(m_transitionTime), pFromDeck->duration()); + } + } double outroLength = outroEnd - outroStart; double toDeckPosition = pToDeck->playPosition() * toTrackDuration; From 0663bab0690bc13d79ec80b1651d84e7132651a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 24 Oct 2019 01:00:20 +0200 Subject: [PATCH 162/198] Improve comments --- src/library/autodj/autodjprocessor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index d14e6c41158..180a09624cf 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1050,6 +1050,10 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroLength = outroEnd - outroStart; double toDeckPosition = pToDeck->playPosition() * toTrackDuration; + // Store here a possible fadeBeginPos for the transition after next + // This is used to check if it will be possible or a re-cue is required. + // here it is done for FullIntroOutro and FadeAtOutroStart. + // It is adjusted below for the other modes. pToDeck->fadeBeginPos = getOutroStartPosition(pToDeck); double introStart; From eb2b0ba02bdd0796d88683b29cafa73e47d7845f Mon Sep 17 00:00:00 2001 From: Be Date: Thu, 24 Oct 2019 08:27:44 -0500 Subject: [PATCH 163/198] AutoDJProcessor: add debug assertion for fadeNow --- src/library/autodj/autodjprocessor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 23cd94118d4..b2551a39592 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -269,6 +269,11 @@ void AutoDJProcessor::fadeNow() { // The fade must end by the outro end at the latest. fadeTime = math_min(timeUntilIntroEnd, timeUntilOutroEnd); } else { + // If this is true, the fade should have already been started + // so the user should not have been able to press the Fade button. + VERIFY_OR_DEBUG_ASSERT(timeUntilOutroEnd > 0) { + timeUntilOutroEnd = 0; + } fadeTime = math_min(spinboxTime, timeUntilOutroEnd); } } else { From e53e9e537781d6785395885e76e055347e2f43d2 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Thu, 24 Oct 2019 20:00:55 +0200 Subject: [PATCH 164/198] add AutoDJ icons to LateNight --- .../buttons/btn_autodj_addrandom.svg | 1 + .../buttons/btn_autodj_enable_off.svg | 1 + .../buttons/btn_autodj_enable_on.svg | 1 + .../LateNight/buttons/btn_autodj_fade.svg | 1 + .../buttons/btn_autodj_fade_disabled.svg | 1 + .../btn_autodj_repeat_playlist_off.svg | 66 +------- .../buttons/btn_autodj_repeat_playlist_on.svg | 66 +------- .../LateNight/buttons/btn_autodj_shuffle.svg | 1 + .../LateNight/buttons/btn_autodj_skip.svg | 1 + .../buttons/btn_autodj_skip_disabled.svg | 1 + ...tor.svg => btn_border_image_qcombobox.svg} | 0 .../btn_border_image_qcombobox_focus.svg | 1 + ...n_border_image_qpushbutton_active_grey.svg | 1 + ...border_image_qpushbutton_checked_focus.svg | 1 + .../btn_border_image_qpushbutton_focus.svg | 1 + res/skins/LateNight/library.xml | 1 + res/skins/LateNight/style.qss | 141 +++++++++++++++--- 17 files changed, 139 insertions(+), 147 deletions(-) create mode 100644 res/skins/LateNight/buttons/btn_autodj_addrandom.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_enable_off.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_enable_on.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_fade.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_fade_disabled.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_shuffle.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_skip.svg create mode 100644 res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg rename res/skins/LateNight/buttons/{btn_border_image_weffectselector.svg => btn_border_image_qcombobox.svg} (100%) create mode 100644 res/skins/LateNight/buttons/btn_border_image_qcombobox_focus.svg create mode 100644 res/skins/LateNight/buttons/btn_border_image_qpushbutton_active_grey.svg create mode 100644 res/skins/LateNight/buttons/btn_border_image_qpushbutton_checked_focus.svg create mode 100644 res/skins/LateNight/buttons/btn_border_image_qpushbutton_focus.svg diff --git a/res/skins/LateNight/buttons/btn_autodj_addrandom.svg b/res/skins/LateNight/buttons/btn_autodj_addrandom.svg new file mode 100644 index 00000000000..32244fa965c --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_addrandom.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_autodj_enable_off.svg b/res/skins/LateNight/buttons/btn_autodj_enable_off.svg new file mode 100644 index 00000000000..307335a70e7 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_enable_off.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_autodj_enable_on.svg b/res/skins/LateNight/buttons/btn_autodj_enable_on.svg new file mode 100644 index 00000000000..b34b4165a53 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_enable_on.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_autodj_fade.svg b/res/skins/LateNight/buttons/btn_autodj_fade.svg new file mode 100644 index 00000000000..3a9c75ad84b --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_fade.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_autodj_fade_disabled.svg b/res/skins/LateNight/buttons/btn_autodj_fade_disabled.svg new file mode 100644 index 00000000000..366995bd74c --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_fade_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg index a51c483b930..39320f02603 100644 --- a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg +++ b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg @@ -1,65 +1 @@ - - - - - - image/svg+xml - - - - - - - - - - - - + diff --git a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg index 1bb45260402..24427bce20a 100644 --- a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg +++ b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_on.svg @@ -1,65 +1 @@ - - - - - - image/svg+xml - - - - - - - - - - - - + diff --git a/res/skins/LateNight/buttons/btn_autodj_shuffle.svg b/res/skins/LateNight/buttons/btn_autodj_shuffle.svg new file mode 100644 index 00000000000..8bf10ce2e88 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_shuffle.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_autodj_skip.svg b/res/skins/LateNight/buttons/btn_autodj_skip.svg new file mode 100644 index 00000000000..d3f0a083f33 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_skip.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg b/res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg new file mode 100644 index 00000000000..a4733443ede --- /dev/null +++ b/res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_border_image_weffectselector.svg b/res/skins/LateNight/buttons/btn_border_image_qcombobox.svg similarity index 100% rename from res/skins/LateNight/buttons/btn_border_image_weffectselector.svg rename to res/skins/LateNight/buttons/btn_border_image_qcombobox.svg diff --git a/res/skins/LateNight/buttons/btn_border_image_qcombobox_focus.svg b/res/skins/LateNight/buttons/btn_border_image_qcombobox_focus.svg new file mode 100644 index 00000000000..228441068e4 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_border_image_qcombobox_focus.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_border_image_qpushbutton_active_grey.svg b/res/skins/LateNight/buttons/btn_border_image_qpushbutton_active_grey.svg new file mode 100644 index 00000000000..38ddccdb5b7 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_border_image_qpushbutton_active_grey.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_border_image_qpushbutton_checked_focus.svg b/res/skins/LateNight/buttons/btn_border_image_qpushbutton_checked_focus.svg new file mode 100644 index 00000000000..3b5e31e3071 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_border_image_qpushbutton_checked_focus.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/buttons/btn_border_image_qpushbutton_focus.svg b/res/skins/LateNight/buttons/btn_border_image_qpushbutton_focus.svg new file mode 100644 index 00000000000..228441068e4 --- /dev/null +++ b/res/skins/LateNight/buttons/btn_border_image_qpushbutton_focus.svg @@ -0,0 +1 @@ + diff --git a/res/skins/LateNight/library.xml b/res/skins/LateNight/library.xml index 7f7316bd7fe..3e9f9a6acbf 100644 --- a/res/skins/LateNight/library.xml +++ b/res/skins/LateNight/library.xml @@ -75,6 +75,7 @@ #585858 #eece33 + false diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss index dc25bc2aac4..067fd0de0f7 100644 --- a/res/skins/LateNight/style.qss +++ b/res/skins/LateNight/style.qss @@ -166,6 +166,25 @@ WSearchLineEdit, border-image: url(skin:buttons/btn_border_image_qpushbutton.svg) 2 3 3 2; color: #bbb; } + #DlgMissing > QPushButton:focus, + #DlgHidden > QPushButton:focus, + #DlgAutoDJ > QPushButton:focus, + #DlgRecording > QPushButton:focus, + #DlgAnalysis > QPushButton:focus { + border-width: 2px 3px 3px 2px; + border-image: url(skin:buttons/btn_border_image_qpushbutton_focus.svg) 2 3 3 2; + outline: none; + } + #DlgAnalysis > QPushButton:checked:focus, + #DlgMissing > QPushButton:checked:focus, + #DlgHidden > QPushButton:checked:focus, + #DlgAutoDJ > QPushButton:checked:focus, + #DlgRecording > QPushButton:checked:focus, + #DlgAnalysis > QPushButton:checked:focus { + border-width: 2px 3px 3px 2px; + border-image: url(skin:buttons/btn_border_image_qpushbutton_checked_focus.svg) 2 3 3 2; + outline: none; + } #DlgMissing > QPushButton:pressed, #DlgHidden > QPushButton:pressed, #DlgAutoDJ > QPushButton:pressed, @@ -191,6 +210,10 @@ WSearchLineEdit, border-image: url(skin:buttons/btn_border_image_qpushbutton_active_red.svg) 2 3 3 2; color: #000; } + QPushButton#pushButtonRepeatPlaylist:checked { + border-image: url(skin:buttons/btn_border_image_qpushbutton_active_grey.svg) 2 3 3 2; + color: #000; + } WBeatSpinBox, #DlgAutoDJ QSpinBox { @@ -206,10 +229,15 @@ WBeatSpinBox, border-image: url(skin:buttons/btn_border_image_spinbox_focus.svg) 1 2 2 1; } -WEffectSelector { +WEffectSelector, +#fadeModeCombobox { border-width: 2px 3px 3px 2px; - border-image: url(skin:buttons/btn_border_image_weffectselector.svg) 2 3 3 2; -} + border-image: url(skin:buttons/btn_border_image_qcombobox.svg) 2 3 3 2; + } + #fadeModeCombobox:focus { + border-width: 2px 3px 3px 2px; + border-image: url(skin:buttons/btn_border_image_qcombobox_focus.svg) 2 3 3 2; + } #RecBox, #GuiToggleButton, @@ -467,7 +495,8 @@ QToolTip, WStarRating, WBeatSpinBox, #DlgAutoDJ QSpinBox, QTableView::indicator, -WEffectSelector, WEffectSelector QAbstractItemView +WEffectSelector, WEffectSelector QAbstractItemView, +#fadeModeCombobox, #fadeModeCombobox QAbstractItemView, #CategoryLabel, #SkinSettingsLabelButton, WSearchLineEdit:focus, #LatencyLabel, WTime { @@ -837,8 +866,9 @@ WBeatSpinBox, } #DlgAutoDJ QSpinBox { height: 22px; + width: 30px; padding: 0px 2px 0px 0px; - margin: 0px 0px 1px 19px; + margin: 0px 0px 1px 4px; } WBeatSpinBox::up-button, @@ -1473,7 +1503,8 @@ WBeatSpinBox, padding: 3px; } -WEffectSelector { +WEffectSelector, +#fadeModeCombobox { font-weight: bold; font-size: 12px/13px; text-transform: uppercase; @@ -1487,23 +1518,45 @@ WEffectSelector { /* The 3D frame on the combo box becomes flat when you give it a border border-radius: 3px; */ } - WEffectSelector::drop-down { + WEffectSelector::drop-down, + #fadeModeCombobox::drop-down { border: 0; } - WEffectSelector::down-arrow { + #fadeModeCombobox { /* */ + height: 20px; + padding: 0px 0px 0px 4px; + margin: 1px 2px 2px 4px; + } + WEffectSelector::down-arrow, + #fadeModeCombobox::down-arrow { image: url(skin:/buttons/btn_fx_selector.svg); border: 0; padding: 0; margin: 0; } - WEffectSelector::down-arrow:hover { + WEffectSelector::down-arrow:hover, + #fadeModeCombobox::down-arrow:hover { image: url(skin:/buttons/btn_fx_selector_pressed.svg); border: 0; padding: 0; margin: 0; } - WEffectSelector QAbstractItemView { + WEffectSelector QAbstractItemView, + #fadeModeCombobox QAbstractItemView { + background-color: #0f0f0f; + /* padding-left: 6px; */ + font-size: 12px/13px; + /* On Linux, this is not applied but font color from WEffectSelector + is inherited. + On Windows, it must be defined here */ + border: 1px solid #444; + border-radius: 2px; + padding: 0px; + margin: 0px; + } + WEffectSelector QAbstractItemView, + #fadeModeCombobox QAbstractItemView { width: 142px; background-color: #0f0f0f; /* padding-left: 6px; */ @@ -1517,7 +1570,8 @@ WEffectSelector { margin: 0px; } /* selected item */ - WEffectSelector::checked { + WEffectSelector::checked, + #fadeModeCombobox::checked { /* not applied padding-left: 5px; font-weight: bold; */ @@ -1527,7 +1581,8 @@ WEffectSelector { background-color: #1e1e1e; } /* hovered items */ - WEffectSelector::item:selected { + WEffectSelector::item:selected, + #fadeModeCombobox::item:selected { background-color: #333; /* Already of those two destroys font config and puts tick mark behind text: margin: 0px; @@ -1536,7 +1591,8 @@ WEffectSelector { text sits at left border now border: 0; */ } - WEffectSelector::indicator { + WEffectSelector::indicator, + #fadeModeCombobox::indicator { /* This is sufficient to completely hide the tick mark, but this alone would show an empty, shadowed box instead of tick mark background-color: transparent;*/ @@ -1968,7 +2024,7 @@ WLibrary QRadioButton { /* Additional space for QLabels */ WLibrary QLabel { - margin: 2px 3px 7px 3px; + margin: 2px 3px 5px 3px; } WLibrary QRadioButton::indicator:checked { @@ -1988,18 +2044,69 @@ WLibrary QRadioButton::indicator:unchecked { #DlgAutoDJ > QPushButton, #DlgRecording > QPushButton, #DlgAnalysis > QPushButton { - margin: 2px 4px 3px 2px; - padding: 3px 8px; - min-width: 65px; + margin: 1px 2px 3px 2px; + padding: 0px 3px; + min-width: 32px; + height: 20px; } + /* Focus highlight is set via border-image at the top */ /* Space in between 'Enable AutoDJ' and transition time spinbox */ QPushButton#pushButtonAutoDJ { + min-width: 40px; margin-left: 1px; + margin-right: 4px; + } + QPushButton#pushButtonFadeNow { + margin-left: 4px; + } + #DlgAutoDJ > #horizontalSpacer { + width: 100px; + background-color: green; } /* Space in between 'All' radio button and 'Select All' button */ QPushButton#pushButtonSelectAll { margin-left: 12px; } + + +/* AutoDJ button icons */ +QPushButton#pushButtonAutoDJ:!checked { + image: url(skin:/buttons/btn_autodj_enable_off.svg) no-repeat center center; + } + QPushButton#pushButtonAutoDJ:checked { + image: url(skin:/buttons/btn_autodj_enable_on.svg) no-repeat center center; + } + +QPushButton#pushButtonFadeNow:!enabled { + image: url(skin:/buttons/btn_autodj_fade_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonFadeNow:enabled { + image: url(skin:/buttons/btn_autodj_fade.svg) no-repeat center center; + } + +QPushButton#pushButtonSkipNext:!enabled { + image: url(skin:/buttons/btn_autodj_skip_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonSkipNext:enabled { + image: url(skin:/buttons/btn_autodj_skip.svg) no-repeat center center; + } + +QPushButton#pushButtonShuffle:enabled { + image: url(skin:/buttons/btn_autodj_shuffle.svg) no-repeat center center; +} + +QPushButton#pushButtonAddRandom:enabled { + image: url(skin:/buttons/btn_autodj_addrandom.svg) no-repeat center center; +} + +QPushButton#pushButtonRepeatPlaylist:!checked { + image: url(skin:/buttons/btn_autodj_repeat_playlist_off.svg) no-repeat center center; + } + QPushButton#pushButtonRepeatPlaylist:checked { + image: url(skin:/buttons/btn_autodj_repeat_playlist_on.svg) no-repeat center center; + } +/* AutoDJ button icons */ + /* triangle for closed/opened branches in treeview */ QTreeView { From 01f354ff74aec6753fbba13cb541979ed7567299 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 25 Oct 2019 00:08:34 +0200 Subject: [PATCH 165/198] add AutoDJ icons to Deere, and ... - make Pause icon as bright as CUE font when active - add focus border to library feature buttons --- res/skins/Deere/icon/ic_autodj_addrandom.svg | 1 + res/skins/Deere/icon/ic_autodj_enable.svg | 1 + res/skins/Deere/icon/ic_autodj_fade.svg | 1 + .../Deere/icon/ic_autodj_fade_disabled.svg | 1 + .../Deere/icon/ic_autodj_repeat_playlist.svg | 1 + res/skins/Deere/icon/ic_autodj_shuffle.svg | 1 + res/skins/Deere/icon/ic_autodj_skip.svg | 1 + .../Deere/icon/ic_autodj_skip_disabled.svg | 1 + res/skins/Deere/icon/ic_pause_48px.svg | 2 +- res/skins/Deere/library.xml | 1 + res/skins/Deere/style.qss | 127 +++++++++++++----- res/skins/LateNight/style.qss | 6 +- 12 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 res/skins/Deere/icon/ic_autodj_addrandom.svg create mode 100644 res/skins/Deere/icon/ic_autodj_enable.svg create mode 100644 res/skins/Deere/icon/ic_autodj_fade.svg create mode 100644 res/skins/Deere/icon/ic_autodj_fade_disabled.svg create mode 100644 res/skins/Deere/icon/ic_autodj_repeat_playlist.svg create mode 100644 res/skins/Deere/icon/ic_autodj_shuffle.svg create mode 100644 res/skins/Deere/icon/ic_autodj_skip.svg create mode 100644 res/skins/Deere/icon/ic_autodj_skip_disabled.svg diff --git a/res/skins/Deere/icon/ic_autodj_addrandom.svg b/res/skins/Deere/icon/ic_autodj_addrandom.svg new file mode 100644 index 00000000000..f73d4bb3810 --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_addrandom.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_autodj_enable.svg b/res/skins/Deere/icon/ic_autodj_enable.svg new file mode 100644 index 00000000000..4b1c4c8d5bb --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_enable.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_autodj_fade.svg b/res/skins/Deere/icon/ic_autodj_fade.svg new file mode 100644 index 00000000000..4b8ee208e5e --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_fade.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_autodj_fade_disabled.svg b/res/skins/Deere/icon/ic_autodj_fade_disabled.svg new file mode 100644 index 00000000000..366995bd74c --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_fade_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_autodj_repeat_playlist.svg b/res/skins/Deere/icon/ic_autodj_repeat_playlist.svg new file mode 100644 index 00000000000..1fa4ab812b5 --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_repeat_playlist.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_autodj_shuffle.svg b/res/skins/Deere/icon/ic_autodj_shuffle.svg new file mode 100644 index 00000000000..a933082001c --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_shuffle.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_autodj_skip.svg b/res/skins/Deere/icon/ic_autodj_skip.svg new file mode 100644 index 00000000000..9cddcde2802 --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_skip.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_autodj_skip_disabled.svg b/res/skins/Deere/icon/ic_autodj_skip_disabled.svg new file mode 100644 index 00000000000..a4733443ede --- /dev/null +++ b/res/skins/Deere/icon/ic_autodj_skip_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Deere/icon/ic_pause_48px.svg b/res/skins/Deere/icon/ic_pause_48px.svg index ffd5ea9eb67..3ea2966e3ce 100644 --- a/res/skins/Deere/icon/ic_pause_48px.svg +++ b/res/skins/Deere/icon/ic_pause_48px.svg @@ -1 +1 @@ - + diff --git a/res/skins/Deere/library.xml b/res/skins/Deere/library.xml index e6464a2671b..cb3bde4c7dd 100644 --- a/res/skins/Deere/library.xml +++ b/res/skins/Deere/library.xml @@ -63,6 +63,7 @@ + false diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss index 0613c145a46..cd1657f9de3 100644 --- a/res/skins/Deere/style.qss +++ b/res/skins/Deere/style.qss @@ -536,13 +536,29 @@ WLibrary QRadioButton::indicator:unchecked { #DlgRecording > QPushButton, #DlgAnalysis > QPushButton { margin: 9px 3px 6px 3px; - padding: 4px; color: #D2D2D2; background-color: #4B4B4B; - border: 0px solid #4B4B4B; + border: 1px solid #4B4B4B; border-radius: 2px; - outline: none; -} + outline: none; + } + #DlgMissing > QPushButton, + #DlgHidden > QPushButton, + #DlgRecording > QPushButton, + #DlgAnalysis > QPushButton { + padding: 3px 4px; + } + #DlgAutoDJ > QPushButton { + padding: 0px 1px; + } + #DlgAutoDJ > QPushButton { + width: 34px; + height: 20px; + } + QPushButton#pushButtonAutoDJ { + width: 42px; + } + #DlgMissing > QPushButton:!enabled, #DlgHidden > QPushButton:!enabled, @@ -550,12 +566,10 @@ WLibrary QRadioButton::indicator:unchecked { #DlgAnalysis > QPushButton:!enabled { /* buttons in "disabled" (not click-able) state. They are nearly invisible by default QT palette, so style accordingly */ - margin: 9px 3px 6px 3px; - padding: 4px; color: #808080; /* Default #A3A3A3 -90L HSL*/ background-color: rgba(95, 95, 95, 127); - /* 50% #5F5F5F = RGBA#5F5F5F7F */ - border: 0px solid #5F5F5F; + /* 50% #5F5F5F = RGBA#5F5F5F7F */ + border: 1px solid rgba(95, 95, 95, 127); border-radius: 2px; outline: none; } @@ -565,12 +579,28 @@ WLibrary QRadioButton::indicator:unchecked { #DlgAutoDJ > QPushButton:hover, #DlgRecording > QPushButton:hover, #DlgAnalysis > QPushButton:hover { - margin: 9px 3px 6px 3px; - padding: 4px; color: #D2D2D2; background-color: #5F5F5F; - border: 0px solid #5F5F5F; - border-radius: 2px; + border: 1px solid #5F5F5F; + outline: none; +} + +#DlgMissing > QPushButton:focus, +#DlgHidden > QPushButton:focus, +#DlgAutoDJ > QPushButton:focus, +#DlgRecording > QPushButton:focus, +#DlgAnalysis > QPushButton:focus, +#fadeModeCombobox:focus, +#DlgAutoDJ QSpinBox:focus { + border: 1px solid #bbb; + outline: none; +} +#DlgMissing > QPushButton:checked:focus, +#DlgHidden > QPushButton:checked:focus, +#DlgAutoDJ > QPushButton:checked:focus, +#DlgRecording > QPushButton:checked:focus, +#DlgAnalysis > QPushButton:checked:focus { + border: 1px solid #d2d2d2; outline: none; } @@ -578,12 +608,9 @@ WLibrary QRadioButton::indicator:unchecked { #DlgRecording > QPushButton:checked, #DlgAnalysis > QPushButton:checked { /* checkbuttons in active state */ - margin: 9px 3px 6px 3px; - padding: 4px; color: #FDFDFD; background-color: #006596; - border: 0px solid #006596; - border-radius: 2px; + border: 1px solid #006596; outline: none; } @@ -592,11 +619,9 @@ WLibrary QRadioButton::indicator:unchecked { #DlgAnalysis > QPushButton:checked:hover { /* checkbuttons hovered over in "active" state */ margin: 9px 3px 6px 3px; - padding: 4px; color: #FDFDFD; background-color: #0080BE; - border: 0px solid #0080BE; - border-radius: 2px; + border: 1px solid #0080BE; outline: none; } @@ -606,11 +631,9 @@ WLibrary QRadioButton::indicator:unchecked { #DlgAnalysis > QPushButton:pressed { /* pushbuttons in "down" state */ margin: 9px 3px 6px 3px; - padding: 4px; color: #FDFDFD; background-color: #006596; - border: 0px solid #006596; - border-radius: 2px; + border: 1px solid #006596; outline: none; } @@ -624,6 +647,33 @@ WLibrary QRadioButton::indicator:unchecked { } +/* AutoDJ button icons */ +QPushButton#pushButtonAutoDJ { + image: url(skin:/icon/ic_autodj_enable.svg) no-repeat center center; +} +QPushButton#pushButtonFadeNow:!enabled { + image: url(skin:/icon/ic_autodj_fade_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonFadeNow:enabled { + image: url(skin:/icon/ic_autodj_fade.svg) no-repeat center center; + } +QPushButton#pushButtonSkipNext:!enabled { + image: url(skin:/icon/ic_autodj_skip_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonSkipNext:enabled { + image: url(skin:/icon/ic_autodj_skip.svg) no-repeat center center; + } +QPushButton#pushButtonShuffle { + image: url(skin:/icon/ic_autodj_shuffle.svg) no-repeat center center; +} +QPushButton#pushButtonAddRandom { + image: url(skin:/icon/ic_autodj_addrandom.svg) no-repeat center center; +} +QPushButton#pushButtonRepeatPlaylist { + image: url(skin:/icon/ic_autodj_repeat_playlist.svg) no-repeat center center; +} +/* AutoDJ button icons */ + /* Scroll bars */ QScrollBar:horizontal { border-top: 1px solid #141414; @@ -1135,56 +1185,65 @@ WBeatSpinBox, image: url(skin:/icon/ic_power_48px.svg) no-repeat center center; } -WEffectSelector { +WEffectSelector, +#fadeModeCombobox { color: #c1cabe; background-color: #444342; /* TODO: use a linear gradient for the background color */ - /* Fixes the white bars on the top/bottom of the popup on Mac OS X */ margin-top: 0px; margin-bottom: 0px; - /* If you use margin top/bottom 0, the combo box shrinks in width (go figure) and * names start getting cut off. Adding explicit padding improves this. */ padding: 0px 6px; - /* The 3D frame on the combo box becomes flat when you give it a border */ border: 1px solid #444342; border-radius: 3px; - font: 15px; } +#fadeModeCombobox { + /* 1px is added in each dimension. 20+1+1 = 22 = button height */ + height: 20px; + margin: 9px 3px 6px 3px; +} - WEffectSelector:hover { + WEffectSelector:hover, + #fadeModeCombobox:hover { border: 1px ridge #015d8d; } - WEffectSelector::drop-down { + WEffectSelector::drop-down, + #fadeModeCombobox::drop-down { /* This causes the Qt theme's widget style to magically not apply. Go figure. */ border: 0; } - WEffectSelector::down-arrow { + WEffectSelector::down-arrow, + #fadeModeCombobox::down-arrow { width: 20px; height: 20px; image: url(skin:/icon/ic_chevron_down_48px.svg); } - WEffectSelector QAbstractItemView { + WEffectSelector QAbstractItemView, + #fadeModeCombobox QAbstractItemView { color: #c1cabe; background-color: #201f1f; } - WEffectSelector::item:!selected { + WEffectSelector::item:!selected, + #fadeModeCombobox::item:!selected { background-color: #201f1f; } - WEffectSelector::item:selected { + WEffectSelector::item:selected, + #fadeModeCombobox::item:selected { background-color: #080808; } /* currently loaded effect */ - WEffectSelector::checked { + WEffectSelector::checked, + #fadeModeCombobox::checked { color: #4495F4; font-weight: bold; } diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss index 067fd0de0f7..a4d210d1a3a 100644 --- a/res/skins/LateNight/style.qss +++ b/res/skins/LateNight/style.qss @@ -2067,7 +2067,7 @@ WLibrary QRadioButton::indicator:unchecked { QPushButton#pushButtonSelectAll { margin-left: 12px; } - + /* AutoDJ button icons */ QPushButton#pushButtonAutoDJ:!checked { @@ -2108,11 +2108,11 @@ QPushButton#pushButtonRepeatPlaylist:!checked { /* AutoDJ button icons */ -/* triangle for closed/opened branches in treeview */ QTreeView { show-decoration-selected: 0; - background-color: #151515; + background-color: #0f0f0f; } + /* triangle for closed/opened branches in treeview */ /* Suppresses that selected sidebar items branch indicator shows wrong color when out of focus ; lp:880588 */ QTreeView::branch:has-children:!has-siblings:closed, QTreeView::branch:closed:has-children:has-siblings { From 207652062009e6d1d7668d600d45d318f3426397 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 25 Oct 2019 15:05:10 +0200 Subject: [PATCH 166/198] add AutoDJ icons to Shade, adapt AutoDJ controls to color schemes --- res/skins/Shade/btn/btn_autodj_addrandom.svg | 1 + res/skins/Shade/btn/btn_autodj_enable.svg | 1 + res/skins/Shade/btn/btn_autodj_fade.svg | 1 + .../Shade/btn/btn_autodj_fade_disabled.svg | 1 + .../Shade/btn/btn_autodj_repeat_playlist.svg | 1 + res/skins/Shade/btn/btn_autodj_shuffle.svg | 1 + res/skins/Shade/btn/btn_autodj_skip.svg | 1 + res/skins/Shade/btn/btn_autodj_skip_arrow.svg | 1 + .../Shade/btn/btn_autodj_skip_disabled.svg | 1 + res/skins/Shade/btn/btn_autodj_skip_x.svg | 1 + res/skins/Shade/skin.xml | 1 + res/skins/Shade/style.qss | 76 +++++++++++++++---- res/skins/Shade/style_dark.qss | 2 + res/skins/Shade/style_summer_sunset.qss | 2 + 14 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 res/skins/Shade/btn/btn_autodj_addrandom.svg create mode 100644 res/skins/Shade/btn/btn_autodj_enable.svg create mode 100644 res/skins/Shade/btn/btn_autodj_fade.svg create mode 100644 res/skins/Shade/btn/btn_autodj_fade_disabled.svg create mode 100644 res/skins/Shade/btn/btn_autodj_repeat_playlist.svg create mode 100644 res/skins/Shade/btn/btn_autodj_shuffle.svg create mode 100644 res/skins/Shade/btn/btn_autodj_skip.svg create mode 100644 res/skins/Shade/btn/btn_autodj_skip_arrow.svg create mode 100644 res/skins/Shade/btn/btn_autodj_skip_disabled.svg create mode 100644 res/skins/Shade/btn/btn_autodj_skip_x.svg diff --git a/res/skins/Shade/btn/btn_autodj_addrandom.svg b/res/skins/Shade/btn/btn_autodj_addrandom.svg new file mode 100644 index 00000000000..d5fad4230c1 --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_addrandom.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_enable.svg b/res/skins/Shade/btn/btn_autodj_enable.svg new file mode 100644 index 00000000000..a93ed8cb2d7 --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_enable.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_fade.svg b/res/skins/Shade/btn/btn_autodj_fade.svg new file mode 100644 index 00000000000..e806487457f --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_fade.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_fade_disabled.svg b/res/skins/Shade/btn/btn_autodj_fade_disabled.svg new file mode 100644 index 00000000000..1d3af4811a8 --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_fade_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_repeat_playlist.svg b/res/skins/Shade/btn/btn_autodj_repeat_playlist.svg new file mode 100644 index 00000000000..2425cdbcbfe --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_repeat_playlist.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_shuffle.svg b/res/skins/Shade/btn/btn_autodj_shuffle.svg new file mode 100644 index 00000000000..7447d931a50 --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_shuffle.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_skip.svg b/res/skins/Shade/btn/btn_autodj_skip.svg new file mode 100644 index 00000000000..a73157774e9 --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_skip.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_skip_arrow.svg b/res/skins/Shade/btn/btn_autodj_skip_arrow.svg new file mode 100644 index 00000000000..8da401e045c --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_skip_arrow.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_skip_disabled.svg b/res/skins/Shade/btn/btn_autodj_skip_disabled.svg new file mode 100644 index 00000000000..5e918ff81d4 --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_skip_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/btn/btn_autodj_skip_x.svg b/res/skins/Shade/btn/btn_autodj_skip_x.svg new file mode 100644 index 00000000000..751459b7fc8 --- /dev/null +++ b/res/skins/Shade/btn/btn_autodj_skip_x.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Shade/skin.xml b/res/skins/Shade/skin.xml index ef38da2b2ae..862fb678ba9 100644 --- a/res/skins/Shade/skin.xml +++ b/res/skins/Shade/skin.xml @@ -490,6 +490,7 @@ me,me + false diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss index 5dfb0c17ee5..03e94b2a8b8 100644 --- a/res/skins/Shade/style.qss +++ b/res/skins/Shade/style.qss @@ -70,11 +70,19 @@ WEffectSelector { background-color: #aab2b7; /* Fixes the white bars on the top/bottom of the popup on Mac OS X */ margin-top: 0px; - margin-bottom: 0px; - border: 1px solid #060613; padding-left: 3px; font: 13px; } +WEffectSelector { + border: 1px solid #060613; + margin-bottom: 0px; +} +#fadeModeCombobox { + height: 18px; + border: 1px solid #99A0A4; + margin-bottom: 2px; + margin-left: 10px; +} #fadeModeCombobox::drop-down, WEffectSelector::drop-down { @@ -91,27 +99,21 @@ WEffectSelector::down-arrow { image: url(skin:/btn/btn_spin_down.png) no-repeat; } - -#fadeModeCombobox { - height: 20px; - background-color: #99a0a4; - border: 1px solid #191919; - margin-bottom: 2px; - margin-left: 10px; -} - -WEffectSelector QAbstractItemView { +WEffectSelector QAbstractItemView, +#fadeModeCombobox QAbstractScrollArea { color: #060613; background-color: #aab2b7; border: 2px solid #060613; selection-background-color: lightgray; } -WEffectSelector::item:selected { +WEffectSelector::item:selected, +#fadeModeCombobox::item:selected { background-color: lightgray; } -WEffectSelector::checked { +WEffectSelector::checked, +#fadeModeCombobox::checked { color: #EC4522; } @@ -421,9 +423,10 @@ The general rule when it comes to stylesheets is always to remember that if you QSpinBox:editable, /* or addressed directly */ #spinBoxTransition { - height: 20px; - border: 1px solid #191919; + height: 18px; + border: 1px solid #99A0A4; background-color: #99a0a4; + margin-left: 3px; } /* Cover Art*/ @@ -483,6 +486,15 @@ WLibrary QPushButton { background-position: center; border: 1px solid #99A0A4; } + #DlgAutoDJ > QPushButton { + padding: 0px; + width: 32px; + height: 18px; + } + QPushButton#pushButtonAutoDJ { + width: 40px; + } + WLibrary QPushButton:!enabled { background-color: #72777A; border: 1px solid #72777A; @@ -495,6 +507,12 @@ WLibrary QPushButton { color: #000; background-color: #F90562; } + WLibrary QPushButton:focus, + #fadeModeCombobox:focus, + #spinBoxTransition:focus { + outline: none; + border-color: #fff; + } /* Hover highlight for action buttons */ QPushButton#pushButtonAutoDJ:hover, QPushButton#pushButtonRecording:hover, @@ -517,6 +535,32 @@ WLibrary QPushButton { QPushButton#pushButtonSelectAll { margin: 1px 2px 3px 10px; } +/* AutoDJ button icons */ +QPushButton#pushButtonAutoDJ { + image: url(skin:/btn/btn_autodj_enable.svg) no-repeat center center; +} +QPushButton#pushButtonFadeNow:!enabled { + image: url(skin:/btn/btn_autodj_fade_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonFadeNow:enabled { + image: url(skin:/btn/btn_autodj_fade.svg) no-repeat center center; + } +QPushButton#pushButtonSkipNext:!enabled { + image: url(skin:/btn/btn_autodj_skip_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonSkipNext:enabled { + image: url(skin:/btn/btn_autodj_skip.svg) no-repeat center center; + } +QPushButton#pushButtonShuffle { + image: url(skin:/btn/btn_autodj_shuffle.svg) no-repeat center center; +} +QPushButton#pushButtonAddRandom { + image: url(skin:/btn/btn_autodj_addrandom.svg) no-repeat center center; +} +QPushButton#pushButtonRepeatPlaylist { + image: url(skin:/btn/btn_autodj_repeat_playlist.svg) no-repeat center center; +} +/* AutoDJ button icons */ /* Hotcue Color: No Color */ #HotcueButton[highlight="0"] { diff --git a/res/skins/Shade/style_dark.qss b/res/skins/Shade/style_dark.qss index be76cb062bc..fda2ce766cb 100644 --- a/res/skins/Shade/style_dark.qss +++ b/res/skins/Shade/style_dark.qss @@ -4,6 +4,8 @@ WBeatSpinBox { background-color: #717171; } +#fadeModeCombobox, +#spinBoxTransition, WEffectSelector { color: #000000; background-color: #717171; diff --git a/res/skins/Shade/style_summer_sunset.qss b/res/skins/Shade/style_summer_sunset.qss index 7e00d1ba503..903adc42713 100644 --- a/res/skins/Shade/style_summer_sunset.qss +++ b/res/skins/Shade/style_summer_sunset.qss @@ -4,6 +4,8 @@ WBeatSpinBox { background-color: #ad9e4f; } +#fadeModeCombobox, +#spinBoxTransition, WEffectSelector { color: #101307; background-color: #ad9e4f; From 8757fdf283ab91875af92a2e6c6749f19472926b Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 25 Oct 2019 16:39:21 +0200 Subject: [PATCH 167/198] add AutoDJ icons to Tango --- .../Tango/buttons/btn_autodj_addrandom.svg | 1 + .../Tango/buttons/btn_autodj_enable_off.svg | 1 + .../Tango/buttons/btn_autodj_enable_on.svg | 1 + res/skins/Tango/buttons/btn_autodj_fade.svg | 1 + .../buttons/btn_autodj_fade_disabled.svg | 1 + .../btn_autodj_repeat_playlist_off.svg | 1 + .../buttons/btn_autodj_repeat_playlist_on.svg | 1 + .../Tango/buttons/btn_autodj_shuffle.svg | 1 + res/skins/Tango/buttons/btn_autodj_skip.svg | 1 + .../buttons/btn_autodj_skip_disabled.svg | 1 + res/skins/Tango/library.xml | 1 + res/skins/Tango/style.qss | 129 ++++++++++++++---- 12 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 res/skins/Tango/buttons/btn_autodj_addrandom.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_enable_off.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_enable_on.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_fade.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_fade_disabled.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_repeat_playlist_off.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_repeat_playlist_on.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_shuffle.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_skip.svg create mode 100644 res/skins/Tango/buttons/btn_autodj_skip_disabled.svg diff --git a/res/skins/Tango/buttons/btn_autodj_addrandom.svg b/res/skins/Tango/buttons/btn_autodj_addrandom.svg new file mode 100644 index 00000000000..f73d4bb3810 --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_addrandom.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_enable_off.svg b/res/skins/Tango/buttons/btn_autodj_enable_off.svg new file mode 100644 index 00000000000..4b1c4c8d5bb --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_enable_off.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_enable_on.svg b/res/skins/Tango/buttons/btn_autodj_enable_on.svg new file mode 100644 index 00000000000..ca3dedd4445 --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_enable_on.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_fade.svg b/res/skins/Tango/buttons/btn_autodj_fade.svg new file mode 100644 index 00000000000..4b8ee208e5e --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_fade.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_fade_disabled.svg b/res/skins/Tango/buttons/btn_autodj_fade_disabled.svg new file mode 100644 index 00000000000..366995bd74c --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_fade_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_repeat_playlist_off.svg b/res/skins/Tango/buttons/btn_autodj_repeat_playlist_off.svg new file mode 100644 index 00000000000..1fa4ab812b5 --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_repeat_playlist_off.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_repeat_playlist_on.svg b/res/skins/Tango/buttons/btn_autodj_repeat_playlist_on.svg new file mode 100644 index 00000000000..2ce9811c3ed --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_repeat_playlist_on.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_shuffle.svg b/res/skins/Tango/buttons/btn_autodj_shuffle.svg new file mode 100644 index 00000000000..a933082001c --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_shuffle.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_skip.svg b/res/skins/Tango/buttons/btn_autodj_skip.svg new file mode 100644 index 00000000000..21a7f07ab35 --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_skip.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/buttons/btn_autodj_skip_disabled.svg b/res/skins/Tango/buttons/btn_autodj_skip_disabled.svg new file mode 100644 index 00000000000..fdcce0d1725 --- /dev/null +++ b/res/skins/Tango/buttons/btn_autodj_skip_disabled.svg @@ -0,0 +1 @@ + diff --git a/res/skins/Tango/library.xml b/res/skins/Tango/library.xml index 2581d3521e1..f563731cab3 100644 --- a/res/skins/Tango/library.xml +++ b/res/skins/Tango/library.xml @@ -95,6 +95,7 @@ Description: #585858 #eece33 + false diff --git a/res/skins/Tango/style.qss b/res/skins/Tango/style.qss index 02b1f9efa3b..9e175df7672 100644 --- a/res/skins/Tango/style.qss +++ b/res/skins/Tango/style.qss @@ -1135,7 +1135,7 @@ WBeatSpinBox, /* Note(ronso0): Individual padding/margin in AutoDJ feature */ padding: -1px 3px -1px 3px; - margin: 0px 17px 3px 7px; + margin: 0px 17px 3px 3px; } WBeatSpinBox:hover, #DlgAutoDJ QSpinBox:hover { @@ -1664,10 +1664,13 @@ decks, samplers, mic, aux, fx */ font-size: 13px/12px; } - WEffectSelector { + WEffectSelector, + #fadeModeCombobox { font-size: 13px/13px; /* On Linux this is applied to both effect name and effect list. */ color: #ccc; + } + WEffectSelector { /* Fixes the white bars on the top/bottom of the popup on Mac OS X */ margin: 0px; /* If you use margin top/bottom 0, the combo box shrinks in width (go figure) and @@ -1677,16 +1680,26 @@ decks, samplers, mic, aux, fx */ border: 0px solid transparent; border-radius: 3px; background-color: #1e1e1e; - } + } + #fadeModeCombobox { + background-color: #333; + border: 1px solid #333; + margin: 0px 0px 2px 1px; + padding: 1px 3px; + border-radius: 2px; + height: 20px; + } WEffectSelector:hover { background-color: #0f0f0f; } - WEffectSelector::drop-down { + WEffectSelector::drop-down, + #fadeModeCombobox::drop-down { border: 0px; margin: 0px -2px 0px 0px; padding: 0px; } - WEffectSelector::down-arrow { + WEffectSelector::down-arrow, + #fadeModeCombobox::down-arrow { /* When the skin is scaled, bg-color would be applied to the (not scaled) button image only: background-color: #101010; @@ -1694,11 +1707,13 @@ decks, samplers, mic, aux, fx */ height: 20px; */ image: url(skin:/buttons/btn_fx_selector_list.svg) no-repeat center center; } - WEffectSelector::down-arrow:hover { + WEffectSelector::down-arrow:hover, + #fadeModeCombobox::down-arrow:hover { image: url(skin:/buttons/btn_fx_selector_list_hover.svg) no-repeat center center; } - WEffectSelector QAbstractItemView { + WEffectSelector QAbstractItemView, + #fadeModeCombobox QAbstractItemView { background-color: #202020; selection-background-color: #0f0f0f; /* On Linux, this is not applied but font color from WEffectSelector @@ -1709,18 +1724,21 @@ decks, samplers, mic, aux, fx */ margin: 0px; } /* items */ - WEffectSelector::item:!selected { + WEffectSelector::item:!selected, + #fadeModeCombobox::item:!selected { background-color: #202020; } /* hovered items */ - WEffectSelector::item:selected { + WEffectSelector::item:selected, + #fadeModeCombobox:item:selected { background-color: #0f0f0f; /* This moves the tick mark behind item text, text sits at left border now. Drawback: font size is not scaled with skin anymore. magic! border: 0; */ } /* selected item */ - WEffectSelector::checked { + WEffectSelector::checked, + #fadeModeCombobox::checked { /* not applied padding-left: 5px; font-weight: bold; @@ -1728,7 +1746,8 @@ decks, samplers, mic, aux, fx */ color: #0081B7; } /* tick mark frame */ - WEffectSelector::indicator:checked { + WEffectSelector::indicator:checked, + #fadeModeCombobox::indicator:checked { /* This is sufficient to completely hide the tick mark, but this alone would show an empty, shadowed box instead of tick mark: */ background-color: transparent; @@ -1745,7 +1764,8 @@ decks, samplers, mic, aux, fx */ background: #0081B7; */ image: url(skin:/buttons/btn_skinsettings_close.svg) no-repeat center center; } - WEffectSelector::indicator:!checked { + WEffectSelector::indicator:!checked, + #fadeModeCombobox::indicator:!checked { image: url(skin:/buttons/btn_.svg) no-repeat center center; background-color: #202020; } @@ -2440,10 +2460,20 @@ WLibrary QPushButton { background-color: #333; background-position: center; } + #DlgAutoDJ > QPushButton { + padding: 1px 2px; + height: 20px; + min-width: 32px; + } + #pushButtonAutoDJ { + width: 42px; + } + WLibrary QPushButton:!enabled { color: #888; } - WLibrary QPushButton:hover { + WLibrary QPushButton:hover, + #fadeModeCombobox:hover { border: 1px solid #888; } WLibrary QPushButton:unchecked { @@ -2455,8 +2485,36 @@ WLibrary QPushButton { background-color: #ff7b00; } WLibrary QPushButton:checked:hover { - border: 1px solid #ff3f00; + border: 1px solid #fff; } + QPushButton#pushButtonRecording:unchecked { + color: #888; + background-color: #444; + border: 1px solid #444; + } + QPushButton#pushButtonAutoDJ:checked { + border: 1px solid #ff9900; + } + QPushButton#pushButtonRepeatPlaylist:checked { + background-color: #888; + border: 1px solid #bbb; + } + QPushButton#pushButtonRecording:unchecked:hover, + QPushButton#pushButtonRecording:checked { + color: #dddddd; + background-color: #a90000; + border: 1px solid #ca0000; + } + WLibrary QPushButton:focus, + #fadeModeCombobox:focus { + border: 1px solid #bbb; + outline: none; + } + WLibrary QPushButton:checked:focus + #pushButtonAutoDJ:checked:focus, + #pushButtonRepeatPlaylist:checked:focus { + border: 1px solid #fff; + } /* make library action buttons bold */ QPushButton#pushButtonAutoDJ, QPushButton#pushButtonRecording, @@ -2471,7 +2529,6 @@ WLibrary QPushButton { QPushButton#pushButtonAnalyze:hover { border: 1px solid #ff6600; } - /* Increased margin for action buttons */ QPushButton#pushButtonAutoDJ, QPushButton#pushButtonRecording { @@ -2480,21 +2537,43 @@ WLibrary QPushButton { QPushButton#btnPurge { margin: 1px 1px 4px 5px; } - QPushButton#pushButtonRecording:unchecked { - color: #888; - background-color: #444; - border: 1px solid #444; + +/* AutoDJ button icons */ +QPushButton#pushButtonAutoDJ:!checked { + image: url(skin:/buttons/btn_autodj_enable_off.svg) no-repeat center center; } - QPushButton#pushButtonRecording:unchecked:hover, - QPushButton#pushButtonRecording:checked { - color: #dddddd; - background-color: #a90000; - border: 1px solid #ca0000; + QPushButton#pushButtonAutoDJ:checked { + image: url(skin:/buttons/btn_autodj_enable_on.svg) no-repeat center center; + } +QPushButton#pushButtonFadeNow:!enabled { + image: url(skin:/buttons/btn_autodj_fade_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonFadeNow:enabled { + image: url(skin:/buttons/btn_autodj_fade.svg) no-repeat center center; + } +QPushButton#pushButtonSkipNext:!enabled { + image: url(skin:/buttons/btn_autodj_skip_disabled.svg) no-repeat center center; + } + QPushButton#pushButtonSkipNext:enabled { + image: url(skin:/buttons/btn_autodj_skip.svg) no-repeat center center; + } +QPushButton#pushButtonShuffle { + image: url(skin:/buttons/btn_autodj_shuffle.svg) no-repeat center center; +} +QPushButton#pushButtonAddRandom { + image: url(skin:/buttons/btn_autodj_addrandom.svg) no-repeat center center; +} +QPushButton#pushButtonRepeatPlaylist:!checked { + image: url(skin:/buttons/btn_autodj_repeat_playlist_off.svg) no-repeat center center; + } + QPushButton#pushButtonRepeatPlaylist:checked { + image: url(skin:/buttons/btn_autodj_repeat_playlist_on.svg) no-repeat center center; } +/* AutoDJ button icons */ /* align/center AutoDJ transition label vertically with spinbox */ QLabel#labelTransitionAppendix { - margin: 0px 0px 5px 2px; + margin: 0px 0px 5px 0px; } /* Push labels away from buttons at the right */ /* AutoDJ selection info */ From 0d027835f81e876ffefa19250f08950d39d13426 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 25 Oct 2019 16:46:07 +0200 Subject: [PATCH 168/198] brighter AutoDJ icons in LateNight --- res/skins/LateNight/buttons/btn_autodj_addrandom.svg | 2 +- res/skins/LateNight/buttons/btn_autodj_enable_off.svg | 2 +- res/skins/LateNight/buttons/btn_autodj_fade.svg | 2 +- res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg | 2 +- res/skins/LateNight/buttons/btn_autodj_shuffle.svg | 2 +- res/skins/LateNight/buttons/btn_autodj_skip.svg | 2 +- res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/res/skins/LateNight/buttons/btn_autodj_addrandom.svg b/res/skins/LateNight/buttons/btn_autodj_addrandom.svg index 32244fa965c..bd7cdbe8d68 100644 --- a/res/skins/LateNight/buttons/btn_autodj_addrandom.svg +++ b/res/skins/LateNight/buttons/btn_autodj_addrandom.svg @@ -1 +1 @@ - + diff --git a/res/skins/LateNight/buttons/btn_autodj_enable_off.svg b/res/skins/LateNight/buttons/btn_autodj_enable_off.svg index 307335a70e7..39c89a701eb 100644 --- a/res/skins/LateNight/buttons/btn_autodj_enable_off.svg +++ b/res/skins/LateNight/buttons/btn_autodj_enable_off.svg @@ -1 +1 @@ - + diff --git a/res/skins/LateNight/buttons/btn_autodj_fade.svg b/res/skins/LateNight/buttons/btn_autodj_fade.svg index 3a9c75ad84b..f6c0f66e100 100644 --- a/res/skins/LateNight/buttons/btn_autodj_fade.svg +++ b/res/skins/LateNight/buttons/btn_autodj_fade.svg @@ -1 +1 @@ - + diff --git a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg index 39320f02603..f3d2a36df70 100644 --- a/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg +++ b/res/skins/LateNight/buttons/btn_autodj_repeat_playlist_off.svg @@ -1 +1 @@ - + diff --git a/res/skins/LateNight/buttons/btn_autodj_shuffle.svg b/res/skins/LateNight/buttons/btn_autodj_shuffle.svg index 8bf10ce2e88..678fe38b0d9 100644 --- a/res/skins/LateNight/buttons/btn_autodj_shuffle.svg +++ b/res/skins/LateNight/buttons/btn_autodj_shuffle.svg @@ -1 +1 @@ - + diff --git a/res/skins/LateNight/buttons/btn_autodj_skip.svg b/res/skins/LateNight/buttons/btn_autodj_skip.svg index d3f0a083f33..21a7f07ab35 100644 --- a/res/skins/LateNight/buttons/btn_autodj_skip.svg +++ b/res/skins/LateNight/buttons/btn_autodj_skip.svg @@ -1 +1 @@ - + diff --git a/res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg b/res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg index a4733443ede..fdcce0d1725 100644 --- a/res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg +++ b/res/skins/LateNight/buttons/btn_autodj_skip_disabled.svg @@ -1 +1 @@ - + From aea297c43b51c5259e4245141a35a7111a3d6c93 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 25 Oct 2019 16:46:33 +0200 Subject: [PATCH 169/198] new Skip icon in Deere --- res/skins/Deere/icon/ic_autodj_skip.svg | 2 +- res/skins/Deere/icon/ic_autodj_skip_disabled.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/skins/Deere/icon/ic_autodj_skip.svg b/res/skins/Deere/icon/ic_autodj_skip.svg index 9cddcde2802..21a7f07ab35 100644 --- a/res/skins/Deere/icon/ic_autodj_skip.svg +++ b/res/skins/Deere/icon/ic_autodj_skip.svg @@ -1 +1 @@ - + diff --git a/res/skins/Deere/icon/ic_autodj_skip_disabled.svg b/res/skins/Deere/icon/ic_autodj_skip_disabled.svg index a4733443ede..fdcce0d1725 100644 --- a/res/skins/Deere/icon/ic_autodj_skip_disabled.svg +++ b/res/skins/Deere/icon/ic_autodj_skip_disabled.svg @@ -1 +1 @@ - + From 4c7b35263128bd73a554e79a90aa3d75d523df25 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 25 Oct 2019 16:47:11 +0200 Subject: [PATCH 170/198] re-arrange AutoDJ controls, adapt skin stylesheets --- res/skins/Deere/style.qss | 11 +--- res/skins/LateNight/style.qss | 15 ++---- res/skins/Shade/style.qss | 11 +--- src/library/autodj/dlgautodj.ui | 90 ++++++++++++++++++++++----------- 4 files changed, 68 insertions(+), 59 deletions(-) diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss index cd1657f9de3..6b5a2c09e68 100644 --- a/res/skins/Deere/style.qss +++ b/res/skins/Deere/style.qss @@ -511,7 +511,7 @@ QTreeView::branch:open:!has-children:has-siblings:selected { WLibrary QLabel, WLibrary QRadioButton { /* same as QTreeview */ color: #d2d2d2; - margin: 9px 10px 6px 0px; + margin: 9px 5px 6px 0px; font-size: 12px; } @@ -637,15 +637,6 @@ WLibrary QRadioButton::indicator:unchecked { outline: none; } -/* Space in between 'Enable AutoDJ' and transition time spinbox */ -#DlgAutoDJ > QPushButton#pushButtonAutoDJ { - margin: 9px 12px 6px 3px; -} - -#DlgAutoDJ > QPushButton#pushButtonShuffle { - margin: 9px 3px 6px 12px; -} - /* AutoDJ button icons */ QPushButton#pushButtonAutoDJ { diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss index a4d210d1a3a..7caf3c2110a 100644 --- a/res/skins/LateNight/style.qss +++ b/res/skins/LateNight/style.qss @@ -868,7 +868,7 @@ WBeatSpinBox, height: 22px; width: 30px; padding: 0px 2px 0px 0px; - margin: 0px 0px 1px 4px; + margin: 0px 1px 1px 1px; } WBeatSpinBox::up-button, @@ -1514,7 +1514,7 @@ WEffectSelector, margin: 0px; /* If you use margin top/bottom 0, the combo box shrinks in width (go figure) and names start getting cut off. Adding explicit padding improves this. */ - padding: 4px 0px 4px 5px; + padding: 4px 0px 4px 2px; /* The 3D frame on the combo box becomes flat when you give it a border border-radius: 3px; */ } @@ -1525,7 +1525,7 @@ WEffectSelector, #fadeModeCombobox { /* */ height: 20px; padding: 0px 0px 0px 4px; - margin: 1px 2px 2px 4px; + margin: 1px 1px 2px 1px; } WEffectSelector::down-arrow, #fadeModeCombobox::down-arrow { @@ -2024,7 +2024,7 @@ WLibrary QRadioButton { /* Additional space for QLabels */ WLibrary QLabel { - margin: 2px 3px 5px 3px; + margin: 2px 5px 5px 1px; } WLibrary QRadioButton::indicator:checked { @@ -2044,7 +2044,7 @@ WLibrary QRadioButton::indicator:unchecked { #DlgAutoDJ > QPushButton, #DlgRecording > QPushButton, #DlgAnalysis > QPushButton { - margin: 1px 2px 3px 2px; + margin: 1px 1px 3px 1px; padding: 0px 3px; min-width: 32px; height: 20px; @@ -2053,11 +2053,6 @@ WLibrary QRadioButton::indicator:unchecked { /* Space in between 'Enable AutoDJ' and transition time spinbox */ QPushButton#pushButtonAutoDJ { min-width: 40px; - margin-left: 1px; - margin-right: 4px; - } - QPushButton#pushButtonFadeNow { - margin-left: 4px; } #DlgAutoDJ > #horizontalSpacer { width: 100px; diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss index 03e94b2a8b8..158e25eb970 100644 --- a/res/skins/Shade/style.qss +++ b/res/skins/Shade/style.qss @@ -80,8 +80,7 @@ WEffectSelector { #fadeModeCombobox { height: 18px; border: 1px solid #99A0A4; - margin-bottom: 2px; - margin-left: 10px; + margin: 0px 0px 2px 1px; } #fadeModeCombobox::drop-down, @@ -519,18 +518,10 @@ WLibrary QPushButton { QPushButton#pushButtonAnalyze:hover { border: 1px solid #F90562; } - /* Space in between 'Enable AutoDJ' button and transition time spinbox */ - QPushButton#pushButtonAutoDJ { - margin: 1px 12px 3px 1px; - } /* Space in between 'Recording' button and recording label */ QPushButton#pushButtonRecording { margin: 1px 6px 3px 1px; } - /* Space in between AutoDJ 'Fade'/'Skip' and 'Shuffle'/'Add Random' */ - QPushButton#pushButtonSkipNext { - margin: 1px 12px 3px 1px; - } /* Push 'Select All' button and away from radio buttons */ QPushButton#pushButtonSelectAll { margin: 1px 2px 3px 10px; diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui index d47312d6f67..817311adae5 100644 --- a/src/library/autodj/dlgautodj.ui +++ b/src/library/autodj/dlgautodj.ui @@ -62,6 +62,22 @@ + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 1 + + + + @@ -92,67 +108,83 @@ - + + + + - + 0 0 - Shuffle the content of the Auto DJ queue. + Determines the duration of the transition. - + false + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + -9 + - - - - 0 - 0 - - + - Adds a random track from track sources (crates) to the Auto DJ queue. -If no track sources are configured, the track is added from the library instead. + Seconds + + + sec. - + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 1 + + + - + - + 0 0 - Determines the duration of the transition. + Shuffle the content of the Auto DJ queue. - + false - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - -9 - - - - Seconds + + + + 0 + 0 + - - sec. + + Adds a random track from track sources (crates) to the Auto DJ queue. +If no track sources are configured, the track is added from the library instead. From 1fd1a04dda55078f9fb1acf8e6855c11f9a8a4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 25 Oct 2019 18:16:33 +0200 Subject: [PATCH 171/198] Use mode dependent pToDeck->fadeBeginPos for limiting the transition time in case of short tracks --- src/library/autodj/autodjprocessor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 9ca70378b98..851d6e13efb 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1231,15 +1231,17 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, if (m_transitionTime > 0.0) { // Guard against the next track being too short. This transition must finish // before the next transition starts. - double toDeckOutroStart = getOutroStartPosition(pToDeck); + double toDeckOutroStart = pToDeck->fadeBeginPos; if (toDeckOutroStart <= startPoint) { // we are already too late + // Check OutroEnd as alternative, which is for all transition mode + // better than directly default to duration() double end = getOutroEndPosition(pToDeck); if (end <= startPoint) { end = pToDeck->duration(); VERIFY_OR_DEBUG_ASSERT(end > startPoint) { // as last resort move start point - // The caller makes sures that this never happens + // The caller makes sure that this never happens startPoint = pToDeck->duration() - 1; } } From 010fd5cf847303549086eeb5dac9258eb9e24462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 26 Oct 2019 14:34:12 +0200 Subject: [PATCH 172/198] Fix auto dj stop issue in case of short tracks --- src/library/autodj/autodjprocessor.cpp | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 851d6e13efb..59145626715 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1116,7 +1116,19 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = introStart; } } else if (outroLength > 0 && introLength <= 0) { - pFromDeck->fadeBeginPos = outroStart; + if (outroLength + introStart < pToDeck->fadeBeginPos) { + pFromDeck->fadeBeginPos = outroStart; + } else { + // This happens if the toDeck track has no intro set and the + // outro of the fromDeck track is longer than the whole toDeck + // track + outroLength = pToDeck->fadeBeginPos - introStart; + VERIFY_OR_DEBUG_ASSERT(outroLength > 0) { + // We seek to intro start above in this case so this never happens + outroLength = 1; + } + pFromDeck->fadeBeginPos = outroEnd - outroLength; + } pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else if (introLength > 0 && outroLength <= 0) { @@ -1159,7 +1171,19 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } pToDeck->startPos = introStart; } else if (outroLength > 0 && introLength <= 0) { - pFromDeck->fadeBeginPos = outroStart; + if (outroLength + introStart < pToDeck->fadeBeginPos) { + pFromDeck->fadeBeginPos = outroStart; + } else { + // This happens if the toDeck track has no intro set and the + // outro of the fromDeck track is longer than the whole toDeck + // track + outroLength = pToDeck->fadeBeginPos - introStart; + VERIFY_OR_DEBUG_ASSERT(outroLength > 0) { + // We seek to intro start above in this case so this never happens + outroLength = 1; + } + pFromDeck->fadeBeginPos = outroEnd - outroLength; + } pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else if (introLength > 0 && outroLength <= 0) { From c1010a640820f28edfd0c7c55135d8adfe0d59e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 27 Oct 2019 15:49:59 +0100 Subject: [PATCH 173/198] make emitLoadTrackToPlayer and emitAutoDJStateChanged a protected non-slot --- src/library/autodj/autodjprocessor.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 50a0398bd5d..7c879f8fb87 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -196,15 +196,6 @@ class AutoDJProcessor : public QObject { void fadeNow(); AutoDJError toggleAutoDJ(bool enable); - // The following virtual signal wrappers are used for testing - virtual void emitLoadTrackToPlayer(TrackPointer pTrack, QString group, - bool play) { - emit(loadTrackToPlayer(pTrack, group, play)); - } - virtual void emitAutoDJStateChanged(AutoDJProcessor::AutoDJState state) { - emit(autoDJStateChanged(state)); - } - signals: void loadTrackToPlayer(TrackPointer pTrack, QString group, bool play); @@ -229,6 +220,16 @@ class AutoDJProcessor : public QObject { void controlShuffle(double value); void controlSkipNext(double value); + protected: + // The following virtual signal wrappers are used for testing + virtual void emitLoadTrackToPlayer(TrackPointer pTrack, QString group, + bool play) { + emit(loadTrackToPlayer(pTrack, group, play)); + } + virtual void emitAutoDJStateChanged(AutoDJProcessor::AutoDJState state) { + emit(autoDJStateChanged(state)); + } + private: // Gets or sets the crossfader position while normalizing it so that -1 is // all the way mixed to the left side and 1 is all the way mixed to the From cf658a9db2ff52038245a75046747c365d298759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 27 Oct 2019 18:10:24 +0100 Subject: [PATCH 174/198] move no outro start fallback code into getOutroStartPosition() --- src/library/autodj/autodjprocessor.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 59145626715..93c30f17bc0 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -932,7 +932,15 @@ double AutoDJProcessor::getIntroEndPosition(DeckAttributes* pDeck) { } double AutoDJProcessor::getOutroStartPosition(DeckAttributes* pDeck) { - return samplePositionToSeconds(pDeck->outroStartPosition(), pDeck); + double outroStart = samplePositionToSeconds(pDeck->outroStartPosition(), pDeck); + if (outroStart < 0.0) { + // Assume a zero length outro if outroStartIsNot set. + // The outroEnd is automatically placed by AnalyzerSilence, so use + // that as a fallback if the user has not placed outroStart. If it has + // not been placed, getOutroEndPosition will return the end of the track. + outroStart = getOutroEndPosition(pDeck); + } + return outroStart; } double AutoDJProcessor::getOutroEndPosition(DeckAttributes* pDeck) { @@ -1037,13 +1045,6 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroStart = getOutroStartPosition(pFromDeck); double fromDeckPosition = pFromDeck->playPosition() * pFromDeck->duration(); - if (outroStart <= 0.0) { - // Assume a zero length outro. - // The outroEnd is automatically placed by AnalyzerSilence, so use - // that as a fallback if the user has not placed outroStart. If it has - // not been placed, getOutroEndPosition will return the end of the track. - outroStart = outroEnd; - } if (fromDeckPosition > outroStart) { // We have already passed outroStart // This can happen if we have just enabled auto DJ From df296333f6c99a5edc6e42c2c988fbaa75ecc45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 27 Oct 2019 22:11:32 +0100 Subject: [PATCH 175/198] consider current position of the from deck after chaning the transition time --- src/library/autodj/autodjprocessor.cpp | 12 +++++++----- src/library/autodj/autodjprocessor.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 93c30f17bc0..59e78d7f431 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1137,7 +1137,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else { - useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); + useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, outroEnd, introStart); } break; case TransitionMode::FadeAtOutroStart: @@ -1192,7 +1192,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else { - useFixedFadeTime(pFromDeck, pToDeck, outroEnd, introStart); + useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, outroEnd, introStart); } break; case TransitionMode::FixedSkipSilence: @@ -1209,6 +1209,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, startPoint = toDeckPosition; } useFixedFadeTime(pFromDeck, pToDeck, + fromDeckPosition, getLastSoundPosition(pFromDeck), startPoint); } @@ -1228,6 +1229,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, startPoint = toDeckPosition; } useFixedFadeTime(pFromDeck, pToDeck, + fromDeckPosition, pFromDeck->duration(), startPoint); } @@ -1252,7 +1254,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, - DeckAttributes* pToDeck, double endPoint, double startPoint) { + DeckAttributes* pToDeck, double fromDeckPosition, double endPoint, double startPoint) { if (m_transitionTime > 0.0) { // Guard against the next track being too short. This transition must finish // before the next transition starts. @@ -1276,12 +1278,12 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, double transitionTime = math_min(toDeckOutroStart - startPoint, m_transitionTime); - pFromDeck->fadeBeginPos = endPoint - transitionTime; + pFromDeck->fadeBeginPos = math_max(endPoint - transitionTime, fromDeckPosition); pFromDeck->fadeEndPos = endPoint; pToDeck->startPos = startPoint; } else { pFromDeck->fadeBeginPos = endPoint; - pFromDeck->fadeEndPos = endPoint - m_transitionTime; + pFromDeck->fadeEndPos = endPoint; pToDeck->startPos = startPoint + m_transitionTime; } } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 7c879f8fb87..e9c7c597bd1 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -255,7 +255,7 @@ class AutoDJProcessor : public QObject { DeckAttributes* pToDeck, bool seekToStartPoint); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, - double endPoint, double startPoint); + double fromDeckPosition, double endPoint, double startPoint); DeckAttributes* getOtherDeck(const DeckAttributes* pFromDeck, bool playing = false); From 2b1f525724b31ead90a6891302991637a58f972d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 27 Oct 2019 23:28:57 +0100 Subject: [PATCH 176/198] fix AutoDJProcessorTest.FadeToDeck2_Long_Transition test. This fixes also a stalled autoDJ in caseof transition time exceedes track duration. --- src/library/autodj/autodjprocessor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 59e78d7f431..624f585bbfe 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1061,6 +1061,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // here it is done for FullIntroOutro and FadeAtOutroStart. // It is adjusted below for the other modes. pToDeck->fadeBeginPos = getOutroStartPosition(pToDeck); + pToDeck->fadeEndPos = getOutroEndPosition(pToDeck); double introStart; if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { @@ -1240,6 +1241,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->fadeEndPos /= fromTrackDuration; pToDeck->startPos /= toTrackDuration; pToDeck->fadeBeginPos /= toTrackDuration; + pToDeck->fadeEndPos /= toTrackDuration; pFromDeck->isFromDeck = true; pToDeck->isFromDeck = false; @@ -1259,6 +1261,10 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, // Guard against the next track being too short. This transition must finish // before the next transition starts. double toDeckOutroStart = pToDeck->fadeBeginPos; + if (pToDeck->fadeBeginPos >= pToDeck->fadeEndPos) { + // no outro defined, the toDeck will also use the transition time + toDeckOutroStart -= m_transitionTime; + } if (toDeckOutroStart <= startPoint) { // we are already too late // Check OutroEnd as alternative, which is for all transition mode From 5e6988ebb7e4a18f33ab1488c4ff3c55078f5d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 28 Oct 2019 08:15:27 +0100 Subject: [PATCH 177/198] Cache hasFadeTransition before possible override --- src/library/autodj/autodjprocessor.cpp | 30 ++++++++++---------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 624f585bbfe..3db98bd42fb 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -622,7 +622,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } if (m_eState == ADJ_IDLE) { - if (!thisDeckPlaying) { + if (!thisDeckPlaying && thisPlayPosition < 1) { // this is a cueing seek, recalculate the transition, from the // new position. // This can be our own seek to startPos or a random seek by a user. @@ -630,6 +630,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // If using the full track mode with a transition time of 0, // thisDeckPlaying will be false but the transition should not be // recalculated here. + // Don't adjust transition when reaching the end. In this case it is + // always stopped. calculateTransition(&otherDeck, &thisDeck, false); } else if (thisDeck.isRepeat()) { // repeat pauses auto DJ @@ -644,6 +646,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (thisPlayPosition >= thisDeck.fadeBeginPos && thisDeck.isFromDeck) { if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { + // cache this before calculating the new transition in otherDeck.play(); + bool hasFadeTransition = thisDeck.fadeBeginPos < thisDeck.fadeEndPos; if (!otherDeckPlaying) { // Re-cue the track if the user has seeked it to the very end if (otherDeck.playPosition() >= otherDeck.fadeBeginPos) { @@ -656,6 +660,12 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // that was "on deck" from the top of the queue. removeLoadedTrackFromTopOfQueue(otherDeck); + if (!hasFadeTransition) { + setCrossfader(thisDeck.isLeft() ? 1.0 : -1.0); + thisDeck.stop(); + loadNextTrackFromQueue(thisDeck); + return; + } m_transitionProgress = 0.0; // Set the state as FADING. m_eState = thisDeck.isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; @@ -685,24 +695,6 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, m_transitionProgress = 1.0; } else { // We are in Fading state. - - // The math below will not work with a transition time of 0. - if (thisDeck.fadeBeginPos == thisDeck.fadeEndPos) { - setCrossfader(crossfaderTarget); - m_transitionProgress = 1.0; - // Usually code above will take care of these steps when the - // playposition updates again, however this does not occur when - // using the Full Track mode with a fade time of 0 because the - // toDeck stops. - if (thisPlayPosition >= 1) { - otherDeck.play(); - loadNextTrackFromQueue(thisDeck); - m_eState = ADJ_IDLE; - emitAutoDJStateChanged(m_eState); - } - return; - } - // Calculate the current transitionProgress, the place between begin // and end position and the step we have taken since the last call double transitionProgress = (thisPlayPosition - thisDeck.fadeBeginPos) / From 74fdcb859482e21a03824e83535c84c27e6d5862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 28 Oct 2019 08:41:10 +0100 Subject: [PATCH 178/198] Adjust FadeToDeck2_Pause_Transition for no fading transitions --- src/test/autodjprocessor_test.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 44939b219fd..95ae2228fe6 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -1493,29 +1493,17 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - // Expect that we will transition into LEFT_FADING mode. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); + // Expect that we will request a track load on deck1. + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); // Seek track in deck1 to its end. deck1.playposition.set(1.0); - // We should have transitioned into LEFT_FADING. - EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - // Deck is still playing, because the crossfader is processed in the next audio // calback. - EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); + EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); - // Fake a final callback, normally in this case the engine - // stops the deck - deck1.play.set(0.0); - - // Expect that we will transition into IDLE mode and request a track load - // on deck1. - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); - EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); - // Advance track to the point where crossfading should be over. deck2.playposition.set(0.0); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); From 277f5da650aeaf978c3ef6a1269014a672e2af00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 28 Oct 2019 23:20:34 +0100 Subject: [PATCH 179/198] improve comments --- src/library/autodj/autodjprocessor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 3db98bd42fb..d045054d8ae 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -647,6 +647,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { // cache this before calculating the new transition in otherDeck.play(); + // thisDeck.fadeBeginPos is equal thisDeck.fadeEndPos in case of zero or + // negative transition time bool hasFadeTransition = thisDeck.fadeBeginPos < thisDeck.fadeEndPos; if (!otherDeckPlaying) { // Re-cue the track if the user has seeked it to the very end From 96a5a454e745e639d289b1e8670c4355a52a8f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 28 Oct 2019 23:34:58 +0100 Subject: [PATCH 180/198] improve error handing in case of -1 cue positions. --- src/library/autodj/autodjprocessor.cpp | 30 +++++++++++++++----------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index d045054d8ae..644154d88b2 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -948,31 +948,33 @@ double AutoDJProcessor::getOutroEndPosition(DeckAttributes* pDeck) { double AutoDJProcessor::getFirstSoundPosition(DeckAttributes* pDeck) { TrackPointer pTrack = pDeck->getLoadedTrack(); if (!pTrack) { - return 0; + return 0.0; } CuePointer pFromTrackAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); if (pFromTrackAudibleSound) { - return samplePositionToSeconds(pFromTrackAudibleSound->getPosition(), pDeck); - } else { - return 0; + double firstSound = pFromTrackAudibleSound->getPosition(); + if (firstSound > 0.0) { + return samplePositionToSeconds(firstSound, pDeck); + } } + return 0.0; } double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { TrackPointer pTrack = pDeck->getLoadedTrack(); if (!pTrack) { - return 0; + return 0.0; } CuePointer pFromTrackAudibleSound = pTrack->findCueByType(Cue::Type::AudibleSound); if (pFromTrackAudibleSound && pFromTrackAudibleSound->getLength() > 0) { - return samplePositionToSeconds( - pFromTrackAudibleSound->getPosition() + pFromTrackAudibleSound->getLength(), - pDeck); - } else { - return pDeck->duration(); + double lastSound = pFromTrackAudibleSound->getEndPosition(); + if (lastSound > 0) { + return samplePositionToSeconds(lastSound, pDeck); + } } + return pDeck->duration(); } double AutoDJProcessor::getMainCuePosition(DeckAttributes* pDeck) { @@ -983,10 +985,12 @@ double AutoDJProcessor::getMainCuePosition(DeckAttributes* pDeck) { CuePointer pMainCue = pTrack->findCueByType(Cue::Type::MainCue); if (pMainCue) { - return samplePositionToSeconds(pMainCue->getPosition(), pDeck); - } else { - return 0; + double mainCue = pMainCue->getPosition(); + if (mainCue > 0) { + return samplePositionToSeconds(mainCue, pDeck); + } } + return 0.0; } From 873e31395ee62e77d29cbd86607a24f1b358a9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 29 Oct 2019 23:22:15 +0100 Subject: [PATCH 181/198] improve crossfaderChanged() --- src/library/autodj/autodjprocessor.cpp | 85 ++++++++++++++++---------- src/library/autodj/autodjprocessor.h | 4 +- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 644154d88b2..8c6c6315757 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -497,26 +497,36 @@ void AutoDJProcessor::crossfaderChanged(double value) { // The user is changing the crossfader manually. If the user has // moved it all the way to the other side, make the deck faded away // from the new "to deck" by loading the next track into it. - DeckAttributes* leftDeck = m_decks.at(0); - DeckAttributes* rightDeck = m_decks.at(1); - DeckAttributes* newToDeck = nullptr; - DeckAttributes* newFromDeck = nullptr; + DeckAttributes* fromDeck = getFromDeck(); + VERIFY_OR_DEBUG_ASSERT(fromDeck) { + // we have always a from deck in case of state IDLE + return; + } - double crossfaderPosition = value * (m_pCOCrossfaderReverse->toBool() ? -1 : 1); - if (crossfaderPosition == 1.0 && leftDeck->isFromDeck) { // crossfader right - newFromDeck = rightDeck; - newToDeck = leftDeck; - } else if (crossfaderPosition == -1.0 && rightDeck->isFromDeck) { // crossfader left - newFromDeck = leftDeck; - newToDeck = rightDeck; + DeckAttributes* toDeck = getOtherDeck(fromDeck); + VERIFY_OR_DEBUG_ASSERT(toDeck) { + // we have always a from deck in case of state IDLE + return; } - if (newToDeck != nullptr && newFromDeck != nullptr) { - newToDeck->stop(); - removeLoadedTrackFromTopOfQueue(*newFromDeck); - loadNextTrackFromQueue(*newToDeck); - calculateTransition(newFromDeck, newToDeck, false); - newFromDeck->play(); + double crossfaderPosition = value * (m_pCOCrossfaderReverse->toBool() ? -1 : 1); + + if ((crossfaderPosition == 1.0 && fromDeck->isLeft()) // crossfader right + || (crossfaderPosition == -1.0 && fromDeck->isRight())) { // crossfader right + + if (!toDeck->isPlaying()) { + // Re-cue the track if the user has seeked it to the very end + if (toDeck->playPosition() >= toDeck->fadeBeginPos) { + toDeck->setPlayPosition(toDeck->startPos); + } + toDeck->play(); + } + + // Now that we have started the other deck playing, remove the track + // that was "on deck" from the top of the queue. + removeLoadedTrackFromTopOfQueue(*toDeck); + fromDeck->stop(); + loadNextTrackFromQueue(*fromDeck); } } } @@ -540,7 +550,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, } DeckAttributes& thisDeck = *pAttributes; - // prefer to fade to deck 0 + // prefer to fade to deck 0 or 1 int otherDeckIndex = 0; if (thisDeck.index == 0) { otherDeckIndex = 1; @@ -1018,10 +1028,10 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, return; } - double fromTrackDuration = pFromDeck->duration(); - double toTrackDuration = pToDeck->duration(); + double fromDeckDuration = pFromDeck->duration(); + double toDeckDuration = pToDeck->duration(); - VERIFY_OR_DEBUG_ASSERT(fromTrackDuration > 0) { + VERIFY_OR_DEBUG_ASSERT(fromDeckDuration > 0) { // Playing Track has no duration. This should not happen, because short // tracks are skipped after load. Play ToDeck immediately. pFromDeck->fadeBeginPos = 0; @@ -1029,7 +1039,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = kKeepPosition; return; } - if (toTrackDuration <= 0) { + if (toDeckDuration <= 0) { // Playing Track has no duration. This should not happen, because short // tracks are skipped after load. loadNextTrackFromQueue(*pToDeck, false); @@ -1041,7 +1051,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroEnd = getOutroEndPosition(pFromDeck); double outroStart = getOutroStartPosition(pFromDeck); - double fromDeckPosition = pFromDeck->playPosition() * pFromDeck->duration(); + double fromDeckPosition = pFromDeck->playPosition() * fromDeckDuration; if (fromDeckPosition > outroStart) { // We have already passed outroStart @@ -1053,7 +1063,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } double outroLength = outroEnd - outroStart; - double toDeckPosition = pToDeck->playPosition() * toTrackDuration; + double toDeckPosition = pToDeck->playPosition() * toDeckDuration; // Store here a possible fadeBeginPos for the transition after next // This is used to check if it will be possible or a re-cue is required. // here it is done for FullIntroOutro and FadeAtOutroStart. @@ -1217,29 +1227,29 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, default: { double startPoint; - pToDeck->fadeBeginPos = pToDeck->duration(); + pToDeck->fadeBeginPos = toDeckDuration; if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { // toDeckPosition >= pToDeck->fadeBeginPos happens when the // user has seeked or played the to track behind fadeBeginPos of // the fade after the next. // In this case we recue the track just before the transition. - startPoint = 0; + startPoint = 0.0; } else { startPoint = toDeckPosition; } useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, - pFromDeck->duration(), + fromDeckDuration, startPoint); } } // These are expected to be a fraction of the track length. - pFromDeck->fadeBeginPos /= fromTrackDuration; - pFromDeck->fadeEndPos /= fromTrackDuration; - pToDeck->startPos /= toTrackDuration; - pToDeck->fadeBeginPos /= toTrackDuration; - pToDeck->fadeEndPos /= toTrackDuration; + pFromDeck->fadeBeginPos /= fromDeckDuration; + pFromDeck->fadeEndPos /= fromDeckDuration; + pToDeck->startPos /= toDeckDuration; + pToDeck->fadeBeginPos /= toDeckDuration; + pToDeck->fadeEndPos /= toDeckDuration; pFromDeck->isFromDeck = true; pToDeck->isFromDeck = false; @@ -1428,7 +1438,7 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { DeckAttributes* AutoDJProcessor::getOtherDeck(const DeckAttributes* pThisDeck, bool playing) { - DeckAttributes* pOtherDeck = NULL; + DeckAttributes* pOtherDeck = nullptr; if (pThisDeck->isLeft()) { // find first right deck foreach(DeckAttributes* pDeck, m_decks) { @@ -1453,6 +1463,15 @@ DeckAttributes* AutoDJProcessor::getOtherDeck(const DeckAttributes* pThisDeck, return pOtherDeck; } +DeckAttributes* AutoDJProcessor::getFromDeck() { + for(const auto& pDeck : m_decks) { + if (pDeck->isFromDeck) { + return pDeck; + } + } + return nullptr; +} + bool AutoDJProcessor::nextTrackLoaded() { if (m_eState == ADJ_DISABLED) { // AutoDJ always loads the top track (again) if enabled diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index e9c7c597bd1..4f53a675572 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -256,8 +256,10 @@ class AutoDJProcessor : public QObject { bool seekToStartPoint); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double fromDeckPosition, double endPoint, double startPoint); - DeckAttributes* getOtherDeck(const DeckAttributes* pFromDeck, + DeckAttributes* getOtherDeck(const DeckAttributes* pThisDeck, bool playing = false); + DeckAttributes* getFromDeck(); + // Removes the track loaded to the player group from the top of the AutoDJ // queue if it is present. From d6e6cf44801707b15b7f41f2046b499c889ff383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 30 Oct 2019 07:41:28 +0100 Subject: [PATCH 182/198] Adjust short track workaround in outro start mode --- src/library/autodj/autodjprocessor.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 8c6c6315757..68eb5f93cbf 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1183,6 +1183,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } else if (outroLength > 0 && introLength <= 0) { if (outroLength + introStart < pToDeck->fadeBeginPos) { pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroEnd; } else { // This happens if the toDeck track has no intro set and the // outro of the fromDeck track is longer than the whole toDeck @@ -1192,9 +1193,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // We seek to intro start above in this case so this never happens outroLength = 1; } - pFromDeck->fadeBeginPos = outroEnd - outroLength; + pFromDeck->fadeBeginPos = outroStart; + pFromDeck->fadeEndPos = outroStart + outroLength; } - pFromDeck->fadeEndPos = outroEnd; pToDeck->startPos = introStart; } else if (introLength > 0 && outroLength <= 0) { pFromDeck->fadeBeginPos = outroEnd - introLength; From 70214dfbd27a0915eb51406d49f827f801586659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 30 Oct 2019 07:57:33 +0100 Subject: [PATCH 183/198] Adjust intro and outro change slots --- src/library/autodj/autodjprocessor.cpp | 53 ++++++++------------------ 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 68eb5f93cbf..11ca18bfecb 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -859,34 +859,23 @@ void AutoDJProcessor::playerIntroStartChanged(DeckAttributes* pAttributes, doubl if (sDebug) { qDebug() << this << "playerIntroStartChanged" << pAttributes->group << position; } - - DeckAttributes* fromDeck; - if (pAttributes->isFromDeck) { - fromDeck = pAttributes; - } else { - fromDeck = getOtherDeck(pAttributes); - } - - if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false); - } + // nothing to do, because we want not to re-cue the toDeck and the from + // Deck has already passed the intro } void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double position) { if (sDebug) { qDebug() << this << "playerIntroEndChanged" << pAttributes->group << position; } - - DeckAttributes* fromDeck; if (pAttributes->isFromDeck) { - fromDeck = pAttributes; - } else { - fromDeck = getOtherDeck(pAttributes); + // We have already passed the intro + return; } - - if (!pAttributes->loading && !pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, true), false); + DeckAttributes* fromDeck = getFromDeck(); + if (!fromDeck) { + return; } + calculateTransition(fromDeck, getOtherDeck(fromDeck), false); } void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, double position) { @@ -894,16 +883,11 @@ void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, doubl qDebug() << this << "playerOutroStartChanged" << pAttributes->group << position; } - DeckAttributes* fromDeck; - if (pAttributes->isFromDeck) { - fromDeck = pAttributes; - } else { - fromDeck = getOtherDeck(pAttributes); - } - - if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false); + DeckAttributes* fromDeck = getFromDeck(); + if (!fromDeck) { + return; } + calculateTransition(fromDeck, getOtherDeck(fromDeck), false); } void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double position) { @@ -911,16 +895,11 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double qDebug() << this << "playerOutroEndChanged" << pAttributes->group << position; } - DeckAttributes* fromDeck; - if (pAttributes->isFromDeck) { - fromDeck = pAttributes; - } else { - fromDeck = getOtherDeck(pAttributes); - } - - if (!pAttributes->loading && pAttributes->isPlaying()) { - calculateTransition(fromDeck, getOtherDeck(fromDeck, false), false); + DeckAttributes* fromDeck = getFromDeck(); + if (!fromDeck) { + return; } + calculateTransition(fromDeck, getOtherDeck(fromDeck), false); } double AutoDJProcessor::getIntroStartPosition(DeckAttributes* pDeck) { From e1c45e55475ff35e3f73d676ede477086f45e71d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 30 Oct 2019 08:08:23 +0100 Subject: [PATCH 184/198] don't bother with playing state when calculating a new transition --- src/library/autodj/autodjprocessor.cpp | 45 +++++++++++++++----------- src/library/autodj/autodjprocessor.h | 3 +- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 11ca18bfecb..2da6b1af55b 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1301,11 +1301,23 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra // (ADJ_ENABLE_P1LOADED state) then play the track. loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } else { - calculateTransition(getOtherDeck(pDeck, true), pDeck, true); - if (pDeck->startPos != kKeepPosition) { - // Note: this seek will trigger the playerPositionChanged slot - // which may calls the calculateTransition() again without seek = true; - pDeck->setPlayPosition(pDeck->startPos); + DeckAttributes* fromDeck = getFromDeck(); + if (!fromDeck) { + // We have no from deck yet this happens if you have AutoDJ enabled and + // manually load two new tracks. Since we need to seek to the start position + // in any case, we adopt the other deck as from deck for now. + fromDeck = getOtherDeck(pDeck); + } + if (fromDeck) { + DeckAttributes* toDeck = getOtherDeck(fromDeck); + if (toDeck == pDeck) { + calculateTransition(fromDeck, getOtherDeck(fromDeck), true); + if (pDeck->startPos != kKeepPosition) { + // Note: this seek will trigger the playerPositionChanged slot + // which may calls the calculateTransition() again without seek = true; + pDeck->setPlayPosition(pDeck->startPos); + } + } } } } @@ -1416,31 +1428,28 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { } } -DeckAttributes* AutoDJProcessor::getOtherDeck(const DeckAttributes* pThisDeck, - bool playing) { - DeckAttributes* pOtherDeck = nullptr; +DeckAttributes* AutoDJProcessor::getOtherDeck( + const DeckAttributes* pThisDeck) { if (pThisDeck->isLeft()) { // find first right deck foreach(DeckAttributes* pDeck, m_decks) { if (pDeck->isRight()) { - if (!playing || pDeck->isPlaying()) { - pOtherDeck = pDeck; - break; - } + return pDeck; } } - } else if (pThisDeck->isRight()) { + return nullptr; + } + + if (pThisDeck->isRight()) { // find first left deck foreach(DeckAttributes* pDeck, m_decks) { if (pDeck->isLeft()) { - if (!playing || pDeck->isPlaying()) { - pOtherDeck = pDeck; - break; - } + return pDeck; } } + return nullptr; } - return pOtherDeck; + return nullptr; } DeckAttributes* AutoDJProcessor::getFromDeck() { diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 4f53a675572..4afc870083b 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -256,8 +256,7 @@ class AutoDJProcessor : public QObject { bool seekToStartPoint); void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, double fromDeckPosition, double endPoint, double startPoint); - DeckAttributes* getOtherDeck(const DeckAttributes* pThisDeck, - bool playing = false); + DeckAttributes* getOtherDeck(const DeckAttributes* pThisDeck); DeckAttributes* getFromDeck(); From 6dac3a66ee0f9c903355eade881146d35a75f38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 31 Oct 2019 11:21:35 +0100 Subject: [PATCH 185/198] Don't use non cons references in playerPositionChanged() and remove fixed deck index orientation asumption --- src/library/autodj/autodjprocessor.cpp | 103 +++++++++++++++---------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2da6b1af55b..bf023924e20 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -549,26 +549,39 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, return; } - DeckAttributes& thisDeck = *pAttributes; - // prefer to fade to deck 0 or 1 - int otherDeckIndex = 0; - if (thisDeck.index == 0) { - otherDeckIndex = 1; + DeckAttributes* thisDeck = pAttributes; + DeckAttributes* otherDeck = getOtherDeck(thisDeck); + if (!otherDeck) { + // This happens if this deck has no orientation or + // there is no deck with the opposite orientation + return; } - DeckAttributes& otherDeck = *m_decks[otherDeckIndex]; - DeckAttributes& leftDeck = *m_decks[0]; - DeckAttributes& rightDeck = *m_decks[1]; - - bool leftDeckPlaying = leftDeck.isPlaying(); - bool rightDeckPlaying = rightDeck.isPlaying(); - - bool thisDeckPlaying = thisDeck.isPlaying(); - bool otherDeckPlaying = otherDeck.isPlaying(); + bool thisDeckPlaying = thisDeck->isPlaying(); + bool otherDeckPlaying = otherDeck->isPlaying(); // To switch out of ADJ_ENABLE_P1LOADED we wait for a playposition update // for either deck. if (m_eState == ADJ_ENABLE_P1LOADED) { + + DeckAttributes* leftDeck; + DeckAttributes* rightDeck; + + + if (thisDeck->isLeft()) { + leftDeck = thisDeck; + DEBUG_ASSERT(otherDeck->isRight()); + rightDeck = otherDeck; + } else { + DEBUG_ASSERT(thisDeck->isRight()); + rightDeck = thisDeck; + DEBUG_ASSERT(otherDeck->isLeft()); + leftDeck = otherDeck; + } + + bool leftDeckPlaying = leftDeck->isPlaying(); + bool rightDeckPlaying = rightDeck->isPlaying(); + if (leftDeckPlaying || rightDeckPlaying) { // One of left and right is playing. Switch to IDLE mode and make // sure our thresholds are configured (by calling calculateFadeThresholds @@ -584,17 +597,17 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // will remove it from the top of the queue and request another // track. Remove the left deck's current track from the queue // since it is the track we requested in toggleAutoDJ. - removeLoadedTrackFromTopOfQueue(leftDeck); + removeLoadedTrackFromTopOfQueue(*leftDeck); // Load the next track into the right player since it is not // playing. - loadNextTrackFromQueue(rightDeck); + loadNextTrackFromQueue(*rightDeck); // Note: calculateTransition() is called in playerTrackLoaded() } else { // At least right deck is playing // Set crossfade thresholds for right deck. - calculateTransition(&rightDeck, &leftDeck, false); + calculateTransition(rightDeck, leftDeck, false); } emitAutoDJStateChanged(m_eState); } @@ -611,7 +624,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // Once P1 or P2 has stopped switch out of fading mode to idle. // If the user stops the toDeck during a fade, let the fade continue // and do not load the next track. - if (!otherDeckPlaying && otherDeck.isFromDeck) { + if (!otherDeckPlaying && otherDeck->isFromDeck) { // Force crossfader all the way to the (non fading) toDeck. if (m_eState == ADJ_RIGHT_FADING) { setCrossfader(-1.0); @@ -622,10 +635,10 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // Invalidate threshold calculated for the old otherDeck // This avoids starting a fade back before the new track is // loaded into the otherDeck - thisDeck.fadeBeginPos = 1.0; - thisDeck.fadeEndPos = 1.0; + thisDeck->fadeBeginPos = 1.0; + thisDeck->fadeEndPos = 1.0; // Load the next track to otherDeck. - loadNextTrackFromQueue(otherDeck); + loadNextTrackFromQueue(*otherDeck); emitAutoDJStateChanged(m_eState); return; } @@ -642,8 +655,8 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // recalculated here. // Don't adjust transition when reaching the end. In this case it is // always stopped. - calculateTransition(&otherDeck, &thisDeck, false); - } else if (thisDeck.isRepeat()) { + calculateTransition(otherDeck, thisDeck, false); + } else if (thisDeck->isRepeat()) { // repeat pauses auto DJ return; } @@ -653,34 +666,34 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // - transition into fading mode, play the other deck and fade to it. // - check if fading is done and stop the deck // - update the crossfader - if (thisPlayPosition >= thisDeck.fadeBeginPos && thisDeck.isFromDeck) { + if (thisPlayPosition >= thisDeck->fadeBeginPos && thisDeck->isFromDeck) { if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { // cache this before calculating the new transition in otherDeck.play(); // thisDeck.fadeBeginPos is equal thisDeck.fadeEndPos in case of zero or // negative transition time - bool hasFadeTransition = thisDeck.fadeBeginPos < thisDeck.fadeEndPos; + bool hasFadeTransition = thisDeck->fadeBeginPos < thisDeck->fadeEndPos; if (!otherDeckPlaying) { // Re-cue the track if the user has seeked it to the very end - if (otherDeck.playPosition() >= otherDeck.fadeBeginPos) { - otherDeck.setPlayPosition(otherDeck.startPos); + if (otherDeck->playPosition() >= otherDeck->fadeBeginPos) { + otherDeck->setPlayPosition(otherDeck->startPos); } - otherDeck.play(); + otherDeck->play(); } // Now that we have started the other deck playing, remove the track // that was "on deck" from the top of the queue. - removeLoadedTrackFromTopOfQueue(otherDeck); + removeLoadedTrackFromTopOfQueue(*otherDeck); if (!hasFadeTransition) { - setCrossfader(thisDeck.isLeft() ? 1.0 : -1.0); - thisDeck.stop(); - loadNextTrackFromQueue(thisDeck); + setCrossfader(thisDeck->isLeft() ? 1.0 : -1.0); + thisDeck->stop(); + loadNextTrackFromQueue(*thisDeck); return; } m_transitionProgress = 0.0; // Set the state as FADING. - m_eState = thisDeck.isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; + m_eState = thisDeck->isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; emitAutoDJStateChanged(m_eState); } } @@ -703,14 +716,14 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // We don't handle mode switches here since that's handled by // the next playerPositionChanged call otherDeck (see the // P1/P2FADING case above). - thisDeck.stop(); + thisDeck->stop(); m_transitionProgress = 1.0; } else { // We are in Fading state. // Calculate the current transitionProgress, the place between begin // and end position and the step we have taken since the last call - double transitionProgress = (thisPlayPosition - thisDeck.fadeBeginPos) / - (thisDeck.fadeEndPos - thisDeck.fadeBeginPos); + double transitionProgress = (thisPlayPosition - thisDeck->fadeBeginPos) / + (thisDeck->fadeEndPos - thisDeck->fadeBeginPos); double transitionStep = transitionProgress - m_transitionProgress; if (transitionStep > 0.0) { // We have made progress. @@ -837,9 +850,16 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) if (sDebug) { qDebug() << this << "playerPlayChanged" << thisDeck->group << playing; } - // In case both decks were stopped and now this one just started, make this - // deck the "from deck". - if (playing && !getOtherDeck(thisDeck)->isPlaying()) { + + DeckAttributes* otherDeck = getOtherDeck(thisDeck); + if (!otherDeck) { + // This happens if all decks have center orientation + return; + } + + if (playing && otherDeck->isPlaying()) { + // In case both decks were stopped and now this one just started, make + // this deck the "from deck". calculateTransition(thisDeck, getOtherDeck(thisDeck), false); } @@ -848,9 +868,10 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) // end, seek back to the start point instead of keeping the deck stopped at // the end. if (!playing && thisDeck->playPosition() >= 1.0 && !thisDeck->isFromDeck) { - // Deck has stopped at the end. Recalculate the transition, because + // toDeck has stopped at the end. Recalculate the transition, because // it has been done from a now irrelevant previous position. - calculateTransition(getOtherDeck(thisDeck), thisDeck, true); + // This forces the other deck to be the fromDeck. + calculateTransition(otherDeck, thisDeck, true); thisDeck->setPlayPosition(thisDeck->startPos); } } From fd3692775f880f986b1669f49b66f0c15be4ff30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 31 Oct 2019 11:39:02 +0100 Subject: [PATCH 186/198] Don't use non const references in toggleAutoDJ() --- src/library/autodj/autodjprocessor.cpp | 74 ++++++++++++++------------ 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index bf023924e20..45538b0a59e 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -314,10 +314,14 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::skipNext() { } AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { - DeckAttributes& deck1 = *m_decks[0]; - DeckAttributes& deck2 = *m_decks[1]; - bool deck1Playing = deck1.isPlaying(); - bool deck2Playing = deck2.isPlaying(); + DeckAttributes* deck1 = m_decks[0]; + DeckAttributes* deck2 = m_decks[1]; + VERIFY_OR_DEBUG_ASSERT(deck1 && deck2) { + return ADJ_NOT_TWO_DECKS; + } + + bool deck1Playing = deck1->isPlaying(); + bool deck2Playing = deck2->isPlaying(); if (enable) { // Enable Auto DJ if (deck1Playing && deck2Playing) { @@ -337,22 +341,22 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { // Never load the same track if it is already playing if (deck1Playing) { - removeLoadedTrackFromTopOfQueue(deck1); + removeLoadedTrackFromTopOfQueue(*deck1); } else if (deck2Playing) { - removeLoadedTrackFromTopOfQueue(deck2); + removeLoadedTrackFromTopOfQueue(*deck2); } else { // If the first track is already cued at a position in the first // 2/3 in on of the Auto DJ decks, start it. // If the track is paused at a later position, it is probably too // close to the end. In this case it is loaded again at the stored // cue point. - if (deck1.playPosition() < 0.66 && - removeLoadedTrackFromTopOfQueue(deck1)) { - deck1.play(); + if (deck1->playPosition() < 0.66 && + removeLoadedTrackFromTopOfQueue(*deck1)) { + deck1->play(); deck1Playing = true; - } else if (deck2.playPosition() < 0.66 && - removeLoadedTrackFromTopOfQueue(deck2)) { - deck2.play(); + } else if (deck2->playPosition() < 0.66 && + removeLoadedTrackFromTopOfQueue(*deck2)) { + deck2->play(); deck2Playing = true; } } @@ -376,49 +380,49 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { m_pCOCrossfader->connectValueChanged(this, &AutoDJProcessor::crossfaderChanged); - connect(&deck1, &DeckAttributes::playPositionChanged, + connect(deck1, &DeckAttributes::playPositionChanged, this, &AutoDJProcessor::playerPositionChanged); - connect(&deck2, &DeckAttributes::playPositionChanged, + connect(deck2, &DeckAttributes::playPositionChanged, this, &AutoDJProcessor::playerPositionChanged); - connect(&deck1, &DeckAttributes::playChanged, + connect(deck1, &DeckAttributes::playChanged, this, &AutoDJProcessor::playerPlayChanged); - connect(&deck2, &DeckAttributes::playChanged, + connect(deck2, &DeckAttributes::playChanged, this, &AutoDJProcessor::playerPlayChanged); - connect(&deck1, &DeckAttributes::introStartPositionChanged, + connect(deck1, &DeckAttributes::introStartPositionChanged, this, &AutoDJProcessor::playerIntroStartChanged); - connect(&deck2, &DeckAttributes::introStartPositionChanged, + connect(deck2, &DeckAttributes::introStartPositionChanged, this, &AutoDJProcessor::playerIntroStartChanged); - connect(&deck1, &DeckAttributes::introEndPositionChanged, + connect(deck1, &DeckAttributes::introEndPositionChanged, this, &AutoDJProcessor::playerIntroEndChanged); - connect(&deck2, &DeckAttributes::introEndPositionChanged, + connect(deck2, &DeckAttributes::introEndPositionChanged, this, &AutoDJProcessor::playerIntroEndChanged); - connect(&deck1, &DeckAttributes::outroStartPositionChanged, + connect(deck1, &DeckAttributes::outroStartPositionChanged, this, &AutoDJProcessor::playerOutroStartChanged); - connect(&deck2, &DeckAttributes::outroStartPositionChanged, + connect(deck2, &DeckAttributes::outroStartPositionChanged, this, &AutoDJProcessor::playerOutroStartChanged); - connect(&deck1, &DeckAttributes::outroEndPositionChanged, + connect(deck1, &DeckAttributes::outroEndPositionChanged, this, &AutoDJProcessor::playerOutroEndChanged); - connect(&deck2, &DeckAttributes::outroEndPositionChanged, + connect(deck2, &DeckAttributes::outroEndPositionChanged, this, &AutoDJProcessor::playerOutroEndChanged); - connect(&deck1, &DeckAttributes::trackLoaded, + connect(deck1, &DeckAttributes::trackLoaded, this, &AutoDJProcessor::playerTrackLoaded); - connect(&deck2, &DeckAttributes::trackLoaded, + connect(deck2, &DeckAttributes::trackLoaded, this, &AutoDJProcessor::playerTrackLoaded); - connect(&deck1, &DeckAttributes::loadingTrack, + connect(deck1, &DeckAttributes::loadingTrack, this, &AutoDJProcessor::playerLoadingTrack); - connect(&deck2, &DeckAttributes::loadingTrack, + connect(deck2, &DeckAttributes::loadingTrack, this, &AutoDJProcessor::playerLoadingTrack); - connect(&deck1, &DeckAttributes::playerEmpty, + connect(deck1, &DeckAttributes::playerEmpty, this, &AutoDJProcessor::playerEmpty); - connect(&deck2, &DeckAttributes::playerEmpty, + connect(deck2, &DeckAttributes::playerEmpty, this, &AutoDJProcessor::playerEmpty); if (!deck1Playing && !deck2Playing) { @@ -436,19 +440,19 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { // Load track into the left deck and play. Once it starts playing, // we will receive a playerPositionChanged update for deck 1 which // will load a track into the right deck and switch to IDLE mode. - emitLoadTrackToPlayer(nextTrack, deck1.group, true); + emitLoadTrackToPlayer(nextTrack, deck1->group, true); } else { // One of the two decks is playing. Switch into IDLE mode and wait // until the playing deck crosses posThreshold to start fading. m_eState = ADJ_IDLE; if (deck1Playing) { // Load track into the right deck. - emitLoadTrackToPlayer(nextTrack, deck2.group, false); + emitLoadTrackToPlayer(nextTrack, deck2->group, false); // Move crossfader to the left. setCrossfader(-1.0); } else { // Load track into the left deck. - emitLoadTrackToPlayer(nextTrack, deck1.group, false); + emitLoadTrackToPlayer(nextTrack, deck1->group, false); // Move crossfader to the right. setCrossfader(1.0); } @@ -462,8 +466,8 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { m_eState = ADJ_DISABLED; disconnect(m_pCOCrossfader, &ControlProxy::valueChanged, this, &AutoDJProcessor::crossfaderChanged); - deck1.disconnect(this); - deck2.disconnect(this); + deck1->disconnect(this); + deck2->disconnect(this); m_pCOCrossfader->set(0); emitAutoDJStateChanged(m_eState); } From 2f88f54019355af6728eb371f9ea04333655f9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 31 Oct 2019 11:44:47 +0100 Subject: [PATCH 187/198] Reset startPos, just in case calculateTransition() is not able to set a new one. --- src/library/autodj/autodjprocessor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 45538b0a59e..09665565cd8 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1336,7 +1336,10 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra if (fromDeck) { DeckAttributes* toDeck = getOtherDeck(fromDeck); if (toDeck == pDeck) { - calculateTransition(fromDeck, getOtherDeck(fromDeck), true); + // Reset startPos, just in case calculateTransition() is not + // able to set a new one. + pDeck->startPos = kKeepPosition; + calculateTransition(fromDeck, pDeck, true); if (pDeck->startPos != kKeepPosition) { // Note: this seek will trigger the playerPositionChanged slot // which may calls the calculateTransition() again without seek = true; From 7036b748b8bd9dd0a21b97a4da8125db455b60d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 4 Nov 2019 00:18:34 +0100 Subject: [PATCH 188/198] Set the just loaded deck as toDeck --- src/library/autodj/autodjprocessor.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 09665565cd8..76629c943ec 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -620,10 +620,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // In FADING states, we expect that both tracks are playing. // Normally the the fading fromDeck stops after the transition is over and - // we need to replace it with a new track from the queue. In the rare case the - // toDeck stops first, we replace this one and stop the transition. - // Then we switch the crossfader fully to the new track side, - // switch to IDLE mode and load the next track into the other deck. + // we need to replace it with a new track from the queue. if (m_eState == ADJ_LEFT_FADING || m_eState == ADJ_RIGHT_FADING) { // Once P1 or P2 has stopped switch out of fading mode to idle. // If the user stops the toDeck during a fade, let the fade continue @@ -861,7 +858,7 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) return; } - if (playing && otherDeck->isPlaying()) { + if (playing && !otherDeck->isPlaying()) { // In case both decks were stopped and now this one just started, make // this deck the "from deck". calculateTransition(thisDeck, getOtherDeck(thisDeck), false); @@ -875,8 +872,13 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) // toDeck has stopped at the end. Recalculate the transition, because // it has been done from a now irrelevant previous position. // This forces the other deck to be the fromDeck. + thisDeck->startPos = kKeepPosition; calculateTransition(otherDeck, thisDeck, true); - thisDeck->setPlayPosition(thisDeck->startPos); + if (thisDeck->startPos != kKeepPosition) { + // Note: this seek will trigger the playerPositionChanged slot + // which may calls the calculateTransition() again without seek = true; + thisDeck->setPlayPosition(thisDeck->startPos); + } } } @@ -1326,18 +1328,12 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra // (ADJ_ENABLE_P1LOADED state) then play the track. loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } else { - DeckAttributes* fromDeck = getFromDeck(); - if (!fromDeck) { - // We have no from deck yet this happens if you have AutoDJ enabled and - // manually load two new tracks. Since we need to seek to the start position - // in any case, we adopt the other deck as from deck for now. - fromDeck = getOtherDeck(pDeck); - } + // this deck has just changed the track so it becomes the toDeck + DeckAttributes* fromDeck = getOtherDeck(pDeck); if (fromDeck) { + // check if this deck has suitable alignment DeckAttributes* toDeck = getOtherDeck(fromDeck); if (toDeck == pDeck) { - // Reset startPos, just in case calculateTransition() is not - // able to set a new one. pDeck->startPos = kKeepPosition; calculateTransition(fromDeck, pDeck, true); if (pDeck->startPos != kKeepPosition) { From 9951daa775e85528d8b35d3a0b3d100319bcdec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 4 Nov 2019 01:37:54 +0100 Subject: [PATCH 189/198] respect the rate slider when calculating auto-DJ transitions --- src/library/autodj/autodjprocessor.cpp | 85 +++++++++++++------------- src/library/autodj/autodjprocessor.h | 12 +++- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 76629c943ec..bf55f02b32f 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -40,6 +40,9 @@ DeckAttributes::DeckAttributes(int index, m_outroEndPos(group, "outro_end_position"), m_sampleRate(group, "track_samplerate"), m_duration(group, "duration"), + m_rateDir(group, "rate_dir"), + m_rateRange(group, "rateRange"), + m_rateSlider(group, "rate"), m_pPlayer(pPlayer) { connect(m_pPlayer, &BaseTrackPlayer::newTrackLoaded, this, &DeckAttributes::slotTrackLoaded); @@ -99,6 +102,23 @@ TrackPointer DeckAttributes::getLoadedTrack() const { return m_pPlayer != NULL ? m_pPlayer->getLoadedTrack() : TrackPointer(); } +double DeckAttributes::calcRateRatio() const { + double rateRatio = 1.0 + m_rateDir.get() * m_rateRange.get() * + m_rateSlider.get(); + if(rateRatio == 0.0) { + return 1.0; + } + return rateRatio; +} + +double DeckAttributes::trackTime() const { + return trackDuration() / calcRateRatio(); +} + +double DeckAttributes::timeElapsed() const { + return playPosition() * trackTime(); +} + AutoDJProcessor::AutoDJProcessor(QObject* pParent, UserSettingsPointer pConfig, PlayerManagerInterface* pPlayerManager, @@ -238,8 +258,8 @@ void AutoDJProcessor::fadeNow() { pFromDeck->isFromDeck = true; pToDeck->isFromDeck = false; - double fromDeckCurrentPosition = pFromDeck->playPosition() * pFromDeck->duration(); - double toDeckCurrentPosition = pToDeck->playPosition() * pToDeck->duration(); + double fromDeckCurrentPosition = pFromDeck->timeElapsed(); + double toDeckCurrentPosition = pToDeck->timeElapsed(); pFromDeck->fadeBeginPos = fromDeckCurrentPosition; // Do not seek to a calculated start point; start the to deck from wherever @@ -280,14 +300,14 @@ void AutoDJProcessor::fadeNow() { fadeTime = spinboxTime; } - double timeUntilEndOfFromTrack = pFromDeck->duration() - fromDeckCurrentPosition; + double timeUntilEndOfFromTrack = pFromDeck->trackTime() - fromDeckCurrentPosition; fadeTime = math_min(fadeTime, timeUntilEndOfFromTrack); pFromDeck->fadeEndPos = fromDeckCurrentPosition + fadeTime; // These are expected to be a fraction of the track length. - pFromDeck->fadeBeginPos /= pFromDeck->duration(); - pFromDeck->fadeEndPos /= pFromDeck->duration(); - pToDeck->startPos /= pToDeck->duration(); + pFromDeck->fadeBeginPos /= pFromDeck->trackTime(); + pFromDeck->fadeEndPos /= pFromDeck->trackTime(); + pToDeck->startPos /= pToDeck->trackTime(); } AutoDJProcessor::AutoDJError AutoDJProcessor::skipNext() { @@ -990,33 +1010,16 @@ double AutoDJProcessor::getLastSoundPosition(DeckAttributes* pDeck) { return samplePositionToSeconds(lastSound, pDeck); } } - return pDeck->duration(); + return pDeck->trackTime(); } -double AutoDJProcessor::getMainCuePosition(DeckAttributes* pDeck) { - TrackPointer pTrack = pDeck->getLoadedTrack(); - if (!pTrack) { - return 0; - } - - CuePointer pMainCue = pTrack->findCueByType(Cue::Type::MainCue); - if (pMainCue) { - double mainCue = pMainCue->getPosition(); - if (mainCue > 0) { - return samplePositionToSeconds(mainCue, pDeck); - } - } - return 0.0; -} - - double AutoDJProcessor::samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck) { samplePosition /= kChannelCount; double sampleRate = pDeck->sampleRate(); if (samplePosition <= 0.0 || sampleRate <= 0.0) { return -1.0; } - return samplePosition / sampleRate; + return samplePosition / sampleRate / pDeck->calcRateRatio(); } void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, @@ -1034,10 +1037,10 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, return; } - double fromDeckDuration = pFromDeck->duration(); - double toDeckDuration = pToDeck->duration(); + double fromTrackTime = pFromDeck->trackTime(); + double toTrackTime = pToDeck->trackTime(); - VERIFY_OR_DEBUG_ASSERT(fromDeckDuration > 0) { + VERIFY_OR_DEBUG_ASSERT(fromTrackTime > 0) { // Playing Track has no duration. This should not happen, because short // tracks are skipped after load. Play ToDeck immediately. pFromDeck->fadeBeginPos = 0; @@ -1045,7 +1048,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pToDeck->startPos = kKeepPosition; return; } - if (toDeckDuration <= 0) { + if (toTrackTime <= 0) { // Playing Track has no duration. This should not happen, because short // tracks are skipped after load. loadNextTrackFromQueue(*pToDeck, false); @@ -1057,19 +1060,19 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroEnd = getOutroEndPosition(pFromDeck); double outroStart = getOutroStartPosition(pFromDeck); - double fromDeckPosition = pFromDeck->playPosition() * fromDeckDuration; + double fromDeckPosition = pFromDeck->timeElapsed(); if (fromDeckPosition > outroStart) { // We have already passed outroStart // This can happen if we have just enabled auto DJ outroStart = fromDeckPosition; if (fromDeckPosition > outroEnd) { - outroEnd = math_min(outroStart + fabs(m_transitionTime), pFromDeck->duration()); + outroEnd = math_min(outroStart + fabs(m_transitionTime), fromTrackTime); } } double outroLength = outroEnd - outroStart; - double toDeckPosition = pToDeck->playPosition() * toDeckDuration; + double toDeckPosition = pToDeck->timeElapsed(); // Store here a possible fadeBeginPos for the transition after next // This is used to check if it will be possible or a re-cue is required. // here it is done for FullIntroOutro and FadeAtOutroStart. @@ -1234,7 +1237,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, default: { double startPoint; - pToDeck->fadeBeginPos = toDeckDuration; + pToDeck->fadeBeginPos = toTrackTime; if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { // toDeckPosition >= pToDeck->fadeBeginPos happens when the // user has seeked or played the to track behind fadeBeginPos of @@ -1246,17 +1249,17 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, } useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, - fromDeckDuration, + fromTrackTime, startPoint); } } // These are expected to be a fraction of the track length. - pFromDeck->fadeBeginPos /= fromDeckDuration; - pFromDeck->fadeEndPos /= fromDeckDuration; - pToDeck->startPos /= toDeckDuration; - pToDeck->fadeBeginPos /= toDeckDuration; - pToDeck->fadeEndPos /= toDeckDuration; + pFromDeck->fadeBeginPos /= fromTrackTime; + pFromDeck->fadeEndPos /= fromTrackTime; + pToDeck->startPos /= toTrackTime; + pToDeck->fadeBeginPos /= toTrackTime; + pToDeck->fadeEndPos /= toTrackTime; pFromDeck->isFromDeck = true; pToDeck->isFromDeck = false; @@ -1286,11 +1289,11 @@ void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, // better than directly default to duration() double end = getOutroEndPosition(pToDeck); if (end <= startPoint) { - end = pToDeck->duration(); + end = pToDeck->trackTime(); VERIFY_OR_DEBUG_ASSERT(end > startPoint) { // as last resort move start point // The caller makes sure that this never happens - startPoint = pToDeck->duration() - 1; + startPoint = pToDeck->trackTime() - 1; } } // use the remaining time for fading diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 4afc870083b..5ea96496606 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -50,6 +50,10 @@ class DeckAttributes : public QObject { return m_playPos.get(); } + double trackTime() const; + + double timeElapsed() const; + void setPlayPosition(double playpos) { m_playPos.set(playpos); } @@ -82,10 +86,12 @@ class DeckAttributes : public QObject { return m_sampleRate.get(); } - double duration() const { + double trackDuration() const { return m_duration.get(); } + double calcRateRatio() const; + TrackPointer getLoadedTrack() const; signals: @@ -130,6 +136,9 @@ class DeckAttributes : public QObject { ControlProxy m_outroEndPos; ControlProxy m_sampleRate; ControlProxy m_duration; + ControlProxy m_rateDir; + ControlProxy m_rateRange; + ControlProxy m_rateSlider; BaseTrackPlayer* m_pPlayer; }; @@ -246,7 +255,6 @@ class AutoDJProcessor : public QObject { double getOutroEndPosition(DeckAttributes* pDeck); double getFirstSoundPosition(DeckAttributes* pDeck); double getLastSoundPosition(DeckAttributes* pDeck); - double getMainCuePosition(DeckAttributes* pDeck); double samplePositionToSeconds(double samplePosition, DeckAttributes* pDeck); TrackPointer getNextTrackFromQueue(); From db49654d6a5f6b94e0b89f8313d5bc0cf652a3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 4 Nov 2019 01:51:40 +0100 Subject: [PATCH 190/198] Whatch rate changes --- src/library/autodj/autodjprocessor.cpp | 26 ++++++++++++++++++++++++++ src/library/autodj/autodjprocessor.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index bf55f02b32f..b82a8657052 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -56,6 +56,9 @@ DeckAttributes::DeckAttributes(int index, m_introEndPos.connectValueChanged(this, &DeckAttributes::slotIntroEndPositionChanged); m_outroStartPos.connectValueChanged(this, &DeckAttributes::slotOutroStartPositionChanged); m_outroEndPos.connectValueChanged(this, &DeckAttributes::slotOutroEndPositionChanged); + m_rateDir.connectValueChanged(this, &DeckAttributes::slotRateChanged); + m_rateRange.connectValueChanged(this, &DeckAttributes::slotRateChanged); + m_rateSlider.connectValueChanged(this, &DeckAttributes::slotRateChanged); } DeckAttributes::~DeckAttributes() { @@ -98,6 +101,11 @@ void DeckAttributes::slotPlayerEmpty() { emit(playerEmpty(this)); } +void DeckAttributes::slotRateChanged(double v) { + Q_UNUSED(v); + emit(rateChanged(this)); +} + TrackPointer DeckAttributes::getLoadedTrack() const { return m_pPlayer != NULL ? m_pPlayer->getLoadedTrack() : TrackPointer(); } @@ -445,6 +453,11 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { connect(deck2, &DeckAttributes::playerEmpty, this, &AutoDJProcessor::playerEmpty); + connect(deck1, &DeckAttributes::rateChanged, + this, &AutoDJProcessor::playerRateChanged); + connect(deck2, &DeckAttributes::rateChanged, + this, &AutoDJProcessor::playerRateChanged); + if (!deck1Playing && !deck2Playing) { // Both decks are stopped. Load a track into deck 1 and start it // playing. Instruct playerPositionChanged to wait for a @@ -1396,6 +1409,19 @@ void AutoDJProcessor::playerEmpty(DeckAttributes* pDeck) { loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } + +void AutoDJProcessor::playerRateChanged(DeckAttributes* pAttributes) { + if (sDebug) { + qDebug() << this << "playerRateChanged" << pAttributes->group; + } + + DeckAttributes* fromDeck = getFromDeck(); + if (!fromDeck) { + return; + } + calculateTransition(fromDeck, getOtherDeck(fromDeck), false); +} + void AutoDJProcessor::setTransitionTime(int time) { if (sDebug) { qDebug() << this << "setTransitionTime" << time; diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 5ea96496606..7c306712ca8 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -104,6 +104,7 @@ class DeckAttributes : public QObject { void trackLoaded(DeckAttributes* pDeck, TrackPointer pTrack); void loadingTrack(DeckAttributes* pDeck, TrackPointer pNewTrack, TrackPointer pOldTrack); void playerEmpty(DeckAttributes* pDeck); + void rateChanged(DeckAttributes* pDeck); private slots: void slotPlayPosChanged(double v); @@ -115,6 +116,7 @@ class DeckAttributes : public QObject { void slotTrackLoaded(TrackPointer pTrack); void slotLoadingTrack(TrackPointer pNewTrack, TrackPointer pOldTrack); void slotPlayerEmpty(); + void slotRateChanged(double v); public: int index; @@ -223,6 +225,7 @@ class AutoDJProcessor : public QObject { void playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTrack); void playerLoadingTrack(DeckAttributes* pDeck, TrackPointer pNewTrack, TrackPointer pOldTrack); void playerEmpty(DeckAttributes* pDeck); + void playerRateChanged(DeckAttributes* pDeck); void controlEnable(double value); void controlFadeNow(double value); From efa6c00d46d5d83ac7be623be145bc80b3e77752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 7 Nov 2019 01:19:33 +0100 Subject: [PATCH 191/198] fix recursive positionChanged call. Fix omitting fist seek. --- src/engine/enginebuffer.cpp | 25 ++----- src/engine/readaheadmanager.h | 9 +-- src/library/autodj/autodjprocessor.cpp | 91 ++++++++++++++++---------- src/test/autodjprocessor_test.cpp | 17 ++++- src/widget/woverview.cpp | 2 +- 5 files changed, 80 insertions(+), 64 deletions(-) diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 5ba47c24a5c..c41d6148273 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -1,5 +1,7 @@ #include "engine/enginebuffer.h" +#include + #include #include "engine/cachingreader/cachingreader.h" @@ -62,7 +64,7 @@ EngineBuffer::EngineBuffer(const QString& group, UserSettingsPointer pConfig, m_pKeyControl(nullptr), m_pReadAheadManager(nullptr), m_pReader(nullptr), - m_filepos_play(0.), + m_filepos_play(DBL_MIN), m_speed_old(0), m_tempo_ratio_old(1.), m_scratching_old(false), @@ -502,6 +504,7 @@ void EngineBuffer::slotTrackLoaded(TrackPointer pTrack, m_pause.lock(); m_visualPlayPos->setInvalid(); + m_filepos_play = DBL_MIN; // for execute seeks to 0.0 m_pCurrentTrack = pTrack; m_pTrackSamples->set(iTrackNumSamples); m_pTrackSampleRate->set(iTrackSampleRate); @@ -552,7 +555,7 @@ void EngineBuffer::ejectTrack() { m_playButton->set(0.0); m_playposSlider->set(0); m_pCueControl->resetIndicators(); - doSeekFractional(0.0, SEEK_EXACT); + doSeekPlayPos(0.0, SEEK_EXACT); m_pause.unlock(); // Close open file handles by unloading the current track @@ -1325,24 +1328,6 @@ double EngineBuffer::getTrackSamples() { return m_pTrackSamples->get(); } -/* -void EngineBuffer::setReader(CachingReader* pReader) { - disconnect(m_pReader, 0, this, 0); - delete m_pReader; - m_pReader = pReader; - m_pReadAheadManager->setReader(pReader); - connect(m_pReader, &CachingReader::trackLoading, - this, &EngineBuffer::slotTrackLoading, - Qt::DirectConnection); - connect(m_pReader, &CachingReader::trackLoaded, - this, &EngineBuffer::slotTrackLoaded, - Qt::DirectConnection); - connect(m_pReader, &CachingReader::trackLoadFailed, - this, &EngineBuffer::slotTrackLoadFailed, - Qt::DirectConnection); -} -*/ - void EngineBuffer::setScalerForTest(EngineBufferScale* pScaleVinyl, EngineBufferScale* pScaleKeylock) { m_pScaleVinyl = pScaleVinyl; diff --git a/src/engine/readaheadmanager.h b/src/engine/readaheadmanager.h index 519b270bffa..9d17efbe86e 100644 --- a/src/engine/readaheadmanager.h +++ b/src/engine/readaheadmanager.h @@ -56,12 +56,9 @@ class ReadAheadManager { // indicate that the given portion of a song is about to be read. virtual void hintReader(double dRate, HintVector* hintList); - virtual double getFilePlaypositionFromLog(double currentFilePlayposition, - double numConsumedSamples); - - virtual void setReader(CachingReader* pReader) { - m_pReader = pReader; - } + virtual double getFilePlaypositionFromLog( + double currentFilePlayposition, + double numConsumedSamples); private: // An entry in the read log indicates the virtual playposition the read diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index b82a8657052..0c897de7113 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -703,10 +703,11 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, if (thisPlayPosition >= thisDeck->fadeBeginPos && thisDeck->isFromDeck) { if (m_eState == ADJ_IDLE) { if (thisDeckPlaying || thisPlayPosition >= 1.0) { - // cache this before calculating the new transition in otherDeck.play(); - // thisDeck.fadeBeginPos is equal thisDeck.fadeEndPos in case of zero or - // negative transition time - bool hasFadeTransition = thisDeck->fadeBeginPos < thisDeck->fadeEndPos; + // Set the state as FADING. + m_eState = thisDeck->isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; + m_transitionProgress = 0.0; + emitAutoDJStateChanged(m_eState); + if (!otherDeckPlaying) { // Re-cue the track if the user has seeked it to the very end if (otherDeck->playPosition() >= otherDeck->fadeBeginPos) { @@ -719,16 +720,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // that was "on deck" from the top of the queue. removeLoadedTrackFromTopOfQueue(*otherDeck); - if (!hasFadeTransition) { + if (thisDeck->fadeBeginPos >= thisDeck->fadeEndPos) { setCrossfader(thisDeck->isLeft() ? 1.0 : -1.0); - thisDeck->stop(); - loadNextTrackFromQueue(*thisDeck); - return; } - m_transitionProgress = 0.0; - // Set the state as FADING. - m_eState = thisDeck->isLeft() ? ADJ_LEFT_FADING : ADJ_RIGHT_FADING; - emitAutoDJStateChanged(m_eState); } } @@ -885,6 +879,11 @@ void AutoDJProcessor::playerPlayChanged(DeckAttributes* thisDeck, bool playing) qDebug() << this << "playerPlayChanged" << thisDeck->group << playing; } + if (m_eState != ADJ_IDLE) { + // We don't want to recalculate a running transition + return; + } + DeckAttributes* otherDeck = getOtherDeck(thisDeck); if (!otherDeck) { // This happens if all decks have center orientation @@ -927,6 +926,12 @@ void AutoDJProcessor::playerIntroEndChanged(DeckAttributes* pAttributes, double if (sDebug) { qDebug() << this << "playerIntroEndChanged" << pAttributes->group << position; } + + if (m_eState != ADJ_IDLE) { + // We don't want to recalculate a running transition + return; + } + if (pAttributes->isFromDeck) { // We have already passed the intro return; @@ -943,6 +948,11 @@ void AutoDJProcessor::playerOutroStartChanged(DeckAttributes* pAttributes, doubl qDebug() << this << "playerOutroStartChanged" << pAttributes->group << position; } + if (m_eState != ADJ_IDLE) { + // We don't want to recalculate a running transition + return; + } + DeckAttributes* fromDeck = getFromDeck(); if (!fromDeck) { return; @@ -955,6 +965,11 @@ void AutoDJProcessor::playerOutroEndChanged(DeckAttributes* pAttributes, double qDebug() << this << "playerOutroEndChanged" << pAttributes->group << position; } + if (m_eState != ADJ_IDLE) { + // We don't want to recalculate a running transition + return; + } + DeckAttributes* fromDeck = getFromDeck(); if (!fromDeck) { return; @@ -1046,7 +1061,7 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, // We require ADJ_IDLE to prevent changing the thresholds in the middle of a // fade. - if (m_eState != ADJ_IDLE) { + VERIFY_OR_DEBUG_ASSERT(m_eState == ADJ_IDLE) { return; } @@ -1343,7 +1358,7 @@ void AutoDJProcessor::playerTrackLoaded(DeckAttributes* pDeck, TrackPointer pTra // Load the next track. If we are the first AutoDJ track // (ADJ_ENABLE_P1LOADED state) then play the track. loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); - } else { + } else if (m_eState == ADJ_IDLE) { // this deck has just changed the track so it becomes the toDeck DeckAttributes* fromDeck = getOtherDeck(pDeck); if (fromDeck) { @@ -1415,6 +1430,11 @@ void AutoDJProcessor::playerRateChanged(DeckAttributes* pAttributes) { qDebug() << this << "playerRateChanged" << pAttributes->group; } + if (m_eState != ADJ_IDLE) { + // We don't want to recalculate a running transition + return; + } + DeckAttributes* fromDeck = getFromDeck(); if (!fromDeck) { return; @@ -1455,29 +1475,32 @@ void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { ConfigValue(static_cast(newMode))); m_transitionMode = newMode; + if (m_eState != ADJ_IDLE) { + // We don't want to recalculate a running transition + return; + } + // Then re-calculate fade thresholds for the decks. - if (m_eState == ADJ_IDLE) { - DeckAttributes& leftDeck = *m_decks[0]; - DeckAttributes& rightDeck = *m_decks[1]; + DeckAttributes& leftDeck = *m_decks[0]; + DeckAttributes& rightDeck = *m_decks[1]; - if (leftDeck.isPlaying() && !rightDeck.isPlaying()) { - calculateTransition(&leftDeck, &rightDeck, true); - if (rightDeck.startPos != kKeepPosition) { - // Note: this seek will trigger the playerPositionChanged slot - // which may calls the calculateTransition() again without seek = true; - rightDeck.setPlayPosition(rightDeck.startPos); - } - } else if (rightDeck.isPlaying() && !leftDeck.isPlaying()) { - calculateTransition(&rightDeck, &leftDeck, true); - if (leftDeck.startPos != kKeepPosition) { - // Note: this seek will trigger the playerPositionChanged slot - // which may calls the calculateTransition() again without seek = true; - leftDeck.setPlayPosition(leftDeck.startPos); - } - } else { - // user has manually started the other deck or stopped both. - // don't know what to do. + if (leftDeck.isPlaying() && !rightDeck.isPlaying()) { + calculateTransition(&leftDeck, &rightDeck, true); + if (rightDeck.startPos != kKeepPosition) { + // Note: this seek will trigger the playerPositionChanged slot + // which may calls the calculateTransition() again without seek = true; + rightDeck.setPlayPosition(rightDeck.startPos); + } + } else if (rightDeck.isPlaying() && !leftDeck.isPlaying()) { + calculateTransition(&rightDeck, &leftDeck, true); + if (leftDeck.startPos != kKeepPosition) { + // Note: this seek will trigger the playerPositionChanged slot + // which may calls the calculateTransition() again without seek = true; + leftDeck.setPlayPosition(leftDeck.startPos); } + } else { + // user has manually started the other deck or stopped both. + // don't know what to do. } } diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index 95ae2228fe6..a5d88b25272 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -1457,7 +1457,6 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel(); pAutoDJTableModel->appendTrack(testId); - EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel2]"), false)); // Enable AutoDJ, we immediately transition into IDLE and request a track @@ -1493,17 +1492,29 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Pause_Transition) { EXPECT_DOUBLE_EQ(1.0, deck1.play.get()); EXPECT_DOUBLE_EQ(0.0, deck2.play.get()); - // Expect that we will request a track load on deck1. - EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); + // Expect that we will transition into LEFT_FADING mode. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_LEFT_FADING)); // Seek track in deck1 to its end. deck1.playposition.set(1.0); + // We should have transitioned into LEFT_FADING. + EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); + // Deck is still playing, because the crossfader is processed in the next audio // calback. EXPECT_DOUBLE_EQ(0.0, deck1.play.get()); EXPECT_DOUBLE_EQ(1.0, deck2.play.get()); + // Fake a final callback, normally in this case the engine + // stops the deck + deck1.play.set(0.0); + + // Expect that we will transition into IDLE mode and request a track load + // on deck1. + EXPECT_CALL(*pProcessor, emitAutoDJStateChanged(AutoDJProcessor::ADJ_IDLE)); + EXPECT_CALL(*pProcessor, emitLoadTrackToPlayer(_, QString("[Channel1]"), false)); + // Advance track to the point where crossfading should be over. deck2.playposition.set(0.0); EXPECT_EQ(AutoDJProcessor::ADJ_IDLE, pProcessor->getState()); diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 6ebe13489cf..d1ccb6c37b2 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -201,7 +201,7 @@ void WOverview::setup(const QDomNode& node, const SkinContext& context) { } void WOverview::onConnectedControlChanged(double dParameter, double dValue) { - Q_UNUSED(dParameter); + // this is connected via skin to "playposition" Q_UNUSED(dValue); // Calculate handle position. Clamp the value within 0-1 because that's // all we represent with this widget. From e9bee7fafd833af0f232e7a6d17db4a5f4752c8a Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Fri, 8 Nov 2019 11:29:36 +0100 Subject: [PATCH 192/198] fix incorrect cue quantization with prevBeat fixed cuepoint being aligned with the next beat in case we were already exactly positioned on the next beat --- src/engine/controls/cuecontrol.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index ae252c45dde..7fa3df5b30b 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1647,8 +1647,9 @@ double CueControl::quantizeCuePoint(double position, QuantizeMode mode) { // Quantize to previous beat, fall back to next beat. return prevBeat != -1.0 ? prevBeat : (nextBeat != -1.0 ? nextBeat : position); } else if (mode == QuantizeMode::NextBeat) { - // Quantize to next beat, fall back to previous beat. - return nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : position); + // use current position if we are already exactly on the grid, + // otherwise quantize to next beat, fall back to previous beat. + return prevBeat == position ? position : (nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : position)); } else { qWarning() << "PROGRAMMING ERROR: Invalid quantize mode" << static_cast(mode); return -1.0; From d099f042596bdcc5ee947e7f3535023bdeb5c569 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Fri, 8 Nov 2019 14:41:53 +0100 Subject: [PATCH 193/198] small refactor: CueControl:quantizeCurrentPosition --- src/engine/controls/cuecontrol.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 7fa3df5b30b..0dc0d4445ef 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1598,15 +1598,16 @@ CueControl::TrackAt CueControl::getTrackAt() const { double CueControl::quantizeCurrentPosition(QuantizeMode mode) { SampleOfTrack sampleOfTrack = getSampleOfTrack(); + const double position = sampleOfTrack.current; // Don't quantize if quantization is disabled. if (!m_pQuantizeEnabled->toBool()) { - return sampleOfTrack.current; + return position; } if (mode == QuantizeMode::ClosestBeat) { double closestBeat = m_pClosestBeat->get(); - return closestBeat != -1.0 ? closestBeat : sampleOfTrack.current; + return closestBeat != -1.0 ? closestBeat : position; } double prevBeat = m_pPrevBeat->get(); @@ -1614,10 +1615,10 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { if (mode == QuantizeMode::PreviousBeat) { // Quantize to previous beat, fall back to next beat. - return prevBeat != -1.0 ? prevBeat : (nextBeat != -1.0 ? nextBeat : sampleOfTrack.current); + return prevBeat != -1.0 ? prevBeat : (nextBeat != -1.0 ? nextBeat : position); } else if (mode == QuantizeMode::NextBeat) { // Quantize to next beat, fall back to previous beat. - return nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : sampleOfTrack.current); + return nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : position); } else { qWarning() << "PROGRAMMING ERROR: Invalid quantize mode" << static_cast(mode); return -1.0; From 10a494993f9ed0c859d28b483578553f422ddd91 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Fri, 8 Nov 2019 14:44:54 +0100 Subject: [PATCH 194/198] added quantize fix to QuantizeCurrentPosition --- src/engine/controls/cuecontrol.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 0dc0d4445ef..5e1b007e74a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1617,8 +1617,9 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { // Quantize to previous beat, fall back to next beat. return prevBeat != -1.0 ? prevBeat : (nextBeat != -1.0 ? nextBeat : position); } else if (mode == QuantizeMode::NextBeat) { - // Quantize to next beat, fall back to previous beat. - return nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : position); + // use current position if we are already exactly on the grid, + // otherwise quantize to next beat, fall back to previous beat. + return prevBeat == position ? position : (nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : position)); } else { qWarning() << "PROGRAMMING ERROR: Invalid quantize mode" << static_cast(mode); return -1.0; From 7a6bdc7c0c6eaf1ad21026ab2dc9907b0b346058 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Fri, 8 Nov 2019 14:58:01 +0100 Subject: [PATCH 195/198] refactored ternary expressions to if clauses --- src/engine/controls/cuecontrol.cpp | 38 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 5e1b007e74a..1321e9a47b5 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1615,11 +1615,25 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { if (mode == QuantizeMode::PreviousBeat) { // Quantize to previous beat, fall back to next beat. - return prevBeat != -1.0 ? prevBeat : (nextBeat != -1.0 ? nextBeat : position); + if (prevBeat != -1.0) { + return prevBeat; + } else if (nextBeat != -1.0) { + return nextBeat; + } else { + return position; + } } else if (mode == QuantizeMode::NextBeat) { // use current position if we are already exactly on the grid, // otherwise quantize to next beat, fall back to previous beat. - return prevBeat == position ? position : (nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : position)); + if (prevBeat == position) { + return position; + } else if (nextBeat != -1.0) { + return nextBeat; + } else if (prevBeat != -1.0) { + return prevBeat; + } else { + return position; + } } else { qWarning() << "PROGRAMMING ERROR: Invalid quantize mode" << static_cast(mode); return -1.0; @@ -1645,13 +1659,27 @@ double CueControl::quantizeCuePoint(double position, QuantizeMode mode) { double prevBeat, nextBeat; pBeats->findPrevNextBeats(position, &prevBeat, &nextBeat); - if (mode == QuantizeMode::PreviousBeat) { + if (mode == QuantizeMode::PreviousBeat) { // Quantize to previous beat, fall back to next beat. - return prevBeat != -1.0 ? prevBeat : (nextBeat != -1.0 ? nextBeat : position); + if (prevBeat != -1.0) { + return prevBeat; + } else if (nextBeat != -1.0) { + return nextBeat; + } else { + return position; + } } else if (mode == QuantizeMode::NextBeat) { // use current position if we are already exactly on the grid, // otherwise quantize to next beat, fall back to previous beat. - return prevBeat == position ? position : (nextBeat != -1.0 ? nextBeat : (prevBeat != -1.0 ? prevBeat : position)); + if (prevBeat == position) { + return position; + } else if (nextBeat != -1.0) { + return nextBeat; + } else if (prevBeat != -1.0) { + return prevBeat; + } else { + return position; + } } else { qWarning() << "PROGRAMMING ERROR: Invalid quantize mode" << static_cast(mode); return -1.0; From 5aafbd2aabd7d8854e773c118eea52d0f44759b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 9 Nov 2019 12:31:32 +0100 Subject: [PATCH 196/198] Prevent to move outro end past the end of the track if quantize is enabed --- src/engine/controls/cuecontrol.cpp | 93 +++++++++++++++----------- src/library/autodj/autodjprocessor.cpp | 8 ++- 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 1321e9a47b5..12f1fa93722 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1598,16 +1598,20 @@ CueControl::TrackAt CueControl::getTrackAt() const { double CueControl::quantizeCurrentPosition(QuantizeMode mode) { SampleOfTrack sampleOfTrack = getSampleOfTrack(); - const double position = sampleOfTrack.current; + const double currentPos = sampleOfTrack.current; + const double total = sampleOfTrack.total; // Don't quantize if quantization is disabled. if (!m_pQuantizeEnabled->toBool()) { - return position; + return currentPos; } if (mode == QuantizeMode::ClosestBeat) { double closestBeat = m_pClosestBeat->get(); - return closestBeat != -1.0 ? closestBeat : position; + if (closestBeat != -1.0 && closestBeat <= total) { + return closestBeat; + } + return currentPos; } double prevBeat = m_pPrevBeat->get(); @@ -1617,73 +1621,86 @@ double CueControl::quantizeCurrentPosition(QuantizeMode mode) { // Quantize to previous beat, fall back to next beat. if (prevBeat != -1.0) { return prevBeat; - } else if (nextBeat != -1.0) { + } + if (nextBeat != -1.0 && nextBeat <= total) { return nextBeat; - } else { - return position; } - } else if (mode == QuantizeMode::NextBeat) { + return currentPos; + } + if (mode == QuantizeMode::NextBeat) { // use current position if we are already exactly on the grid, // otherwise quantize to next beat, fall back to previous beat. - if (prevBeat == position) { - return position; - } else if (nextBeat != -1.0) { + if (prevBeat == currentPos) { + return currentPos; + } + if (nextBeat != -1.0 && nextBeat <= total) { return nextBeat; - } else if (prevBeat != -1.0) { + } + if (prevBeat != -1.0) { return prevBeat; - } else { - return position; } - } else { - qWarning() << "PROGRAMMING ERROR: Invalid quantize mode" << static_cast(mode); - return -1.0; + return currentPos; } + DEBUG_ASSERT(!"PROGRAMMING ERROR: Invalid quantize mode"); + return currentPos; } -double CueControl::quantizeCuePoint(double position, QuantizeMode mode) { +double CueControl::quantizeCuePoint(double cuePos, QuantizeMode mode) { + // we need to use m_pTrackSamples here because SampleOfTrack + // is set later by the engine and not during EngineBuffer::slotTrackLoaded + const double total = m_pTrackSamples->get(); + + VERIFY_OR_DEBUG_ASSERT(cuePos <= total) { + cuePos = total; + } + // Don't quantize unset cues, manual cues or when quantization is disabled. - if (position == Cue::kNoPosition || !m_pQuantizeEnabled->toBool()) { - return position; + if (cuePos == Cue::kNoPosition || !m_pQuantizeEnabled->toBool()) { + return cuePos; } BeatsPointer pBeats = m_pLoadedTrack->getBeats(); if (!pBeats) { - return position; + return cuePos; } if (mode == QuantizeMode::ClosestBeat) { - double closestBeat = pBeats->findClosestBeat(position); - return closestBeat != -1.0 ? closestBeat : position; + double closestBeat = pBeats->findClosestBeat(cuePos); + if (closestBeat != -1.0 && closestBeat <= total) { + return closestBeat; + } + return cuePos; } double prevBeat, nextBeat; - pBeats->findPrevNextBeats(position, &prevBeat, &nextBeat); + pBeats->findPrevNextBeats(cuePos, &prevBeat, &nextBeat); - if (mode == QuantizeMode::PreviousBeat) { + if (mode == QuantizeMode::PreviousBeat) { // Quantize to previous beat, fall back to next beat. if (prevBeat != -1.0) { return prevBeat; - } else if (nextBeat != -1.0) { + } + if (nextBeat != -1.0 && nextBeat <= total) { return nextBeat; - } else { - return position; } - } else if (mode == QuantizeMode::NextBeat) { - // use current position if we are already exactly on the grid, + return cuePos; + } + if (mode == QuantizeMode::NextBeat) { + // use current cuePos if we are already exactly on the grid, // otherwise quantize to next beat, fall back to previous beat. - if (prevBeat == position) { - return position; - } else if (nextBeat != -1.0) { + if (prevBeat == cuePos) { + return cuePos; + } + if (nextBeat != -1.0 && nextBeat <= total) { return nextBeat; - } else if (prevBeat != -1.0) { + } + if (prevBeat != -1.0) { return prevBeat; - } else { - return position; } - } else { - qWarning() << "PROGRAMMING ERROR: Invalid quantize mode" << static_cast(mode); - return -1.0; + return cuePos; } + DEBUG_ASSERT(!"PROGRAMMING ERROR: Invalid quantize mode"); + return cuePos; } bool CueControl::isTrackAtZeroPos() { diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 0c897de7113..c46fc8f6a3d 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -1090,6 +1090,10 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, double outroStart = getOutroStartPosition(pFromDeck); double fromDeckPosition = pFromDeck->timeElapsed(); + VERIFY_OR_DEBUG_ASSERT(outroEnd <= fromTrackTime) { + outroEnd = fromTrackTime; + } + if (fromDeckPosition > outroStart) { // We have already passed outroStart // This can happen if we have just enabled auto DJ @@ -1292,7 +1296,9 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, pFromDeck->isFromDeck = true; pToDeck->isFromDeck = false; - DEBUG_ASSERT(pFromDeck->fadeBeginPos <= 1); + VERIFY_OR_DEBUG_ASSERT(pFromDeck->fadeBeginPos <= 1) { + pFromDeck->fadeBeginPos = 0; + } if (sDebug) { qDebug() << this << "calculateTransition" << pFromDeck->group From ea3f2b9e588d29bc0ce55977542076b1387145ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 9 Nov 2019 13:25:25 +0100 Subject: [PATCH 197/198] git-clang-format --- src/analyzer/analyzersilence.cpp | 6 +- src/analyzer/analyzersilence.h | 1 - src/engine/cachingreader/cachingreader.cpp | 6 +- src/engine/cachingreader/cachingreader.h | 6 +- .../cachingreader/cachingreaderworker.cpp | 21 +- src/engine/controls/bpmcontrol.cpp | 8 +- src/engine/controls/cuecontrol.cpp | 40 ++- src/engine/controls/cuecontrol.h | 7 +- src/engine/enginebuffer.cpp | 6 +- src/library/autodj/autodjfeature.cpp | 16 +- src/library/autodj/autodjprocessor.cpp | 245 ++++++++++-------- src/library/autodj/autodjprocessor.h | 15 +- src/library/autodj/dlgautodj.cpp | 163 +++++++----- src/library/autodj/dlgautodj.h | 17 +- src/preferences/dialog/dlgprefdeck.cpp | 48 ++-- src/preferences/dialog/dlgprefdeck.h | 6 +- src/test/autodjprocessor_test.cpp | 2 - src/widget/woverview.cpp | 118 ++++----- src/widget/woverview.h | 3 +- 19 files changed, 386 insertions(+), 348 deletions(-) diff --git a/src/analyzer/analyzersilence.cpp b/src/analyzer/analyzersilence.cpp index 961c72b14be..bde8445beff 100644 --- a/src/analyzer/analyzersilence.cpp +++ b/src/analyzer/analyzersilence.cpp @@ -118,9 +118,9 @@ void AnalyzerSilence::storeResults(TrackPointer pTrack) { bool upgradingWithMainCueAtDefault = (mainCue == 0.0 && pIntroCue == nullptr); if (mainCue == Cue::kNoPosition || upgradingWithMainCueAtDefault) { pTrack->setCuePoint(CuePosition(firstSound)); - // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. - } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) - && pIntroCue == nullptr) { + // NOTE: the actual default for this ConfigValue is set in DlgPrefDeck. + } else if (m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), false) && + pIntroCue == nullptr) { introStart = mainCue; } diff --git a/src/analyzer/analyzersilence.h b/src/analyzer/analyzersilence.h index ce5a43a15df..9c27b5c1e6b 100644 --- a/src/analyzer/analyzersilence.h +++ b/src/analyzer/analyzersilence.h @@ -11,7 +11,6 @@ class AnalyzerSilence : public Analyzer { explicit AnalyzerSilence(UserSettingsPointer pConfig); ~AnalyzerSilence() override = default; - bool initialize(TrackPointer pTrack, int sampleRate, int totalSamples) override; bool processSamples(const CSAMPLE* pIn, const int iLen) override; void storeResults(TrackPointer pTrack) override; diff --git a/src/engine/cachingreader/cachingreader.cpp b/src/engine/cachingreader/cachingreader.cpp index edaf66b42b0..fa045c4eb3f 100644 --- a/src/engine/cachingreader/cachingreader.cpp +++ b/src/engine/cachingreader/cachingreader.cpp @@ -40,9 +40,8 @@ const SINT kNumberOfCachedChunksInMemory = 80; } // anonymous namespace - CachingReader::CachingReader(QString group, - UserSettingsPointer config) + UserSettingsPointer config) : m_pConfig(config), // Limit the number of in-flight requests to the worker. This should // prevent to overload the worker when it is not able to fetch those @@ -63,7 +62,6 @@ CachingReader::CachingReader(QString group, m_lruCachingReaderChunk(nullptr), m_sampleBuffer(CachingReaderChunk::kSamples * kNumberOfCachedChunksInMemory), m_worker(group, &m_chunkReadRequestFIFO, &m_readerStatusUpdateFIFO) { - m_allocatedCachingReaderChunks.reserve(kNumberOfCachedChunksInMemory); // Divide up the allocated raw memory buffer into total_chunks // chunks. Initialize each chunk to hold nothing and add it to the free @@ -265,7 +263,7 @@ void CachingReader::process() { // TRACK_LOADED without a chunk in between, assert this here. DEBUG_ASSERT(m_state.load() == STATE_TRACK_LOADING || (m_state.load() == STATE_TRACK_LOADED && - !m_mruCachingReaderChunk && !m_lruCachingReaderChunk)); + !m_mruCachingReaderChunk && !m_lruCachingReaderChunk)); // now purge also the recently used chunk list from the old track. if (m_mruCachingReaderChunk || m_lruCachingReaderChunk) { DEBUG_ASSERT(m_state.load() == STATE_TRACK_LOADING); diff --git a/src/engine/cachingreader/cachingreader.h b/src/engine/cachingreader/cachingreader.h index ca0df4d7d27..acec6c0ec5a 100644 --- a/src/engine/cachingreader/cachingreader.h +++ b/src/engine/cachingreader/cachingreader.h @@ -5,11 +5,11 @@ #define ENGINE_CACHINGREADER_H #include -#include -#include -#include #include +#include +#include #include +#include #include "util/types.h" #include "preferences/usersettings.h" diff --git a/src/engine/cachingreader/cachingreaderworker.cpp b/src/engine/cachingreader/cachingreaderworker.cpp index ddfe9f3dbc4..070a9993a2b 100644 --- a/src/engine/cachingreader/cachingreaderworker.cpp +++ b/src/engine/cachingreader/cachingreaderworker.cpp @@ -42,8 +42,7 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( chunkFrameIndexRange <= m_pAudioSource->frameIndexRange()); if (chunkFrameIndexRange.empty()) { ReaderStatusUpdate result; - result.init(CHUNK_READ_INVALID, pChunk, - m_pAudioSource ? m_pAudioSource->frameIndexRange() : mixxx::IndexRange()); + result.init(CHUNK_READ_INVALID, pChunk, m_pAudioSource ? m_pAudioSource->frameIndexRange() : mixxx::IndexRange()); return result; } @@ -71,8 +70,7 @@ ReaderStatusUpdate CachingReaderWorker::processReadRequest( } ReaderStatusUpdate result; - result.init(status, pChunk, - m_pAudioSource ? m_pAudioSource->frameIndexRange() : mixxx::IndexRange()); + result.init(status, pChunk, m_pAudioSource ? m_pAudioSource->frameIndexRange() : mixxx::IndexRange()); return result; } @@ -139,14 +137,13 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { QString filename = pTrack->getLocation(); if (filename.isEmpty() || !pTrack->checkFileExists()) { kLogger.warning() - << m_group - << "File not found" - << filename; + << m_group + << "File not found" + << filename; const auto update = ReaderStatusUpdate::trackUnloaded(); m_pReaderStatusFIFO->writeBlocking(&update, 1); emit trackLoadFailed( - pTrack, QString("The file '%1' could not be found.") - .arg(QDir::toNativeSeparators(filename))); + pTrack, QString("The file '%1' could not be found.").arg(QDir::toNativeSeparators(filename))); return; } @@ -161,7 +158,7 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { const auto update = ReaderStatusUpdate::trackUnloaded(); m_pReaderStatusFIFO->writeBlocking(&update, 1); emit trackLoadFailed( - pTrack, QString("The file '%1' could not be loaded").arg(filename)); + pTrack, QString("The file '%1' could not be loaded").arg(filename)); return; } @@ -177,7 +174,7 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { const auto update = ReaderStatusUpdate::trackUnloaded(); m_pReaderStatusFIFO->writeBlocking(&update, 1); emit trackLoadFailed( - pTrack, QString("The file '%1' is empty and could not be loaded").arg(filename)); + pTrack, QString("The file '%1' is empty and could not be loaded").arg(filename)); return; } @@ -190,7 +187,7 @@ void CachingReaderWorker::loadTrack(const TrackPointer& pTrack) { const auto update = ReaderStatusUpdate::trackLoaded( - m_pAudioSource->frameIndexRange()); + m_pAudioSource->frameIndexRange()); m_pReaderStatusFIFO->writeBlocking(&update, 1); // Emit that the track is loaded. diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 301a2fd8fdf..cd0725d1ddb 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -37,7 +37,7 @@ constexpr SINT kSamplesPerFrame = 2; } BpmControl::BpmControl(QString group, - UserSettingsPointer pConfig) + UserSettingsPointer pConfig) : EngineControl(group, pConfig), m_tapFilter(this, kBpmTapFilterLength, kBpmTapMaxInterval), m_dSyncInstantaneousBpm(0.0), @@ -96,8 +96,10 @@ BpmControl::BpmControl(QString group, // bpm_up_small / bpm_down_small steps by kBpmRangeSmallStep m_pEngineBpm = new ControlLinPotmeter( ConfigKey(group, "bpm"), - kBpmRangeMin, kBpmRangeMax, - kBpmRangeStep, kBpmRangeSmallStep, + kBpmRangeMin, + kBpmRangeMax, + kBpmRangeStep, + kBpmRangeSmallStep, true); connect(m_pEngineBpm, &ControlObject::valueChanged, this, &BpmControl::slotUpdateRateSlider, diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 12f1fa93722..e8bc100292a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -303,7 +303,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { QMutexLocker lock(&m_mutex); if (m_pLoadedTrack) { disconnect(m_pLoadedTrack.get(), 0, this, 0); - for (const auto& pControl: m_hotcueControls) { + for (const auto& pControl : m_hotcueControls) { detachCue(pControl); } @@ -334,7 +334,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { Qt::DirectConnection); CuePointer pMainCue; - for (const CuePointer& pCue: m_pLoadedTrack->getCuePoints()) { + for (const CuePointer& pCue : m_pLoadedTrack->getCuePoints()) { if (pCue->getType() == Cue::Type::MainCue) { DEBUG_ASSERT(!pMainCue); pMainCue = pCue; @@ -346,7 +346,6 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { // Use pNewTrack from now, because m_pLoadedTrack might have been reset // immediately after leaving the locking scope! - // Because of legacy, we store the (load) cue point twice and need to // sync both values. // The Cue::Type::MainCue from getCuePoints() has the priority @@ -383,7 +382,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { case SeekOnLoadMode::Beginning: // This allows users to load tracks and have the needle-drop be maintained. if (!(m_pVinylControlEnabled->get() && - m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) { + m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) { seekExact(0.0); } break; @@ -401,16 +400,15 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { seekExact(0.0); } break; - case SeekOnLoadMode::IntroStart: - { - double introStart = m_pIntroStartPosition->get(); - if (introStart != Cue::kNoPosition) { - seekExact(introStart); - } else { - seekExact(0.0); - } - break; + case SeekOnLoadMode::IntroStart: { + double introStart = m_pIntroStartPosition->get(); + if (introStart != Cue::kNoPosition) { + seekExact(introStart); + } else { + seekExact(0.0); } + break; + } default: seekExact(0.0); break; @@ -432,13 +430,13 @@ void CueControl::loadCuesFromTrack() { for (const CuePointer& pCue: m_pLoadedTrack->getCuePoints()) { if (pCue->getType() == Cue::Type::MainCue) { - DEBUG_ASSERT(!pLoadCue); // There should be only one MainCue cue + DEBUG_ASSERT(!pLoadCue); // There should be only one MainCue cue pLoadCue = pCue; } else if (pCue->getType() == Cue::Type::Intro) { - DEBUG_ASSERT(!pIntroCue); // There should be only one Intro cue + DEBUG_ASSERT(!pIntroCue); // There should be only one Intro cue pIntroCue = pCue; } else if (pCue->getType() == Cue::Type::Outro) { - DEBUG_ASSERT(!pOutroCue); // There should be only one Outro cue + DEBUG_ASSERT(!pOutroCue); // There should be only one Outro cue pOutroCue = pCue; } else if (pCue->getType() == Cue::Type::HotCue && pCue->getHotCue() != Cue::kNoHotCue) { int hotcue = pCue->getHotCue(); @@ -1440,9 +1438,9 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) QMutexLocker lock(&m_mutex); CueMode cueMode = static_cast(static_cast(m_pCueMode->get())); if ((cueMode == CueMode::Denon || cueMode == CueMode::Numark) && - newPlay && playPossible && - !m_pPlay->toBool() && - !m_bypassCueSetByPlay) { + newPlay && playPossible && + !m_pPlay->toBool() && + !m_bypassCueSetByPlay) { // in Denon mode each play from pause moves the cue point // if not previewing cueSet(1.0); @@ -1485,7 +1483,7 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) m_pPlayIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_500MS); } } else if (cueMode == CueMode::Mixxx || cueMode == CueMode::MixxxNoBlinking || - cueMode == CueMode::Numark) { + cueMode == CueMode::Numark) { m_pPlayIndicator->setBlinkValue(ControlIndicator::OFF); } else { // Flashing indicates that play is possible in Pioneer mode @@ -1718,7 +1716,7 @@ bool CueControl::isPlayingByPlayButton() { SeekOnLoadMode CueControl::getSeekOnLoadPreference() { int configValue = getConfig()->getValue(ConfigKey("[Controls]", "CueRecall"), - static_cast(SeekOnLoadMode::IntroStart)); + static_cast(SeekOnLoadMode::IntroStart)); return static_cast(configValue); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 774e8b8ad1b..ee9ce2412d4 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -28,14 +28,15 @@ enum class CueMode { }; enum class SeekOnLoadMode { - MainCue = 0, // Use main cue point + MainCue = 0, // Use main cue point Beginning = 1, // Use 0:00.000 FirstSound = 2, // Skip leading silence - IntroStart = 3, // Use intro start cue point + IntroStart = 3, // Use intro start cue point }; inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { - return static_cast(int(value));; + return static_cast(int(value)); + ; } class HotcueControl : public QObject { diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index c41d6148273..df62acfe961 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -52,8 +52,10 @@ const SINT kSamplesPerFrame = 2; // Engine buffer uses Stereo frames only } // anonymous namespace -EngineBuffer::EngineBuffer(const QString& group, UserSettingsPointer pConfig, - EngineChannel* pChannel, EngineMaster* pMixingEngine) +EngineBuffer::EngineBuffer(const QString& group, + UserSettingsPointer pConfig, + EngineChannel* pChannel, + EngineMaster* pMixingEngine) : m_group(group), m_pConfig(pConfig), m_pLoopingControl(nullptr), diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index 20c5bd29b2d..7d5c8232c4d 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -118,12 +118,12 @@ QIcon AutoDJFeature::getIcon() { void AutoDJFeature::bindWidget(WLibrary* libraryWidget, KeyboardEventFilter* keyboard) { m_pAutoDJView = new DlgAutoDJ(libraryWidget, - m_pConfig, - m_pLibrary, - m_pAutoDJProcessor, - m_pTrackCollection, - keyboard, - libraryWidget->getShowButtonText()); + m_pConfig, + m_pLibrary, + m_pAutoDJProcessor, + m_pTrackCollection, + keyboard, + libraryWidget->getShowButtonText()); libraryWidget->registerView(m_sAutoDJViewName, m_pAutoDJView); connect(m_pAutoDJView, &DlgAutoDJ::loadTrack, @@ -264,8 +264,8 @@ void AutoDJFeature::slotAddRandomTrack() { } if (!pRandomTrack->checkFileExists()) { qWarning() << "Track does not exist:" - << pRandomTrack->getInfo() - << pRandomTrack->getFileInfo(); + << pRandomTrack->getInfo() + << pRandomTrack->getFileInfo(); pRandomTrack.reset(); } } diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index c46fc8f6a3d..2cadc453eac 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -21,8 +21,8 @@ static const bool sDebug = false; } // anonymous namespace DeckAttributes::DeckAttributes(int index, - BaseTrackPlayer* pPlayer, - EngineChannel::ChannelOrientation orientation) + BaseTrackPlayer* pPlayer, + EngineChannel::ChannelOrientation orientation) : index(index), group(pPlayer->getGroup()), startPos(kKeepPosition), @@ -111,9 +111,8 @@ TrackPointer DeckAttributes::getLoadedTrack() const { } double DeckAttributes::calcRateRatio() const { - double rateRatio = 1.0 + m_rateDir.get() * m_rateRange.get() * - m_rateSlider.get(); - if(rateRatio == 0.0) { + double rateRatio = 1.0 + m_rateDir.get() * m_rateRange.get() * m_rateSlider.get(); + if (rateRatio == 0.0) { return 1.0; } return rateRatio; @@ -279,8 +278,8 @@ void AutoDJProcessor::fadeNow() { double spinboxTime = fabs(m_transitionTime); double fadeTime; - if (m_transitionMode == TransitionMode::FullIntroOutro - || m_transitionMode == TransitionMode::FadeAtOutroStart) { + if (m_transitionMode == TransitionMode::FullIntroOutro || + m_transitionMode == TransitionMode::FadeAtOutroStart) { // Use the intro length as the transition time. If the user has seeked // away from the intro start since the track was loaded, start from // there and do not seek back to the intro start. If they have seeked @@ -291,8 +290,10 @@ void AutoDJProcessor::fadeNow() { double introStart = getIntroStartPosition(pToDeck); double timeUntilOutroEnd = outroEnd - fromDeckCurrentPosition; - if (toDeckCurrentPosition >= introStart && introStart >= 0 - && toDeckCurrentPosition <= introEnd && introEnd >= 0) { + if (toDeckCurrentPosition >= introStart && + introStart >= 0 && + toDeckCurrentPosition <= introEnd && + introEnd >= 0) { double timeUntilIntroEnd = introEnd - toDeckCurrentPosition; // The fade must end by the outro end at the latest. fadeTime = math_min(timeUntilIntroEnd, timeUntilOutroEnd); @@ -408,55 +409,95 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { m_pCOCrossfader->connectValueChanged(this, &AutoDJProcessor::crossfaderChanged); - connect(deck1, &DeckAttributes::playPositionChanged, - this, &AutoDJProcessor::playerPositionChanged); - connect(deck2, &DeckAttributes::playPositionChanged, - this, &AutoDJProcessor::playerPositionChanged); - - connect(deck1, &DeckAttributes::playChanged, - this, &AutoDJProcessor::playerPlayChanged); - connect(deck2, &DeckAttributes::playChanged, - this, &AutoDJProcessor::playerPlayChanged); - - connect(deck1, &DeckAttributes::introStartPositionChanged, - this, &AutoDJProcessor::playerIntroStartChanged); - connect(deck2, &DeckAttributes::introStartPositionChanged, - this, &AutoDJProcessor::playerIntroStartChanged); - - connect(deck1, &DeckAttributes::introEndPositionChanged, - this, &AutoDJProcessor::playerIntroEndChanged); - connect(deck2, &DeckAttributes::introEndPositionChanged, - this, &AutoDJProcessor::playerIntroEndChanged); - - connect(deck1, &DeckAttributes::outroStartPositionChanged, - this, &AutoDJProcessor::playerOutroStartChanged); - connect(deck2, &DeckAttributes::outroStartPositionChanged, - this, &AutoDJProcessor::playerOutroStartChanged); - - connect(deck1, &DeckAttributes::outroEndPositionChanged, - this, &AutoDJProcessor::playerOutroEndChanged); - connect(deck2, &DeckAttributes::outroEndPositionChanged, - this, &AutoDJProcessor::playerOutroEndChanged); - - connect(deck1, &DeckAttributes::trackLoaded, - this, &AutoDJProcessor::playerTrackLoaded); - connect(deck2, &DeckAttributes::trackLoaded, - this, &AutoDJProcessor::playerTrackLoaded); - - connect(deck1, &DeckAttributes::loadingTrack, - this, &AutoDJProcessor::playerLoadingTrack); - connect(deck2, &DeckAttributes::loadingTrack, - this, &AutoDJProcessor::playerLoadingTrack); - - connect(deck1, &DeckAttributes::playerEmpty, - this, &AutoDJProcessor::playerEmpty); - connect(deck2, &DeckAttributes::playerEmpty, - this, &AutoDJProcessor::playerEmpty); - - connect(deck1, &DeckAttributes::rateChanged, - this, &AutoDJProcessor::playerRateChanged); - connect(deck2, &DeckAttributes::rateChanged, - this, &AutoDJProcessor::playerRateChanged); + connect(deck1, + &DeckAttributes::playPositionChanged, + this, + &AutoDJProcessor::playerPositionChanged); + connect(deck2, + &DeckAttributes::playPositionChanged, + this, + &AutoDJProcessor::playerPositionChanged); + + connect(deck1, + &DeckAttributes::playChanged, + this, + &AutoDJProcessor::playerPlayChanged); + connect(deck2, + &DeckAttributes::playChanged, + this, + &AutoDJProcessor::playerPlayChanged); + + connect(deck1, + &DeckAttributes::introStartPositionChanged, + this, + &AutoDJProcessor::playerIntroStartChanged); + connect(deck2, + &DeckAttributes::introStartPositionChanged, + this, + &AutoDJProcessor::playerIntroStartChanged); + + connect(deck1, + &DeckAttributes::introEndPositionChanged, + this, + &AutoDJProcessor::playerIntroEndChanged); + connect(deck2, + &DeckAttributes::introEndPositionChanged, + this, + &AutoDJProcessor::playerIntroEndChanged); + + connect(deck1, + &DeckAttributes::outroStartPositionChanged, + this, + &AutoDJProcessor::playerOutroStartChanged); + connect(deck2, + &DeckAttributes::outroStartPositionChanged, + this, + &AutoDJProcessor::playerOutroStartChanged); + + connect(deck1, + &DeckAttributes::outroEndPositionChanged, + this, + &AutoDJProcessor::playerOutroEndChanged); + connect(deck2, + &DeckAttributes::outroEndPositionChanged, + this, + &AutoDJProcessor::playerOutroEndChanged); + + connect(deck1, + &DeckAttributes::trackLoaded, + this, + &AutoDJProcessor::playerTrackLoaded); + connect(deck2, + &DeckAttributes::trackLoaded, + this, + &AutoDJProcessor::playerTrackLoaded); + + connect(deck1, + &DeckAttributes::loadingTrack, + this, + &AutoDJProcessor::playerLoadingTrack); + connect(deck2, + &DeckAttributes::loadingTrack, + this, + &AutoDJProcessor::playerLoadingTrack); + + connect(deck1, + &DeckAttributes::playerEmpty, + this, + &AutoDJProcessor::playerEmpty); + connect(deck2, + &DeckAttributes::playerEmpty, + this, + &AutoDJProcessor::playerEmpty); + + connect(deck1, + &DeckAttributes::rateChanged, + this, + &AutoDJProcessor::playerRateChanged); + connect(deck2, + &DeckAttributes::rateChanged, + this, + &AutoDJProcessor::playerRateChanged); if (!deck1Playing && !deck2Playing) { // Both decks are stopped. Load a track into deck 1 and start it @@ -497,8 +538,10 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) { } qDebug() << "Auto DJ disabled"; m_eState = ADJ_DISABLED; - disconnect(m_pCOCrossfader, &ControlProxy::valueChanged, - this, &AutoDJProcessor::crossfaderChanged); + disconnect(m_pCOCrossfader, + &ControlProxy::valueChanged, + this, + &AutoDJProcessor::crossfaderChanged); deck1->disconnect(this); deck2->disconnect(this); m_pCOCrossfader->set(0); @@ -548,9 +591,8 @@ void AutoDJProcessor::crossfaderChanged(double value) { double crossfaderPosition = value * (m_pCOCrossfaderReverse->toBool() ? -1 : 1); - if ((crossfaderPosition == 1.0 && fromDeck->isLeft()) // crossfader right - || (crossfaderPosition == -1.0 && fromDeck->isRight())) { // crossfader right - + if ((crossfaderPosition == 1.0 && fromDeck->isLeft()) || // crossfader right + (crossfaderPosition == -1.0 && fromDeck->isRight())) { // crossfader right if (!toDeck->isPlaying()) { // Re-cue the track if the user has seeked it to the very end if (toDeck->playPosition() >= toDeck->fadeBeginPos) { @@ -600,11 +642,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // To switch out of ADJ_ENABLE_P1LOADED we wait for a playposition update // for either deck. if (m_eState == ADJ_ENABLE_P1LOADED) { - DeckAttributes* leftDeck; DeckAttributes* rightDeck; - if (thisDeck->isLeft()) { leftDeck = thisDeck; DEBUG_ASSERT(otherDeck->isRight()); @@ -1246,43 +1286,34 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, outroEnd, introStart); } break; - case TransitionMode::FixedSkipSilence: - { - double startPoint; - pToDeck->fadeBeginPos = getLastSoundPosition(pToDeck); - if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { - // toDeckPosition >= pToDeck->fadeBeginPos happens when the - // user has seeked or played the to track behind fadeBeginPos of - // the fade after the next. - // In this case we recue the track just before the transition. - startPoint = getFirstSoundPosition(pToDeck); - } else { - startPoint = toDeckPosition; - } - useFixedFadeTime(pFromDeck, pToDeck, - fromDeckPosition, - getLastSoundPosition(pFromDeck), - startPoint); + case TransitionMode::FixedSkipSilence: { + double startPoint; + pToDeck->fadeBeginPos = getLastSoundPosition(pToDeck); + if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { + // toDeckPosition >= pToDeck->fadeBeginPos happens when the + // user has seeked or played the to track behind fadeBeginPos of + // the fade after the next. + // In this case we recue the track just before the transition. + startPoint = getFirstSoundPosition(pToDeck); + } else { + startPoint = toDeckPosition; } - break; + useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, getLastSoundPosition(pFromDeck), startPoint); + } break; case TransitionMode::FixedFullTrack: - default: - { - double startPoint; - pToDeck->fadeBeginPos = toTrackTime; - if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { - // toDeckPosition >= pToDeck->fadeBeginPos happens when the - // user has seeked or played the to track behind fadeBeginPos of - // the fade after the next. - // In this case we recue the track just before the transition. - startPoint = 0.0; - } else { - startPoint = toDeckPosition; - } - useFixedFadeTime(pFromDeck, pToDeck, - fromDeckPosition, - fromTrackTime, - startPoint); + default: { + double startPoint; + pToDeck->fadeBeginPos = toTrackTime; + if (seekToStartPoint || toDeckPosition >= pToDeck->fadeBeginPos) { + // toDeckPosition >= pToDeck->fadeBeginPos happens when the + // user has seeked or played the to track behind fadeBeginPos of + // the fade after the next. + // In this case we recue the track just before the transition. + startPoint = 0.0; + } else { + startPoint = toDeckPosition; + } + useFixedFadeTime(pFromDeck, pToDeck, fromDeckPosition, fromTrackTime, startPoint); } } @@ -1302,13 +1333,16 @@ void AutoDJProcessor::calculateTransition(DeckAttributes* pFromDeck, if (sDebug) { qDebug() << this << "calculateTransition" << pFromDeck->group - << pFromDeck->fadeBeginPos << pFromDeck->fadeEndPos - << pToDeck->startPos; + << pFromDeck->fadeBeginPos << pFromDeck->fadeEndPos + << pToDeck->startPos; } } void AutoDJProcessor::useFixedFadeTime(DeckAttributes* pFromDeck, - DeckAttributes* pToDeck, double fromDeckPosition, double endPoint, double startPoint) { + DeckAttributes* pToDeck, + double fromDeckPosition, + double endPoint, + double startPoint) { if (m_transitionTime > 0.0) { // Guard against the next track being too short. This transition must finish // before the next transition starts. @@ -1430,7 +1464,6 @@ void AutoDJProcessor::playerEmpty(DeckAttributes* pDeck) { loadNextTrackFromQueue(*pDeck, m_eState == ADJ_ENABLE_P1LOADED); } - void AutoDJProcessor::playerRateChanged(DeckAttributes* pAttributes) { if (sDebug) { qDebug() << this << "playerRateChanged" << pAttributes->group; @@ -1478,7 +1511,7 @@ void AutoDJProcessor::setTransitionTime(int time) { void AutoDJProcessor::setTransitionMode(TransitionMode newMode) { m_pConfig->set(ConfigKey(kConfigKey, kTransitionModePreferenceName), - ConfigValue(static_cast(newMode))); + ConfigValue(static_cast(newMode))); m_transitionMode = newMode; if (m_eState != ADJ_IDLE) { @@ -1535,7 +1568,7 @@ DeckAttributes* AutoDJProcessor::getOtherDeck( } DeckAttributes* AutoDJProcessor::getFromDeck() { - for(const auto& pDeck : m_decks) { + for (const auto& pDeck : m_decks) { if (pDeck->isFromDeck) { return pDeck; } diff --git a/src/library/autodj/autodjprocessor.h b/src/library/autodj/autodjprocessor.h index 7c306712ca8..32f90fe2214 100644 --- a/src/library/autodj/autodjprocessor.h +++ b/src/library/autodj/autodjprocessor.h @@ -121,9 +121,9 @@ class DeckAttributes : public QObject { public: int index; QString group; - double startPos; // Set in toDeck nature + double startPos; // Set in toDeck nature double fadeBeginPos; // set in fromDeck nature - double fadeEndPos; // set in fromDeck nature + double fadeEndPos; // set in fromDeck nature bool isFromDeck; bool loading; // The data is inconsistent during loading a deck @@ -234,8 +234,7 @@ class AutoDJProcessor : public QObject { protected: // The following virtual signal wrappers are used for testing - virtual void emitLoadTrackToPlayer(TrackPointer pTrack, QString group, - bool play) { + virtual void emitLoadTrackToPlayer(TrackPointer pTrack, QString group, bool play) { emit(loadTrackToPlayer(pTrack, group, play)); } virtual void emitAutoDJStateChanged(AutoDJProcessor::AutoDJState state) { @@ -265,12 +264,14 @@ class AutoDJProcessor : public QObject { void calculateTransition(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, bool seekToStartPoint); - void useFixedFadeTime(DeckAttributes* pFromDeck, DeckAttributes* pToDeck, - double fromDeckPosition, double endPoint, double startPoint); + void useFixedFadeTime(DeckAttributes* pFromDeck, + DeckAttributes* pToDeck, + double fromDeckPosition, + double endPoint, + double startPoint); DeckAttributes* getOtherDeck(const DeckAttributes* pThisDeck); DeckAttributes* getFromDeck(); - // Removes the track loaded to the player group from the top of the AutoDJ // queue if it is present. bool removeLoadedTrackFromTopOfQueue(const DeckAttributes& deck); diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index fe8b24ec676..7bae799f157 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -14,39 +14,52 @@ const char* kRepeatPlaylistPreference = "Requeue"; } // anonymous namespace DlgAutoDJ::DlgAutoDJ(QWidget* parent, - UserSettingsPointer pConfig, - Library* pLibrary, - AutoDJProcessor* pProcessor, - TrackCollection* pTrackCollection, - KeyboardEventFilter* pKeyboard, - bool showButtonText) + UserSettingsPointer pConfig, + Library* pLibrary, + AutoDJProcessor* pProcessor, + TrackCollection* pTrackCollection, + KeyboardEventFilter* pKeyboard, + bool showButtonText) : QWidget(parent), Ui::DlgAutoDJ(), m_pAutoDJProcessor(pProcessor), // no sorting - m_pTrackTableView(new WTrackTableView(this, pConfig, - pTrackCollection, false)), + m_pTrackTableView(new WTrackTableView(this, pConfig, pTrackCollection, false)), m_pAutoDJTableModel(nullptr), m_pConfig(pConfig), m_bShowButtonText(showButtonText) { setupUi(this); m_pTrackTableView->installEventFilter(pKeyboard); - connect(m_pTrackTableView, &WTrackTableView::loadTrack, - this, &DlgAutoDJ::loadTrack); - connect(m_pTrackTableView, &WTrackTableView::loadTrackToPlayer, - this, &DlgAutoDJ::loadTrackToPlayer); - connect(m_pTrackTableView, &WTrackTableView::trackSelected, - this, &DlgAutoDJ::trackSelected); - connect(m_pTrackTableView, &WTrackTableView::trackSelected, - this, &DlgAutoDJ::updateSelectionInfo); - - connect(pLibrary, &Library::setTrackTableFont, - m_pTrackTableView, &WTrackTableView::setTrackTableFont); - connect(pLibrary, &Library::setTrackTableRowHeight, - m_pTrackTableView, &WTrackTableView::setTrackTableRowHeight); - connect(pLibrary, &Library::setSelectedClick, - m_pTrackTableView, &WTrackTableView::setSelectedClick); + connect(m_pTrackTableView, + &WTrackTableView::loadTrack, + this, + &DlgAutoDJ::loadTrack); + connect(m_pTrackTableView, + &WTrackTableView::loadTrackToPlayer, + this, + &DlgAutoDJ::loadTrackToPlayer); + connect(m_pTrackTableView, + &WTrackTableView::trackSelected, + this, + &DlgAutoDJ::trackSelected); + connect(m_pTrackTableView, + &WTrackTableView::trackSelected, + this, + &DlgAutoDJ::updateSelectionInfo); + + connect(pLibrary, + &Library::setTrackTableFont, + m_pTrackTableView, + &WTrackTableView::setTrackTableFont); + connect(pLibrary, + &Library::setTrackTableRowHeight, + m_pTrackTableView, + &WTrackTableView::setTrackTableRowHeight); + connect(pLibrary, + &Library::setSelectedClick, + m_pTrackTableView, + &WTrackTableView::setSelectedClick); QBoxLayout* box = dynamic_cast(layout()); VERIFY_OR_DEBUG_ASSERT(box) { //Assumes the form layout is a QVBox/QHBoxLayout! @@ -65,61 +78,61 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, // Do not set this because it disables auto-scrolling //m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove); - connect(pushButtonAutoDJ, &QPushButton::toggled, - this, &DlgAutoDJ::toggleAutoDJButton); + connect(pushButtonAutoDJ, &QPushButton::toggled, this, &DlgAutoDJ::toggleAutoDJButton); - setupActionButton(pushButtonShuffle, &DlgAutoDJ::shufflePlaylistButton, - tr("Shuffle")); - setupActionButton(pushButtonSkipNext, &DlgAutoDJ::skipNextButton, - tr("Skip")); - setupActionButton(pushButtonAddRandom, &DlgAutoDJ::addRandomButton, - tr("Random")); - setupActionButton(pushButtonFadeNow, &DlgAutoDJ::fadeNowButton, - tr("Fade")); + setupActionButton(pushButtonShuffle, &DlgAutoDJ::shufflePlaylistButton, tr("Shuffle")); + setupActionButton(pushButtonSkipNext, &DlgAutoDJ::skipNextButton, tr("Skip")); + setupActionButton(pushButtonAddRandom, &DlgAutoDJ::addRandomButton, tr("Random")); + setupActionButton(pushButtonFadeNow, &DlgAutoDJ::fadeNowButton, tr("Fade")); - connect(spinBoxTransition, QOverload::of(&QSpinBox::valueChanged), - this, &DlgAutoDJ::transitionSliderChanged); + connect(spinBoxTransition, + QOverload::of(&QSpinBox::valueChanged), + this, + &DlgAutoDJ::transitionSliderChanged); fadeModeCombobox->addItem(tr("Full Intro + Outro"), - static_cast(AutoDJProcessor::TransitionMode::FullIntroOutro)); + static_cast(AutoDJProcessor::TransitionMode::FullIntroOutro)); fadeModeCombobox->addItem(tr("Fade At Outro Start"), - static_cast(AutoDJProcessor::TransitionMode::FadeAtOutroStart)); + static_cast(AutoDJProcessor::TransitionMode::FadeAtOutroStart)); fadeModeCombobox->addItem(tr("Full Track"), - static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); + static_cast(AutoDJProcessor::TransitionMode::FixedFullTrack)); fadeModeCombobox->addItem(tr("Skip Silence"), - static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); + static_cast(AutoDJProcessor::TransitionMode::FixedSkipSilence)); fadeModeCombobox->setCurrentIndex( fadeModeCombobox->findData(static_cast(m_pAutoDJProcessor->getTransitionMode()))); - connect(fadeModeCombobox, QOverload::of(&QComboBox::currentIndexChanged), - this, &DlgAutoDJ::slotTransitionModeChanged); + connect(fadeModeCombobox, + QOverload::of(&QComboBox::currentIndexChanged), + this, + &DlgAutoDJ::slotTransitionModeChanged); QString fadeModeTooltip = tr( - "AutoDJ Fade Modes\n" - "\n" - "Full Intro + Outro:\n" - "Play the full intro and outro. Use the intro or outro length as the\n" - "crossfade time, whichever is shorter. If no intro or outro are marked,\n" - "use the selected crossfade time.\n" - "\n" - "Fade At Outro Start:\n" - "Start crossfading at the outro start. If the outro is longer than the\n" - "intro, cut off the end of the outro. Use the intro or outro length as\n" - "the crossfade time, whichever is shorter. If no intro or outro are\n" - "marked, use the selected crossfade time.\n" - "\n" - "Full Track:\n" - "Play the whole track. Begin crossfading from the selected number of\n" - "seconds before the end of the track. A negative crossfade time adds\n" - "silence between tracks.\n" - "\n" - "Skip Silence:\n" - "Play the whole track except for silence at the beginning and end.\n" - "Begin crossfading from the selected number of seconds before the\n" - "last sound." - ); + "AutoDJ Fade Modes\n" + "\n" + "Full Intro + Outro:\n" + "Play the full intro and outro. Use the intro or outro length as the\n" + "crossfade time, whichever is shorter. If no intro or outro are marked,\n" + "use the selected crossfade time.\n" + "\n" + "Fade At Outro Start:\n" + "Start crossfading at the outro start. If the outro is longer than the\n" + "intro, cut off the end of the outro. Use the intro or outro length as\n" + "the crossfade time, whichever is shorter. If no intro or outro are\n" + "marked, use the selected crossfade time.\n" + "\n" + "Full Track:\n" + "Play the whole track. Begin crossfading from the selected number of\n" + "seconds before the end of the track. A negative crossfade time adds\n" + "silence between tracks.\n" + "\n" + "Skip Silence:\n" + "Play the whole track except for silence at the beginning and end.\n" + "Begin crossfading from the selected number of seconds before the\n" + "last sound."); fadeModeCombobox->setToolTip(fadeModeTooltip); - connect(pushButtonRepeatPlaylist, &QPushButton::toggled, - this, &DlgAutoDJ::slotRepeatPlaylistChanged); + connect(pushButtonRepeatPlaylist, + &QPushButton::toggled, + this, + &DlgAutoDJ::slotRepeatPlaylistChanged); if (m_bShowButtonText) { pushButtonRepeatPlaylist->setText(tr("Repeat")); } @@ -132,10 +145,14 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent, // mind that AutoDJ may already be active when DlgAutoDJ is created (due to // skin changes, etc.). spinBoxTransition->setValue(m_pAutoDJProcessor->getTransitionTime()); - connect(m_pAutoDJProcessor, &AutoDJProcessor::transitionTimeChanged, - this, &DlgAutoDJ::transitionTimeChanged); - connect(m_pAutoDJProcessor, &AutoDJProcessor::autoDJStateChanged, - this, &DlgAutoDJ::autoDJStateChanged); + connect(m_pAutoDJProcessor, + &AutoDJProcessor::transitionTimeChanged, + this, + &DlgAutoDJ::transitionTimeChanged); + connect(m_pAutoDJProcessor, + &AutoDJProcessor::autoDJStateChanged, + this, + &DlgAutoDJ::autoDJStateChanged); autoDJStateChanged(m_pAutoDJProcessor->getState()); updateSelectionInfo(); @@ -149,7 +166,9 @@ DlgAutoDJ::~DlgAutoDJ() { delete m_pTrackTableView; } -void DlgAutoDJ::setupActionButton(QPushButton* pButton, void (DlgAutoDJ::*pSlot)(bool), QString fallbackText) { +void DlgAutoDJ::setupActionButton(QPushButton* pButton, + void (DlgAutoDJ::*pSlot)(bool), + QString fallbackText) { connect(pButton, &QPushButton::clicked, this, pSlot); if (m_bShowButtonText) { pButton->setText(fallbackText); @@ -260,7 +279,7 @@ void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) { void DlgAutoDJ::slotTransitionModeChanged(int comboboxIndex) { m_pAutoDJProcessor->setTransitionMode(static_cast( - fadeModeCombobox->itemData(comboboxIndex).toInt())); + fadeModeCombobox->itemData(comboboxIndex).toInt())); } void DlgAutoDJ::slotRepeatPlaylistChanged(int checkState) { diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index 7324e86eeec..091702b7282 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -19,11 +19,13 @@ class WTrackTableView; class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { Q_OBJECT public: - DlgAutoDJ(QWidget* parent, UserSettingsPointer pConfig, - Library* pLibrary, - AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, - KeyboardEventFilter* pKeyboard, - bool showButtonText); + DlgAutoDJ(QWidget* parent, + UserSettingsPointer pConfig, + Library* pLibrary, + AutoDJProcessor* pProcessor, + TrackCollection* pTrackCollection, + KeyboardEventFilter* pKeyboard, + bool showButtonText); ~DlgAutoDJ() override; void onShow() override; @@ -52,8 +54,9 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { void trackSelected(TrackPointer pTrack); private: - void setupActionButton(QPushButton* pButton, void (DlgAutoDJ::*pSlot)(bool), - QString fallbackText); + void setupActionButton(QPushButton* pButton, + void (DlgAutoDJ::*pSlot)(bool), + QString fallbackText); AutoDJProcessor* m_pAutoDJProcessor; WTrackTableView* m_pTrackTableView; diff --git a/src/preferences/dialog/dlgprefdeck.cpp b/src/preferences/dialog/dlgprefdeck.cpp index a94afe56420..af130ff1254 100644 --- a/src/preferences/dialog/dlgprefdeck.cpp +++ b/src/preferences/dialog/dlgprefdeck.cpp @@ -58,7 +58,6 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, int cueDefaultValue = m_pConfig->getValue( ConfigKey("[Controls]", "CueDefault"), 0); - // Update combo box ComboBoxCueMode->addItem(tr("Mixxx mode"), static_cast(CueMode::Mixxx)); ComboBoxCueMode->addItem(tr("Mixxx mode (no blinking)"), static_cast(CueMode::MixxxNoBlinking)); @@ -111,7 +110,10 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, m_pControlTrackTimeFormat = new ControlObject( ConfigKey("[Controls]", "TimeFormat")); - connect(m_pControlTrackTimeFormat, &ControlObject::valueChanged, this, &DlgPrefDeck::slotTimeFormatChanged); + connect(m_pControlTrackTimeFormat, + &ControlObject::valueChanged, + this, + &DlgPrefDeck::slotTimeFormatChanged); QLocale locale; // Track Display model @@ -164,12 +166,14 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, comboBoxLoadPoint->addItem(tr("Beginning of track"), static_cast(SeekOnLoadMode::Beginning)); bool seekModeExisted = m_pConfig->exists(ConfigKey("[Controls]", "CueRecall")); int seekMode = m_pConfig->getValue(ConfigKey("[Controls]", "CueRecall"), - static_cast(SeekOnLoadMode::IntroStart)); + static_cast(SeekOnLoadMode::IntroStart)); comboBoxLoadPoint->setCurrentIndex( comboBoxLoadPoint->findData(seekMode)); m_seekOnLoadMode = static_cast(seekMode); - connect(comboBoxLoadPoint, QOverload::of(&QComboBox::currentIndexChanged), - this, &DlgPrefDeck::slotSetTrackLoadMode); + connect(comboBoxLoadPoint, + QOverload::of(&QComboBox::currentIndexChanged), + this, + &DlgPrefDeck::slotSetTrackLoadMode); // This option was introduced in Mixxx 2.3 with the intro & outro cues. // If the user has set main cue points with the intention of starting tracks @@ -178,30 +182,38 @@ DlgPrefDeck::DlgPrefDeck(QWidget * parent, MixxxMainWindow * mixxx, // main cue point because it is very easy to move the main cue point without // explicitly intending to in those modes (the main cue point moves whenever // the deck is not at the main cue point and play is pressed). - bool introStartMoveDefault = (m_seekOnLoadMode == SeekOnLoadMode::MainCue || !seekModeExisted) - && !(m_cueMode == CueMode::Denon || m_cueMode == CueMode::Numark); + bool introStartMoveDefault = (m_seekOnLoadMode == SeekOnLoadMode::MainCue || + !seekModeExisted) && + !(m_cueMode == CueMode::Denon || + m_cueMode == CueMode::Numark); m_bSetIntroStartAtMainCue = m_pConfig->getValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), - introStartMoveDefault); + introStartMoveDefault); // This is an ugly hack to ensure AnalyzerSilence gets the correct default // value because ConfigValue::getValue does not set the value of the ConfigValue // in case no value had been set previously (when mixxx.cfg is empty). m_pConfig->setValue(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), m_bSetIntroStartAtMainCue); checkBoxIntroStartMove->setChecked(m_bSetIntroStartAtMainCue); - connect(checkBoxIntroStartMove, &QCheckBox::toggled, - this, &DlgPrefDeck::slotMoveIntroStartCheckbox); + connect(checkBoxIntroStartMove, + &QCheckBox::toggled, + this, + &DlgPrefDeck::slotMoveIntroStartCheckbox); // Double-tap Load to clone a deck via keyboard or controller ([ChannelN],LoadSelectedTrack) m_bCloneDeckOnLoadDoubleTap = m_pConfig->getValue( ConfigKey("[Controls]", "CloneDeckOnLoadDoubleTap"), true); checkBoxCloneDeckOnLoadDoubleTap->setChecked(m_bCloneDeckOnLoadDoubleTap); - connect(checkBoxCloneDeckOnLoadDoubleTap, SIGNAL(toggled(bool)), - this, SLOT(slotCloneDeckOnLoadDoubleTapCheckbox(bool))); + connect(checkBoxCloneDeckOnLoadDoubleTap, + SIGNAL(toggled(bool)), + this, + SLOT(slotCloneDeckOnLoadDoubleTapCheckbox(bool))); // Automatically assign a color to new hot cues m_bAssignHotcueColors = m_pConfig->getValue(ConfigKey("[Controls]", "auto_hotcue_colors"), false); checkBoxAssignHotcueColors->setChecked(m_bAssignHotcueColors); - connect(checkBoxAssignHotcueColors, SIGNAL(toggled(bool)), - this, SLOT(slotAssignHotcueColorsCheckbox(bool))); + connect(checkBoxAssignHotcueColors, + SIGNAL(toggled(bool)), + this, + SLOT(slotAssignHotcueColorsCheckbox(bool))); m_bRateInverted = m_pConfig->getValue(ConfigKey("[Controls]", "RateDir"), false); setRateDirectionForAllDecks(m_bRateInverted); @@ -455,7 +467,7 @@ void DlgPrefDeck::slotResetToDefaults() { // Load at intro start comboBoxLoadPoint->setCurrentIndex( - comboBoxLoadPoint->findData(static_cast(SeekOnLoadMode::IntroStart))); + comboBoxLoadPoint->findData(static_cast(SeekOnLoadMode::IntroStart))); // Rate-ramping default off. radioButtonRateRampModeStepping->setChecked(true); @@ -603,12 +615,12 @@ void DlgPrefDeck::slotTimeFormatChanged(double v) { void DlgPrefDeck::slotSetTrackLoadMode(int comboboxIndex) { m_seekOnLoadMode = static_cast( - comboBoxLoadPoint->itemData(comboboxIndex).toInt()); + comboBoxLoadPoint->itemData(comboboxIndex).toInt()); } void DlgPrefDeck::slotApply() { m_pConfig->set(ConfigKey("[Controls]", "SetIntroStartAtMainCue"), - ConfigValue(m_bSetIntroStartAtMainCue)); + ConfigValue(m_bSetIntroStartAtMainCue)); double timeDisplay = static_cast(m_timeDisplayMode); m_pConfig->set(ConfigKey("[Controls]","PositionDisplay"), ConfigValue(timeDisplay)); @@ -630,7 +642,7 @@ void DlgPrefDeck::slotApply() { m_pConfig->setValue(ConfigKey("[Controls]", "CueRecall"), static_cast(m_seekOnLoadMode)); m_pConfig->setValue(ConfigKey("[Controls]", "CloneDeckOnLoadDoubleTap"), - m_bCloneDeckOnLoadDoubleTap); + m_bCloneDeckOnLoadDoubleTap); m_pConfig->setValue(ConfigKey("[Controls]", "auto_hotcue_colors"), m_bAssignHotcueColors); // Set rate range diff --git a/src/preferences/dialog/dlgprefdeck.h b/src/preferences/dialog/dlgprefdeck.h index 7cb5d5b3885..cbc3b5b8688 100644 --- a/src/preferences/dialog/dlgprefdeck.h +++ b/src/preferences/dialog/dlgprefdeck.h @@ -3,12 +3,12 @@ #include -#include "engine/controls/ratecontrol.h" #include "engine/controls/cuecontrol.h" +#include "engine/controls/ratecontrol.h" #include "preferences/constants.h" #include "preferences/dialog/ui_dlgprefdeckdlg.h" -#include "preferences/usersettings.h" #include "preferences/dlgpreferencepage.h" +#include "preferences/usersettings.h" class ControlProxy; class ControlPotmeter; @@ -18,7 +18,7 @@ class MixxxMainWindow; class ControlObject; namespace { - constexpr bool kDefaultCloneDeckOnLoad = true; +constexpr bool kDefaultCloneDeckOnLoad = true; } namespace TrackTime { diff --git a/src/test/autodjprocessor_test.cpp b/src/test/autodjprocessor_test.cpp index a5d88b25272..60c25e2a9f8 100644 --- a/src/test/autodjprocessor_test.cpp +++ b/src/test/autodjprocessor_test.cpp @@ -224,7 +224,6 @@ class AutoDJProcessorTest : public LibraryTest { QScopedPointer pProcessor; }; - TEST_F(AutoDJProcessorTest, FullIntroOutro_LongerIntro) { pProcessor->setTransitionMode(AutoDJProcessor::TransitionMode::FullIntroOutro); @@ -1417,7 +1416,6 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_Long_Transition) { deck1.playposition.set(1.0); EXPECT_EQ(AutoDJProcessor::ADJ_LEFT_FADING, pProcessor->getState()); - EXPECT_DOUBLE_EQ(1.0, master.crossfader.get()); // Deck is still playing, because the crossfader is processed in the next audio // calback. diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index d1ccb6c37b2..88d1f0286fe 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -44,29 +44,29 @@ WOverview::WOverview( const char* group, PlayerManager* pPlayerManager, UserSettingsPointer pConfig, - QWidget* parent) : - WWidget(parent), - m_actualCompletion(0), - m_pixmapDone(false), - m_waveformPeak(-1.0), - m_diffGain(0), - m_devicePixelRatio(1.0), - m_group(group), - m_pConfig(pConfig), - m_endOfTrack(false), - m_pCueMenu(std::make_unique(this)), - m_bShowCueTimes(true), - m_iPosSeconds(0), - m_iPos(0), - m_pHoveredMark(nullptr), - m_bHotcueMenuShowing(false), - m_bTimeRulerActive(false), - m_orientation(Qt::Horizontal), - m_a(1.0), - m_b(0.0), - m_analyzerProgress(kAnalyzerProgressUnknown), - m_trackLoaded(false), - m_scaleFactor(1.0) { + QWidget* parent) + : WWidget(parent), + m_actualCompletion(0), + m_pixmapDone(false), + m_waveformPeak(-1.0), + m_diffGain(0), + m_devicePixelRatio(1.0), + m_group(group), + m_pConfig(pConfig), + m_endOfTrack(false), + m_pCueMenu(std::make_unique(this)), + m_bShowCueTimes(true), + m_iPosSeconds(0), + m_iPos(0), + m_pHoveredMark(nullptr), + m_bHotcueMenuShowing(false), + m_bTimeRulerActive(false), + m_orientation(Qt::Horizontal), + m_a(1.0), + m_b(0.0), + m_analyzerProgress(kAnalyzerProgressUnknown), + m_trackLoaded(false), + m_scaleFactor(1.0) { m_endOfTrackControl = new ControlProxy( m_group, "end_of_track", this); m_endOfTrackControl->connectValueChanged(this, &WOverview::onEndOfTrackChange); @@ -87,8 +87,7 @@ WOverview::WOverview( connect(pPlayerManager, &PlayerManager::trackAnalyzerProgress, this, &WOverview::onTrackAnalyzerProgress); - connect(m_pCueMenu.get(), &QMenu::aboutToHide, - this, &WOverview::slotCueMenuAboutToHide); + connect(m_pCueMenu.get(), &QMenu::aboutToHide, this, &WOverview::slotCueMenuAboutToHide); } void WOverview::setup(const QDomNode& node, const SkinContext& context) { @@ -220,8 +219,7 @@ void WOverview::onConnectedControlChanged(double dParameter, double dValue) { // of the widget. int oldPositionSeconds = m_iPosSeconds; m_iPosSeconds = static_cast(dParameter * m_trackSamplesControl->get()); - if ((m_bTimeRulerActive || m_pHoveredMark != nullptr) - && oldPositionSeconds != m_iPosSeconds) { + if ((m_bTimeRulerActive || m_pHoveredMark != nullptr) && oldPositionSeconds != m_iPosSeconds) { redraw = true; } @@ -340,8 +338,7 @@ void WOverview::updateCues(const QList &loadedCues) { for (CuePointer currentCue: loadedCues) { const WaveformMarkPointer pMark = m_marks.getHotCueMark(currentCue->getHotCue()); - if (pMark != nullptr && pMark->isValid() && pMark->isVisible() - && pMark->getSamplePosition() != Cue::kNoPosition) { + if (pMark != nullptr && pMark->isValid() && pMark->isVisible() && pMark->getSamplePosition() != Cue::kNoPosition) { QColor newColor = m_predefinedColorsRepresentation.representationFor(currentCue->getColor()); if (newColor != pMark->fillColor() || newColor != pMark->m_textColor) { pMark->setBaseColor(newColor); @@ -368,10 +365,7 @@ void WOverview::updateCues(const QList &loadedCues) { // The loop above only adds WaveformMarks for hotcues to m_marksToRender. for (const auto& pMark : m_marks) { - if (!m_marksToRender.contains(pMark) - && pMark->isValid() - && pMark->getSamplePosition() != Cue::kNoPosition - && pMark->isVisible()) { + if (!m_marksToRender.contains(pMark) && pMark->isValid() && pMark->getSamplePosition() != Cue::kNoPosition && pMark->isVisible()) { m_marksToRender.append(pMark); } } @@ -406,7 +400,7 @@ void WOverview::mouseMoveEvent(QMouseEvent* e) { // the hotcue rendered on top must be assigned to m_pHoveredMark to show // the CueMenu. To accomplish this, m_marksToRender is iterated in reverse // and the loop breaks as soon as m_pHoveredMark is set. - for (int i = m_marksToRender.size() - 1; i >= 0 ; --i) { + for (int i = m_marksToRender.size() - 1; i >= 0; --i) { WaveformMarkPointer pMark = m_marksToRender.at(i); int hoveredPosition; if (m_orientation == Qt::Horizontal) { @@ -415,8 +409,7 @@ void WOverview::mouseMoveEvent(QMouseEvent* e) { hoveredPosition = e->y(); } bool lineHovered = - pMark->m_linePosition >= hoveredPosition - lineHoverPadding - && pMark->m_linePosition <= hoveredPosition + lineHoverPadding; + pMark->m_linePosition >= hoveredPosition - lineHoverPadding && pMark->m_linePosition <= hoveredPosition + lineHoverPadding; if (pMark->m_label.area().contains(e->pos()) || lineHovered) { m_pHoveredMark = pMark; @@ -709,7 +702,8 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga const qreal markPosition = math_clamp( offset + m_marksToRender.at(i)->getSamplePosition() * gain, - 0.0, static_cast(width())); + 0.0, + static_cast(width())); pMark->m_linePosition = markPosition; QPen shadowPen(QBrush(pMark->borderColor()), 2.5 * m_scaleFactor); @@ -736,14 +730,13 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga // hovering over it. Elide it if it would render over the next // label, but do not elide it if the next mark's label is not at the // same vertical position. - if (pMark != m_pHoveredMark && i < m_marksToRender.size()-1) { + if (pMark != m_pHoveredMark && i < m_marksToRender.size() - 1) { float nextMarkPosition = -1.0; for (int m = i + 1; m < m_marksToRender.size() - 1; ++m) { WaveformMarkPointer otherMark = m_marksToRender.at(m); bool otherAtSameHeight = valign == (otherMark->m_align & Qt::AlignVertical_Mask); // Hotcues always show at least their number. - bool otherHasLabel = !otherMark->m_text.isEmpty() - || otherMark->getHotCue() != Cue::kNoHotCue; + bool otherHasLabel = !otherMark->m_text.isEmpty() || otherMark->getHotCue() != Cue::kNoHotCue; if (otherAtSameHeight && otherHasLabel) { nextMarkPosition = offset + otherMark->getSamplePosition() * gain; break; @@ -756,9 +749,8 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga // Sometimes QFontMetrics::elidedText turns the QString into just an // elipsis character, so always show at least the hotcue number if // the label does not fit. - if ((text.isEmpty() || text == "…") - && pMark->getHotCue() != Cue::kNoHotCue) { - text = QString::number(pMark->getHotCue()+1); + if ((text.isEmpty() || text == "…") && pMark->getHotCue() != Cue::kNoHotCue) { + text = QString::number(pMark->getHotCue() + 1); } QRectF textRect = fontMetrics.boundingRect(text); @@ -797,9 +789,7 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga } } - pMark->m_label.prerender(textPoint, QPixmap(), text, - markerFont, m_labelTextColor, m_labelBackgroundColor, - width(), getDevicePixelRatioF(this)); + pMark->m_label.prerender(textPoint, QPixmap(), text, markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); } // Show cue position when hovered @@ -840,12 +830,10 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga cueTimeDistanceText = "-" + cueTimeDistanceText; } - m_cuePositionLabel.prerender(positionTextPoint, QPixmap(), cuePositionText, - markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); + m_cuePositionLabel.prerender(positionTextPoint, QPixmap(), cuePositionText, markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); QPointF timeDistancePoint(positionTextPoint.x(), (fontMetrics.height() + height()) / 2); - m_cueTimeDistanceLabel.prerender(timeDistancePoint, QPixmap(), cueTimeDistanceText, - markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); + m_cueTimeDistanceLabel.prerender(timeDistancePoint, QPixmap(), cueTimeDistanceText, markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); markHovered = true; } } @@ -925,11 +913,9 @@ void WOverview::drawTimeRuler(QPainter* pPainter) { qreal timeDistance = samplePositionToSeconds( (widgetPositionFraction - m_playpositionControl->get()) * trackSamples); - QString timeText = mixxx::Duration::formatTime(timePosition) - + " -" + mixxx::Duration::formatTime(timePositionTillEnd); + QString timeText = mixxx::Duration::formatTime(timePosition) + " -" + mixxx::Duration::formatTime(timePositionTillEnd); - m_timeRulerPositionLabel.prerender(textPoint, QPixmap(), timeText, - markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); + m_timeRulerPositionLabel.prerender(textPoint, QPixmap(), timeText, markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); m_timeRulerPositionLabel.draw(pPainter); QString timeDistanceText = mixxx::Duration::formatTime(fabs(timeDistance)); @@ -938,8 +924,7 @@ void WOverview::drawTimeRuler(QPainter* pPainter) { if (static_cast(timeDistance) < 0) { timeDistanceText = "-" + timeDistanceText; } - m_timeRulerDistanceLabel.prerender(textPointDistance, QPixmap(), timeDistanceText, - markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); + m_timeRulerDistanceLabel.prerender(textPointDistance, QPixmap(), timeDistanceText, markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); m_timeRulerDistanceLabel.draw(pPainter); } else { m_timeRulerPositionLabel.clear(); @@ -960,12 +945,10 @@ void WOverview::drawMarkLabels(QPainter* pPainter, const float offset, const flo } } if (m_bShowCueTimes && - (pMark->m_label.intersects(m_cuePositionLabel) - || pMark->m_label.intersects(m_cueTimeDistanceLabel))) { + (pMark->m_label.intersects(m_cuePositionLabel) || pMark->m_label.intersects(m_cueTimeDistanceLabel))) { continue; } - if (pMark->m_label.intersects(m_timeRulerPositionLabel) - || pMark->m_label.intersects(m_timeRulerDistanceLabel)) { + if (pMark->m_label.intersects(m_timeRulerPositionLabel) || pMark->m_label.intersects(m_timeRulerDistanceLabel)) { continue; } @@ -1006,14 +989,9 @@ void WOverview::drawMarkLabels(QPainter* pPainter, const float offset, const flo QPointF durationBottomLeft(x, fontMetrics.height()); - markRange.m_durationLabel.prerender(durationBottomLeft, QPixmap(), - duration, markerFont, m_labelTextColor, - m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); + markRange.m_durationLabel.prerender(durationBottomLeft, QPixmap(), duration, markerFont, m_labelTextColor, m_labelBackgroundColor, width(), getDevicePixelRatioF(this)); - if (!(markRange.m_durationLabel.intersects(m_cuePositionLabel) - || markRange.m_durationLabel.intersects(m_cueTimeDistanceLabel) - || markRange.m_durationLabel.intersects(m_timeRulerPositionLabel) - || markRange.m_durationLabel.intersects(m_timeRulerDistanceLabel))) { + if (!(markRange.m_durationLabel.intersects(m_cuePositionLabel) || markRange.m_durationLabel.intersects(m_cueTimeDistanceLabel) || markRange.m_durationLabel.intersects(m_timeRulerPositionLabel) || markRange.m_durationLabel.intersects(m_timeRulerDistanceLabel))) { markRange.m_durationLabel.draw(pPainter); } } @@ -1049,10 +1027,8 @@ void WOverview::paintText(const QString& text, QPainter* pPainter) { double WOverview::samplePositionToSeconds(double sample) { // TODO: replace with rate_ratio in PR #1765 - double rateRatio = 1.0 + m_pRateDirControl->get() - * m_pRateRangeControl->get() * m_pRateSliderControl->get(); - return sample / m_trackSampleRateControl->get() - / mixxx::kEngineChannelCount / rateRatio; + double rateRatio = 1.0 + m_pRateDirControl->get() * m_pRateRangeControl->get() * m_pRateSliderControl->get(); + return sample / m_trackSampleRateControl->get() / mixxx::kEngineChannelCount / rateRatio; } void WOverview::resizeEvent(QResizeEvent * /*unused*/) { diff --git a/src/widget/woverview.h b/src/widget/woverview.h index 9df3e48829b..79c0d52d9d5 100644 --- a/src/widget/woverview.h +++ b/src/widget/woverview.h @@ -18,11 +18,11 @@ #include #include +#include "analyzer/analyzerprogress.h" #include "track/track.h" #include "widget/cuemenu.h" #include "widget/trackdroptarget.h" #include "widget/wwidget.h" -#include "analyzer/analyzerprogress.h" #include "util/color/color.h" @@ -103,7 +103,6 @@ class WOverview : public WWidget, public TrackDropTarget { void slotWaveformSummaryUpdated(); void slotCueMenuAboutToHide(); - private: // Append the waveform overview pixmap according to available data // in waveform From 082e2e6065c5da9d0924ce1e40191763cd752d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 10 Nov 2019 02:35:22 +0100 Subject: [PATCH 198/198] Fix a bug where outro end was passed the end of the track, because not updated lenght info when updating outro start. --- src/engine/controls/cuecontrol.cpp | 30 ++++-------- src/library/autodj/autodjprocessor.cpp | 3 ++ src/mixer/basetrackplayer.cpp | 2 +- src/test/analyzersilence_test.cpp | 16 +++--- src/test/cuecontrol_test.cpp | 68 +++++++++++++------------- src/track/cue.cpp | 47 ++++++++---------- src/track/cue.h | 3 +- 7 files changed, 77 insertions(+), 92 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index e8bc100292a..3a160eded79 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1149,7 +1149,7 @@ void CueControl::introStartSet(double v) { pCue->setType(Cue::Type::Intro); } pCue->setStartPosition(position); - pCue->setLength(introEnd != Cue::kNoPosition ? introEnd - position : 0.0); + pCue->setEndPosition(introEnd); } } @@ -1167,7 +1167,7 @@ void CueControl::introStartClear(double v) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (introEnd != Cue::kNoPosition) { pCue->setStartPosition(Cue::kNoPosition); - pCue->setLength(introEnd); + pCue->setEndPosition(introEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); } @@ -1226,13 +1226,8 @@ void CueControl::introEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Intro); } - if (introStart != Cue::kNoPosition) { - pCue->setStartPosition(introStart); - pCue->setLength(position - introStart); - } else { - pCue->setStartPosition(Cue::kNoPosition); - pCue->setLength(position); - } + pCue->setStartPosition(introStart); + pCue->setEndPosition(position); } } @@ -1250,7 +1245,7 @@ void CueControl::introEndClear(double v) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Intro); if (introStart != Cue::kNoPosition) { pCue->setStartPosition(introStart); - pCue->setLength(0.0); + pCue->setEndPosition(Cue::kNoPosition); } else if (pCue) { pLoadedTrack->removeCue(pCue); } @@ -1310,7 +1305,7 @@ void CueControl::outroStartSet(double v) { pCue->setType(Cue::Type::Outro); } pCue->setStartPosition(position); - pCue->setLength(outroEnd != Cue::kNoPosition ? outroEnd - position : 0.0); + pCue->setEndPosition(outroEnd); } } @@ -1328,7 +1323,7 @@ void CueControl::outroStartClear(double v) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (outroEnd != Cue::kNoPosition) { pCue->setStartPosition(Cue::kNoPosition); - pCue->setLength(outroEnd); + pCue->setEndPosition(outroEnd); } else if (pCue) { pLoadedTrack->removeCue(pCue); } @@ -1387,13 +1382,8 @@ void CueControl::outroEndSet(double v) { pCue = pLoadedTrack->createAndAddCue(); pCue->setType(Cue::Type::Outro); } - if (outroStart != Cue::kNoPosition) { - pCue->setStartPosition(outroStart); - pCue->setLength(position - outroStart); - } else { - pCue->setStartPosition(Cue::kNoPosition); - pCue->setLength(position); - } + pCue->setStartPosition(outroStart); + pCue->setEndPosition(position); } } @@ -1411,7 +1401,7 @@ void CueControl::outroEndClear(double v) { CuePointer pCue = pLoadedTrack->findCueByType(Cue::Type::Outro); if (outroStart != Cue::kNoPosition) { pCue->setStartPosition(outroStart); - pCue->setLength(0.0); + pCue->setEndPosition(Cue::kNoPosition); } else if (pCue) { pLoadedTrack->removeCue(pCue); } diff --git a/src/library/autodj/autodjprocessor.cpp b/src/library/autodj/autodjprocessor.cpp index 2cadc453eac..5d8ed0368cf 100644 --- a/src/library/autodj/autodjprocessor.cpp +++ b/src/library/autodj/autodjprocessor.cpp @@ -786,6 +786,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes, // P1/P2FADING case above). thisDeck->stop(); m_transitionProgress = 1.0; + // Note: If the user has stopped the toDeck during the transition. + // this deck just stops as well. In this case a stopped AutoDJ is accepted + // because the use did it intentionally } else { // We are in Fading state. // Calculate the current transitionProgress, the place between begin diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 8e55acd58be..b66d84bc16b 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -229,7 +229,7 @@ TrackPointer BaseTrackPlayerImpl::unloadTrack() { pLoopCue->setType(Cue::Type::Loop); } pLoopCue->setStartPosition(loopStart); - pLoopCue->setLength(loopEnd - loopStart); + pLoopCue->setEndPosition(loopEnd); } disconnectLoadedTrack(); diff --git a/src/test/analyzersilence_test.cpp b/src/test/analyzersilence_test.cpp index 1c877e4e72b..3f4c117d8f3 100644 --- a/src/test/analyzersilence_test.cpp +++ b/src/test/analyzersilence_test.cpp @@ -59,7 +59,7 @@ TEST_F(AnalyzerSilenceTest, SilenceTrack) { EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); - EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); } @@ -80,7 +80,7 @@ TEST_F(AnalyzerSilenceTest, EndToEndToneTrack) { EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); - EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(nTrackSampleDataLength, pOutroCue->getLength()); } @@ -111,7 +111,7 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilence) { EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); - EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(3 * nTrackSampleDataLength / 4, pOutroCue->getLength()); } @@ -154,7 +154,7 @@ TEST_F(AnalyzerSilenceTest, ToneTrackWithSilenceInTheMiddle) { EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); CuePointer pOutroCue = pTrack->findCueByType(Cue::Type::Outro); - EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(4 * oneFifthOfTrackLength, pOutroCue->getLength()); } @@ -169,12 +169,12 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { CuePointer pIntroCue = pTrack->createAndAddCue(); pIntroCue->setType(Cue::Type::Intro); pIntroCue->setStartPosition(kManualIntroPosition); - pIntroCue->setLength(0.0); + pIntroCue->setEndPosition(Cue::kNoPosition); CuePointer pOutroCue = pTrack->createAndAddCue(); pOutroCue->setType(Cue::Type::Outro); - pOutroCue->setStartPosition(-1.0); - pOutroCue->setLength(kManualOutroPosition); + pOutroCue->setStartPosition(Cue::kNoPosition); + pOutroCue->setEndPosition(kManualOutroPosition); // Fill the first half with silence for (int i = 0; i < nTrackSampleDataLength / 2; i++) { @@ -195,7 +195,7 @@ TEST_F(AnalyzerSilenceTest, RespectUserEdits) { EXPECT_DOUBLE_EQ(kManualIntroPosition, pIntroCue->getPosition()); EXPECT_DOUBLE_EQ(0.0, pIntroCue->getLength()); - EXPECT_DOUBLE_EQ(-1.0, pOutroCue->getPosition()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, pOutroCue->getPosition()); EXPECT_DOUBLE_EQ(kManualOutroPosition, pOutroCue->getLength()); } diff --git a/src/test/cuecontrol_test.cpp b/src/test/cuecontrol_test.cpp index 50ee9e753fe..206c5fe81a1 100644 --- a/src/test/cuecontrol_test.cpp +++ b/src/test/cuecontrol_test.cpp @@ -79,11 +79,11 @@ TEST_F(CueControlTest, LoadUnloadTrack) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); pIntro->setStartPosition(150.0); - pIntro->setLength(50.0); + pIntro->setEndPosition(200.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); pOutro->setStartPosition(250.0); - pOutro->setLength(50.0); + pOutro->setEndPosition(300.0); loadTrack(pTrack); @@ -99,11 +99,11 @@ TEST_F(CueControlTest, LoadUnloadTrack) { unloadTrack(); - EXPECT_DOUBLE_EQ(-1.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroStartPosition->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroEndPosition->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroStartPosition->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pCuePoint->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroEndPosition->get()); EXPECT_FALSE(m_pIntroStartEnabled->toBool()); EXPECT_FALSE(m_pIntroEndEnabled->toBool()); EXPECT_FALSE(m_pOutroStartEnabled->toBool()); @@ -116,18 +116,18 @@ TEST_F(CueControlTest, LoadTrackWithDetectedCues) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); pIntro->setStartPosition(100.0); - pIntro->setLength(0.0); + pIntro->setEndPosition(Cue::kNoPosition); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); - pOutro->setStartPosition(-1.0); - pOutro->setLength(200.0); + pOutro->setStartPosition(Cue::kNoPosition); + pOutro->setEndPosition(200.0); loadTrack(pTrack); EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(100.0, m_pIntroStartPosition->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroEndPosition->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroStartPosition->get()); EXPECT_DOUBLE_EQ(200.0, m_pOutroEndPosition->get()); EXPECT_TRUE(m_pIntroStartEnabled->toBool()); EXPECT_FALSE(m_pIntroEndEnabled->toBool()); @@ -139,20 +139,20 @@ TEST_F(CueControlTest, LoadTrackWithIntroEndAndOutroStart) { TrackPointer pTrack = createTestTrack(); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); - pIntro->setStartPosition(-1.0); - pIntro->setLength(150.0); + pIntro->setStartPosition(Cue::kNoPosition); + pIntro->setEndPosition(150.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); pOutro->setStartPosition(250.0); - pOutro->setLength(0.0); + pOutro->setEndPosition(Cue::kNoPosition); loadTrack(pTrack); EXPECT_DOUBLE_EQ(0.0, m_pCuePoint->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroStartPosition->get()); EXPECT_DOUBLE_EQ(150.0, m_pIntroEndPosition->get()); EXPECT_DOUBLE_EQ(250.0, m_pOutroStartPosition->get()); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroEndPosition->get()); EXPECT_FALSE(m_pIntroStartEnabled->toBool()); EXPECT_TRUE(m_pIntroEndEnabled->toBool()); EXPECT_TRUE(m_pOutroStartEnabled->toBool()); @@ -176,12 +176,12 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabled) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); pIntro->setStartPosition(2.1 * beatLength); - pIntro->setLength(1.2 * beatLength); + pIntro->setEndPosition(3.3 * beatLength); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); pOutro->setStartPosition(11.1 * beatLength); - pOutro->setLength(4.4 * beatLength); + pOutro->setEndPosition(15.5 * beatLength); loadTrack(pTrack); @@ -204,12 +204,12 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabledNoBeats) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); pIntro->setStartPosition(250.0); - pIntro->setLength(150.0); + pIntro->setEndPosition(400.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); pOutro->setStartPosition(550.0); - pOutro->setLength(250.0); + pOutro->setEndPosition(800.0); loadTrack(pTrack); @@ -232,12 +232,12 @@ TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); pIntro->setStartPosition(210.0); - pIntro->setLength(120.0); + pIntro->setEndPosition(330.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::Type::Outro); pOutro->setStartPosition(770.0); - pOutro->setLength(220.0); + pOutro->setEndPosition(990.0); loadTrack(pTrack); @@ -254,7 +254,7 @@ TEST_F(CueControlTest, SeekOnLoadDefault) { auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::Type::Intro); pIntro->setStartPosition(250.0); - pIntro->setLength(150.0); + pIntro->setEndPosition(400.0); loadTrack(pTrack); @@ -309,7 +309,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { m_pIntroStartSet->slotSet(0); EXPECT_DOUBLE_EQ(100.0, m_pIntroStartPosition->get()); EXPECT_TRUE(m_pIntroStartEnabled->toBool()); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroEndPosition->get()); EXPECT_FALSE(m_pIntroEndEnabled->toBool()); CuePointer pCue = pTrack->findCueByType(Cue::Type::Intro); @@ -338,7 +338,7 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { // Clear intro start cue m_pIntroStartClear->slotSet(1); m_pIntroStartClear->slotSet(0); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroStartPosition->get()); EXPECT_FALSE(m_pIntroStartEnabled->toBool()); EXPECT_DOUBLE_EQ(500.0, m_pIntroEndPosition->get()); EXPECT_TRUE(m_pIntroEndEnabled->toBool()); @@ -346,16 +346,16 @@ TEST_F(CueControlTest, IntroCue_SetStartEnd_ClearStartEnd) { pCue = pTrack->findCueByType(Cue::Type::Intro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, pCue->getPosition()); EXPECT_DOUBLE_EQ(500.0, pCue->getLength()); } // Clear intro end cue m_pIntroEndClear->slotSet(1); m_pIntroEndClear->slotSet(0); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroStartPosition->get()); EXPECT_FALSE(m_pIntroStartEnabled->toBool()); - EXPECT_DOUBLE_EQ(-1.0, m_pIntroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pIntroEndPosition->get()); EXPECT_FALSE(m_pIntroEndEnabled->toBool()); EXPECT_EQ(nullptr, pTrack->findCueByType(Cue::Type::Intro)); @@ -370,7 +370,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { m_pOutroStartSet->slotSet(0); EXPECT_DOUBLE_EQ(750.0, m_pOutroStartPosition->get()); EXPECT_TRUE(m_pOutroStartEnabled->toBool()); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroEndPosition->get()); EXPECT_FALSE(m_pOutroEndEnabled->toBool()); CuePointer pCue = pTrack->findCueByType(Cue::Type::Outro); @@ -399,7 +399,7 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { // Clear outro start cue m_pOutroStartClear->slotSet(1); m_pOutroStartClear->slotSet(0); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroStartPosition->get()); EXPECT_FALSE(m_pOutroStartEnabled->toBool()); EXPECT_DOUBLE_EQ(1000.0, m_pOutroEndPosition->get()); EXPECT_TRUE(m_pOutroEndEnabled->toBool()); @@ -407,16 +407,16 @@ TEST_F(CueControlTest, OutroCue_SetStartEnd_ClearStartEnd) { pCue = pTrack->findCueByType(Cue::Type::Outro); EXPECT_NE(nullptr, pCue); if (pCue != nullptr) { - EXPECT_DOUBLE_EQ(-1.0, pCue->getPosition()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, pCue->getPosition()); EXPECT_DOUBLE_EQ(1000.0, pCue->getLength()); } // Clear outro end cue m_pOutroEndClear->slotSet(1); m_pOutroEndClear->slotSet(0); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroStartPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroStartPosition->get()); EXPECT_FALSE(m_pOutroStartEnabled->toBool()); - EXPECT_DOUBLE_EQ(-1.0, m_pOutroEndPosition->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pOutroEndPosition->get()); EXPECT_FALSE(m_pOutroEndEnabled->toBool()); EXPECT_EQ(nullptr, pTrack->findCueByType(Cue::Type::Outro)); diff --git a/src/track/cue.cpp b/src/track/cue.cpp index db49b6756dd..f4d8711f85d 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -24,8 +24,8 @@ Cue::Cue(TrackId trackId) m_iId(-1), m_trackId(trackId), m_type(Cue::Type::Invalid), - m_sampleStartPosition(-1.0), - m_length(0.0), + m_sampleStartPosition(Cue::kNoPosition), + m_sampleEndPosition(Cue::kNoPosition), m_iHotCue(-1), m_label(kDefaultLabel), m_color(Color::kPredefinedColorsSet.noColor) { @@ -39,13 +39,20 @@ Cue::Cue(int id, TrackId trackId, Cue::Type type, double position, double length m_trackId(trackId), m_type(type), m_sampleStartPosition(position), - m_length(length), m_iHotCue(hotCue), m_label(label), m_color(color) { DEBUG_ASSERT(!m_label.isNull()); + if (length) { + if (position != Cue::kNoPosition) { + m_sampleEndPosition = position + length; + } else { + m_sampleEndPosition = length; + } + } else { + m_sampleEndPosition = Cue::kNoPosition; + } } - int Cue::getId() const { QMutexLocker lock(&m_mutex); return m_iId; @@ -100,13 +107,7 @@ void Cue::setStartPosition(double samplePosition) { void Cue::setEndPosition(double samplePosition) { QMutexLocker lock(&m_mutex); - if (samplePosition == -1.0) { - m_length = 0; - } else if (m_sampleStartPosition == -1.0) { - m_length = samplePosition; - } else { - m_length = samplePosition - m_sampleStartPosition; - } + m_sampleEndPosition = samplePosition; m_bDirty = true; lock.unlock(); emit(updated()); @@ -114,15 +115,13 @@ void Cue::setEndPosition(double samplePosition) { double Cue::getLength() const { QMutexLocker lock(&m_mutex); - return m_length; -} - -void Cue::setLength(double length) { - QMutexLocker lock(&m_mutex); - m_length = length; - m_bDirty = true; - lock.unlock(); - emit(updated()); + if (m_sampleEndPosition == Cue::kNoPosition) { + return 0; + } + if (m_sampleStartPosition == Cue::kNoPosition) { + return m_sampleEndPosition; + } + return m_sampleEndPosition - m_sampleStartPosition; } int Cue::getHotCue() const { @@ -179,13 +178,7 @@ void Cue::setDirty(bool dirty) { double Cue::getEndPosition() const { QMutexLocker lock(&m_mutex); - if (m_sampleStartPosition == -1.0) { - return m_length; - } else if (m_length == 0.0) { - return -1.0; - } else { - return m_sampleStartPosition + m_length; - } + return m_sampleEndPosition; } bool operator==(const CuePosition& lhs, const CuePosition& rhs) { diff --git a/src/track/cue.h b/src/track/cue.h index 1e0ac94893f..ffc1c814690 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -47,7 +47,6 @@ class Cue : public QObject { void setEndPosition(double samplePosition); double getLength() const; - void setLength(double length); int getHotCue() const; void setHotCue(int hotCue); @@ -78,7 +77,7 @@ class Cue : public QObject { TrackId m_trackId; Cue::Type m_type; double m_sampleStartPosition; - double m_length; + double m_sampleEndPosition; int m_iHotCue; QString m_label; PredefinedColorPointer m_color;