void testSetEndPosition_Seek_Reverse(bool unique, bool inclusive) { auto harnessHelper = newHarnessHelper(); auto opCtx = harnessHelper->newOperationContext(); auto sorted = harnessHelper->newSortedDataInterface(unique, { {key1, loc1}, {key2, loc1}, // No key3 {key4, loc1}, }); auto cursor = sorted->newCursor(opCtx.get(), false); cursor->setEndPosition(key2, inclusive); // Directly seeking past end is considered out of range. ASSERT_EQ(cursor->seek(key1, true), boost::none); ASSERT_EQ(cursor->seekExact(key1), boost::none); // Seeking to key2 directly or indirectly is only returned if endPosition is inclusive. auto maybeKey2 = inclusive ? boost::make_optional(IndexKeyEntry(key2, loc1)) : boost::none; // direct ASSERT_EQ(cursor->seek(key2, true), maybeKey2); ASSERT_EQ(cursor->seekExact(key2), maybeKey2); // indirect ASSERT_EQ(cursor->seek(key3, true), maybeKey2); cursor->saveUnpositioned(); removeFromIndex(opCtx, sorted, {{key2, loc1}}); cursor->restore(); ASSERT_EQ(cursor->seek(key3, true), boost::none); ASSERT_EQ(cursor->seek(key2, true), boost::none); }
void CueControl::trackLoaded(TrackPointer pTrack) { QMutexLocker lock(&m_mutex); if (m_pLoadedTrack) trackUnloaded(m_pLoadedTrack); if (!pTrack) { return; } m_pLoadedTrack = pTrack; connect(pTrack.data(), SIGNAL(cuesUpdated()), this, SLOT(trackCuesUpdated()), Qt::DirectConnection); Cue* loadCue = NULL; const QList<Cue*>& cuePoints = pTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() == Cue::LOAD) { loadCue = pCue; } else if (pCue->getType() != Cue::CUE) { continue; } int hotcue = pCue->getHotCue(); if (hotcue != -1) attachCue(pCue, hotcue); } double loadCuePoint = 0.0; // 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 (loadCue != NULL) { m_pCuePoint->set(loadCue->getPosition()); if (cueRecall) { loadCuePoint = loadCue->getPosition(); } } else { // If no cue point is stored, set one at track start m_pCuePoint->set(0.0); } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); // If cueRecall is on, seek to it even if we didn't find a cue value (we'll // seek to 0. if (cueRecall) { seekExact(loadCuePoint); } 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); } }
void DbContext::getWrSegWrtStoreData(const ReadableSegment* seg, llong subId, valvec<byte>* buf) { assert(seg->getWritableSegment() != NULL); assert(!seg->m_hasLockFreePointSearch); auto sctx = m_segCtx.data(); size_t segIdx = m_segCtx.size(); while (segIdx > 0) { auto seg2 = sctx[--segIdx]->seg; if (seg2 == seg) { auto wrtStoreIter = getWrtStoreIterNoLock(segIdx); buf->erase_all(); wrtStoreIter->reset(); if (!wrtStoreIter->seekExact(subId, buf)) { llong baseId = m_rowNumVec[segIdx]; throw ReadRecordException("wrtStoreIter->seekExact", seg->m_segDir.string().c_str(), baseId, subId); } wrtStoreIter->reset(); return; } } fprintf(stderr , "WARN: DbContext::getWrSegWrtStoreData: not found segment: %s\n" , seg->m_segDir.string().c_str()); // fallback to slow locked getValue: WritableSegment* wrseg = seg->getWritableSegment(); assert(wrseg != nullptr); wrseg->m_wrtStore->getValue(subId, buf, this); }
// Tests seekExact when it doesn't hit the query. void testSeekExact_Miss(bool unique, bool forward) { auto harnessHelper = newHarnessHelper(); auto opCtx = harnessHelper->newOperationContext(); auto sorted = harnessHelper->newSortedDataInterface(unique, { {key1, loc1}, // No key2. {key3, loc1}, }); auto cursor = sorted->newCursor(opCtx.get(), forward); ASSERT_EQ(cursor->seekExact(key2), boost::none); // Not testing iteration since the cursors position following a failed seekExact is // undefined. However, you must be able to seek somewhere else. ASSERT_EQ(cursor->seekExact(key1), IndexKeyEntry(key1, loc1)); }
void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) return; Cue* pCue = pControl->getCue(); if (v) { if (pCue && pCue->getPosition() != -1) { m_iCurrentlyPreviewingHotcues++; int iPosition = pCue->getPosition(); m_pPlayButton->set(1.0); m_bPreviewingHotcue = true; pControl->setPreviewing(true); pControl->setPreviewingPosition(iPosition); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(iPosition); } } else if (m_bPreviewingHotcue) { // This is a activate release and we are previewing at least one // hotcue. If this hotcue is previewing: if (pControl->isPreviewing()) { // Mark this hotcue as not previewing. int iPosition = pControl->getPreviewingPosition(); pControl->setPreviewing(false); pControl->setPreviewingPosition(-1); // If this is the last hotcue to leave preview. if (--m_iCurrentlyPreviewingHotcues == 0) { bool bHotcueCancel = m_bHotcueCancel; m_bPreviewingHotcue = false; m_bHotcueCancel = false; // If hotcue cancel is marked then do not snap back to the // hotcue and stop. Otherwise, seek back to the start point and // stop. if (bHotcueCancel) { // Re-trigger the play button value so controllers get the correct one // after. m_pPlayButton->set(m_pPlayButton->get()); } else { m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(iPosition); } } } } }
void CueControl::cueGotoAndStop(double v) { if (!v) return; QMutexLocker lock(&m_mutex); m_pPlayButton->set(0.0); double cuePoint = m_pCuePoint->get(); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(cuePoint); }
void CueControl::trackLoaded(TrackPointer pTrack) { QMutexLocker lock(&m_mutex); if (m_pLoadedTrack) trackUnloaded(m_pLoadedTrack); if (!pTrack) { return; } m_pLoadedTrack = pTrack; connect(pTrack.data(), SIGNAL(cuesUpdated()), this, SLOT(trackCuesUpdated()), Qt::DirectConnection); Cue* loadCue = NULL; const QList<Cue*>& cuePoints = pTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() == Cue::LOAD) { loadCue = pCue; } else if (pCue->getType() != Cue::CUE) { continue; } int hotcue = pCue->getHotCue(); if (hotcue != -1) attachCue(pCue, hotcue); } double loadCuePoint = 0.0; if (loadCue != NULL) { m_pCuePoint->set(loadCue->getPosition()); // 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. if (!getConfig()->getValueString( ConfigKey("[Controls]","CueRecall")).toInt()) { loadCuePoint = loadCue->getPosition(); } } else { // If no cue point is stored, set one at track start m_pCuePoint->set(0.0); } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(loadCuePoint); }
// Tests seekExact on reverse cursor when it hits something with dup keys. Doesn't make sense // for unique indexes. TEST(SortedDataInterface, SeekExact_HitWithDups_Reverse) { auto harnessHelper = newHarnessHelper(); auto opCtx = harnessHelper->newOperationContext(); auto sorted = harnessHelper->newSortedDataInterface(false, { {key1, loc1}, {key2, loc1}, {key2, loc2}, {key3, loc1}, }); auto cursor = sorted->newCursor(opCtx.get(), false); ASSERT_EQ(cursor->seekExact(key2), IndexKeyEntry(key2, loc2)); ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1)); ASSERT_EQ(cursor->next(), IndexKeyEntry(key1, loc1)); ASSERT_EQ(cursor->next(), boost::none); }
// Tests seekExact when it hits something. void testSeekExact_Hit(bool unique, bool forward) { auto harnessHelper = newHarnessHelper(); auto opCtx = harnessHelper->newOperationContext(); auto sorted = harnessHelper->newSortedDataInterface(unique, { {key1, loc1}, {key2, loc1}, {key3, loc1}, }); auto cursor = sorted->newCursor(opCtx.get(), forward); ASSERT_EQ(cursor->seekExact(key2), IndexKeyEntry(key2, loc1)); // Make sure iterating works. We may consider loosening this requirement if it is a hardship // for some storage engines. ASSERT_EQ(cursor->next(), IndexKeyEntry(forward ? key3 : key1, loc1)); ASSERT_EQ(cursor->next(), boost::none); }
void CueControl::hotcueGotoAndStop(HotcueControl* pControl, double v) { if (!v) return; QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) return; Cue* pCue = pControl->getCue(); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); if (pCue) { int position = pCue->getPosition(); if (position != -1) { m_pPlayButton->set(0.0); seekExact(position); } } }
void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { return; } CuePointer pCue(pControl->getCue()); if (v) { if (pCue && pCue->getPosition() != -1) { m_iCurrentlyPreviewingHotcues++; int iPosition = pCue->getPosition(); m_bypassCueSetByPlay = true; m_pPlayButton->set(1.0); pControl->setPreviewing(true); pControl->setPreviewingPosition(iPosition); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(iPosition); } } 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()) { // Mark this hotcue as not previewing. int iPosition = pControl->getPreviewingPosition(); pControl->setPreviewing(false); pControl->setPreviewingPosition(-1); // If this is the last hotcue to leave preview. if (--m_iCurrentlyPreviewingHotcues == 0 && !m_bPreviewing) { m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(iPosition); } } } }
void VinylControlControl::slotControlVinylSeek(double change) { if (isnan(change) || change > 1.14 || change < -0.14) { // This seek is ridiculous. return; } double total_samples = getTotalSamples(); double new_playpos = round(change*total_samples); // Do nothing if no track is loaded. if (!m_pCurrentTrack) { return; } if (m_pControlVinylEnabled->get() > 0.0 && m_pControlVinylMode->get() == MIXXX_VCMODE_RELATIVE) { int cuemode = (int)m_pControlVinylCueing->get(); //if in preroll, always seek if (new_playpos < 0) { seek(change); return; } switch (cuemode) { case MIXXX_RELATIVE_CUE_OFF: return; // If off, do nothing. case MIXXX_RELATIVE_CUE_ONECUE: //if onecue, just seek to the regular cue seekExact(m_pCurrentTrack->getCuePoint()); return; case MIXXX_RELATIVE_CUE_HOTCUE: // Continue processing in this function. break; default: qWarning() << "Invalid vinyl cue setting"; return; } double distance = 0; int nearest_playpos = -1; QList<Cue*> cuePoints = m_pCurrentTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() != Cue::CUE || pCue->getHotCue() == -1) { continue; } int cue_position = pCue->getPosition(); //pick cues closest to new_playpos if ((nearest_playpos == -1) || (fabs(new_playpos - cue_position) < distance)) { nearest_playpos = cue_position; distance = fabs(new_playpos - cue_position); } } if (nearest_playpos == -1) { if (new_playpos >= 0) { //never found an appropriate cue, so don't seek? return; } //if negative, allow a seek by falling down to the bottom } else { m_bSeekRequested = true; seekExact(nearest_playpos); m_bSeekRequested = false; return; } } // Just seek where it wanted to originally. m_bSeekRequested = true; seek(change); m_bSeekRequested = false; }
void CueControl::trackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack) { Q_UNUSED(pOldTrack); QMutexLocker lock(&m_mutex); if (m_pLoadedTrack) { disconnect(m_pLoadedTrack.data(), 0, this, 0); for (int i = 0; i < m_iNumHotCues; ++i) { detachCue(i); } // Store the cue point in a load cue. double cuePoint = m_pCuePoint->get(); if (cuePoint != -1 && cuePoint != 0.0) { CuePointer loadCue; const QList<CuePointer> cuePoints(m_pLoadedTrack->getCuePoints()); QListIterator<CuePointer> it(cuePoints); while (it.hasNext()) { CuePointer pCue(it.next()); if (pCue->getType() == Cue::LOAD) { loadCue = pCue; break; } } if (!loadCue) { loadCue = m_pLoadedTrack->addCue(); loadCue->setType(Cue::LOAD); loadCue->setLength(0); } loadCue->setPosition(cuePoint); } m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); m_pCuePoint->set(-1.0); m_pLoadedTrack.clear(); } if (pNewTrack.isNull()) { return; } m_pLoadedTrack = pNewTrack; connect(pNewTrack.data(), SIGNAL(cuesUpdated()), this, SLOT(trackCuesUpdated()), Qt::DirectConnection); CuePointer loadCue; const QList<CuePointer> cuePoints(pNewTrack->getCuePoints()); QListIterator<CuePointer> it(cuePoints); while (it.hasNext()) { CuePointer pCue(it.next()); if (pCue->getType() == Cue::LOAD) { loadCue = pCue; } else if (pCue->getType() != Cue::CUE) { continue; } int hotcue = pCue->getHotCue(); if (hotcue != -1) attachCue(pCue, hotcue); } double loadCuePoint = 0.0; // 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 (loadCue != NULL) { m_pCuePoint->set(loadCue->getPosition()); if (cueRecall) { loadCuePoint = loadCue->getPosition(); } } else { // If no cue point is stored, set one at track start m_pCuePoint->set(0.0); } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); // If cueRecall is on, seek to it even if we didn't find a cue value (we'll // seek to 0. if (cueRecall) { seekExact(loadCuePoint); } 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); } }
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(); }