void CueControl::cueDenon(double v) { // This is how Denon DN-S 3700 cue buttons work: // If pressed go to cue and stop. // If pressed while stopped and at cue, play while pressed. // Cue Point is moved by play from pause QMutexLocker lock(&m_mutex); bool playing = (m_pPlayButton->get() == 1.0); if (v) { if (!playing && isTrackAtCue()) { // pause at cue point m_bPreviewing = true; m_pPlayButton->set(1.0); } else { // Just in case. m_bPreviewing = false; m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); } } else if (m_bPreviewing) { m_bPreviewing = false; m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); } }
void CueControl::cueCDJ(double v) { // This is how Pioneer cue buttons work: // If pressed while playing, stop playback and go to cue. // If pressed while stopped and at cue, play while pressed. // If pressed while stopped and not at cue, set new cue point. // If play is pressed while holding cue, the deck is now playing. (Handled in playFromCuePreview().) QMutexLocker lock(&m_mutex); bool playing = (m_pPlayButton->get() == 1.0); if (v) { if (playing || getCurrentSample() >= getTotalSamples()) { // Jump to cue when playing or when at end position // Just in case. m_bPreviewing = false; m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); } else if (isTrackAtCue()) { // pause at cue point m_bPreviewing = true; m_pPlayButton->set(1.0); } else { // Pause not at cue point and not at end position cueSet(v); // Just in case. m_bPreviewing = false; // If quantize is enabled, jump to the cue point since it's not // necessarily where we currently are if (m_pQuantizeEnabled->get() > 0.0) { lock.unlock(); // prevent deadlock. // Enginebuffer will quantize more exactly than we can. seekAbs(m_pCuePoint->get()); } } } else if (m_bPreviewing) { m_bPreviewing = false; m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); } // indicator may flash because the delayed adoption of seekAbs // Correct the Indicator set via play if (m_pLoadedTrack && !playing) { m_pCueIndicator->setBlinkValue(ControlIndicator::ON); } else { m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); } }
void CueControl::cueCDJ(double v) { /* This is how CDJ cue buttons work: * If pressed while playing, stop playback and go to cue. * If pressed while stopped and at cue, play while pressed. * If pressed while stopped and not at cue, set new cue point. * If play is pressed while holding cue, the deck is now playing. (Handled in playFromCuePreview().) */ QMutexLocker lock(&m_mutex); bool playing = (m_pPlayButton->get() == 1.0); double cuePoint = m_pCuePoint->get(); if (v) { if (playing) { m_pPlayButton->set(0.0); // Just in case. m_bPreviewing = false; // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(cuePoint); } else { if (fabs(getCurrentSample() - m_pCuePoint->get()) < 1.0f) { m_pPlayButton->set(1.0); m_bPreviewing = true; } else { cueSet(v); // Just in case. m_bPreviewing = false; // If quantize is enabled, jump to the cue point since it's not // necessarily where we currently are if (m_pQuantizeEnabled->get() > 0.0) { lock.unlock(); // prevent deadlock. seekAbs(m_pCuePoint->get()); } } } } else if (m_bPreviewing) { m_pPlayButton->set(0.0); m_bPreviewing = false; // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(cuePoint); } else { // Re-trigger the play button value so controllers get the correct one // after playFromCuePreview() changes it. m_pPlayButton->set(m_pPlayButton->get()); } }
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(); seekAbs(iPosition); } } } } }
void CueControl::hotcueSet(HotcueControl* pControl, double v) { //qDebug() << "CueControl::hotcueSet" << v; if (!v) return; QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) return; int hotcue = pControl->getHotcueNumber(); detachCue(hotcue); Cue* pCue = m_pLoadedTrack->addCue(); double cuePosition = (m_pQuantizeEnabled->get() > 0.0 && m_pClosestBeat->get() != -1) ? floorf(m_pClosestBeat->get()) : floorf(getCurrentSample()); if (!even(cuePosition)) cuePosition--; pCue->setPosition(cuePosition); pCue->setHotCue(hotcue); pCue->setLabel(""); pCue->setType(Cue::CUE); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); // 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_pPlayButton->get() > 0; if (!playing && m_pQuantizeEnabled->get() > 0.0) { lock.unlock(); // prevent deadlock. // Enginebuffer will quantize more exactly than we can. seekAbs(cuePosition); } }
void CueControl::hotcueGotoAndPlay(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) { int position = pCue->getPosition(); if (position != -1) { seekAbs(position); 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::cuePlay(double v) { // This is how CUP button works: // If freely playing (i.e. playing and platter NOT being touched), press to go to cue and stop. // 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(); // pressed if (v) { if (freely_playing) { m_bPreviewing = false; m_pPlay->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); } else if (!isTrackAtCue() && getCurrentSample() <= getTotalSamples()) { // Pause not at cue point and not at end position cueSet(v); // Just in case. m_bPreviewing = false; m_pPlay->set(0.0); // If quantize is enabled, jump to the cue point since it's not // necessarily where we currently are if (m_pQuantizeEnabled->get() > 0.0) { lock.unlock(); // prevent deadlock. // Enginebuffer will quantize more exactly than we can. seekAbs(m_pCuePoint->get()); } } } else if (isTrackAtCue()){ m_bPreviewing = false; m_pPlay->set(1.0); lock.unlock(); } }
void LoopingControl::slotBeatJump(double beats) { if (!m_pTrack || !m_pBeats) { return; } double dPosition = getCurrentSample(); double dBeatLength; if (BpmControl::getBeatContext(m_pBeats, dPosition, NULL, NULL, &dBeatLength, NULL)) { seekAbs(dPosition + beats * dBeatLength); } }
void CueControl::cueGoto(double v) { if (!v) return; QMutexLocker lock(&m_mutex); // Seek to cue point double cuePoint = m_pCuePoint->get(); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(cuePoint); }
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(); seekAbs(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); } if (loadCue != NULL) { m_pCuePoint->set(loadCue->getPosition()); } else { m_pCuePoint->set(0.0f); } int cueRecall = getConfig()->getValueString( ConfigKey("[Controls]","CueRecall")).toInt(); //If cue recall is ON in the prefs, then we're supposed to seek to the cue //point on song load. Note that cueRecall == 0 corresponds to "ON", not OFF. double loadCuePoint = 0; if (loadCue && cueRecall == 0) { loadCuePoint = loadCue->getPosition(); } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(loadCuePoint); }
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_bPreviewingHotcue = 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_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 was not marked then snap back to the // hotcue and stop. if (!bHotcueCancel) { m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(iPosition); } } } } }
void CueControl::cueSimple(double v) { if (!v) return; QMutexLocker lock(&m_mutex); // Simple cueing is if the player is not playing, set the cue point -- // otherwise seek to the cue point. if (m_pPlayButton->get() == 0.0f) { return cueSet(v); } double cuePoint = m_pCuePoint->get(); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(cuePoint); }
void CueControl::cuePreview(double v) { QMutexLocker lock(&m_mutex); if (v) { m_bPreviewing = true; m_pPlayButton->set(1.0); } else if (!v && m_bPreviewing) { m_bPreviewing = false; m_pPlayButton->set(0.0); } double cuePoint = m_pCuePoint->get(); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(cuePoint); }
void CueControl::hotcueGoto(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) { seekAbs(position); } } }
void LoopingControl::seekInsideAdjustedLoop(int old_loop_in, int old_loop_out, int new_loop_in, int new_loop_out) { if (m_iCurrentSample >= new_loop_in && m_iCurrentSample <= new_loop_out) { return; } int new_loop_size = new_loop_out - new_loop_in; if (!even(new_loop_size)) { --new_loop_size; } if (new_loop_size > old_loop_out - old_loop_in) { // Could this happen if the user grows a loop and then also shifts it? qWarning() << "seekInsideAdjustedLoop called for loop that got larger -- ignoring"; return; } int adjusted_position = m_iCurrentSample; while (adjusted_position > new_loop_out) { adjusted_position -= new_loop_size; if (adjusted_position < new_loop_in) { // I'm not even sure this is possible. The new loop would have to be bigger than the // old loop, and the playhead was somehow outside the old loop. qWarning() << "SHOULDN'T HAPPEN: seekInsideAdjustedLoop couldn't find a new position --" << " seeking to in point"; adjusted_position = new_loop_in; } } while (adjusted_position < new_loop_in) { adjusted_position += new_loop_size; if (adjusted_position > new_loop_out) { qWarning() << "SHOULDN'T HAPPEN: seekInsideAdjustedLoop couldn't find a new position --" << " seeking to in point"; adjusted_position = new_loop_in; } } if (adjusted_position != m_iCurrentSample) { m_iCurrentSample = adjusted_position; seekAbs(static_cast<double>(adjusted_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_pPlay->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_pPlay->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(iPosition); } } } }
void CueControl::hotcueSet(HotcueControl* pControl, double v) { //qDebug() << "CueControl::hotcueSet" << 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 : getCurrentSample(); pCue->setPosition(cuePosition); pCue->setHotCue(hotcue); pCue->setLabel(""); pCue->setType(Cue::CUE); // TODO(XXX) deal with spurious signals attachCue(pCue, hotcue); // 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->get() > 0.0) { lock.unlock(); // prevent deadlock. // Enginebuffer will quantize more exactly than we can. seekAbs(cuePosition); } }
void CueControl::hotcueGotoAndPlay(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) { int position = pCue->getPosition(); if (position != -1) { seekAbs(position); // don't move the cue point to the hot cue point in DENON mode m_bypassCueSetByPlay = true; m_pPlayButton->set(1.0); } } }
void CueControl::cuePreview(double v) { QMutexLocker lock(&m_mutex); if (v) { m_bPreviewing = true; m_bypassCueSetByPlay = true; m_pPlayButton->set(1.0); } else if (!v && m_bPreviewing) { m_bPreviewing = false; if (!m_iCurrentlyPreviewingHotcues) { m_pPlayButton->set(0.0); } else { return; } } else { return; } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); }
bool BpmControl::syncPhase(EngineBuffer* pOtherEngineBuffer) { if (!pOtherEngineBuffer) { return false; } TrackPointer otherTrack = pOtherEngineBuffer->getLoadedTrack(); BeatsPointer otherBeats = otherTrack ? otherTrack->getBeats() : BeatsPointer(); // If either track does not have beats, then we can't adjust the phase. if (!m_pBeats || !otherBeats) { return false; } // Get the file BPM of each song. //double dThisBpm = m_pBeats->getBpm(); //double dOtherBpm = ControlObject::getControl( //ConfigKey(pOtherEngineBuffer->getGroup(), "file_bpm"))->get(); // Get the current position of both decks double dThisPosition = getCurrentSample(); double dOtherLength = ControlObject::getControl( ConfigKey(pOtherEngineBuffer->getGroup(), "track_samples"))->get(); double dOtherEnginePlayPos = ControlObject::getControl( ConfigKey(pOtherEngineBuffer->getGroup(), "visual_playposition"))->get(); double dOtherPosition = dOtherLength * dOtherEnginePlayPos; double dThisPrevBeat = m_pBeats->findPrevBeat(dThisPosition); double dThisNextBeat = m_pBeats->findNextBeat(dThisPosition); if (dThisPrevBeat == -1 || dThisNextBeat == -1 || dOtherEnginePlayPos == -1 || dOtherLength == 0) { return false; } // Protect against the case where we are sitting exactly on the beat. if (dThisPrevBeat == dThisNextBeat) { dThisNextBeat = m_pBeats->findNthBeat(dThisPosition, 2); } double dOtherPrevBeat = otherBeats->findPrevBeat(dOtherPosition); double dOtherNextBeat = otherBeats->findNextBeat(dOtherPosition); if (dOtherPrevBeat == -1 || dOtherNextBeat == -1) { return false; } // Protect against the case where we are sitting exactly on the beat. if (dOtherPrevBeat == dOtherNextBeat) { dOtherNextBeat = otherBeats->findNthBeat(dOtherPosition, 2); } double dThisBeatLength = fabs(dThisNextBeat - dThisPrevBeat); double dOtherBeatLength = fabs(dOtherNextBeat - dOtherPrevBeat); double dOtherBeatFraction = (dOtherPosition - dOtherPrevBeat) / dOtherBeatLength; double dNewPlaypos; bool this_near_next = dThisNextBeat - dThisPosition <= dThisPosition - dThisPrevBeat; bool other_near_next = dOtherNextBeat - dOtherPosition <= dOtherPosition - dOtherPrevBeat; // We want our beat fraction to be identical to theirs. // If the two tracks have similar alignment, adjust phase is straight- // forward. Use the same fraction for both beats, starting from the previous // beat. But if This track is nearer to the next beat and the Other track // is nearer to the previous beat, use This Next beat as the starting point // for the phase. (ie, we pushed the sync button late). If This track // is nearer to the previous beat, but the Other track is nearer to the // next beat, we pushed the sync button early so use the double-previous // beat as the basis for the adjustment. // // This makes way more sense when you're actually mixing. // // TODO(XXX) Revisit this logic once we move away from tempo-locked, // infinite beatgrids because the assumption that findNthBeat(-2) always // works will be wrong then. if (this_near_next == other_near_next) { dNewPlaypos = dThisPrevBeat + dOtherBeatFraction * dThisBeatLength; } else if (this_near_next && !other_near_next) { dNewPlaypos = dThisNextBeat + dOtherBeatFraction * dThisBeatLength; } else { //!this_near_next && other_near_next dThisPrevBeat = m_pBeats->findNthBeat(dThisPosition, -2); dNewPlaypos = dThisPrevBeat + dOtherBeatFraction * dThisBeatLength; } // We might be seeking outside the loop. const bool loop_enabled = m_pLoopEnabled->get() > 0.0; const double loop_start_position = m_pLoopStartPosition->get(); const double loop_end_position = m_pLoopEndPosition->get(); // Cases for sanity: // // CASE 1 // Two identical 1-beat loops, out of phase by X samples. // Other deck is at its loop start. // This deck is half way through. We want to jump forward X samples to the loop end point. // // Two identical 1-beat loop, out of phase by X samples. // Other deck is // If sync target is 50% through the beat, // If we are at the loop end point and hit sync, jump forward X samples. // TODO(rryan): Revise this with something that keeps a broader number of // cases in sync. This at least prevents breaking out of the loop. if (loop_enabled) { const double loop_length = loop_end_position - loop_start_position; if (loop_length <= 0.0) { return false; } // TODO(rryan): If loop_length is not a multiple of dThisBeatLength should // we bail and not sync phase? // Syncing to after the loop end. double end_delta = dNewPlaypos - loop_end_position; if (end_delta > 0) { int i = end_delta / loop_length; dNewPlaypos = loop_start_position + end_delta - i * loop_length; } // Syncing to before the loop beginning. double start_delta = loop_start_position - dNewPlaypos; if (start_delta > 0) { int i = start_delta / loop_length; dNewPlaypos = loop_end_position - start_delta + i * loop_length; } } seekAbs(dNewPlaypos); return true; }
void VinylControlControl::slotControlVinylSeek(double change) { if(isnan(change) || change > 1.14 || change < -1.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; } else if (cuemode == MIXXX_RELATIVE_CUE_OFF) { return; //if off, do nothing } else if (cuemode == MIXXX_RELATIVE_CUE_ONECUE) { //if onecue, just seek to the regular cue seekAbs(m_pCurrentTrack->getCuePoint()); 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 { seekAbs(nearest_playpos); return; } } // just seek where it wanted to originally seek(change); }
void CueControl::cueCDJ(double v) { // This is how Pioneer cue buttons work: // If pressed while freely playing (i.e. playing and platter NOT being touched), stop playback and go to cue. // If pressed while NOT freely playing (i.e. stopped or playing but platter IS being touched), set new cue point. // If pressed while stopped and at cue, play while pressed. // 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(); if (v) { if (m_iCurrentlyPreviewingHotcues) { // we are already previewing by hotcues // just jump to cue point and continue previewing m_bPreviewing = true; lock.unlock(); seekAbs(m_pCuePoint->get()); } else if (freely_playing || atEndPosition()) { // Jump to cue when playing or when at end position // Just in case. m_bPreviewing = false; m_pPlay->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); } else if (isTrackAtCue()) { // pause at cue point m_bPreviewing = true; m_pPlay->set(1.0); } else { // Pause not at cue point and not at end position cueSet(v); // Just in case. m_bPreviewing = false; m_pPlay->set(0.0); // If quantize is enabled, jump to the cue point since it's not // necessarily where we currently are if (m_pQuantizeEnabled->get() > 0.0) { lock.unlock(); // prevent deadlock. // Enginebuffer will quantize more exactly than we can. seekAbs(m_pCuePoint->get()); } } } else if (m_bPreviewing) { m_bPreviewing = false; if (!m_iCurrentlyPreviewingHotcues) { m_pPlay->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(m_pCuePoint->get()); } } // indicator may flash because the delayed adoption of seekAbs // Correct the Indicator set via play if (m_pLoadedTrack && !freely_playing) { m_pCueIndicator->setBlinkValue(ControlIndicator::ON); } else { m_pCueIndicator->setBlinkValue(ControlIndicator::OFF); } }