From 5c269494555bff7ef8b758a7408457caa73b5cf0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 27 Jun 2019 17:08:55 +0200 Subject: [PATCH 001/153] Fix durationItem misnomer for position in DlgTrackInfo::populateCues() Before this change, the variable were called duration/durationItem, but contained information about the position. This might be confusing, especially if we introduce an additional length table column (for saved loops). --- src/library/dlgtrackinfo.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index c8b9de3f603d..43694d6cce55 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -299,12 +299,12 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { hotcue = QString("%1").arg(iHotcue); } - int position = pCue->getPosition(); + int iPosition = pCue->getPosition(); double totalSeconds; - if (position == -1) + if (iPosition == -1) continue; else { - totalSeconds = float(position) / float(sampleRate) / 2.0; + totalSeconds = float(iPosition) / float(sampleRate) / 2.0; } int fraction = 100*(totalSeconds - floor(totalSeconds)); @@ -312,15 +312,15 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { int mins = int(totalSeconds) / 60; //int hours = mins / 60; //Not going to worry about this for now. :) - //Construct a nicely formatted duration string now. - QString duration = QString("%1:%2.%3").arg( + //Construct a nicely formatted position string now. + QString position = QString("%1:%2.%3").arg( QString::number(mins), QString("%1").arg(seconds, 2, 10, QChar('0')), QString("%1").arg(fraction, 2, 10, QChar('0'))); - QTableWidgetItem* durationItem = new QTableWidgetItem(duration); - // Make the duration read only - durationItem->setFlags(Qt::NoItemFlags); + QTableWidgetItem* positionItem = new QTableWidgetItem(position); + // Make the position read only + positionItem->setFlags(Qt::NoItemFlags); // Decode cue type to display text QString cueType; @@ -361,7 +361,7 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { m_cueMap[row] = pCue; cueTable->insertRow(row); cueTable->setItem(row, 0, new QTableWidgetItem(rowStr)); - cueTable->setItem(row, 1, durationItem); + cueTable->setItem(row, 1, positionItem); cueTable->setItem(row, 2, typeItem); cueTable->setItem(row, 3, new QTableWidgetItem(hotcue)); cueTable->setCellWidget(row, 4, colorComboBox); From d3948595fed71b3d932422bb34bbbf0019b0831a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 27 Jun 2019 17:37:04 +0200 Subject: [PATCH 002/153] Add length column to the DlgTrackInfo dialog table --- src/library/dlgtrackinfo.cpp | 28 +++++++++++++++++++++++----- src/library/dlgtrackinfo.ui | 5 +++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/library/dlgtrackinfo.cpp b/src/library/dlgtrackinfo.cpp index 43694d6cce55..2ec88b7d5b64 100644 --- a/src/library/dlgtrackinfo.cpp +++ b/src/library/dlgtrackinfo.cpp @@ -322,6 +322,23 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { // Make the position read only positionItem->setFlags(Qt::NoItemFlags); + QString length; + int iLength = pCue->getLength(); + if (iLength > 0) { + totalSeconds = float(iLength) / float(sampleRate) / 2.0; + fraction = 100*(totalSeconds - floor(totalSeconds)); + seconds = int(totalSeconds) % 60; + + //Construct a nicely formatted length string now. + length = QString("%1.%2").arg( + QString("%1").arg(seconds, 2, 10, QChar('0')), + QString("%1").arg(fraction, 2, 10, QChar('0'))); + } + + QTableWidgetItem* lengthItem = new QTableWidgetItem(length); + // Make the length read only + lengthItem->setFlags(Qt::NoItemFlags); + // Decode cue type to display text QString cueType; switch (pCue->getType()) { @@ -362,15 +379,16 @@ void DlgTrackInfo::populateCues(TrackPointer pTrack) { cueTable->insertRow(row); cueTable->setItem(row, 0, new QTableWidgetItem(rowStr)); cueTable->setItem(row, 1, positionItem); - cueTable->setItem(row, 2, typeItem); - cueTable->setItem(row, 3, new QTableWidgetItem(hotcue)); - cueTable->setCellWidget(row, 4, colorComboBox); - cueTable->setItem(row, 5, new QTableWidgetItem(pCue->getLabel())); + cueTable->setItem(row, 2, lengthItem); + cueTable->setItem(row, 3, typeItem); + cueTable->setItem(row, 4, new QTableWidgetItem(hotcue)); + cueTable->setCellWidget(row, 5, colorComboBox); + cueTable->setItem(row, 6, new QTableWidgetItem(pCue->getLabel())); row += 1; } cueTable->setSortingEnabled(true); cueTable->horizontalHeader()->setStretchLastSection(true); - cueTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents); + cueTable->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeToContents); } void DlgTrackInfo::saveTrack() { diff --git a/src/library/dlgtrackinfo.ui b/src/library/dlgtrackinfo.ui index 4435134c7a04..f4a2c7e1b019 100644 --- a/src/library/dlgtrackinfo.ui +++ b/src/library/dlgtrackinfo.ui @@ -815,6 +815,11 @@ Often results in higher quality beatgrids, but will not do well on tracks that h Position + + + Length + + Type From 36130decb2f3a8659e440b1e1cbb4500b18eb543 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 28 Jun 2019 18:51:07 +0200 Subject: [PATCH 003/153] Add possiblity avoid seek after adjusting a loop --- src/engine/controls/loopingcontrol.cpp | 69 ++++++++++++++------------ src/engine/controls/loopingcontrol.h | 7 ++- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 19c506e086cf..b4317cd0dee8 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -49,7 +49,7 @@ LoopingControl::LoopingControl(QString group, m_bAdjustingLoopInOld(false), m_bAdjustingLoopOutOld(false), m_bLoopOutPressedWhileLoopDisabled(false) { - m_oldLoopSamples = { kNoTrigger, kNoTrigger, false }; + m_oldLoopSamples = { kNoTrigger, kNoTrigger, LoopSeekMode::MOVED_OUT }; m_loopSamples.setValue(m_oldLoopSamples); m_currentSample.setValue(0.0); m_pActiveBeatLoop = NULL; @@ -280,7 +280,7 @@ void LoopingControl::slotLoopScale(double scaleFactor) { } // Reseek if the loop shrank out from under the playposition. - loopSamples.seek = (m_bLoopingEnabled && scaleFactor < 1.0); + loopSamples.seekMode = (m_bLoopingEnabled && scaleFactor < 1.0) ? LoopSeekMode::CHANGED : LoopSeekMode::MOVED_OUT; m_loopSamples.setValue(loopSamples); @@ -325,7 +325,7 @@ void LoopingControl::process(const double dRate, if (loopSamples.start != m_oldLoopSamples.start || loopSamples.end != m_oldLoopSamples.end) { // bool seek is only valid after the loop has changed - if (loopSamples.seek) { + if (loopSamples.seekMode == LoopSeekMode::CHANGED) { // here the loop has changed and the play position // should be moved with it double target = seekInsideAdjustedLoop(currentSample, @@ -380,27 +380,34 @@ double LoopingControl::nextTrigger(bool reverse, if (loopSamples.start != m_oldLoopSamples.start || loopSamples.end != m_oldLoopSamples.end) { // bool seek is only valid after the loop has changed - if (loopSamples.seek) { - // here the loop has changed and the play position - // should be moved with it - *pTarget = seekInsideAdjustedLoop(currentSample, - m_oldLoopSamples.start, loopSamples.start, loopSamples.end); - } else { - bool movedOut = false; - // Check if we have moved out of the loop, before we could enable it - if (reverse) { - if (loopSamples.start > currentSample) { - movedOut = true; + bool movedOut; + switch(loopSamples.seekMode) { + case LoopSeekMode::CHANGED: + // here the loop has changed and the play position + // should be moved with it + *pTarget = seekInsideAdjustedLoop(currentSample, + m_oldLoopSamples.start, loopSamples.start, loopSamples.end); + break; + case LoopSeekMode::MOVED_OUT: + movedOut = false; + // Check if we have moved out of the loop, before we could enable it + if (reverse) { + if (loopSamples.start > currentSample) { + movedOut = true; + } + } else { + if (loopSamples.end < currentSample) { + movedOut = true; + } } - } else { - if (loopSamples.end < currentSample) { - movedOut = true; + if (movedOut) { + *pTarget = seekInsideAdjustedLoop(currentSample, + loopSamples.start, loopSamples.start, loopSamples.end); } - } - if (movedOut) { - *pTarget = seekInsideAdjustedLoop(currentSample, - loopSamples.start, loopSamples.start, loopSamples.end); - } + break; + case LoopSeekMode::NONE: + // Nothing to do here + break; } m_oldLoopSamples = loopSamples; if (*pTarget != kNoTrigger) { @@ -555,9 +562,9 @@ void LoopingControl::setLoopInToCurrentPosition() { if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger) { setLoopingEnabled(true); - loopSamples.seek = true; + loopSamples.seekMode = LoopSeekMode::CHANGED; } else { - loopSamples.seek = false; + loopSamples.seekMode = LoopSeekMode::MOVED_OUT; } if (m_pQuantizeEnabled->toBool() @@ -655,9 +662,9 @@ void LoopingControl::setLoopOutToCurrentPosition() { if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger) { setLoopingEnabled(true); - loopSamples.seek = true; + loopSamples.seekMode = LoopSeekMode::CHANGED; } else { - loopSamples.seek = false; + loopSamples.seekMode = LoopSeekMode::MOVED_OUT; } if (m_pQuantizeEnabled->toBool() && pBeats) { @@ -776,7 +783,7 @@ void LoopingControl::slotLoopStartPos(double pos) { setLoopingEnabled(false); } - loopSamples.seek = false; + loopSamples.seekMode = LoopSeekMode::MOVED_OUT; loopSamples.start = pos; m_pCOLoopStartPosition->set(pos); @@ -812,7 +819,7 @@ void LoopingControl::slotLoopEndPos(double pos) { setLoopingEnabled(false); } loopSamples.end = pos; - loopSamples.seek = false; + loopSamples.seekMode = LoopSeekMode::MOVED_OUT; m_pCOLoopEndPosition->set(pos); m_loopSamples.setValue(loopSamples); } @@ -1037,7 +1044,7 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable // Calculate the new loop start and end samples // give start and end defaults so we can detect problems - LoopSamples newloopSamples = {kNoTrigger, kNoTrigger, false}; + LoopSamples newloopSamples = {kNoTrigger, kNoTrigger, LoopSeekMode::MOVED_OUT}; LoopSamples loopSamples = m_loopSamples.getValue(); double currentSample = m_currentSample.getValue(); @@ -1124,7 +1131,7 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable // If resizing an inactive loop by changing beatloop_size, // do not seek to the adjusted loop. - newloopSamples.seek = (keepStartPoint && (enable || m_bLoopingEnabled)); + newloopSamples.seekMode = (keepStartPoint && (enable || m_bLoopingEnabled)) ? LoopSeekMode::CHANGED : LoopSeekMode::MOVED_OUT; m_loopSamples.setValue(newloopSamples); m_pCOLoopStartPosition->set(newloopSamples.start); @@ -1226,7 +1233,7 @@ void LoopingControl::slotLoopMove(double beats) { // If we are looping make sure that the play head does not leave the // loop as a result of our adjustment. - loopSamples.seek = m_bLoopingEnabled; + loopSamples.seekMode = m_bLoopingEnabled ? LoopSeekMode::CHANGED : LoopSeekMode::MOVED_OUT; loopSamples.start = new_loop_in; loopSamples.end = new_loop_out; diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 55d4f0c15f17..49351a24a9b0 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -90,11 +90,16 @@ class LoopingControl : public EngineControl { void slotLoopHalve(double pressed); private: + enum LoopSeekMode { + CHANGED, // force the playposition to be inside the loop after adjusting it. + MOVED_OUT, + NONE, + }; struct LoopSamples { double start; double end; - bool seek; // force the playposition to be inside the loop after adjusting it. + LoopSeekMode seekMode; }; void setLoopingEnabled(bool enabled); From 6c94d02e81553ff2e19cdc6daaec51f15c913746 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 28 Jun 2019 18:56:02 +0200 Subject: [PATCH 004/153] Implement a direct way to trigger saved loops --- src/engine/controls/enginecontrol.cpp | 6 ++++++ src/engine/controls/enginecontrol.h | 2 ++ src/engine/controls/loopingcontrol.cpp | 26 ++++++++++++++++++++++++++ src/engine/controls/loopingcontrol.h | 2 ++ src/engine/enginebuffer.cpp | 4 ++++ src/engine/enginebuffer.h | 2 ++ 6 files changed, 42 insertions(+) diff --git a/src/engine/controls/enginecontrol.cpp b/src/engine/controls/enginecontrol.cpp index ddacfb7583df..fbb2a649363a 100644 --- a/src/engine/controls/enginecontrol.cpp +++ b/src/engine/controls/enginecontrol.cpp @@ -67,6 +67,12 @@ EngineBuffer* EngineControl::getEngineBuffer() { return m_pEngineBuffer; } +void EngineControl::setLoop(double startPosition, double endPosition, bool reloop) { + if (m_pEngineBuffer) { + m_pEngineBuffer->setLoop(startPosition, endPosition, reloop); + } +} + void EngineControl::seekAbs(double samplePosition) { if (m_pEngineBuffer) { m_pEngineBuffer->slotControlSeekAbs(samplePosition); diff --git a/src/engine/controls/enginecontrol.h b/src/engine/controls/enginecontrol.h index 2e2d3ce06f39..1a8e4b008d39 100644 --- a/src/engine/controls/enginecontrol.h +++ b/src/engine/controls/enginecontrol.h @@ -59,6 +59,8 @@ class EngineControl : public QObject { const double dTotalSamples, const double dTrackSampleRate); QString getGroup() const; + void setLoop(double startPosition, double endPosition, bool reloop); + // Called to collect player features for effects processing. virtual void collectFeatureState(GroupFeatureState* pGroupFeatures) const { Q_UNUSED(pGroupFeatures); diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index b4317cd0dee8..d64b965f972a 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -509,6 +509,32 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl return dSyncedPlayPos; } +void LoopingControl::setLoop(double startPosition, double endPosition, bool reloop) { + qDebug() << "setLoop" << startPosition << endPosition << reloop; + + LoopSamples loopSamples = m_loopSamples.getValue(); + if (loopSamples.start != startPosition || loopSamples.end != endPosition || loopSamples.seekMode != LoopSeekMode::NONE) { + loopSamples.start = startPosition; + loopSamples.end = endPosition; + loopSamples.seekMode = LoopSeekMode::NONE; + + clearActiveBeatLoop(); + + m_loopSamples.setValue(loopSamples); + m_pCOLoopStartPosition->set(loopSamples.start); + m_pCOLoopEndPosition->set(loopSamples.end); + setLoopingEnabled(true); + } else { + setLoopingEnabled(m_bLoopingEnabled ? reloop : true); + } + + if (reloop) { + // seekExact is necessary here to prevent notifySeek() from disabling our loop + seekAbs(static_cast( + m_loopSamples.getValue().start)); + } +} + void LoopingControl::setLoopInToCurrentPosition() { // set loop-in position BeatsPointer pBeats = m_pBeats; diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 49351a24a9b0..9edd2f4e75f1 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -51,6 +51,8 @@ class LoopingControl : public EngineControl { void notifySeek(double dNewPlaypos) override; + void setLoop(double startPosition, double endPosition, bool reloop); + bool isLoopingEnabled(); public slots: diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 2c10c3bfe8a4..1a99456b9a04 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -350,6 +350,10 @@ double EngineBuffer::getLocalBpm() { return m_pBpmControl->getLocalBpm(); } +void EngineBuffer::setLoop(double startPosition, double endPosition, bool reloop) { + m_pLoopingControl->setLoop(startPosition, endPosition, reloop); +} + void EngineBuffer::setEngineMaster(EngineMaster* pEngineMaster) { for (const auto& pControl: qAsConst(m_engineControls)) { pControl->setEngineMaster(pEngineMaster); diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 46735d16fa11..bd54a5db0a4c 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -124,6 +124,8 @@ class EngineBuffer : public EngineObject { double getBpm(); // Returns the BPM of the loaded track around the current position (not thread-safe) double getLocalBpm(); + // Sets a loop for the loaded track (not thread safe) + void setLoop(double, double, bool); // Sets pointer to other engine buffer/channel void setEngineMaster(EngineMaster*); From 4b22bb036c1d02975ac19c40af4d53a106c898cf Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 9 Jul 2019 14:12:25 +0200 Subject: [PATCH 005/153] Add new loop_toggle CO (like reloop_toggle but without jumping) --- src/engine/controls/loopingcontrol.cpp | 34 ++++++++++++++++++++++++++ src/engine/controls/loopingcontrol.h | 2 ++ 2 files changed, 36 insertions(+) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index d64b965f972a..5421d855e1b8 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -82,6 +82,12 @@ LoopingControl::LoopingControl(QString group, Qt::DirectConnection); m_pLoopExitButton->set(0); + m_pLoopToggleButton = new ControlPushButton(ConfigKey(group, "loop_toggle")); + connect(m_pLoopToggleButton, &ControlObject::valueChanged, + this, &LoopingControl::slotLoopToggle, + Qt::DirectConnection); + m_pLoopToggleButton->set(0); + m_pReloopToggleButton = new ControlPushButton(ConfigKey(group, "reloop_toggle")); connect(m_pReloopToggleButton, &ControlObject::valueChanged, this, &LoopingControl::slotReloopToggle, @@ -211,6 +217,7 @@ LoopingControl::~LoopingControl() { delete m_pLoopInButton; delete m_pLoopInGotoButton; delete m_pLoopExitButton; + delete m_pLoopToggleButton; delete m_pReloopToggleButton; delete m_pReloopAndStopButton; delete m_pCOLoopEnabled; @@ -755,6 +762,33 @@ void LoopingControl::slotLoopExit(double val) { } } +void LoopingControl::slotLoopToggle(double val) { + if (!m_pTrack || val <= 0.0) { + return; + } + + // If we're looping, stop looping + if (m_bLoopingEnabled) { + // If loop roll was active, also disable slip. + if (m_bLoopRollActive) { + m_pSlipEnabled->set(0); + m_bLoopRollActive = false; + m_activeLoopRolls.clear(); + } + setLoopingEnabled(false); + //qDebug() << "loop_toggle looping off"; + } else { + // If we're not looping, enable the loop. + // In contrast to the reloop_toggle CO, we do not jump in any case. + LoopSamples loopSamples = m_loopSamples.getValue(); + if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger && + loopSamples.start <= loopSamples.end) { + setLoopingEnabled(true); + } + //qDebug() << "loop_toggle looping on"; + } +} + void LoopingControl::slotReloopToggle(double val) { if (!m_pTrack || val <= 0.0) { return; diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 9edd2f4e75f1..0968d35f0f86 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -61,6 +61,7 @@ class LoopingControl : public EngineControl { void slotLoopOut(double pressed); void slotLoopOutGoto(double); void slotLoopExit(double); + void slotLoopToggle(double); void slotReloopToggle(double); void slotReloopAndStop(double); void slotLoopStartPos(double); @@ -130,6 +131,7 @@ class LoopingControl : public EngineControl { ControlPushButton* m_pLoopOutButton; ControlPushButton* m_pLoopOutGotoButton; ControlPushButton* m_pLoopExitButton; + ControlPushButton* m_pLoopToggleButton; ControlPushButton* m_pReloopToggleButton; ControlPushButton* m_pReloopAndStopButton; ControlObject* m_pCOLoopScale; From b8243e468e4822aef7ece9ff41079d9142bac44d Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 9 Jul 2019 14:21:23 +0200 Subject: [PATCH 006/153] Implemented saved loops for hot cues --- src/engine/controls/cuecontrol.cpp | 200 ++++++++++++++++++++++++++++- src/engine/controls/cuecontrol.h | 18 +++ 2 files changed, 217 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index e102eba89fcd..022daa49aa7f 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -50,6 +50,9 @@ CueControl::CueControl(QString group, m_pPrevBeat = ControlObject::getControl(ConfigKey(group, "beat_prev")); m_pNextBeat = ControlObject::getControl(ConfigKey(group, "beat_next")); m_pClosestBeat = ControlObject::getControl(ConfigKey(group, "beat_closest")); + m_pLoopStartPosition = new ControlProxy(group, "loop_start_position", this); + m_pLoopEndPosition = new ControlProxy(group, "loop_end_position", this); + m_pLoopToggle = new ControlProxy(group, "loop_toggle", this); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); m_pCuePoint->set(-1.0); @@ -252,9 +255,15 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcuePositionChanged, this, &CueControl::hotcuePositionChanged, Qt::DirectConnection); + connect(pControl, &HotcueControl::hotcueLengthChanged, + this, &CueControl::hotcueLengthChanged, + Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueSet, this, &CueControl::hotcueSet, Qt::DirectConnection); + connect(pControl, &HotcueControl::hotcueSetLoop, + this, &CueControl::hotcueSetLoop, + Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueGoto, this, &CueControl::hotcueGoto, Qt::DirectConnection); @@ -267,6 +276,9 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueActivate, this, &CueControl::hotcueActivate, Qt::DirectConnection); + connect(pControl, &HotcueControl::hotcueActivateLoop, + this, &CueControl::hotcueActivateLoop, + Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueActivatePreview, this, &CueControl::hotcueActivatePreview, Qt::DirectConnection); @@ -418,6 +430,7 @@ void CueControl::loadCuesFromTrack() { } else { // If the old hotcue is the same, then we only need to update pControl->setPosition(pCue->getPosition()); + pControl->setLength(pCue->getLength()); pControl->setColor(pCue->getColor()); } // Add the hotcue to the list of active hotcues @@ -567,6 +580,45 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { } } +void CueControl::hotcueSetLoop(HotcueControl* pControl, double v) { + //qDebug() << "CueControl::hotcueSetLoop" << v; + + if (!v) + return; + + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) + return; + + int hotcue = pControl->getHotcueNumber(); + // Note: the cue is just detached from the hotcue control + // It remains in the database for later use + // TODO: find a rule, that allows us to delete the cue as well + // https://bugs.launchpad.net/mixxx/+bug/1653276 + hotcueClear(pControl, v); + + CuePointer pCue(m_pLoadedTrack->createAndAddCue()); + double loopStartPosition = m_pLoopStartPosition->get(); + double loopLength = m_pLoopEndPosition->get() - loopStartPosition; + if (loopStartPosition < 0 || loopLength <= 0) { + return; + } + + pCue->setPosition(loopStartPosition); + pCue->setLength(loopLength); + pCue->setHotCue(hotcue); + pCue->setLabel(""); + pCue->setType(Cue::CUE); + pCue->setSource(Cue::MANUAL); + // TODO(XXX) deal with spurious signals + attachCue(pCue, hotcue); + + if (getConfig()->getValue(ConfigKey("[Controls]", "auto_hotcue_colors"), false)) { + const QList predefinedColors = Color::kPredefinedColorsSet.allColors; + pCue->setColor(predefinedColors.at((hotcue % (predefinedColors.count() - 1)) + 1)); + }; +} + void CueControl::hotcueGoto(HotcueControl* pControl, double v) { if (!v) return; @@ -642,6 +694,41 @@ void CueControl::hotcueGotoAndPlay(HotcueControl* pControl, double v) { } } +void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { + if (!v) + return; + + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) { + return; + } + + CuePointer pCue(pControl->getCue()); + + // Need to unlock before emitting any signals to prevent deadlock. + lock.unlock(); + + if (!pCue) { + return; + } + + double startPosition = pCue->getPosition(); + if (startPosition == -1) { + return; + } + + double endPosition = startPosition + pCue->getLength(); + if (startPosition >= endPosition) { + return; + } + + if(m_pLoopStartPosition->get() != startPosition || m_pLoopEndPosition->get() != endPosition) { + setLoop(startPosition, endPosition, false); + } else { + m_pLoopToggle->set(1.0); + } +} + void CueControl::hotcueActivate(HotcueControl* pControl, double v) { //qDebug() << "CueControl::hotcueActivate" << v; @@ -661,7 +748,11 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { hotcueSet(pControl, v); } else { if (isPlayingByPlayButton()) { - hotcueGoto(pControl, v); + if (pCue->getLength() > 0) { + hotcueLoopToggle(pControl, v); + } else { + hotcueGoto(pControl, v); + } } else { hotcueActivatePreview(pControl, v); } @@ -685,6 +776,53 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { } } +void CueControl::hotcueActivateLoop(HotcueControl* pControl, double v) { + //qDebug() << "CueControl::hotcueActivate" << v; + + QMutexLocker lock(&m_mutex); + + if (!m_pLoadedTrack) { + return; + } + + CuePointer pCue(pControl->getCue()); + + lock.unlock(); + + if (pCue) { + if (v) { + if (pCue->getPosition() == -1) { + hotcueSetLoop(pControl, v); + } else { + if (isPlayingByPlayButton()) { + if (pCue->getLength() > 0) { + hotcueLoopToggle(pControl, v); + } else { + hotcueGoto(pControl, v); + } + } else { + hotcueActivatePreview(pControl, v); + } + } + } else { + if (pCue->getPosition() != -1) { + hotcueActivatePreview(pControl, v); + } + } + } else { + if (v) { + // just in case + hotcueSetLoop(pControl, v); + } else if (m_iCurrentlyPreviewingHotcues) { + // The cue is non-existent, yet we got a release for it and are + // currently previewing a hotcue. This is indicative of a corner + // case where the cue was detached while we were pressing it. Let + // hotcueActivatePreview handle it. + hotcueActivatePreview(pControl, v); + } + } +} + void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { @@ -752,11 +890,32 @@ void CueControl::hotcuePositionChanged(HotcueControl* pControl, double newPositi pCue->setHotCue(-1); detachCue(pControl->getHotcueNumber()); } else if (newPosition > 0 && newPosition < m_pTrackSamples->get()) { + //TODO: Handle Loops pCue->setPosition(newPosition); } } } +void CueControl::hotcueLengthChanged(HotcueControl* pControl, double newLength) { + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) + return; + + CuePointer pCue(pControl->getCue()); + if (pCue) { + // Setting the length to -1 is the same as calling hotcue_x_clear + if (newLength == -1) { + pCue->setHotCue(-1); + detachCue(pControl->getHotcueNumber()); + } else { + double position = pControl->getPosition(); + if (position >= 0 && newLength > 0 && (position + newLength) <= m_pTrackSamples->get()) { + pCue->setLength(newLength); + } + } + } +} + void CueControl::hintReader(HintVector* pHintList) { Hint cue_hint; double cuePoint = m_pCuePoint->get(); @@ -1666,6 +1825,12 @@ HotcueControl::HotcueControl(QString group, int i) Qt::DirectConnection); m_hotcuePosition->set(-1); + m_hotcueLength = new ControlObject(keyForControl(i, "length")); + connect(m_hotcueLength, &ControlObject::valueChanged, + this, &HotcueControl::slotHotcueLengthChanged, + Qt::DirectConnection); + m_hotcueLength->set(-1); + m_hotcueEnabled = new ControlObject(keyForControl(i, "enabled")); m_hotcueEnabled->setReadOnly(); @@ -1682,6 +1847,11 @@ HotcueControl::HotcueControl(QString group, int i) this, &HotcueControl::slotHotcueSet, Qt::DirectConnection); + m_hotcueSetLoop = new ControlPushButton(keyForControl(i, "setloop")); + connect(m_hotcueSetLoop, &ControlObject::valueChanged, + this, &HotcueControl::slotHotcueSetLoop, + Qt::DirectConnection); + m_hotcueGoto = new ControlPushButton(keyForControl(i, "goto")); connect(m_hotcueGoto, &ControlObject::valueChanged, this, &HotcueControl::slotHotcueGoto, @@ -1702,6 +1872,11 @@ HotcueControl::HotcueControl(QString group, int i) this, &HotcueControl::slotHotcueActivate, Qt::DirectConnection); + m_hotcueActivateLoop = new ControlPushButton(keyForControl(i, "activateloop")); + connect(m_hotcueActivateLoop, &ControlObject::valueChanged, + this, &HotcueControl::slotHotcueActivateLoop, + Qt::DirectConnection); + m_hotcueActivatePreview = new ControlPushButton(keyForControl(i, "activate_preview")); connect(m_hotcueActivatePreview, &ControlObject::valueChanged, this, &HotcueControl::slotHotcueActivatePreview, @@ -1715,13 +1890,16 @@ HotcueControl::HotcueControl(QString group, int i) HotcueControl::~HotcueControl() { delete m_hotcuePosition; + delete m_hotcueLength; delete m_hotcueEnabled; delete m_hotcueColor; delete m_hotcueSet; + delete m_hotcueSetLoop; delete m_hotcueGoto; delete m_hotcueGotoAndPlay; delete m_hotcueGotoAndStop; delete m_hotcueActivate; + delete m_hotcueActivateLoop; delete m_hotcueActivatePreview; delete m_hotcueClear; } @@ -1730,6 +1908,10 @@ void HotcueControl::slotHotcueSet(double v) { emit(hotcueSet(this, v)); } +void HotcueControl::slotHotcueSetLoop(double v) { + emit(hotcueSetLoop(this, v)); +} + void HotcueControl::slotHotcueGoto(double v) { emit(hotcueGoto(this, v)); } @@ -1746,6 +1928,10 @@ void HotcueControl::slotHotcueActivate(double v) { emit(hotcueActivate(this, v)); } +void HotcueControl::slotHotcueActivateLoop(double v) { + emit(hotcueActivateLoop(this, v)); +} + void HotcueControl::slotHotcueActivatePreview(double v) { emit(hotcueActivatePreview(this, v)); } @@ -1759,6 +1945,10 @@ void HotcueControl::slotHotcuePositionChanged(double newPosition) { emit(hotcuePositionChanged(this, newPosition)); } +void HotcueControl::slotHotcueLengthChanged(double newLength) { + emit(hotcueLengthChanged(this, newLength)); +} + void HotcueControl::slotHotcueColorChanged(double newColorId) { m_pCue->setColor(Color::kPredefinedColorsSet.predefinedColorFromId(newColorId)); emit(hotcueColorChanged(this, newColorId)); @@ -1768,6 +1958,10 @@ double HotcueControl::getPosition() const { return m_hotcuePosition->get(); } +double HotcueControl::getLength() const { + return m_hotcueLength->get(); +} + void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); setColor(pCue->getColor()); @@ -1793,3 +1987,7 @@ void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); m_hotcueEnabled->forceSet(position == -1.0 ? 0.0 : 1.0); } + +void HotcueControl::setLength(double length) { + m_hotcueLength->set(length); +} diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 97ba673afb37..dccb3e32c1fb 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -44,9 +44,11 @@ class HotcueControl : public QObject { inline int getHotcueNumber() { return m_iHotcueNumber; } inline CuePointer getCue() { return m_pCue; } double getPosition() const; + double getLength() const; void setCue(CuePointer pCue); void resetCue(); void setPosition(double position); + void setLength(double length); void setColor(PredefinedColorPointer newColor); PredefinedColorPointer getColor() const; @@ -66,24 +68,30 @@ class HotcueControl : public QObject { private slots: void slotHotcueSet(double v); + void slotHotcueSetLoop(double v); void slotHotcueGoto(double v); void slotHotcueGotoAndPlay(double v); void slotHotcueGotoAndStop(double v); void slotHotcueActivate(double v); + void slotHotcueActivateLoop(double v); void slotHotcueActivatePreview(double v); void slotHotcueClear(double v); + void slotHotcueLengthChanged(double newPosition); void slotHotcuePositionChanged(double newPosition); void slotHotcueColorChanged(double newColorId); signals: void hotcueSet(HotcueControl* pHotcue, double v); + void hotcueSetLoop(HotcueControl* pHotcue, double v); void hotcueGoto(HotcueControl* pHotcue, double v); void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); void hotcueActivate(HotcueControl* pHotcue, double v); + void hotcueActivateLoop(HotcueControl* pHotcue, double v); void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); void hotcuePositionChanged(HotcueControl* pHotcue, double newPosition); + void hotcueLengthChanged(HotcueControl* pHotcue, double newLength); void hotcueColorChanged(HotcueControl* pHotcue, double newColorId); void hotcuePlay(double v); @@ -96,14 +104,17 @@ class HotcueControl : public QObject { // Hotcue state controls ControlObject* m_hotcuePosition; + ControlObject* m_hotcueLength; ControlObject* m_hotcueEnabled; ControlObject* m_hotcueColor; // Hotcue button controls ControlObject* m_hotcueSet; + ControlObject* m_hotcueSetLoop; ControlObject* m_hotcueGoto; ControlObject* m_hotcueGotoAndPlay; ControlObject* m_hotcueGotoAndStop; ControlObject* m_hotcueActivate; + ControlObject* m_hotcueActivateLoop; ControlObject* m_hotcueActivatePreview; ControlObject* m_hotcueClear; @@ -137,13 +148,17 @@ class CueControl : public EngineControl { void trackCuesUpdated(); void trackBeatsUpdated(); void hotcueSet(HotcueControl* pControl, double v); + void hotcueSetLoop(HotcueControl* pControl, double v); void hotcueGoto(HotcueControl* pControl, double v); void hotcueGotoAndPlay(HotcueControl* pControl, double v); void hotcueGotoAndStop(HotcueControl* pControl, double v); + void hotcueLoopToggle(HotcueControl* pControl, double v); void hotcueActivate(HotcueControl* pControl, double v); + void hotcueActivateLoop(HotcueControl* pControl, double v); void hotcueActivatePreview(HotcueControl* pControl, double v); void hotcueClear(HotcueControl* pControl, double v); void hotcuePositionChanged(HotcueControl* pControl, double newPosition); + void hotcueLengthChanged(HotcueControl* pControl, double newLength); void cueSet(double v); void cueClear(double v); @@ -202,6 +217,9 @@ class CueControl : public EngineControl { ControlObject* m_pPrevBeat; ControlObject* m_pNextBeat; ControlObject* m_pClosestBeat; + ControlProxy* m_pLoopStartPosition; + ControlProxy* m_pLoopEndPosition; + ControlProxy* m_pLoopToggle; bool m_bypassCueSetByPlay; const int m_iNumHotCues; From 72b9da6d6430621c0ba88f0eda9e5d48e9f6405a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 9 Jul 2019 22:29:16 +0200 Subject: [PATCH 007/153] Added hotcue_X_setcue/_activatecue COs and make hotcue_X_set/_active smarter --- src/engine/controls/cuecontrol.cpp | 135 +++++++++++++++++++++++++++++ src/engine/controls/cuecontrol.h | 9 ++ 2 files changed, 144 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 022daa49aa7f..4e5a0874a178 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -52,6 +52,7 @@ CueControl::CueControl(QString group, m_pClosestBeat = ControlObject::getControl(ConfigKey(group, "beat_closest")); m_pLoopStartPosition = new ControlProxy(group, "loop_start_position", this); m_pLoopEndPosition = new ControlProxy(group, "loop_end_position", this); + m_pLoopEnabled = new ControlProxy(group, "loop_enabled", this); m_pLoopToggle = new ControlProxy(group, "loop_toggle", this); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); @@ -261,6 +262,9 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueSet, this, &CueControl::hotcueSet, Qt::DirectConnection); + connect(pControl, &HotcueControl::hotcueSetCue, + this, &CueControl::hotcueSetCue, + Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueSetLoop, this, &CueControl::hotcueSetLoop, Qt::DirectConnection); @@ -276,6 +280,9 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueActivate, this, &CueControl::hotcueActivate, Qt::DirectConnection); + connect(pControl, &HotcueControl::hotcueActivateCue, + this, &CueControl::hotcueActivateCue, + Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueActivateLoop, this, &CueControl::hotcueActivateLoop, Qt::DirectConnection); @@ -551,12 +558,73 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { // https://bugs.launchpad.net/mixxx/+bug/1653276 hotcueClear(pControl, v); + CuePointer pCue(m_pLoadedTrack->createAndAddCue()); + + double cuePosition; + double cueLength; + if (m_pLoopEnabled->get()) { + cuePosition = m_pLoopStartPosition->get(); + cueLength = m_pLoopEndPosition->get() - cuePosition; + if (cuePosition < 0 || cueLength <= 0) { + return; + } + } else { + double closestBeat = m_pClosestBeat->get(); + cuePosition = + (m_pQuantizeEnabled->toBool() && closestBeat != -1) ? + closestBeat : getSampleOfTrack().current; + cueLength = -1; + } + + pCue->setPosition(cuePosition); + pCue->setLength(cueLength); + pCue->setHotCue(hotcue); + pCue->setLabel(""); + pCue->setType(Cue::CUE); + pCue->setSource(Cue::MANUAL); + // TODO(XXX) deal with spurious signals + attachCue(pCue, hotcue); + + if (getConfig()->getValue(ConfigKey("[Controls]", "auto_hotcue_colors"), false)) { + const QList predefinedColors = Color::kPredefinedColorsSet.allColors; + pCue->setColor(predefinedColors.at((hotcue % (predefinedColors.count() - 1)) + 1)); + }; + + // If quantize is enabled and we are not playing, jump to the cue point + // since it's not necessarily where we currently are. TODO(XXX) is this + // potentially invalid for vinyl control? + bool playing = m_pPlay->toBool(); + if (!playing && m_pQuantizeEnabled->toBool()) { + lock.unlock(); // prevent deadlock. + // Enginebuffer will quantize more exactly than we can. + seekAbs(cuePosition); + } +} + +void CueControl::hotcueSetCue(HotcueControl* pControl, double v) { + //qDebug() << "CueControl::hotcueSetCue" << v; + + if (!v) + return; + + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) + return; + + int hotcue = pControl->getHotcueNumber(); + // Note: the cue is just detached from the hotcue control + // It remains in the database for later use + // TODO: find a rule, that allows us to delete the cue as well + // https://bugs.launchpad.net/mixxx/+bug/1653276 + hotcueClear(pControl, v); + CuePointer pCue(m_pLoadedTrack->createAndAddCue()); double closestBeat = m_pClosestBeat->get(); double cuePosition = (m_pQuantizeEnabled->toBool() && closestBeat != -1) ? closestBeat : getSampleOfTrack().current; pCue->setPosition(cuePosition); + pCue->setLength(-1); pCue->setHotCue(hotcue); pCue->setLabel(""); pCue->setType(Cue::CUE); @@ -776,6 +844,53 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { } } +void CueControl::hotcueActivateCue(HotcueControl* pControl, double v) { + //qDebug() << "CueControl::hotcueActivateCue" << v; + + QMutexLocker lock(&m_mutex); + + if (!m_pLoadedTrack) { + return; + } + + CuePointer pCue(pControl->getCue()); + + lock.unlock(); + + if (pCue) { + if (v) { + if (pCue->getPosition() == -1) { + hotcueSetCue(pControl, v); + } else { + if (isPlayingByPlayButton()) { + if (pCue->getLength() > 0) { + hotcueLoopToggle(pControl, v); + } else { + hotcueGoto(pControl, v); + } + } else { + hotcueActivatePreview(pControl, v); + } + } + } else { + if (pCue->getPosition() != -1) { + hotcueActivatePreview(pControl, v); + } + } + } else { + if (v) { + // just in case + hotcueSetCue(pControl, v); + } else if (m_iCurrentlyPreviewingHotcues) { + // The cue is non-existent, yet we got a release for it and are + // currently previewing a hotcue. This is indicative of a corner + // case where the cue was detached while we were pressing it. Let + // hotcueActivatePreview handle it. + hotcueActivatePreview(pControl, v); + } + } +} + void CueControl::hotcueActivateLoop(HotcueControl* pControl, double v) { //qDebug() << "CueControl::hotcueActivate" << v; @@ -1847,6 +1962,11 @@ HotcueControl::HotcueControl(QString group, int i) this, &HotcueControl::slotHotcueSet, Qt::DirectConnection); + m_hotcueSetCue = new ControlPushButton(keyForControl(i, "setcue")); + connect(m_hotcueSetCue, &ControlObject::valueChanged, + this, &HotcueControl::slotHotcueSetCue, + Qt::DirectConnection); + m_hotcueSetLoop = new ControlPushButton(keyForControl(i, "setloop")); connect(m_hotcueSetLoop, &ControlObject::valueChanged, this, &HotcueControl::slotHotcueSetLoop, @@ -1872,6 +1992,11 @@ HotcueControl::HotcueControl(QString group, int i) this, &HotcueControl::slotHotcueActivate, Qt::DirectConnection); + m_hotcueActivateCue = new ControlPushButton(keyForControl(i, "activatecue")); + connect(m_hotcueActivateCue, &ControlObject::valueChanged, + this, &HotcueControl::slotHotcueActivateCue, + Qt::DirectConnection); + m_hotcueActivateLoop = new ControlPushButton(keyForControl(i, "activateloop")); connect(m_hotcueActivateLoop, &ControlObject::valueChanged, this, &HotcueControl::slotHotcueActivateLoop, @@ -1894,11 +2019,13 @@ HotcueControl::~HotcueControl() { delete m_hotcueEnabled; delete m_hotcueColor; delete m_hotcueSet; + delete m_hotcueSetCue; delete m_hotcueSetLoop; delete m_hotcueGoto; delete m_hotcueGotoAndPlay; delete m_hotcueGotoAndStop; delete m_hotcueActivate; + delete m_hotcueActivateCue; delete m_hotcueActivateLoop; delete m_hotcueActivatePreview; delete m_hotcueClear; @@ -1908,6 +2035,10 @@ void HotcueControl::slotHotcueSet(double v) { emit(hotcueSet(this, v)); } +void HotcueControl::slotHotcueSetCue(double v) { + emit(hotcueSetCue(this, v)); +} + void HotcueControl::slotHotcueSetLoop(double v) { emit(hotcueSetLoop(this, v)); } @@ -1928,6 +2059,10 @@ void HotcueControl::slotHotcueActivate(double v) { emit(hotcueActivate(this, v)); } +void HotcueControl::slotHotcueActivateCue(double v) { + emit(hotcueActivateCue(this, v)); +} + void HotcueControl::slotHotcueActivateLoop(double v) { emit(hotcueActivateLoop(this, v)); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index dccb3e32c1fb..19b9073635a1 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -68,11 +68,13 @@ class HotcueControl : public QObject { private slots: void slotHotcueSet(double v); + void slotHotcueSetCue(double v); void slotHotcueSetLoop(double v); void slotHotcueGoto(double v); void slotHotcueGotoAndPlay(double v); void slotHotcueGotoAndStop(double v); void slotHotcueActivate(double v); + void slotHotcueActivateCue(double v); void slotHotcueActivateLoop(double v); void slotHotcueActivatePreview(double v); void slotHotcueClear(double v); @@ -82,11 +84,13 @@ class HotcueControl : public QObject { signals: void hotcueSet(HotcueControl* pHotcue, double v); + void hotcueSetCue(HotcueControl* pHotcue, double v); void hotcueSetLoop(HotcueControl* pHotcue, double v); void hotcueGoto(HotcueControl* pHotcue, double v); void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); void hotcueActivate(HotcueControl* pHotcue, double v); + void hotcueActivateCue(HotcueControl* pHotcue, double v); void hotcueActivateLoop(HotcueControl* pHotcue, double v); void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); @@ -109,11 +113,13 @@ class HotcueControl : public QObject { ControlObject* m_hotcueColor; // Hotcue button controls ControlObject* m_hotcueSet; + ControlObject* m_hotcueSetCue; ControlObject* m_hotcueSetLoop; ControlObject* m_hotcueGoto; ControlObject* m_hotcueGotoAndPlay; ControlObject* m_hotcueGotoAndStop; ControlObject* m_hotcueActivate; + ControlObject* m_hotcueActivateCue; ControlObject* m_hotcueActivateLoop; ControlObject* m_hotcueActivatePreview; ControlObject* m_hotcueClear; @@ -148,12 +154,14 @@ class CueControl : public EngineControl { void trackCuesUpdated(); void trackBeatsUpdated(); void hotcueSet(HotcueControl* pControl, double v); + void hotcueSetCue(HotcueControl* pControl, double v); void hotcueSetLoop(HotcueControl* pControl, double v); void hotcueGoto(HotcueControl* pControl, double v); void hotcueGotoAndPlay(HotcueControl* pControl, double v); void hotcueGotoAndStop(HotcueControl* pControl, double v); void hotcueLoopToggle(HotcueControl* pControl, double v); void hotcueActivate(HotcueControl* pControl, double v); + void hotcueActivateCue(HotcueControl* pControl, double v); void hotcueActivateLoop(HotcueControl* pControl, double v); void hotcueActivatePreview(HotcueControl* pControl, double v); void hotcueClear(HotcueControl* pControl, double v); @@ -219,6 +227,7 @@ class CueControl : public EngineControl { ControlObject* m_pClosestBeat; ControlProxy* m_pLoopStartPosition; ControlProxy* m_pLoopEndPosition; + ControlProxy* m_pLoopEnabled; ControlProxy* m_pLoopToggle; bool m_bypassCueSetByPlay; From 203289e11830c696011cd242a40bffd3e7ebaf9e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 9 Jul 2019 15:13:48 +0200 Subject: [PATCH 008/153] Add hotcue_X_reloop CO (for saved loop hotcues) --- src/engine/controls/cuecontrol.cpp | 53 ++++++++++++++++++++++++++++++ src/engine/controls/cuecontrol.h | 4 +++ 2 files changed, 57 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 4e5a0874a178..a2567a2d353f 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -277,6 +277,9 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueGotoAndStop, this, &CueControl::hotcueGotoAndStop, Qt::DirectConnection); + connect(pControl, &HotcueControl::hotcueReloop, + this, &CueControl::hotcueReloop, + Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueActivate, this, &CueControl::hotcueActivate, Qt::DirectConnection); @@ -762,6 +765,46 @@ void CueControl::hotcueGotoAndPlay(HotcueControl* pControl, double v) { } } +void CueControl::hotcueReloop(HotcueControl* pControl, double v) { + if (!v) + return; + + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) { + return; + } + + CuePointer pCue(pControl->getCue()); + + // Need to unlock before emitting any signals to prevent deadlock. + lock.unlock(); + + if (!pCue) { + return; + } + + double startPosition = pCue->getPosition(); + if (startPosition == -1) { + return; + } + + double endPosition = startPosition + pCue->getLength(); + if (startPosition >= endPosition) { + return; + } + + setLoop(startPosition, endPosition, true); + if (!isPlayingByPlayButton()) { + // cueGoto is processed asynchrony. + // avoid a wrong cue set if seek by cueGoto is still pending + m_bPreviewing = false; + m_iCurrentlyPreviewingHotcues = 0; + // don't move the cue point to the hot cue point in DENON mode + m_bypassCueSetByPlay = true; + m_pPlay->set(1.0); + } +} + void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { if (!v) return; @@ -1987,6 +2030,11 @@ HotcueControl::HotcueControl(QString group, int i) this, &HotcueControl::slotHotcueGotoAndStop, Qt::DirectConnection); + m_hotcueReloop = new ControlPushButton(keyForControl(i, "reloop")); + connect(m_hotcueReloop, &ControlObject::valueChanged, + this, &HotcueControl::slotHotcueReloop, + Qt::DirectConnection); + m_hotcueActivate = new ControlPushButton(keyForControl(i, "activate")); connect(m_hotcueActivate, &ControlObject::valueChanged, this, &HotcueControl::slotHotcueActivate, @@ -2024,6 +2072,7 @@ HotcueControl::~HotcueControl() { delete m_hotcueGoto; delete m_hotcueGotoAndPlay; delete m_hotcueGotoAndStop; + delete m_hotcueReloop; delete m_hotcueActivate; delete m_hotcueActivateCue; delete m_hotcueActivateLoop; @@ -2055,6 +2104,10 @@ void HotcueControl::slotHotcueGotoAndStop(double v) { emit(hotcueGotoAndStop(this, v)); } +void HotcueControl::slotHotcueReloop(double v) { + emit(hotcueReloop(this, v)); +} + void HotcueControl::slotHotcueActivate(double v) { emit(hotcueActivate(this, v)); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 19b9073635a1..89f065b01ffb 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -73,6 +73,7 @@ class HotcueControl : public QObject { void slotHotcueGoto(double v); void slotHotcueGotoAndPlay(double v); void slotHotcueGotoAndStop(double v); + void slotHotcueReloop(double v); void slotHotcueActivate(double v); void slotHotcueActivateCue(double v); void slotHotcueActivateLoop(double v); @@ -89,6 +90,7 @@ class HotcueControl : public QObject { void hotcueGoto(HotcueControl* pHotcue, double v); void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); + void hotcueReloop(HotcueControl* pHotcue, double v); void hotcueActivate(HotcueControl* pHotcue, double v); void hotcueActivateCue(HotcueControl* pHotcue, double v); void hotcueActivateLoop(HotcueControl* pHotcue, double v); @@ -118,6 +120,7 @@ class HotcueControl : public QObject { ControlObject* m_hotcueGoto; ControlObject* m_hotcueGotoAndPlay; ControlObject* m_hotcueGotoAndStop; + ControlObject* m_hotcueReloop; ControlObject* m_hotcueActivate; ControlObject* m_hotcueActivateCue; ControlObject* m_hotcueActivateLoop; @@ -159,6 +162,7 @@ class CueControl : public EngineControl { void hotcueGoto(HotcueControl* pControl, double v); void hotcueGotoAndPlay(HotcueControl* pControl, double v); void hotcueGotoAndStop(HotcueControl* pControl, double v); + void hotcueReloop(HotcueControl* pControl, double v); void hotcueLoopToggle(HotcueControl* pControl, double v); void hotcueActivate(HotcueControl* pControl, double v); void hotcueActivateCue(HotcueControl* pControl, double v); From 2ed774b5e77f752da7cdd2a94d513eb57318aac0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 11 Aug 2019 20:02:30 +0200 Subject: [PATCH 009/153] Add hotcue_X_type CO --- src/engine/controls/cuecontrol.cpp | 31 +++++++++++++++++++++++++++++- src/engine/controls/cuecontrol.h | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index a2567a2d353f..c715e6b0ff8e 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -23,6 +23,12 @@ static const double CUE_MODE_NUMARK = 3.0; static const double CUE_MODE_MIXXX_NO_BLINK = 4.0; static const double CUE_MODE_CUP = 5.0; +typedef enum { + HOTCUE_TYPE_NONE = -1, + HOTCUE_TYPE_CUE = 0, + HOTCUE_TYPE_LOOP = 1, +} HotcueType; + CueControl::CueControl(QString group, UserSettingsPointer pConfig) : EngineControl(group, pConfig), @@ -1992,6 +1998,10 @@ HotcueControl::HotcueControl(QString group, int i) m_hotcueEnabled = new ControlObject(keyForControl(i, "enabled")); m_hotcueEnabled->setReadOnly(); + m_hotcueType = new ControlObject(keyForControl(i, "type")); + m_hotcueType->set(HOTCUE_TYPE_NONE); + m_hotcueType->setReadOnly(); + // The id of the predefined color assigned to this color. m_hotcueColor = new ControlObject(keyForControl(i, "color_id")); connect(m_hotcueColor, @@ -2065,6 +2075,7 @@ HotcueControl::~HotcueControl() { delete m_hotcuePosition; delete m_hotcueLength; delete m_hotcueEnabled; + delete m_hotcueType; delete m_hotcueColor; delete m_hotcueSet; delete m_hotcueSetCue; @@ -2130,10 +2141,17 @@ void HotcueControl::slotHotcueClear(double v) { void HotcueControl::slotHotcuePositionChanged(double newPosition) { m_hotcueEnabled->forceSet(newPosition == -1 ? 0.0 : 1.0); + if (newPosition == -1) { + m_hotcueType->forceSet(HOTCUE_TYPE_NONE); + } + emit(hotcuePositionChanged(this, newPosition)); } void HotcueControl::slotHotcueLengthChanged(double newLength) { + if (m_hotcueEnabled->get() == 1.0) { + m_hotcueType->forceSet((newLength > 0) ? HOTCUE_TYPE_LOOP : HOTCUE_TYPE_CUE); + } emit(hotcueLengthChanged(this, newLength)); } @@ -2173,9 +2191,20 @@ void HotcueControl::resetCue() { void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); - m_hotcueEnabled->forceSet(position == -1.0 ? 0.0 : 1.0); + if (position == -1) { + m_hotcueEnabled->forceSet(0.0); + m_hotcueType->forceSet(HOTCUE_TYPE_NONE); + } else { + m_hotcueEnabled->forceSet(1.0); + m_hotcueType->forceSet((m_hotcueLength->get() > 0) ? HOTCUE_TYPE_LOOP : HOTCUE_TYPE_CUE); + } } void HotcueControl::setLength(double length) { m_hotcueLength->set(length); + if (m_hotcuePosition->get() == -1.0) { + m_hotcueType->forceSet(HOTCUE_TYPE_NONE); + } else { + m_hotcueType->forceSet((length > 0) ? HOTCUE_TYPE_LOOP : HOTCUE_TYPE_CUE); + } } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 89f065b01ffb..b853115577e5 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -112,6 +112,7 @@ class HotcueControl : public QObject { ControlObject* m_hotcuePosition; ControlObject* m_hotcueLength; ControlObject* m_hotcueEnabled; + ControlObject* m_hotcueType; ControlObject* m_hotcueColor; // Hotcue button controls ControlObject* m_hotcueSet; From 881c2677e84af56cee3d072c8de6e67256a28a2c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 13 Aug 2019 16:08:28 +0200 Subject: [PATCH 010/153] =?UTF-8?q?cuecontrol:=20=C3=8Dnvoke=20setLength()?= =?UTF-8?q?=20on=20setCue/resetCue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/controls/cuecontrol.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c715e6b0ff8e..3c728521e520 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2170,6 +2170,7 @@ double HotcueControl::getLength() const { void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); + setLength(pCue->getLength()); setColor(pCue->getColor()); // set pCue only if all other data is in place // because we have a null check for valid data else where in the code @@ -2187,6 +2188,7 @@ void HotcueControl::resetCue() { // in the code m_pCue.reset(); setPosition(-1.0); + setLength(-1.0); } void HotcueControl::setPosition(double position) { From ef3b611c69c9dbbdf3b33ed4703c2a5c17722249 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 13 Aug 2019 16:09:19 +0200 Subject: [PATCH 011/153] cuecontrol: Use enum class instead of C style typedef for HotcueType --- src/engine/controls/cuecontrol.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 3c728521e520..02f37ab2c439 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -23,11 +23,11 @@ static const double CUE_MODE_NUMARK = 3.0; static const double CUE_MODE_MIXXX_NO_BLINK = 4.0; static const double CUE_MODE_CUP = 5.0; -typedef enum { - HOTCUE_TYPE_NONE = -1, - HOTCUE_TYPE_CUE = 0, - HOTCUE_TYPE_LOOP = 1, -} HotcueType; +enum class HotcueType { + NONE = -1, + CUE = 0, + LOOP = 1, +}; CueControl::CueControl(QString group, UserSettingsPointer pConfig) : @@ -1999,7 +1999,7 @@ HotcueControl::HotcueControl(QString group, int i) m_hotcueEnabled->setReadOnly(); m_hotcueType = new ControlObject(keyForControl(i, "type")); - m_hotcueType->set(HOTCUE_TYPE_NONE); + m_hotcueType->set(static_cast(HotcueType::NONE)); m_hotcueType->setReadOnly(); // The id of the predefined color assigned to this color. @@ -2142,7 +2142,7 @@ void HotcueControl::slotHotcueClear(double v) { void HotcueControl::slotHotcuePositionChanged(double newPosition) { m_hotcueEnabled->forceSet(newPosition == -1 ? 0.0 : 1.0); if (newPosition == -1) { - m_hotcueType->forceSet(HOTCUE_TYPE_NONE); + m_hotcueType->forceSet(static_cast(HotcueType::NONE)); } emit(hotcuePositionChanged(this, newPosition)); @@ -2150,7 +2150,7 @@ void HotcueControl::slotHotcuePositionChanged(double newPosition) { void HotcueControl::slotHotcueLengthChanged(double newLength) { if (m_hotcueEnabled->get() == 1.0) { - m_hotcueType->forceSet((newLength > 0) ? HOTCUE_TYPE_LOOP : HOTCUE_TYPE_CUE); + m_hotcueType->forceSet(static_cast((newLength > 0) ? HotcueType::LOOP : HotcueType::CUE)); } emit(hotcueLengthChanged(this, newLength)); } @@ -2195,18 +2195,18 @@ void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); if (position == -1) { m_hotcueEnabled->forceSet(0.0); - m_hotcueType->forceSet(HOTCUE_TYPE_NONE); + m_hotcueType->forceSet(static_cast(HotcueType::NONE)); } else { m_hotcueEnabled->forceSet(1.0); - m_hotcueType->forceSet((m_hotcueLength->get() > 0) ? HOTCUE_TYPE_LOOP : HOTCUE_TYPE_CUE); + m_hotcueType->forceSet(static_cast((m_hotcueLength->get() > 0) ? HotcueType::LOOP : HotcueType::CUE)); } } void HotcueControl::setLength(double length) { m_hotcueLength->set(length); if (m_hotcuePosition->get() == -1.0) { - m_hotcueType->forceSet(HOTCUE_TYPE_NONE); + m_hotcueType->forceSet(static_cast(HotcueType::NONE)); } else { - m_hotcueType->forceSet((length > 0) ? HOTCUE_TYPE_LOOP : HOTCUE_TYPE_CUE); + m_hotcueType->forceSet(static_cast((length > 0) ? HotcueType::LOOP : HotcueType::CUE)); } } From 8c4143ed22f8f52d6d875fc23b5cf7710ad06c67 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 15 Aug 2019 10:36:58 +0200 Subject: [PATCH 012/153] loopingcontrol: Use enum class for LoopSeekMode --- src/engine/controls/loopingcontrol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 0968d35f0f86..0905614c8108 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -93,7 +93,7 @@ class LoopingControl : public EngineControl { void slotLoopHalve(double pressed); private: - enum LoopSeekMode { + enum class LoopSeekMode { CHANGED, // force the playposition to be inside the loop after adjusting it. MOVED_OUT, NONE, From 1f316ea763fb45aa182e10d4352595f3787bb8fd Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 23 Aug 2019 12:17:00 +0200 Subject: [PATCH 013/153] loopingcontrol: Use PascalCase for enum values --- src/engine/controls/loopingcontrol.cpp | 34 +++++++++++++------------- src/engine/controls/loopingcontrol.h | 6 ++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 5421d855e1b8..7644f0a9cdac 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -49,7 +49,7 @@ LoopingControl::LoopingControl(QString group, m_bAdjustingLoopInOld(false), m_bAdjustingLoopOutOld(false), m_bLoopOutPressedWhileLoopDisabled(false) { - m_oldLoopSamples = { kNoTrigger, kNoTrigger, LoopSeekMode::MOVED_OUT }; + m_oldLoopSamples = { kNoTrigger, kNoTrigger, LoopSeekMode::MovedOut }; m_loopSamples.setValue(m_oldLoopSamples); m_currentSample.setValue(0.0); m_pActiveBeatLoop = NULL; @@ -287,7 +287,7 @@ void LoopingControl::slotLoopScale(double scaleFactor) { } // Reseek if the loop shrank out from under the playposition. - loopSamples.seekMode = (m_bLoopingEnabled && scaleFactor < 1.0) ? LoopSeekMode::CHANGED : LoopSeekMode::MOVED_OUT; + loopSamples.seekMode = (m_bLoopingEnabled && scaleFactor < 1.0) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; m_loopSamples.setValue(loopSamples); @@ -332,7 +332,7 @@ void LoopingControl::process(const double dRate, if (loopSamples.start != m_oldLoopSamples.start || loopSamples.end != m_oldLoopSamples.end) { // bool seek is only valid after the loop has changed - if (loopSamples.seekMode == LoopSeekMode::CHANGED) { + if (loopSamples.seekMode == LoopSeekMode::Changed) { // here the loop has changed and the play position // should be moved with it double target = seekInsideAdjustedLoop(currentSample, @@ -389,13 +389,13 @@ double LoopingControl::nextTrigger(bool reverse, // bool seek is only valid after the loop has changed bool movedOut; switch(loopSamples.seekMode) { - case LoopSeekMode::CHANGED: + case LoopSeekMode::Changed: // here the loop has changed and the play position // should be moved with it *pTarget = seekInsideAdjustedLoop(currentSample, m_oldLoopSamples.start, loopSamples.start, loopSamples.end); break; - case LoopSeekMode::MOVED_OUT: + case LoopSeekMode::MovedOut: movedOut = false; // Check if we have moved out of the loop, before we could enable it if (reverse) { @@ -412,7 +412,7 @@ double LoopingControl::nextTrigger(bool reverse, loopSamples.start, loopSamples.start, loopSamples.end); } break; - case LoopSeekMode::NONE: + case LoopSeekMode::None: // Nothing to do here break; } @@ -520,10 +520,10 @@ void LoopingControl::setLoop(double startPosition, double endPosition, bool relo qDebug() << "setLoop" << startPosition << endPosition << reloop; LoopSamples loopSamples = m_loopSamples.getValue(); - if (loopSamples.start != startPosition || loopSamples.end != endPosition || loopSamples.seekMode != LoopSeekMode::NONE) { + if (loopSamples.start != startPosition || loopSamples.end != endPosition || loopSamples.seekMode != LoopSeekMode::None) { loopSamples.start = startPosition; loopSamples.end = endPosition; - loopSamples.seekMode = LoopSeekMode::NONE; + loopSamples.seekMode = LoopSeekMode::None; clearActiveBeatLoop(); @@ -595,9 +595,9 @@ void LoopingControl::setLoopInToCurrentPosition() { if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger) { setLoopingEnabled(true); - loopSamples.seekMode = LoopSeekMode::CHANGED; + loopSamples.seekMode = LoopSeekMode::Changed; } else { - loopSamples.seekMode = LoopSeekMode::MOVED_OUT; + loopSamples.seekMode = LoopSeekMode::MovedOut; } if (m_pQuantizeEnabled->toBool() @@ -695,9 +695,9 @@ void LoopingControl::setLoopOutToCurrentPosition() { if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger) { setLoopingEnabled(true); - loopSamples.seekMode = LoopSeekMode::CHANGED; + loopSamples.seekMode = LoopSeekMode::Changed; } else { - loopSamples.seekMode = LoopSeekMode::MOVED_OUT; + loopSamples.seekMode = LoopSeekMode::MovedOut; } if (m_pQuantizeEnabled->toBool() && pBeats) { @@ -843,7 +843,7 @@ void LoopingControl::slotLoopStartPos(double pos) { setLoopingEnabled(false); } - loopSamples.seekMode = LoopSeekMode::MOVED_OUT; + loopSamples.seekMode = LoopSeekMode::MovedOut; loopSamples.start = pos; m_pCOLoopStartPosition->set(pos); @@ -879,7 +879,7 @@ void LoopingControl::slotLoopEndPos(double pos) { setLoopingEnabled(false); } loopSamples.end = pos; - loopSamples.seekMode = LoopSeekMode::MOVED_OUT; + loopSamples.seekMode = LoopSeekMode::MovedOut; m_pCOLoopEndPosition->set(pos); m_loopSamples.setValue(loopSamples); } @@ -1104,7 +1104,7 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable // Calculate the new loop start and end samples // give start and end defaults so we can detect problems - LoopSamples newloopSamples = {kNoTrigger, kNoTrigger, LoopSeekMode::MOVED_OUT}; + LoopSamples newloopSamples = {kNoTrigger, kNoTrigger, LoopSeekMode::MovedOut}; LoopSamples loopSamples = m_loopSamples.getValue(); double currentSample = m_currentSample.getValue(); @@ -1191,7 +1191,7 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable // If resizing an inactive loop by changing beatloop_size, // do not seek to the adjusted loop. - newloopSamples.seekMode = (keepStartPoint && (enable || m_bLoopingEnabled)) ? LoopSeekMode::CHANGED : LoopSeekMode::MOVED_OUT; + newloopSamples.seekMode = (keepStartPoint && (enable || m_bLoopingEnabled)) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; m_loopSamples.setValue(newloopSamples); m_pCOLoopStartPosition->set(newloopSamples.start); @@ -1293,7 +1293,7 @@ void LoopingControl::slotLoopMove(double beats) { // If we are looping make sure that the play head does not leave the // loop as a result of our adjustment. - loopSamples.seekMode = m_bLoopingEnabled ? LoopSeekMode::CHANGED : LoopSeekMode::MOVED_OUT; + loopSamples.seekMode = m_bLoopingEnabled ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; loopSamples.start = new_loop_in; loopSamples.end = new_loop_out; diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 0905614c8108..8cc5f1689282 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -94,9 +94,9 @@ class LoopingControl : public EngineControl { private: enum class LoopSeekMode { - CHANGED, // force the playposition to be inside the loop after adjusting it. - MOVED_OUT, - NONE, + Changed, // force the playposition to be inside the loop after adjusting it. + MovedOut, + None, }; struct LoopSamples { From 369dbdbca82aed65aa212a45ba3bb95199fa7c12 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 30 Aug 2019 12:32:10 +0200 Subject: [PATCH 014/153] Use Cue::LOOP type for saved loop cues --- src/engine/controls/cuecontrol.cpp | 70 +++++++++++++++++------------- src/engine/controls/cuecontrol.h | 5 +++ src/mixer/basetrackplayer.cpp | 4 +- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 02f37ab2c439..319e46cfcd0d 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -23,12 +23,6 @@ static const double CUE_MODE_NUMARK = 3.0; static const double CUE_MODE_MIXXX_NO_BLINK = 4.0; static const double CUE_MODE_CUP = 5.0; -enum class HotcueType { - NONE = -1, - CUE = 0, - LOOP = 1, -}; - CueControl::CueControl(QString group, UserSettingsPointer pConfig) : EngineControl(group, pConfig), @@ -425,7 +419,8 @@ void CueControl::loadCuesFromTrack() { } else if (pCue->getType() == Cue::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::CUE || pCue->getType() == Cue::LOOP) + && pCue->getHotCue() != -1) { int hotcue = pCue->getHotCue(); HotcueControl* pControl = m_hotcueControls.value(hotcue, NULL); @@ -448,6 +443,7 @@ void CueControl::loadCuesFromTrack() { pControl->setPosition(pCue->getPosition()); pControl->setLength(pCue->getLength()); pControl->setColor(pCue->getColor()); + pControl->setType(pCue->getType()); } // Add the hotcue to the list of active hotcues active_hotcues.insert(hotcue); @@ -589,7 +585,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { pCue->setLength(cueLength); pCue->setHotCue(hotcue); pCue->setLabel(""); - pCue->setType(Cue::CUE); + pCue->setType(cueLength == -1 ? Cue::CUE : Cue::LOOP); pCue->setSource(Cue::MANUAL); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); @@ -685,7 +681,7 @@ void CueControl::hotcueSetLoop(HotcueControl* pControl, double v) { pCue->setLength(loopLength); pCue->setHotCue(hotcue); pCue->setLabel(""); - pCue->setType(Cue::CUE); + pCue->setType(Cue::LOOP); pCue->setSource(Cue::MANUAL); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); @@ -1080,6 +1076,23 @@ void CueControl::hotcueLengthChanged(HotcueControl* pControl, double newLength) } } +void CueControl::hotcueTypeChanged(HotcueControl* pControl, double newType) { + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) + return; + + CuePointer pCue(pControl->getCue()); + if (pCue) { + // Setting the type to 0 or -1 is the same as calling hotcue_x_clear + if (newType <= 0) { + pCue->setHotCue(-1); + detachCue(pControl->getHotcueNumber()); + } else { + pCue->setType(static_cast(newType)); + } + } +} + void CueControl::hintReader(HintVector* pHintList) { Hint cue_hint; double cuePoint = m_pCuePoint->get(); @@ -1999,8 +2012,11 @@ HotcueControl::HotcueControl(QString group, int i) m_hotcueEnabled->setReadOnly(); m_hotcueType = new ControlObject(keyForControl(i, "type")); - m_hotcueType->set(static_cast(HotcueType::NONE)); - m_hotcueType->setReadOnly(); + connect(m_hotcueType, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueTypeChanged, + Qt::DirectConnection); // The id of the predefined color assigned to this color. m_hotcueColor = new ControlObject(keyForControl(i, "color_id")); @@ -2141,20 +2157,17 @@ void HotcueControl::slotHotcueClear(double v) { void HotcueControl::slotHotcuePositionChanged(double newPosition) { m_hotcueEnabled->forceSet(newPosition == -1 ? 0.0 : 1.0); - if (newPosition == -1) { - m_hotcueType->forceSet(static_cast(HotcueType::NONE)); - } - emit(hotcuePositionChanged(this, newPosition)); } void HotcueControl::slotHotcueLengthChanged(double newLength) { - if (m_hotcueEnabled->get() == 1.0) { - m_hotcueType->forceSet(static_cast((newLength > 0) ? HotcueType::LOOP : HotcueType::CUE)); - } emit(hotcueLengthChanged(this, newLength)); } +void HotcueControl::slotHotcueTypeChanged(double newType) { + emit(hotcueTypeChanged(this, newType)); +} + void HotcueControl::slotHotcueColorChanged(double newColorId) { m_pCue->setColor(Color::kPredefinedColorsSet.predefinedColorFromId(newColorId)); emit(hotcueColorChanged(this, newColorId)); @@ -2168,6 +2181,10 @@ double HotcueControl::getLength() const { return m_hotcueLength->get(); } +double HotcueControl::getType() const { + return m_hotcueType->get(); +} + void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); setLength(pCue->getLength()); @@ -2193,20 +2210,13 @@ void HotcueControl::resetCue() { void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); - if (position == -1) { - m_hotcueEnabled->forceSet(0.0); - m_hotcueType->forceSet(static_cast(HotcueType::NONE)); - } else { - m_hotcueEnabled->forceSet(1.0); - m_hotcueType->forceSet(static_cast((m_hotcueLength->get() > 0) ? HotcueType::LOOP : HotcueType::CUE)); - } + m_hotcueEnabled->forceSet((position == -1) ? 0.0 : 1.0); } void HotcueControl::setLength(double length) { m_hotcueLength->set(length); - if (m_hotcuePosition->get() == -1.0) { - m_hotcueType->forceSet(static_cast(HotcueType::NONE)); - } else { - m_hotcueType->forceSet(static_cast((length > 0) ? HotcueType::LOOP : HotcueType::CUE)); - } +} + +void HotcueControl::setType(double type) { + m_hotcueType->set(type); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index b853115577e5..f257886a5409 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -45,10 +45,12 @@ class HotcueControl : public QObject { inline CuePointer getCue() { return m_pCue; } double getPosition() const; double getLength() const; + double getType() const; void setCue(CuePointer pCue); void resetCue(); void setPosition(double position); void setLength(double length); + void setType(double type); void setColor(PredefinedColorPointer newColor); PredefinedColorPointer getColor() const; @@ -81,6 +83,7 @@ class HotcueControl : public QObject { void slotHotcueClear(double v); void slotHotcueLengthChanged(double newPosition); void slotHotcuePositionChanged(double newPosition); + void slotHotcueTypeChanged(double newType); void slotHotcueColorChanged(double newColorId); signals: @@ -98,6 +101,7 @@ class HotcueControl : public QObject { void hotcueClear(HotcueControl* pHotcue, double v); void hotcuePositionChanged(HotcueControl* pHotcue, double newPosition); void hotcueLengthChanged(HotcueControl* pHotcue, double newLength); + void hotcueTypeChanged(HotcueControl* pHotcue, double newType); void hotcueColorChanged(HotcueControl* pHotcue, double newColorId); void hotcuePlay(double v); @@ -172,6 +176,7 @@ class CueControl : public EngineControl { void hotcueClear(HotcueControl* pControl, double v); void hotcuePositionChanged(HotcueControl* pControl, double newPosition); void hotcueLengthChanged(HotcueControl* pControl, double newLength); + void hotcueTypeChanged(HotcueControl* pControl, double newType); void cueSet(double v); void cueClear(double v); diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index 56554935ccc6..fb66d86a5d27 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::LOOP && pCue->getHotCue() == -1) { double loopStart = pCue->getPosition(); double loopEnd = loopStart + pCue->getLength(); if (loopStart != kNoTrigger && loopEnd != kNoTrigger && loopStart <= loopEnd) { @@ -220,7 +220,7 @@ TrackPointer BaseTrackPlayerImpl::unloadTrack() { QListIterator it(cuePoints); while (it.hasNext()) { CuePointer pCue(it.next()); - if (pCue->getType() == Cue::LOOP) { + if (pCue->getType() == Cue::LOOP && pCue->getHotCue() == -1) { pLoopCue = pCue; } } From 486a346abc419be362e2d6421853fa2b957a30ca Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 30 Aug 2019 14:26:07 +0200 Subject: [PATCH 015/153] Pass CuePointer to LoopingControl to track saved loop changes --- src/engine/controls/cuecontrol.cpp | 18 ++---------------- src/engine/controls/enginecontrol.cpp | 4 ++-- src/engine/controls/enginecontrol.h | 2 +- src/engine/controls/loopingcontrol.cpp | 25 +++++++++++++++++++------ src/engine/controls/loopingcontrol.h | 4 +++- src/engine/enginebuffer.cpp | 4 ++-- src/engine/enginebuffer.h | 2 +- 7 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 319e46cfcd0d..0de430bb3022 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -795,7 +795,7 @@ void CueControl::hotcueReloop(HotcueControl* pControl, double v) { return; } - setLoop(startPosition, endPosition, true); + setSavedLoop(pCue, true); if (!isPlayingByPlayButton()) { // cueGoto is processed asynchrony. // avoid a wrong cue set if seek by cueGoto is still pending @@ -825,21 +825,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { return; } - double startPosition = pCue->getPosition(); - if (startPosition == -1) { - return; - } - - double endPosition = startPosition + pCue->getLength(); - if (startPosition >= endPosition) { - return; - } - - if(m_pLoopStartPosition->get() != startPosition || m_pLoopEndPosition->get() != endPosition) { - setLoop(startPosition, endPosition, false); - } else { - m_pLoopToggle->set(1.0); - } + setSavedLoop(pCue, false); } void CueControl::hotcueActivate(HotcueControl* pControl, double v) { diff --git a/src/engine/controls/enginecontrol.cpp b/src/engine/controls/enginecontrol.cpp index fbb2a649363a..624366a9dc0b 100644 --- a/src/engine/controls/enginecontrol.cpp +++ b/src/engine/controls/enginecontrol.cpp @@ -67,9 +67,9 @@ EngineBuffer* EngineControl::getEngineBuffer() { return m_pEngineBuffer; } -void EngineControl::setLoop(double startPosition, double endPosition, bool reloop) { +void EngineControl::setSavedLoop(CuePointer pCue, bool reloop) { if (m_pEngineBuffer) { - m_pEngineBuffer->setLoop(startPosition, endPosition, reloop); + m_pEngineBuffer->setSavedLoop(pCue, reloop); } } diff --git a/src/engine/controls/enginecontrol.h b/src/engine/controls/enginecontrol.h index 1a8e4b008d39..04463c6aed84 100644 --- a/src/engine/controls/enginecontrol.h +++ b/src/engine/controls/enginecontrol.h @@ -59,7 +59,7 @@ class EngineControl : public QObject { const double dTotalSamples, const double dTrackSampleRate); QString getGroup() const; - void setLoop(double startPosition, double endPosition, bool reloop); + void setSavedLoop(CuePointer pCue, bool reloop); // Called to collect player features for effects processing. virtual void collectFeatureState(GroupFeatureState* pGroupFeatures) const { diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 7644f0a9cdac..529e82f4fd7c 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -516,17 +516,32 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl return dSyncedPlayPos; } -void LoopingControl::setLoop(double startPosition, double endPosition, bool reloop) { - qDebug() << "setLoop" << startPosition << endPosition << reloop; +void LoopingControl::setSavedLoop(CuePointer pCue, bool reloop) { + qDebug() << "setSavedLoop" << reloop; + + if(!pCue) { + m_pCue.reset(); + clearActiveBeatLoop(); + return; + } + DEBUG_ASSERT(pCue->getType() == Cue::LOOP); + + double startPosition = pCue->getPosition();; + double endPosition = startPosition + pCue->getLength(); + if(startPosition < 0 || startPosition >= endPosition) { + m_pCue.reset(); + clearActiveBeatLoop(); + return; + } LoopSamples loopSamples = m_loopSamples.getValue(); if (loopSamples.start != startPosition || loopSamples.end != endPosition || loopSamples.seekMode != LoopSeekMode::None) { loopSamples.start = startPosition; loopSamples.end = endPosition; loopSamples.seekMode = LoopSeekMode::None; - clearActiveBeatLoop(); + m_pCue = pCue; m_loopSamples.setValue(loopSamples); m_pCOLoopStartPosition->set(loopSamples.start); m_pCOLoopEndPosition->set(loopSamples.end); @@ -536,9 +551,7 @@ void LoopingControl::setLoop(double startPosition, double endPosition, bool relo } if (reloop) { - // seekExact is necessary here to prevent notifySeek() from disabling our loop - seekAbs(static_cast( - m_loopSamples.getValue().start)); + seekAbs(static_cast(m_loopSamples.getValue().start)); } } diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 8cc5f1689282..a705027d2151 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -51,7 +51,7 @@ class LoopingControl : public EngineControl { void notifySeek(double dNewPlaypos) override; - void setLoop(double startPosition, double endPosition, bool reloop); + void setSavedLoop(CuePointer pCue, bool reloop); bool isLoopingEnabled(); @@ -175,6 +175,8 @@ class LoopingControl : public EngineControl { ControlObject* m_pCOLoopMove; QList m_loopMoves; + CuePointer m_pCue; + // objects below are written from an engine worker thread TrackPointer m_pTrack; BeatsPointer m_pBeats; diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 1a99456b9a04..139b0d27f7b2 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -350,8 +350,8 @@ double EngineBuffer::getLocalBpm() { return m_pBpmControl->getLocalBpm(); } -void EngineBuffer::setLoop(double startPosition, double endPosition, bool reloop) { - m_pLoopingControl->setLoop(startPosition, endPosition, reloop); +void EngineBuffer::setSavedLoop(CuePointer pCue, bool reloop) { + m_pLoopingControl->setSavedLoop(pCue, reloop); } void EngineBuffer::setEngineMaster(EngineMaster* pEngineMaster) { diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index bd54a5db0a4c..90d866cc80e8 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -125,7 +125,7 @@ class EngineBuffer : public EngineObject { // Returns the BPM of the loaded track around the current position (not thread-safe) double getLocalBpm(); // Sets a loop for the loaded track (not thread safe) - void setLoop(double, double, bool); + void setSavedLoop(CuePointer, bool); // Sets pointer to other engine buffer/channel void setEngineMaster(EngineMaster*); From 7fc1c8de00e918167e7d22620d40c6b9a15e5e17 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 30 Aug 2019 15:35:51 +0200 Subject: [PATCH 016/153] Replace setSavedLoop's second paramter "reloop" with "toggle" --- src/engine/controls/cuecontrol.cpp | 6 ++++-- src/engine/controls/enginecontrol.cpp | 4 ++-- src/engine/controls/enginecontrol.h | 2 +- src/engine/controls/loopingcontrol.cpp | 10 +++------- src/engine/controls/loopingcontrol.h | 2 +- src/engine/enginebuffer.cpp | 4 ++-- 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 0de430bb3022..fd8d8a7df76a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -795,7 +795,9 @@ void CueControl::hotcueReloop(HotcueControl* pControl, double v) { return; } - setSavedLoop(pCue, true); + setSavedLoop(pCue, false); + hotcueGoto(pControl, v); + if (!isPlayingByPlayButton()) { // cueGoto is processed asynchrony. // avoid a wrong cue set if seek by cueGoto is still pending @@ -825,7 +827,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { return; } - setSavedLoop(pCue, false); + setSavedLoop(pCue, true); } void CueControl::hotcueActivate(HotcueControl* pControl, double v) { diff --git a/src/engine/controls/enginecontrol.cpp b/src/engine/controls/enginecontrol.cpp index 624366a9dc0b..b19ee98b5127 100644 --- a/src/engine/controls/enginecontrol.cpp +++ b/src/engine/controls/enginecontrol.cpp @@ -67,9 +67,9 @@ EngineBuffer* EngineControl::getEngineBuffer() { return m_pEngineBuffer; } -void EngineControl::setSavedLoop(CuePointer pCue, bool reloop) { +void EngineControl::setSavedLoop(CuePointer pCue, bool toggle) { if (m_pEngineBuffer) { - m_pEngineBuffer->setSavedLoop(pCue, reloop); + m_pEngineBuffer->setSavedLoop(pCue, toggle); } } diff --git a/src/engine/controls/enginecontrol.h b/src/engine/controls/enginecontrol.h index 04463c6aed84..f3208b37a864 100644 --- a/src/engine/controls/enginecontrol.h +++ b/src/engine/controls/enginecontrol.h @@ -59,7 +59,7 @@ class EngineControl : public QObject { const double dTotalSamples, const double dTrackSampleRate); QString getGroup() const; - void setSavedLoop(CuePointer pCue, bool reloop); + void setSavedLoop(CuePointer pCue, bool toggle); // Called to collect player features for effects processing. virtual void collectFeatureState(GroupFeatureState* pGroupFeatures) const { diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 529e82f4fd7c..3e9c069965c1 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -516,8 +516,8 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl return dSyncedPlayPos; } -void LoopingControl::setSavedLoop(CuePointer pCue, bool reloop) { - qDebug() << "setSavedLoop" << reloop; +void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { + qDebug() << "setSavedLoop" << toggle; if(!pCue) { m_pCue.reset(); @@ -547,11 +547,7 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool reloop) { m_pCOLoopEndPosition->set(loopSamples.end); setLoopingEnabled(true); } else { - setLoopingEnabled(m_bLoopingEnabled ? reloop : true); - } - - if (reloop) { - seekAbs(static_cast(m_loopSamples.getValue().start)); + setLoopingEnabled(toggle ? !m_bLoopingEnabled : true); } } diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index a705027d2151..0f683a2e4119 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -51,7 +51,7 @@ class LoopingControl : public EngineControl { void notifySeek(double dNewPlaypos) override; - void setSavedLoop(CuePointer pCue, bool reloop); + void setSavedLoop(CuePointer pCue, bool toggle); bool isLoopingEnabled(); diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 139b0d27f7b2..7941641eea29 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -350,8 +350,8 @@ double EngineBuffer::getLocalBpm() { return m_pBpmControl->getLocalBpm(); } -void EngineBuffer::setSavedLoop(CuePointer pCue, bool reloop) { - m_pLoopingControl->setSavedLoop(pCue, reloop); +void EngineBuffer::setSavedLoop(CuePointer pCue, bool toggle) { + m_pLoopingControl->setSavedLoop(pCue, toggle); } void EngineBuffer::setEngineMaster(EngineMaster* pEngineMaster) { From f1a1bb26474943370331e53a428afadd2cccf8f6 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 30 Aug 2019 15:36:32 +0200 Subject: [PATCH 017/153] loopingcontrol: Add tracking of changes to an active saved loop --- src/engine/controls/cuecontrol.cpp | 6 ++++++ src/engine/controls/loopingcontrol.cpp | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index fd8d8a7df76a..8e589d827912 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -595,6 +595,10 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { pCue->setColor(predefinedColors.at((hotcue % (predefinedColors.count() - 1)) + 1)); }; + if (pCue->getType() == Cue::LOOP) { + setSavedLoop(pCue, false); + } + // If quantize is enabled and we are not playing, jump to the cue point // since it's not necessarily where we currently are. TODO(XXX) is this // potentially invalid for vinyl control? @@ -690,6 +694,8 @@ void CueControl::hotcueSetLoop(HotcueControl* pControl, double v) { const QList predefinedColors = Color::kPredefinedColorsSet.allColors; pCue->setColor(predefinedColors.at((hotcue % (predefinedColors.count() - 1)) + 1)); }; + + setSavedLoop(pCue, false); } void CueControl::hotcueGoto(HotcueControl* pControl, double v) { diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 3e9c069965c1..f4dd7e04fb05 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -290,6 +290,10 @@ void LoopingControl::slotLoopScale(double scaleFactor) { loopSamples.seekMode = (m_bLoopingEnabled && scaleFactor < 1.0) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; m_loopSamples.setValue(loopSamples); + if(m_pCue) { + m_pCue->setPosition(loopSamples.start); + m_pCue->setLength(loopSamples.end - loopSamples.start); + } // Update CO for loop end marker m_pCOLoopEndPosition->set(loopSamples.end); @@ -1084,6 +1088,11 @@ void LoopingControl::updateBeatLoopingControls() { } void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable) { + // If this is a "new" loop, stop tracking saved loop changes + if(!keepStartPoint) { + m_pCue.reset(); + } + // if a seek was queued in the engine buffer move the current sample to its position double p_seekPosition = 0; if (getEngineBuffer()->getQueuedSeekPosition(&p_seekPosition)) { @@ -1205,6 +1214,10 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable m_loopSamples.setValue(newloopSamples); m_pCOLoopStartPosition->set(newloopSamples.start); m_pCOLoopEndPosition->set(newloopSamples.end); + if(m_pCue) { + m_pCue->setPosition(loopSamples.start); + m_pCue->setLength(loopSamples.end - loopSamples.start); + } if (enable) { setLoopingEnabled(true); @@ -1307,6 +1320,10 @@ void LoopingControl::slotLoopMove(double beats) { loopSamples.start = new_loop_in; loopSamples.end = new_loop_out; m_loopSamples.setValue(loopSamples); + if (m_pCue) { + m_pCue->setPosition(loopSamples.start); + m_pCue->setLength(loopSamples.end - loopSamples.start); + } m_pCOLoopStartPosition->set(new_loop_in); m_pCOLoopEndPosition->set(new_loop_out); } From 1980ef5ee0fb2d62e31bcdcd04e237c1061309df Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 2 Sep 2019 21:36:40 +0200 Subject: [PATCH 018/153] cue: Manage hotcue status inside Cue class --- src/engine/controls/cuecontrol.cpp | 9 +++-- src/engine/controls/cuecontrol.h | 1 + src/engine/controls/loopingcontrol.cpp | 24 ++++++++++--- src/track/cue.cpp | 49 ++++++++++++++++++++++++++ src/track/cue.h | 12 +++++++ 5 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 8e589d827912..3db2a0a104ed 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -444,6 +444,7 @@ void CueControl::loadCuesFromTrack() { pControl->setLength(pCue->getLength()); pControl->setColor(pCue->getColor()); pControl->setType(pCue->getType()); + pControl->setStatus(pCue->getStatus()); } // Add the hotcue to the list of active hotcues active_hotcues.insert(hotcue); @@ -2150,7 +2151,6 @@ void HotcueControl::slotHotcueClear(double v) { } void HotcueControl::slotHotcuePositionChanged(double newPosition) { - m_hotcueEnabled->forceSet(newPosition == -1 ? 0.0 : 1.0); emit(hotcuePositionChanged(this, newPosition)); } @@ -2183,6 +2183,7 @@ void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); setLength(pCue->getLength()); setColor(pCue->getColor()); + setStatus(pCue->getStatus()); // set pCue only if all other data is in place // because we have a null check for valid data else where in the code m_pCue = pCue; @@ -2200,11 +2201,11 @@ void HotcueControl::resetCue() { m_pCue.reset(); setPosition(-1.0); setLength(-1.0); + setStatus(static_cast(Cue::CueStatus::DISABLED)); } void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); - m_hotcueEnabled->forceSet((position == -1) ? 0.0 : 1.0); } void HotcueControl::setLength(double length) { @@ -2214,3 +2215,7 @@ void HotcueControl::setLength(double length) { void HotcueControl::setType(double type) { m_hotcueType->set(type); } + +void HotcueControl::setStatus(double status) { + m_hotcueEnabled->set(static_cast(status)); +} diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index f257886a5409..c6b9ff1d0fb0 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -51,6 +51,7 @@ class HotcueControl : public QObject { void setPosition(double position); void setLength(double length); void setType(double type); + void setStatus(double status); void setColor(PredefinedColorPointer newColor); PredefinedColorPointer getColor() const; diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index f4dd7e04fb05..e77a587fce81 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -524,8 +524,11 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { qDebug() << "setSavedLoop" << toggle; if(!pCue) { - m_pCue.reset(); - clearActiveBeatLoop(); + if(m_pCue) { + m_pCue->deactivate(); + m_pCue.reset(); + } + clearActiveBeatLoop(); return; } DEBUG_ASSERT(pCue->getType() == Cue::LOOP); @@ -533,7 +536,10 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { double startPosition = pCue->getPosition();; double endPosition = startPosition + pCue->getLength(); if(startPosition < 0 || startPosition >= endPosition) { - m_pCue.reset(); + if(m_pCue) { + m_pCue->deactivate(); + m_pCue.reset(); + } clearActiveBeatLoop(); return; } @@ -550,8 +556,15 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { m_pCOLoopStartPosition->set(loopSamples.start); m_pCOLoopEndPosition->set(loopSamples.end); setLoopingEnabled(true); + m_pCue->activate(); } else { - setLoopingEnabled(toggle ? !m_bLoopingEnabled : true); + bool activate_cue = toggle ? !m_bLoopingEnabled : true; + setLoopingEnabled(activate_cue); + if(activate_cue) { + m_pCue->activate(); + } else { + m_pCue->deactivate(); + } } } @@ -1089,7 +1102,8 @@ void LoopingControl::updateBeatLoopingControls() { void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable) { // If this is a "new" loop, stop tracking saved loop changes - if(!keepStartPoint) { + if(!keepStartPoint && m_pCue) { + m_pCue->deactivate(); m_pCue.reset(); } diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 1d27df21c6d2..33df9d54c4ab 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -21,6 +21,7 @@ void CuePointer::deleteLater(Cue* pCue) { Cue::Cue(TrackId trackId) : m_bDirty(false), + m_bActive(false), m_iId(-1), m_trackId(trackId), m_source(UNKNOWN), @@ -36,6 +37,7 @@ Cue::Cue(TrackId trackId) Cue::Cue(int id, TrackId trackId, Cue::CueSource source, Cue::CueType type, double position, double length, int hotCue, QString label, PredefinedColorPointer color) : m_bDirty(false), + m_bActive(false), m_iId(id), m_trackId(trackId), m_source(source), @@ -87,6 +89,53 @@ void Cue::setSource(CueSource source) { emit(updated()); } +Cue::CueStatus Cue::getStatus() const { + CueStatus status = CueStatus::DISABLED; + switch(getType()) { + case CueType::LOOP: + if (getPosition() != -1 && getPosition() > 0) { + status = CueStatus::ENABLED; + } + break; + default: + if (getPosition() != -1) { + status = CueStatus::ENABLED; + } + break; + } + + if(status == CueStatus::ENABLED && isActive()) { + status = CueStatus::ACTIVE; + } + + return status; +} + +bool Cue::isActive() const { + QMutexLocker lock(&m_mutex); + return m_bActive; +} + +void Cue::activate() { + QMutexLocker lock(&m_mutex); + bool changed = !m_bActive; + m_bActive = true; + lock.unlock(); + if (changed) { + emit(updated()); + } +} + +void Cue::deactivate() { + QMutexLocker lock(&m_mutex); + bool changed = m_bActive; + m_bActive = false; + lock.unlock(); + if (changed) { + emit(updated()); + } +} + Cue::CueType Cue::getType() const { QMutexLocker lock(&m_mutex); return m_type; diff --git a/src/track/cue.h b/src/track/cue.h index 6843dab19743..19dedc0d76b0 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -23,6 +23,12 @@ class Cue : public QObject { MANUAL = 2, }; + enum CueStatus { + DISABLED = 0, + ENABLED = 1, + ACTIVE = 2, + }; + enum CueType { INVALID = 0, CUE = 1, // hot cue @@ -46,6 +52,11 @@ class Cue : public QObject { CueType getType() const; void setType(CueType type); + CueStatus getStatus() const; + bool isActive() const; + void activate(); + void deactivate(); + double getPosition() const; void setPosition(double samplePosition); @@ -77,6 +88,7 @@ class Cue : public QObject { mutable QMutex m_mutex; bool m_bDirty; + bool m_bActive; int m_iId; TrackId m_trackId; CueSource m_source; From b3220d0c83fa6a0cfbfcc6abfa6a3a298b620eae Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 2 Sep 2019 22:08:05 +0200 Subject: [PATCH 019/153] cuecontrol: Reset cue type in resetCue() --- src/engine/controls/cuecontrol.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 3db2a0a104ed..7c9ae2e07a74 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2201,6 +2201,7 @@ void HotcueControl::resetCue() { m_pCue.reset(); setPosition(-1.0); setLength(-1.0); + setType(static_cast(Cue::CueType::INVALID)); setStatus(static_cast(Cue::CueStatus::DISABLED)); } From 5f18a64a437f03fb136c83e199b1816a83365f93 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 2 Sep 2019 22:26:26 +0200 Subject: [PATCH 020/153] cuecontrol: Fix HotcueControl::get/setType methods --- src/engine/controls/cuecontrol.cpp | 10 +++------- src/engine/controls/cuecontrol.h | 3 +-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 7c9ae2e07a74..2af6934828c5 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2175,10 +2175,6 @@ double HotcueControl::getLength() const { return m_hotcueLength->get(); } -double HotcueControl::getType() const { - return m_hotcueType->get(); -} - void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); setLength(pCue->getLength()); @@ -2201,7 +2197,7 @@ void HotcueControl::resetCue() { m_pCue.reset(); setPosition(-1.0); setLength(-1.0); - setType(static_cast(Cue::CueType::INVALID)); + setType(Cue::CueType::INVALID); setStatus(static_cast(Cue::CueStatus::DISABLED)); } @@ -2213,8 +2209,8 @@ void HotcueControl::setLength(double length) { m_hotcueLength->set(length); } -void HotcueControl::setType(double type) { - m_hotcueType->set(type); +void HotcueControl::setType(Cue::CueType type) { + m_hotcueType->set(static_cast(type)); } void HotcueControl::setStatus(double status) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index c6b9ff1d0fb0..344b9a51afc8 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -45,12 +45,11 @@ class HotcueControl : public QObject { inline CuePointer getCue() { return m_pCue; } double getPosition() const; double getLength() const; - double getType() const; void setCue(CuePointer pCue); void resetCue(); void setPosition(double position); void setLength(double length); - void setType(double type); + void setType(Cue::CueType type); void setStatus(double status); void setColor(PredefinedColorPointer newColor); PredefinedColorPointer getColor() const; From 0d5568c1ea353486881a7ad29c37979038fd78c0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 2 Sep 2019 22:26:36 +0200 Subject: [PATCH 021/153] cuecontrol: Fix HotcueControl::setStatus method --- src/engine/controls/cuecontrol.cpp | 6 +++--- src/engine/controls/cuecontrol.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 2af6934828c5..ff43a66911ca 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2198,7 +2198,7 @@ void HotcueControl::resetCue() { setPosition(-1.0); setLength(-1.0); setType(Cue::CueType::INVALID); - setStatus(static_cast(Cue::CueStatus::DISABLED)); + setStatus(Cue::CueStatus::DISABLED); } void HotcueControl::setPosition(double position) { @@ -2213,6 +2213,6 @@ void HotcueControl::setType(Cue::CueType type) { m_hotcueType->set(static_cast(type)); } -void HotcueControl::setStatus(double status) { - m_hotcueEnabled->set(static_cast(status)); +void HotcueControl::setStatus(Cue::CueStatus status) { + m_hotcueEnabled->forceSet(static_cast(status)); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 344b9a51afc8..f6d94b40d034 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -50,7 +50,7 @@ class HotcueControl : public QObject { void setPosition(double position); void setLength(double length); void setType(Cue::CueType type); - void setStatus(double status); + void setStatus(Cue::CueStatus status); void setColor(PredefinedColorPointer newColor); PredefinedColorPointer getColor() const; From 9773c410e8e1fa6a36fd7c4515b979f8b7ac4e43 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 10:50:20 +0200 Subject: [PATCH 022/153] loopingcontrol: Set diffent cue pointer even if start/end position are equal --- src/engine/controls/loopingcontrol.cpp | 30 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index e77a587fce81..8ce6f30f7cc4 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -545,18 +545,26 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { } LoopSamples loopSamples = m_loopSamples.getValue(); - if (loopSamples.start != startPosition || loopSamples.end != endPosition || loopSamples.seekMode != LoopSeekMode::None) { - loopSamples.start = startPosition; - loopSamples.end = endPosition; - loopSamples.seekMode = LoopSeekMode::None; - clearActiveBeatLoop(); + bool loopSamplesChanged = (loopSamples.start != startPosition || loopSamples.end != endPosition || loopSamples.seekMode != LoopSeekMode::None); + if (m_pCue != pCue || loopSamplesChanged) { + if(loopSamplesChanged) { + loopSamples.start = startPosition; + loopSamples.end = endPosition; + loopSamples.seekMode = LoopSeekMode::None; + clearActiveBeatLoop(); + m_loopSamples.setValue(loopSamples); + m_pCOLoopStartPosition->set(loopSamples.start); + m_pCOLoopEndPosition->set(loopSamples.end); + setLoopingEnabled(true); + } - m_pCue = pCue; - m_loopSamples.setValue(loopSamples); - m_pCOLoopStartPosition->set(loopSamples.start); - m_pCOLoopEndPosition->set(loopSamples.end); - setLoopingEnabled(true); - m_pCue->activate(); + if(m_pCue != pCue) { + if(m_pCue) { + m_pCue->deactivate(); + } + m_pCue = pCue; + m_pCue->activate(); + } } else { bool activate_cue = toggle ? !m_bLoopingEnabled : true; setLoopingEnabled(activate_cue); From 8146080b714db838875731a43f0bf5a8683e85a9 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 11:20:38 +0200 Subject: [PATCH 023/153] cuecontrol: Allow cues to start at position < 0, just require non-negative lengths --- src/engine/controls/cuecontrol.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index ff43a66911ca..48740ffcedc7 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1063,8 +1063,7 @@ void CueControl::hotcueLengthChanged(HotcueControl* pControl, double newLength) pCue->setHotCue(-1); detachCue(pControl->getHotcueNumber()); } else { - double position = pControl->getPosition(); - if (position >= 0 && newLength > 0 && (position + newLength) <= m_pTrackSamples->get()) { + if (newLength >= 0) { pCue->setLength(newLength); } } @@ -2196,7 +2195,7 @@ void HotcueControl::resetCue() { // in the code m_pCue.reset(); setPosition(-1.0); - setLength(-1.0); + setLength(0.0); setType(Cue::CueType::INVALID); setStatus(Cue::CueStatus::DISABLED); } From bdadaff5057c1421b81dc7066975e941191765a6 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 11:22:15 +0200 Subject: [PATCH 024/153] cue: Fix loop length check in Cue::getStatus() --- src/track/cue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 33df9d54c4ab..f2448fce7f65 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -93,7 +93,7 @@ Cue::CueStatus Cue::getStatus() const { CueStatus status = CueStatus::DISABLED; switch(getType()) { case CueType::LOOP: - if (getPosition() != -1 && getPosition() > 0) { + if (getPosition() != -1 && getLength() > 0) { status = CueStatus::ENABLED; } break; From 27d1567facb1e6cf9b387f22648f4d04d1c01f78 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 11:31:24 +0200 Subject: [PATCH 025/153] loopingcontrol: Fix saved loop updates in slotBeatLoop --- src/engine/controls/loopingcontrol.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 8ce6f30f7cc4..7a24e3c3eb04 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -1234,12 +1234,12 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable newloopSamples.seekMode = (keepStartPoint && (enable || m_bLoopingEnabled)) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; m_loopSamples.setValue(newloopSamples); - m_pCOLoopStartPosition->set(newloopSamples.start); - m_pCOLoopEndPosition->set(newloopSamples.end); if(m_pCue) { - m_pCue->setPosition(loopSamples.start); - m_pCue->setLength(loopSamples.end - loopSamples.start); + m_pCue->setPosition(newloopSamples.start); + m_pCue->setLength(newloopSamples.end - newloopSamples.start); } + m_pCOLoopStartPosition->set(newloopSamples.start); + m_pCOLoopEndPosition->set(newloopSamples.end); if (enable) { setLoopingEnabled(true); From 24c8ba1aa0190fae61693d13985c1fce7fadc0ff Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 11:41:42 +0200 Subject: [PATCH 026/153] loopingcontrol: Fix saved loop change detection in setSavedLoop --- src/engine/controls/loopingcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 7a24e3c3eb04..eb7354b8ace8 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -545,7 +545,7 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { } LoopSamples loopSamples = m_loopSamples.getValue(); - bool loopSamplesChanged = (loopSamples.start != startPosition || loopSamples.end != endPosition || loopSamples.seekMode != LoopSeekMode::None); + bool loopSamplesChanged = loopSamples.start != startPosition || loopSamples.end != endPosition; if (m_pCue != pCue || loopSamplesChanged) { if(loopSamplesChanged) { loopSamples.start = startPosition; From c9726517b326e208fc843125e488189ec948b31e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 11:44:40 +0200 Subject: [PATCH 027/153] loopingcontrol: Add saved loop deactivation via slotBeatLoopDeactivate --- src/engine/controls/loopingcontrol.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index eb7354b8ace8..5162164a5390 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -1019,6 +1019,9 @@ void LoopingControl::slotBeatLoopActivateRoll(BeatLoopingControl* pBeatLoopContr void LoopingControl::slotBeatLoopDeactivate(BeatLoopingControl* pBeatLoopControl) { Q_UNUSED(pBeatLoopControl); setLoopingEnabled(false); + if(m_pCue) { + m_pCue->deactivate(); + } } void LoopingControl::slotBeatLoopDeactivateRoll(BeatLoopingControl* pBeatLoopControl) { From 4f16fdbb02049cfd645ae60bc6e614ef11584984 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 12:33:20 +0200 Subject: [PATCH 028/153] loopingcontrol: Improve saved loop activate()/deactivate() logic --- src/engine/controls/loopingcontrol.cpp | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 5162164a5390..88f4a493a293 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -547,7 +547,14 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { LoopSamples loopSamples = m_loopSamples.getValue(); bool loopSamplesChanged = loopSamples.start != startPosition || loopSamples.end != endPosition; if (m_pCue != pCue || loopSamplesChanged) { + if(m_pCue != pCue) { + if(m_pCue) { + m_pCue->deactivate(); + } + m_pCue = pCue; + } if(loopSamplesChanged) { + // Copy saved loop parameters to active loop loopSamples.start = startPosition; loopSamples.end = endPosition; loopSamples.seekMode = LoopSeekMode::None; @@ -556,23 +563,13 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { m_pCOLoopStartPosition->set(loopSamples.start); m_pCOLoopEndPosition->set(loopSamples.end); setLoopingEnabled(true); - } - - if(m_pCue != pCue) { - if(m_pCue) { - m_pCue->deactivate(); - } - m_pCue = pCue; + } else if(m_pCue && m_bLoopingEnabled) { + // Currently active loop became a saved loop, mark it as active m_pCue->activate(); } } else { bool activate_cue = toggle ? !m_bLoopingEnabled : true; setLoopingEnabled(activate_cue); - if(activate_cue) { - m_pCue->activate(); - } else { - m_pCue->deactivate(); - } } } @@ -951,6 +948,13 @@ void LoopingControl::setLoopingEnabled(bool enabled) { pActiveBeatLoop->deactivate(); } } + if (m_pCue) { + if (enabled) { + m_pCue->activate(); + } else { + m_pCue->deactivate(); + } + } } bool LoopingControl::isLoopingEnabled() { @@ -1019,9 +1023,6 @@ void LoopingControl::slotBeatLoopActivateRoll(BeatLoopingControl* pBeatLoopContr void LoopingControl::slotBeatLoopDeactivate(BeatLoopingControl* pBeatLoopControl) { Q_UNUSED(pBeatLoopControl); setLoopingEnabled(false); - if(m_pCue) { - m_pCue->deactivate(); - } } void LoopingControl::slotBeatLoopDeactivateRoll(BeatLoopingControl* pBeatLoopControl) { From 60a5aa713d7f2a07b16f9c485b56f55750217ef0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 3 Sep 2019 15:37:57 +0200 Subject: [PATCH 029/153] cuecontrol: Cast double value to int before casting it to CueType --- src/engine/controls/cuecontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 48740ffcedc7..8f1ddf9afb3c 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1082,7 +1082,7 @@ void CueControl::hotcueTypeChanged(HotcueControl* pControl, double newType) { pCue->setHotCue(-1); detachCue(pControl->getHotcueNumber()); } else { - pCue->setType(static_cast(newType)); + pCue->setType(static_cast(static_cast(newType))); } } } From adbc46c87bfd7fe87b1992d52fefe3a19effe93e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 19 Nov 2019 19:21:06 +0100 Subject: [PATCH 030/153] engine/controls/cuecontrol: Fix some minor style issues --- src/engine/controls/cuecontrol.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index d54256f0ea57..dabc3407a6b5 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -597,12 +597,14 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { double cuePosition; double cueLength; if (m_pLoopEnabled->get()) { + // If a loop is enabled, the hotcue will be saved loop cuePosition = m_pLoopStartPosition->get(); cueLength = m_pLoopEndPosition->get() - cuePosition; - if (cuePosition < 0 || cueLength <= 0) { + if (cuePosition == -1 || cueLength == -1) { return; } } else { + // If no loop is enabled, just store regular jump cue double closestBeat = m_pClosestBeat->get(); cuePosition = (m_pQuantizeEnabled->toBool() && closestBeat != -1) ? @@ -689,8 +691,9 @@ void CueControl::hotcueSetCue(HotcueControl* pControl, double v) { void CueControl::hotcueSetLoop(HotcueControl* pControl, double v) { //qDebug() << "CueControl::hotcueSetLoop" << v; - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) @@ -853,7 +856,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { return; } - CuePointer pCue(pControl->getCue()); + CuePointer pCue = pControl->getCue(); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); From 9bdde82407b1a4bd65e173f8d2fc47efc244131f Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 6 Dec 2019 12:28:18 +0100 Subject: [PATCH 031/153] engine/controls/loopingcontrol: Remove duplicate semicolon --- src/engine/controls/loopingcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index cd167d6e1a19..0b7aa99fc82a 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -543,7 +543,7 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { } DEBUG_ASSERT(pCue->getType() == Cue::Type::Loop); - double startPosition = pCue->getPosition();; + double startPosition = pCue->getPosition(); double endPosition = startPosition + pCue->getLength(); if(startPosition < 0 || startPosition >= endPosition) { if(m_pCue) { From afecf4c6365e26abb497878a5bd56ead2c906b19 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 6 Dec 2019 12:28:51 +0100 Subject: [PATCH 032/153] engine/controls/cuecontrol: Check for maximum cue type --- 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 1c313a90c237..59911ce5466d 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1115,11 +1115,12 @@ void CueControl::hotcueTypeChanged(HotcueControl* pControl, double newType) { CuePointer pCue(pControl->getCue()); if (pCue) { // Setting the type to 0 or -1 is the same as calling hotcue_x_clear - if (newType <= 0) { + int iType = static_cast(newType); + if (iType <= 0 || iType > static_cast(Cue::Type::AudibleSound)) { pCue->setHotCue(-1); detachCue(pControl); } else { - pCue->setType(static_cast(static_cast(newType))); + pCue->setType(static_cast(iType)); } } } From 13ba34709515df1a8bd3f4c1c014cf50993177d3 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 5 Jan 2020 02:05:43 +0100 Subject: [PATCH 033/153] engine/controls/cuecontrol: Use parented_ptr for loop ControlProxies --- src/engine/controls/cuecontrol.cpp | 8 ++++---- src/engine/controls/cuecontrol.h | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 59911ce5466d..6be4f09e850c 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -50,10 +50,10 @@ CueControl::CueControl(QString group, m_pPrevBeat = ControlObject::getControl(ConfigKey(group, "beat_prev")); m_pNextBeat = ControlObject::getControl(ConfigKey(group, "beat_next")); m_pClosestBeat = ControlObject::getControl(ConfigKey(group, "beat_closest")); - m_pLoopStartPosition = new ControlProxy(group, "loop_start_position", this); - m_pLoopEndPosition = new ControlProxy(group, "loop_end_position", this); - m_pLoopEnabled = new ControlProxy(group, "loop_enabled", this); - m_pLoopToggle = new ControlProxy(group, "loop_toggle", this); + m_pLoopStartPosition = make_parented(group, "loop_start_position"); + m_pLoopEndPosition = make_parented(group, "loop_end_position"); + m_pLoopEnabled = make_parented(group, "loop_enabled"); + m_pLoopToggle = make_parented(group, "loop_toggle"); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); m_pCuePoint->set(Cue::kNoPosition); diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 695106208d0f..848a092baa75 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -11,6 +11,7 @@ #include "preferences/usersettings.h" #include "control/controlproxy.h" #include "track/track.h" +#include "util/parented_ptr.h" #define NUM_HOT_CUES 37 @@ -238,10 +239,10 @@ class CueControl : public EngineControl { ControlObject* m_pPrevBeat; ControlObject* m_pNextBeat; ControlObject* m_pClosestBeat; - ControlProxy* m_pLoopStartPosition; - ControlProxy* m_pLoopEndPosition; - ControlProxy* m_pLoopEnabled; - ControlProxy* m_pLoopToggle; + parented_ptr m_pLoopStartPosition; + parented_ptr m_pLoopEndPosition; + parented_ptr m_pLoopEnabled; + parented_ptr m_pLoopToggle; bool m_bypassCueSetByPlay; const int m_iNumHotCues; From 9d3e5f0a889931c1d71372505a6bad4c5d818d5e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 5 Jan 2020 02:31:56 +0100 Subject: [PATCH 034/153] track/cue: Use better member names for Cue::Status enum class --- src/engine/controls/cuecontrol.cpp | 2 +- src/track/cue.cpp | 8 ++++---- src/track/cue.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 6be4f09e850c..17bca554fd54 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2267,7 +2267,7 @@ void HotcueControl::resetCue() { setPosition(Cue::kNoPosition); setLength(0.0); setType(Cue::Type::Invalid); - setStatus(Cue::Status::Disabled); + setStatus(Cue::Status::Invalid); } void HotcueControl::setPosition(double position) { diff --git a/src/track/cue.cpp b/src/track/cue.cpp index 802f26fad324..32330cb4d82a 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -95,21 +95,21 @@ void Cue::setType(Cue::Type type) { } Cue::Status Cue::getStatus() const { - Cue::Status status = Cue::Status::Disabled; + Cue::Status status = Cue::Status::Invalid; switch(getType()) { case Cue::Type::Loop: if (getPosition() != Cue::kNoPosition && getLength() > 0) { - status = Cue::Status::Enabled; + status = Cue::Status::Valid; } break; default: if (getPosition() != Cue::kNoPosition) { - status = Cue::Status::Enabled; + status = Cue::Status::Valid; } break; } - if(status == Cue::Status::Enabled && isActive()) { + if(status == Cue::Status::Valid && isActive()) { status = Cue::Status::Active; } diff --git a/src/track/cue.h b/src/track/cue.h index e59ea4a5a8c7..57b82c5fedcb 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -18,9 +18,9 @@ class Cue : public QObject { public: enum class Status { - Disabled = 0, - Enabled = 1, - Active = 2, + Invalid = 0, + Valid = 1, + Active = 2, }; enum class Type { From f77eb9aef2c8334708f36238e0552a21ff8d97f0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 5 Jan 2020 02:55:04 +0100 Subject: [PATCH 035/153] engine/controls/cuecontrol: Rename reloop control object to gotoandloop --- src/engine/controls/cuecontrol.cpp | 18 +++++++++--------- src/engine/controls/cuecontrol.h | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 17bca554fd54..5e5a69f3d546 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -274,8 +274,8 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueGotoAndStop, this, &CueControl::hotcueGotoAndStop, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueReloop, - this, &CueControl::hotcueReloop, + connect(pControl, &HotcueControl::hotcueGotoAndLoop, + this, &CueControl::hotcueGotoAndLoop, Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueActivate, this, &CueControl::hotcueActivate, @@ -808,7 +808,7 @@ void CueControl::hotcueGotoAndPlay(HotcueControl* pControl, double v) { } } -void CueControl::hotcueReloop(HotcueControl* pControl, double v) { +void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { if (!v) return; @@ -2119,9 +2119,9 @@ HotcueControl::HotcueControl(QString group, int i) this, &HotcueControl::slotHotcueGotoAndStop, Qt::DirectConnection); - m_hotcueReloop = new ControlPushButton(keyForControl(i, "reloop")); - connect(m_hotcueReloop, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcueReloop, + m_hotcueGotoAndLoop = new ControlPushButton(keyForControl(i, "gotoandloop")); + connect(m_hotcueGotoAndLoop, &ControlObject::valueChanged, + this, &HotcueControl::slotHotcueGotoAndLoop, Qt::DirectConnection); m_hotcueActivate = new ControlPushButton(keyForControl(i, "activate")); @@ -2162,7 +2162,7 @@ HotcueControl::~HotcueControl() { delete m_hotcueGoto; delete m_hotcueGotoAndPlay; delete m_hotcueGotoAndStop; - delete m_hotcueReloop; + delete m_hotcueGotoAndLoop; delete m_hotcueActivate; delete m_hotcueActivateCue; delete m_hotcueActivateLoop; @@ -2194,8 +2194,8 @@ void HotcueControl::slotHotcueGotoAndStop(double v) { emit(hotcueGotoAndStop(this, v)); } -void HotcueControl::slotHotcueReloop(double v) { - emit(hotcueReloop(this, v)); +void HotcueControl::slotHotcueGotoAndLoop(double v) { + emit(hotcueGotoAndLoop(this, v)); } void HotcueControl::slotHotcueActivate(double v) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 848a092baa75..a5a28b533c43 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -80,7 +80,7 @@ class HotcueControl : public QObject { void slotHotcueGoto(double v); void slotHotcueGotoAndPlay(double v); void slotHotcueGotoAndStop(double v); - void slotHotcueReloop(double v); + void slotHotcueGotoAndLoop(double v); void slotHotcueActivate(double v); void slotHotcueActivateCue(double v); void slotHotcueActivateLoop(double v); @@ -98,7 +98,7 @@ class HotcueControl : public QObject { void hotcueGoto(HotcueControl* pHotcue, double v); void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); - void hotcueReloop(HotcueControl* pHotcue, double v); + void hotcueGotoAndLoop(HotcueControl* pHotcue, double v); void hotcueActivate(HotcueControl* pHotcue, double v); void hotcueActivateCue(HotcueControl* pHotcue, double v); void hotcueActivateLoop(HotcueControl* pHotcue, double v); @@ -130,7 +130,7 @@ class HotcueControl : public QObject { ControlObject* m_hotcueGoto; ControlObject* m_hotcueGotoAndPlay; ControlObject* m_hotcueGotoAndStop; - ControlObject* m_hotcueReloop; + ControlObject* m_hotcueGotoAndLoop; ControlObject* m_hotcueActivate; ControlObject* m_hotcueActivateCue; ControlObject* m_hotcueActivateLoop; @@ -171,7 +171,7 @@ class CueControl : public EngineControl { void hotcueGoto(HotcueControl* pControl, double v); void hotcueGotoAndPlay(HotcueControl* pControl, double v); void hotcueGotoAndStop(HotcueControl* pControl, double v); - void hotcueReloop(HotcueControl* pControl, double v); + void hotcueGotoAndLoop(HotcueControl* pControl, double v); void hotcueLoopToggle(HotcueControl* pControl, double v); void hotcueActivate(HotcueControl* pControl, double v); void hotcueActivateCue(HotcueControl* pControl, double v); From 5c510ba0ba603abf53bf40b135112be5498fa625 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 5 Jan 2020 03:22:14 +0100 Subject: [PATCH 036/153] engine/controls/cuecontrol: Add support for gotoandloop on non-loop cues --- src/engine/controls/cuecontrol.cpp | 17 +++++++++++++---- src/engine/controls/cuecontrol.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 5e5a69f3d546..1b79a5fc9dcc 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -54,6 +54,7 @@ CueControl::CueControl(QString group, m_pLoopEndPosition = make_parented(group, "loop_end_position"); m_pLoopEnabled = make_parented(group, "loop_enabled"); m_pLoopToggle = make_parented(group, "loop_toggle"); + m_pBeatLoopActivate = make_parented(group, "beatloop_activate"); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); m_pCuePoint->set(Cue::kNoPosition); @@ -831,13 +832,21 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { return; } - double endPosition = startPosition + pCue->getLength(); - if (startPosition >= endPosition) { + if (pCue->getType() == Cue::Type::Loop) { + double endPosition = startPosition + pCue->getLength(); + if (startPosition >= endPosition) { + return; + } + + setSavedLoop(pCue, false); + hotcueGoto(pControl, v); + } else if (pCue->getType() == Cue::Type::HotCue) { + hotcueGoto(pControl, v); + m_pBeatLoopActivate->set(1); + } else { return; } - setSavedLoop(pCue, false); - hotcueGoto(pControl, v); if (!isPlayingByPlayButton()) { // cueGoto is processed asynchrony. diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index a5a28b533c43..debf0cba8ae7 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -243,6 +243,7 @@ class CueControl : public EngineControl { parented_ptr m_pLoopEndPosition; parented_ptr m_pLoopEnabled; parented_ptr m_pLoopToggle; + parented_ptr m_pBeatLoopActivate; bool m_bypassCueSetByPlay; const int m_iNumHotCues; From b7bdb0d0ee38904623154a6fb5e5649def386b51 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 5 Jan 2020 11:32:09 +0100 Subject: [PATCH 037/153] engine/controls/loopingcontrol: Remove setSavedLoop toggle flag --- src/engine/controls/cuecontrol.cpp | 12 ++++++++---- src/engine/controls/enginecontrol.cpp | 5 +++-- src/engine/controls/enginecontrol.h | 2 +- src/engine/controls/loopingcontrol.cpp | 16 ++++++++++------ src/engine/controls/loopingcontrol.h | 2 +- src/engine/enginebuffer.cpp | 4 ++-- src/engine/enginebuffer.h | 2 +- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 541acbc24692..dc5313538a3a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -627,7 +627,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { }; if (cueType == Cue::Type::Loop) { - setSavedLoop(pCue, false); + setSavedLoop(pCue); } // If quantize is enabled and we are not playing, jump to the cue point @@ -722,7 +722,7 @@ void CueControl::hotcueSetLoop(HotcueControl* pControl, double v) { pCue->setColor(predefinedColors.at((hotcue % (predefinedColors.count() - 1)) + 1)); }; - setSavedLoop(pCue, false); + setSavedLoop(pCue); } void CueControl::hotcueGoto(HotcueControl* pControl, double v) { @@ -829,7 +829,7 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { return; } - setSavedLoop(pCue, false); + setSavedLoop(pCue); hotcueGoto(pControl, v); } else if (pCue->getType() == Cue::Type::HotCue) { hotcueGoto(pControl, v); @@ -868,7 +868,11 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { return; } - setSavedLoop(pCue, true); + bool loopAlreadyActive = setSavedLoop(pCue); + if (loopAlreadyActive) { + // Loop is already set and active, disable it + m_pLoopToggle->set(1); + } } void CueControl::hotcueActivate(HotcueControl* pControl, double v) { diff --git a/src/engine/controls/enginecontrol.cpp b/src/engine/controls/enginecontrol.cpp index b19ee98b5127..751314a948fc 100644 --- a/src/engine/controls/enginecontrol.cpp +++ b/src/engine/controls/enginecontrol.cpp @@ -67,10 +67,11 @@ EngineBuffer* EngineControl::getEngineBuffer() { return m_pEngineBuffer; } -void EngineControl::setSavedLoop(CuePointer pCue, bool toggle) { +bool EngineControl::setSavedLoop(CuePointer pCue) { if (m_pEngineBuffer) { - m_pEngineBuffer->setSavedLoop(pCue, toggle); + return m_pEngineBuffer->setSavedLoop(pCue); } + return false; } void EngineControl::seekAbs(double samplePosition) { diff --git a/src/engine/controls/enginecontrol.h b/src/engine/controls/enginecontrol.h index f3208b37a864..270332670d98 100644 --- a/src/engine/controls/enginecontrol.h +++ b/src/engine/controls/enginecontrol.h @@ -59,7 +59,7 @@ class EngineControl : public QObject { const double dTotalSamples, const double dTrackSampleRate); QString getGroup() const; - void setSavedLoop(CuePointer pCue, bool toggle); + bool setSavedLoop(CuePointer pCue); // Called to collect player features for effects processing. virtual void collectFeatureState(GroupFeatureState* pGroupFeatures) const { diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 0b7aa99fc82a..b94b5e9a9ed1 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -530,16 +530,17 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl return dSyncedPlayPos; } -void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { - qDebug() << "setSavedLoop" << toggle; +bool LoopingControl::setSavedLoop(CuePointer pCue) { + qDebug() << "setSavedLoop"; + bool loopAlreadyActive = false; if(!pCue) { if(m_pCue) { m_pCue->deactivate(); m_pCue.reset(); } clearActiveBeatLoop(); - return; + return loopAlreadyActive; } DEBUG_ASSERT(pCue->getType() == Cue::Type::Loop); @@ -551,7 +552,7 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { m_pCue.reset(); } clearActiveBeatLoop(); - return; + return loopAlreadyActive; } LoopSamples loopSamples = m_loopSamples.getValue(); @@ -577,10 +578,13 @@ void LoopingControl::setSavedLoop(CuePointer pCue, bool toggle) { // Currently active loop became a saved loop, mark it as active m_pCue->activate(); } + } else if (!m_bLoopingEnabled) { + setLoopingEnabled(true); } else { - bool activate_cue = toggle ? !m_bLoopingEnabled : true; - setLoopingEnabled(activate_cue); + loopAlreadyActive = true; } + + return loopAlreadyActive; } void LoopingControl::setLoopInToCurrentPosition() { diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index e3823cd47411..127d102f25ac 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -52,7 +52,7 @@ class LoopingControl : public EngineControl { void notifySeek(double dNewPlaypos) override; - void setSavedLoop(CuePointer pCue, bool toggle); + bool setSavedLoop(CuePointer pCue); void setRateControl(RateControl* rateControl); bool isLoopingEnabled(); diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 595e21939ff3..165fc92db10e 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -356,8 +356,8 @@ double EngineBuffer::getLocalBpm() { return m_pBpmControl->getLocalBpm(); } -void EngineBuffer::setSavedLoop(CuePointer pCue, bool toggle) { - m_pLoopingControl->setSavedLoop(pCue, toggle); +bool EngineBuffer::setSavedLoop(CuePointer pCue) { + return m_pLoopingControl->setSavedLoop(pCue); } void EngineBuffer::setEngineMaster(EngineMaster* pEngineMaster) { diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 3bf7ba481cfd..2ea7e94095e2 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -125,7 +125,7 @@ class EngineBuffer : public EngineObject { // Returns the BPM of the loaded track around the current position (not thread-safe) double getLocalBpm(); // Sets a loop for the loaded track (not thread safe) - void setSavedLoop(CuePointer, bool); + bool setSavedLoop(CuePointer); // Sets pointer to other engine buffer/channel void setEngineMaster(EngineMaster*); From 0786225fca907bccdde5a9bcbc1381dfedc28d2c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 5 Jan 2020 11:46:44 +0100 Subject: [PATCH 038/153] res/skins: Fix disappearing hotcues on saved loop activation --- res/skins/Deere/hotcue_button.xml | 8 +++++++- res/skins/LateNight/button_hotcue.xml | 7 ++++++- res/skins/Shade/deck_hotcue_button.xml | 7 ++++++- res/skins/Tango/button_hotcue_deck.xml | 7 ++++++- res/skins/Tango/button_hotcue_sam_pre.xml | 7 ++++++- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/res/skins/Deere/hotcue_button.xml b/res/skins/Deere/hotcue_button.xml index f5e477762261..2c27cf3dbac4 100644 --- a/res/skins/Deere/hotcue_button.xml +++ b/res/skins/Deere/hotcue_button.xml @@ -14,7 +14,7 @@ - 2 + 3 @@ -29,6 +29,12 @@ + + 2 + + + + ,hotcue__activate true diff --git a/res/skins/LateNight/button_hotcue.xml b/res/skins/LateNight/button_hotcue.xml index 647656855040..36ee9272744f 100644 --- a/res/skins/LateNight/button_hotcue.xml +++ b/res/skins/LateNight/button_hotcue.xml @@ -13,7 +13,7 @@ 26,26 26,26 me,f - 2 + 3 0 skin:/buttons_/btn__square.svg @@ -24,6 +24,11 @@ skin:/buttons_/btn__square_set.svg skin:/buttons_/btn__square_active.svg + + 2 + skin:/buttons_/btn__square_set.svg + skin:/buttons_/btn__square_active.svg + ,hotcue__activate LeftButton diff --git a/res/skins/Shade/deck_hotcue_button.xml b/res/skins/Shade/deck_hotcue_button.xml index 69c10a0fac1b..f8be7f211e3a 100644 --- a/res/skins/Shade/deck_hotcue_button.xml +++ b/res/skins/Shade/deck_hotcue_button.xml @@ -3,7 +3,7 @@ hotcue HotcueButton - 2 + 3 true true @@ -16,6 +16,11 @@ skin:/btn/btn_hotcue__overdown.png skin:/btn/btn_hotcue__over.png + + 2 + skin:/btn/btn_hotcue__overdown.png + skin:/btn/btn_hotcue__over.png + [Channel],hotcue__activate true diff --git a/res/skins/Tango/button_hotcue_deck.xml b/res/skins/Tango/button_hotcue_deck.xml index bb1009dbf424..32dbc5d86a9d 100644 --- a/res/skins/Tango/button_hotcue_deck.xml +++ b/res/skins/Tango/button_hotcue_deck.xml @@ -14,7 +14,7 @@ Variables: 15,24 23,24 me,f - 2 + 3 0 @@ -25,6 +25,11 @@ Variables: center + + 2 + + center + ,hotcue__activate LeftButton diff --git a/res/skins/Tango/button_hotcue_sam_pre.xml b/res/skins/Tango/button_hotcue_sam_pre.xml index 5f13a2166286..0c89fccdbcee 100644 --- a/res/skins/Tango/button_hotcue_sam_pre.xml +++ b/res/skins/Tango/button_hotcue_sam_pre.xml @@ -15,7 +15,7 @@ Variables: 14,18 20,18 me,f - 2 + 3 0 @@ -26,6 +26,11 @@ Variables: center + + 2 + + center + ,hotcue__activate LeftButton From c237c381ecda74984f24201f267014189fb2bdde Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 12 May 2020 10:32:27 +0200 Subject: [PATCH 039/153] engine/controls/cuecontrol: Reduce code duplication --- src/engine/controls/cuecontrol.cpp | 263 +++++------------------------ src/engine/controls/cuecontrol.h | 25 +-- 2 files changed, 53 insertions(+), 235 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 83ca350acae3..3bd3fff39c65 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -297,12 +297,6 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueSet, this, &CueControl::hotcueSet, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueSetCue, - this, &CueControl::hotcueSetCue, - Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueSetLoop, - this, &CueControl::hotcueSetLoop, - Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueGoto, this, &CueControl::hotcueGoto, Qt::DirectConnection); @@ -318,12 +312,6 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueActivate, this, &CueControl::hotcueActivate, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueActivateCue, - this, &CueControl::hotcueActivateCue, - Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueActivateLoop, - this, &CueControl::hotcueActivateLoop, - Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueActivatePreview, this, &CueControl::hotcueActivatePreview, Qt::DirectConnection); @@ -660,7 +648,7 @@ void CueControl::quantizeChanged(double v) { } } -void CueControl::hotcueSet(HotcueControl* pControl, double v) { +void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { //qDebug() << "CueControl::hotcueSet" << v; if (!v) @@ -682,8 +670,34 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { double cueStartPosition; double cueEndPosition; mixxx::CueType cueType; - if (m_pLoopEnabled->get()) { - // If a loop is enabled, the hotcue will be saved loop + switch (mode) { + case HotcueMode::Auto: { + if (m_pLoopEnabled->get()) { + // If a loop is enabled, the hotcue will be a saved loop + cueStartPosition = m_pLoopStartPosition->get(); + cueEndPosition = m_pLoopEndPosition->get(); + if (cueStartPosition == Cue::kNoPosition || + cueEndPosition == Cue::kNoPosition) { + return; + } + cueType = mixxx::CueType::Loop; + } else { + // If no loop is enabled, just store regular jump cue + cueStartPosition = getQuantizedCurrentPosition(); + cueEndPosition = Cue::kNoPosition; + cueType = mixxx::CueType::HotCue; + } + break; + } + case HotcueMode::Cue: { + // If no loop is enabled, just store regular jump cue + cueStartPosition = getQuantizedCurrentPosition(); + cueEndPosition = Cue::kNoPosition; + cueType = mixxx::CueType::HotCue; + break; + } + case HotcueMode::Loop: { + // If no loop is enabled, just store regular jump cue cueStartPosition = m_pLoopStartPosition->get(); cueEndPosition = m_pLoopEndPosition->get(); if (cueStartPosition == Cue::kNoPosition || @@ -691,13 +705,9 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { return; } cueType = mixxx::CueType::Loop; - } else { - // If no loop is enabled, just store regular jump cue - cueStartPosition = getQuantizedCurrentPosition(); - cueEndPosition = Cue::kNoPosition; - cueType = mixxx::CueType::HotCue; + break; + } } - pCue->setStartPosition(cueStartPosition); pCue->setEndPosition(cueEndPosition); pCue->setHotCue(hotcue); @@ -730,105 +740,6 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v) { } } -void CueControl::hotcueSetCue(HotcueControl* pControl, double v) { - //qDebug() << "CueControl::hotcueSetCue" << v; - - if (!v) - return; - - QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) - return; - - int hotcue = pControl->getHotcueNumber(); - // Note: the cue is just detached from the hotcue control - // It remains in the database for later use - // TODO: find a rule, that allows us to delete the cue as well - // https://bugs.launchpad.net/mixxx/+bug/1653276 - hotcueClear(pControl, v); - - CuePointer pCue(m_pLoadedTrack->createAndAddCue()); - double cueStartPosition = getQuantizedCurrentPosition(); - pCue->setStartPosition(cueStartPosition); - pCue->setEndPosition(Cue::kNoPosition); - pCue->setHotCue(hotcue); - pCue->setLabel(); - pCue->setType(mixxx::CueType::HotCue); - - const ColorPalette hotcueColorPalette = - m_colorPaletteSettings.getHotcueColorPalette(); - if (getConfig()->getValue( - ConfigKey("[Controls]", "auto_hotcue_colors"), false)) { - pCue->setColor(hotcueColorPalette.colorForHotcueIndex(hotcue)); - } else { - int hotcueDefaultColorIndex = m_pConfig->getValue( - ConfigKey("[Controls]", "HotcueDefaultColorIndex"), -1); - if (hotcueDefaultColorIndex < 0 || - hotcueDefaultColorIndex >= hotcueColorPalette.size()) { - hotcueDefaultColorIndex = hotcueColorPalette.size() - - 1; // default to last color (orange) - } - pCue->setColor(hotcueColorPalette.at(hotcueDefaultColorIndex)); - } - - // TODO(XXX) deal with spurious signals - attachCue(pCue, pControl); - - // If quantize is enabled and we are not playing, jump to the cue point - // since it's not necessarily where we currently are. TODO(XXX) is this - // potentially invalid for vinyl control? - bool playing = m_pPlay->toBool(); - if (!playing && m_pQuantizeEnabled->toBool()) { - lock.unlock(); // prevent deadlock. - // Enginebuffer will quantize more exactly than we can. - seekAbs(cueStartPosition); - } -} - -void CueControl::hotcueSetLoop(HotcueControl* pControl, double v) { - //qDebug() << "CueControl::hotcueSetLoop" << v; - - if (!v) { - return; - } - - QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) - return; - - int hotcue = pControl->getHotcueNumber(); - // Note: the cue is just detached from the hotcue control - // It remains in the database for later use - // TODO: find a rule, that allows us to delete the cue as well - // https://bugs.launchpad.net/mixxx/+bug/1653276 - hotcueClear(pControl, v); - - CuePointer pCue(m_pLoadedTrack->createAndAddCue()); - double cueStartPosition = m_pLoopStartPosition->get(); - double cueEndPosition = m_pLoopEndPosition->get(); - if (cueStartPosition == Cue::kNoPosition || cueEndPosition == Cue::kNoPosition) { - return; - } - - pCue->setStartPosition(cueStartPosition); - pCue->setEndPosition(cueEndPosition); - pCue->setHotCue(hotcue); - pCue->setLabel(""); - pCue->setType(mixxx::CueType::Loop); - // TODO(XXX) deal with spurious signals - attachCue(pCue, pControl); - - ConfigKey autoHotcueColorsKey("[Controls]", "auto_hotcue_colors"); - if (getConfig()->getValue(autoHotcueColorsKey, false)) { - auto hotcueColorPalette = m_colorPaletteSettings.getHotcueColorPalette(); - pCue->setColor(hotcueColorPalette.colorForHotcueIndex(hotcue)); - } else { - pCue->setColor(mixxx::PredefinedColorPalettes::kDefaultCueColor); - } - - setSavedLoop(pCue); -} - void CueControl::hotcueGoto(HotcueControl* pControl, double v) { if (!v) return; @@ -978,7 +889,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { } } -void CueControl::hotcueActivate(HotcueControl* pControl, double v) { +void CueControl::hotcueActivate(HotcueControl* pControl, double v, HotcueMode mode) { //qDebug() << "CueControl::hotcueActivate" << v; QMutexLocker lock(&m_mutex); @@ -994,7 +905,7 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { if (pCue) { if (v) { if (pCue->getPosition() == Cue::kNoPosition) { - hotcueSet(pControl, v); + hotcueSet(pControl, v, mode); } else { if (isPlayingByPlayButton()) { if (pCue->getLength() > 0) { @@ -1015,7 +926,7 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { // The cue is non-existent ... if (v) { // set it to the current position - hotcueSet(pControl, v); + hotcueSet(pControl, v, mode); } else if (m_iCurrentlyPreviewingHotcues) { // yet we got a release for it and are // currently previewing a hotcue. This is indicative of a corner @@ -1028,100 +939,6 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v) { m_pHotcueFocus->set(pControl->getHotcueNumber()); } -void CueControl::hotcueActivateCue(HotcueControl* pControl, double v) { - //qDebug() << "CueControl::hotcueActivateCue" << v; - - QMutexLocker lock(&m_mutex); - - if (!m_pLoadedTrack) { - return; - } - - CuePointer pCue(pControl->getCue()); - - lock.unlock(); - - if (pCue) { - if (v) { - if (pCue->getPosition() == Cue::kNoPosition) { - hotcueSetCue(pControl, v); - } else { - if (isPlayingByPlayButton()) { - if (pCue->getLength() > 0) { - hotcueLoopToggle(pControl, v); - } else { - hotcueGoto(pControl, v); - } - } else { - hotcueActivatePreview(pControl, v); - } - } - } else { - if (pCue->getPosition() != Cue::kNoPosition) { - hotcueActivatePreview(pControl, v); - } - } - } else { - if (v) { - // just in case - hotcueSetCue(pControl, v); - } else if (m_iCurrentlyPreviewingHotcues) { - // The cue is non-existent, yet we got a release for it and are - // currently previewing a hotcue. This is indicative of a corner - // case where the cue was detached while we were pressing it. Let - // hotcueActivatePreview handle it. - hotcueActivatePreview(pControl, v); - } - } -} - -void CueControl::hotcueActivateLoop(HotcueControl* pControl, double v) { - //qDebug() << "CueControl::hotcueActivate" << v; - - QMutexLocker lock(&m_mutex); - - if (!m_pLoadedTrack) { - return; - } - - CuePointer pCue(pControl->getCue()); - - lock.unlock(); - - if (pCue) { - if (v) { - if (pCue->getPosition() == Cue::kNoPosition) { - hotcueSetLoop(pControl, v); - } else { - if (isPlayingByPlayButton()) { - if (pCue->getLength() > 0) { - hotcueLoopToggle(pControl, v); - } else { - hotcueGoto(pControl, v); - } - } else { - hotcueActivatePreview(pControl, v); - } - } - } else { - if (pCue->getPosition() != Cue::kNoPosition) { - hotcueActivatePreview(pControl, v); - } - } - } else { - if (v) { - // just in case - hotcueSetLoop(pControl, v); - } else if (m_iCurrentlyPreviewingHotcues) { - // The cue is non-existent, yet we got a release for it and are - // currently previewing a hotcue. This is indicative of a corner - // case where the cue was detached while we were pressing it. Let - // hotcueActivatePreview handle it. - hotcueActivatePreview(pControl, v); - } - } -} - void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { @@ -2279,15 +2096,15 @@ HotcueControl::~HotcueControl() { } void HotcueControl::slotHotcueSet(double v) { - emit hotcueSet(this, v); + emit hotcueSet(this, v, HotcueMode::Auto); } void HotcueControl::slotHotcueSetCue(double v) { - emit(hotcueSetCue(this, v)); + emit(hotcueSet(this, v, HotcueMode::Cue)); } void HotcueControl::slotHotcueSetLoop(double v) { - emit(hotcueSetLoop(this, v)); + emit(hotcueSet(this, v, HotcueMode::Loop)); } void HotcueControl::slotHotcueGoto(double v) { @@ -2307,15 +2124,15 @@ void HotcueControl::slotHotcueGotoAndLoop(double v) { } void HotcueControl::slotHotcueActivate(double v) { - emit hotcueActivate(this, v); + emit hotcueActivate(this, v, HotcueMode::Auto); } void HotcueControl::slotHotcueActivateCue(double v) { - emit(hotcueActivateCue(this, v)); + emit(hotcueActivate(this, v, HotcueMode::Cue)); } void HotcueControl::slotHotcueActivateLoop(double v) { - emit(hotcueActivateLoop(this, v)); + emit(hotcueActivate(this, v, HotcueMode::Loop)); } void HotcueControl::slotHotcueActivatePreview(double v) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index adbdbbb11a5b..9bbed93e7354 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -36,6 +36,15 @@ enum class SeekOnLoadMode { IntroStart = 3, // Use intro start cue point }; +/// Used for requesting a specific hotcue type when activating/setting a +/// hotcue. Auto will make CueControl determine the type automatically (i.e. +/// create a loop cue if a loop is set, and a regular cue in all other cases). +enum class HotcueMode { + Auto = 0, + Cue = 1, + Loop = 2, +}; + inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { return static_cast(int(value)); } @@ -93,16 +102,12 @@ class HotcueControl : public QObject { void slotHotcueColorChanged(double newColor); signals: - void hotcueSet(HotcueControl* pHotcue, double v); - void hotcueSetCue(HotcueControl* pHotcue, double v); - void hotcueSetLoop(HotcueControl* pHotcue, double v); + void hotcueSet(HotcueControl* pHotcue, double v, HotcueMode mode); void hotcueGoto(HotcueControl* pHotcue, double v); void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); void hotcueGotoAndLoop(HotcueControl* pHotcue, double v); - void hotcueActivate(HotcueControl* pHotcue, double v); - void hotcueActivateCue(HotcueControl* pHotcue, double v); - void hotcueActivateLoop(HotcueControl* pHotcue, double v); + void hotcueActivate(HotcueControl* pHotcue, double v, HotcueMode mode); void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); void hotcuePositionChanged(HotcueControl* pHotcue, double newPosition); @@ -166,17 +171,13 @@ class CueControl : public EngineControl { void cueUpdated(); void trackAnalyzed(); void trackCuesUpdated(); - void hotcueSet(HotcueControl* pControl, double v); - void hotcueSetCue(HotcueControl* pControl, double v); - void hotcueSetLoop(HotcueControl* pControl, double v); + void hotcueSet(HotcueControl* pControl, double v, HotcueMode mode); void hotcueGoto(HotcueControl* pControl, double v); void hotcueGotoAndPlay(HotcueControl* pControl, double v); void hotcueGotoAndStop(HotcueControl* pControl, double v); void hotcueGotoAndLoop(HotcueControl* pControl, double v); void hotcueLoopToggle(HotcueControl* pControl, double v); - void hotcueActivate(HotcueControl* pControl, double v); - void hotcueActivateCue(HotcueControl* pControl, double v); - void hotcueActivateLoop(HotcueControl* pControl, double v); + void hotcueActivate(HotcueControl* pControl, double v, HotcueMode mode); void hotcueActivatePreview(HotcueControl* pControl, double v); void hotcueClear(HotcueControl* pControl, double v); void hotcuePositionChanged(HotcueControl* pControl, double newPosition); From b64cbf67fe2b09cec6ea6345d0e78667734fe9ba Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 12 May 2020 10:45:50 +0200 Subject: [PATCH 040/153] engine/controls/cuecontrol: Clean up hotcueSet code a bit --- src/engine/controls/cuecontrol.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 3bd3fff39c65..748294c3c0c2 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -667,19 +667,16 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { CuePointer pCue(m_pLoadedTrack->createAndAddCue()); - double cueStartPosition; - double cueEndPosition; - mixxx::CueType cueType; + double cueStartPosition = Cue::kNoPosition; + double cueEndPosition = Cue::kNoPosition; + mixxx::CueType cueType = mixxx::CueType::Invalid; + switch (mode) { case HotcueMode::Auto: { if (m_pLoopEnabled->get()) { // If a loop is enabled, the hotcue will be a saved loop cueStartPosition = m_pLoopStartPosition->get(); cueEndPosition = m_pLoopEndPosition->get(); - if (cueStartPosition == Cue::kNoPosition || - cueEndPosition == Cue::kNoPosition) { - return; - } cueType = mixxx::CueType::Loop; } else { // If no loop is enabled, just store regular jump cue @@ -700,14 +697,22 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { // If no loop is enabled, just store regular jump cue cueStartPosition = m_pLoopStartPosition->get(); cueEndPosition = m_pLoopEndPosition->get(); - if (cueStartPosition == Cue::kNoPosition || - cueEndPosition == Cue::kNoPosition) { - return; - } cueType = mixxx::CueType::Loop; break; } } + + VERIFY_OR_DEBUG_ASSERT(cueType != mixxx::CueType::Invalid) { + return; + } + + // Abort if no position has been found. This can happen if a loop cue is + // requested while no loop is set, so we can't debug assert here. + if (cueStartPosition == Cue::kNoPosition || + (cueType == mixxx::CueType::Loop && cueEndPosition == Cue::kNoPosition)) { + return; + } + pCue->setStartPosition(cueStartPosition); pCue->setEndPosition(cueEndPosition); pCue->setHotCue(hotcue); From 94d84939c815bf078d5bb312c1c78e2c73c960df Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 12 May 2020 11:02:23 +0200 Subject: [PATCH 041/153] engine/controls/cuecontrol: Fix initialization of parented_ptr --- src/engine/controls/cuecontrol.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 748294c3c0c2..0a5e35e83ba7 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -67,11 +67,11 @@ CueControl::CueControl(QString group, Qt::DirectConnection); m_pClosestBeat = ControlObject::getControl(ConfigKey(group, "beat_closest")); - m_pLoopStartPosition = make_parented(group, "loop_start_position"); - m_pLoopEndPosition = make_parented(group, "loop_end_position"); - m_pLoopEnabled = make_parented(group, "loop_enabled"); - m_pLoopToggle = make_parented(group, "loop_toggle"); - m_pBeatLoopActivate = make_parented(group, "beatloop_activate"); + m_pLoopStartPosition = make_parented(group, "loop_start_position", this); + m_pLoopEndPosition = make_parented(group, "loop_end_position", this); + m_pLoopEnabled = make_parented(group, "loop_enabled", this); + m_pLoopToggle = make_parented(group, "loop_toggle", this); + m_pBeatLoopActivate = make_parented(group, "beatloop_activate", this); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); m_pCuePoint->set(Cue::kNoPosition); From 27c5f37865bc6dfc8116e21b5719a90cb2dc1600 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 19 Jun 2020 12:17:50 +0200 Subject: [PATCH 042/153] engine/controls/cuecontrol: Fix Qt signal emit keyword --- src/engine/controls/cuecontrol.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 0a5e35e83ba7..a47b23be83fd 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2105,11 +2105,11 @@ void HotcueControl::slotHotcueSet(double v) { } void HotcueControl::slotHotcueSetCue(double v) { - emit(hotcueSet(this, v, HotcueMode::Cue)); + emit hotcueSet(this, v, HotcueMode::Cue); } void HotcueControl::slotHotcueSetLoop(double v) { - emit(hotcueSet(this, v, HotcueMode::Loop)); + emit hotcueSet(this, v, HotcueMode::Loop); } void HotcueControl::slotHotcueGoto(double v) { @@ -2125,7 +2125,7 @@ void HotcueControl::slotHotcueGotoAndStop(double v) { } void HotcueControl::slotHotcueGotoAndLoop(double v) { - emit(hotcueGotoAndLoop(this, v)); + emit hotcueGotoAndLoop(this, v); } void HotcueControl::slotHotcueActivate(double v) { @@ -2133,11 +2133,11 @@ void HotcueControl::slotHotcueActivate(double v) { } void HotcueControl::slotHotcueActivateCue(double v) { - emit(hotcueActivate(this, v, HotcueMode::Cue)); + emit hotcueActivate(this, v, HotcueMode::Cue); } void HotcueControl::slotHotcueActivateLoop(double v) { - emit(hotcueActivate(this, v, HotcueMode::Loop)); + emit hotcueActivate(this, v, HotcueMode::Loop); } void HotcueControl::slotHotcueActivatePreview(double v) { @@ -2154,11 +2154,11 @@ void HotcueControl::slotHotcuePositionChanged(double newPosition) { } void HotcueControl::slotHotcueLengthChanged(double newLength) { - emit(hotcueLengthChanged(this, newLength)); + emit hotcueLengthChanged(this, newLength); } void HotcueControl::slotHotcueTypeChanged(double newType) { - emit(hotcueTypeChanged(this, newType)); + emit hotcueTypeChanged(this, newType); } void HotcueControl::slotHotcueColorChangeRequest(double color) { From 34efdc30fbb65c11660de0274cddf87f1ff741eb Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 19 Jun 2020 12:43:41 +0200 Subject: [PATCH 043/153] engine/controls/cuecontrol: Fix order in hotcueGotoAndLoop call This fixes an issue where the loop might get disabled after the jump. --- src/engine/controls/cuecontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index a47b23be83fd..30d49ff8f095 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -849,8 +849,8 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { return; } - setSavedLoop(pCue); hotcueGoto(pControl, v); + setSavedLoop(pCue); } else if (pCue->getType() == mixxx::CueType::HotCue) { hotcueGoto(pControl, v); m_pBeatLoopActivate->set(1); From fd5dac64c063d565758cc3681f9989a1a73e88c7 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 19 Jun 2020 17:33:48 +0200 Subject: [PATCH 044/153] engine: Move saved loop cue tracking from LoopingControl into CueControl --- src/engine/controls/cuecontrol.cpp | 75 +++++++++++++++++--- src/engine/controls/cuecontrol.h | 7 ++ src/engine/controls/enginecontrol.cpp | 5 +- src/engine/controls/enginecontrol.h | 2 +- src/engine/controls/loopingcontrol.cpp | 95 ++++++-------------------- src/engine/controls/loopingcontrol.h | 7 +- src/engine/enginebuffer.cpp | 20 +++++- src/engine/enginebuffer.h | 2 +- 8 files changed, 121 insertions(+), 92 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 30d49ff8f095..49ed96f0aa83 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -731,7 +731,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { } if (cueType == mixxx::CueType::Loop) { - setSavedLoop(pCue); + setCurrentSavedLoop(pCue); } // If quantize is enabled and we are not playing, jump to the cue point @@ -844,14 +844,10 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { } if (pCue->getType() == mixxx::CueType::Loop) { - double endPosition = startPosition + pCue->getLength(); - if (startPosition >= endPosition) { - return; - } - hotcueGoto(pControl, v); - setSavedLoop(pCue); + setCurrentSavedLoop(pCue); } else if (pCue->getType() == mixxx::CueType::HotCue) { + setCurrentSavedLoop(CuePointer()); hotcueGoto(pControl, v); m_pBeatLoopActivate->set(1); } else { @@ -887,10 +883,12 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { return; } - bool loopAlreadyActive = setSavedLoop(pCue); - if (loopAlreadyActive) { - // Loop is already set and active, disable it - m_pLoopToggle->set(1); + bool enabled; + if (m_pCurrentSavedLoop != pCue) { + setCurrentSavedLoop(pCue); + } else { + enabled = !pCue->isActive(); + setLoop(pCue->getPosition(), pCue->getEndPosition(), enabled); } } @@ -1971,6 +1969,61 @@ void CueControl::hotcueFocusColorNext(double v) { pCue->setColor(colorPalette.nextColor(*color)); } +void CueControl::setCurrentSavedLoop(CuePointer pCue) { + if (m_pCurrentSavedLoop != pCue) { + if (m_pCurrentSavedLoop) { + m_pCurrentSavedLoop->deactivate(); + } + + if (!pCue) { + m_pCurrentSavedLoop.reset(); + return; + } + + VERIFY_OR_DEBUG_ASSERT(pCue->getType() == mixxx::CueType::Loop && + pCue->getEndPosition() != Cue::kNoPosition) { + return; + } + + m_pCurrentSavedLoop = pCue; + } + + if (m_pCurrentSavedLoop) { + qDebug() << "CueControl::setLoop" << pCue->getPosition() << pCue->getEndPosition() << true; + setLoop(pCue->getPosition(), pCue->getEndPosition(), true); + pCue->activate(); + } +} + +void CueControl::slotLoopReset() { + setCurrentSavedLoop(CuePointer()); +} + +void CueControl::slotLoopToggled(bool enabled) { + if (!m_pCurrentSavedLoop) { + return; + } + + if (enabled) { + m_pCurrentSavedLoop->activate(); + } else { + m_pCurrentSavedLoop->deactivate(); + } +} + +void CueControl::slotLoopUpdated(double startPosition, double endPosition) { + if (!m_pCurrentSavedLoop) { + return; + } + + DEBUG_ASSERT(startPosition != Cue::kNoPosition); + DEBUG_ASSERT(endPosition != Cue::kNoPosition); + DEBUG_ASSERT(startPosition > endPosition); + + m_pCurrentSavedLoop->setStartPosition(startPosition); + m_pCurrentSavedLoop->setEndPosition(endPosition); +} + ConfigKey HotcueControl::keyForControl(int hotcue, const char* name) { ConfigKey key; key.group = m_group; diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index c8042dd7abdd..eea11b87e9ad 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -165,6 +165,11 @@ class CueControl : public EngineControl { void trackLoaded(TrackPointer pNewTrack) override; void trackBeatsUpdated(mixxx::BeatsPointer pBeats) override; + public slots: + void slotLoopReset(); + void slotLoopToggled(bool enabled); + void slotLoopUpdated(double startPosition, double endPosition); + private slots: void quantizeChanged(double v); @@ -224,6 +229,7 @@ class CueControl : public EngineControl { void createControls(); void attachCue(CuePointer pCue, HotcueControl* pControl); void detachCue(HotcueControl* pControl); + void setCurrentSavedLoop(CuePointer pCue); void loadCuesFromTrack(); double quantizeCuePoint(double position); double getQuantizedCurrentPosition(); @@ -295,6 +301,7 @@ class CueControl : public EngineControl { ControlObject* m_pHotcueFocusColorPrev; TrackPointer m_pLoadedTrack; // is written from an engine worker thread + CuePointer m_pCurrentSavedLoop; // Tells us which controls map to which hotcue QMap m_controlMap; diff --git a/src/engine/controls/enginecontrol.cpp b/src/engine/controls/enginecontrol.cpp index 8db85584cd23..c7bdcbddea7f 100644 --- a/src/engine/controls/enginecontrol.cpp +++ b/src/engine/controls/enginecontrol.cpp @@ -71,11 +71,10 @@ EngineBuffer* EngineControl::getEngineBuffer() { return m_pEngineBuffer; } -bool EngineControl::setSavedLoop(CuePointer pCue) { +void EngineControl::setLoop(double startPosition, double endPosition, bool enabled) { if (m_pEngineBuffer) { - return m_pEngineBuffer->setSavedLoop(pCue); + return m_pEngineBuffer->setLoop(startPosition, endPosition, enabled); } - return false; } void EngineControl::seekAbs(double samplePosition) { diff --git a/src/engine/controls/enginecontrol.h b/src/engine/controls/enginecontrol.h index d329cde79b84..9b4d10d286e1 100644 --- a/src/engine/controls/enginecontrol.h +++ b/src/engine/controls/enginecontrol.h @@ -60,7 +60,7 @@ class EngineControl : public QObject { const double dTotalSamples, const double dTrackSampleRate); QString getGroup() const; - bool setSavedLoop(CuePointer pCue); + void setLoop(double startPosition, double endPosition, bool enabled); // Called to collect player features for effects processing. virtual void collectFeatureState(GroupFeatureState* pGroupFeatures) const { diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 2a458189467c..0041aa5e915a 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -290,10 +290,7 @@ void LoopingControl::slotLoopScale(double scaleFactor) { loopSamples.seekMode = (m_bLoopingEnabled && scaleFactor < 1.0) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; m_loopSamples.setValue(loopSamples); - if(m_pCue) { - m_pCue->setStartPosition(loopSamples.start); - m_pCue->setEndPosition(loopSamples.end); - } + emit loopUpdated(loopSamples.start, loopSamples.end); // Update CO for loop end marker m_pCOLoopEndPosition->set(loopSamples.end); @@ -530,61 +527,25 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl return dSyncedPlayPos; } -bool LoopingControl::setSavedLoop(CuePointer pCue) { - qDebug() << "setSavedLoop"; - - bool loopAlreadyActive = false; - if(!pCue) { - if(m_pCue) { - m_pCue->deactivate(); - m_pCue.reset(); - } - clearActiveBeatLoop(); - return loopAlreadyActive; - } - DEBUG_ASSERT(pCue->getType() == mixxx::CueType::Loop); - - double startPosition = pCue->getPosition(); - double endPosition = startPosition + pCue->getLength(); - if(startPosition < 0 || startPosition >= endPosition) { - if(m_pCue) { - m_pCue->deactivate(); - m_pCue.reset(); - } - clearActiveBeatLoop(); - return loopAlreadyActive; +void LoopingControl::setLoop(double startPosition, double endPosition, bool enabled) { + VERIFY_OR_DEBUG_ASSERT(startPosition != Cue::kNoPosition && + (startPosition < endPosition || endPosition == Cue::kNoPosition)) { + return; } + qDebug() << "LoopingControl::setLoop" << startPosition << endPosition << enabled; LoopSamples loopSamples = m_loopSamples.getValue(); - bool loopSamplesChanged = loopSamples.start != startPosition || loopSamples.end != endPosition; - if (m_pCue != pCue || loopSamplesChanged) { - if(m_pCue != pCue) { - if(m_pCue) { - m_pCue->deactivate(); - } - m_pCue = pCue; - } - if(loopSamplesChanged) { - // Copy saved loop parameters to active loop - loopSamples.start = startPosition; - loopSamples.end = endPosition; - loopSamples.seekMode = LoopSeekMode::None; - clearActiveBeatLoop(); - m_loopSamples.setValue(loopSamples); - m_pCOLoopStartPosition->set(loopSamples.start); - m_pCOLoopEndPosition->set(loopSamples.end); - setLoopingEnabled(true); - } else if(m_pCue && m_bLoopingEnabled) { - // Currently active loop became a saved loop, mark it as active - m_pCue->activate(); - } - } else if (!m_bLoopingEnabled) { - setLoopingEnabled(true); - } else { - loopAlreadyActive = true; + if (loopSamples.start != startPosition || loopSamples.end != endPosition) { + // Copy saved loop parameters to active loop + loopSamples.start = startPosition; + loopSamples.end = endPosition; + loopSamples.seekMode = LoopSeekMode::None; + clearActiveBeatLoop(); + m_loopSamples.setValue(loopSamples); + m_pCOLoopStartPosition->set(loopSamples.start); + m_pCOLoopEndPosition->set(loopSamples.end); } - - return loopAlreadyActive; + setLoopingEnabled(enabled); } void LoopingControl::setLoopInToCurrentPosition() { @@ -967,13 +928,8 @@ void LoopingControl::setLoopingEnabled(bool enabled) { pActiveBeatLoop->deactivate(); } } - if (m_pCue) { - if (enabled) { - m_pCue->activate(); - } else { - m_pCue->deactivate(); - } - } + + emit loopToggled(enabled); } bool LoopingControl::isLoopingEnabled() { @@ -1122,9 +1078,8 @@ void LoopingControl::updateBeatLoopingControls() { void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable) { // If this is a "new" loop, stop tracking saved loop changes - if(!keepStartPoint && m_pCue) { - m_pCue->deactivate(); - m_pCue.reset(); + if (!keepStartPoint) { + emit loopReset(); } // if a seek was queued in the engine buffer move the current sample to its position @@ -1263,10 +1218,7 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable newloopSamples.seekMode = (keepStartPoint && (enable || m_bLoopingEnabled)) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; m_loopSamples.setValue(newloopSamples); - if(m_pCue) { - m_pCue->setStartPosition(newloopSamples.start); - m_pCue->setEndPosition(newloopSamples.end); - } + emit loopUpdated(newloopSamples.start, newloopSamples.end); m_pCOLoopStartPosition->set(newloopSamples.start); m_pCOLoopEndPosition->set(newloopSamples.end); @@ -1371,10 +1323,7 @@ void LoopingControl::slotLoopMove(double beats) { loopSamples.start = new_loop_in; loopSamples.end = new_loop_out; m_loopSamples.setValue(loopSamples); - if (m_pCue) { - m_pCue->setStartPosition(loopSamples.start); - m_pCue->setEndPosition(loopSamples.end); - } + emit loopUpdated(loopSamples.start, loopSamples.end); m_pCOLoopStartPosition->set(new_loop_in); m_pCOLoopEndPosition->set(new_loop_out); } diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 7db31c778112..04711b86c3f3 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -52,13 +52,18 @@ class LoopingControl : public EngineControl { void notifySeek(double dNewPlaypos) override; - bool setSavedLoop(CuePointer pCue); + void setLoop(double startPosition, double endPosition, bool enabled); void setRateControl(RateControl* rateControl); bool isLoopingEnabled(); void trackLoaded(TrackPointer pNewTrack) override; void trackBeatsUpdated(mixxx::BeatsPointer pBeats) override; + signals: + void loopReset(); + void loopToggled(bool enabled); + void loopUpdated(double startPosition, double endPosition); + public slots: void slotLoopIn(double pressed); void slotLoopInGoto(double); diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 9ae4692fa90a..b5b85dade2a6 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -232,6 +232,22 @@ EngineBuffer::EngineBuffer(const QString& group, m_pCueControl = new CueControl(group, pConfig); addControl(m_pCueControl); + connect(m_pLoopingControl, + &LoopingControl::loopReset, + m_pCueControl, + &CueControl::slotLoopReset, + Qt::DirectConnection); + connect(m_pLoopingControl, + &LoopingControl::loopUpdated, + m_pCueControl, + &CueControl::slotLoopUpdated, + Qt::DirectConnection); + connect(m_pLoopingControl, + &LoopingControl::loopToggled, + m_pCueControl, + &CueControl::slotLoopToggled, + Qt::DirectConnection); + m_pReadAheadManager = new ReadAheadManager(m_pReader, m_pLoopingControl); m_pReadAheadManager->addRateControl(m_pRateControl); @@ -357,8 +373,8 @@ double EngineBuffer::getLocalBpm() { return m_pBpmControl->getLocalBpm(); } -bool EngineBuffer::setSavedLoop(CuePointer pCue) { - return m_pLoopingControl->setSavedLoop(pCue); +void EngineBuffer::setLoop(double startPosition, double endPositon, bool enabled) { + return m_pLoopingControl->setLoop(startPosition, endPositon, enabled); } void EngineBuffer::setEngineMaster(EngineMaster* pEngineMaster) { diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 24db03751d79..439615d45f25 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -125,7 +125,7 @@ class EngineBuffer : public EngineObject { // Returns the BPM of the loaded track around the current position (not thread-safe) double getLocalBpm(); // Sets a loop for the loaded track (not thread safe) - bool setSavedLoop(CuePointer); + void setLoop(double startPosition, double endPositon, bool enabled); // Sets pointer to other engine buffer/channel void setEngineMaster(EngineMaster*); From 2fe585e3d54a1b240a12bad4b579f2b943f40130 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 19 Jun 2020 19:09:24 +0200 Subject: [PATCH 045/153] engine/controls: Add support for setting beatloops from hotcues --- src/engine/controls/cuecontrol.cpp | 44 +++++++++++++++++++++----- src/engine/controls/cuecontrol.h | 3 ++ src/engine/controls/loopingcontrol.cpp | 10 ++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 49ed96f0aa83..052d95c09cfb 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -309,6 +309,11 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcueGotoAndLoop, this, &CueControl::hotcueGotoAndLoop, Qt::DirectConnection); + connect(pControl, + &HotcueControl::hotcueLoopToggle, + this, + &CueControl::hotcueLoopToggle, + Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueActivate, this, &CueControl::hotcueActivate, Qt::DirectConnection); @@ -847,9 +852,8 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { hotcueGoto(pControl, v); setCurrentSavedLoop(pCue); } else if (pCue->getType() == mixxx::CueType::HotCue) { - setCurrentSavedLoop(CuePointer()); hotcueGoto(pControl, v); - m_pBeatLoopActivate->set(1); + setLoop(pCue->getPosition(), Cue::kNoPosition, true); } else { return; } @@ -883,12 +887,25 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { return; } - bool enabled; - if (m_pCurrentSavedLoop != pCue) { - setCurrentSavedLoop(pCue); - } else { - enabled = !pCue->isActive(); - setLoop(pCue->getPosition(), pCue->getEndPosition(), enabled); + switch (pCue->getType()) { + case mixxx::CueType::Loop: { + bool enabled; + if (m_pCurrentSavedLoop != pCue) { + setCurrentSavedLoop(pCue); + } else { + enabled = !pCue->isActive(); + setLoop(pCue->getPosition(), pCue->getEndPosition(), enabled); + } + } break; + case mixxx::CueType::HotCue: { + double startPosition = pCue->getPosition(); + bool enabled = startPosition != m_pLoopStartPosition->get() || + !m_pLoopEnabled->get(); + setLoop(startPosition, Cue::kNoPosition, enabled); + break; + } + default: + break; } } @@ -2107,6 +2124,13 @@ HotcueControl::HotcueControl(QString group, int i) this, &HotcueControl::slotHotcueGotoAndLoop, Qt::DirectConnection); + m_hotcueLoopToggle = new ControlPushButton(keyForControl(i, "loop_toggle")); + connect(m_hotcueLoopToggle, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueLoopToggle, + Qt::DirectConnection); + m_hotcueActivate = new ControlPushButton(keyForControl(i, "activate")); connect(m_hotcueActivate, &ControlObject::valueChanged, this, &HotcueControl::slotHotcueActivate, @@ -2181,6 +2205,10 @@ void HotcueControl::slotHotcueGotoAndLoop(double v) { emit hotcueGotoAndLoop(this, v); } +void HotcueControl::slotHotcueLoopToggle(double v) { + emit hotcueLoopToggle(this, v); +} + void HotcueControl::slotHotcueActivate(double v) { emit hotcueActivate(this, v, HotcueMode::Auto); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index eea11b87e9ad..12065ad9ad2e 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -90,6 +90,7 @@ class HotcueControl : public QObject { void slotHotcueGotoAndPlay(double v); void slotHotcueGotoAndStop(double v); void slotHotcueGotoAndLoop(double v); + void slotHotcueLoopToggle(double v); void slotHotcueActivate(double v); void slotHotcueActivateCue(double v); void slotHotcueActivateLoop(double v); @@ -107,6 +108,7 @@ class HotcueControl : public QObject { void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); void hotcueGotoAndLoop(HotcueControl* pHotcue, double v); + void hotcueLoopToggle(HotcueControl* pHotcue, double v); void hotcueActivate(HotcueControl* pHotcue, double v, HotcueMode mode); void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); @@ -137,6 +139,7 @@ class HotcueControl : public QObject { ControlObject* m_hotcueGotoAndPlay; ControlObject* m_hotcueGotoAndStop; ControlObject* m_hotcueGotoAndLoop; + ControlObject* m_hotcueLoopToggle; ControlObject* m_hotcueActivate; ControlObject* m_hotcueActivateCue; ControlObject* m_hotcueActivateLoop; diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 0041aa5e915a..7f385e089ce9 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -535,6 +535,16 @@ void LoopingControl::setLoop(double startPosition, double endPosition, bool enab qDebug() << "LoopingControl::setLoop" << startPosition << endPosition << enabled; LoopSamples loopSamples = m_loopSamples.getValue(); + if (endPosition == Cue::kNoPosition) { + mixxx::BeatsPointer pBeats = m_pBeats; + if (!pBeats) { + return; + } + + double beatloopSize = m_pCOBeatLoopSize->get(); + endPosition = pBeats->findNBeatsFromSample(startPosition, beatloopSize); + } + if (loopSamples.start != startPosition || loopSamples.end != endPosition) { // Copy saved loop parameters to active loop loopSamples.start = startPosition; From ef70a5aa14acb2c133f570c9e38fdde346b0c1f3 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 19 Jun 2020 19:36:12 +0200 Subject: [PATCH 046/153] engine/controls/cuecontrol: Reset current saved loop on hotcue beetloop --- src/engine/controls/cuecontrol.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 052d95c09cfb..13efbd53c59d 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -898,6 +898,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { } } break; case mixxx::CueType::HotCue: { + setCurrentSavedLoop(CuePointer()); double startPosition = pCue->getPosition(); bool enabled = startPosition != m_pLoopStartPosition->get() || !m_pLoopEnabled->get(); From 96b18854531827e4dfe2c73350bf82a87327c8c6 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Jul 2020 00:27:31 +0200 Subject: [PATCH 047/153] engine/controls/cuecontrol: Add support for previewing loop cues --- src/engine/controls/cuecontrol.cpp | 18 +++++++++++++----- src/engine/controls/cuecontrol.h | 10 +++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 13efbd53c59d..f8a6129fbffe 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -968,13 +968,17 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { CuePointer pCue(pControl->getCue()); if (v) { - if (pCue && pCue->getPosition() != Cue::kNoPosition) { + if (pCue && pCue->getPosition() != Cue::kNoPosition && + pCue->getType() != mixxx::CueType::Invalid) { m_iCurrentlyPreviewingHotcues++; double position = pCue->getPosition(); m_bypassCueSetByPlay = true; m_pPlay->set(1.0); - pControl->setPreviewing(true); + pControl->setPreviewingType(pCue->getType()); pControl->setPreviewingPosition(position); + if (pCue->getType() == mixxx::CueType::Loop) { + setCurrentSavedLoop(pCue); + } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); @@ -984,10 +988,11 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { } else if (m_iCurrentlyPreviewingHotcues) { // This is a activate release and we are previewing at least one // hotcue. If this hotcue is previewing: - if (pControl->isPreviewing()) { + mixxx::CueType cueType = pControl->getPreviewingType(); + if (cueType != mixxx::CueType::Invalid) { // Mark this hotcue as not previewing. double position = pControl->getPreviewingPosition(); - pControl->setPreviewing(false); + pControl->setPreviewingType(mixxx::CueType::Invalid); pControl->setPreviewingPosition(Cue::kNoPosition); // If this is the last hotcue to leave preview. @@ -995,6 +1000,9 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { m_pPlay->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); + if (cueType == mixxx::CueType::Loop) { + m_pLoopEnabled->set(0); + } seekExact(position); } } @@ -2054,7 +2062,7 @@ HotcueControl::HotcueControl(QString group, int i) : m_group(group), m_iHotcueNumber(i), m_pCue(NULL), - m_bPreviewing(false), + m_previewingType(mixxx::CueType::Invalid), m_previewingPosition(-1) { m_hotcuePosition = new ControlObject(keyForControl(i, "position")); connect(m_hotcuePosition, &ControlObject::valueChanged, diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 12065ad9ad2e..200fa36916af 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -69,11 +69,11 @@ class HotcueControl : public QObject { mixxx::RgbColor::optional_t getColor() const; // Used for caching the preview state of this hotcue control. - inline bool isPreviewing() { - return m_bPreviewing; + inline mixxx::CueType getPreviewingType() { + return m_previewingType; } - inline void setPreviewing(bool bPreviewing) { - m_bPreviewing = bPreviewing; + inline void setPreviewingType(mixxx::CueType type) { + m_previewingType = type; } inline double getPreviewingPosition() { return m_previewingPosition; @@ -146,7 +146,7 @@ class HotcueControl : public QObject { ControlObject* m_hotcueActivatePreview; ControlObject* m_hotcueClear; - bool m_bPreviewing; + mixxx::CueType m_previewingType; double m_previewingPosition; }; From 39854e07d6ce5d12e2f0ecfbcc3eb15c43e41a69 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Jul 2020 02:06:53 +0200 Subject: [PATCH 048/153] widget/woverview: Fix labels for loop cues on overview waveforms --- src/widget/woverview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index cc43c830495a..0f185ba8abb0 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -392,7 +392,9 @@ void WOverview::updateCues(const QList &loadedCues) { } int hotcueNumber = currentCue->getHotCue(); - if (currentCue->getType() == mixxx::CueType::HotCue && hotcueNumber != Cue::kNoHotCue) { + if ((currentCue->getType() == mixxx::CueType::HotCue || + currentCue->getType() == mixxx::CueType::Loop) && + hotcueNumber != Cue::kNoHotCue) { // Prepend the hotcue number to hotcues' labels QString newLabel = currentCue->getLabel(); if (newLabel.isEmpty()) { From 3b4e2e674cc999318097ddcc40b482c2404ea185 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Jul 2020 01:31:29 +0200 Subject: [PATCH 049/153] waveform: Draw loop cues on scrolling waveforms --- src/waveform/renderers/waveformmark.cpp | 16 +++++++++++----- src/waveform/renderers/waveformmark.h | 13 +++++++++++++ src/waveform/renderers/waveformrendermark.cpp | 16 ++++++++++++++++ src/widget/woverview.cpp | 2 ++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/waveform/renderers/waveformmark.cpp b/src/waveform/renderers/waveformmark.cpp index 46d75d921a4f..2ae0b74fdff2 100644 --- a/src/waveform/renderers/waveformmark.cpp +++ b/src/waveform/renderers/waveformmark.cpp @@ -56,14 +56,20 @@ WaveformMark::WaveformMark(const QString& group, const WaveformSignalColors& signalColors, int hotCue) : m_iHotCue(hotCue) { - QString control; + QString positionControl; + QString lengthControl; if (hotCue != Cue::kNoHotCue) { - control = "hotcue_" + QString::number(hotCue + 1) + "_position"; + positionControl = "hotcue_" + QString::number(hotCue + 1) + "_position"; + lengthControl = "hotcue_" + QString::number(hotCue + 1) + "_length"; } else { - control = context.selectString(node, "Control"); + positionControl = context.selectString(node, "Control"); } - if (!control.isEmpty()) { - m_pPointCos = std::make_unique(group, control); + + if (!positionControl.isEmpty()) { + m_pPointCos = std::make_unique(group, positionControl); + } + if (!lengthControl.isEmpty()) { + m_pLengthCos = std::make_unique(group, lengthControl); } QString visibilityControl = context.selectString(node, "VisibilityControl"); diff --git a/src/waveform/renderers/waveformmark.h b/src/waveform/renderers/waveformmark.h index abb0da82868b..280b839935a1 100644 --- a/src/waveform/renderers/waveformmark.h +++ b/src/waveform/renderers/waveformmark.h @@ -37,7 +37,19 @@ class WaveformMark { void connectSamplePositionChanged(Receiver receiver, Slot slot) const { m_pPointCos->connectValueChanged(receiver, slot, Qt::AutoConnection); }; + template + void connectSampleLengthChanged(Receiver receiver, Slot slot) const { + if (m_pLengthCos) { + m_pLengthCos->connectValueChanged(receiver, slot, Qt::AutoConnection); + } + }; double getSamplePosition() const { return m_pPointCos->get(); } + double getSampleLength() const { + if (m_pLengthCos) { + return m_pLengthCos->get(); + } + return 0; + } QString getItem() const { return m_pPointCos->getKey().item; } // The m_pVisibleCos related function @@ -80,6 +92,7 @@ class WaveformMark { private: std::unique_ptr m_pPointCos; + std::unique_ptr m_pLengthCos; std::unique_ptr m_pVisibleCos; int m_iHotCue; QImage m_image; diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 6a789d0d6a1d..fc586f615308 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -61,6 +61,7 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { if (samplePosition != -1.0) { double currentMarkPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(samplePosition); + double sampleLength = pMark->getSampleLength(); if (m_waveformRenderer->getOrientation() == Qt::Horizontal) { // NOTE: vRince I guess image width is odd to display the center on the exact line ! // external image should respect that ... @@ -71,8 +72,16 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { if (currentMarkPoint > -markHalfWidth && currentMarkPoint < m_waveformRenderer->getWidth() + markHalfWidth) { int drawOffset = currentMarkPoint - markHalfWidth; painter->drawImage(QPoint(drawOffset, 0), pMark->m_image); + if (sampleLength > 0) { + double currentMarkEndPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(samplePosition + sampleLength); + painter->fillRect(QRect( + QPoint(currentMarkPoint, m_waveformRenderer->getHeight() - 5), + QPoint(currentMarkEndPoint, m_waveformRenderer->getHeight())), + pMark->fillColor()); + } marksOnScreen[pMark] = drawOffset; } + } else { const int markHalfHeight = pMark->m_image.height() / 2.0; if (currentMarkPoint > -markHalfHeight && @@ -80,6 +89,13 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { markHalfHeight) { int drawOffset = currentMarkPoint - markHalfHeight; painter->drawImage(QPoint(0, drawOffset), pMark->m_image); + if (sampleLength > 0) { + double currentMarkEndPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(samplePosition + sampleLength); + painter->fillRect(QRect( + QPoint(m_waveformRenderer->getWidth() - 5, currentMarkPoint), + QPoint(m_waveformRenderer->getWidth(), currentMarkEndPoint)), + pMark->fillColor()); + } marksOnScreen[pMark] = drawOffset; } } diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 0f185ba8abb0..17f73ee2a654 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -162,6 +162,8 @@ void WOverview::setup(const QDomNode& node, const SkinContext& context) { if (pMark->isValid()) { pMark->connectSamplePositionChanged(this, &WOverview::onMarkChanged); + pMark->connectSampleLengthChanged(this, + &WOverview::onMarkChanged); } if (pMark->hasVisible()) { pMark->connectVisibleChanged(this, From f7d0522fea0d973283df4d6999e3230be210c5f0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 6 Jul 2020 02:07:33 +0200 Subject: [PATCH 050/153] widget/woverview: Draw loop cue lengths on overview waveforms --- src/widget/woverview.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 17f73ee2a654..98e91e9e926f 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -790,8 +790,9 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga WaveformMarkPointer pMark = m_marksToRender.at(i); PainterScope painterScope(pPainter); + double samplePosition = m_marksToRender.at(i)->getSamplePosition(); const qreal markPosition = math_clamp( - offset + m_marksToRender.at(i)->getSamplePosition() * gain, + offset + samplePosition * gain, 0.0, static_cast(width())); pMark->m_linePosition = markPosition; @@ -804,11 +805,33 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga } else { line.setLine(0.0, markPosition, width(), markPosition); } + + QRectF rect; + double sampleLength = m_marksToRender.at(i)->getSampleLength(); + if (sampleLength > 0) { + const qreal markEndPosition = math_clamp( + offset + (samplePosition + sampleLength) * gain, + 0.0, + static_cast(width())); + + if (m_orientation == Qt::Horizontal) { + rect.setCoords(markPosition, 0, markEndPosition, 5); + } else { + rect.setCoords(0, markPosition, 5, markEndPosition); + } + } + pPainter->setPen(shadowPen); pPainter->drawLine(line); + if (rect.isValid()) { + pPainter->drawRect(rect); + } pPainter->setPen(pMark->fillColor()); pPainter->drawLine(line); + if (rect.isValid()) { + pPainter->fillRect(rect, pMark->fillColor()); + } if (!pMark->m_text.isEmpty()) { Qt::Alignment halign = pMark->m_align & Qt::AlignHorizontal_Mask; From e9245a9cc1381430c447b2866db2c7434808d761 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 7 Jul 2020 14:25:17 +0200 Subject: [PATCH 051/153] widget/woverview: Render transparent loop preview --- src/widget/woverview.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 98e91e9e926f..f550781385e8 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -815,22 +815,22 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga static_cast(width())); if (m_orientation == Qt::Horizontal) { - rect.setCoords(markPosition, 0, markEndPosition, 5); + rect.setCoords(markPosition, 0, markEndPosition, height()); } else { - rect.setCoords(0, markPosition, 5, markEndPosition); + rect.setCoords(0, markPosition, width(), markEndPosition); } } pPainter->setPen(shadowPen); pPainter->drawLine(line); - if (rect.isValid()) { - pPainter->drawRect(rect); - } pPainter->setPen(pMark->fillColor()); pPainter->drawLine(line); + if (rect.isValid()) { - pPainter->fillRect(rect, pMark->fillColor()); + QColor loopColor = pMark->fillColor(); + loopColor.setAlphaF(0.5); + pPainter->fillRect(rect, loopColor); } if (!pMark->m_text.isEmpty()) { From ce1e22ec74ec1d20938f88dccbc11a143307a3f4 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:14:21 +0200 Subject: [PATCH 052/153] engine/controls/cuecontrol: Use braces for include guard Co-authored-by: Be --- src/engine/controls/cuecontrol.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index f8a6129fbffe..2598b585987c 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1046,8 +1046,9 @@ void CueControl::hotcuePositionChanged(HotcueControl* pControl, double newPositi void CueControl::hotcueLengthChanged(HotcueControl* pControl, double newLength) { QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) + if (!m_pLoadedTrack) { return; + } CuePointer pCue(pControl->getCue()); if (pCue) { From ab2eee09022ede0f3f567023148f5a5d1af476d8 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:20:00 +0200 Subject: [PATCH 053/153] engine/enginebuffer: Use doxygen-style /// comments Co-authored-by: Be --- src/engine/enginebuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 2a1e33724edc..ffeb67316478 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -123,7 +123,7 @@ class EngineBuffer : public EngineObject { double getBpm(); // Returns the BPM of the loaded track around the current position (not thread-safe) double getLocalBpm(); - // Sets a loop for the loaded track (not thread safe) + /// Sets a loop for the loaded track (not thread safe) void setLoop(double startPosition, double endPositon, bool enabled); // Sets pointer to other engine buffer/channel void setEngineMaster(EngineMaster*); From 95dabe16ac77d36834506a1f9c34ef4e15281852 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:36:33 +0200 Subject: [PATCH 054/153] engine/controls/cuecontrol: Remove boolean literal from debug msg Co-authored-by: Be --- src/engine/controls/cuecontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 2598b585987c..c74897bd3d3a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2016,7 +2016,7 @@ void CueControl::setCurrentSavedLoop(CuePointer pCue) { } if (m_pCurrentSavedLoop) { - qDebug() << "CueControl::setLoop" << pCue->getPosition() << pCue->getEndPosition() << true; + qDebug() << "CueControl::setLoop" << pCue->getPosition() << pCue->getEndPosition(); setLoop(pCue->getPosition(), pCue->getEndPosition(), true); pCue->activate(); } From e93853cd66dcc18d9e74b1d70f849ba952c6b5a3 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:16:05 +0200 Subject: [PATCH 055/153] engine/controls/cuecontrol: Use braces for include guards --- src/engine/controls/cuecontrol.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c74897bd3d3a..f6f474c3edb1 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -656,8 +656,9 @@ void CueControl::quantizeChanged(double v) { void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { //qDebug() << "CueControl::hotcueSet" << v; - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) @@ -751,8 +752,9 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { } void CueControl::hotcueGoto(HotcueControl* pControl, double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { @@ -773,8 +775,9 @@ void CueControl::hotcueGoto(HotcueControl* pControl, double v) { } void CueControl::hotcueGotoAndStop(HotcueControl* pControl, double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) @@ -795,8 +798,9 @@ void CueControl::hotcueGotoAndStop(HotcueControl* pControl, double v) { } void CueControl::hotcueGotoAndPlay(HotcueControl* pControl, double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { @@ -826,8 +830,9 @@ void CueControl::hotcueGotoAndPlay(HotcueControl* pControl, double v) { } void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { @@ -870,8 +875,9 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { } void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { @@ -1010,8 +1016,9 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { } void CueControl::hotcueClear(HotcueControl* pControl, double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { @@ -1109,8 +1116,9 @@ void CueControl::hintReader(HintVector* pHintList) { // Moves the cue point to current position or to closest beat in case // quantize is enabled void CueControl::cueSet(double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); @@ -1142,8 +1150,9 @@ void CueControl::cueClear(double v) { void CueControl::cueGoto(double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); // Seek to cue point @@ -1173,8 +1182,9 @@ void CueControl::cueGotoAndPlay(double v) void CueControl::cueGotoAndStop(double v) { - if (!v) + if (!v) { return; + } QMutexLocker lock(&m_mutex); m_pPlay->set(0.0); From 29cbaf123636df79b67240310843814b6ec4f88a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:17:15 +0200 Subject: [PATCH 056/153] engine/controls/cuecontrol: Use named constants for resetting the hotcue --- 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 f6f474c3edb1..47b9f00ed8ef 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1061,7 +1061,7 @@ void CueControl::hotcueLengthChanged(HotcueControl* pControl, double newLength) if (pCue) { // Setting the length to Cue::kNoPosition is the same as calling hotcue_x_clear if (newLength == Cue::kNoPosition) { - pCue->setHotCue(-1); + pCue->setHotCue(Cue::kNoHotCue); detachCue(pControl); } else { if (newLength >= 0) { @@ -1081,7 +1081,7 @@ void CueControl::hotcueTypeChanged(HotcueControl* pControl, double newType) { // Setting the type to 0 or -1 is the same as calling hotcue_x_clear int iType = static_cast(newType); if (iType <= 0 || iType > static_cast(mixxx::CueType::AudibleSound)) { - pCue->setHotCue(-1); + pCue->setHotCue(Cue::kNoHotCue); detachCue(pControl); } else { pCue->setType(static_cast(iType)); From 564e60d48add77f57c8608404df35f0dbd42876e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:17:54 +0200 Subject: [PATCH 057/153] engine/controls/cuecontrol: Deduplicate code in hotcueSet method --- src/engine/controls/cuecontrol.cpp | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 47b9f00ed8ef..886c8b7375e2 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -677,21 +677,11 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { double cueEndPosition = Cue::kNoPosition; mixxx::CueType cueType = mixxx::CueType::Invalid; - switch (mode) { - case HotcueMode::Auto: { - if (m_pLoopEnabled->get()) { - // If a loop is enabled, the hotcue will be a saved loop - cueStartPosition = m_pLoopStartPosition->get(); - cueEndPosition = m_pLoopEndPosition->get(); - cueType = mixxx::CueType::Loop; - } else { - // If no loop is enabled, just store regular jump cue - cueStartPosition = getQuantizedCurrentPosition(); - cueEndPosition = Cue::kNoPosition; - cueType = mixxx::CueType::HotCue; - } - break; + if (mode == HotcueMode::Auto) { + mode = m_pLoopEnabled->get() ? HotcueMode::Loop : HotcueMode::Cue; } + + switch (mode) { case HotcueMode::Cue: { // If no loop is enabled, just store regular jump cue cueStartPosition = getQuantizedCurrentPosition(); @@ -706,6 +696,8 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { cueType = mixxx::CueType::Loop; break; } + default: + DEBUG_ASSERT(!"Invalid HotcueMode"); } VERIFY_OR_DEBUG_ASSERT(cueType != mixxx::CueType::Invalid) { From 9556db022c1ae697ddc0ab7a621e607ef5e3ef80 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:31:14 +0200 Subject: [PATCH 058/153] engine/controls/cuecontrol: Use type instead of length in hotcueActivate --- src/engine/controls/cuecontrol.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 886c8b7375e2..d092c91df0c2 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -927,10 +927,15 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double v, HotcueMode mo hotcueSet(pControl, v, mode); } else { if (isPlayingByPlayButton()) { - if (pCue->getLength() > 0) { - hotcueLoopToggle(pControl, v); - } else { + switch (pCue->getType()) { + case mixxx::CueType::HotCue: hotcueGoto(pControl, v); + break; + case mixxx::CueType::Loop: + hotcueLoopToggle(pControl, v); + break; + default: + DEBUG_ASSERT(!"Invalid CueType!"); } } else { hotcueActivatePreview(pControl, v); From b5dda793235273f6be26bb033673b8118853661d Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 12:34:48 +0200 Subject: [PATCH 059/153] engine/controls/cuecontrol: Fix typo in comment --- src/engine/controls/cuecontrol.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index d092c91df0c2..87c2574c6694 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -809,7 +809,7 @@ void CueControl::hotcueGotoAndPlay(HotcueControl* pControl, double v) { if (position != Cue::kNoPosition) { seekAbs(position); if (!isPlayingByPlayButton()) { - // cueGoto is processed asynchrony. + // cueGoto is processed asynchronously. // avoid a wrong cue set if seek by cueGoto is still pending m_bPreviewing = false; m_iCurrentlyPreviewingHotcues = 0; @@ -856,7 +856,7 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { } if (!isPlayingByPlayButton()) { - // cueGoto is processed asynchrony. + // cueGoto is processed asynchronously. // avoid a wrong cue set if seek by cueGoto is still pending m_bPreviewing = false; m_iCurrentlyPreviewingHotcues = 0; @@ -1168,7 +1168,7 @@ void CueControl::cueGotoAndPlay(double v) QMutexLocker lock(&m_mutex); // Start playing if not already if (!isPlayingByPlayButton()) { - // cueGoto is processed asynchrony. + // cueGoto is processed asynchronously. // avoid a wrong cue set if seek by cueGoto is still pending m_bPreviewing = false; m_iCurrentlyPreviewingHotcues = 0; From ddb694e17422d6a1f1a491b9aea2df0b9b868b42 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 8 Jul 2020 16:29:38 +0200 Subject: [PATCH 060/153] engine/controls/cuecontrol: Fix wrong debug assertion --- src/engine/controls/cuecontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 87c2574c6694..d0d55a55c265 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2052,7 +2052,7 @@ void CueControl::slotLoopUpdated(double startPosition, double endPosition) { DEBUG_ASSERT(startPosition != Cue::kNoPosition); DEBUG_ASSERT(endPosition != Cue::kNoPosition); - DEBUG_ASSERT(startPosition > endPosition); + DEBUG_ASSERT(startPosition < endPosition); m_pCurrentSavedLoop->setStartPosition(startPosition); m_pCurrentSavedLoop->setEndPosition(endPosition); From 1071dbd258439ff5b3ac680a324b54e4cdb2a96a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 14 Jul 2020 15:20:22 +0200 Subject: [PATCH 061/153] engine/controls/loopingcontrol: Add setBeatLoop method --- src/engine/controls/cuecontrol.cpp | 4 ++-- src/engine/controls/enginecontrol.cpp | 6 ++++++ src/engine/controls/enginecontrol.h | 1 + src/engine/controls/loopingcontrol.cpp | 28 ++++++++++++++++---------- src/engine/controls/loopingcontrol.h | 1 + src/engine/enginebuffer.cpp | 4 ++++ src/engine/enginebuffer.h | 2 ++ 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index d0d55a55c265..8ac561c7a596 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -850,7 +850,7 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { setCurrentSavedLoop(pCue); } else if (pCue->getType() == mixxx::CueType::HotCue) { hotcueGoto(pControl, v); - setLoop(pCue->getPosition(), Cue::kNoPosition, true); + setBeatLoop(pCue->getPosition(), true); } else { return; } @@ -900,7 +900,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { double startPosition = pCue->getPosition(); bool enabled = startPosition != m_pLoopStartPosition->get() || !m_pLoopEnabled->get(); - setLoop(startPosition, Cue::kNoPosition, enabled); + setBeatLoop(startPosition, enabled); break; } default: diff --git a/src/engine/controls/enginecontrol.cpp b/src/engine/controls/enginecontrol.cpp index c7bdcbddea7f..51a6fab56f33 100644 --- a/src/engine/controls/enginecontrol.cpp +++ b/src/engine/controls/enginecontrol.cpp @@ -71,6 +71,12 @@ EngineBuffer* EngineControl::getEngineBuffer() { return m_pEngineBuffer; } +void EngineControl::setBeatLoop(double startPosition, bool enabled) { + if (m_pEngineBuffer) { + return m_pEngineBuffer->setBeatLoop(startPosition, enabled); + } +} + void EngineControl::setLoop(double startPosition, double endPosition, bool enabled) { if (m_pEngineBuffer) { return m_pEngineBuffer->setLoop(startPosition, endPosition, enabled); diff --git a/src/engine/controls/enginecontrol.h b/src/engine/controls/enginecontrol.h index 9b4d10d286e1..5476fdb66b2c 100644 --- a/src/engine/controls/enginecontrol.h +++ b/src/engine/controls/enginecontrol.h @@ -60,6 +60,7 @@ class EngineControl : public QObject { const double dTotalSamples, const double dTrackSampleRate); QString getGroup() const; + void setBeatLoop(double startPosition, bool enabled); void setLoop(double startPosition, double endPosition, bool enabled); // Called to collect player features for effects processing. diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 7f385e089ce9..a2fda6370b9a 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -527,24 +527,30 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl return dSyncedPlayPos; } +void LoopingControl::setBeatLoop(double startPosition, bool enabled) { + VERIFY_OR_DEBUG_ASSERT(startPosition != Cue::kNoPosition) { + return; + } + + mixxx::BeatsPointer pBeats = m_pBeats; + if (!pBeats) { + return; + } + + double beatloopSize = m_pCOBeatLoopSize->get(); + double endPosition = pBeats->findNBeatsFromSample(startPosition, beatloopSize); + + setLoop(startPosition, endPosition, enabled); +} + void LoopingControl::setLoop(double startPosition, double endPosition, bool enabled) { VERIFY_OR_DEBUG_ASSERT(startPosition != Cue::kNoPosition && - (startPosition < endPosition || endPosition == Cue::kNoPosition)) { + endPosition != Cue::kNoPosition && startPosition < endPosition) { return; } qDebug() << "LoopingControl::setLoop" << startPosition << endPosition << enabled; LoopSamples loopSamples = m_loopSamples.getValue(); - if (endPosition == Cue::kNoPosition) { - mixxx::BeatsPointer pBeats = m_pBeats; - if (!pBeats) { - return; - } - - double beatloopSize = m_pCOBeatLoopSize->get(); - endPosition = pBeats->findNBeatsFromSample(startPosition, beatloopSize); - } - if (loopSamples.start != startPosition || loopSamples.end != endPosition) { // Copy saved loop parameters to active loop loopSamples.start = startPosition; diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 04711b86c3f3..aa10a984e8d9 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -52,6 +52,7 @@ class LoopingControl : public EngineControl { void notifySeek(double dNewPlaypos) override; + void setBeatLoop(double startPosition, bool enabled); void setLoop(double startPosition, double endPosition, bool enabled); void setRateControl(RateControl* rateControl); bool isLoopingEnabled(); diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 670d4dd922b6..ecf8a308be80 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -373,6 +373,10 @@ double EngineBuffer::getLocalBpm() { return m_pBpmControl->getLocalBpm(); } +void EngineBuffer::setBeatLoop(double startPosition, bool enabled) { + return m_pLoopingControl->setBeatLoop(startPosition, enabled); +} + void EngineBuffer::setLoop(double startPosition, double endPositon, bool enabled) { return m_pLoopingControl->setLoop(startPosition, endPositon, enabled); } diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index ffeb67316478..abea09e6c345 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -123,6 +123,8 @@ class EngineBuffer : public EngineObject { double getBpm(); // Returns the BPM of the loaded track around the current position (not thread-safe) double getLocalBpm(); + /// Sets a beatloop for the loaded track (not thread safe) + void setBeatLoop(double startPosition, bool enabled); /// Sets a loop for the loaded track (not thread safe) void setLoop(double startPosition, double endPositon, bool enabled); // Sets pointer to other engine buffer/channel From 0159cde3227d8c0c8226971f211b2c85bd25d829 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 16 Jul 2020 12:09:24 +0200 Subject: [PATCH 062/153] cuecontrol: Use hotcue_X_endposition instead hotcue_X_length --- src/engine/controls/cuecontrol.cpp | 245 +++++++++++------- src/engine/controls/cuecontrol.h | 12 +- src/waveform/renderers/waveformmark.cpp | 12 +- src/waveform/renderers/waveformmark.h | 48 ++-- src/waveform/renderers/waveformrendermark.cpp | 30 ++- src/widget/woverview.cpp | 8 +- 6 files changed, 214 insertions(+), 141 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 8c87223cbada..33a188a6f698 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -294,37 +294,55 @@ void CueControl::createControls() { connect(pControl, &HotcueControl::hotcuePositionChanged, this, &CueControl::hotcuePositionChanged, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueLengthChanged, - this, &CueControl::hotcueLengthChanged, + connect(pControl, + &HotcueControl::hotcueEndPositionChanged, + this, + &CueControl::hotcueEndPositionChanged, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueSet, - this, &CueControl::hotcueSet, + connect(pControl, + &HotcueControl::hotcueSet, + this, + &CueControl::hotcueSet, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueGoto, - this, &CueControl::hotcueGoto, + connect(pControl, + &HotcueControl::hotcueGoto, + this, + &CueControl::hotcueGoto, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueGotoAndPlay, - this, &CueControl::hotcueGotoAndPlay, + connect(pControl, + &HotcueControl::hotcueGotoAndPlay, + this, + &CueControl::hotcueGotoAndPlay, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueGotoAndStop, - this, &CueControl::hotcueGotoAndStop, + connect(pControl, + &HotcueControl::hotcueGotoAndStop, + this, + &CueControl::hotcueGotoAndStop, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueGotoAndLoop, - this, &CueControl::hotcueGotoAndLoop, + connect(pControl, + &HotcueControl::hotcueGotoAndLoop, + this, + &CueControl::hotcueGotoAndLoop, Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueLoopToggle, this, &CueControl::hotcueLoopToggle, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueActivate, - this, &CueControl::hotcueActivate, + connect(pControl, + &HotcueControl::hotcueActivate, + this, + &CueControl::hotcueActivate, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueActivatePreview, - this, &CueControl::hotcueActivatePreview, + connect(pControl, + &HotcueControl::hotcueActivatePreview, + this, + &CueControl::hotcueActivatePreview, Qt::DirectConnection); - connect(pControl, &HotcueControl::hotcueClear, - this, &CueControl::hotcueClear, + connect(pControl, + &HotcueControl::hotcueClear, + this, + &CueControl::hotcueClear, Qt::DirectConnection); m_hotcueControls.append(pControl); @@ -336,8 +354,10 @@ void CueControl::attachCue(CuePointer pCue, HotcueControl* pControl) { return; } detachCue(pControl); - connect(pCue.get(), &Cue::updated, - this, &CueControl::cueUpdated, + connect(pCue.get(), + &Cue::updated, + this, + &CueControl::cueUpdated, Qt::DirectConnection); pControl->setCue(pCue); @@ -443,7 +463,8 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { } break; case SeekOnLoadMode::FirstSound: { - CuePointer pAudibleSound = pNewTrack->findCueByType(mixxx::CueType::AudibleSound); + CuePointer pAudibleSound = + pNewTrack->findCueByType(mixxx::CueType::AudibleSound); double audibleSoundPosition = Cue::kNoPosition; if (pAudibleSound) { audibleSoundPosition = pAudibleSound->getPosition(); @@ -539,7 +560,7 @@ void CueControl::loadCuesFromTrack() { } else { // If the old hotcue is the same, then we only need to update pControl->setPosition(pCue->getPosition()); - pControl->setLength(pCue->getLength()); + pControl->setEndPosition(pCue->getEndPosition()); pControl->setColor(pCue->getColor()); pControl->setType(pCue->getType()); pControl->setStatus(pCue->getStatus()); @@ -719,7 +740,8 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { // Abort if no position has been found. This can happen if a loop cue is // requested while no loop is set, so we can't debug assert here. if (cueStartPosition == Cue::kNoPosition || - (cueType == mixxx::CueType::Loop && cueEndPosition == Cue::kNoPosition)) { + (cueType == mixxx::CueType::Loop && + cueEndPosition == Cue::kNoPosition)) { return; } @@ -920,7 +942,8 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { } } -void CueControl::hotcueActivate(HotcueControl* pControl, double v, HotcueMode mode) { +void CueControl::hotcueActivate( + HotcueControl* pControl, double v, HotcueMode mode) { //qDebug() << "CueControl::hotcueActivate" << v; QMutexLocker lock(&m_mutex); @@ -1043,7 +1066,8 @@ void CueControl::hotcueClear(HotcueControl* pControl, double v) { m_pHotcueFocus->set(Cue::kNoHotCue); } -void CueControl::hotcuePositionChanged(HotcueControl* pControl, double newPosition) { +void CueControl::hotcuePositionChanged( + HotcueControl* pControl, double newPosition) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) return; @@ -1060,7 +1084,8 @@ void CueControl::hotcuePositionChanged(HotcueControl* pControl, double newPositi } } -void CueControl::hotcueLengthChanged(HotcueControl* pControl, double newLength) { +void CueControl::hotcueEndPositionChanged( + HotcueControl* pControl, double newEndPosition) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { return; @@ -1068,13 +1093,15 @@ void CueControl::hotcueLengthChanged(HotcueControl* pControl, double newLength) CuePointer pCue(pControl->getCue()); if (pCue) { - // Setting the length to Cue::kNoPosition is the same as calling hotcue_x_clear - if (newLength == Cue::kNoPosition) { - pCue->setHotCue(Cue::kNoHotCue); - detachCue(pControl); + // Setting the end position of a loop cue to Cue::kNoPosition converts + // it into a regular jump cue + if (pCue->getType() == mixxx::CueType::Loop && + newEndPosition == Cue::kNoPosition) { + pCue->setType(mixxx::CueType::HotCue); + pCue->setEndPosition(Cue::kNoPosition); } else { - if (newLength >= 0) { - pCue->setEndPosition(pCue->getPosition() + newLength); + if (newEndPosition > pCue->getPosition()) { + pCue->setEndPosition(newEndPosition); } } } @@ -1089,7 +1116,8 @@ void CueControl::hotcueTypeChanged(HotcueControl* pControl, double newType) { if (pCue) { // Setting the type to 0 or -1 is the same as calling hotcue_x_clear int iType = static_cast(newType); - if (iType <= 0 || iType > static_cast(mixxx::CueType::AudibleSound)) { + if (iType <= 0 || + iType > static_cast(mixxx::CueType::AudibleSound)) { pCue->setHotCue(Cue::kNoHotCue); detachCue(pControl); } else { @@ -1111,7 +1139,7 @@ void CueControl::hintReader(HintVector* pHintList) { // this is called from the engine thread // it is no locking required, because m_hotcueControl is filled during the // constructor and getPosition()->get() is a ControlObject - for (const auto& pControl: m_hotcueControls) { + for (const auto& pControl : m_hotcueControls) { double position = pControl->getPosition(); if (position != Cue::kNoPosition) { cue_hint.frame = SampleUtil::floorPlayPosToFrame(position); @@ -1157,8 +1185,7 @@ void CueControl::cueClear(double v) { } } -void CueControl::cueGoto(double v) -{ +void CueControl::cueGoto(double v) { if (!v) { return; } @@ -1173,9 +1200,9 @@ void CueControl::cueGoto(double v) seekAbs(cuePoint); } -void CueControl::cueGotoAndPlay(double v) -{ - if (!v) return; +void CueControl::cueGotoAndPlay(double v) { + if (!v) + return; cueGoto(v); QMutexLocker lock(&m_mutex); // Start playing if not already @@ -1189,8 +1216,7 @@ void CueControl::cueGotoAndPlay(double v) } } -void CueControl::cueGotoAndStop(double v) -{ +void CueControl::cueGotoAndStop(double v) { if (!v) { return; } @@ -1205,8 +1231,7 @@ void CueControl::cueGotoAndStop(double v) seekExact(cuePoint); } -void CueControl::cuePreview(double v) -{ +void CueControl::cuePreview(double v) { QMutexLocker lock(&m_mutex); if (v) { @@ -1238,7 +1263,8 @@ void CueControl::cueCDJ(double v) { // If play is pressed while holding cue, the deck is now playing. (Handled in playFromCuePreview().) QMutexLocker lock(&m_mutex); - const auto freely_playing = m_pPlay->toBool() && !getEngineBuffer()->getScratching(); + const auto freely_playing = + m_pPlay->toBool() && !getEngineBuffer()->getScratching(); TrackAt trackAt = getTrackAt(); if (v) { @@ -1273,7 +1299,7 @@ void CueControl::cueCDJ(double v) { // If quantize is enabled, jump to the cue point since it's not // necessarily where we currently are if (m_pQuantizeEnabled->toBool()) { - lock.unlock(); // prevent deadlock. + lock.unlock(); // prevent deadlock. // Enginebuffer will quantize more exactly than we can. seekAbs(m_pCuePoint->get()); } @@ -1348,9 +1374,9 @@ void CueControl::cuePlay(double v) { // If not freely playing (i.e. stopped or platter IS being touched), press to go to cue and stop. // On release, start playing from cue point. - QMutexLocker lock(&m_mutex); - const auto freely_playing = m_pPlay->toBool() && !getEngineBuffer()->getScratching(); + const auto freely_playing = + m_pPlay->toBool() && !getEngineBuffer()->getScratching(); TrackAt trackAt = getTrackAt(); // pressed @@ -1372,12 +1398,12 @@ void CueControl::cuePlay(double v) { // If quantize is enabled, jump to the cue point since it's not // necessarily where we currently are if (m_pQuantizeEnabled->toBool()) { - lock.unlock(); // prevent deadlock. + lock.unlock(); // prevent deadlock. // Enginebuffer will quantize more exactly than we can. seekAbs(m_pCuePoint->get()); } } - } else if (trackAt == TrackAt::Cue){ + } else if (trackAt == TrackAt::Cue) { m_bPreviewing = false; m_pPlay->set(1.0); lock.unlock(); @@ -1434,15 +1460,18 @@ void CueControl::introStartSet(double v) { double outroStart = m_pOutroStartPosition->get(); double outroEnd = m_pOutroEndPosition->get(); if (introEnd != Cue::kNoPosition && position >= introEnd) { - qWarning() << "Trying to place intro start cue on or after intro end cue."; + qWarning() + << "Trying to place intro start cue on or after intro end cue."; return; } if (outroStart != Cue::kNoPosition && position >= outroStart) { - qWarning() << "Trying to place intro start cue on or after outro start cue."; + qWarning() << "Trying to place intro start cue on or after outro start " + "cue."; return; } if (outroEnd != Cue::kNoPosition && position >= outroEnd) { - qWarning() << "Trying to place intro start cue on or after outro end cue."; + qWarning() + << "Trying to place intro start cue on or after outro end cue."; return; } @@ -1510,15 +1539,18 @@ void CueControl::introEndSet(double v) { double outroStart = m_pOutroStartPosition->get(); double outroEnd = m_pOutroEndPosition->get(); if (introStart != Cue::kNoPosition && position <= introStart) { - qWarning() << "Trying to place intro end cue on or before intro start cue."; + qWarning() << "Trying to place intro end cue on or before intro start " + "cue."; return; } if (outroStart != Cue::kNoPosition && position >= outroStart) { - qWarning() << "Trying to place intro end cue on or after outro start cue."; + qWarning() + << "Trying to place intro end cue on or after outro start cue."; return; } if (outroEnd != Cue::kNoPosition && position >= outroEnd) { - qWarning() << "Trying to place intro end cue on or after outro end cue."; + qWarning() + << "Trying to place intro end cue on or after outro end cue."; return; } @@ -1586,15 +1618,18 @@ void CueControl::outroStartSet(double v) { double introEnd = m_pIntroEndPosition->get(); double outroEnd = m_pOutroEndPosition->get(); if (introStart != Cue::kNoPosition && position <= introStart) { - qWarning() << "Trying to place outro start cue on or before intro start cue."; + qWarning() << "Trying to place outro start cue on or before intro " + "start cue."; return; } if (introEnd != Cue::kNoPosition && position <= introEnd) { - qWarning() << "Trying to place outro start cue on or before intro end cue."; + qWarning() << "Trying to place outro start cue on or before intro end " + "cue."; return; } if (outroEnd != Cue::kNoPosition && position >= outroEnd) { - qWarning() << "Trying to place outro start cue on or after outro end cue."; + qWarning() + << "Trying to place outro start cue on or after outro end cue."; return; } @@ -1662,15 +1697,18 @@ void CueControl::outroEndSet(double v) { double introEnd = m_pIntroEndPosition->get(); double outroStart = m_pOutroStartPosition->get(); if (introStart != Cue::kNoPosition && position <= introStart) { - qWarning() << "Trying to place outro end cue on or before intro start cue."; + qWarning() << "Trying to place outro end cue on or before intro start " + "cue."; return; } if (introEnd != Cue::kNoPosition && position <= introEnd) { - qWarning() << "Trying to place outro end cue on or before intro end cue."; + qWarning() + << "Trying to place outro end cue on or before intro end cue."; return; } if (outroStart != Cue::kNoPosition && position <= outroStart) { - qWarning() << "Trying to place outro end cue on or before outro start cue."; + qWarning() << "Trying to place outro end cue on or before outro start " + "cue."; return; } @@ -1723,15 +1761,14 @@ void CueControl::outroEndActivate(double v) { } } -bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) { +bool CueControl::updateIndicatorsAndModifyPlay( + bool newPlay, bool playPossible) { //qDebug() << "updateIndicatorsAndModifyPlay" << newPlay << playPossible // << m_iCurrentlyPreviewingHotcues << m_bPreviewing; 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) { + if ((cueMode == CueMode::Denon || cueMode == CueMode::Numark) && newPlay && + playPossible && !m_pPlay->toBool() && !m_bypassCueSetByPlay) { // in Denon mode each play from pause moves the cue point // if not previewing cueSet(1.0); @@ -1771,9 +1808,11 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) m_pPlayIndicator->setBlinkValue(ControlIndicator::OFF); } else { // Flashing indicates that a following play would move cue point - m_pPlayIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_500MS); + m_pPlayIndicator->setBlinkValue( + ControlIndicator::RATIO1TO1_500MS); } - } else if (cueMode == CueMode::Mixxx || cueMode == CueMode::MixxxNoBlinking || + } else if (cueMode == CueMode::Mixxx || + cueMode == CueMode::MixxxNoBlinking || cueMode == CueMode::Numark) { m_pPlayIndicator->setBlinkValue(ControlIndicator::OFF); } else { @@ -1787,12 +1826,14 @@ bool CueControl::updateIndicatorsAndModifyPlay(bool newPlay, bool playPossible) 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 - m_pCueIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_500MS); + m_pCueIndicator->setBlinkValue( + ControlIndicator::RATIO1TO1_500MS); } 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 - m_pCueIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_250MS); + m_pCueIndicator->setBlinkValue( + ControlIndicator::RATIO1TO1_250MS); } } else { m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); @@ -1826,7 +1867,8 @@ void CueControl::updateIndicators() { if (!playing) { if (trackAt != TrackAt::End && cueMode != CUE_MODE_NUMARK) { // Play will move cue point - m_pPlayIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_500MS); + m_pPlayIndicator->setBlinkValue( + ControlIndicator::RATIO1TO1_500MS); } else { // At track end m_pPlayIndicator->setBlinkValue(ControlIndicator::OFF); @@ -1837,18 +1879,21 @@ void CueControl::updateIndicators() { // Here we have CUE_MODE_PIONEER or CUE_MODE_MIXXX // default to Pioneer mode if (!m_bPreviewing) { - const auto freely_playing = m_pPlay->toBool() && !getEngineBuffer()->getScratching(); + const auto freely_playing = + m_pPlay->toBool() && !getEngineBuffer()->getScratching(); if (!freely_playing) { switch (trackAt) { case TrackAt::ElseWhere: if (cueMode == CUE_MODE_MIXXX) { // in Mixxx mode Cue Button is flashing slow if CUE will move Cue point - m_pCueIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_500MS); + m_pCueIndicator->setBlinkValue( + ControlIndicator::RATIO1TO1_500MS); } else if (cueMode == CUE_MODE_MIXXX_NO_BLINK) { m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); } else { // in Pioneer mode Cue Button is flashing fast if CUE will move Cue point - m_pCueIndicator->setBlinkValue(ControlIndicator::RATIO1TO1_250MS); + m_pCueIndicator->setBlinkValue( + ControlIndicator::RATIO1TO1_250MS); } break; case TrackAt::End: @@ -1943,17 +1988,19 @@ double CueControl::quantizeCuePoint(double cuePos) { } bool CueControl::isTrackAtIntroCue() { - return (fabs(getSampleOfTrack().current - m_pIntroStartPosition->get()) < 1.0f); + return (fabs(getSampleOfTrack().current - m_pIntroStartPosition->get()) < + 1.0f); } bool CueControl::isPlayingByPlayButton() { - return m_pPlay->toBool() && - !m_iCurrentlyPreviewingHotcues && !m_bPreviewing; + return m_pPlay->toBool() && !m_iCurrentlyPreviewingHotcues && + !m_bPreviewing; } SeekOnLoadMode CueControl::getSeekOnLoadPreference() { - int configValue = getConfig()->getValue(ConfigKey("[Controls]", "CueRecall"), - static_cast(SeekOnLoadMode::IntroStart)); + int configValue = + getConfig()->getValue(ConfigKey("[Controls]", "CueRecall"), + static_cast(SeekOnLoadMode::IntroStart)); return static_cast(configValue); } @@ -2035,7 +2082,8 @@ void CueControl::setCurrentSavedLoop(CuePointer pCue) { } if (m_pCurrentSavedLoop) { - qDebug() << "CueControl::setLoop" << pCue->getPosition() << pCue->getEndPosition(); + qDebug() << "CueControl::setLoop" << pCue->getPosition() + << pCue->getEndPosition(); setLoop(pCue->getPosition(), pCue->getEndPosition(), true); pCue->activate(); } @@ -2074,7 +2122,8 @@ ConfigKey HotcueControl::keyForControl(int hotcue, const char* name) { ConfigKey key; key.group = m_group; // Add one to hotcue so that we don't have a hotcue_0 - key.item = QLatin1String("hotcue_") % QString::number(hotcue+1) % "_" % name; + key.item = + QLatin1String("hotcue_") % QString::number(hotcue + 1) % "_" % name; return key; } @@ -2085,16 +2134,20 @@ HotcueControl::HotcueControl(QString group, int i) m_previewingType(mixxx::CueType::Invalid), m_previewingPosition(-1) { m_hotcuePosition = new ControlObject(keyForControl(i, "position")); - connect(m_hotcuePosition, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcuePositionChanged, + connect(m_hotcuePosition, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcuePositionChanged, Qt::DirectConnection); m_hotcuePosition->set(Cue::kNoPosition); - m_hotcueLength = new ControlObject(keyForControl(i, "length")); - connect(m_hotcueLength, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcueLengthChanged, + m_hotcueEndPosition = new ControlObject(keyForControl(i, "endposition")); + connect(m_hotcueEndPosition, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueEndPositionChanged, Qt::DirectConnection); - m_hotcueLength->set(-1); + m_hotcueEndPosition->set(Cue::kNoPosition); m_hotcueEnabled = new ControlObject(keyForControl(i, "enabled")); m_hotcueEnabled->setReadOnly(); @@ -2188,7 +2241,7 @@ HotcueControl::HotcueControl(QString group, int i) HotcueControl::~HotcueControl() { delete m_hotcuePosition; - delete m_hotcueLength; + delete m_hotcueEndPosition; delete m_hotcueEnabled; delete m_hotcueType; delete m_hotcueColor; @@ -2263,8 +2316,8 @@ void HotcueControl::slotHotcuePositionChanged(double newPosition) { emit hotcuePositionChanged(this, newPosition); } -void HotcueControl::slotHotcueLengthChanged(double newLength) { - emit hotcueLengthChanged(this, newLength); +void HotcueControl::slotHotcueEndPositionChanged(double newEndPosition) { + emit hotcueEndPositionChanged(this, newEndPosition); } void HotcueControl::slotHotcueTypeChanged(double newType) { @@ -2297,13 +2350,13 @@ double HotcueControl::getPosition() const { return m_hotcuePosition->get(); } -double HotcueControl::getLength() const { - return m_hotcueLength->get(); +double HotcueControl::getEndPosition() const { + return m_hotcueEndPosition->get(); } void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); - setLength(pCue->getLength()); + setEndPosition(pCue->getEndPosition()); setColor(pCue->getColor()); setStatus(pCue->getStatus()); // set pCue only if all other data is in place @@ -2324,7 +2377,7 @@ void HotcueControl::resetCue() { // in the code m_pCue.reset(); setPosition(Cue::kNoPosition); - setLength(0.0); + setEndPosition(Cue::kNoPosition); setType(mixxx::CueType::Invalid); setStatus(mixxx::CueStatus::Invalid); } @@ -2333,8 +2386,8 @@ void HotcueControl::setPosition(double position) { m_hotcuePosition->set(position); } -void HotcueControl::setLength(double length) { - m_hotcueLength->set(length); +void HotcueControl::setEndPosition(double endPosition) { + m_hotcueEndPosition->set(endPosition); } void HotcueControl::setType(mixxx::CueType type) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 4da4af454f73..b9efa46a8c3d 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -58,11 +58,11 @@ class HotcueControl : public QObject { inline int getHotcueNumber() { return m_iHotcueNumber; } inline CuePointer getCue() { return m_pCue; } double getPosition() const; - double getLength() const; + double getEndPosition() const; void setCue(CuePointer pCue); void resetCue(); void setPosition(double position); - void setLength(double length); + void setEndPosition(double endPosition); void setType(mixxx::CueType type); void setStatus(mixxx::CueStatus status); void setColor(mixxx::RgbColor::optional_t newColor); @@ -96,7 +96,7 @@ class HotcueControl : public QObject { void slotHotcueActivateLoop(double v); void slotHotcueActivatePreview(double v); void slotHotcueClear(double v); - void slotHotcueLengthChanged(double newPosition); + void slotHotcueEndPositionChanged(double newPosition); void slotHotcuePositionChanged(double newPosition); void slotHotcueTypeChanged(double newType); void slotHotcueColorChangeRequest(double newColor); @@ -113,7 +113,7 @@ class HotcueControl : public QObject { void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); void hotcuePositionChanged(HotcueControl* pHotcue, double newPosition); - void hotcueLengthChanged(HotcueControl* pHotcue, double newLength); + void hotcueEndPositionChanged(HotcueControl* pHotcue, double newEndPosition); void hotcueTypeChanged(HotcueControl* pHotcue, double newType); void hotcueColorChanged(HotcueControl* pHotcue, double newColor); void hotcuePlay(double v); @@ -127,7 +127,7 @@ class HotcueControl : public QObject { // Hotcue state controls ControlObject* m_hotcuePosition; - ControlObject* m_hotcueLength; + ControlObject* m_hotcueEndPosition; ControlObject* m_hotcueEnabled; ControlObject* m_hotcueType; ControlObject* m_hotcueColor; @@ -189,7 +189,7 @@ class CueControl : public EngineControl { void hotcueActivatePreview(HotcueControl* pControl, double v); void hotcueClear(HotcueControl* pControl, double v); void hotcuePositionChanged(HotcueControl* pControl, double newPosition); - void hotcueLengthChanged(HotcueControl* pControl, double newLength); + void hotcueEndPositionChanged(HotcueControl* pControl, double newEndPosition); void hotcueTypeChanged(HotcueControl* pControl, double newType); void hotcueFocusColorNext(double v); diff --git a/src/waveform/renderers/waveformmark.cpp b/src/waveform/renderers/waveformmark.cpp index 2ae0b74fdff2..3eb7b0aab8ad 100644 --- a/src/waveform/renderers/waveformmark.cpp +++ b/src/waveform/renderers/waveformmark.cpp @@ -57,25 +57,25 @@ WaveformMark::WaveformMark(const QString& group, int hotCue) : m_iHotCue(hotCue) { QString positionControl; - QString lengthControl; + QString endPositionControl; if (hotCue != Cue::kNoHotCue) { positionControl = "hotcue_" + QString::number(hotCue + 1) + "_position"; - lengthControl = "hotcue_" + QString::number(hotCue + 1) + "_length"; + endPositionControl = "hotcue_" + QString::number(hotCue + 1) + "_endposition"; } else { positionControl = context.selectString(node, "Control"); } if (!positionControl.isEmpty()) { - m_pPointCos = std::make_unique(group, positionControl); + m_pPositionCO = std::make_unique(group, positionControl); } - if (!lengthControl.isEmpty()) { - m_pLengthCos = std::make_unique(group, lengthControl); + if (!endPositionControl.isEmpty()) { + m_pEndPositionCO = std::make_unique(group, endPositionControl); } QString visibilityControl = context.selectString(node, "VisibilityControl"); if (!visibilityControl.isEmpty()) { ConfigKey key = ConfigKey::parseCommaSeparated(visibilityControl); - m_pVisibleCos = std::make_unique(key); + m_pVisibleCO = std::make_unique(key); } QColor color(context.selectString(node, "Color")); diff --git a/src/waveform/renderers/waveformmark.h b/src/waveform/renderers/waveformmark.h index 280b839935a1..4a44c6905708 100644 --- a/src/waveform/renderers/waveformmark.h +++ b/src/waveform/renderers/waveformmark.h @@ -30,40 +30,48 @@ class WaveformMark { int getHotCue() const { return m_iHotCue; }; - //The m_pPointCos related function - bool isValid() const { return m_pPointCos && m_pPointCos->valid(); } + //The m_pPositionCO related function + bool isValid() const { + return m_pPositionCO && m_pPositionCO->valid(); + } template void connectSamplePositionChanged(Receiver receiver, Slot slot) const { - m_pPointCos->connectValueChanged(receiver, slot, Qt::AutoConnection); + m_pPositionCO->connectValueChanged(receiver, slot, Qt::AutoConnection); }; - template - void connectSampleLengthChanged(Receiver receiver, Slot slot) const { - if (m_pLengthCos) { - m_pLengthCos->connectValueChanged(receiver, slot, Qt::AutoConnection); + template + void connectSampleEndPositionChanged(Receiver receiver, Slot slot) const { + if (m_pEndPositionCO) { + m_pEndPositionCO->connectValueChanged(receiver, slot, Qt::AutoConnection); } }; - double getSamplePosition() const { return m_pPointCos->get(); } - double getSampleLength() const { - if (m_pLengthCos) { - return m_pLengthCos->get(); + double getSamplePosition() const { + return m_pPositionCO->get(); + } + double getSampleEndPosition() const { + if (m_pEndPositionCO) { + return m_pEndPositionCO->get(); } - return 0; + return Cue::kNoPosition; + } + QString getItem() const { + return m_pPositionCO->getKey().item; } - QString getItem() const { return m_pPointCos->getKey().item; } - // The m_pVisibleCos related function - bool hasVisible() const { return m_pVisibleCos && m_pVisibleCos->valid(); } + // The m_pVisibleCO related function + bool hasVisible() const { + return m_pVisibleCO && m_pVisibleCO->valid(); + } bool isVisible() const { if (!hasVisible()) { return true; } - return m_pVisibleCos->get(); + return m_pVisibleCO->get(); } template void connectVisibleChanged(Receiver receiver, Slot slot) const { - m_pVisibleCos->connectValueChanged(receiver, slot, Qt::AutoConnection); + m_pVisibleCO->connectValueChanged(receiver, slot, Qt::AutoConnection); } // Sets the appropriate mark colors based on the base color @@ -91,9 +99,9 @@ class WaveformMark { WaveformMarkLabel m_label; private: - std::unique_ptr m_pPointCos; - std::unique_ptr m_pLengthCos; - std::unique_ptr m_pVisibleCos; + std::unique_ptr m_pPositionCO; + std::unique_ptr m_pEndPositionCO; + std::unique_ptr m_pVisibleCO; int m_iHotCue; QImage m_image; diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index fc586f615308..eb67ec30d4cd 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -58,10 +58,10 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { } double samplePosition = pMark->getSamplePosition(); - if (samplePosition != -1.0) { + if (samplePosition != Cue::kNoPosition) { double currentMarkPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(samplePosition); - double sampleLength = pMark->getSampleLength(); + double sampleEndPosition = pMark->getSampleEndPosition(); if (m_waveformRenderer->getOrientation() == Qt::Horizontal) { // NOTE: vRince I guess image width is odd to display the center on the exact line ! // external image should respect that ... @@ -72,11 +72,19 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { if (currentMarkPoint > -markHalfWidth && currentMarkPoint < m_waveformRenderer->getWidth() + markHalfWidth) { int drawOffset = currentMarkPoint - markHalfWidth; painter->drawImage(QPoint(drawOffset, 0), pMark->m_image); - if (sampleLength > 0) { - double currentMarkEndPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(samplePosition + sampleLength); - painter->fillRect(QRect( - QPoint(currentMarkPoint, m_waveformRenderer->getHeight() - 5), - QPoint(currentMarkEndPoint, m_waveformRenderer->getHeight())), + if (sampleEndPosition != Cue::kNoPosition) { + DEBUG_ASSERT(samplePosition < sampleEndPosition); + double currentMarkEndPoint = + m_waveformRenderer + ->transformSamplePositionInRendererWorld( + sampleEndPosition); + painter->fillRect( + QRect(QPoint(currentMarkPoint, + m_waveformRenderer->getHeight() - + 5), + QPoint(currentMarkEndPoint, + m_waveformRenderer + ->getHeight())), pMark->fillColor()); } marksOnScreen[pMark] = drawOffset; @@ -89,8 +97,12 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { markHalfHeight) { int drawOffset = currentMarkPoint - markHalfHeight; painter->drawImage(QPoint(0, drawOffset), pMark->m_image); - if (sampleLength > 0) { - double currentMarkEndPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(samplePosition + sampleLength); + if (sampleEndPosition != Cue::kNoPosition) { + DEBUG_ASSERT(samplePosition < sampleEndPosition); + double currentMarkEndPoint = + m_waveformRenderer + ->transformSamplePositionInRendererWorld( + sampleEndPosition); painter->fillRect(QRect( QPoint(m_waveformRenderer->getWidth() - 5, currentMarkPoint), QPoint(m_waveformRenderer->getWidth(), currentMarkEndPoint)), diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index 7df77da82c51..1ef7060a7129 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -161,7 +161,7 @@ void WOverview::setup(const QDomNode& node, const SkinContext& context) { if (pMark->isValid()) { pMark->connectSamplePositionChanged(this, &WOverview::onMarkChanged); - pMark->connectSampleLengthChanged(this, + pMark->connectSampleEndPositionChanged(this, &WOverview::onMarkChanged); } if (pMark->hasVisible()) { @@ -802,10 +802,10 @@ void WOverview::drawMarks(QPainter* pPainter, const float offset, const float ga } QRectF rect; - double sampleLength = m_marksToRender.at(i)->getSampleLength(); - if (sampleLength > 0) { + double sampleEndPosition = m_marksToRender.at(i)->getSampleEndPosition(); + if (sampleEndPosition > 0) { const qreal markEndPosition = math_clamp( - offset + (samplePosition + sampleLength) * gain, + offset + sampleEndPosition * gain, 0.0, static_cast(width())); From 78650e240786700f6b15b7894372cae45a5bf464 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 16 Jul 2020 14:21:28 +0200 Subject: [PATCH 063/153] engine/controls/cuecontrol: Set hotcue type CO on cue load --- src/engine/controls/cuecontrol.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 33a188a6f698..92d24c2a1f82 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2359,6 +2359,7 @@ void HotcueControl::setCue(CuePointer pCue) { setEndPosition(pCue->getEndPosition()); setColor(pCue->getColor()); setStatus(pCue->getStatus()); + setType(pCue->getType()); // set pCue only if all other data is in place // because we have a null check for valid data else where in the code m_pCue = pCue; From b169407e0e019e906a040feb988d4eae3b8a8630 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 16 Jul 2020 14:21:15 +0200 Subject: [PATCH 064/153] engine/controls/cuecontrol: Remove code to change hotcue type via CO This is currently not needed. We just make the CO read-only because otherwise this would need a lot more checks. --- src/engine/controls/cuecontrol.cpp | 31 ++---------------------------- src/engine/controls/cuecontrol.h | 3 --- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 92d24c2a1f82..b1cc58a0ba1a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1107,25 +1107,6 @@ void CueControl::hotcueEndPositionChanged( } } -void CueControl::hotcueTypeChanged(HotcueControl* pControl, double newType) { - QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) - return; - - CuePointer pCue(pControl->getCue()); - if (pCue) { - // Setting the type to 0 or -1 is the same as calling hotcue_x_clear - int iType = static_cast(newType); - if (iType <= 0 || - iType > static_cast(mixxx::CueType::AudibleSound)) { - pCue->setHotCue(Cue::kNoHotCue); - detachCue(pControl); - } else { - pCue->setType(static_cast(iType)); - } - } -} - void CueControl::hintReader(HintVector* pHintList) { Hint cue_hint; double cuePoint = m_pCuePoint->get(); @@ -2153,11 +2134,7 @@ HotcueControl::HotcueControl(QString group, int i) m_hotcueEnabled->setReadOnly(); m_hotcueType = new ControlObject(keyForControl(i, "type")); - connect(m_hotcueType, - &ControlObject::valueChanged, - this, - &HotcueControl::slotHotcueTypeChanged, - Qt::DirectConnection); + m_hotcueType->setReadOnly(); // The rgba value of the color assigned to this color. m_hotcueColor = new ControlObject(keyForControl(i, "color")); @@ -2320,10 +2297,6 @@ void HotcueControl::slotHotcueEndPositionChanged(double newEndPosition) { emit hotcueEndPositionChanged(this, newEndPosition); } -void HotcueControl::slotHotcueTypeChanged(double newType) { - emit hotcueTypeChanged(this, newType); -} - void HotcueControl::slotHotcueColorChangeRequest(double color) { if (color < 0 || color > 0xFFFFFF) { qWarning() << "slotHotcueColorChanged got invalid value:" << color; @@ -2392,7 +2365,7 @@ void HotcueControl::setEndPosition(double endPosition) { } void HotcueControl::setType(mixxx::CueType type) { - m_hotcueType->set(static_cast(type)); + m_hotcueType->forceSet(static_cast(type)); } void HotcueControl::setStatus(mixxx::CueStatus status) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index b9efa46a8c3d..260f4b7961f6 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -98,7 +98,6 @@ class HotcueControl : public QObject { void slotHotcueClear(double v); void slotHotcueEndPositionChanged(double newPosition); void slotHotcuePositionChanged(double newPosition); - void slotHotcueTypeChanged(double newType); void slotHotcueColorChangeRequest(double newColor); void slotHotcueColorChanged(double newColor); @@ -114,7 +113,6 @@ class HotcueControl : public QObject { void hotcueClear(HotcueControl* pHotcue, double v); void hotcuePositionChanged(HotcueControl* pHotcue, double newPosition); void hotcueEndPositionChanged(HotcueControl* pHotcue, double newEndPosition); - void hotcueTypeChanged(HotcueControl* pHotcue, double newType); void hotcueColorChanged(HotcueControl* pHotcue, double newColor); void hotcuePlay(double v); @@ -190,7 +188,6 @@ class CueControl : public EngineControl { void hotcueClear(HotcueControl* pControl, double v); void hotcuePositionChanged(HotcueControl* pControl, double newPosition); void hotcueEndPositionChanged(HotcueControl* pControl, double newEndPosition); - void hotcueTypeChanged(HotcueControl* pControl, double newType); void hotcueFocusColorNext(double v); void hotcueFocusColorPrev(double v); From 57f15681e83d37783819256496f3d0e5913a9d7c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 16 Jul 2020 14:56:02 +0200 Subject: [PATCH 065/153] engine/controls/cuecontrol: Add missing braces to guard clauses --- src/engine/controls/cuecontrol.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index b1cc58a0ba1a..d55b0be1c227 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -520,8 +520,9 @@ void CueControl::loadCuesFromTrack() { QSet active_hotcues; CuePointer pLoadCue, pIntroCue, pOutroCue; - if (!m_pLoadedTrack) + if (!m_pLoadedTrack) { return; + } for (const CuePointer& pCue : m_pLoadedTrack->getCuePoints()) { switch (pCue->getType()) { @@ -694,8 +695,9 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { } QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) + if (!m_pLoadedTrack) { return; + } int hotcue = pControl->getHotcueNumber(); // Note: the cue is just detached from the hotcue control @@ -806,8 +808,9 @@ void CueControl::hotcueGotoAndStop(HotcueControl* pControl, double v) { } QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) + if (!m_pLoadedTrack) { return; + } CuePointer pCue(pControl->getCue()); @@ -1069,8 +1072,9 @@ void CueControl::hotcueClear(HotcueControl* pControl, double v) { void CueControl::hotcuePositionChanged( HotcueControl* pControl, double newPosition) { QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) + if (!m_pLoadedTrack) { return; + } CuePointer pCue(pControl->getCue()); if (pCue) { @@ -1182,8 +1186,10 @@ void CueControl::cueGoto(double v) { } void CueControl::cueGotoAndPlay(double v) { - if (!v) + if (!v) { return; + } + cueGoto(v); QMutexLocker lock(&m_mutex); // Start playing if not already From 58f9666f11d525dba75d81511d499c34d156378c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 16 Jul 2020 17:32:21 +0200 Subject: [PATCH 066/153] engine/controls/cuecontrol: Move loop status tracking into HotcueControl --- src/engine/controls/cuecontrol.cpp | 94 +++++++++++++++++++----------- src/engine/controls/cuecontrol.h | 13 ++++- src/track/cue.cpp | 49 ---------------- src/track/cue.h | 6 -- src/track/cueinfo.h | 6 -- 5 files changed, 70 insertions(+), 98 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index d55b0be1c227..124a878ba98a 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -43,6 +43,13 @@ inline mixxx::RgbColor::optional_t doubleToRgbColor(double value) { return mixxx::RgbColor::optional(colorCode); } +inline HotcueControl::Status hotcueControlStatusFromCue(CuePointer pCue) { + if (pCue && pCue->getType() != mixxx::CueType::Invalid) { + return HotcueControl::Status::Valid; + } + return HotcueControl::Status::Invalid; +} + } // namespace CueControl::CueControl(QString group, @@ -57,6 +64,7 @@ CueControl::CueControl(QString group, m_bypassCueSetByPlay(false), m_iNumHotCues(NUM_HOT_CUES), m_pLoadedTrack(), + m_pCurrentSavedLoopControl(nullptr), m_mutex(QMutex::Recursive) { // To silence a compiler warning about CUE_MODE_PIONEER. Q_UNUSED(CUE_MODE_PIONEER); @@ -73,7 +81,6 @@ CueControl::CueControl(QString group, m_pLoopStartPosition = make_parented(group, "loop_start_position", this); m_pLoopEndPosition = make_parented(group, "loop_end_position", this); m_pLoopEnabled = make_parented(group, "loop_enabled", this); - m_pLoopToggle = make_parented(group, "loop_toggle", this); m_pBeatLoopActivate = make_parented(group, "beatloop_activate", this); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); @@ -564,7 +571,7 @@ void CueControl::loadCuesFromTrack() { pControl->setEndPosition(pCue->getEndPosition()); pControl->setColor(pCue->getColor()); pControl->setType(pCue->getType()); - pControl->setStatus(pCue->getStatus()); + pControl->setStatus(hotcueControlStatusFromCue(pCue)); } // Add the hotcue to the list of active hotcues active_hotcues.insert(hotcue); @@ -765,7 +772,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { } if (cueType == mixxx::CueType::Loop) { - setCurrentSavedLoop(pCue); + setCurrentSavedLoopControl(pControl); } // If quantize is enabled and we are not playing, jump to the cue point @@ -884,7 +891,7 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { if (pCue->getType() == mixxx::CueType::Loop) { hotcueGoto(pControl, v); - setCurrentSavedLoop(pCue); + setCurrentSavedLoopControl(pControl); } else if (pCue->getType() == mixxx::CueType::HotCue) { hotcueGoto(pControl, v); setBeatLoop(pCue->getPosition(), true); @@ -924,16 +931,15 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { switch (pCue->getType()) { case mixxx::CueType::Loop: { - bool enabled; - if (m_pCurrentSavedLoop != pCue) { - setCurrentSavedLoop(pCue); + if (m_pCurrentSavedLoopControl != pControl) { + setCurrentSavedLoopControl(pControl); } else { - enabled = !pCue->isActive(); - setLoop(pCue->getPosition(), pCue->getEndPosition(), enabled); + bool loopActive = !(pControl->getStatus() == HotcueControl::Status::Active); + setLoop(pCue->getPosition(), pCue->getEndPosition(), loopActive); } } break; case mixxx::CueType::HotCue: { - setCurrentSavedLoop(CuePointer()); + setCurrentSavedLoopControl(nullptr); double startPosition = pCue->getPosition(); bool enabled = startPosition != m_pLoopStartPosition->get() || !m_pLoopEnabled->get(); @@ -1018,7 +1024,7 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { pControl->setPreviewingType(pCue->getType()); pControl->setPreviewingPosition(position); if (pCue->getType() == mixxx::CueType::Loop) { - setCurrentSavedLoop(pCue); + setCurrentSavedLoopControl(pControl); } // Need to unlock before emitting any signals to prevent deadlock. @@ -2049,60 +2055,76 @@ void CueControl::hotcueFocusColorNext(double v) { pCue->setColor(colorPalette.nextColor(*color)); } -void CueControl::setCurrentSavedLoop(CuePointer pCue) { - if (m_pCurrentSavedLoop != pCue) { - if (m_pCurrentSavedLoop) { - m_pCurrentSavedLoop->deactivate(); - } +void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { + if (m_pCurrentSavedLoopControl && m_pCurrentSavedLoopControl != pControl) { + // Disable previous saved loop + m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Valid); + m_pCurrentSavedLoopControl = nullptr; + } - if (!pCue) { - m_pCurrentSavedLoop.reset(); + // Set new control as active + if (pControl) { + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) { return; } - VERIFY_OR_DEBUG_ASSERT(pCue->getType() == mixxx::CueType::Loop && + CuePointer pCue(pControl->getCue()); + + // Need to unlock before emitting any signals to prevent deadlock. + lock.unlock(); + + VERIFY_OR_DEBUG_ASSERT(pCue && + pCue->getType() == mixxx::CueType::Loop && pCue->getEndPosition() != Cue::kNoPosition) { return; } - m_pCurrentSavedLoop = pCue; - } - - if (m_pCurrentSavedLoop) { + m_pCurrentSavedLoopControl = pControl; qDebug() << "CueControl::setLoop" << pCue->getPosition() << pCue->getEndPosition(); setLoop(pCue->getPosition(), pCue->getEndPosition(), true); - pCue->activate(); + pControl->setStatus(HotcueControl::Status::Active); } } void CueControl::slotLoopReset() { - setCurrentSavedLoop(CuePointer()); + setCurrentSavedLoopControl(nullptr); } void CueControl::slotLoopToggled(bool enabled) { - if (!m_pCurrentSavedLoop) { + if (!m_pCurrentSavedLoopControl) { return; } if (enabled) { - m_pCurrentSavedLoop->activate(); + m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Active); } else { - m_pCurrentSavedLoop->deactivate(); + m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Valid); } } void CueControl::slotLoopUpdated(double startPosition, double endPosition) { - if (!m_pCurrentSavedLoop) { + if (!m_pCurrentSavedLoopControl) { return; } + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) { + return; + } + + CuePointer pCue(m_pCurrentSavedLoopControl->getCue()); + + // Need to unlock before emitting any signals to prevent deadlock. + lock.unlock(); + DEBUG_ASSERT(startPosition != Cue::kNoPosition); DEBUG_ASSERT(endPosition != Cue::kNoPosition); DEBUG_ASSERT(startPosition < endPosition); - m_pCurrentSavedLoop->setStartPosition(startPosition); - m_pCurrentSavedLoop->setEndPosition(endPosition); + pCue->setStartPosition(startPosition); + pCue->setEndPosition(endPosition); } ConfigKey HotcueControl::keyForControl(int hotcue, const char* name) { @@ -2337,7 +2359,7 @@ void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); setEndPosition(pCue->getEndPosition()); setColor(pCue->getColor()); - setStatus(pCue->getStatus()); + setStatus(hotcueControlStatusFromCue(pCue)); setType(pCue->getType()); // set pCue only if all other data is in place // because we have a null check for valid data else where in the code @@ -2359,7 +2381,7 @@ void HotcueControl::resetCue() { setPosition(Cue::kNoPosition); setEndPosition(Cue::kNoPosition); setType(mixxx::CueType::Invalid); - setStatus(mixxx::CueStatus::Invalid); + setStatus(Status::Invalid); } void HotcueControl::setPosition(double position) { @@ -2374,6 +2396,10 @@ void HotcueControl::setType(mixxx::CueType type) { m_hotcueType->forceSet(static_cast(type)); } -void HotcueControl::setStatus(mixxx::CueStatus status) { +void HotcueControl::setStatus(HotcueControl::Status status) { m_hotcueEnabled->forceSet(static_cast(status)); } + +HotcueControl::Status HotcueControl::getStatus() { + return static_cast(m_hotcueEnabled->get()); +} diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 260f4b7961f6..27de9e6d1657 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -52,6 +52,12 @@ inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { class HotcueControl : public QObject { Q_OBJECT public: + enum class Status { + Invalid = 0, + Valid = 1, + Active = 2, + }; + HotcueControl(QString group, int hotcueNumber); ~HotcueControl() override; @@ -64,7 +70,8 @@ class HotcueControl : public QObject { void setPosition(double position); void setEndPosition(double endPosition); void setType(mixxx::CueType type); - void setStatus(mixxx::CueStatus status); + void setStatus(HotcueControl::Status status); + HotcueControl::Status getStatus(); void setColor(mixxx::RgbColor::optional_t newColor); mixxx::RgbColor::optional_t getColor() const; @@ -229,7 +236,7 @@ class CueControl : public EngineControl { void createControls(); void attachCue(CuePointer pCue, HotcueControl* pControl); void detachCue(HotcueControl* pControl); - void setCurrentSavedLoop(CuePointer pCue); + void setCurrentSavedLoopControl(HotcueControl* pControl); void loadCuesFromTrack(); double quantizeCuePoint(double position); double getQuantizedCurrentPosition(); @@ -303,7 +310,7 @@ class CueControl : public EngineControl { ControlObject* m_pHotcueFocusColorPrev; TrackPointer m_pLoadedTrack; // is written from an engine worker thread - CuePointer m_pCurrentSavedLoop; + HotcueControl* m_pCurrentSavedLoopControl; // Tells us which controls map to which hotcue QMap m_controlMap; diff --git a/src/track/cue.cpp b/src/track/cue.cpp index c22c9f942266..96d0365f6416 100644 --- a/src/track/cue.cpp +++ b/src/track/cue.cpp @@ -49,7 +49,6 @@ void CuePointer::deleteLater(Cue* pCue) { Cue::Cue() : m_bDirty(false), - m_bActive(false), m_iId(-1), m_type(mixxx::CueType::Invalid), m_sampleStartPosition(Cue::kNoPosition), @@ -68,7 +67,6 @@ Cue::Cue( QString label, mixxx::RgbColor color) : m_bDirty(false), - m_bActive(false), m_iId(id), m_trackId(trackId), m_type(type), @@ -170,53 +168,6 @@ void Cue::setType(mixxx::CueType type) { emit updated(); } -mixxx::CueStatus Cue::getStatus() const { - mixxx::CueStatus status = mixxx::CueStatus::Invalid; - switch(getType()) { - case mixxx::CueType::Loop: - if (getPosition() != Cue::kNoPosition && getLength() > 0) { - status = mixxx::CueStatus::Valid; - } - break; - default: - if (getPosition() != Cue::kNoPosition) { - status = mixxx::CueStatus::Valid; - } - break; - } - - if (status == mixxx::CueStatus::Valid && isActive()) { - status = mixxx::CueStatus::Active; - } - - return status; -} - -bool Cue::isActive() const { - QMutexLocker lock(&m_mutex); - return m_bActive; -} - -void Cue::activate() { - QMutexLocker lock(&m_mutex); - bool changed = !m_bActive; - m_bActive = true; - lock.unlock(); - if (changed) { - emit(updated()); - } -} - -void Cue::deactivate() { - QMutexLocker lock(&m_mutex); - bool changed = m_bActive; - m_bActive = false; - lock.unlock(); - if (changed) { - emit(updated()); - } -} - double Cue::getPosition() const { QMutexLocker lock(&m_mutex); return m_sampleStartPosition; diff --git a/src/track/cue.h b/src/track/cue.h index 83a2d0a09f6b..6a3aeb8def13 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -45,11 +45,6 @@ class Cue : public QObject { mixxx::CueType getType() const; void setType(mixxx::CueType type); - mixxx::CueStatus getStatus() const; - bool isActive() const; - void activate(); - void deactivate(); - double getPosition() const; void setStartPosition( double samplePosition = kNoPosition); @@ -87,7 +82,6 @@ class Cue : public QObject { mutable QMutex m_mutex; bool m_bDirty; - bool m_bActive; int m_iId; TrackId m_trackId; mixxx::CueType m_type; diff --git a/src/track/cueinfo.h b/src/track/cueinfo.h index 48a418a0d084..94e38320f630 100644 --- a/src/track/cueinfo.h +++ b/src/track/cueinfo.h @@ -8,12 +8,6 @@ namespace mixxx { -enum class CueStatus { - Invalid = 0, - Valid = 1, - Active = 2, -}; - enum class CueType { Invalid = 0, HotCue = 1, From 5c6ecb7c5a8e94916036fe5213142ec0a7613878 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 12:31:04 +0200 Subject: [PATCH 067/153] waveform/renderers/waveformrendermark: Improve loop cue waveform display --- src/waveform/renderers/waveformrendermark.cpp | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index eb67ec30d4cd..702751fc5e47 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -75,17 +75,16 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { if (sampleEndPosition != Cue::kNoPosition) { DEBUG_ASSERT(samplePosition < sampleEndPosition); double currentMarkEndPoint = - m_waveformRenderer - ->transformSamplePositionInRendererWorld( - sampleEndPosition); + m_waveformRenderer->transformSamplePositionInRendererWorld( + sampleEndPosition); + QColor color = pMark->fillColor(); + color.setAlphaF(0.5); painter->fillRect( - QRect(QPoint(currentMarkPoint, - m_waveformRenderer->getHeight() - - 5), + QRect(QPoint(currentMarkPoint, 0), QPoint(currentMarkEndPoint, m_waveformRenderer ->getHeight())), - pMark->fillColor()); + QBrush(color, Qt::BDiagPattern)); } marksOnScreen[pMark] = drawOffset; } @@ -103,10 +102,13 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { m_waveformRenderer ->transformSamplePositionInRendererWorld( sampleEndPosition); - painter->fillRect(QRect( - QPoint(m_waveformRenderer->getWidth() - 5, currentMarkPoint), - QPoint(m_waveformRenderer->getWidth(), currentMarkEndPoint)), - pMark->fillColor()); + QColor color = pMark->fillColor(); + color.setAlphaF(0.5); + painter->fillRect( + QRect(QPoint(0, currentMarkPoint), + QPoint(m_waveformRenderer->getWidth(), + currentMarkEndPoint)), + QBrush(color, Qt::BDiagPattern)); } marksOnScreen[pMark] = drawOffset; } From 298c92a89aafb323b6952d2f5dc604d15d69813c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 12:51:46 +0200 Subject: [PATCH 068/153] widget/whotcuebutton: Fix right click menu on active loop cue buttons --- src/widget/whotcuebutton.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/whotcuebutton.cpp b/src/widget/whotcuebutton.cpp index 68241deb3f0f..65c780242c26 100644 --- a/src/widget/whotcuebutton.cpp +++ b/src/widget/whotcuebutton.cpp @@ -70,7 +70,7 @@ void WHotcueButton::setup(const QDomNode& node, const SkinContext& context) { void WHotcueButton::mousePressEvent(QMouseEvent* e) { const bool rightClick = e->button() == Qt::RightButton; if (rightClick) { - if (readDisplayValue() == 1) { + if (readDisplayValue()) { // hot cue is set TrackPointer pTrack = PlayerInfo::instance().getTrackInfo(m_group); if (!pTrack) { From 8b81ca82d41e5c3503e8bd4e6bbf1bf19034f07e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 12:53:34 +0200 Subject: [PATCH 069/153] LateNight: Fix missing WHotcueButton labels of active loops in PaleMoon --- res/skins/LateNight/style_palemoon.qss | 48 +++++++++++++++++--------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/res/skins/LateNight/style_palemoon.qss b/res/skins/LateNight/style_palemoon.qss index a2921434e2fa..63d109dc607b 100644 --- a/res/skins/LateNight/style_palemoon.qss +++ b/res/skins/LateNight/style_palemoon.qss @@ -1736,80 +1736,96 @@ WPushButton#RecButton[displayValue="1"], #Hotcue1 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__1.svg) no-repeat center center; } - #Hotcue1 WPushButton[displayValue="1"] { + #Hotcue1 WPushButton[displayValue="1"], + #Hotcue1 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__1_active.svg) no-repeat center center; } - #Hotcue1 WPushButton[displayValue="1"][dark="true"] { + #Hotcue1 WPushButton[displayValue="1"][dark="true"], + #Hotcue1 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__1_active_dark.svg) no-repeat center center; } #Hotcue2 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__2.svg) no-repeat center center; } - #Hotcue2 WPushButton[displayValue="1"] { + #Hotcue2 WPushButton[displayValue="1"], + #Hotcue2 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__2_active.svg) no-repeat center center; } - #Hotcue2 WPushButton[displayValue="1"][dark="true"] { + #Hotcue2 WPushButton[displayValue="1"][dark="true"], + #Hotcue2 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__2_active_dark.svg) no-repeat center center; } #Hotcue3 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__3.svg) no-repeat center center; } - #Hotcue3 WPushButton[displayValue="1"] { + #Hotcue3 WPushButton[displayValue="1"], + #Hotcue3 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__3_active.svg) no-repeat center center; } - #Hotcue3 WPushButton[displayValue="1"][dark="true"] { + #Hotcue3 WPushButton[displayValue="1"][dark="true"], + #Hotcue3 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__3_active_dark.svg) no-repeat center center; } #Hotcue4 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__4.svg) no-repeat center center; } - #Hotcue4 WPushButton[displayValue="1"] { + #Hotcue4 WPushButton[displayValue="1"], + #Hotcue4 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__4_active.svg) no-repeat center center; } - #Hotcue4 WPushButton[displayValue="1"][dark="true"] { + #Hotcue4 WPushButton[displayValue="1"][dark="true"], + #Hotcue4 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__4_active_dark.svg) no-repeat center center; } #Hotcue5 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__5.svg) no-repeat center center; } - #Hotcue5 WPushButton[displayValue="1"] { + #Hotcue5 WPushButton[displayValue="1"], + #Hotcue5 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__5_active.svg) no-repeat center center; } - #Hotcue5 WPushButton[displayValue="1"][dark="true"] { + #Hotcue5 WPushButton[displayValue="1"][dark="true"], + #Hotcue5 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__5_active_dark.svg) no-repeat center center; } #Hotcue6 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__6.svg) no-repeat center center; } - #Hotcue6 WPushButton[displayValue="1"] { + #Hotcue6 WPushButton[displayValue="1"], + #Hotcue6 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__6_active.svg) no-repeat center center; } - #Hotcue6 WPushButton[displayValue="1"][dark="true"] { + #Hotcue6 WPushButton[displayValue="1"][dark="true"], + #Hotcue6 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__6_active_dark.svg) no-repeat center center; } #Hotcue7 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__7.svg) no-repeat center center; } - #Hotcue7 WPushButton[displayValue="1"] { + #Hotcue7 WPushButton[displayValue="1"], + #Hotcue7 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__7_active.svg) no-repeat center center; } - #Hotcue7 WPushButton[displayValue="1"][dark="true"] { + #Hotcue7 WPushButton[displayValue="1"][dark="true"], + #Hotcue7 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__7_active_dark.svg) no-repeat center center; } #Hotcue8 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__8.svg) no-repeat center center; } - #Hotcue8 WPushButton[displayValue="1"] { + #Hotcue8 WPushButton[displayValue="1"], + #Hotcue8 WPushButton[displayValue="2"] { image: url(skin:/palemoon/buttons/btn__8_active.svg) no-repeat center center; } - #Hotcue8 WPushButton[displayValue="1"][dark="true"] { + #Hotcue8 WPushButton[displayValue="1"][dark="true"], + #Hotcue8 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__8_active_dark.svg) no-repeat center center; } From 9f2eeb4cfafc60a3e260d20574a55d470b84e25c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 13:00:57 +0200 Subject: [PATCH 070/153] engine/controls/cuecontrol: Document HotcueControl::Status enum --- src/engine/controls/cuecontrol.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 27de9e6d1657..28ec916687f6 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -52,9 +52,17 @@ inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { class HotcueControl : public QObject { Q_OBJECT public: + /// Describes the current status of the hotcue enum class Status { + /// Hotuce not set Invalid = 0, + /// Hotcue is set and can be used Valid = 1, + /// Hotcue is currently active (this only applies to Saved Loop cues + /// while their loop is enabled). This status can be used by skins or + /// controller mappings to highlight a currently active saved loop, + /// because resizing or moving the loop will make persistent changed to + /// the cue. Active = 2, }; From 4f3c4753156bf371dce9d5480ab277fec74995ef Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 13:10:47 +0200 Subject: [PATCH 071/153] engine/controls/cuecontrol: Reset saved loop pointer on cue detach --- src/engine/controls/cuecontrol.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 124a878ba98a..a98708fe293f 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -374,11 +374,17 @@ void CueControl::detachCue(HotcueControl* pControl) { VERIFY_OR_DEBUG_ASSERT(pControl) { return; } + CuePointer pCue(pControl->getCue()); if (!pCue) { return; } + disconnect(pCue.get(), 0, this, 0); + + if (m_pCurrentSavedLoopControl == pControl) { + m_pCurrentSavedLoopControl = nullptr; + } pControl->resetCue(); } From 26e1ce624a78eec0434bdd25eff97fb43c8c95c0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 13:12:07 +0200 Subject: [PATCH 072/153] engine/controls/cuecontrol: Reduce nesting in setCurrentSavedLoopControl --- src/engine/controls/cuecontrol.cpp | 38 ++++++++++++++++-------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index a98708fe293f..75211f9e4998 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2069,29 +2069,31 @@ void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { } // Set new control as active - if (pControl) { - QMutexLocker lock(&m_mutex); - if (!m_pLoadedTrack) { - return; - } + if (!pControl) { + return; + } - CuePointer pCue(pControl->getCue()); + QMutexLocker lock(&m_mutex); + if (!m_pLoadedTrack) { + return; + } - // Need to unlock before emitting any signals to prevent deadlock. - lock.unlock(); + CuePointer pCue(pControl->getCue()); - VERIFY_OR_DEBUG_ASSERT(pCue && - pCue->getType() == mixxx::CueType::Loop && - pCue->getEndPosition() != Cue::kNoPosition) { - return; - } + // Need to unlock before emitting any signals to prevent deadlock. + lock.unlock(); - m_pCurrentSavedLoopControl = pControl; - qDebug() << "CueControl::setLoop" << pCue->getPosition() - << pCue->getEndPosition(); - setLoop(pCue->getPosition(), pCue->getEndPosition(), true); - pControl->setStatus(HotcueControl::Status::Active); + VERIFY_OR_DEBUG_ASSERT(pCue && + pCue->getType() == mixxx::CueType::Loop && + pCue->getEndPosition() != Cue::kNoPosition) { + return; } + + m_pCurrentSavedLoopControl = pControl; + qDebug() << "CueControl::setLoop" << pCue->getPosition() + << pCue->getEndPosition(); + setLoop(pCue->getPosition(), pCue->getEndPosition(), true); + pControl->setStatus(HotcueControl::Status::Active); } void CueControl::slotLoopReset() { From abf6d143a6b2fa9cf0da69de1c91613cb5517b19 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 15:44:44 +0200 Subject: [PATCH 073/153] engine/controls/cuecontrol: Fix duplicate space in comment Co-authored-by: Be --- src/engine/controls/cuecontrol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 28ec916687f6..ecff64be3999 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -60,7 +60,7 @@ class HotcueControl : public QObject { Valid = 1, /// Hotcue is currently active (this only applies to Saved Loop cues /// while their loop is enabled). This status can be used by skins or - /// controller mappings to highlight a currently active saved loop, + /// controller mappings to highlight a currently active saved loop, /// because resizing or moving the loop will make persistent changed to /// the cue. Active = 2, From 773a2ae194283505bdac327ce2bbb9fac797c916 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 19 Jul 2020 15:45:17 +0200 Subject: [PATCH 074/153] engine/controls/cuecontrol: Fix typo in comment Co-authored-by: Be --- src/engine/controls/cuecontrol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index ecff64be3999..d1dd7f34c212 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -61,7 +61,7 @@ class HotcueControl : public QObject { /// Hotcue is currently active (this only applies to Saved Loop cues /// while their loop is enabled). This status can be used by skins or /// controller mappings to highlight a currently active saved loop, - /// because resizing or moving the loop will make persistent changed to + /// because resizing or moving the loop will make persistent changes to /// the cue. Active = 2, }; From 29bbc92836806180322ca92393a281088030ae07 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 2 Aug 2020 14:33:17 +0200 Subject: [PATCH 075/153] engine/controls/cuecontrol: Fix leaked control --- src/engine/controls/cuecontrol.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 75211f9e4998..3e7e21d0a217 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2265,6 +2265,7 @@ HotcueControl::~HotcueControl() { delete m_hotcueGotoAndPlay; delete m_hotcueGotoAndStop; delete m_hotcueGotoAndLoop; + delete m_hotcueLoopToggle; delete m_hotcueActivate; delete m_hotcueActivateCue; delete m_hotcueActivateLoop; From 9e1c6066cff1b4d5baa74b82f3141c522c2231af Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 2 Aug 2020 14:34:51 +0200 Subject: [PATCH 076/153] preferences/dialog/dlgprefcolors: Add support for different loop color --- src/engine/controls/cuecontrol.cpp | 23 +++-- src/preferences/dialog/dlgprefcolors.cpp | 109 ++++++++++++++++----- src/preferences/dialog/dlgprefcolors.h | 3 +- src/preferences/dialog/dlgprefcolorsdlg.ui | 36 ++++--- src/util/color/predefinedcolorpalettes.cpp | 3 + src/util/color/predefinedcolorpalettes.h | 1 + 6 files changed, 130 insertions(+), 45 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 3e7e21d0a217..f5d510d91d1c 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -768,13 +768,24 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { // TODO(XXX) deal with spurious signals attachCue(pCue, pControl); - ConfigKey autoHotcueColorsKey("[Controls]", "auto_hotcue_colors"); - if (getConfig()->getValue(autoHotcueColorsKey, false)) { - auto hotcueColorPalette = - m_colorPaletteSettings.getHotcueColorPalette(); - pCue->setColor(hotcueColorPalette.colorForHotcueIndex(hotcue)); + if (cueType == mixxx::CueType::Loop) { + ConfigKey autoLoopColorsKey("[Controls]", "auto_loop_colors"); + if (getConfig()->getValue(autoLoopColorsKey, false)) { + auto hotcueColorPalette = + m_colorPaletteSettings.getHotcueColorPalette(); + pCue->setColor(hotcueColorPalette.colorForHotcueIndex(hotcue)); + } else { + pCue->setColor(mixxx::PredefinedColorPalettes::kDefaultLoopColor); + } } else { - pCue->setColor(mixxx::PredefinedColorPalettes::kDefaultCueColor); + ConfigKey autoHotcueColorsKey("[Controls]", "auto_hotcue_colors"); + if (getConfig()->getValue(autoHotcueColorsKey, false)) { + auto hotcueColorPalette = + m_colorPaletteSettings.getHotcueColorPalette(); + pCue->setColor(hotcueColorPalette.colorForHotcueIndex(hotcue)); + } else { + pCue->setColor(mixxx::PredefinedColorPalettes::kDefaultCueColor); + } } if (cueType == mixxx::CueType::Loop) { diff --git a/src/preferences/dialog/dlgprefcolors.cpp b/src/preferences/dialog/dlgprefcolors.cpp index 715be63c5c94..e03b0b7121b7 100644 --- a/src/preferences/dialog/dlgprefcolors.cpp +++ b/src/preferences/dialog/dlgprefcolors.cpp @@ -17,9 +17,13 @@ namespace { constexpr int kHotcueDefaultColorIndex = -1; +constexpr int kLoopDefaultColorIndex = -1; constexpr QSize kPalettePreviewSize = QSize(108, 16); const ConfigKey kAutoHotcueColorsConfigKey("[Controls]", "auto_hotcue_colors"); +const ConfigKey kAutoLoopColorsConfigKey("[Controls]", "auto_loop_colors"); const ConfigKey kHotcueDefaultColorIndexConfigKey("[Controls]", "HotcueDefaultColorIndex"); +const ConfigKey kLoopDefaultColorIndexConfigKey("[Controls]", "LoopDefaultColorIndex"); + } // anonymous namespace DlgPrefColors::DlgPrefColors( @@ -123,6 +127,24 @@ void DlgPrefColors::slotUpdate() { comboBoxHotcueDefaultColor->setCurrentIndex( hotcueDefaultColorIndex + 1); } + + bool autoLoopColors = m_pConfig->getValue(kAutoLoopColorsConfigKey, false); + if (autoLoopColors) { + comboBoxLoopDefaultColor->setCurrentIndex(0); + } else { + int loopDefaultColorIndex = m_pConfig->getValue( + kLoopDefaultColorIndexConfigKey, kLoopDefaultColorIndex); + if (loopDefaultColorIndex < 0 || + loopDefaultColorIndex >= hotcuePalette.size()) { + loopDefaultColorIndex = + hotcuePalette.size() - 2; // default to second last color + if (loopDefaultColorIndex < 0) { + loopDefaultColorIndex = 0; + } + } + comboBoxLoopDefaultColor->setCurrentIndex( + loopDefaultColorIndex + 1); + } } // Set the default values for all the widgets @@ -135,6 +157,8 @@ void DlgPrefColors::slotResetToDefaults() { .getName()); comboBoxHotcueDefaultColor->setCurrentIndex( mixxx::PredefinedColorPalettes::kDefaultTrackColorPalette.size()); + comboBoxLoopDefaultColor->setCurrentIndex( + mixxx::PredefinedColorPalettes::kDefaultTrackColorPalette.size() - 1); slotApply(); } @@ -171,15 +195,25 @@ void DlgPrefColors::slotApply() { m_colorPaletteSettings.getTrackColorPalette())); } - int index = comboBoxHotcueDefaultColor->currentIndex(); + int hotcueColorIndex = comboBoxHotcueDefaultColor->currentIndex(); - if (index > 0) { + if (hotcueColorIndex > 0) { m_pConfig->setValue(kAutoHotcueColorsConfigKey, false); - m_pConfig->setValue(kHotcueDefaultColorIndexConfigKey, index - 1); + m_pConfig->setValue(kHotcueDefaultColorIndexConfigKey, hotcueColorIndex - 1); } else { m_pConfig->setValue(kAutoHotcueColorsConfigKey, true); m_pConfig->setValue(kHotcueDefaultColorIndexConfigKey, -1); } + + int loopColorIndex = comboBoxLoopDefaultColor->currentIndex(); + + if (loopColorIndex > 0) { + m_pConfig->setValue(kAutoLoopColorsConfigKey, false); + m_pConfig->setValue(kLoopDefaultColorIndexConfigKey, loopColorIndex - 1); + } else { + m_pConfig->setValue(kAutoLoopColorsConfigKey, true); + m_pConfig->setValue(kLoopDefaultColorIndexConfigKey, -1); + } } void DlgPrefColors::slotReplaceCueColorClicked() { @@ -256,33 +290,48 @@ void DlgPrefColors::slotHotcuePaletteIndexChanged(int paletteIndex) { ColorPalette palette = m_colorPaletteSettings.getHotcueColorPalette(paletteName); - int defaultColor = comboBoxHotcueDefaultColor->currentIndex(); + int defaultHotcueColor = comboBoxHotcueDefaultColor->currentIndex(); comboBoxHotcueDefaultColor->clear(); + int defaultLoopColor = comboBoxLoopDefaultColor->currentIndex(); + comboBoxLoopDefaultColor->clear(); + + QIcon paletteIcon = drawHotcueColorByPaletteIcon(paletteName); + comboBoxHotcueDefaultColor->addItem(tr("By hotcue number"), -1); - QIcon icon = drawHotcueColorByPaletteIcon(paletteName); - comboBoxHotcueDefaultColor->setItemIcon(0, icon); + comboBoxHotcueDefaultColor->setItemIcon(0, paletteIcon); + + comboBoxLoopDefaultColor->addItem(tr("By hotcue number"), -1); + comboBoxLoopDefaultColor->setItemIcon(0, paletteIcon); QPixmap pixmap(16, 16); for (int i = 0; i < palette.size(); ++i) { QColor color = mixxx::RgbColor::toQColor(palette.at(i)); - comboBoxHotcueDefaultColor->addItem( - tr("Color") + - QStringLiteral(" ") + - QString::number(i + 1) + - QStringLiteral(": ") + - color.name(), - i); pixmap.fill(color); - comboBoxHotcueDefaultColor->setItemIcon(i + 1, QIcon(pixmap)); + QIcon icon(pixmap); + QString item = tr("Color") + QStringLiteral(" ") + + QString::number(i + 1) + QStringLiteral(": ") + color.name(); + + comboBoxHotcueDefaultColor->addItem(item, i); + comboBoxHotcueDefaultColor->setItemIcon(i + 1, icon); + + comboBoxLoopDefaultColor->addItem(item, i); + comboBoxLoopDefaultColor->setItemIcon(i + 1, icon); } - if (comboBoxHotcueDefaultColor->count() > defaultColor) { - comboBoxHotcueDefaultColor->setCurrentIndex(defaultColor); + if (comboBoxHotcueDefaultColor->count() > defaultHotcueColor) { + comboBoxHotcueDefaultColor->setCurrentIndex(defaultHotcueColor); } else { comboBoxHotcueDefaultColor->setCurrentIndex( comboBoxHotcueDefaultColor->count() - 1); } + + if (comboBoxLoopDefaultColor->count() > defaultLoopColor) { + comboBoxLoopDefaultColor->setCurrentIndex(defaultLoopColor); + } else { + comboBoxLoopDefaultColor->setCurrentIndex( + comboBoxLoopDefaultColor->count() - 1); + } } void DlgPrefColors::slotEditTrackPaletteClicked() { @@ -323,39 +372,49 @@ void DlgPrefColors::openColorPaletteEditor( void DlgPrefColors::trackPaletteUpdated(const QString& trackColors) { QString hotcueColors = comboBoxHotcueColors->currentText(); - int defaultColor = comboBoxHotcueDefaultColor->currentIndex(); + int defaultHotcueColor = comboBoxHotcueDefaultColor->currentIndex(); + int defaultLoopColor = comboBoxLoopDefaultColor->currentIndex(); slotUpdate(); - restoreComboBoxes(hotcueColors, trackColors, defaultColor); + restoreComboBoxes(hotcueColors, trackColors, defaultHotcueColor, defaultLoopColor); } void DlgPrefColors::hotcuePaletteUpdated(const QString& hotcueColors) { QString trackColors = comboBoxTrackColors->currentText(); - int defaultColor = comboBoxHotcueDefaultColor->currentIndex(); + int defaultHotcueColor = comboBoxHotcueDefaultColor->currentIndex(); + int defaultLoopColor = comboBoxLoopDefaultColor->currentIndex(); slotUpdate(); - restoreComboBoxes(hotcueColors, trackColors, defaultColor); + restoreComboBoxes(hotcueColors, trackColors, defaultHotcueColor, defaultLoopColor); } void DlgPrefColors::palettesUpdated() { QString hotcueColors = comboBoxHotcueColors->currentText(); QString trackColors = comboBoxTrackColors->currentText(); - int defaultColor = comboBoxHotcueDefaultColor->currentIndex(); + int defaultHotcueColor = comboBoxHotcueDefaultColor->currentIndex(); + int defaultLoopColor = comboBoxLoopDefaultColor->currentIndex(); slotUpdate(); - restoreComboBoxes(hotcueColors, trackColors, defaultColor); + restoreComboBoxes(hotcueColors, trackColors, defaultHotcueColor, defaultLoopColor); } void DlgPrefColors::restoreComboBoxes( const QString& hotcueColors, const QString& trackColors, - int defaultColor) { + int defaultHotcueColor, + int defaultLoopColor) { comboBoxHotcueColors->setCurrentText(hotcueColors); comboBoxTrackColors->setCurrentText(trackColors); - if (comboBoxHotcueDefaultColor->count() > defaultColor) { - comboBoxHotcueDefaultColor->setCurrentIndex(defaultColor); + if (comboBoxHotcueDefaultColor->count() > defaultHotcueColor) { + comboBoxHotcueDefaultColor->setCurrentIndex(defaultHotcueColor); } else { comboBoxHotcueDefaultColor->setCurrentIndex( comboBoxHotcueDefaultColor->count() - 1); } + if (comboBoxLoopDefaultColor->count() > defaultLoopColor) { + comboBoxLoopDefaultColor->setCurrentIndex(defaultLoopColor); + } else { + comboBoxLoopDefaultColor->setCurrentIndex( + comboBoxLoopDefaultColor->count() - 1); + } } diff --git a/src/preferences/dialog/dlgprefcolors.h b/src/preferences/dialog/dlgprefcolors.h index 24c943acf6e9..2d6e9678dfe4 100644 --- a/src/preferences/dialog/dlgprefcolors.h +++ b/src/preferences/dialog/dlgprefcolors.h @@ -48,7 +48,8 @@ class DlgPrefColors : public DlgPreferencePage, public Ui::DlgPrefColorsDlg { void restoreComboBoxes( const QString& hotcueColors, const QString& trackColors, - int defaultColor); + int defaultHotcueColor, + int defaultLoopColor); const UserSettingsPointer m_pConfig; ColorPaletteSettings m_colorPaletteSettings; diff --git a/src/preferences/dialog/dlgprefcolorsdlg.ui b/src/preferences/dialog/dlgprefcolorsdlg.ui index 3c7ea1b7e8e1..bfe32c6bdd6e 100644 --- a/src/preferences/dialog/dlgprefcolorsdlg.ui +++ b/src/preferences/dialog/dlgprefcolorsdlg.ui @@ -26,6 +26,20 @@ Colors + + + + Hotcue default color + + + + + + + Replace… + + + @@ -43,13 +57,6 @@ - - - - Track palette - - - @@ -67,10 +74,10 @@ - - + + - Hotcue default color + Track palette @@ -84,13 +91,16 @@ - - + + - Replace… + Loop default color + + + diff --git a/src/util/color/predefinedcolorpalettes.cpp b/src/util/color/predefinedcolorpalettes.cpp index 4ff3d79e57fd..fffc61459b04 100644 --- a/src/util/color/predefinedcolorpalettes.cpp +++ b/src/util/color/predefinedcolorpalettes.cpp @@ -268,4 +268,7 @@ const QList PredefinedColorPalettes::kPalettes{ const mixxx::RgbColor PredefinedColorPalettes::kDefaultCueColor = kSchemaMigrationReplacementColor; +const mixxx::RgbColor PredefinedColorPalettes::kDefaultLoopColor = + kColorMixxxWhite; + } // namespace mixxx diff --git a/src/util/color/predefinedcolorpalettes.h b/src/util/color/predefinedcolorpalettes.h index 87deb01f2f7c..c70c8160d85d 100644 --- a/src/util/color/predefinedcolorpalettes.h +++ b/src/util/color/predefinedcolorpalettes.h @@ -19,6 +19,7 @@ class PredefinedColorPalettes { static const QList kPalettes; static const mixxx::RgbColor kDefaultCueColor; + static const mixxx::RgbColor kDefaultLoopColor; }; } // namespace mixxx From 42683aefc4c558f69200d66ece8ebf1c55c06125 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 2 Aug 2020 17:49:44 +0200 Subject: [PATCH 077/153] waveform/renderers/waveformrendermark: Fix disappearing loops on waveform --- src/waveform/renderers/waveformrendermark.cpp | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 702751fc5e47..9bd341959163 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -67,16 +67,22 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { // external image should respect that ... const int markHalfWidth = pMark->m_image.width() / 2.0 / m_waveformRenderer->getDevicePixelRatio(); + int drawOffset = currentMarkPoint - markHalfWidth; + bool visible = false; // Check if the current point needs to be displayed. if (currentMarkPoint > -markHalfWidth && currentMarkPoint < m_waveformRenderer->getWidth() + markHalfWidth) { - int drawOffset = currentMarkPoint - markHalfWidth; painter->drawImage(QPoint(drawOffset, 0), pMark->m_image); - if (sampleEndPosition != Cue::kNoPosition) { - DEBUG_ASSERT(samplePosition < sampleEndPosition); - double currentMarkEndPoint = - m_waveformRenderer->transformSamplePositionInRendererWorld( - sampleEndPosition); + visible = true; + } + + // Check if the range needs to be displayed. + if (sampleEndPosition != Cue::kNoPosition) { + DEBUG_ASSERT(samplePosition < sampleEndPosition); + double currentMarkEndPoint = + m_waveformRenderer->transformSamplePositionInRendererWorld( + sampleEndPosition); + if (currentMarkEndPoint < m_waveformRenderer->getWidth()) { QColor color = pMark->fillColor(); color.setAlphaF(0.5); painter->fillRect( @@ -85,23 +91,34 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { m_waveformRenderer ->getHeight())), QBrush(color, Qt::BDiagPattern)); + visible = true; } - marksOnScreen[pMark] = drawOffset; } + if (visible) { + marksOnScreen[pMark] = drawOffset; + } } else { const int markHalfHeight = pMark->m_image.height() / 2.0; + int drawOffset = currentMarkPoint - markHalfHeight; + + bool visible = false; + // Check if the current point needs to be displayed. if (currentMarkPoint > -markHalfHeight && currentMarkPoint < m_waveformRenderer->getHeight() + markHalfHeight) { - int drawOffset = currentMarkPoint - markHalfHeight; painter->drawImage(QPoint(0, drawOffset), pMark->m_image); - if (sampleEndPosition != Cue::kNoPosition) { - DEBUG_ASSERT(samplePosition < sampleEndPosition); - double currentMarkEndPoint = - m_waveformRenderer - ->transformSamplePositionInRendererWorld( - sampleEndPosition); + visible = true; + } + + // Check if the range needs to be displayed. + if (sampleEndPosition != Cue::kNoPosition) { + DEBUG_ASSERT(samplePosition < sampleEndPosition); + double currentMarkEndPoint = + m_waveformRenderer + ->transformSamplePositionInRendererWorld( + sampleEndPosition); + if (currentMarkEndPoint < m_waveformRenderer->getHeight()) { QColor color = pMark->fillColor(); color.setAlphaF(0.5); painter->fillRect( @@ -109,7 +126,11 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { QPoint(m_waveformRenderer->getWidth(), currentMarkEndPoint)), QBrush(color, Qt::BDiagPattern)); + visible = true; } + } + + if (visible) { marksOnScreen[pMark] = drawOffset; } } From 89dd699d524c399f77096183267be966b2d5e8dc Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 2 Aug 2020 18:08:12 +0200 Subject: [PATCH 078/153] waveform/renderers/waveformrendermark: Make loop display less disruptive --- src/waveform/renderers/waveformrendermark.cpp | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 9bd341959163..419a8ebf8b3b 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -84,13 +84,20 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { sampleEndPosition); if (currentMarkEndPoint < m_waveformRenderer->getWidth()) { QColor color = pMark->fillColor(); - color.setAlphaF(0.5); + color.setAlphaF(0.4); + + QLinearGradient gradient(QPointF(0, 0), + QPointF(0, m_waveformRenderer->getHeight())); + gradient.setColorAt(0, color); + gradient.setColorAt(0.25, QColor(Qt::transparent)); + gradient.setColorAt(0.75, QColor(Qt::transparent)); + gradient.setColorAt(1, color); painter->fillRect( QRect(QPoint(currentMarkPoint, 0), QPoint(currentMarkEndPoint, m_waveformRenderer ->getHeight())), - QBrush(color, Qt::BDiagPattern)); + QBrush(gradient)); visible = true; } } @@ -120,12 +127,19 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { sampleEndPosition); if (currentMarkEndPoint < m_waveformRenderer->getHeight()) { QColor color = pMark->fillColor(); - color.setAlphaF(0.5); + color.setAlphaF(0.4); + + QLinearGradient gradient(QPointF(0, 0), + QPointF(m_waveformRenderer->getWidth(), 0)); + gradient.setColorAt(0, color); + gradient.setColorAt(0.25, QColor(Qt::transparent)); + gradient.setColorAt(0.75, QColor(Qt::transparent)); + gradient.setColorAt(1, color); painter->fillRect( QRect(QPoint(0, currentMarkPoint), QPoint(m_waveformRenderer->getWidth(), currentMarkEndPoint)), - QBrush(color, Qt::BDiagPattern)); + QBrush(gradient)); visible = true; } } From 09fe3673189569361a9e6459869b24cf476d39b3 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 6 Sep 2020 22:27:34 +0200 Subject: [PATCH 079/153] test: Add basic HotcueControlTest class --- CMakeLists.txt | 1 + src/engine/controls/cuecontrol.h | 2 + src/engine/enginebuffer.h | 1 + src/test/hotcuecontrol_test.cpp | 119 +++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 src/test/hotcuecontrol_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 489d19943e5c..a5a9e3233404 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1268,6 +1268,7 @@ add_executable(mixxx-test src/test/enginemicrophonetest.cpp src/test/enginesynctest.cpp src/test/globaltrackcache_test.cpp + src/test/hotcuecontrol_test.cpp src/test/imageutils_test.cpp src/test/indexrange_test.cpp src/test/keyutilstest.cpp diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index d1dd7f34c212..9ae2a2584f8a 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -324,6 +324,8 @@ class CueControl : public EngineControl { QMap m_controlMap; QMutex m_mutex; + + friend class HotcueControlTest; }; diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index bf0e932a185d..9fcb8c358251 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -254,6 +254,7 @@ class EngineBuffer : public EngineObject { UserSettingsPointer m_pConfig; friend class CueControlTest; + friend class HotcueControlTest; LoopingControl* m_pLoopingControl; // used for testes FRIEND_TEST(LoopingControlTest, LoopScale_HalvesLoop); diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp new file mode 100644 index 000000000000..97b5535321a7 --- /dev/null +++ b/src/test/hotcuecontrol_test.cpp @@ -0,0 +1,119 @@ +#include "engine/controls/cuecontrol.h" +#include "test/signalpathtest.h" + +class HotcueControlTest : public BaseSignalPathTest { + protected: + void SetUp() override { + BaseSignalPathTest::SetUp(); + + m_pHotcue1Activate = std::make_unique(m_sGroup1, "hotcue_1_activate"); + m_pHotcue1ActivateCue = std::make_unique(m_sGroup1, "hotcue_1_activatecue"); + m_pHotcue1ActivateLoop = std::make_unique(m_sGroup1, "hotcue_1_activateloop"); + m_pHotcue1Set = std::make_unique(m_sGroup1, "hotcue_1_set"); + m_pHotcue1SetCue = std::make_unique(m_sGroup1, "hotcue_1_setcue"); + m_pHotcue1SetLoop = std::make_unique(m_sGroup1, "hotcue_1_setloop"); + m_pHotcue1Position = std::make_unique(m_sGroup1, "hotcue_1_position"); + m_pHotcue1EndPosition = std::make_unique(m_sGroup1, "hotcue_1_endposition"); + m_pHotcue1Enabled = std::make_unique(m_sGroup1, "hotcue_1_enabled"); + m_pHotcue1Clear = std::make_unique(m_sGroup1, "hotcue_1_clear"); + } + + TrackPointer createTestTrack() const { + const QString kTrackLocationTest = QDir::currentPath() + "/src/test/sine-30.wav"; + const auto pTrack = Track::newTemporary(kTrackLocationTest, SecurityTokenPointer()); + pTrack->setAudioProperties( + mixxx::audio::ChannelCount(2), + mixxx::audio::SampleRate(44100), + mixxx::audio::Bitrate(), + mixxx::Duration::fromSeconds(180)); + return pTrack; + } + + void loadTrack(TrackPointer pTrack) { + BaseSignalPathTest::loadTrack(m_pMixerDeck1, pTrack); + ProcessBuffer(); + } + + TrackPointer createAndLoadFakeTrack() { + return m_pMixerDeck1->loadFakeTrack(false, 0.0); + } + + void unloadTrack() { + m_pMixerDeck1->slotLoadTrack(TrackPointer(), false); + } + + double getCurrentSample() { + return m_pChannel1->getEngineBuffer()->m_pCueControl->getSampleOfTrack().current; + } + + void setCurrentSample(double sample) { + m_pChannel1->getEngineBuffer()->queueNewPlaypos(sample, EngineBuffer::SEEK_STANDARD); + ProcessBuffer(); + } + + std::unique_ptr m_pHotcue1Activate; + std::unique_ptr m_pHotcue1ActivateCue; + std::unique_ptr m_pHotcue1ActivateLoop; + std::unique_ptr m_pHotcue1Set; + std::unique_ptr m_pHotcue1SetCue; + std::unique_ptr m_pHotcue1SetLoop; + std::unique_ptr m_pHotcue1Position; + std::unique_ptr m_pHotcue1EndPosition; + std::unique_ptr m_pHotcue1Enabled; + std::unique_ptr m_pHotcue1Clear; + std::unique_ptr m_pQuantizeEnabled; +}; + +TEST_F(HotcueControlTest, DefautltControlValues) { + TrackPointer pTrack = createTestTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + loadTrack(pTrack); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, NoTrackLoaded) { + TrackPointer pTrack = createTestTrack(); + + m_pHotcue1Set->slotSet(1); + m_pHotcue1Set->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1SetCue->slotSet(1); + m_pHotcue1SetCue->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1ActivateCue->slotSet(1); + m_pHotcue1ActivateCue->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1ActivateLoop->slotSet(1); + m_pHotcue1ActivateLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} From dee7ca75485c82657776c97dcc1b8ca249d01608 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 6 Sep 2020 23:56:19 +0200 Subject: [PATCH 080/153] HotcueControlTest: Add some basic tests for setting cues/loops --- src/test/hotcuecontrol_test.cpp | 116 ++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 97b5535321a7..9c8d8b05b3ee 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -6,6 +6,7 @@ class HotcueControlTest : public BaseSignalPathTest { void SetUp() override { BaseSignalPathTest::SetUp(); + m_pLoopToggle = std::make_unique(m_sGroup1, "loop_toggle"); m_pHotcue1Activate = std::make_unique(m_sGroup1, "hotcue_1_activate"); m_pHotcue1ActivateCue = std::make_unique(m_sGroup1, "hotcue_1_activatecue"); m_pHotcue1ActivateLoop = std::make_unique(m_sGroup1, "hotcue_1_activateloop"); @@ -16,6 +17,7 @@ class HotcueControlTest : public BaseSignalPathTest { m_pHotcue1EndPosition = std::make_unique(m_sGroup1, "hotcue_1_endposition"); m_pHotcue1Enabled = std::make_unique(m_sGroup1, "hotcue_1_enabled"); m_pHotcue1Clear = std::make_unique(m_sGroup1, "hotcue_1_clear"); + m_pQuantizeEnabled = std::make_unique(m_sGroup1, "quantize"); } TrackPointer createTestTrack() const { @@ -51,6 +53,7 @@ class HotcueControlTest : public BaseSignalPathTest { ProcessBuffer(); } + std::unique_ptr m_pLoopToggle; std::unique_ptr m_pHotcue1Activate; std::unique_ptr m_pHotcue1ActivateCue; std::unique_ptr m_pHotcue1ActivateLoop; @@ -117,3 +120,116 @@ TEST_F(HotcueControlTest, NoTrackLoaded) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } + +TEST_F(HotcueControlTest, SetCueAuto) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pQuantizeEnabled->slotSet(0); + setCurrentSample(100); + ProcessBuffer(); + + m_pHotcue1Set->slotSet(1); + m_pHotcue1Set->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, SetCueManual) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pQuantizeEnabled->slotSet(0); + setCurrentSample(100); + ProcessBuffer(); + + m_pHotcue1SetCue->slotSet(1); + m_pHotcue1SetCue->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, SetLoopAuto) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pChannel1->getEngineBuffer()->setLoop(100, 200, true); + ProcessBuffer(); + + m_pHotcue1Set->slotSet(1); + m_pHotcue1Set->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, SetLoopManual) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pChannel1->getEngineBuffer()->setLoop(100, 200, true); + ProcessBuffer(); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, LoopStatus) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pChannel1->getEngineBuffer()->setLoop(100, 200, true); + ProcessBuffer(); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); + + // Disable Loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); + + // Re-Enable Loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); + + m_pHotcue1Clear->slotSet(1); + m_pHotcue1Clear->slotSet(0); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} From bb4cbdf491909abb3d257050ca0f621488f30766 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 7 Sep 2020 21:08:30 +0200 Subject: [PATCH 081/153] HotcueControlText: Remove unnecessary ProcessBuffer calls --- src/test/hotcuecontrol_test.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 9c8d8b05b3ee..ae16848afd8b 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -148,7 +148,6 @@ TEST_F(HotcueControlTest, SetCueManual) { m_pQuantizeEnabled->slotSet(0); setCurrentSample(100); - ProcessBuffer(); m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); @@ -165,7 +164,6 @@ TEST_F(HotcueControlTest, SetLoopAuto) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pChannel1->getEngineBuffer()->setLoop(100, 200, true); - ProcessBuffer(); m_pHotcue1Set->slotSet(1); m_pHotcue1Set->slotSet(0); @@ -182,7 +180,6 @@ TEST_F(HotcueControlTest, SetLoopManual) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pChannel1->getEngineBuffer()->setLoop(100, 200, true); - ProcessBuffer(); m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); @@ -199,7 +196,6 @@ TEST_F(HotcueControlTest, LoopStatus) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pChannel1->getEngineBuffer()->setLoop(100, 200, true); - ProcessBuffer(); m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); @@ -210,7 +206,6 @@ TEST_F(HotcueControlTest, LoopStatus) { // Disable Loop m_pLoopToggle->slotSet(1); m_pLoopToggle->slotSet(0); - ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); @@ -219,7 +214,6 @@ TEST_F(HotcueControlTest, LoopStatus) { // Re-Enable Loop m_pLoopToggle->slotSet(1); m_pLoopToggle->slotSet(0); - ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); @@ -227,7 +221,6 @@ TEST_F(HotcueControlTest, LoopStatus) { m_pHotcue1Clear->slotSet(1); m_pHotcue1Clear->slotSet(0); - ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); From 4c7e8cf4478127900aabe479ca03c03351d28c04 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 7 Sep 2020 21:14:29 +0200 Subject: [PATCH 082/153] HotcueControlTest: Also check loop enabled state in SavedLoopStatus test --- src/test/hotcuecontrol_test.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index ae16848afd8b..b0b530b15946 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -6,6 +6,7 @@ class HotcueControlTest : public BaseSignalPathTest { void SetUp() override { BaseSignalPathTest::SetUp(); + m_pLoopEnabled = std::make_unique(m_sGroup1, "loop_enabled"); m_pLoopToggle = std::make_unique(m_sGroup1, "loop_toggle"); m_pHotcue1Activate = std::make_unique(m_sGroup1, "hotcue_1_activate"); m_pHotcue1ActivateCue = std::make_unique(m_sGroup1, "hotcue_1_activatecue"); @@ -53,6 +54,7 @@ class HotcueControlTest : public BaseSignalPathTest { ProcessBuffer(); } + std::unique_ptr m_pLoopEnabled; std::unique_ptr m_pLoopToggle; std::unique_ptr m_pHotcue1Activate; std::unique_ptr m_pHotcue1ActivateCue; @@ -188,7 +190,7 @@ TEST_F(HotcueControlTest, SetLoopManual) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); } -TEST_F(HotcueControlTest, LoopStatus) { +TEST_F(HotcueControlTest, SavedLoopStatus) { createAndLoadFakeTrack(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); @@ -199,6 +201,7 @@ TEST_F(HotcueControlTest, LoopStatus) { m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); @@ -207,6 +210,7 @@ TEST_F(HotcueControlTest, LoopStatus) { m_pLoopToggle->slotSet(1); m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); @@ -215,6 +219,7 @@ TEST_F(HotcueControlTest, LoopStatus) { m_pLoopToggle->slotSet(1); m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); @@ -222,6 +227,7 @@ TEST_F(HotcueControlTest, LoopStatus) { m_pHotcue1Clear->slotSet(1); m_pHotcue1Clear->slotSet(0); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); From a7af0a4988a2e3bd4d46256cec25719b3965d257 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 7 Sep 2020 22:21:59 +0200 Subject: [PATCH 083/153] HotcueControlTest: Test saved loop move/scale tracking --- src/test/hotcuecontrol_test.cpp | 98 +++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index b0b530b15946..9cabadf08aee 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1,12 +1,24 @@ #include "engine/controls/cuecontrol.h" #include "test/signalpathtest.h" +namespace { +double getBeatLengthFrames(TrackPointer pTrack) { + double beatLengthSecs = 60.0 / pTrack->getBpm(); + return beatLengthSecs * (pTrack->getSampleRate() * mixxx::kEngineChannelCount); +} +} // anonymous namespace + class HotcueControlTest : public BaseSignalPathTest { protected: void SetUp() override { BaseSignalPathTest::SetUp(); + m_pBeatloopActivate = std::make_unique(m_sGroup1, "beatloop_activate"); + m_pBeatloopSize = std::make_unique(m_sGroup1, "beatloop_size"); m_pLoopEnabled = std::make_unique(m_sGroup1, "loop_enabled"); + m_pLoopDouble = std::make_unique(m_sGroup1, "loop_double"); + m_pLoopHalve = std::make_unique(m_sGroup1, "loop_halve"); + m_pLoopMove = std::make_unique(m_sGroup1, "loop_move"); m_pLoopToggle = std::make_unique(m_sGroup1, "loop_toggle"); m_pHotcue1Activate = std::make_unique(m_sGroup1, "hotcue_1_activate"); m_pHotcue1ActivateCue = std::make_unique(m_sGroup1, "hotcue_1_activatecue"); @@ -54,7 +66,12 @@ class HotcueControlTest : public BaseSignalPathTest { ProcessBuffer(); } + std::unique_ptr m_pBeatloopActivate; + std::unique_ptr m_pBeatloopSize; std::unique_ptr m_pLoopEnabled; + std::unique_ptr m_pLoopDouble; + std::unique_ptr m_pLoopHalve; + std::unique_ptr m_pLoopMove; std::unique_ptr m_pLoopToggle; std::unique_ptr m_pHotcue1Activate; std::unique_ptr m_pHotcue1ActivateCue; @@ -232,3 +249,84 @@ TEST_F(HotcueControlTest, SavedLoopStatus) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } + +TEST_F(HotcueControlTest, SavedLoopScale) { + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + const double beatLength = getBeatLengthFrames(pTrack); + const double loopSize = 4; + const double loopLength = loopSize * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop + m_pBeatloopSize->slotSet(loopSize); + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + ProcessBuffer(); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + m_pLoopDouble->slotSet(1); + m_pLoopDouble->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(2 * loopLength, m_pHotcue1EndPosition->get()); + + m_pLoopHalve->slotSet(1); + m_pLoopHalve->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + m_pLoopHalve->slotSet(1); + m_pLoopHalve->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength / 2, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, SavedLoopMove) { + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + const double beatLength = getBeatLengthFrames(pTrack); + const double loopSize = 4; + const double loopLength = loopSize * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop + m_pBeatloopSize->slotSet(loopSize); + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + ProcessBuffer(); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + m_pLoopMove->slotSet(loopSize); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(2 * loopLength, m_pHotcue1EndPosition->get()); + + m_pLoopMove->slotSet(-loopSize); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + m_pLoopMove->slotSet(-loopSize); + EXPECT_DOUBLE_EQ(-loopLength, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1EndPosition->get()); +} From 59fe42f8678bf0aca64b0ddcde366f75e5a21f25 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 7 Sep 2020 22:30:46 +0200 Subject: [PATCH 084/153] HotcueControlText: Add test for saved loop reset behavior --- src/test/hotcuecontrol_test.cpp | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 9cabadf08aee..5e0124df88e4 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -330,3 +330,41 @@ TEST_F(HotcueControlTest, SavedLoopMove) { EXPECT_DOUBLE_EQ(-loopLength, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1EndPosition->get()); } + +TEST_F(HotcueControlTest, SavedLoopReset) { + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + const double beatLength = getBeatLengthFrames(pTrack); + const double loopSize = 4; + const double loopLength = loopSize * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop + m_pBeatloopSize->slotSet(loopSize); + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + ProcessBuffer(); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + // Set a new beatloop (should disable saved loop) + setCurrentSample(loopLength); + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); +} From bf4b6f0e723f589f9d675d30c1edf2a41ae0d81e Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 7 Sep 2020 22:40:57 +0200 Subject: [PATCH 085/153] HotcueControlTest: Add some comments --- src/test/hotcuecontrol_test.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 5e0124df88e4..bffedb566c78 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -251,6 +251,7 @@ TEST_F(HotcueControlTest, SavedLoopStatus) { } TEST_F(HotcueControlTest, SavedLoopScale) { + // Setup fake track with 120 bpm can calculate loop size TrackPointer pTrack = createTestTrack(); pTrack->setBpm(120.0); @@ -265,27 +266,31 @@ TEST_F(HotcueControlTest, SavedLoopScale) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - // Set a beatloop + // Set a beatloop (4 beats) m_pBeatloopSize->slotSet(loopSize); m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); ProcessBuffer(); + // Save currently active loop to hotcue slot 1 m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + // Double loop size (4 => 8 beats) m_pLoopDouble->slotSet(1); m_pLoopDouble->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(2 * loopLength, m_pHotcue1EndPosition->get()); + // Halve loop size (8 => 4 beats) m_pLoopHalve->slotSet(1); m_pLoopHalve->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + // Halve loop size (4 => 2 beats) m_pLoopHalve->slotSet(1); m_pLoopHalve->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); @@ -293,6 +298,7 @@ TEST_F(HotcueControlTest, SavedLoopScale) { } TEST_F(HotcueControlTest, SavedLoopMove) { + // Setup fake track with 120 bpm can calculate loop size TrackPointer pTrack = createTestTrack(); pTrack->setBpm(120.0); @@ -307,31 +313,36 @@ TEST_F(HotcueControlTest, SavedLoopMove) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - // Set a beatloop + // Set a beatloop at position 0 m_pBeatloopSize->slotSet(loopSize); m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); ProcessBuffer(); + // Save currently active loop to hotcue slot 1 m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + // Move loop right (0 => 4 beats) m_pLoopMove->slotSet(loopSize); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(2 * loopLength, m_pHotcue1EndPosition->get()); + // Move loop left (4 => 0 beats) m_pLoopMove->slotSet(-loopSize); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + // Move loop left (0 => -4 beats) m_pLoopMove->slotSet(-loopSize); EXPECT_DOUBLE_EQ(-loopLength, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1EndPosition->get()); } TEST_F(HotcueControlTest, SavedLoopReset) { + // Setup fake track with 120 bpm can calculate loop size TrackPointer pTrack = createTestTrack(); pTrack->setBpm(120.0); @@ -352,18 +363,20 @@ TEST_F(HotcueControlTest, SavedLoopReset) { m_pBeatloopActivate->slotSet(0); ProcessBuffer(); + // Save currently active loop to hotcue slot 1 m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); - // Set a new beatloop (should disable saved loop) + // Set a new beatloop setCurrentSample(loopLength); m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); ProcessBuffer(); + // Check if setting the new beatloop disabled the current saved loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); From 1e3ba8332c68491725fb3946b56ef422b327757b Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 7 Sep 2020 23:30:02 +0200 Subject: [PATCH 086/153] HotcueControlTest: Add tests for saved loops toggle/activate behavior --- src/test/hotcuecontrol_test.cpp | 210 ++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index bffedb566c78..1d1a14846d4c 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -26,6 +26,7 @@ class HotcueControlTest : public BaseSignalPathTest { m_pHotcue1Set = std::make_unique(m_sGroup1, "hotcue_1_set"); m_pHotcue1SetCue = std::make_unique(m_sGroup1, "hotcue_1_setcue"); m_pHotcue1SetLoop = std::make_unique(m_sGroup1, "hotcue_1_setloop"); + m_pHotcue1LoopToggle = std::make_unique(m_sGroup1, "hotcue_1_loop_toggle"); m_pHotcue1Position = std::make_unique(m_sGroup1, "hotcue_1_position"); m_pHotcue1EndPosition = std::make_unique(m_sGroup1, "hotcue_1_endposition"); m_pHotcue1Enabled = std::make_unique(m_sGroup1, "hotcue_1_enabled"); @@ -79,6 +80,7 @@ class HotcueControlTest : public BaseSignalPathTest { std::unique_ptr m_pHotcue1Set; std::unique_ptr m_pHotcue1SetCue; std::unique_ptr m_pHotcue1SetLoop; + std::unique_ptr m_pHotcue1LoopToggle; std::unique_ptr m_pHotcue1Position; std::unique_ptr m_pHotcue1EndPosition; std::unique_ptr m_pHotcue1Enabled; @@ -381,3 +383,211 @@ TEST_F(HotcueControlTest, SavedLoopReset) { EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); } + +TEST_F(HotcueControlTest, SavedLoopToggle) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pChannel1->getEngineBuffer()->setLoop(100, 200, true); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); + + // Disable Loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); + + // Re-Enable Loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLength = getBeatLengthFrames(pTrack); + const double loopLength = m_pBeatloopSize->get() * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + const double beforeLoopPosition = 0; + const double loopStartPosition = 8 * beatLength; + const double afterLoopPosition = 16 * beatLength; + + // Seek to loop start position + setCurrentSample(loopStartPosition); + ProcessBuffer(); + + // Set a beatloop + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Seek to start of track + setCurrentSample(beforeLoopPosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + + // Check that the previous seek disabled the loop + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Re-Enable loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Check that re-enabling loop didn't seek + EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + + // Disable loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Check that re-enabling loop didn't seek + EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + + // Seek to position after saved loop + setCurrentSample(afterLoopPosition); + ProcessBuffer(); + + // Check that the previous seek disabled the loop + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Re-Enable loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Check that re-enabling loop didn't seek + EXPECT_DOUBLE_EQ(afterLoopPosition, getCurrentSample()); + + // Disable loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Check that re-enabling loop didn't seek + EXPECT_DOUBLE_EQ(afterLoopPosition, getCurrentSample()); +} + +TEST_F(HotcueControlTest, SavedLoopActivate) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLength = getBeatLengthFrames(pTrack); + const double loopLength = m_pBeatloopSize->get() * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + const double beforeLoopPosition = 0; + const double loopStartPosition = 8 * beatLength; + const double afterLoopPosition = 16 * beatLength; + + // Seek to loop start position + setCurrentSample(loopStartPosition); + ProcessBuffer(); + + // Set a beatloop + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Seek to start of track + setCurrentSample(beforeLoopPosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + + // Check that the previous seek disabled the loop + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Activate saved loop (implies seeking to loop start) + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, getCurrentSample()); + + // Disable loop + // Seek to position after saved loop + setCurrentSample(afterLoopPosition); + ProcessBuffer(); + + // Check that the previous seek disabled the loop + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + + // Activate saved loop (implies seeking to loop start) + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, getCurrentSample()); +} From 754457b625e78e47c193a8de5b3c04d8a678c480 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 13:26:03 +0200 Subject: [PATCH 087/153] engine/controls/cuecontrol: Do not reset saved loop on cue updates --- src/engine/controls/cuecontrol.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index f5d510d91d1c..048b4f1e5a22 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -577,7 +577,6 @@ void CueControl::loadCuesFromTrack() { pControl->setEndPosition(pCue->getEndPosition()); pControl->setColor(pCue->getColor()); pControl->setType(pCue->getType()); - pControl->setStatus(hotcueControlStatusFromCue(pCue)); } // Add the hotcue to the list of active hotcues active_hotcues.insert(hotcue); @@ -2133,17 +2132,28 @@ void CueControl::slotLoopUpdated(double startPosition, double endPosition) { return; } + if (m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Active) { + slotLoopReset(); + return; + } + CuePointer pCue(m_pCurrentSavedLoopControl->getCue()); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); + VERIFY_OR_DEBUG_ASSERT(pCue->getType() == mixxx::CueType::Loop) { + return; + } + DEBUG_ASSERT(startPosition != Cue::kNoPosition); DEBUG_ASSERT(endPosition != Cue::kNoPosition); DEBUG_ASSERT(startPosition < endPosition); + DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() == HotcueControl::Status::Active); pCue->setStartPosition(startPosition); pCue->setEndPosition(endPosition); + DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() == HotcueControl::Status::Active); } ConfigKey HotcueControl::keyForControl(int hotcue, const char* name) { From c20cc747396a24348a83a1ea6f742f49d34b018f Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 13:27:54 +0200 Subject: [PATCH 088/153] HotcueControlTest: Improve tests for saved loop scaling/moving --- src/test/hotcuecontrol_test.cpp | 160 ++++++++++++++++++++++++++++---- 1 file changed, 141 insertions(+), 19 deletions(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 1d1a14846d4c..5becbf81be0f 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -13,6 +13,7 @@ class HotcueControlTest : public BaseSignalPathTest { void SetUp() override { BaseSignalPathTest::SetUp(); + m_pPlay = std::make_unique(m_sGroup1, "play"); m_pBeatloopActivate = std::make_unique(m_sGroup1, "beatloop_activate"); m_pBeatloopSize = std::make_unique(m_sGroup1, "beatloop_size"); m_pLoopEnabled = std::make_unique(m_sGroup1, "loop_enabled"); @@ -67,6 +68,7 @@ class HotcueControlTest : public BaseSignalPathTest { ProcessBuffer(); } + std::unique_ptr m_pPlay; std::unique_ptr m_pBeatloopActivate; std::unique_ptr m_pBeatloopSize; std::unique_ptr m_pLoopEnabled; @@ -257,9 +259,9 @@ TEST_F(HotcueControlTest, SavedLoopScale) { TrackPointer pTrack = createTestTrack(); pTrack->setBpm(120.0); + m_pBeatloopSize->slotSet(4); const double beatLength = getBeatLengthFrames(pTrack); - const double loopSize = 4; - const double loopLength = loopSize * beatLength; + const double loopLength = m_pBeatloopSize->get() * beatLength; loadTrack(pTrack); ProcessBuffer(); @@ -269,14 +271,15 @@ TEST_F(HotcueControlTest, SavedLoopScale) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Set a beatloop (4 beats) - m_pBeatloopSize->slotSet(loopSize); m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); + m_pPlay->slotSet(1); ProcessBuffer(); // Save currently active loop to hotcue slot 1 m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); @@ -297,6 +300,8 @@ TEST_F(HotcueControlTest, SavedLoopScale) { m_pLoopHalve->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength / 2, m_pHotcue1EndPosition->get()); + + m_pPlay->slotSet(0); } TEST_F(HotcueControlTest, SavedLoopMove) { @@ -304,8 +309,9 @@ TEST_F(HotcueControlTest, SavedLoopMove) { TrackPointer pTrack = createTestTrack(); pTrack->setBpm(120.0); + constexpr double loopSize = 4; + m_pBeatloopSize->slotSet(loopSize); const double beatLength = getBeatLengthFrames(pTrack); - const double loopSize = 4; const double loopLength = loopSize * beatLength; loadTrack(pTrack); @@ -316,40 +322,105 @@ TEST_F(HotcueControlTest, SavedLoopMove) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Set a beatloop at position 0 - m_pBeatloopSize->slotSet(loopSize); m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); - ProcessBuffer(); + m_pPlay->slotSet(1); // Save currently active loop to hotcue slot 1 m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); // Move loop right (0 => 4 beats) m_pLoopMove->slotSet(loopSize); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(2 * loopLength, m_pHotcue1EndPosition->get()); // Move loop left (4 => 0 beats) m_pLoopMove->slotSet(-loopSize); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); // Move loop left (0 => -4 beats) m_pLoopMove->slotSet(-loopSize); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(-loopLength, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1EndPosition->get()); + + m_pPlay->slotSet(0); } -TEST_F(HotcueControlTest, SavedLoopReset) { +TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLength = getBeatLengthFrames(pTrack); + const double loopLength = m_pBeatloopSize->get() * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop (4 beats) + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + m_pPlay->slotSet(1); + ProcessBuffer(); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + // Disable loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + + // Double loop size (4 => 8 beats) while saved loop is disabled + m_pLoopDouble->slotSet(1); + m_pLoopDouble->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + // Halve loop size (8 => 4 beats) while saved loop is disabled + m_pLoopHalve->slotSet(1); + m_pLoopHalve->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + // Halve loop size (4 => 2 beats) while saved loop is disabled + m_pLoopHalve->slotSet(1); + m_pLoopHalve->slotSet(0); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + m_pPlay->slotSet(0); +} + +TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { // Setup fake track with 120 bpm can calculate loop size TrackPointer pTrack = createTestTrack(); pTrack->setBpm(120.0); + constexpr double loopSize = 4; + m_pBeatloopSize->slotSet(loopSize); const double beatLength = getBeatLengthFrames(pTrack); - const double loopSize = 4; const double loopLength = loopSize * beatLength; loadTrack(pTrack); @@ -359,8 +430,59 @@ TEST_F(HotcueControlTest, SavedLoopReset) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + // Set a beatloop at position 0 + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + m_pPlay->slotSet(1); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + // Disable Loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + + // Move loop right (0 => 4 beats) while saved loop is disabled + m_pLoopMove->slotSet(loopSize); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + // Move loop left (4 => 0 beats) while saved loop is disabled + m_pLoopMove->slotSet(-loopSize); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + // Move loop left (0 => -4 beats) while saved loop is disabled + m_pLoopMove->slotSet(-loopSize); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + + m_pPlay->slotSet(0); +} + +TEST_F(HotcueControlTest, SavedLoopReset) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLength = getBeatLengthFrames(pTrack); + const double loopLength = m_pBeatloopSize->get() * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + // Set a beatloop - m_pBeatloopSize->slotSet(loopSize); m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); ProcessBuffer(); @@ -424,9 +546,13 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { TrackPointer pTrack = createTestTrack(); pTrack->setBpm(120.0); - m_pBeatloopSize->slotSet(4); + constexpr double loopSize = 4; const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; + const double loopLength = loopSize * beatLength; + + const double beforeLoopPosition = 0; + const double loopStartPosition = 8 * beatLength; + const double afterLoopPosition = 16 * beatLength; loadTrack(pTrack); ProcessBuffer(); @@ -435,10 +561,6 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - const double beforeLoopPosition = 0; - const double loopStartPosition = 8 * beatLength; - const double afterLoopPosition = 16 * beatLength; - // Seek to loop start position setCurrentSample(loopStartPosition); ProcessBuffer(); @@ -527,6 +649,10 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { const double beatLength = getBeatLengthFrames(pTrack); const double loopLength = m_pBeatloopSize->get() * beatLength; + const double beforeLoopPosition = 0; + const double loopStartPosition = 8 * beatLength; + const double afterLoopPosition = 16 * beatLength; + loadTrack(pTrack); ProcessBuffer(); @@ -534,10 +660,6 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - const double beforeLoopPosition = 0; - const double loopStartPosition = 8 * beatLength; - const double afterLoopPosition = 16 * beatLength; - // Seek to loop start position setCurrentSample(loopStartPosition); ProcessBuffer(); From 51489aab94d6d07e98db83f36689e8ebea3cd772 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 14:10:06 +0200 Subject: [PATCH 089/153] HotcueControlTest: Add tests for cue goto/gotoandplay/gotoandloop behavior --- src/test/hotcuecontrol_test.cpp | 139 ++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 5becbf81be0f..757b82970a27 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -16,6 +16,8 @@ class HotcueControlTest : public BaseSignalPathTest { m_pPlay = std::make_unique(m_sGroup1, "play"); m_pBeatloopActivate = std::make_unique(m_sGroup1, "beatloop_activate"); m_pBeatloopSize = std::make_unique(m_sGroup1, "beatloop_size"); + m_pLoopStartPosition = std::make_unique(m_sGroup1, "loop_start_position"); + m_pLoopEndPosition = std::make_unique(m_sGroup1, "loop_end_position"); m_pLoopEnabled = std::make_unique(m_sGroup1, "loop_enabled"); m_pLoopDouble = std::make_unique(m_sGroup1, "loop_double"); m_pLoopHalve = std::make_unique(m_sGroup1, "loop_halve"); @@ -27,6 +29,9 @@ class HotcueControlTest : public BaseSignalPathTest { m_pHotcue1Set = std::make_unique(m_sGroup1, "hotcue_1_set"); m_pHotcue1SetCue = std::make_unique(m_sGroup1, "hotcue_1_setcue"); m_pHotcue1SetLoop = std::make_unique(m_sGroup1, "hotcue_1_setloop"); + m_pHotcue1Goto = std::make_unique(m_sGroup1, "hotcue_1_goto"); + m_pHotcue1GotoAndPlay = std::make_unique(m_sGroup1, "hotcue_1_gotoandplay"); + m_pHotcue1GotoAndLoop = std::make_unique(m_sGroup1, "hotcue_1_gotoandloop"); m_pHotcue1LoopToggle = std::make_unique(m_sGroup1, "hotcue_1_loop_toggle"); m_pHotcue1Position = std::make_unique(m_sGroup1, "hotcue_1_position"); m_pHotcue1EndPosition = std::make_unique(m_sGroup1, "hotcue_1_endposition"); @@ -71,6 +76,8 @@ class HotcueControlTest : public BaseSignalPathTest { std::unique_ptr m_pPlay; std::unique_ptr m_pBeatloopActivate; std::unique_ptr m_pBeatloopSize; + std::unique_ptr m_pLoopStartPosition; + std::unique_ptr m_pLoopEndPosition; std::unique_ptr m_pLoopEnabled; std::unique_ptr m_pLoopDouble; std::unique_ptr m_pLoopHalve; @@ -82,6 +89,9 @@ class HotcueControlTest : public BaseSignalPathTest { std::unique_ptr m_pHotcue1Set; std::unique_ptr m_pHotcue1SetCue; std::unique_ptr m_pHotcue1SetLoop; + std::unique_ptr m_pHotcue1Goto; + std::unique_ptr m_pHotcue1GotoAndPlay; + std::unique_ptr m_pHotcue1GotoAndLoop; std::unique_ptr m_pHotcue1LoopToggle; std::unique_ptr m_pHotcue1Position; std::unique_ptr m_pHotcue1EndPosition; @@ -211,6 +221,135 @@ TEST_F(HotcueControlTest, SetLoopManual) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); } +TEST_F(HotcueControlTest, CueGoto) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + const double cuePosition = 8 * getBeatLengthFrames(pTrack); + + // Seek to cue Position (8th beat) + setCurrentSample(cuePosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + m_pHotcue1SetCue->slotSet(1); + m_pHotcue1SetCue->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Seek to start of track + setCurrentSample(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(0, getCurrentSample()); + + m_pHotcue1Goto->slotSet(1); + m_pHotcue1Goto->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); +} + +TEST_F(HotcueControlTest, CueGotoAndPlay) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + const double cuePosition = 8 * getBeatLengthFrames(pTrack); + + // Seek to cue Position (8th beat) + setCurrentSample(cuePosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + m_pHotcue1SetCue->slotSet(1); + m_pHotcue1SetCue->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Seek to start of track + setCurrentSample(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(0, getCurrentSample()); + + m_pHotcue1GotoAndPlay->slotSet(1); + m_pHotcue1GotoAndPlay->slotSet(0); + ProcessBuffer(); + EXPECT_LE(cuePosition, getCurrentSample()); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); +} + +TEST_F(HotcueControlTest, CueGotoAndLoop) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + const double beatLength = getBeatLengthFrames(pTrack); + const double cuePosition = 8 * beatLength; + m_pBeatloopSize->slotSet(4); + const double beatloopLength = m_pBeatloopSize->get() * getBeatLengthFrames(pTrack); + + // Seek to cue Position (8th beat) + setCurrentSample(cuePosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + m_pHotcue1SetCue->slotSet(1); + m_pHotcue1SetCue->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Seek to start of track + setCurrentSample(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(0, getCurrentSample()); + + m_pHotcue1GotoAndLoop->slotSet(1); + m_pHotcue1GotoAndLoop->slotSet(0); + ProcessBuffer(); + EXPECT_LE(cuePosition, getCurrentSample()); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pLoopStartPosition->get()); + EXPECT_DOUBLE_EQ(cuePosition + beatloopLength, m_pLoopEndPosition->get()); +} + TEST_F(HotcueControlTest, SavedLoopStatus) { createAndLoadFakeTrack(); From 40a7a1d555322ffcbbb027ae36912aec149f3f74 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 14:30:59 +0200 Subject: [PATCH 090/153] HotcueControlTest: Add tests for saved loop goto/gotoandplay/gotoandloop --- src/test/hotcuecontrol_test.cpp | 170 ++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 757b82970a27..b7d110f00784 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -350,6 +350,176 @@ TEST_F(HotcueControlTest, CueGotoAndLoop) { EXPECT_DOUBLE_EQ(cuePosition + beatloopLength, m_pLoopEndPosition->get()); } +TEST_F(HotcueControlTest, SavedLoopGoto) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLength = getBeatLengthFrames(pTrack); + const double loopLength = m_pBeatloopSize->get() * beatLength; + const double cuePosition = 8 * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Seek to cue Position (8th beat) + setCurrentSample(cuePosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + // Set a beatloop this position + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + + // Save loop to hotcue slot 1 + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + + // Disable loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + + // Seek to start of track + setCurrentSample(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(0, getCurrentSample()); + + m_pHotcue1Goto->slotSet(1); + m_pHotcue1Goto->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); +} + +TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLength = getBeatLengthFrames(pTrack); + const double loopLength = m_pBeatloopSize->get() * beatLength; + const double cuePosition = 8 * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Seek to cue Position (8th beat) + setCurrentSample(cuePosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + // Set a beatloop this position + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + + // Save loop to hotcue slot 1 + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + + // Disable loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + + // Seek to start of track + setCurrentSample(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(0, getCurrentSample()); + + m_pHotcue1GotoAndPlay->slotSet(1); + m_pHotcue1GotoAndPlay->slotSet(0); + ProcessBuffer(); + EXPECT_LE(cuePosition, getCurrentSample()); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); +} + +TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLength = getBeatLengthFrames(pTrack); + const double loopLength = m_pBeatloopSize->get() * beatLength; + const double cuePosition = 8 * beatLength; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Seek to cue Position (8th beat) + setCurrentSample(cuePosition); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + + // Set a beatloop this position + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + + // Save loop to hotcue slot 1 + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + + // Disable loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + + // Seek to start of track + setCurrentSample(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(0, getCurrentSample()); + + m_pHotcue1GotoAndLoop->slotSet(1); + m_pHotcue1GotoAndLoop->slotSet(0); + ProcessBuffer(); + EXPECT_LE(cuePosition, getCurrentSample()); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(cuePosition, m_pLoopStartPosition->get()); + EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pLoopEndPosition->get()); +} + TEST_F(HotcueControlTest, SavedLoopStatus) { createAndLoadFakeTrack(); From 8875fc223e2b11d73d9217ea610d4be710bd8200 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 14:43:08 +0200 Subject: [PATCH 091/153] HotcueControlTest: Fix position/length variable and function unit names --- src/test/hotcuecontrol_test.cpp | 298 ++++++++++++++++---------------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index b7d110f00784..41861b5b0a72 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -2,7 +2,7 @@ #include "test/signalpathtest.h" namespace { -double getBeatLengthFrames(TrackPointer pTrack) { +double getBeatLengthSamples(TrackPointer pTrack) { double beatLengthSecs = 60.0 / pTrack->getBpm(); return beatLengthSecs * (pTrack->getSampleRate() * mixxx::kEngineChannelCount); } @@ -64,11 +64,11 @@ class HotcueControlTest : public BaseSignalPathTest { m_pMixerDeck1->slotLoadTrack(TrackPointer(), false); } - double getCurrentSample() { + double currentSamplePosition() { return m_pChannel1->getEngineBuffer()->m_pCueControl->getSampleOfTrack().current; } - void setCurrentSample(double sample) { + void setCurrentSamplePosition(double sample) { m_pChannel1->getEngineBuffer()->queueNewPlaypos(sample, EngineBuffer::SEEK_STANDARD); ProcessBuffer(); } @@ -162,7 +162,7 @@ TEST_F(HotcueControlTest, SetCueAuto) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pQuantizeEnabled->slotSet(0); - setCurrentSample(100); + setCurrentSamplePosition(100); ProcessBuffer(); m_pHotcue1Set->slotSet(1); @@ -180,7 +180,7 @@ TEST_F(HotcueControlTest, SetCueManual) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pQuantizeEnabled->slotSet(0); - setCurrentSample(100); + setCurrentSamplePosition(100); m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); @@ -233,31 +233,31 @@ TEST_F(HotcueControlTest, CueGoto) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - const double cuePosition = 8 * getBeatLengthFrames(pTrack); + const double cuePositionSamples = 8 * getBeatLengthSamples(pTrack); // Seek to cue Position (8th beat) - setCurrentSample(cuePosition); + setCurrentSamplePosition(cuePositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to start of track - setCurrentSample(0); + setCurrentSamplePosition(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(0, getCurrentSample()); + EXPECT_DOUBLE_EQ(0, currentSamplePosition()); m_pHotcue1Goto->slotSet(1); m_pHotcue1Goto->slotSet(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); } @@ -274,31 +274,31 @@ TEST_F(HotcueControlTest, CueGotoAndPlay) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - const double cuePosition = 8 * getBeatLengthFrames(pTrack); + const double cuePositionSamples = 8 * getBeatLengthSamples(pTrack); // Seek to cue Position (8th beat) - setCurrentSample(cuePosition); + setCurrentSamplePosition(cuePositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to start of track - setCurrentSample(0); + setCurrentSamplePosition(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(0, getCurrentSample()); + EXPECT_DOUBLE_EQ(0, currentSamplePosition()); m_pHotcue1GotoAndPlay->slotSet(1); m_pHotcue1GotoAndPlay->slotSet(0); ProcessBuffer(); - EXPECT_LE(cuePosition, getCurrentSample()); + EXPECT_LE(cuePositionSamples, currentSamplePosition()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); } @@ -315,39 +315,39 @@ TEST_F(HotcueControlTest, CueGotoAndLoop) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - const double beatLength = getBeatLengthFrames(pTrack); - const double cuePosition = 8 * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double cuePositionSamples = 8 * beatLengthSamples; m_pBeatloopSize->slotSet(4); - const double beatloopLength = m_pBeatloopSize->get() * getBeatLengthFrames(pTrack); + const double beatloopLengthSamples = m_pBeatloopSize->get() * getBeatLengthSamples(pTrack); // Seek to cue Position (8th beat) - setCurrentSample(cuePosition); + setCurrentSamplePosition(cuePositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to start of track - setCurrentSample(0); + setCurrentSamplePosition(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(0, getCurrentSample()); + EXPECT_DOUBLE_EQ(0, currentSamplePosition()); m_pHotcue1GotoAndLoop->slotSet(1); m_pHotcue1GotoAndLoop->slotSet(0); ProcessBuffer(); - EXPECT_LE(cuePosition, getCurrentSample()); + EXPECT_LE(cuePositionSamples, currentSamplePosition()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pLoopStartPosition->get()); - EXPECT_DOUBLE_EQ(cuePosition + beatloopLength, m_pLoopEndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pLoopStartPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + beatloopLengthSamples, m_pLoopEndPosition->get()); } TEST_F(HotcueControlTest, SavedLoopGoto) { @@ -356,9 +356,9 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { pTrack->setBpm(120.0); m_pBeatloopSize->slotSet(4); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; - const double cuePosition = 8 * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; + const double cuePositionSamples = 8 * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -368,9 +368,9 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to cue Position (8th beat) - setCurrentSample(cuePosition); + setCurrentSamplePosition(cuePositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); // Set a beatloop this position m_pBeatloopActivate->slotSet(1); @@ -381,8 +381,8 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { // Save loop to hotcue slot 1 EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop m_pLoopToggle->slotSet(1); @@ -391,18 +391,18 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); // Seek to start of track - setCurrentSample(0); + setCurrentSamplePosition(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(0, getCurrentSample()); + EXPECT_DOUBLE_EQ(0, currentSamplePosition()); m_pHotcue1Goto->slotSet(1); m_pHotcue1Goto->slotSet(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); } @@ -412,9 +412,9 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { pTrack->setBpm(120.0); m_pBeatloopSize->slotSet(4); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; - const double cuePosition = 8 * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; + const double cuePositionSamples = 8 * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -424,9 +424,9 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to cue Position (8th beat) - setCurrentSample(cuePosition); + setCurrentSamplePosition(cuePositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); // Set a beatloop this position m_pBeatloopActivate->slotSet(1); @@ -437,8 +437,8 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { // Save loop to hotcue slot 1 EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop m_pLoopToggle->slotSet(1); @@ -447,18 +447,18 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); // Seek to start of track - setCurrentSample(0); + setCurrentSamplePosition(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(0, getCurrentSample()); + EXPECT_DOUBLE_EQ(0, currentSamplePosition()); m_pHotcue1GotoAndPlay->slotSet(1); m_pHotcue1GotoAndPlay->slotSet(0); ProcessBuffer(); - EXPECT_LE(cuePosition, getCurrentSample()); + EXPECT_LE(cuePositionSamples, currentSamplePosition()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); } @@ -468,9 +468,9 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { pTrack->setBpm(120.0); m_pBeatloopSize->slotSet(4); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; - const double cuePosition = 8 * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; + const double cuePositionSamples = 8 * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -480,9 +480,9 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to cue Position (8th beat) - setCurrentSample(cuePosition); + setCurrentSamplePosition(cuePositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(cuePosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); // Set a beatloop this position m_pBeatloopActivate->slotSet(1); @@ -493,8 +493,8 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { // Save loop to hotcue slot 1 EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop m_pLoopToggle->slotSet(1); @@ -503,21 +503,21 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); // Seek to start of track - setCurrentSample(0); + setCurrentSamplePosition(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(0, getCurrentSample()); + EXPECT_DOUBLE_EQ(0, currentSamplePosition()); m_pHotcue1GotoAndLoop->slotSet(1); m_pHotcue1GotoAndLoop->slotSet(0); ProcessBuffer(); - EXPECT_LE(cuePosition, getCurrentSample()); + EXPECT_LE(cuePositionSamples, currentSamplePosition()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(cuePosition, m_pLoopStartPosition->get()); - EXPECT_DOUBLE_EQ(cuePosition + loopLength, m_pLoopEndPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pLoopStartPosition->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pLoopEndPosition->get()); } TEST_F(HotcueControlTest, SavedLoopStatus) { @@ -569,8 +569,8 @@ TEST_F(HotcueControlTest, SavedLoopScale) { pTrack->setBpm(120.0); m_pBeatloopSize->slotSet(4); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -590,25 +590,25 @@ TEST_F(HotcueControlTest, SavedLoopScale) { m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Double loop size (4 => 8 beats) m_pLoopDouble->slotSet(1); m_pLoopDouble->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(2 * loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(2 * loopLengthSamples, m_pHotcue1EndPosition->get()); // Halve loop size (8 => 4 beats) m_pLoopHalve->slotSet(1); m_pLoopHalve->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Halve loop size (4 => 2 beats) m_pLoopHalve->slotSet(1); m_pLoopHalve->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength / 2, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples / 2, m_pHotcue1EndPosition->get()); m_pPlay->slotSet(0); } @@ -620,8 +620,8 @@ TEST_F(HotcueControlTest, SavedLoopMove) { constexpr double loopSize = 4; m_pBeatloopSize->slotSet(loopSize); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = loopSize * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = loopSize * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -641,27 +641,27 @@ TEST_F(HotcueControlTest, SavedLoopMove) { ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Move loop right (0 => 4 beats) m_pLoopMove->slotSet(loopSize); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(2 * loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(2 * loopLengthSamples, m_pHotcue1EndPosition->get()); // Move loop left (4 => 0 beats) m_pLoopMove->slotSet(-loopSize); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Move loop left (0 => -4 beats) m_pLoopMove->slotSet(-loopSize); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(-loopLength, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(-loopLengthSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1EndPosition->get()); m_pPlay->slotSet(0); @@ -673,8 +673,8 @@ TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { pTrack->setBpm(120.0); m_pBeatloopSize->slotSet(4); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -694,7 +694,7 @@ TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop m_pLoopToggle->slotSet(1); @@ -705,19 +705,19 @@ TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { m_pLoopDouble->slotSet(1); m_pLoopDouble->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Halve loop size (8 => 4 beats) while saved loop is disabled m_pLoopHalve->slotSet(1); m_pLoopHalve->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Halve loop size (4 => 2 beats) while saved loop is disabled m_pLoopHalve->slotSet(1); m_pLoopHalve->slotSet(0); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); m_pPlay->slotSet(0); } @@ -729,8 +729,8 @@ TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { constexpr double loopSize = 4; m_pBeatloopSize->slotSet(loopSize); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = loopSize * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = loopSize * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -749,7 +749,7 @@ TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable Loop m_pLoopToggle->slotSet(1); @@ -760,17 +760,17 @@ TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { // Move loop right (0 => 4 beats) while saved loop is disabled m_pLoopMove->slotSet(loopSize); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Move loop left (4 => 0 beats) while saved loop is disabled m_pLoopMove->slotSet(-loopSize); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Move loop left (0 => -4 beats) while saved loop is disabled m_pLoopMove->slotSet(-loopSize); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); m_pPlay->slotSet(0); } @@ -781,8 +781,8 @@ TEST_F(HotcueControlTest, SavedLoopReset) { pTrack->setBpm(120.0); m_pBeatloopSize->slotSet(4); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -801,10 +801,10 @@ TEST_F(HotcueControlTest, SavedLoopReset) { m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Set a new beatloop - setCurrentSample(loopLength); + setCurrentSamplePosition(loopLengthSamples); m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); ProcessBuffer(); @@ -812,7 +812,7 @@ TEST_F(HotcueControlTest, SavedLoopReset) { // Check if setting the new beatloop disabled the current saved loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); } TEST_F(HotcueControlTest, SavedLoopToggle) { @@ -856,12 +856,12 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { pTrack->setBpm(120.0); constexpr double loopSize = 4; - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = loopSize * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = loopSize * beatLengthSamples; - const double beforeLoopPosition = 0; - const double loopStartPosition = 8 * beatLength; - const double afterLoopPosition = 16 * beatLength; + const double beforeLoopPositionSamples = 0; + const double loopStartPositionSamples = 8 * beatLengthSamples; + const double afterLoopPositionSamples = 16 * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -871,7 +871,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to loop start position - setCurrentSample(loopStartPosition); + setCurrentSamplePosition(loopStartPositionSamples); ProcessBuffer(); // Set a beatloop @@ -882,71 +882,71 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Seek to start of track - setCurrentSample(beforeLoopPosition); + setCurrentSamplePosition(beforeLoopPositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); // Check that the previous seek disabled the loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Re-Enable loop m_pHotcue1LoopToggle->slotSet(1); m_pHotcue1LoopToggle->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); // Disable loop m_pHotcue1LoopToggle->slotSet(1); m_pHotcue1LoopToggle->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); // Seek to position after saved loop - setCurrentSample(afterLoopPosition); + setCurrentSamplePosition(afterLoopPositionSamples); ProcessBuffer(); // Check that the previous seek disabled the loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Re-Enable loop m_pHotcue1LoopToggle->slotSet(1); m_pHotcue1LoopToggle->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(afterLoopPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(afterLoopPositionSamples, currentSamplePosition()); // Disable loop m_pHotcue1LoopToggle->slotSet(1); m_pHotcue1LoopToggle->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(afterLoopPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(afterLoopPositionSamples, currentSamplePosition()); } TEST_F(HotcueControlTest, SavedLoopActivate) { @@ -955,12 +955,12 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { pTrack->setBpm(120.0); m_pBeatloopSize->slotSet(4); - const double beatLength = getBeatLengthFrames(pTrack); - const double loopLength = m_pBeatloopSize->get() * beatLength; + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - const double beforeLoopPosition = 0; - const double loopStartPosition = 8 * beatLength; - const double afterLoopPosition = 16 * beatLength; + const double beforeLoopPositionSamples = 0; + const double loopStartPositionSamples = 8 * beatLengthSamples; + const double afterLoopPositionSamples = 16 * beatLengthSamples; loadTrack(pTrack); ProcessBuffer(); @@ -970,7 +970,7 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); // Seek to loop start position - setCurrentSample(loopStartPosition); + setCurrentSamplePosition(loopStartPositionSamples); ProcessBuffer(); // Set a beatloop @@ -981,44 +981,44 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Seek to start of track - setCurrentSample(beforeLoopPosition); + setCurrentSamplePosition(beforeLoopPositionSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(beforeLoopPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); // Check that the previous seek disabled the loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Activate saved loop (implies seeking to loop start) m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, currentSamplePosition()); // Disable loop // Seek to position after saved loop - setCurrentSample(afterLoopPosition); + setCurrentSamplePosition(afterLoopPositionSamples); ProcessBuffer(); // Check that the previous seek disabled the loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Activate saved loop (implies seeking to loop start) m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPosition + loopLength, m_pHotcue1EndPosition->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, getCurrentSample()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(loopStartPositionSamples, currentSamplePosition()); } From d544cec224836d53d8ff18e29e6818ae8438a558 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 15:15:18 +0200 Subject: [PATCH 092/153] waveform/renderers/waveformrendermark: Fix rendering for long loop cues --- src/waveform/renderers/waveformrendermark.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 419a8ebf8b3b..b4039f130685 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -82,7 +82,7 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { double currentMarkEndPoint = m_waveformRenderer->transformSamplePositionInRendererWorld( sampleEndPosition); - if (currentMarkEndPoint < m_waveformRenderer->getWidth()) { + if (visible || currentMarkEndPoint > 0) { QColor color = pMark->fillColor(); color.setAlphaF(0.4); From 4ff11630b148c0f1c9d0794159315092a6532fb5 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 15:40:55 +0200 Subject: [PATCH 093/153] engine/controls/loopingcontrol: Set beatloop size on saved loop --- src/engine/controls/loopingcontrol.cpp | 1 + src/test/hotcuecontrol_test.cpp | 144 +++++++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index a2fda6370b9a..63789a966469 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -562,6 +562,7 @@ void LoopingControl::setLoop(double startPosition, double endPosition, bool enab m_pCOLoopEndPosition->set(loopSamples.end); } setLoopingEnabled(enabled); + m_pCOBeatLoopSize->setAndConfirm(findBeatloopSizeForLoop(startPosition, endPosition)); } void LoopingControl::setLoopInToCurrentPosition() { diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 41861b5b0a72..3bbe77a66d29 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1022,3 +1022,147 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, currentSamplePosition()); } + +TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + constexpr double savedLoopSize = 8; + m_pBeatloopSize->slotSet(savedLoopSize); + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1ActivateLoop->slotSet(1); + m_pHotcue1ActivateLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Disable loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Set new beatloop size + m_pBeatloopSize->slotSet(savedLoopSize / 2); + + // Re-enabled saved loop + m_pHotcue1ActivateLoop->slotSet(1); + m_pHotcue1ActivateLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Check that saved loop's beatloop size has been restored + EXPECT_DOUBLE_EQ(savedLoopSize, m_pBeatloopSize->get()); +} + +TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + constexpr double savedLoopSize = 4; + m_pBeatloopSize->slotSet(savedLoopSize); + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; + const double cuePositionSamples = 8 * beatLengthSamples; + const double beforeLoopPositionSamples = 0; + const double afterLoopPositionSamples = beatLengthSamples; + + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Seek to cue Position (8th beat) + setCurrentSamplePosition(cuePositionSamples); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); + + // Set a beatloop + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Check 1: Play position before saved loop + + // Disable loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Seek to position before saved loop + setCurrentSamplePosition(beforeLoopPositionSamples); + + // Set new beatloop size + m_pBeatloopSize->slotSet(m_pBeatloopSize->get() / 2); + ProcessBuffer(); + + // Re-enable saved loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Check that saved loop's beatloop size has been restored + EXPECT_DOUBLE_EQ(savedLoopSize, m_pBeatloopSize->get()); + + // Check that enabling the loop didn't cause a jump + EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); + + // Check 2: Play position after saved loop + + // Disable loop + m_pLoopToggle->slotSet(1); + m_pLoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Seek to position after saved loop + setCurrentSamplePosition(afterLoopPositionSamples); + + // Set new beatloop size + m_pBeatloopSize->slotSet(m_pBeatloopSize->get() / 2); + ProcessBuffer(); + + // Re-enable saved loop + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + + // Check that saved loop's beatloop size has been restored + EXPECT_DOUBLE_EQ(savedLoopSize, m_pBeatloopSize->get()); + + // Check that enabling the loop didn't cause a jump + EXPECT_DOUBLE_EQ(afterLoopPositionSamples, currentSamplePosition()); +} From c8cc7300a1d38ff0d67ecedc3bf85a74cac35be3 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 16:10:59 +0200 Subject: [PATCH 094/153] engine/controls/cuecontrol: Make hotcue_X_setloop work without active loop Instead, this CO will now set a beatloop from the current position. --- src/engine/controls/cuecontrol.cpp | 27 +++++++++++++++++++++------ src/engine/controls/cuecontrol.h | 1 + 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 048b4f1e5a22..c9e38b97ea72 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -82,6 +82,7 @@ CueControl::CueControl(QString group, m_pLoopEndPosition = make_parented(group, "loop_end_position", this); m_pLoopEnabled = make_parented(group, "loop_enabled", this); m_pBeatLoopActivate = make_parented(group, "beatloop_activate", this); + m_pBeatLoopSize = make_parented(group, "beatloop_size", this); m_pCuePoint = new ControlObject(ConfigKey(group, "cue_point")); m_pCuePoint->set(Cue::kNoPosition); @@ -724,22 +725,35 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { double cueEndPosition = Cue::kNoPosition; mixxx::CueType cueType = mixxx::CueType::Invalid; + bool loopEnabled = m_pLoopEnabled->get(); if (mode == HotcueMode::Auto) { - mode = m_pLoopEnabled->get() ? HotcueMode::Loop : HotcueMode::Cue; + mode = loopEnabled ? HotcueMode::Loop : HotcueMode::Cue; } switch (mode) { case HotcueMode::Cue: { // If no loop is enabled, just store regular jump cue cueStartPosition = getQuantizedCurrentPosition(); - cueEndPosition = Cue::kNoPosition; cueType = mixxx::CueType::HotCue; break; } case HotcueMode::Loop: { - // If no loop is enabled, just store regular jump cue - cueStartPosition = m_pLoopStartPosition->get(); - cueEndPosition = m_pLoopEndPosition->get(); + if (loopEnabled) { + // If a loop is enabled, save the current loop + cueStartPosition = m_pLoopStartPosition->get(); + cueEndPosition = m_pLoopEndPosition->get(); + } else { + // If no loop is enabled, save a loop starting from the current + // position and with the current beatloop size + cueStartPosition = getQuantizedCurrentPosition(); + double beatloopSize = m_pBeatLoopSize->get(); + if (beatloopSize > 0) { + mixxx::BeatsPointer pBeats = m_pLoadedTrack->getBeats(); + if (pBeats) { + cueEndPosition = pBeats->findNBeatsFromSample(cueStartPosition, beatloopSize); + } + } + } cueType = mixxx::CueType::Loop; break; } @@ -752,7 +766,8 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { } // Abort if no position has been found. This can happen if a loop cue is - // requested while no loop is set, so we can't debug assert here. + // requested while no loop is set and the track has no beatgrid, so we + // can't debug assert here. if (cueStartPosition == Cue::kNoPosition || (cueType == mixxx::CueType::Loop && cueEndPosition == Cue::kNoPosition)) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 9ae2a2584f8a..fe0de15ceff3 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -264,6 +264,7 @@ class CueControl : public EngineControl { parented_ptr m_pLoopEnabled; parented_ptr m_pLoopToggle; parented_ptr m_pBeatLoopActivate; + parented_ptr m_pBeatLoopSize; bool m_bypassCueSetByPlay; ControlValueAtomic m_usedSeekOnLoadPosition; From abf46ed7e4484c2a15f9c4bb7ede08b5d3322f8a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 16:20:13 +0200 Subject: [PATCH 095/153] HotcueControlTest: Add tests for new hotcue_X_setloop behavior --- src/test/hotcuecontrol_test.cpp | 42 ++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 3bbe77a66d29..e08bca3fd81c 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -205,7 +205,7 @@ TEST_F(HotcueControlTest, SetLoopAuto) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); } -TEST_F(HotcueControlTest, SetLoopManual) { +TEST_F(HotcueControlTest, SetLoopManualWithLoop) { createAndLoadFakeTrack(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); @@ -221,6 +221,46 @@ TEST_F(HotcueControlTest, SetLoopManual) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); } +TEST_F(HotcueControlTest, SetLoopManualWithoutLoop) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + loadTrack(pTrack); + ProcessBuffer(); + + const double beatLengthSamples = getBeatLengthSamples(pTrack); + m_pBeatloopSize->slotSet(4); + const double beatloopLengthSamples = m_pBeatloopSize->get() * getBeatLengthSamples(pTrack); + + setCurrentSamplePosition(8 * beatLengthSamples); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(currentSamplePosition(), m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(currentSamplePosition() + beatloopLengthSamples, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, SetLoopManualWithoutLoopOrBeats) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} + TEST_F(HotcueControlTest, CueGoto) { // Setup fake track with 120 bpm can calculate loop size TrackPointer pTrack = createTestTrack(); From 9263e612f1614529dcb55268b85f6c95338dcab5 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 16:33:14 +0200 Subject: [PATCH 096/153] engine/controls/cuecontrol: Allow hotcue_X_loop_toggle to set new loops --- src/engine/controls/cuecontrol.cpp | 3 ++- src/test/hotcuecontrol_test.cpp | 43 +++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c9e38b97ea72..32ab420226a4 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -956,7 +956,8 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); - if (!pCue) { + if (!pCue || pCue->getPosition() == Cue::kNoPosition) { + hotcueSet(pControl, v, HotcueMode::Loop); return; } diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index e08bca3fd81c..4f3cdf8ec365 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -855,7 +855,7 @@ TEST_F(HotcueControlTest, SavedLoopReset) { EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); } -TEST_F(HotcueControlTest, SavedLoopToggle) { +TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { createAndLoadFakeTrack(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); @@ -890,6 +890,47 @@ TEST_F(HotcueControlTest, SavedLoopToggle) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); } +TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopSetsNewLoop) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + loadTrack(pTrack); + ProcessBuffer(); + + const double beatLengthSamples = getBeatLengthSamples(pTrack); + m_pBeatloopSize->slotSet(4); + const double beatloopLengthSamples = m_pBeatloopSize->get() * getBeatLengthSamples(pTrack); + + setCurrentSamplePosition(8 * beatLengthSamples); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(currentSamplePosition(), m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(currentSamplePosition() + beatloopLengthSamples, m_pHotcue1EndPosition->get()); +} + +TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopOrBeats) { + createAndLoadFakeTrack(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1LoopToggle->slotSet(1); + m_pHotcue1LoopToggle->slotSet(0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} + TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { // Setup fake track with 120 bpm can calculate loop size TrackPointer pTrack = createTestTrack(); From b70061e6a7ce9ffbe206d7f4dad2cc885ceff42d Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 17:50:11 +0200 Subject: [PATCH 097/153] engine/controls/cuecontrol: Let "activate" jump to saved loop --- src/engine/controls/cuecontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 32ab420226a4..761776b9dd8b 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1008,7 +1008,7 @@ void CueControl::hotcueActivate( hotcueGoto(pControl, v); break; case mixxx::CueType::Loop: - hotcueLoopToggle(pControl, v); + hotcueGotoAndLoop(pControl, v); break; default: DEBUG_ASSERT(!"Invalid CueType!"); From a3c99bb67de8e362529244270c5287c296fe46f1 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 18:47:37 +0200 Subject: [PATCH 098/153] HotcueControlTest: Test that loop activate does not disable looping --- src/test/hotcuecontrol_test.cpp | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 4f3cdf8ec365..a0eb9ea98828 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1104,6 +1104,85 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(loopStartPositionSamples, currentSamplePosition()); } +TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingDoesNotDisableLoop) { + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(120.0); + + m_pBeatloopSize->slotSet(4); + const double beatLengthSamples = getBeatLengthSamples(pTrack); + const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; + const double loopStartPosition = 8 * beatLengthSamples; + const double loopEndPosition = loopStartPosition + loopLengthSamples; + loadTrack(pTrack); + ProcessBuffer(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop + setCurrentSamplePosition(loopStartPosition); + ProcessBuffer(); + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + + m_pQuantizeEnabled->slotSet(1); + m_pPlay->slotSet(1); + ProcessBuffer(); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopEndPosition, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(m_pHotcue1Position->get(), m_pLoopStartPosition->get()); + EXPECT_DOUBLE_EQ(m_pHotcue1EndPosition->get(), m_pLoopEndPosition->get()); + + const QList seekPositionsSamples = { + loopStartPosition + 0.1 * beatLengthSamples, + loopStartPosition + 0.25 * beatLengthSamples, + loopStartPosition + 0.5 * beatLengthSamples, + loopStartPosition + 0.75 * beatLengthSamples, + loopStartPosition + 0.9 * beatLengthSamples, + loopEndPosition - 0.1 * beatLengthSamples, + loopEndPosition - 0.25 * beatLengthSamples, + loopEndPosition - 0.5 * beatLengthSamples, + loopEndPosition - 0.75 * beatLengthSamples, + loopEndPosition - 0.9 * beatLengthSamples, + }; + + for (double seekPositionSamples : seekPositionsSamples) { + setCurrentSamplePosition(seekPositionSamples); + + ProcessBuffer(); + QCoreApplication::processEvents(); + + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), + m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopEndPosition, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(m_pHotcue1Position->get(), m_pLoopStartPosition->get()); + EXPECT_DOUBLE_EQ(m_pHotcue1EndPosition->get(), m_pLoopEndPosition->get()); + + ProcessBuffer(); + QCoreApplication::processEvents(); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), + m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(loopEndPosition, m_pHotcue1EndPosition->get()); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); + EXPECT_DOUBLE_EQ(m_pHotcue1Position->get(), m_pLoopStartPosition->get()); + EXPECT_DOUBLE_EQ(m_pHotcue1EndPosition->get(), m_pLoopEndPosition->get()); + } +} + TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { // Setup fake track with 120 bpm can calculate loop size TrackPointer pTrack = createTestTrack(); From 3735bee1fc19bb329dcb40abe8a8257319a48a93 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 8 Sep 2020 18:48:45 +0200 Subject: [PATCH 099/153] engine/controls/cuecontrol: Remove unused member variable --- src/engine/controls/cuecontrol.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index fe0de15ceff3..3f2a19c6b7fb 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -262,7 +262,6 @@ class CueControl : public EngineControl { parented_ptr m_pLoopStartPosition; parented_ptr m_pLoopEndPosition; parented_ptr m_pLoopEnabled; - parented_ptr m_pLoopToggle; parented_ptr m_pBeatLoopActivate; parented_ptr m_pBeatLoopSize; bool m_bypassCueSetByPlay; From 6614837d9878cd8d3f37f97e8d27cb55570697ad Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sat, 12 Sep 2020 00:08:44 +0200 Subject: [PATCH 100/153] engine/controls: Remove some debugging messages --- src/engine/controls/cuecontrol.cpp | 2 -- src/engine/controls/loopingcontrol.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 761776b9dd8b..bb265f22b3e0 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2116,8 +2116,6 @@ void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { } m_pCurrentSavedLoopControl = pControl; - qDebug() << "CueControl::setLoop" << pCue->getPosition() - << pCue->getEndPosition(); setLoop(pCue->getPosition(), pCue->getEndPosition(), true); pControl->setStatus(HotcueControl::Status::Active); } diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 63789a966469..2a83bd1225a0 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -548,7 +548,6 @@ void LoopingControl::setLoop(double startPosition, double endPosition, bool enab endPosition != Cue::kNoPosition && startPosition < endPosition) { return; } - qDebug() << "LoopingControl::setLoop" << startPosition << endPosition << enabled; LoopSamples loopSamples = m_loopSamples.getValue(); if (loopSamples.start != startPosition || loopSamples.end != endPosition) { From c17ff889486934b0ff6058948cba3cbf98b06526 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 22 Sep 2020 16:40:33 +0200 Subject: [PATCH 101/153] test/HotcueControlTest: Move some shared code into helper method --- src/test/hotcuecontrol_test.cpp | 159 ++++++++++---------------------- 1 file changed, 48 insertions(+), 111 deletions(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index a0eb9ea98828..60b8d3f5f6db 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -56,6 +56,18 @@ class HotcueControlTest : public BaseSignalPathTest { ProcessBuffer(); } + TrackPointer loadTestTrackWithBpm(double bpm) { + DEBUG_ASSERT(!m_pPlay->get()); + // Setup fake track with 120 bpm can calculate loop size + TrackPointer pTrack = createTestTrack(); + pTrack->setBpm(bpm); + + loadTrack(pTrack); + ProcessBuffer(); + + return pTrack; + } + TrackPointer createAndLoadFakeTrack() { return m_pMixerDeck1->loadFakeTrack(false, 0.0); } @@ -222,12 +234,8 @@ TEST_F(HotcueControlTest, SetLoopManualWithLoop) { } TEST_F(HotcueControlTest, SetLoopManualWithoutLoop) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); - - loadTrack(pTrack); - ProcessBuffer(); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); const double beatLengthSamples = getBeatLengthSamples(pTrack); m_pBeatloopSize->slotSet(4); @@ -262,12 +270,8 @@ TEST_F(HotcueControlTest, SetLoopManualWithoutLoopOrBeats) { } TEST_F(HotcueControlTest, CueGoto) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); - - loadTrack(pTrack); - ProcessBuffer(); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); @@ -303,12 +307,8 @@ TEST_F(HotcueControlTest, CueGoto) { } TEST_F(HotcueControlTest, CueGotoAndPlay) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); - - loadTrack(pTrack); - ProcessBuffer(); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); @@ -344,12 +344,8 @@ TEST_F(HotcueControlTest, CueGotoAndPlay) { } TEST_F(HotcueControlTest, CueGotoAndLoop) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); - - loadTrack(pTrack); - ProcessBuffer(); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); @@ -391,18 +387,14 @@ TEST_F(HotcueControlTest, CueGotoAndLoop) { } TEST_F(HotcueControlTest, SavedLoopGoto) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; const double cuePositionSamples = 8 * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -447,18 +439,14 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { } TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; const double cuePositionSamples = 8 * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -503,18 +491,14 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { } TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; const double cuePositionSamples = 8 * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -604,17 +588,13 @@ TEST_F(HotcueControlTest, SavedLoopStatus) { } TEST_F(HotcueControlTest, SavedLoopScale) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -654,18 +634,14 @@ TEST_F(HotcueControlTest, SavedLoopScale) { } TEST_F(HotcueControlTest, SavedLoopMove) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); constexpr double loopSize = 4; m_pBeatloopSize->slotSet(loopSize); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = loopSize * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -708,17 +684,13 @@ TEST_F(HotcueControlTest, SavedLoopMove) { } TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -763,18 +735,14 @@ TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { } TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); constexpr double loopSize = 4; m_pBeatloopSize->slotSet(loopSize); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = loopSize * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -816,17 +784,13 @@ TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { } TEST_F(HotcueControlTest, SavedLoopReset) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -891,20 +855,12 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { } TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopSetsNewLoop) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); - - loadTrack(pTrack); - ProcessBuffer(); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); - const double beatLengthSamples = getBeatLengthSamples(pTrack); m_pBeatloopSize->slotSet(4); const double beatloopLengthSamples = m_pBeatloopSize->get() * getBeatLengthSamples(pTrack); - setCurrentSamplePosition(8 * beatLengthSamples); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -932,9 +888,8 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopOrBeats) { } TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); constexpr double loopSize = 4; const double beatLengthSamples = getBeatLengthSamples(pTrack); @@ -944,9 +899,6 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { const double loopStartPositionSamples = 8 * beatLengthSamples; const double afterLoopPositionSamples = 16 * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1031,9 +983,8 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { } TEST_F(HotcueControlTest, SavedLoopActivate) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); @@ -1043,9 +994,6 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { const double loopStartPositionSamples = 8 * beatLengthSamples; const double afterLoopPositionSamples = 16 * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1105,17 +1053,14 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { } TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingDoesNotDisableLoop) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); m_pBeatloopSize->slotSet(4); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; const double loopStartPosition = 8 * beatLengthSamples; const double loopEndPosition = loopStartPosition + loopLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); @@ -1184,18 +1129,14 @@ TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingDoesNotDisableLoop) { } TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); constexpr double savedLoopSize = 8; m_pBeatloopSize->slotSet(savedLoopSize); const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1233,9 +1174,8 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { } TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { - // Setup fake track with 120 bpm can calculate loop size - TrackPointer pTrack = createTestTrack(); - pTrack->setBpm(120.0); + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); constexpr double savedLoopSize = 4; m_pBeatloopSize->slotSet(savedLoopSize); @@ -1245,9 +1185,6 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { const double beforeLoopPositionSamples = 0; const double afterLoopPositionSamples = beatLengthSamples; - loadTrack(pTrack); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); From de9eff7f87d22d24d606f05d57cfbfcfcfd63121 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 22 Sep 2020 23:34:37 +0200 Subject: [PATCH 102/153] CueControl: Improve some checks and add debug assertions --- src/engine/controls/cuecontrol.cpp | 38 +++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index bb265f22b3e0..caf2d55c35df 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -747,18 +747,18 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { // position and with the current beatloop size cueStartPosition = getQuantizedCurrentPosition(); double beatloopSize = m_pBeatLoopSize->get(); - if (beatloopSize > 0) { - mixxx::BeatsPointer pBeats = m_pLoadedTrack->getBeats(); - if (pBeats) { - cueEndPosition = pBeats->findNBeatsFromSample(cueStartPosition, beatloopSize); - } + const mixxx::BeatsPointer pBeats = m_pLoadedTrack->getBeats(); + if (beatloopSize <= 0 || !pBeats) { + return; } + cueEndPosition = pBeats->findNBeatsFromSample(cueStartPosition, beatloopSize); } cueType = mixxx::CueType::Loop; break; } default: DEBUG_ASSERT(!"Invalid HotcueMode"); + return; } VERIFY_OR_DEBUG_ASSERT(cueType != mixxx::CueType::Invalid) { @@ -768,9 +768,9 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { // Abort if no position has been found. This can happen if a loop cue is // requested while no loop is set and the track has no beatgrid, so we // can't debug assert here. - if (cueStartPosition == Cue::kNoPosition || - (cueType == mixxx::CueType::Loop && - cueEndPosition == Cue::kNoPosition)) { + VERIFY_OR_DEBUG_ASSERT(cueStartPosition != Cue::kNoPosition && + (cueType != mixxx::CueType::Loop || + cueEndPosition != Cue::kNoPosition)) { return; } @@ -966,16 +966,15 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { if (m_pCurrentSavedLoopControl != pControl) { setCurrentSavedLoopControl(pControl); } else { - bool loopActive = !(pControl->getStatus() == HotcueControl::Status::Active); - setLoop(pCue->getPosition(), pCue->getEndPosition(), loopActive); + bool loopActive = pControl->getStatus() == HotcueControl::Status::Active; + setLoop(pCue->getPosition(), pCue->getEndPosition(), !loopActive); } } break; case mixxx::CueType::HotCue: { setCurrentSavedLoopControl(nullptr); double startPosition = pCue->getPosition(); - bool enabled = startPosition != m_pLoopStartPosition->get() || - !m_pLoopEnabled->get(); - setBeatLoop(startPosition, enabled); + bool loopActive = m_pLoopEnabled->get() && (startPosition == m_pLoopStartPosition->get()); + setBeatLoop(startPosition, !loopActive); break; } default: @@ -2090,11 +2089,11 @@ void CueControl::hotcueFocusColorNext(double v) { void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { if (m_pCurrentSavedLoopControl && m_pCurrentSavedLoopControl != pControl) { // Disable previous saved loop + DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Invalid); m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Valid); m_pCurrentSavedLoopControl = nullptr; } - // Set new control as active if (!pControl) { return; } @@ -2115,6 +2114,7 @@ void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { return; } + // Set new control as active m_pCurrentSavedLoopControl = pControl; setLoop(pCue->getPosition(), pCue->getEndPosition(), true); pControl->setStatus(HotcueControl::Status::Active); @@ -2129,6 +2129,16 @@ void CueControl::slotLoopToggled(bool enabled) { return; } + DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Invalid); + DEBUG_ASSERT( + m_pCurrentSavedLoopControl->getCue() && + m_pCurrentSavedLoopControl->getCue()->getPosition() == + m_pLoopStartPosition->get()); + DEBUG_ASSERT( + m_pCurrentSavedLoopControl->getCue() && + m_pCurrentSavedLoopControl->getCue()->getEndPosition() == + m_pLoopEndPosition->get()); + if (enabled) { m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Active); } else { From 2d943dbb1e97453e6f378ca3a426c5abf8e3c836 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 22 Sep 2020 23:51:22 +0200 Subject: [PATCH 103/153] LoopingControl: Rename loopToggled signal to loopEnabledChanged --- src/engine/controls/cuecontrol.cpp | 2 +- src/engine/controls/cuecontrol.h | 2 +- src/engine/controls/loopingcontrol.cpp | 2 +- src/engine/controls/loopingcontrol.h | 2 +- src/engine/enginebuffer.cpp | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index caf2d55c35df..f10c3a821b85 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2124,7 +2124,7 @@ void CueControl::slotLoopReset() { setCurrentSavedLoopControl(nullptr); } -void CueControl::slotLoopToggled(bool enabled) { +void CueControl::slotLoopEnabledChanged(bool enabled) { if (!m_pCurrentSavedLoopControl) { return; } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 3f2a19c6b7fb..39d739459bfc 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -183,7 +183,7 @@ class CueControl : public EngineControl { public slots: void slotLoopReset(); - void slotLoopToggled(bool enabled); + void slotLoopEnabledChanged(bool enabled); void slotLoopUpdated(double startPosition, double endPosition); private slots: diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 2a83bd1225a0..b8d7819010e9 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -945,7 +945,7 @@ void LoopingControl::setLoopingEnabled(bool enabled) { } } - emit loopToggled(enabled); + emit loopEnabledChanged(enabled); } bool LoopingControl::isLoopingEnabled() { diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index aa10a984e8d9..03f2623b63a2 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -62,7 +62,7 @@ class LoopingControl : public EngineControl { signals: void loopReset(); - void loopToggled(bool enabled); + void loopEnabledChanged(bool enabled); void loopUpdated(double startPosition, double endPosition); public slots: diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 7e369ad4edd1..7c9ffd597ec9 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -243,9 +243,9 @@ EngineBuffer::EngineBuffer(const QString& group, &CueControl::slotLoopUpdated, Qt::DirectConnection); connect(m_pLoopingControl, - &LoopingControl::loopToggled, + &LoopingControl::loopEnabledChanged, m_pCueControl, - &CueControl::slotLoopToggled, + &CueControl::slotLoopEnabledChanged, Qt::DirectConnection); m_pReadAheadManager = new ReadAheadManager(m_pReader, From e22f60c91618e4b21dd84671ac41e71582667fbb Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 23 Sep 2020 00:22:05 +0200 Subject: [PATCH 104/153] CueControl: Add comment regarding broken locking mechanism --- src/engine/controls/cuecontrol.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 39d739459bfc..73997dc77492 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -323,6 +323,17 @@ class CueControl : public EngineControl { // Tells us which controls map to which hotcue QMap m_controlMap; + // TODO(daschuer): It looks like the whole m_mutex is broken. Originally it + // ensured that the main cue really belongs to the loaded track. Now that + // we have hot cues that are altered outsite this guard this guarantee has + // become void. + // + // We have multiple cases where it locks m_pLoadedTrack and + // pControl->getCue(). This guards the hotcueClear() that could detach the + // cue call, but doesn't protect from cue changes via loadCuesFromTrack() + // which is called outside the mutex lock. + // + // We need to repair this. QMutex m_mutex; friend class HotcueControlTest; From 3cbd39c5f2d16f08129964c8d3d5f6959577f93d Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 23 Sep 2020 00:22:59 +0200 Subject: [PATCH 105/153] CueControl: Reset current saved loop if cue is not a loop --- src/engine/controls/cuecontrol.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index f10c3a821b85..4c9301a9b7cd 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2167,6 +2167,7 @@ void CueControl::slotLoopUpdated(double startPosition, double endPosition) { lock.unlock(); VERIFY_OR_DEBUG_ASSERT(pCue->getType() == mixxx::CueType::Loop) { + setCurrentSavedLoopControl(nullptr); return; } From 66fe407c567d146fa67e0b68ce9cf9270f0a09bc Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 23 Sep 2020 00:39:24 +0200 Subject: [PATCH 106/153] HotcueControl: Use "Active" state for previewing hotcues --- src/engine/controls/cuecontrol.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 4c9301a9b7cd..dd10aa97e0f6 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1056,6 +1056,8 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { pControl->setPreviewingPosition(position); if (pCue->getType() == mixxx::CueType::Loop) { setCurrentSavedLoopControl(pControl); + } else if (pControl->getStatus() == HotcueControl::Status::Valid) { + pControl->setStatus(HotcueControl::Status::Active); } // Need to unlock before emitting any signals to prevent deadlock. @@ -1080,6 +1082,8 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { lock.unlock(); if (cueType == mixxx::CueType::Loop) { m_pLoopEnabled->set(0); + } else if (pControl->getStatus() == HotcueControl::Status::Active) { + pControl->setStatus(HotcueControl::Status::Valid); } seekExact(position); } From 87b831d533ce2b8137cacca1bbd0867b1d3cac75 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 24 Sep 2020 15:48:00 +0200 Subject: [PATCH 107/153] HotcueControlTest: Enable playback where missing and fix comparisons --- src/test/hotcuecontrol_test.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 60b8d3f5f6db..368e08be472a 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1006,6 +1006,8 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); + m_pPlay->set(1); + // Save currently active loop to hotcue slot 1 m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); @@ -1015,8 +1017,7 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { // Seek to start of track setCurrentSamplePosition(beforeLoopPositionSamples); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); + EXPECT_NEAR(beforeLoopPositionSamples, currentSamplePosition(), 2000); // Check that the previous seek disabled the loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); @@ -1030,9 +1031,8 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples, currentSamplePosition()); + EXPECT_NEAR(loopStartPositionSamples, currentSamplePosition(), 2000); - // Disable loop // Seek to position after saved loop setCurrentSamplePosition(afterLoopPositionSamples); ProcessBuffer(); @@ -1049,7 +1049,7 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples, currentSamplePosition()); + EXPECT_NEAR(loopStartPositionSamples, currentSamplePosition(), 2000); } TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingDoesNotDisableLoop) { @@ -1145,6 +1145,8 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); + m_pPlay->set(1); + // Save currently active loop to hotcue slot 1 m_pHotcue1ActivateLoop->slotSet(1); m_pHotcue1ActivateLoop->slotSet(0); @@ -1205,6 +1207,8 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); + m_pPlay->set(1); + // Check 1: Play position before saved loop // Disable loop @@ -1214,12 +1218,11 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - // Seek to position before saved loop - setCurrentSamplePosition(beforeLoopPositionSamples); - // Set new beatloop size m_pBeatloopSize->slotSet(m_pBeatloopSize->get() / 2); - ProcessBuffer(); + + // Seek to position before saved loop + setCurrentSamplePosition(beforeLoopPositionSamples); // Re-enable saved loop m_pHotcue1LoopToggle->slotSet(1); @@ -1232,7 +1235,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { EXPECT_DOUBLE_EQ(savedLoopSize, m_pBeatloopSize->get()); // Check that enabling the loop didn't cause a jump - EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); + EXPECT_NEAR(beforeLoopPositionSamples, currentSamplePosition(), 2000); // Check 2: Play position after saved loop @@ -1243,12 +1246,11 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - // Seek to position after saved loop - setCurrentSamplePosition(afterLoopPositionSamples); - // Set new beatloop size m_pBeatloopSize->slotSet(m_pBeatloopSize->get() / 2); - ProcessBuffer(); + + // Seek to position after saved loop + setCurrentSamplePosition(afterLoopPositionSamples); // Re-enable saved loop m_pHotcue1LoopToggle->slotSet(1); @@ -1261,5 +1263,5 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { EXPECT_DOUBLE_EQ(savedLoopSize, m_pBeatloopSize->get()); // Check that enabling the loop didn't cause a jump - EXPECT_DOUBLE_EQ(afterLoopPositionSamples, currentSamplePosition()); + EXPECT_NEAR(afterLoopPositionSamples, currentSamplePosition(), 2000); } From a2c7c0e4b4c884129dafe457ccb597afb0230aff Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 24 Sep 2020 15:49:33 +0200 Subject: [PATCH 108/153] LoopingControl: Replace loop_toggle CO by making loop_enabled writable --- src/engine/controls/loopingcontrol.cpp | 60 +++++++++++++++----------- src/engine/controls/loopingcontrol.h | 4 +- src/test/hotcuecontrol_test.cpp | 32 +++++--------- 3 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index b8d7819010e9..c424fe95dd5c 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -82,12 +82,6 @@ LoopingControl::LoopingControl(QString group, Qt::DirectConnection); m_pLoopExitButton->set(0); - m_pLoopToggleButton = new ControlPushButton(ConfigKey(group, "loop_toggle")); - connect(m_pLoopToggleButton, &ControlObject::valueChanged, - this, &LoopingControl::slotLoopToggle, - Qt::DirectConnection); - m_pLoopToggleButton->set(0); - m_pReloopToggleButton = new ControlPushButton(ConfigKey(group, "reloop_toggle")); connect(m_pReloopToggleButton, &ControlObject::valueChanged, this, &LoopingControl::slotReloopToggle, @@ -104,6 +98,9 @@ LoopingControl::LoopingControl(QString group, m_pCOLoopEnabled = new ControlObject(ConfigKey(group, "loop_enabled")); m_pCOLoopEnabled->set(0.0); + m_pCOLoopEnabled->connectValueChangeRequest(this, + &LoopingControl::slotLoopEnabledValueChangeRequest, + Qt::DirectConnection); m_pCOLoopStartPosition = new ControlObject(ConfigKey(group, "loop_start_position")); @@ -217,7 +214,6 @@ LoopingControl::~LoopingControl() { delete m_pLoopInButton; delete m_pLoopInGotoButton; delete m_pLoopExitButton; - delete m_pLoopToggleButton; delete m_pReloopToggleButton; delete m_pReloopAndStopButton; delete m_pCOLoopEnabled; @@ -788,30 +784,42 @@ void LoopingControl::slotLoopExit(double val) { } } -void LoopingControl::slotLoopToggle(double val) { - if (!m_pTrack || val <= 0.0) { +void LoopingControl::slotLoopEnabledValueChangeRequest(double value) { + if (!m_pTrack) { return; } - // If we're looping, stop looping - if (m_bLoopingEnabled) { - // If loop roll was active, also disable slip. - if (m_bLoopRollActive) { - m_pSlipEnabled->set(0); - m_bLoopRollActive = false; - m_activeLoopRolls.clear(); + if (value) { + // Requested to set loop_enabled to 1 + if (m_bLoopingEnabled) { + DEBUG_ASSERT(m_pCOLoopEnabled->get()); + m_pCOLoopEnabled->setAndConfirm(1.0); + } else { + // Looping is currently disabled, try to enable the loop. In + // contrast to the reloop_toggle CO, we do not jump in any case. + LoopSamples loopSamples = m_loopSamples.getValue(); + if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger && + loopSamples.start <= loopSamples.end) { + // setAndConfirm is called by setLoopingEnabled + setLoopingEnabled(true); + } } - setLoopingEnabled(false); - //qDebug() << "loop_toggle looping off"; } else { - // If we're not looping, enable the loop. - // In contrast to the reloop_toggle CO, we do not jump in any case. - LoopSamples loopSamples = m_loopSamples.getValue(); - if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger && - loopSamples.start <= loopSamples.end) { - setLoopingEnabled(true); + // Requested to set loop_enabled to 0 + if (m_bLoopingEnabled) { + // Looping is currently enabled, disable the loop. If loop roll + // was active, also disable slip. + if (m_bLoopRollActive) { + m_pSlipEnabled->set(0); + m_bLoopRollActive = false; + m_activeLoopRolls.clear(); + } + // setAndConfirm is called by setLoopingEnabled + setLoopingEnabled(false); + } else { + DEBUG_ASSERT(!m_pCOLoopEnabled->get()); + m_pCOLoopEnabled->setAndConfirm(0.0); } - //qDebug() << "loop_toggle looping on"; } } @@ -935,7 +943,7 @@ void LoopingControl::notifySeek(double dNewPlaypos) { void LoopingControl::setLoopingEnabled(bool enabled) { m_bLoopingEnabled = enabled; - m_pCOLoopEnabled->set(enabled); + m_pCOLoopEnabled->setAndConfirm(enabled ? 1.0 : 0.0); BeatLoopingControl* pActiveBeatLoop = atomicLoadRelaxed(m_pActiveBeatLoop); if (pActiveBeatLoop != nullptr) { if (enabled) { diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 03f2623b63a2..e09258c1f4fa 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -71,7 +71,6 @@ class LoopingControl : public EngineControl { void slotLoopOut(double pressed); void slotLoopOutGoto(double); void slotLoopExit(double); - void slotLoopToggle(double); void slotReloopToggle(double); void slotReloopAndStop(double); void slotLoopStartPos(double); @@ -100,6 +99,9 @@ class LoopingControl : public EngineControl { void slotLoopDouble(double pressed); void slotLoopHalve(double pressed); + private slots: + void slotLoopEnabledValueChangeRequest(double enabled); + private: enum class LoopSeekMode { Changed, // force the playposition to be inside the loop after adjusting it. diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 368e08be472a..6606e7c307c0 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -22,7 +22,6 @@ class HotcueControlTest : public BaseSignalPathTest { m_pLoopDouble = std::make_unique(m_sGroup1, "loop_double"); m_pLoopHalve = std::make_unique(m_sGroup1, "loop_halve"); m_pLoopMove = std::make_unique(m_sGroup1, "loop_move"); - m_pLoopToggle = std::make_unique(m_sGroup1, "loop_toggle"); m_pHotcue1Activate = std::make_unique(m_sGroup1, "hotcue_1_activate"); m_pHotcue1ActivateCue = std::make_unique(m_sGroup1, "hotcue_1_activatecue"); m_pHotcue1ActivateLoop = std::make_unique(m_sGroup1, "hotcue_1_activateloop"); @@ -94,7 +93,6 @@ class HotcueControlTest : public BaseSignalPathTest { std::unique_ptr m_pLoopDouble; std::unique_ptr m_pLoopHalve; std::unique_ptr m_pLoopMove; - std::unique_ptr m_pLoopToggle; std::unique_ptr m_pHotcue1Activate; std::unique_ptr m_pHotcue1ActivateCue; std::unique_ptr m_pHotcue1ActivateLoop; @@ -417,8 +415,7 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); @@ -469,8 +466,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); @@ -521,8 +517,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); @@ -561,8 +556,7 @@ TEST_F(HotcueControlTest, SavedLoopStatus) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); // Disable Loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); @@ -570,8 +564,7 @@ TEST_F(HotcueControlTest, SavedLoopStatus) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); // Re-Enable Loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(1); EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); @@ -709,8 +702,7 @@ TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); // Double loop size (4 => 8 beats) while saved loop is disabled @@ -760,8 +752,7 @@ TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable Loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); @@ -1155,8 +1146,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); // Disable loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1212,8 +1202,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { // Check 1: Play position before saved loop // Disable loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1240,8 +1229,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { // Check 2: Play position after saved loop // Disable loop - m_pLoopToggle->slotSet(1); - m_pLoopToggle->slotSet(0); + m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); From 772d099683164792930993f2f4aba1bd4aa9fc33 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 27 Sep 2020 14:00:03 +0200 Subject: [PATCH 109/153] widget/whotcuebutton: Add type property to hotcue buttons --- src/widget/whotcuebutton.cpp | 43 ++++++++++++++++++++++++++++++++++++ src/widget/whotcuebutton.h | 5 +++++ 2 files changed, 48 insertions(+) diff --git a/src/widget/whotcuebutton.cpp b/src/widget/whotcuebutton.cpp index 65c780242c26..2f213c5955fc 100644 --- a/src/widget/whotcuebutton.cpp +++ b/src/widget/whotcuebutton.cpp @@ -44,6 +44,13 @@ void WHotcueButton::setup(const QDomNode& node, const SkinContext& context) { m_pCoColor->connectValueChanged(this, &WHotcueButton::slotColorChanged); slotColorChanged(m_pCoColor->get()); + m_pCoType = make_parented( + createConfigKey(QStringLiteral("type")), + this, + ControlFlag::NoAssertIfMissing); + m_pCoType->connectValueChanged(this, &WHotcueButton::slotTypeChanged); + slotTypeChanged(m_pCoType->get()); + auto pLeftConnection = new ControlParameterWidgetConnection( this, createConfigKey(QStringLiteral("activate")), @@ -133,6 +140,42 @@ void WHotcueButton::slotColorChanged(double color) { restyleAndRepaint(); } +void WHotcueButton::slotTypeChanged(double type) { + switch (static_cast(type)) { + case mixxx::CueType::Invalid: + m_type = QStringLiteral(""); + break; + case mixxx::CueType::HotCue: + m_type = QStringLiteral("hotcue"); + break; + case mixxx::CueType::MainCue: + m_type = QStringLiteral("maincue"); + break; + case mixxx::CueType::Beat: + m_type = QStringLiteral("beat"); + break; + case mixxx::CueType::Loop: + m_type = QStringLiteral("loop"); + break; + case mixxx::CueType::Jump: + m_type = QStringLiteral("jump"); + break; + case mixxx::CueType::Intro: + m_type = QStringLiteral("intro"); + break; + case mixxx::CueType::Outro: + m_type = QStringLiteral("outro"); + break; + case mixxx::CueType::AudibleSound: + m_type = QStringLiteral("audiblesound"); + break; + default: + DEBUG_ASSERT(!"Unknown cue type!"); + m_type = QStringLiteral(""); + } + restyleAndRepaint(); +} + void WHotcueButton::restyleAndRepaint() { if (readDisplayValue()) { // Adjust properties for Qss file diff --git a/src/widget/whotcuebutton.h b/src/widget/whotcuebutton.h index 0229958f802f..ef2734c11d4b 100644 --- a/src/widget/whotcuebutton.h +++ b/src/widget/whotcuebutton.h @@ -2,6 +2,7 @@ #include #include +#include #include #include "skin/skincontext.h" @@ -18,6 +19,7 @@ class WHotcueButton : public WPushButton { Q_PROPERTY(bool light MEMBER m_isCueColorLight); Q_PROPERTY(bool dark MEMBER m_isCueColorDark); + Q_PROPERTY(QString type MEMBER m_type); protected: void mousePressEvent(QMouseEvent* e) override; @@ -25,6 +27,7 @@ class WHotcueButton : public WPushButton { private slots: void slotColorChanged(double color); + void slotTypeChanged(double type); private: ConfigKey createConfigKey(const QString& name); @@ -34,8 +37,10 @@ class WHotcueButton : public WPushButton { int m_hotcue; bool m_hoverCueColor; parented_ptr m_pCoColor; + parented_ptr m_pCoType; parented_ptr m_pCueMenuPopup; bool m_cueColorDimmed; bool m_isCueColorLight; bool m_isCueColorDark; + QString m_type; }; From 27278cd5de7d1289cd9bb2b09dc4ddd56b4f8c6d Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 27 Sep 2020 14:01:02 +0200 Subject: [PATCH 110/153] LateNight PaleMoon: Add styling for loop cues to hotcue buttons --- .../palemoon/buttons/btn__1_loop.svg | 167 ++++++++++++++++++ .../palemoon/buttons/btn__2_loop.svg | 109 ++++++++++++ .../palemoon/buttons/btn__3_loop.svg | 109 ++++++++++++ .../palemoon/buttons/btn__4_loop.svg | 109 ++++++++++++ .../palemoon/buttons/btn__5_loop.svg | 109 ++++++++++++ .../palemoon/buttons/btn__6_loop.svg | 109 ++++++++++++ .../palemoon/buttons/btn__7_loop.svg | 109 ++++++++++++ .../palemoon/buttons/btn__8_loop.svg | 159 +++++++++++++++++ res/skins/LateNight/style_palemoon.qss | 48 +++++ 9 files changed, 1028 insertions(+) create mode 100644 res/skins/LateNight/palemoon/buttons/btn__1_loop.svg create mode 100644 res/skins/LateNight/palemoon/buttons/btn__2_loop.svg create mode 100644 res/skins/LateNight/palemoon/buttons/btn__3_loop.svg create mode 100644 res/skins/LateNight/palemoon/buttons/btn__4_loop.svg create mode 100644 res/skins/LateNight/palemoon/buttons/btn__5_loop.svg create mode 100644 res/skins/LateNight/palemoon/buttons/btn__6_loop.svg create mode 100644 res/skins/LateNight/palemoon/buttons/btn__7_loop.svg create mode 100644 res/skins/LateNight/palemoon/buttons/btn__8_loop.svg diff --git a/res/skins/LateNight/palemoon/buttons/btn__1_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__1_loop.svg new file mode 100644 index 000000000000..f4a66fb01a92 --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__1_loop.svg @@ -0,0 +1,167 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + diff --git a/res/skins/LateNight/palemoon/buttons/btn__2_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__2_loop.svg new file mode 100644 index 000000000000..501235396fd6 --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__2_loop.svg @@ -0,0 +1,109 @@ + + + + + + + image/svg+xml + + + + + + + 2 + + + + + + + diff --git a/res/skins/LateNight/palemoon/buttons/btn__3_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__3_loop.svg new file mode 100644 index 000000000000..e5327ba2c1b0 --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__3_loop.svg @@ -0,0 +1,109 @@ + + + + + + + image/svg+xml + + + + + + + 3 + + + + + + + diff --git a/res/skins/LateNight/palemoon/buttons/btn__4_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__4_loop.svg new file mode 100644 index 000000000000..2c2ce420c775 --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__4_loop.svg @@ -0,0 +1,109 @@ + + + + + + + image/svg+xml + + + + + + + 4 + + + + + + + diff --git a/res/skins/LateNight/palemoon/buttons/btn__5_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__5_loop.svg new file mode 100644 index 000000000000..7757dcc9ac7d --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__5_loop.svg @@ -0,0 +1,109 @@ + + + + + + + image/svg+xml + + + + + + + 5 + + + + + + + diff --git a/res/skins/LateNight/palemoon/buttons/btn__6_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__6_loop.svg new file mode 100644 index 000000000000..e284a940e41c --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__6_loop.svg @@ -0,0 +1,109 @@ + + + + + + + image/svg+xml + + + + + + + 6 + + + + + + + diff --git a/res/skins/LateNight/palemoon/buttons/btn__7_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__7_loop.svg new file mode 100644 index 000000000000..03f4ac0c1b46 --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__7_loop.svg @@ -0,0 +1,109 @@ + + + + + + + image/svg+xml + + + + + + + 7 + + + + + + + diff --git a/res/skins/LateNight/palemoon/buttons/btn__8_loop.svg b/res/skins/LateNight/palemoon/buttons/btn__8_loop.svg new file mode 100644 index 000000000000..db05c078bdf0 --- /dev/null +++ b/res/skins/LateNight/palemoon/buttons/btn__8_loop.svg @@ -0,0 +1,159 @@ + + + + + + + image/svg+xml + + + + + + + 8 + + + + + + + + + + + + + diff --git a/res/skins/LateNight/style_palemoon.qss b/res/skins/LateNight/style_palemoon.qss index a3234f97fd40..e33e43420837 100644 --- a/res/skins/LateNight/style_palemoon.qss +++ b/res/skins/LateNight/style_palemoon.qss @@ -1810,6 +1810,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue1 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__1_active_dark.svg) no-repeat center center; } + #Hotcue1 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue1 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue1 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue1 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__1_loop.svg) no-repeat center center; + } #Hotcue2 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__2.svg) no-repeat center center; @@ -1822,6 +1828,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue2 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__2_active_dark.svg) no-repeat center center; } + #Hotcue2 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue2 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue2 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue2 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__2_loop.svg) no-repeat center center; + } #Hotcue3 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__3.svg) no-repeat center center; @@ -1834,6 +1846,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue3 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__3_active_dark.svg) no-repeat center center; } + #Hotcue3 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue3 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue3 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue3 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__3_loop.svg) no-repeat center center; + } #Hotcue4 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__4.svg) no-repeat center center; @@ -1846,6 +1864,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue4 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__4_active_dark.svg) no-repeat center center; } + #Hotcue4 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue4 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue4 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue4 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__4_loop.svg) no-repeat center center; + } #Hotcue5 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__5.svg) no-repeat center center; @@ -1858,6 +1882,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue5 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__5_active_dark.svg) no-repeat center center; } + #Hotcue5 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue5 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue5 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue5 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__5_loop.svg) no-repeat center center; + } #Hotcue6 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__6.svg) no-repeat center center; @@ -1870,6 +1900,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue6 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__6_active_dark.svg) no-repeat center center; } + #Hotcue6 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue6 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue6 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue6 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__6_loop.svg) no-repeat center center; + } #Hotcue7 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__7.svg) no-repeat center center; @@ -1882,6 +1918,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue7 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__7_active_dark.svg) no-repeat center center; } + #Hotcue7 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue7 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue7 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue7 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__7_loop.svg) no-repeat center center; + } #Hotcue8 WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__8.svg) no-repeat center center; @@ -1894,6 +1936,12 @@ WPushButton#RecButton[displayValue="1"], #Hotcue8 WPushButton[displayValue="2"][dark="true"] { image: url(skin:/palemoon/buttons/btn__8_active_dark.svg) no-repeat center center; } + #Hotcue8 WPushButton[type="loop"][displayValue="1"][dark="false"], + #Hotcue8 WPushButton[type="loop"][displayValue="2"][dark="false"], + #Hotcue8 WPushButton[type="loop"][displayValue="1"][dark="true"], + #Hotcue8 WPushButton[type="loop"][displayValue="2"][dark="true"] { + image: url(skin:/palemoon/buttons/btn__8_loop.svg) no-repeat center center; + } #SpecialCueButton_intro_start WPushButton[displayValue="0"] { image: url(skin:/palemoon/buttons/btn__intro_start.svg) no-repeat center center; From f6b196d8e36f4a5b7da4fffee3ffa5a3e243c768 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 27 Sep 2020 19:34:23 +0200 Subject: [PATCH 111/153] engine/controls: Fix some code formatting issues --- src/engine/controls/cuecontrol.cpp | 30 ++++++++----- src/engine/controls/loopingcontrol.cpp | 60 ++++++++++++++------------ 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 2c25d0c46467..6f10317ebc42 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2240,13 +2240,17 @@ HotcueControl::HotcueControl(QString group, int i) Qt::DirectConnection); m_hotcueSetCue = new ControlPushButton(keyForControl(i, "setcue")); - connect(m_hotcueSetCue, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcueSetCue, + connect(m_hotcueSetCue, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueSetCue, Qt::DirectConnection); m_hotcueSetLoop = new ControlPushButton(keyForControl(i, "setloop")); - connect(m_hotcueSetLoop, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcueSetLoop, + connect(m_hotcueSetLoop, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueSetLoop, Qt::DirectConnection); m_hotcueGoto = new ControlPushButton(keyForControl(i, "goto")); @@ -2265,8 +2269,10 @@ HotcueControl::HotcueControl(QString group, int i) Qt::DirectConnection); m_hotcueGotoAndLoop = new ControlPushButton(keyForControl(i, "gotoandloop")); - connect(m_hotcueGotoAndLoop, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcueGotoAndLoop, + connect(m_hotcueGotoAndLoop, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueGotoAndLoop, Qt::DirectConnection); m_hotcueLoopToggle = new ControlPushButton(keyForControl(i, "loop_toggle")); @@ -2282,13 +2288,17 @@ HotcueControl::HotcueControl(QString group, int i) Qt::DirectConnection); m_hotcueActivateCue = new ControlPushButton(keyForControl(i, "activatecue")); - connect(m_hotcueActivateCue, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcueActivateCue, + connect(m_hotcueActivateCue, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueActivateCue, Qt::DirectConnection); m_hotcueActivateLoop = new ControlPushButton(keyForControl(i, "activateloop")); - connect(m_hotcueActivateLoop, &ControlObject::valueChanged, - this, &HotcueControl::slotHotcueActivateLoop, + connect(m_hotcueActivateLoop, + &ControlObject::valueChanged, + this, + &HotcueControl::slotHotcueActivateLoop, Qt::DirectConnection); m_hotcueActivatePreview = new ControlPushButton(keyForControl(i, "activate_preview")); diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index c424fe95dd5c..18fb41d24881 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -49,7 +49,7 @@ LoopingControl::LoopingControl(QString group, m_bAdjustingLoopInOld(false), m_bAdjustingLoopOutOld(false), m_bLoopOutPressedWhileLoopDisabled(false) { - m_oldLoopSamples = { kNoTrigger, kNoTrigger, LoopSeekMode::MovedOut }; + m_oldLoopSamples = {kNoTrigger, kNoTrigger, LoopSeekMode::MovedOut}; m_loopSamples.setValue(m_oldLoopSamples); m_currentSample.setValue(0.0); m_pActiveBeatLoop = NULL; @@ -283,7 +283,9 @@ void LoopingControl::slotLoopScale(double scaleFactor) { } // Reseek if the loop shrank out from under the playposition. - loopSamples.seekMode = (m_bLoopingEnabled && scaleFactor < 1.0) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; + loopSamples.seekMode = (m_bLoopingEnabled && scaleFactor < 1.0) + ? LoopSeekMode::Changed + : LoopSeekMode::MovedOut; m_loopSamples.setValue(loopSamples); emit loopUpdated(loopSamples.start, loopSamples.end); @@ -395,33 +397,37 @@ double LoopingControl::nextTrigger(bool reverse, loopSamples.end != m_oldLoopSamples.end) { // bool seek is only valid after the loop has changed bool movedOut; - switch(loopSamples.seekMode) { - case LoopSeekMode::Changed: - // here the loop has changed and the play position - // should be moved with it - *pTarget = seekInsideAdjustedLoop(currentSample, - m_oldLoopSamples.start, loopSamples.start, loopSamples.end); - break; - case LoopSeekMode::MovedOut: - movedOut = false; - // Check if we have moved out of the loop, before we could enable it - if (reverse) { - if (loopSamples.start > currentSample) { - movedOut = true; - } - } else { - if (loopSamples.end < currentSample) { - movedOut = true; - } + switch (loopSamples.seekMode) { + case LoopSeekMode::Changed: + // here the loop has changed and the play position + // should be moved with it + *pTarget = seekInsideAdjustedLoop(currentSample, + m_oldLoopSamples.start, + loopSamples.start, + loopSamples.end); + break; + case LoopSeekMode::MovedOut: + movedOut = false; + // Check if we have moved out of the loop, before we could enable it + if (reverse) { + if (loopSamples.start > currentSample) { + movedOut = true; } - if (movedOut) { - *pTarget = seekInsideAdjustedLoop(currentSample, - loopSamples.start, loopSamples.start, loopSamples.end); + } else { + if (loopSamples.end < currentSample) { + movedOut = true; } - break; - case LoopSeekMode::None: - // Nothing to do here - break; + } + if (movedOut) { + *pTarget = seekInsideAdjustedLoop(currentSample, + loopSamples.start, + loopSamples.start, + loopSamples.end); + } + break; + case LoopSeekMode::None: + // Nothing to do here + break; } m_oldLoopSamples = loopSamples; if (*pTarget != kNoTrigger) { From d41ab4bd637a6ead06ebc507275f5be3c05a5405 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 9 Oct 2020 13:46:36 +0200 Subject: [PATCH 112/153] engine/controls/cuecontrol: Do not jump when activating saved loop --- src/engine/controls/cuecontrol.cpp | 3 +- src/test/hotcuecontrol_test.cpp | 78 ++++++------------------------ 2 files changed, 17 insertions(+), 64 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 6f10317ebc42..f0bbbc96bc74 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -957,7 +957,6 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { lock.unlock(); if (!pCue || pCue->getPosition() == Cue::kNoPosition) { - hotcueSet(pControl, v, HotcueMode::Loop); return; } @@ -1007,7 +1006,7 @@ void CueControl::hotcueActivate( hotcueGoto(pControl, v); break; case mixxx::CueType::Loop: - hotcueGotoAndLoop(pControl, v); + hotcueLoopToggle(pControl, v); break; default: DEBUG_ASSERT(!"Invalid CueType!"); diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 6606e7c307c0..8bc5a81abcab 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -845,24 +845,6 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); } -TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopSetsNewLoop) { - // Setup fake track with 120 bpm and calculate loop size - TrackPointer pTrack = loadTestTrackWithBpm(120.0); - - m_pBeatloopSize->slotSet(4); - const double beatloopLengthSamples = m_pBeatloopSize->get() * getBeatLengthSamples(pTrack); - - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(currentSamplePosition(), m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(currentSamplePosition() + beatloopLengthSamples, m_pHotcue1EndPosition->get()); -} - TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopOrBeats) { createAndLoadFakeTrack(); @@ -1008,6 +990,7 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { // Seek to start of track setCurrentSamplePosition(beforeLoopPositionSamples); + double positionBeforeActivate = currentSamplePosition(); EXPECT_NEAR(beforeLoopPositionSamples, currentSamplePosition(), 2000); // Check that the previous seek disabled the loop @@ -1015,14 +998,14 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - // Activate saved loop (implies seeking to loop start) + // Activate saved loop (does not imply seeking to loop start) m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - EXPECT_NEAR(loopStartPositionSamples, currentSamplePosition(), 2000); + EXPECT_NEAR(positionBeforeActivate, currentSamplePosition(), 2000); // Seek to position after saved loop setCurrentSamplePosition(afterLoopPositionSamples); @@ -1033,17 +1016,19 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - // Activate saved loop (implies seeking to loop start) + positionBeforeActivate = currentSamplePosition(); + + // Activate saved loop (does not imply seeking to loop start) m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - EXPECT_NEAR(loopStartPositionSamples, currentSamplePosition(), 2000); + EXPECT_NEAR(positionBeforeActivate, currentSamplePosition(), 2000); } -TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingDoesNotDisableLoop) { +TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingTogglesLoop) { // Setup fake track with 120 bpm and calculate loop size TrackPointer pTrack = loadTestTrackWithBpm(120.0); @@ -1077,46 +1062,15 @@ TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingDoesNotDisableLoop) { EXPECT_DOUBLE_EQ(m_pHotcue1Position->get(), m_pLoopStartPosition->get()); EXPECT_DOUBLE_EQ(m_pHotcue1EndPosition->get(), m_pLoopEndPosition->get()); - const QList seekPositionsSamples = { - loopStartPosition + 0.1 * beatLengthSamples, - loopStartPosition + 0.25 * beatLengthSamples, - loopStartPosition + 0.5 * beatLengthSamples, - loopStartPosition + 0.75 * beatLengthSamples, - loopStartPosition + 0.9 * beatLengthSamples, - loopEndPosition - 0.1 * beatLengthSamples, - loopEndPosition - 0.25 * beatLengthSamples, - loopEndPosition - 0.5 * beatLengthSamples, - loopEndPosition - 0.75 * beatLengthSamples, - loopEndPosition - 0.9 * beatLengthSamples, - }; - - for (double seekPositionSamples : seekPositionsSamples) { - setCurrentSamplePosition(seekPositionSamples); - - ProcessBuffer(); - QCoreApplication::processEvents(); - - m_pHotcue1Activate->slotSet(1); - m_pHotcue1Activate->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), - m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopEndPosition, m_pHotcue1EndPosition->get()); - EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(m_pHotcue1Position->get(), m_pLoopStartPosition->get()); - EXPECT_DOUBLE_EQ(m_pHotcue1EndPosition->get(), m_pLoopEndPosition->get()); + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); - ProcessBuffer(); - QCoreApplication::processEvents(); - - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), - m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPosition, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopEndPosition, m_pHotcue1EndPosition->get()); - EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(m_pHotcue1Position->get(), m_pLoopStartPosition->get()); - EXPECT_DOUBLE_EQ(m_pHotcue1EndPosition->get(), m_pLoopEndPosition->get()); - } + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); } TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { From 299bd85412914f90681f592188da033b025850da Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Fri, 16 Oct 2020 10:51:01 +0200 Subject: [PATCH 113/153] engine/controls/loopingcontrol: Break long line --- src/engine/controls/loopingcontrol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index e8254b246f9e..9c98d4eb4552 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -1243,7 +1243,9 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable // If resizing an inactive loop by changing beatloop_size, // do not seek to the adjusted loop. - newloopSamples.seekMode = (keepStartPoint && (enable || m_bLoopingEnabled)) ? LoopSeekMode::Changed : LoopSeekMode::MovedOut; + newloopSamples.seekMode = (keepStartPoint && (enable || m_bLoopingEnabled)) + ? LoopSeekMode::Changed + : LoopSeekMode::MovedOut; m_loopSamples.setValue(newloopSamples); emit loopUpdated(newloopSamples.start, newloopSamples.end); From 03b79a6232d8e54ef1a72fcf334e6b6b7efae187 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sat, 17 Oct 2020 21:59:52 +0200 Subject: [PATCH 114/153] waveform/renderers/waveformrendermark: Use QRectF for saved loop drawing --- src/waveform/renderers/waveformrendermark.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 6203fedee2fd..c1190dc43aec 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -94,10 +94,10 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { gradient.setColorAt(0.75, QColor(Qt::transparent)); gradient.setColorAt(1, color); painter->fillRect( - QRect(QPoint(currentMarkPoint, 0), - QPoint(currentMarkEndPoint, - m_waveformRenderer - ->getHeight())), + QRectF(currentMarkPoint, + 0, + currentMarkEndPoint, + m_waveformRenderer->getHeight()), QBrush(gradient)); visible = true; } @@ -137,9 +137,10 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { gradient.setColorAt(0.75, QColor(Qt::transparent)); gradient.setColorAt(1, color); painter->fillRect( - QRect(QPoint(0, currentMarkPoint), - QPoint(m_waveformRenderer->getWidth(), - currentMarkEndPoint)), + QRectF(0, + currentMarkPoint, + m_waveformRenderer->getWidth(), + currentMarkEndPoint), QBrush(gradient)); visible = true; } From 3485786bcedba3d7baa87c0b73b660a132415aad Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 18 Oct 2020 14:11:31 +0200 Subject: [PATCH 115/153] widget/whotcuebutton: Fix false-positive compiler warning on Travis CI --- src/widget/whotcuebutton.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/widget/whotcuebutton.cpp b/src/widget/whotcuebutton.cpp index 960a2bac1d48..ba13c962cf68 100644 --- a/src/widget/whotcuebutton.cpp +++ b/src/widget/whotcuebutton.cpp @@ -142,7 +142,11 @@ void WHotcueButton::slotColorChanged(double color) { } void WHotcueButton::slotTypeChanged(double type) { - switch (static_cast(type)) { + // If the cast is put directly into the switch case, this seems to trigger + // a false positive warning on gcc 7.5.0 on Ubuntu 18.04.4 Bionic, so we cast + // it to int first and save to a local const variable. + const mixxx::CueType cueType = static_cast(static_cast(type)); + switch (cueType) { case mixxx::CueType::Invalid: m_type = QStringLiteral(""); break; From cf4f58607c7d9e183096b42670d077651901e10f Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Sun, 18 Oct 2020 18:44:20 +0200 Subject: [PATCH 116/153] CHANGELOG: Add entry for saved loops feature --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65567a02ef59..52cfcd5e01e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Cover art: Prevent wrong cover art display due to hash conflicts * Cover art: Add background color for quick cover art preview +* Add support for saving loops as hotcues #2194 lp:1367159 ## [2.3.0](https://launchpad.net/mixxx/+milestone/2.3.0) (Unreleased) ### Hotcues ### From 53b15a6250c2d3c39e6d0e4f47edc821ab7429a0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 12:03:55 +0200 Subject: [PATCH 117/153] CHANGELOG: Add missing markdown links to changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52cfcd5e01e8..ea55ea97a62e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * Cover art: Prevent wrong cover art display due to hash conflicts * Cover art: Add background color for quick cover art preview -* Add support for saving loops as hotcues #2194 lp:1367159 +* Add support for saving loops as hotcues [#2194](https://github.com/mixxxdj/mixxx/pull/2194) [lp:1367159](https://bugs.launchpad.net/mixxx/+bug/1367159) ## [2.3.0](https://launchpad.net/mixxx/+milestone/2.3.0) (Unreleased) ### Hotcues ### From 3dfddcc2093e89aafd8db15bae71fa455bdc51eb Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 12:13:31 +0200 Subject: [PATCH 118/153] HotcueControl: Fix const & redundant inline for getters --- src/engine/controls/cuecontrol.cpp | 2 +- src/engine/controls/cuecontrol.h | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index d486c288eafd..846935a9a6db 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2469,6 +2469,6 @@ void HotcueControl::setStatus(HotcueControl::Status status) { m_hotcueEnabled->forceSet(static_cast(status)); } -HotcueControl::Status HotcueControl::getStatus() { +HotcueControl::Status HotcueControl::getStatus() const { return static_cast(m_hotcueEnabled->get()); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 7d45e855fb89..86cababadbe3 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -70,31 +70,41 @@ class HotcueControl : public QObject { HotcueControl(QString group, int hotcueNumber); ~HotcueControl() override; - inline int getHotcueNumber() { return m_iHotcueNumber; } - inline CuePointer getCue() { return m_pCue; } - double getPosition() const; - double getEndPosition() const; + int getHotcueNumber() const { + return m_iHotcueNumber; + } + + CuePointer getCue() const { + return m_pCue; + } void setCue(CuePointer pCue); void resetCue(); + + double getPosition() const; void setPosition(double position); + + double getEndPosition() const; void setEndPosition(double endPosition); + void setType(mixxx::CueType type); + void setStatus(HotcueControl::Status status); - HotcueControl::Status getStatus(); + HotcueControl::Status getStatus() const; + void setColor(mixxx::RgbColor::optional_t newColor); mixxx::RgbColor::optional_t getColor() const; // Used for caching the preview state of this hotcue control. - inline mixxx::CueType getPreviewingType() { + mixxx::CueType getPreviewingType() const { return m_previewingType; } - inline void setPreviewingType(mixxx::CueType type) { + void setPreviewingType(mixxx::CueType type) { m_previewingType = type; } - inline double getPreviewingPosition() { + double getPreviewingPosition() const { return m_previewingPosition; } - inline void setPreviewingPosition(double position) { + void setPreviewingPosition(double position) { m_previewingPosition = position; } From 7edeb00ef51fde808f517f5e1631a6104318f3c1 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 12:33:07 +0200 Subject: [PATCH 119/153] Cue: Remove default argument for setLabel() --- src/engine/controls/cuecontrol.cpp | 2 +- src/track/cue.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 846935a9a6db..2b5ecee93c6d 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -778,7 +778,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { pCue->setStartPosition(cueStartPosition); pCue->setEndPosition(cueEndPosition); pCue->setHotCue(hotcue); - pCue->setLabel(""); + pCue->setLabel(QString()); pCue->setType(cueType); // TODO(XXX) deal with spurious signals attachCue(pCue, pControl); diff --git a/src/track/cue.h b/src/track/cue.h index 471104f2e680..dfdccc16db53 100644 --- a/src/track/cue.h +++ b/src/track/cue.h @@ -56,8 +56,7 @@ class Cue : public QObject { int hotCue = kNoHotCue); QString getLabel() const; - void setLabel( - QString label = QString()); + void setLabel(QString label); mixxx::RgbColor getColor() const; void setColor(mixxx::RgbColor color); From c38fc947d60b51e6dd7c8de10aed7ad4cc5ef03c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 12:33:35 +0200 Subject: [PATCH 120/153] LoopingControl: Remove unused member variable --- src/engine/controls/loopingcontrol.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index ec6fa695e3ca..d7bdaed1bd76 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -187,8 +187,6 @@ class LoopingControl : public EngineControl { ControlObject* m_pCOLoopMove; QList m_loopMoves; - CuePointer m_pCue; - // objects below are written from an engine worker thread TrackPointer m_pTrack; mixxx::BeatsPointer m_pBeats; From e0b97d2db32564ec70f921d44aa79103cf0b8e69 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 12:36:03 +0200 Subject: [PATCH 121/153] LoopingControl: Move variable declaration into switch case local scope --- src/engine/controls/loopingcontrol.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index f3977c1fb3dc..a84135c46b74 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -393,7 +393,6 @@ double LoopingControl::nextTrigger(bool reverse, if (loopSamples.start != m_oldLoopSamples.start || loopSamples.end != m_oldLoopSamples.end) { // bool seek is only valid after the loop has changed - bool movedOut; switch (loopSamples.seekMode) { case LoopSeekMode::Changed: // here the loop has changed and the play position @@ -403,8 +402,8 @@ double LoopingControl::nextTrigger(bool reverse, loopSamples.start, loopSamples.end); break; - case LoopSeekMode::MovedOut: - movedOut = false; + case LoopSeekMode::MovedOut: { + bool movedOut = false; // Check if we have moved out of the loop, before we could enable it if (reverse) { if (loopSamples.start > currentSample) { @@ -422,6 +421,7 @@ double LoopingControl::nextTrigger(bool reverse, loopSamples.end); } break; + } case LoopSeekMode::None: // Nothing to do here break; From d92157ab26d448e03dfd8f6c0e9701bffe48ee2a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 12:44:18 +0200 Subject: [PATCH 122/153] LoopingControl: Do not write loop_enable CO value again unnecessarily --- src/engine/controls/loopingcontrol.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index a84135c46b74..72fff87a47d1 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -795,8 +795,9 @@ void LoopingControl::slotLoopEnabledValueChangeRequest(double value) { if (value) { // Requested to set loop_enabled to 1 if (m_bLoopingEnabled) { - DEBUG_ASSERT(m_pCOLoopEnabled->get()); - m_pCOLoopEnabled->setAndConfirm(1.0); + VERIFY_OR_DEBUG_ASSERT(m_pCOLoopEnabled->get()) { + m_pCOLoopEnabled->setAndConfirm(1.0); + } } else { // Looping is currently disabled, try to enable the loop. In // contrast to the reloop_toggle CO, we do not jump in any case. @@ -820,8 +821,9 @@ void LoopingControl::slotLoopEnabledValueChangeRequest(double value) { // setAndConfirm is called by setLoopingEnabled setLoopingEnabled(false); } else { - DEBUG_ASSERT(!m_pCOLoopEnabled->get()); - m_pCOLoopEnabled->setAndConfirm(0.0); + VERIFY_OR_DEBUG_ASSERT(!m_pCOLoopEnabled->get()) { + m_pCOLoopEnabled->setAndConfirm(0.0); + } } } } From b8cc376016187433f135778976eefe74cdbd9cff Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 13:08:53 +0200 Subject: [PATCH 123/153] LoopingControl: Document realtime unsafety of findNBeatsFromSample As per @Be-ing's request: https://github.com/mixxxdj/mixxx/pull/2194/files#r454377439 --- src/engine/controls/loopingcontrol.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 72fff87a47d1..93e7199f5a49 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -537,6 +537,9 @@ void LoopingControl::setBeatLoop(double startPosition, bool enabled) { } double beatloopSize = m_pCOBeatLoopSize->get(); + + // TODO(XXX): This is not realtime safe. See this Zulip discussion for details: + // https://mixxx.zulipchat.com/#narrow/stream/109171-development/topic/getting.20locks.20out.20of.20Beats double endPosition = pBeats->findNBeatsFromSample(startPosition, beatloopSize); setLoop(startPosition, endPosition, enabled); From 46ff035d7658dc03886267313f96cfc9c6ab8d97 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 13:11:00 +0200 Subject: [PATCH 124/153] CueControl: Add comments regarding hotcue_X_loop_toggle behaviour --- src/engine/controls/cuecontrol.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 2b5ecee93c6d..3fcf4971e288 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -963,6 +963,9 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { switch (pCue->getType()) { case mixxx::CueType::Loop: { + // The hotcue_X_loop_toggle CO was invoked for a saved loop, set it as + // active the first time this happens and toggle the loop_enabled state + // on subsequent invocations. if (m_pCurrentSavedLoopControl != pControl) { setCurrentSavedLoopControl(pControl); } else { @@ -971,6 +974,9 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { } } break; case mixxx::CueType::HotCue: { + // The hotcue_X_loop_toggle CO was invoked for a hotcue. In that case, + // create a beatloop starting at the hotcue position. This is useful for + // mapping the CUE LOOP mode labeled on some controllers. setCurrentSavedLoopControl(nullptr); double startPosition = pCue->getPosition(); bool loopActive = m_pLoopEnabled->get() && (startPosition == m_pLoopStartPosition->get()); @@ -2275,6 +2281,8 @@ HotcueControl::HotcueControl(QString group, int i) &HotcueControl::slotHotcueGotoAndLoop, Qt::DirectConnection); + // Enable/disable the loop associated with this hotcue (either a saved loop + // or a beatloop from the hotcue position if this is a regular hotcue). m_hotcueLoopToggle = new ControlPushButton(keyForControl(i, "loop_toggle")); connect(m_hotcueLoopToggle, &ControlObject::valueChanged, From 47b2724edee8441b4c889aaf77e2e90fd46b99d5 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 13:11:44 +0200 Subject: [PATCH 125/153] HotcueControl: Add comment regarding change of hotcue_X_enabled CO --- src/engine/controls/cuecontrol.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 3fcf4971e288..3aea8ce6a429 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2473,6 +2473,9 @@ void HotcueControl::setType(mixxx::CueType type) { m_hotcueType->forceSet(static_cast(type)); } +// Starting with Mixxx 2.4, the `hotcue_X_enabled` CO is an enum instead of a +// boolean value. Refer to the definition of the HotcueControl::Status enum for +// details. void HotcueControl::setStatus(HotcueControl::Status status) { m_hotcueEnabled->forceSet(static_cast(status)); } From 7ee9e8c8a2d858f4d237c7baa7b4c9d0cfd0adb9 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 13:29:11 +0200 Subject: [PATCH 126/153] CueControl: Clean up hotcueGotoAndLoop a bit --- src/engine/controls/cuecontrol.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 3aea8ce6a429..a7c4592f7839 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -922,11 +922,11 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { } if (pCue->getType() == mixxx::CueType::Loop) { - hotcueGoto(pControl, v); + seekAbs(startPosition); setCurrentSavedLoopControl(pControl); } else if (pCue->getType() == mixxx::CueType::HotCue) { - hotcueGoto(pControl, v); - setBeatLoop(pCue->getPosition(), true); + seekAbs(startPosition); + setBeatLoop(startPosition, true); } else { return; } From 2167e16fc08eb28971c3fb1b53fe40dc33e14e41 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 13:30:19 +0200 Subject: [PATCH 127/153] CueControl: Set focused hotcue on loop-related hotcue COs --- src/engine/controls/cuecontrol.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index a7c4592f7839..059c87ecafb9 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -940,6 +940,8 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double v) { m_bypassCueSetByPlay = true; m_pPlay->set(1.0); } + + m_pHotcueFocus->set(pControl->getHotcueNumber()); } void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { @@ -984,8 +986,10 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { break; } default: - break; + return; } + + m_pHotcueFocus->set(pControl->getHotcueNumber()); } void CueControl::hotcueActivate( From c346f6ad3ce81b07e0605c549333ac5ae4c1bd80 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 14:20:39 +0200 Subject: [PATCH 128/153] WaveformRenderMark: Use QRectF(QPointF, QPointF) for drawing saved loops This fixes a regression from 03b79a6232d8e54ef1a72fcf334e6b6b7efae187. --- src/waveform/renderers/waveformrendermark.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index c1190dc43aec..83c14c41f0f0 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -94,10 +94,10 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { gradient.setColorAt(0.75, QColor(Qt::transparent)); gradient.setColorAt(1, color); painter->fillRect( - QRectF(currentMarkPoint, - 0, - currentMarkEndPoint, - m_waveformRenderer->getHeight()), + QRectF(QPointF(currentMarkPoint, 0), + QPointF(currentMarkEndPoint, + m_waveformRenderer + ->getHeight())), QBrush(gradient)); visible = true; } @@ -137,10 +137,9 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { gradient.setColorAt(0.75, QColor(Qt::transparent)); gradient.setColorAt(1, color); painter->fillRect( - QRectF(0, - currentMarkPoint, - m_waveformRenderer->getWidth(), - currentMarkEndPoint), + QRectF(QPointF(0, currentMarkPoint), + QPointF(m_waveformRenderer->getWidth(), + currentMarkEndPoint)), QBrush(gradient)); visible = true; } From 8d1010436254dc30b964d2ef0c7a2f862480f0a5 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 14:21:27 +0200 Subject: [PATCH 129/153] WaveformRenderMark: Make some local variables const in draw() method --- src/waveform/renderers/waveformrendermark.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/waveform/renderers/waveformrendermark.cpp b/src/waveform/renderers/waveformrendermark.cpp index 83c14c41f0f0..faa7c0b656ec 100644 --- a/src/waveform/renderers/waveformrendermark.cpp +++ b/src/waveform/renderers/waveformrendermark.cpp @@ -57,11 +57,11 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { generateMarkImage(pMark); } - double samplePosition = pMark->getSamplePosition(); + const double samplePosition = pMark->getSamplePosition(); if (samplePosition != Cue::kNoPosition) { - double currentMarkPoint = + const double currentMarkPoint = m_waveformRenderer->transformSamplePositionInRendererWorld(samplePosition); - double sampleEndPosition = pMark->getSampleEndPosition(); + const double sampleEndPosition = pMark->getSampleEndPosition(); if (m_waveformRenderer->getOrientation() == Qt::Horizontal) { // NOTE: vRince I guess image width is odd to display the center on the exact line ! // external image should respect that ... @@ -80,7 +80,7 @@ void WaveformRenderMark::draw(QPainter* painter, QPaintEvent* /*event*/) { // Check if the range needs to be displayed. if (sampleEndPosition != Cue::kNoPosition) { DEBUG_ASSERT(samplePosition < sampleEndPosition); - double currentMarkEndPoint = + const double currentMarkEndPoint = m_waveformRenderer->transformSamplePositionInRendererWorld( sampleEndPosition); if (visible || currentMarkEndPoint > 0) { From 8babfc8b1e1067b8cec928faaacb1513d7f4e441 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 21 Oct 2020 14:51:17 +0200 Subject: [PATCH 130/153] HotcueControl: Rename hotcue_X_enabled to hotcue_X_status and add alias --- src/engine/controls/cuecontrol.cpp | 19 ++++++++++--------- src/engine/controls/cuecontrol.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 059c87ecafb9..78ee2683cae7 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2226,8 +2226,12 @@ HotcueControl::HotcueControl(QString group, int i) Qt::DirectConnection); m_hotcueEndPosition->set(Cue::kNoPosition); - m_hotcueEnabled = new ControlObject(keyForControl(i, "enabled")); - m_hotcueEnabled->setReadOnly(); + m_pHotcueStatus = new ControlObject(keyForControl(i, "status")); + m_pHotcueStatus->setReadOnly(); + + // Add an alias for the legacy hotcue_X_enabled CO + ControlDoublePrivate::insertAlias(keyForControl(i, "enabled"), + keyForControl(i, "status")); m_hotcueType = new ControlObject(keyForControl(i, "type")); m_hotcueType->setReadOnly(); @@ -2327,7 +2331,7 @@ HotcueControl::HotcueControl(QString group, int i) HotcueControl::~HotcueControl() { delete m_hotcuePosition; delete m_hotcueEndPosition; - delete m_hotcueEnabled; + delete m_pHotcueStatus; delete m_hotcueType; delete m_hotcueColor; delete m_hotcueSet; @@ -2398,7 +2402,7 @@ void HotcueControl::slotHotcueClear(double v) { } void HotcueControl::slotHotcuePositionChanged(double newPosition) { - m_hotcueEnabled->forceSet(newPosition == Cue::kNoPosition ? 0.0 : 1.0); + m_pHotcueStatus->forceSet(newPosition == Cue::kNoPosition ? 0.0 : 1.0); emit hotcuePositionChanged(this, newPosition); } @@ -2477,13 +2481,10 @@ void HotcueControl::setType(mixxx::CueType type) { m_hotcueType->forceSet(static_cast(type)); } -// Starting with Mixxx 2.4, the `hotcue_X_enabled` CO is an enum instead of a -// boolean value. Refer to the definition of the HotcueControl::Status enum for -// details. void HotcueControl::setStatus(HotcueControl::Status status) { - m_hotcueEnabled->forceSet(static_cast(status)); + m_pHotcueStatus->forceSet(static_cast(status)); } HotcueControl::Status HotcueControl::getStatus() const { - return static_cast(m_hotcueEnabled->get()); + return static_cast(m_pHotcueStatus->get()); } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 86cababadbe3..d2811dbab730 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -152,7 +152,7 @@ class HotcueControl : public QObject { // Hotcue state controls ControlObject* m_hotcuePosition; ControlObject* m_hotcueEndPosition; - ControlObject* m_hotcueEnabled; + ControlObject* m_pHotcueStatus; ControlObject* m_hotcueType; ControlObject* m_hotcueColor; // Hotcue button controls From 096c0d90eb663719dcec19a0ed7c76f065ad4907 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 13:29:46 +0200 Subject: [PATCH 131/153] LoopingControl: Emit loopReset signal in loop position COs --- src/engine/controls/loopingcontrol.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 93e7199f5a49..6f9a3b4e0aa1 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -882,6 +882,7 @@ void LoopingControl::slotLoopStartPos(double pos) { clearActiveBeatLoop(); if (pos == kNoTrigger) { + emit loopReset(); setLoopingEnabled(false); } @@ -891,6 +892,7 @@ void LoopingControl::slotLoopStartPos(double pos) { if (loopSamples.end != kNoTrigger && loopSamples.end <= loopSamples.start) { + emit loopReset(); loopSamples.end = kNoTrigger; m_pCOLoopEndPosition->set(kNoTrigger); setLoopingEnabled(false); @@ -917,7 +919,8 @@ void LoopingControl::slotLoopEndPos(double pos) { clearActiveBeatLoop(); - if (pos == -1.0) { + if (pos == kNoTrigger) { + emit loopReset(); setLoopingEnabled(false); } loopSamples.end = pos; From 5419c9e9e7d3de3eb6110c70d067779d6120bfc0 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 13:29:56 +0200 Subject: [PATCH 132/153] HotcueControlTest: Add test for loading new track with active saved loop --- src/test/hotcuecontrol_test.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 8bc5a81abcab..1e0053862e4c 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1207,3 +1207,32 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { // Check that enabling the loop didn't cause a jump EXPECT_NEAR(afterLoopPositionSamples, currentSamplePosition(), 2000); } + +TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { + // Setup fake track with 120 bpm and calculate loop size + qWarning() << "Loading first track"; + loadTestTrackWithBpm(120.0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_NE(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_NE(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Setup fake track with 120 bpm and calculate loop size + qWarning() << "Loading second track"; + loadTestTrackWithBpm(130.0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); +} From 2270b645c1f15833fe97183b113b393c045d0840 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 14:16:48 +0200 Subject: [PATCH 133/153] LoopingControl: Improve comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Schürmann --- src/engine/controls/loopingcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 6f9a3b4e0aa1..77235c4defbc 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -803,7 +803,7 @@ void LoopingControl::slotLoopEnabledValueChangeRequest(double value) { } } else { // Looping is currently disabled, try to enable the loop. In - // contrast to the reloop_toggle CO, we do not jump in any case. + // contrast to the reloop_toggle CO, we jump in no case. LoopSamples loopSamples = m_loopSamples.getValue(); if (loopSamples.start != kNoTrigger && loopSamples.end != kNoTrigger && loopSamples.start <= loopSamples.end) { From 78185029db6ca93bab8c5b192dc6bb62c3d5efa2 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 14:24:20 +0200 Subject: [PATCH 134/153] HotcueControlTest: Add some missing ProcessBuffer calls --- src/test/hotcuecontrol_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 1e0053862e4c..34231de09a3b 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1220,10 +1220,12 @@ TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { // Set a beatloop m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); + ProcessBuffer(); // Save currently active loop to hotcue slot 1 m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); + ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_NE(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_NE(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1231,6 +1233,7 @@ TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { // Setup fake track with 120 bpm and calculate loop size qWarning() << "Loading second track"; loadTestTrackWithBpm(130.0); + ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); From 68c230426a442234cb8b7207b90649a2a75d14c5 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 14:24:52 +0200 Subject: [PATCH 135/153] CueControl: Inline hotcueControlStatusFromCue function --- src/engine/controls/cuecontrol.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 78ee2683cae7..c93f52deedbe 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -44,13 +44,6 @@ inline mixxx::RgbColor::optional_t doubleToRgbColor(double value) { return mixxx::RgbColor::optional(colorCode); } -inline HotcueControl::Status hotcueControlStatusFromCue(CuePointer pCue) { - if (pCue && pCue->getType() != mixxx::CueType::Invalid) { - return HotcueControl::Status::Valid; - } - return HotcueControl::Status::Invalid; -} - } // namespace CueControl::CueControl(QString group, @@ -2444,7 +2437,9 @@ void HotcueControl::setCue(CuePointer pCue) { setPosition(pCue->getPosition()); setEndPosition(pCue->getEndPosition()); setColor(pCue->getColor()); - setStatus(hotcueControlStatusFromCue(pCue)); + setStatus((pCue->getType() == mixxx::CueType::Invalid) + ? HotcueControl::Status::Invalid + : HotcueControl::Status::Valid); setType(pCue->getType()); // set pCue only if all other data is in place // because we have a null check for valid data else where in the code From b59c20332818896e344004bac1833103e85f8a67 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 14:34:25 +0200 Subject: [PATCH 136/153] CueControl: Fix outdated comment --- src/engine/controls/cuecontrol.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index c93f52deedbe..5a54d3ac7c4b 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -759,9 +759,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double v, HotcueMode mode) { return; } - // Abort if no position has been found. This can happen if a loop cue is - // requested while no loop is set and the track has no beatgrid, so we - // can't debug assert here. + // Abort if no position has been found. VERIFY_OR_DEBUG_ASSERT(cueStartPosition != Cue::kNoPosition && (cueType != mixxx::CueType::Loop || cueEndPosition != Cue::kNoPosition)) { From 785aa66105fd0d7d266d999b9614281675e761ef Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 14:36:36 +0200 Subject: [PATCH 137/153] CueControl: Remove useless lock --- src/engine/controls/cuecontrol.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 5a54d3ac7c4b..9b739078750b 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -940,16 +940,12 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double v) { return; } - QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { return; } CuePointer pCue = pControl->getCue(); - // Need to unlock before emitting any signals to prevent deadlock. - lock.unlock(); - if (!pCue || pCue->getPosition() == Cue::kNoPosition) { return; } From 68114905c893b3f8b4f3e978314ed217e88ba887 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 14:41:03 +0200 Subject: [PATCH 138/153] CueControl: Remove more useless locks --- src/engine/controls/cuecontrol.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 9b739078750b..12a8267cb44f 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2099,16 +2099,12 @@ void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { return; } - QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { return; } CuePointer pCue(pControl->getCue()); - // Need to unlock before emitting any signals to prevent deadlock. - lock.unlock(); - VERIFY_OR_DEBUG_ASSERT(pCue && pCue->getType() == mixxx::CueType::Loop && pCue->getEndPosition() != Cue::kNoPosition) { @@ -2152,7 +2148,6 @@ void CueControl::slotLoopUpdated(double startPosition, double endPosition) { return; } - QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { return; } @@ -2164,9 +2159,6 @@ void CueControl::slotLoopUpdated(double startPosition, double endPosition) { CuePointer pCue(m_pCurrentSavedLoopControl->getCue()); - // Need to unlock before emitting any signals to prevent deadlock. - lock.unlock(); - VERIFY_OR_DEBUG_ASSERT(pCue->getType() == mixxx::CueType::Loop) { setCurrentSavedLoopControl(nullptr); return; From 479459188a002390c1b9fb3efda782394d13ae4c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 14:43:08 +0200 Subject: [PATCH 139/153] HotcueControl: Improve comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Schürmann --- src/engine/controls/cuecontrol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index d2811dbab730..abf9f412fa9e 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -61,7 +61,7 @@ class HotcueControl : public QObject { Valid = 1, /// Hotcue is currently active (this only applies to Saved Loop cues /// while their loop is enabled). This status can be used by skins or - /// controller mappings to highlight a currently active saved loop, + /// controller mappings to highlight a the cue control that has saved the current loop, /// because resizing or moving the loop will make persistent changes to /// the cue. Active = 2, From 796dd7c856d359806d688427501e6f80125cb774 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 15:54:46 +0200 Subject: [PATCH 140/153] HotcueControlTest: Fix missing unloadTrack call --- src/test/hotcuecontrol_test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 34231de09a3b..646383f69340 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1209,7 +1209,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { } TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { - // Setup fake track with 120 bpm and calculate loop size + // Setup fake track with 120 bpm qWarning() << "Loading first track"; loadTestTrackWithBpm(120.0); @@ -1230,7 +1230,8 @@ TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { EXPECT_NE(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_NE(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - // Setup fake track with 120 bpm and calculate loop size + // Setup another fake track with 130 bpm + unloadTrack(); qWarning() << "Loading second track"; loadTestTrackWithBpm(130.0); ProcessBuffer(); From 8b0120b63a1774cc74427d29a52bb907af9ace08 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 17:05:27 +0200 Subject: [PATCH 141/153] LoopingControl: Fix DEBUG_ASSERTs when using Loop In/Out with saved loop --- src/engine/controls/loopingcontrol.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 77235c4defbc..b2edf0db6fe0 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -653,8 +653,15 @@ void LoopingControl::slotLoopIn(double pressed) { } else { setLoopInToCurrentPosition(); m_bAdjustingLoopIn = false; + LoopSamples loopSamples = m_loopSamples.getValue(); + if (loopSamples.start < loopSamples.end) { + emit loopUpdated(loopSamples.start, loopSamples.end); + } else { + emit loopReset(); + } } } else { + emit loopReset(); if (pressed > 0.0) { setLoopInToCurrentPosition(); } @@ -758,12 +765,19 @@ void LoopingControl::slotLoopOut(double pressed) { // loop out point when the button is released. if (!m_bLoopOutPressedWhileLoopDisabled) { setLoopOutToCurrentPosition(); + LoopSamples loopSamples = m_loopSamples.getValue(); + if (loopSamples.start < loopSamples.end) { + emit loopUpdated(loopSamples.start, loopSamples.end); + } else { + emit loopReset(); + } m_bAdjustingLoopOut = false; } else { m_bLoopOutPressedWhileLoopDisabled = false; } } } else { + emit loopReset(); if (pressed > 0.0) { setLoopOutToCurrentPosition(); m_bLoopOutPressedWhileLoopDisabled = true; @@ -953,6 +967,10 @@ void LoopingControl::notifySeek(double dNewPlaypos) { } void LoopingControl::setLoopingEnabled(bool enabled) { + if (m_bLoopingEnabled == enabled) { + return; + } + m_bLoopingEnabled = enabled; m_pCOLoopEnabled->setAndConfirm(enabled ? 1.0 : 0.0); BeatLoopingControl* pActiveBeatLoop = atomicLoadRelaxed(m_pActiveBeatLoop); From f985abcf60c9595a82a0dd48483b75834e5a8418 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 17:06:03 +0200 Subject: [PATCH 142/153] HotcueControlTest: Add new test for new loop_in/loop_out behaviour --- src/test/hotcuecontrol_test.cpp | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 646383f69340..536615b58852 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -1240,3 +1240,44 @@ TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } + +TEST_F(HotcueControlTest, SavedLoopUseLoopInOutWhileActive) { + std::unique_ptr pLoopIn = std::make_unique(m_sGroup1, "loop_in"); + std::unique_ptr pLoopOut = std::make_unique(m_sGroup1, "loop_out"); + + // Setup fake track with 120 bpm + loadTestTrackWithBpm(120.0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + // Set a beatloop + m_pBeatloopActivate->slotSet(1); + m_pBeatloopActivate->slotSet(0); + ProcessBuffer(); + + // Save currently active loop to hotcue slot 1 + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_NE(Cue::kNoPosition, m_pHotcue1Position->get()); + EXPECT_NE(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + setCurrentSamplePosition(0); + + pLoopIn->slotSet(1); + pLoopIn->slotSet(0); + ProcessBuffer(); + + setCurrentSamplePosition(1000); + + pLoopOut->slotSet(1); + pLoopOut->slotSet(0); + + ProcessBuffer(); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(1000, m_pHotcue1EndPosition->get()); +} From ad72d2281dbeb26e6c9a57d9cffc73925d91e6ff Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 17:21:38 +0200 Subject: [PATCH 143/153] HotcueControl: Add comment and TODO to header file --- src/engine/controls/cuecontrol.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index abf9f412fa9e..253051645618 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -50,6 +50,10 @@ inline SeekOnLoadMode seekOnLoadModeFromDouble(double value) { return static_cast(int(value)); } +/// A `HotcueControl` represents a hotcue slot. It can either be empty or have +/// a (hot-)cue attached to it. +/// +/// TODO(XXX): This class should be moved into a separate file. class HotcueControl : public QObject { Q_OBJECT public: From 17e6d4a641bde3cd91acedfebfaad0a8cb17ca9a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 17:22:07 +0200 Subject: [PATCH 144/153] LoopingControl: Improve comment regarding LoopSeekMode::None --- src/engine/controls/loopingcontrol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index b2edf0db6fe0..c66af2bc96bc 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -423,7 +423,9 @@ double LoopingControl::nextTrigger(bool reverse, break; } case LoopSeekMode::None: - // Nothing to do here + // Nothing to do here. This is used for enabling saved loops + // which we want to do without jumping to the loop start + // position. break; } m_oldLoopSamples = loopSamples; From 398e946d2d7289c1ec23f2b804423ce0f604bc21 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Thu, 22 Oct 2020 19:23:57 +0200 Subject: [PATCH 145/153] CueControl: Handle loops in hotcuePositionChanged slot --- src/engine/controls/cuecontrol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 12a8267cb44f..8f8f24de3ab9 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1120,7 +1120,9 @@ void CueControl::hotcuePositionChanged( if (newPosition == Cue::kNoPosition) { detachCue(pControl); } else if (newPosition > 0 && newPosition < m_pTrackSamples->get()) { - //TODO: Handle Loops + if (pCue->getType() == mixxx::CueType::Loop && newPosition >= pCue->getEndPosition()) { + return; + } pCue->setStartPosition(newPosition); } } From ee14f1722ef1b9fa86fff9b127e063c40e36424c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 00:49:44 +0100 Subject: [PATCH 146/153] CueControl: Rename HotcueMode to HotcueSetMode --- src/engine/controls/cuecontrol.cpp | 26 +++++++++++++------------- src/engine/controls/cuecontrol.h | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 87fd2c5a3983..b81182eb12c1 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -694,7 +694,7 @@ void CueControl::quantizeChanged(double v) { } } -void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueMode mode) { +void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueSetMode mode) { //qDebug() << "CueControl::hotcueSet" << value; if (value == 0) { @@ -720,18 +720,18 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueMode mod mixxx::CueType cueType = mixxx::CueType::Invalid; bool loopEnabled = m_pLoopEnabled->get(); - if (mode == HotcueMode::Auto) { - mode = loopEnabled ? HotcueMode::Loop : HotcueMode::Cue; + if (mode == HotcueSetMode::Auto) { + mode = loopEnabled ? HotcueSetMode::Loop : HotcueSetMode::Cue; } switch (mode) { - case HotcueMode::Cue: { + case HotcueSetMode::Cue: { // If no loop is enabled, just store regular jump cue cueStartPosition = getQuantizedCurrentPosition(); cueType = mixxx::CueType::HotCue; break; } - case HotcueMode::Loop: { + case HotcueSetMode::Loop: { if (loopEnabled) { // If a loop is enabled, save the current loop cueStartPosition = m_pLoopStartPosition->get(); @@ -751,7 +751,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueMode mod break; } default: - DEBUG_ASSERT(!"Invalid HotcueMode"); + DEBUG_ASSERT(!"Invalid HotcueSetMode"); return; } @@ -979,7 +979,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double value) { m_pHotcueFocus->set(pControl->getHotcueNumber()); } -void CueControl::hotcueActivate(HotcueControl* pControl, double value, HotcueMode mode) { +void CueControl::hotcueActivate(HotcueControl* pControl, double value, HotcueSetMode mode) { //qDebug() << "CueControl::hotcueActivate" << value; QMutexLocker lock(&m_mutex); @@ -2337,15 +2337,15 @@ HotcueControl::~HotcueControl() { } void HotcueControl::slotHotcueSet(double v) { - emit hotcueSet(this, v, HotcueMode::Auto); + emit hotcueSet(this, v, HotcueSetMode::Auto); } void HotcueControl::slotHotcueSetCue(double v) { - emit hotcueSet(this, v, HotcueMode::Cue); + emit hotcueSet(this, v, HotcueSetMode::Cue); } void HotcueControl::slotHotcueSetLoop(double v) { - emit hotcueSet(this, v, HotcueMode::Loop); + emit hotcueSet(this, v, HotcueSetMode::Loop); } void HotcueControl::slotHotcueGoto(double v) { @@ -2369,15 +2369,15 @@ void HotcueControl::slotHotcueLoopToggle(double v) { } void HotcueControl::slotHotcueActivate(double v) { - emit hotcueActivate(this, v, HotcueMode::Auto); + emit hotcueActivate(this, v, HotcueSetMode::Auto); } void HotcueControl::slotHotcueActivateCue(double v) { - emit hotcueActivate(this, v, HotcueMode::Cue); + emit hotcueActivate(this, v, HotcueSetMode::Cue); } void HotcueControl::slotHotcueActivateLoop(double v) { - emit hotcueActivate(this, v, HotcueMode::Loop); + emit hotcueActivate(this, v, HotcueSetMode::Loop); } void HotcueControl::slotHotcueActivatePreview(double v) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 253051645618..54d9945a728f 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -40,7 +40,7 @@ enum class SeekOnLoadMode { /// Used for requesting a specific hotcue type when activating/setting a /// hotcue. Auto will make CueControl determine the type automatically (i.e. /// create a loop cue if a loop is set, and a regular cue in all other cases). -enum class HotcueMode { +enum class HotcueSetMode { Auto = 0, Cue = 1, Loop = 2, @@ -132,13 +132,13 @@ class HotcueControl : public QObject { void slotHotcueColorChanged(double newColor); signals: - void hotcueSet(HotcueControl* pHotcue, double v, HotcueMode mode); + void hotcueSet(HotcueControl* pHotcue, double v, HotcueSetMode mode); void hotcueGoto(HotcueControl* pHotcue, double v); void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); void hotcueGotoAndLoop(HotcueControl* pHotcue, double v); void hotcueLoopToggle(HotcueControl* pHotcue, double v); - void hotcueActivate(HotcueControl* pHotcue, double v, HotcueMode mode); + void hotcueActivate(HotcueControl* pHotcue, double v, HotcueSetMode mode); void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); void hotcuePositionChanged(HotcueControl* pHotcue, double newPosition); @@ -207,13 +207,13 @@ class CueControl : public EngineControl { void cueUpdated(); void trackAnalyzed(); void trackCuesUpdated(); - void hotcueSet(HotcueControl* pControl, double v, HotcueMode mode); + void hotcueSet(HotcueControl* pControl, double v, HotcueSetMode mode); void hotcueGoto(HotcueControl* pControl, double v); void hotcueGotoAndPlay(HotcueControl* pControl, double v); void hotcueGotoAndStop(HotcueControl* pControl, double v); void hotcueGotoAndLoop(HotcueControl* pControl, double v); void hotcueLoopToggle(HotcueControl* pControl, double v); - void hotcueActivate(HotcueControl* pControl, double v, HotcueMode mode); + void hotcueActivate(HotcueControl* pControl, double v, HotcueSetMode mode); void hotcueActivatePreview(HotcueControl* pControl, double v); void hotcueClear(HotcueControl* pControl, double v); void hotcuePositionChanged(HotcueControl* pControl, double newPosition); From 101bbc6e2d1fd8083bf24b7a4b606d0b6c014eef Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 00:55:29 +0100 Subject: [PATCH 147/153] HotcueControl: Rename Status enum members --- src/engine/controls/cuecontrol.cpp | 18 ++-- src/engine/controls/cuecontrol.h | 4 +- src/test/hotcuecontrol_test.cpp | 134 ++++++++++++++--------------- 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index b81182eb12c1..6e6653e5c283 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -1051,7 +1051,7 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double value) { pControl->setPreviewingPosition(position); if (pCue->getType() == mixxx::CueType::Loop) { setCurrentSavedLoopControl(pControl); - } else if (pControl->getStatus() == HotcueControl::Status::Valid) { + } else if (pControl->getStatus() == HotcueControl::Status::Set) { pControl->setStatus(HotcueControl::Status::Active); } @@ -1079,7 +1079,7 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double value) { if (cueType == mixxx::CueType::Loop) { m_pLoopEnabled->set(0); } else if (pControl->getStatus() == HotcueControl::Status::Active) { - pControl->setStatus(HotcueControl::Status::Valid); + pControl->setStatus(HotcueControl::Status::Set); } seekExact(position); } @@ -2098,8 +2098,8 @@ void CueControl::hotcueFocusColorNext(double value) { void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { if (m_pCurrentSavedLoopControl && m_pCurrentSavedLoopControl != pControl) { // Disable previous saved loop - DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Invalid); - m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Valid); + DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Empty); + m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Set); m_pCurrentSavedLoopControl = nullptr; } @@ -2134,7 +2134,7 @@ void CueControl::slotLoopEnabledChanged(bool enabled) { return; } - DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Invalid); + DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Empty); DEBUG_ASSERT( m_pCurrentSavedLoopControl->getCue() && m_pCurrentSavedLoopControl->getCue()->getPosition() == @@ -2147,7 +2147,7 @@ void CueControl::slotLoopEnabledChanged(bool enabled) { if (enabled) { m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Active); } else { - m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Valid); + m_pCurrentSavedLoopControl->setStatus(HotcueControl::Status::Set); } } @@ -2432,8 +2432,8 @@ void HotcueControl::setCue(CuePointer pCue) { setEndPosition(pCue->getEndPosition()); setColor(pCue->getColor()); setStatus((pCue->getType() == mixxx::CueType::Invalid) - ? HotcueControl::Status::Invalid - : HotcueControl::Status::Valid); + ? HotcueControl::Status::Empty + : HotcueControl::Status::Set); setType(pCue->getType()); // set pCue only if all other data is in place // because we have a null check for valid data else where in the code @@ -2455,7 +2455,7 @@ void HotcueControl::resetCue() { setPosition(Cue::kNoPosition); setEndPosition(Cue::kNoPosition); setType(mixxx::CueType::Invalid); - setStatus(Status::Invalid); + setStatus(Status::Empty); } void HotcueControl::setPosition(double position) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index 54d9945a728f..aaee7f23dc80 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -60,9 +60,9 @@ class HotcueControl : public QObject { /// Describes the current status of the hotcue enum class Status { /// Hotuce not set - Invalid = 0, + Empty = 0, /// Hotcue is set and can be used - Valid = 1, + Set = 1, /// Hotcue is currently active (this only applies to Saved Loop cues /// while their loop is enabled). This status can be used by skins or /// controller mappings to highlight a the cue control that has saved the current loop, diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 536615b58852..224aa8cedd8d 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -113,13 +113,13 @@ class HotcueControlTest : public BaseSignalPathTest { TEST_F(HotcueControlTest, DefautltControlValues) { TrackPointer pTrack = createTestTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); loadTrack(pTrack); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -129,37 +129,37 @@ TEST_F(HotcueControlTest, NoTrackLoaded) { m_pHotcue1Set->slotSet(1); m_pHotcue1Set->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pHotcue1ActivateCue->slotSet(1); m_pHotcue1ActivateCue->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pHotcue1ActivateLoop->slotSet(1); m_pHotcue1ActivateLoop->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -167,7 +167,7 @@ TEST_F(HotcueControlTest, NoTrackLoaded) { TEST_F(HotcueControlTest, SetCueAuto) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -177,7 +177,7 @@ TEST_F(HotcueControlTest, SetCueAuto) { m_pHotcue1Set->slotSet(1); m_pHotcue1Set->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -185,7 +185,7 @@ TEST_F(HotcueControlTest, SetCueAuto) { TEST_F(HotcueControlTest, SetCueManual) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -194,7 +194,7 @@ TEST_F(HotcueControlTest, SetCueManual) { m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -202,7 +202,7 @@ TEST_F(HotcueControlTest, SetCueManual) { TEST_F(HotcueControlTest, SetLoopAuto) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -218,7 +218,7 @@ TEST_F(HotcueControlTest, SetLoopAuto) { TEST_F(HotcueControlTest, SetLoopManualWithLoop) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -242,7 +242,7 @@ TEST_F(HotcueControlTest, SetLoopManualWithoutLoop) { setCurrentSamplePosition(8 * beatLengthSamples); ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -256,13 +256,13 @@ TEST_F(HotcueControlTest, SetLoopManualWithoutLoop) { TEST_F(HotcueControlTest, SetLoopManualWithoutLoopOrBeats) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pHotcue1SetLoop->slotSet(1); m_pHotcue1SetLoop->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -271,7 +271,7 @@ TEST_F(HotcueControlTest, CueGoto) { // Setup fake track with 120 bpm and calculate loop size TrackPointer pTrack = loadTestTrackWithBpm(120.0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -284,7 +284,7 @@ TEST_F(HotcueControlTest, CueGoto) { m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -298,7 +298,7 @@ TEST_F(HotcueControlTest, CueGoto) { ProcessBuffer(); EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); @@ -308,7 +308,7 @@ TEST_F(HotcueControlTest, CueGotoAndPlay) { // Setup fake track with 120 bpm and calculate loop size TrackPointer pTrack = loadTestTrackWithBpm(120.0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -321,7 +321,7 @@ TEST_F(HotcueControlTest, CueGotoAndPlay) { m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -335,7 +335,7 @@ TEST_F(HotcueControlTest, CueGotoAndPlay) { ProcessBuffer(); EXPECT_LE(cuePositionSamples, currentSamplePosition()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); @@ -345,7 +345,7 @@ TEST_F(HotcueControlTest, CueGotoAndLoop) { // Setup fake track with 120 bpm and calculate loop size TrackPointer pTrack = loadTestTrackWithBpm(120.0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -361,7 +361,7 @@ TEST_F(HotcueControlTest, CueGotoAndLoop) { m_pHotcue1SetCue->slotSet(1); m_pHotcue1SetCue->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -375,7 +375,7 @@ TEST_F(HotcueControlTest, CueGotoAndLoop) { ProcessBuffer(); EXPECT_LE(cuePositionSamples, currentSamplePosition()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -393,7 +393,7 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; const double cuePositionSamples = 8 * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -417,7 +417,7 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { // Disable loop m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); // Seek to start of track setCurrentSamplePosition(0); @@ -429,7 +429,7 @@ TEST_F(HotcueControlTest, SavedLoopGoto) { ProcessBuffer(); EXPECT_DOUBLE_EQ(cuePositionSamples, currentSamplePosition()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); @@ -444,7 +444,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; const double cuePositionSamples = 8 * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -468,7 +468,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { // Disable loop m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); // Seek to start of track setCurrentSamplePosition(0); @@ -480,7 +480,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndPlay) { ProcessBuffer(); EXPECT_LE(cuePositionSamples, currentSamplePosition()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); @@ -495,7 +495,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; const double cuePositionSamples = 8 * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -519,7 +519,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { // Disable loop m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); // Seek to start of track setCurrentSamplePosition(0); @@ -542,7 +542,7 @@ TEST_F(HotcueControlTest, SavedLoopGotoAndLoop) { TEST_F(HotcueControlTest, SavedLoopStatus) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -559,7 +559,7 @@ TEST_F(HotcueControlTest, SavedLoopStatus) { m_pLoopEnabled->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); @@ -575,7 +575,7 @@ TEST_F(HotcueControlTest, SavedLoopStatus) { m_pHotcue1Clear->slotSet(0); EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -588,7 +588,7 @@ TEST_F(HotcueControlTest, SavedLoopScale) { const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -635,7 +635,7 @@ TEST_F(HotcueControlTest, SavedLoopMove) { const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = loopSize * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -684,7 +684,7 @@ TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -703,7 +703,7 @@ TEST_F(HotcueControlTest, SavedLoopNoScaleIfDisabled) { // Disable loop m_pLoopEnabled->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); // Double loop size (4 => 8 beats) while saved loop is disabled m_pLoopDouble->slotSet(1); @@ -735,7 +735,7 @@ TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = loopSize * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -754,7 +754,7 @@ TEST_F(HotcueControlTest, SavedLoopNoMoveIfDisabled) { // Disable Loop m_pLoopEnabled->slotSet(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); // Move loop right (0 => 4 beats) while saved loop is disabled m_pLoopMove->slotSet(loopSize); @@ -782,7 +782,7 @@ TEST_F(HotcueControlTest, SavedLoopReset) { const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -805,7 +805,7 @@ TEST_F(HotcueControlTest, SavedLoopReset) { ProcessBuffer(); // Check if setting the new beatloop disabled the current saved loop - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); } @@ -813,7 +813,7 @@ TEST_F(HotcueControlTest, SavedLoopReset) { TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -831,7 +831,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { m_pHotcue1LoopToggle->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(100, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); @@ -848,14 +848,14 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopOrBeats) { createAndLoadFakeTrack(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); m_pHotcue1LoopToggle->slotSet(1); m_pHotcue1LoopToggle->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -872,7 +872,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { const double loopStartPositionSamples = 8 * beatLengthSamples; const double afterLoopPositionSamples = 16 * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -897,7 +897,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); // Check that the previous seek disabled the loop - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -916,7 +916,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { m_pHotcue1LoopToggle->slotSet(1); m_pHotcue1LoopToggle->slotSet(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -928,7 +928,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { ProcessBuffer(); // Check that the previous seek disabled the loop - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -947,7 +947,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { m_pHotcue1LoopToggle->slotSet(1); m_pHotcue1LoopToggle->slotSet(0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -967,7 +967,7 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { const double loopStartPositionSamples = 8 * beatLengthSamples; const double afterLoopPositionSamples = 16 * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -994,7 +994,7 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { EXPECT_NEAR(beforeLoopPositionSamples, currentSamplePosition(), 2000); // Check that the previous seek disabled the loop - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1012,7 +1012,7 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { ProcessBuffer(); // Check that the previous seek disabled the loop - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1038,7 +1038,7 @@ TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingTogglesLoop) { const double loopStartPosition = 8 * beatLengthSamples; const double loopEndPosition = loopStartPosition + loopLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1064,7 +1064,7 @@ TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingTogglesLoop) { m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); m_pHotcue1Activate->slotSet(1); @@ -1082,7 +1082,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { const double beatLengthSamples = getBeatLengthSamples(pTrack); const double loopLengthSamples = m_pBeatloopSize->get() * beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1101,7 +1101,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestore) { // Disable loop m_pLoopEnabled->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1131,7 +1131,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { const double beforeLoopPositionSamples = 0; const double afterLoopPositionSamples = beatLengthSamples; - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1157,7 +1157,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { // Disable loop m_pLoopEnabled->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1184,7 +1184,7 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { // Disable loop m_pLoopEnabled->slotSet(0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Valid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1213,7 +1213,7 @@ TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { qWarning() << "Loading first track"; loadTestTrackWithBpm(120.0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); @@ -1236,7 +1236,7 @@ TEST_F(HotcueControlTest, SavedLoopUnloadTrackWhileActive) { loadTestTrackWithBpm(130.0); ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); } @@ -1248,7 +1248,7 @@ TEST_F(HotcueControlTest, SavedLoopUseLoopInOutWhileActive) { // Setup fake track with 120 bpm loadTestTrackWithBpm(120.0); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Invalid), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); From a25d3a5a0a83dba3fa7962057f99db56ac9c4525 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 00:59:08 +0100 Subject: [PATCH 148/153] CueControl: Rename setCurrentSavedLoopControl method --- src/engine/controls/cuecontrol.cpp | 16 ++++++++-------- src/engine/controls/cuecontrol.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 6e6653e5c283..deddc09ef4ea 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -795,7 +795,7 @@ void CueControl::hotcueSet(HotcueControl* pControl, double value, HotcueSetMode } if (cueType == mixxx::CueType::Loop) { - setCurrentSavedLoopControl(pControl); + setCurrentSavedLoopControlAndActivate(pControl); } // If quantize is enabled and we are not playing, jump to the cue point @@ -914,7 +914,7 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double value) { if (pCue->getType() == mixxx::CueType::Loop) { seekAbs(startPosition); - setCurrentSavedLoopControl(pControl); + setCurrentSavedLoopControlAndActivate(pControl); } else if (pCue->getType() == mixxx::CueType::HotCue) { seekAbs(startPosition); setBeatLoop(startPosition, true); @@ -956,7 +956,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double value) { // active the first time this happens and toggle the loop_enabled state // on subsequent invocations. if (m_pCurrentSavedLoopControl != pControl) { - setCurrentSavedLoopControl(pControl); + setCurrentSavedLoopControlAndActivate(pControl); } else { bool loopActive = pControl->getStatus() == HotcueControl::Status::Active; setLoop(pCue->getPosition(), pCue->getEndPosition(), !loopActive); @@ -966,7 +966,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double value) { // The hotcue_X_loop_toggle CO was invoked for a hotcue. In that case, // create a beatloop starting at the hotcue position. This is useful for // mapping the CUE LOOP mode labeled on some controllers. - setCurrentSavedLoopControl(nullptr); + setCurrentSavedLoopControlAndActivate(nullptr); double startPosition = pCue->getPosition(); bool loopActive = m_pLoopEnabled->get() && (startPosition == m_pLoopStartPosition->get()); setBeatLoop(startPosition, !loopActive); @@ -1050,7 +1050,7 @@ void CueControl::hotcueActivatePreview(HotcueControl* pControl, double value) { pControl->setPreviewingType(pCue->getType()); pControl->setPreviewingPosition(position); if (pCue->getType() == mixxx::CueType::Loop) { - setCurrentSavedLoopControl(pControl); + setCurrentSavedLoopControlAndActivate(pControl); } else if (pControl->getStatus() == HotcueControl::Status::Set) { pControl->setStatus(HotcueControl::Status::Active); } @@ -2095,7 +2095,7 @@ void CueControl::hotcueFocusColorNext(double value) { pCue->setColor(colorPalette.nextColor(*color)); } -void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { +void CueControl::setCurrentSavedLoopControlAndActivate(HotcueControl* pControl) { if (m_pCurrentSavedLoopControl && m_pCurrentSavedLoopControl != pControl) { // Disable previous saved loop DEBUG_ASSERT(m_pCurrentSavedLoopControl->getStatus() != HotcueControl::Status::Empty); @@ -2126,7 +2126,7 @@ void CueControl::setCurrentSavedLoopControl(HotcueControl* pControl) { } void CueControl::slotLoopReset() { - setCurrentSavedLoopControl(nullptr); + setCurrentSavedLoopControlAndActivate(nullptr); } void CueControl::slotLoopEnabledChanged(bool enabled) { @@ -2168,7 +2168,7 @@ void CueControl::slotLoopUpdated(double startPosition, double endPosition) { CuePointer pCue(m_pCurrentSavedLoopControl->getCue()); VERIFY_OR_DEBUG_ASSERT(pCue->getType() == mixxx::CueType::Loop) { - setCurrentSavedLoopControl(nullptr); + setCurrentSavedLoopControlAndActivate(nullptr); return; } diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index aaee7f23dc80..a40dacf23f48 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -259,7 +259,7 @@ class CueControl : public EngineControl { void createControls(); void attachCue(CuePointer pCue, HotcueControl* pControl); void detachCue(HotcueControl* pControl); - void setCurrentSavedLoopControl(HotcueControl* pControl); + void setCurrentSavedLoopControlAndActivate(HotcueControl* pControl); void loadCuesFromTrack(); double quantizeCuePoint(double position); double getQuantizedCurrentPosition(); From f99f42ff4706a2bee281b3e477cd0c17bcfb92ad Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 01:09:46 +0100 Subject: [PATCH 149/153] Deere: Remove obsolete connections (fixes duplicate signal bug) Fixes the issue described here: https://github.com/mixxxdj/mixxx/pull/2194#pullrequestreview-522907244 --- res/skins/Deere/hotcue_button.xml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/res/skins/Deere/hotcue_button.xml b/res/skins/Deere/hotcue_button.xml index 50f2bed4f7fa..2da3bac06396 100644 --- a/res/skins/Deere/hotcue_button.xml +++ b/res/skins/Deere/hotcue_button.xml @@ -29,28 +29,6 @@ 2 - - - - ,hotcue__activate - true - LeftButton - false - - - ,hotcue__clear - true - RightButton - false - - - ,hotcue__enabled - false - - - ,hotcue__color_id - highlight - From 13313b1f2d17d4be6b10cb07e9a9d476f144b76c Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 01:10:51 +0100 Subject: [PATCH 150/153] Tango: Remove obsolete connections (fixes duplicate signal bug) Fixes the issue described here: https://github.com/mixxxdj/mixxx/pull/2194#pullrequestreview-522907244 --- res/skins/Tango/button_hotcue_deck.xml | 16 ---------------- res/skins/Tango/button_hotcue_sam_pre.xml | 12 ------------ 2 files changed, 28 deletions(-) diff --git a/res/skins/Tango/button_hotcue_deck.xml b/res/skins/Tango/button_hotcue_deck.xml index cd46e1b56a44..9bef283bef14 100644 --- a/res/skins/Tango/button_hotcue_deck.xml +++ b/res/skins/Tango/button_hotcue_deck.xml @@ -32,21 +32,5 @@ Variables: center - - ,hotcue__activate - LeftButton - - - ,hotcue__clear - RightButton - - - ,hotcue__enabled - false - - - ,hotcue__color_id - highlight - diff --git a/res/skins/Tango/button_hotcue_sam_pre.xml b/res/skins/Tango/button_hotcue_sam_pre.xml index 1d503956920d..a5cd146d5055 100644 --- a/res/skins/Tango/button_hotcue_sam_pre.xml +++ b/res/skins/Tango/button_hotcue_sam_pre.xml @@ -33,17 +33,5 @@ Variables: center - - ,hotcue__activate - LeftButton - - - ,hotcue__clear - RightButton - - - ,hotcue__enabled - false - From 81ae1469f40b21050d49d99da249fcb040e06ed6 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 13:15:50 +0100 Subject: [PATCH 151/153] CueControl: Rename loop_toggle to cueloop and make it set new cuepoints --- src/engine/controls/cuecontrol.cpp | 36 ++++++---- src/engine/controls/cuecontrol.h | 8 +-- src/test/hotcuecontrol_test.cpp | 109 ++++++++++++++++++++--------- 3 files changed, 102 insertions(+), 51 deletions(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index deddc09ef4ea..227eac6771bd 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -327,9 +327,9 @@ void CueControl::createControls() { &CueControl::hotcueGotoAndLoop, Qt::DirectConnection); connect(pControl, - &HotcueControl::hotcueLoopToggle, + &HotcueControl::hotcueCueLoop, this, - &CueControl::hotcueLoopToggle, + &CueControl::hotcueCueLoop, Qt::DirectConnection); connect(pControl, &HotcueControl::hotcueActivate, @@ -935,7 +935,7 @@ void CueControl::hotcueGotoAndLoop(HotcueControl* pControl, double value) { m_pHotcueFocus->set(pControl->getHotcueNumber()); } -void CueControl::hotcueLoopToggle(HotcueControl* pControl, double value) { +void CueControl::hotcueCueLoop(HotcueControl* pControl, double value) { if (value == 0) { return; } @@ -947,12 +947,16 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double value) { CuePointer pCue = pControl->getCue(); if (!pCue || pCue->getPosition() == Cue::kNoPosition) { - return; + hotcueSet(pControl, value, HotcueSetMode::Cue); + pCue = pControl->getCue(); + VERIFY_OR_DEBUG_ASSERT(pCue && pCue->getPosition() != Cue::kNoPosition) { + return; + } } switch (pCue->getType()) { case mixxx::CueType::Loop: { - // The hotcue_X_loop_toggle CO was invoked for a saved loop, set it as + // The hotcue_X_cueloop CO was invoked for a saved loop, set it as // active the first time this happens and toggle the loop_enabled state // on subsequent invocations. if (m_pCurrentSavedLoopControl != pControl) { @@ -963,7 +967,7 @@ void CueControl::hotcueLoopToggle(HotcueControl* pControl, double value) { } } break; case mixxx::CueType::HotCue: { - // The hotcue_X_loop_toggle CO was invoked for a hotcue. In that case, + // The hotcue_X_cueloop CO was invoked for a hotcue. In that case, // create a beatloop starting at the hotcue position. This is useful for // mapping the CUE LOOP mode labeled on some controllers. setCurrentSavedLoopControlAndActivate(nullptr); @@ -1003,7 +1007,13 @@ void CueControl::hotcueActivate(HotcueControl* pControl, double value, HotcueSet hotcueGoto(pControl, value); break; case mixxx::CueType::Loop: - hotcueLoopToggle(pControl, value); + if (m_pCurrentSavedLoopControl != pControl) { + setCurrentSavedLoopControlAndActivate(pControl); + } else { + bool loopActive = pControl->getStatus() == + HotcueControl::Status::Active; + setLoop(pCue->getPosition(), pCue->getEndPosition(), !loopActive); + } break; default: DEBUG_ASSERT(!"Invalid CueType!"); @@ -2278,11 +2288,11 @@ HotcueControl::HotcueControl(QString group, int i) // Enable/disable the loop associated with this hotcue (either a saved loop // or a beatloop from the hotcue position if this is a regular hotcue). - m_hotcueLoopToggle = new ControlPushButton(keyForControl(i, "loop_toggle")); - connect(m_hotcueLoopToggle, + m_hotcueCueLoop = new ControlPushButton(keyForControl(i, "cueloop")); + connect(m_hotcueCueLoop, &ControlObject::valueChanged, this, - &HotcueControl::slotHotcueLoopToggle, + &HotcueControl::slotHotcueCueLoop, Qt::DirectConnection); m_hotcueActivate = new ControlPushButton(keyForControl(i, "activate")); @@ -2328,7 +2338,7 @@ HotcueControl::~HotcueControl() { delete m_hotcueGotoAndPlay; delete m_hotcueGotoAndStop; delete m_hotcueGotoAndLoop; - delete m_hotcueLoopToggle; + delete m_hotcueCueLoop; delete m_hotcueActivate; delete m_hotcueActivateCue; delete m_hotcueActivateLoop; @@ -2364,8 +2374,8 @@ void HotcueControl::slotHotcueGotoAndLoop(double v) { emit hotcueGotoAndLoop(this, v); } -void HotcueControl::slotHotcueLoopToggle(double v) { - emit hotcueLoopToggle(this, v); +void HotcueControl::slotHotcueCueLoop(double v) { + emit hotcueCueLoop(this, v); } void HotcueControl::slotHotcueActivate(double v) { diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index a40dacf23f48..3cede9511fdd 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -120,7 +120,7 @@ class HotcueControl : public QObject { void slotHotcueGotoAndPlay(double v); void slotHotcueGotoAndStop(double v); void slotHotcueGotoAndLoop(double v); - void slotHotcueLoopToggle(double v); + void slotHotcueCueLoop(double v); void slotHotcueActivate(double v); void slotHotcueActivateCue(double v); void slotHotcueActivateLoop(double v); @@ -137,7 +137,7 @@ class HotcueControl : public QObject { void hotcueGotoAndPlay(HotcueControl* pHotcue, double v); void hotcueGotoAndStop(HotcueControl* pHotcue, double v); void hotcueGotoAndLoop(HotcueControl* pHotcue, double v); - void hotcueLoopToggle(HotcueControl* pHotcue, double v); + void hotcueCueLoop(HotcueControl* pHotcue, double v); void hotcueActivate(HotcueControl* pHotcue, double v, HotcueSetMode mode); void hotcueActivatePreview(HotcueControl* pHotcue, double v); void hotcueClear(HotcueControl* pHotcue, double v); @@ -167,7 +167,7 @@ class HotcueControl : public QObject { ControlObject* m_hotcueGotoAndPlay; ControlObject* m_hotcueGotoAndStop; ControlObject* m_hotcueGotoAndLoop; - ControlObject* m_hotcueLoopToggle; + ControlObject* m_hotcueCueLoop; ControlObject* m_hotcueActivate; ControlObject* m_hotcueActivateCue; ControlObject* m_hotcueActivateLoop; @@ -212,7 +212,7 @@ class CueControl : public EngineControl { void hotcueGotoAndPlay(HotcueControl* pControl, double v); void hotcueGotoAndStop(HotcueControl* pControl, double v); void hotcueGotoAndLoop(HotcueControl* pControl, double v); - void hotcueLoopToggle(HotcueControl* pControl, double v); + void hotcueCueLoop(HotcueControl* pControl, double v); void hotcueActivate(HotcueControl* pControl, double v, HotcueSetMode mode); void hotcueActivatePreview(HotcueControl* pControl, double v); void hotcueClear(HotcueControl* pControl, double v); diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index 224aa8cedd8d..ea7e0a3286c9 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -31,7 +31,7 @@ class HotcueControlTest : public BaseSignalPathTest { m_pHotcue1Goto = std::make_unique(m_sGroup1, "hotcue_1_goto"); m_pHotcue1GotoAndPlay = std::make_unique(m_sGroup1, "hotcue_1_gotoandplay"); m_pHotcue1GotoAndLoop = std::make_unique(m_sGroup1, "hotcue_1_gotoandloop"); - m_pHotcue1LoopToggle = std::make_unique(m_sGroup1, "hotcue_1_loop_toggle"); + m_pHotcue1CueLoop = std::make_unique(m_sGroup1, "hotcue_1_cueloop"); m_pHotcue1Position = std::make_unique(m_sGroup1, "hotcue_1_position"); m_pHotcue1EndPosition = std::make_unique(m_sGroup1, "hotcue_1_endposition"); m_pHotcue1Enabled = std::make_unique(m_sGroup1, "hotcue_1_enabled"); @@ -102,7 +102,7 @@ class HotcueControlTest : public BaseSignalPathTest { std::unique_ptr m_pHotcue1Goto; std::unique_ptr m_pHotcue1GotoAndPlay; std::unique_ptr m_pHotcue1GotoAndLoop; - std::unique_ptr m_pHotcue1LoopToggle; + std::unique_ptr m_pHotcue1CueLoop; std::unique_ptr m_pHotcue1Position; std::unique_ptr m_pHotcue1EndPosition; std::unique_ptr m_pHotcue1Enabled; @@ -810,7 +810,7 @@ TEST_F(HotcueControlTest, SavedLoopReset) { EXPECT_DOUBLE_EQ(loopLengthSamples, m_pHotcue1EndPosition->get()); } -TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { +TEST_F(HotcueControlTest, SavedLoopCueLoopWithExistingLoop) { createAndLoadFakeTrack(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); @@ -827,8 +827,8 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); // Disable Loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1CueLoop->slotSet(1); + m_pHotcue1CueLoop->slotSet(0); EXPECT_DOUBLE_EQ(0.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); @@ -836,8 +836,8 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); // Re-Enable Loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1CueLoop->slotSet(1); + m_pHotcue1CueLoop->slotSet(0); EXPECT_DOUBLE_EQ(1.0, m_pLoopEnabled->get()); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); @@ -845,19 +845,66 @@ TEST_F(HotcueControlTest, SavedLoopToggleWithExistingLoop) { EXPECT_DOUBLE_EQ(200, m_pHotcue1EndPosition->get()); } -TEST_F(HotcueControlTest, SavedLoopToggleWithoutLoopOrBeats) { - createAndLoadFakeTrack(); +TEST_F(HotcueControlTest, CueLoopWithoutHotcueSetsHotcue) { + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1CueLoop->slotSet(1); + m_pHotcue1CueLoop->slotSet(0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + EXPECT_TRUE(m_pLoopEnabled->toBool()); +} + +TEST_F(HotcueControlTest, CueLoopWithSavedLoopToggles) { + // Setup fake track with 120 bpm and calculate loop size + TrackPointer pTrack = loadTestTrackWithBpm(120.0); + + m_pHotcue1SetLoop->slotSet(1); + m_pHotcue1SetLoop->slotSet(0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_NE(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + EXPECT_TRUE(m_pLoopEnabled->toBool()); + + m_pHotcue1CueLoop->slotSet(1); + m_pHotcue1CueLoop->slotSet(0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_NE(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + EXPECT_FALSE(m_pLoopEnabled->toBool()); + + m_pHotcue1CueLoop->slotSet(1); + m_pHotcue1CueLoop->slotSet(0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_NE(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + EXPECT_TRUE(m_pLoopEnabled->toBool()); +} + +TEST_F(HotcueControlTest, CueLoopWithoutLoopOrBeats) { + createAndLoadFakeTrack(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + + m_pHotcue1CueLoop->slotSet(1); + m_pHotcue1CueLoop->slotSet(0); + + EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); + EXPECT_DOUBLE_EQ(0, m_pHotcue1Position->get()); + EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1EndPosition->get()); + EXPECT_FALSE(m_pLoopEnabled->toBool()); } TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { @@ -880,6 +927,8 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { setCurrentSamplePosition(loopStartPositionSamples); ProcessBuffer(); + m_pPlay->slotSet(1); + // Set a beatloop m_pBeatloopActivate->slotSet(1); m_pBeatloopActivate->slotSet(0); @@ -893,8 +942,7 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { // Seek to start of track setCurrentSamplePosition(beforeLoopPositionSamples); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); + EXPECT_NEAR(beforeLoopPositionSamples, currentSamplePosition(), 2048); // Check that the previous seek disabled the loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); @@ -902,30 +950,26 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Re-Enable loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); + EXPECT_NEAR(beforeLoopPositionSamples, currentSamplePosition(), 2048); // Disable loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(beforeLoopPositionSamples, currentSamplePosition()); - // Seek to position after saved loop setCurrentSamplePosition(afterLoopPositionSamples); - ProcessBuffer(); // Check that the previous seek disabled the loop EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); @@ -933,26 +977,23 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Re-Enable loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(afterLoopPositionSamples, currentSamplePosition()); + EXPECT_NEAR(afterLoopPositionSamples, currentSamplePosition(), 2048); // Disable loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - - // Check that re-enabling loop didn't seek - EXPECT_DOUBLE_EQ(afterLoopPositionSamples, currentSamplePosition()); } TEST_F(HotcueControlTest, SavedLoopActivate) { @@ -1168,8 +1209,8 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { setCurrentSamplePosition(beforeLoopPositionSamples); // Re-enable saved loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); @@ -1195,8 +1236,8 @@ TEST_F(HotcueControlTest, SavedLoopBeatLoopSizeRestoreDoesNotJump) { setCurrentSamplePosition(afterLoopPositionSamples); // Re-enable saved loop - m_pHotcue1LoopToggle->slotSet(1); - m_pHotcue1LoopToggle->slotSet(0); + m_pHotcue1Activate->slotSet(1); + m_pHotcue1Activate->slotSet(0); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(cuePositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(cuePositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); From c7bfb05dd9c0c70af90369481c2e95329ef38145 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 13:20:06 +0100 Subject: [PATCH 152/153] CueControl: Fix cast from double to enum on MSVC Fixes this error on MSVC: ..\src\engine\controls\cuecontrol.cpp(2478): error C2440: 'static_cast': cannot convert from 'double' to 'HotcueControl::Status' ..\src\engine\controls\cuecontrol.cpp(2478): note: Conversions between enumeration and floating point values are no longer allowed --- src/engine/controls/cuecontrol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 227eac6771bd..c675385be300 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -2485,5 +2485,7 @@ void HotcueControl::setStatus(HotcueControl::Status status) { } HotcueControl::Status HotcueControl::getStatus() const { - return static_cast(m_pHotcueStatus->get()); + // Cast to int before casting to the int-based enum class because MSVC will + // throw a hissy fit otherwise. + return static_cast(static_cast(m_pHotcueStatus->get())); } From daf442e1013cab6173be7cdb2a1cface87e8457a Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Wed, 4 Nov 2020 18:52:05 +0100 Subject: [PATCH 153/153] LoopingControl: Seek to loop in setLoop() if playpos is behind loop end --- src/engine/controls/loopingcontrol.cpp | 12 ++++++++++ src/test/hotcuecontrol_test.cpp | 33 +++----------------------- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index ba3f9a62a6ff..4a206f9d7497 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -565,6 +565,18 @@ void LoopingControl::setLoop(double startPosition, double endPosition, bool enab m_pCOLoopEndPosition->set(loopSamples.end); } setLoopingEnabled(enabled); + + // Seek back to loop in position if we're already behind the loop end. + // + // TODO(Holzhaus): This needs to be reverted as soon as GUI controls for + // controlling saved loop behaviour are in place, because this change makes + // saved loops very risky to use and might potentially mess up your mix. + // See https://github.com/mixxxdj/mixxx/pull/2194#issuecomment-721847833 + // for details. + if (enabled && m_currentSample.getValue() > loopSamples.end) { + slotLoopInGoto(1); + } + m_pCOBeatLoopSize->setAndConfirm(findBeatloopSizeForLoop(startPosition, endPosition)); } diff --git a/src/test/hotcuecontrol_test.cpp b/src/test/hotcuecontrol_test.cpp index ea7e0a3286c9..001308ec68f3 100644 --- a/src/test/hotcuecontrol_test.cpp +++ b/src/test/hotcuecontrol_test.cpp @@ -917,7 +917,6 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { const double beforeLoopPositionSamples = 0; const double loopStartPositionSamples = 8 * beatLengthSamples; - const double afterLoopPositionSamples = 16 * beatLengthSamples; EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Empty), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(Cue::kNoPosition, m_pHotcue1Position->get()); @@ -967,33 +966,6 @@ TEST_F(HotcueControlTest, SavedLoopToggleDoesNotSeek) { EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - - // Seek to position after saved loop - setCurrentSamplePosition(afterLoopPositionSamples); - - // Check that the previous seek disabled the loop - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - - // Re-Enable loop - m_pHotcue1Activate->slotSet(1); - m_pHotcue1Activate->slotSet(0); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - - // Check that re-enabling loop didn't seek - EXPECT_NEAR(afterLoopPositionSamples, currentSamplePosition(), 2048); - - // Disable loop - m_pHotcue1Activate->slotSet(1); - m_pHotcue1Activate->slotSet(0); - ProcessBuffer(); - EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Set), m_pHotcue1Enabled->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); - EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); } TEST_F(HotcueControlTest, SavedLoopActivate) { @@ -1059,14 +1031,15 @@ TEST_F(HotcueControlTest, SavedLoopActivate) { positionBeforeActivate = currentSamplePosition(); - // Activate saved loop (does not imply seeking to loop start) + // Activate saved loop (usually doesn't imply seeking to loop start, but in this case it does + // because the play position is behind the loop end position) m_pHotcue1Activate->slotSet(1); m_pHotcue1Activate->slotSet(0); ProcessBuffer(); EXPECT_DOUBLE_EQ(static_cast(HotcueControl::Status::Active), m_pHotcue1Enabled->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples, m_pHotcue1Position->get()); EXPECT_DOUBLE_EQ(loopStartPositionSamples + loopLengthSamples, m_pHotcue1EndPosition->get()); - EXPECT_NEAR(positionBeforeActivate, currentSamplePosition(), 2000); + EXPECT_NEAR(loopStartPositionSamples, currentSamplePosition(), 2000); } TEST_F(HotcueControlTest, SavedLoopActivateWhilePlayingTogglesLoop) {