TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeDisabled) { m_pQuantizeEnabled->set(0); TrackPointer pTrack = createTestTrack(); pTrack->setSampleRate(44100); pTrack->setBpm(120.0); pTrack->setCuePoint(CuePosition(240.0, Cue::AUTOMATIC)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::INTRO); pIntro->setSource(Cue::AUTOMATIC); pIntro->setPosition(210.0); pIntro->setLength(120.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::OUTRO); pOutro->setSource(Cue::AUTOMATIC); pOutro->setPosition(770.0); pOutro->setLength(220.0); loadTrack(pTrack); EXPECT_DOUBLE_EQ(240.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(210.0, m_pIntroStartPosition->get()); EXPECT_DOUBLE_EQ(330.0, m_pIntroEndPosition->get()); EXPECT_DOUBLE_EQ(770.0, m_pOutroStartPosition->get()); EXPECT_DOUBLE_EQ(990.0, m_pOutroEndPosition->get()); }
TEST_F(CueControlTest, LoadAutodetectedCues_QuantizeEnabled) { m_pQuantizeEnabled->set(1); TrackPointer pTrack = createTestTrack(); pTrack->setSampleRate(44100); pTrack->setBpm(120.0); const int frameSize = 2; const int sampleRate = pTrack->getSampleRate(); const double bpm = pTrack->getBpm(); const double beatLength = (60.0 * sampleRate / bpm) * frameSize; pTrack->setCuePoint(CuePosition(1.9 * beatLength, Cue::AUTOMATIC)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::INTRO); pIntro->setSource(Cue::AUTOMATIC); pIntro->setPosition(2.1 * beatLength); pIntro->setLength(1.2 * beatLength); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::OUTRO); pOutro->setSource(Cue::AUTOMATIC); pOutro->setPosition(11.1 * beatLength); pOutro->setLength(4.4 * beatLength); loadTrack(pTrack); EXPECT_DOUBLE_EQ(2.0 * beatLength, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(2.0 * beatLength, m_pIntroStartPosition->get()); EXPECT_DOUBLE_EQ(4.0 * beatLength, m_pIntroEndPosition->get()); EXPECT_DOUBLE_EQ(11.0 * beatLength, m_pOutroStartPosition->get()); EXPECT_DOUBLE_EQ(16.0 * beatLength, m_pOutroEndPosition->get()); }
TEST_F(CueControlTest, LoadTrackWithDetectedCues) { TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::AUTOMATIC)); auto pIntro = pTrack->createAndAddCue(); pIntro->setType(Cue::INTRO); pIntro->setSource(Cue::AUTOMATIC); pIntro->setPosition(100.0); pIntro->setLength(0.0); auto pOutro = pTrack->createAndAddCue(); pOutro->setType(Cue::OUTRO); pOutro->setSource(Cue::AUTOMATIC); pOutro->setPosition(-1.0); pOutro->setLength(200.0); loadTrack(pTrack); EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(100.0, m_pIntroStartPosition->get()); EXPECT_DOUBLE_EQ(-1.0, m_pIntroEndPosition->get()); EXPECT_DOUBLE_EQ(-1.0, m_pOutroStartPosition->get()); EXPECT_DOUBLE_EQ(200.0, m_pOutroEndPosition->get()); EXPECT_TRUE(m_pIntroStartEnabled->toBool()); EXPECT_FALSE(m_pIntroEndEnabled->toBool()); EXPECT_FALSE(m_pOutroStartEnabled->toBool()); EXPECT_TRUE(m_pOutroEndEnabled->toBool()); }
TEST_F(CueControlTest, SeekOnLoadMainCue) { m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_MAIN_CUE); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); loadTrack(pTrack); EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(100.0, getCurrentSample()); // Move cue and check if track is following it. pTrack->setCuePoint(CuePosition(200.0, Cue::MANUAL)); ProcessBuffer(); EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(200.0, getCurrentSample()); }
TEST_F(CueControlTest, SeekOnLoadZeroPos) { m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_ZERO_POS); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); loadTrack(pTrack); EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(0.0, getCurrentSample()); }
TEST_F(CueControlTest, SeekOnLoadDefault_CueRecallDisabled) { m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_DEFAULT); // Note: CueRecall uses inverse logic (0 means enabled). config()->set(ConfigKey("[Controls]", "CueRecall"), ConfigValue(1)); TrackPointer pTrack = createTestTrack(); pTrack->setCuePoint(CuePosition(100.0, Cue::MANUAL)); loadTrack(pTrack); EXPECT_DOUBLE_EQ(100.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(0.0, getCurrentSample()); }
// Moves the cue point to current position or to closest beat in case // quantize is enabled void CueControl::cueSet(double v) { if (!v) return; QMutexLocker lock(&m_mutex); double closestBeat = m_pClosestBeat->get(); double cue = (m_pQuantizeEnabled->get() > 0.0 && closestBeat != -1) ? closestBeat : getCurrentSample(); m_pCuePoint->set(cue); TrackPointer pLoadedTrack = m_pLoadedTrack; lock.unlock(); // Store cue point in loaded track if (pLoadedTrack) { pLoadedTrack->setCuePoint(cue); } }
TEST_F(CueControlTest, SeekOnLoadDefault_NoCue) { m_pSeekOnLoadMode->slotSet(SEEK_ON_LOAD_DEFAULT); TrackPointer pTrack = createTestTrack(); loadTrack(pTrack); EXPECT_DOUBLE_EQ(-1.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(0.0, getCurrentSample()); // Set cue and check if track is seeked to it. pTrack->setCuePoint(CuePosition(200.0, Cue::MANUAL)); ProcessBuffer(); EXPECT_DOUBLE_EQ(200.0, m_pCuePoint->get()); EXPECT_DOUBLE_EQ(200.0, getCurrentSample()); }
// Moves the cue point to current position or to closest beat in case // quantize is enabled void CueControl::cueSet(double v) { if (!v) return; QMutexLocker lock(&m_mutex); double cue = (m_pQuantizeEnabled->get() > 0.0 && m_pClosestBeat->get() != -1) ? floor(m_pClosestBeat->get()) : floor(getCurrentSample()); if (!even(static_cast<int>(cue))) { cue--; } m_pCuePoint->set(cue); TrackPointer pLoadedTrack = m_pLoadedTrack; lock.unlock(); // Store cue point in loaded track if (pLoadedTrack) { pLoadedTrack->setCuePoint(cue); } }
void CueControl::trackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack) { QMutexLocker lock(&m_mutex); DEBUG_ASSERT(m_pLoadedTrack == pOldTrack); if (m_pLoadedTrack) { disconnect(m_pLoadedTrack.get(), 0, this, 0); for (int i = 0; i < m_iNumHotCues; ++i) { detachCue(i); } m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); m_pCuePoint->set(-1.0); m_pLoadedTrack.reset(); } if (!pNewTrack) { return; } m_pLoadedTrack = pNewTrack; connect(m_pLoadedTrack.get(), SIGNAL(cuesUpdated()), this, SLOT(trackCuesUpdated()), Qt::DirectConnection); CuePointer pLoadCue; for (const CuePointer& pCue: m_pLoadedTrack->getCuePoints()) { if (pCue->getType() == Cue::CUE) { continue; // skip } if (pCue->getType() == Cue::LOAD) { DEBUG_ASSERT(!pLoadCue); pLoadCue = pCue; } int hotcue = pCue->getHotCue(); if (hotcue != -1) { attachCue(pCue, hotcue); } } double cuePoint; if (pLoadCue) { cuePoint = pLoadCue->getPosition(); } else { // If no load cue point is stored, read from track cuePoint = m_pLoadedTrack->getCuePoint(); } m_pCuePoint->set(cuePoint); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); // Use pNewTrack here, because m_pLoadedTrack might have been reset // immediately after leaving the locking scope! pNewTrack->setCuePoint(cuePoint); // If cue recall is ON in the prefs, then we're supposed to seek to the cue // point on song load. Note that [Controls],cueRecall == 0 corresponds to "ON", not OFF. bool cueRecall = (getConfig()->getValueString( ConfigKey("[Controls]","CueRecall"), "0").toInt() == 0); if (cueRecall && (cuePoint >= 0.0)) { seekExact(cuePoint); } else if (!(m_pVinylControlEnabled->get() && m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) { // If cuerecall is off, seek to zero unless // vinylcontrol is on and set to absolute. This allows users to // load tracks and have the needle-drop be maintained. seekExact(0.0); } trackCuesUpdated(); }