![]() |
Mixxx
|
00001 // cuecontrol.cpp 00002 // Created 11/5/2009 by RJ Ryan (rryan@mit.edu) 00003 00004 #include <QMutexLocker> 00005 00006 #include "engine/cuecontrol.h" 00007 00008 #include "controlobject.h" 00009 #include "controlpushbutton.h" 00010 #include "trackinfoobject.h" 00011 #include "library/dao/cue.h" 00012 #include "cachingreader.h" 00013 #include "mathstuff.h" 00014 00015 #define NUM_HOT_CUES 37 00016 00017 CueControl::CueControl(const char * _group, 00018 ConfigObject<ConfigValue> * _config) : 00019 EngineControl(_group, _config), 00020 m_bPreviewing(false), 00021 m_bPreviewingHotcue(false), 00022 m_pPlayButton(ControlObject::getControl(ConfigKey(_group, "play"))), 00023 m_iCurrentlyPreviewingHotcues(0), 00024 m_iNumHotCues(NUM_HOT_CUES), 00025 m_pLoadedTrack(), 00026 m_mutex(QMutex::Recursive), 00027 m_bHotcueCancel(false) { 00028 createControls(); 00029 00030 m_pTrackSamples = ControlObject::getControl(ConfigKey(_group, "track_samples")); 00031 00032 m_pQuantizeEnabled = ControlObject::getControl(ConfigKey(_group, "quantize")); 00033 00034 m_pNextBeat = ControlObject::getControl(ConfigKey(_group, "beat_next")); 00035 m_pClosestBeat = ControlObject::getControl(ConfigKey(_group, "beat_closest")); 00036 00037 m_pCuePoint = new ControlObject(ConfigKey(_group, "cue_point")); 00038 m_pCueMode = new ControlObject(ConfigKey(_group,"cue_mode")); 00039 m_pCuePoint->set(-1); 00040 00041 m_pCueSet = new ControlPushButton(ConfigKey(_group, "cue_set")); 00042 connect(m_pCueSet, SIGNAL(valueChanged(double)), 00043 this, SLOT(cueSet(double)), 00044 Qt::DirectConnection); 00045 00046 m_pCueGoto = new ControlPushButton(ConfigKey(_group, "cue_goto")); 00047 connect(m_pCueGoto, SIGNAL(valueChanged(double)), 00048 this, SLOT(cueGoto(double)), 00049 Qt::DirectConnection); 00050 00051 m_pCueGotoAndStop = 00052 new ControlPushButton(ConfigKey(_group, "cue_gotoandstop")); 00053 connect(m_pCueGotoAndStop, SIGNAL(valueChanged(double)), 00054 this, SLOT(cueGotoAndStop(double)), 00055 Qt::DirectConnection); 00056 00057 m_pCueSimple = new ControlPushButton(ConfigKey(_group, "cue_simple")); 00058 connect(m_pCueSimple, SIGNAL(valueChanged(double)), 00059 this, SLOT(cueSimple(double)), 00060 Qt::DirectConnection); 00061 00062 m_pCuePreview = new ControlPushButton(ConfigKey(_group, "cue_preview")); 00063 connect(m_pCuePreview, SIGNAL(valueChanged(double)), 00064 this, SLOT(cuePreview(double)), 00065 Qt::DirectConnection); 00066 00067 m_pCueCDJ = new ControlPushButton(ConfigKey(_group, "cue_cdj")); 00068 connect(m_pCueCDJ, SIGNAL(valueChanged(double)), 00069 this, SLOT(cueCDJ(double)), 00070 Qt::DirectConnection); 00071 00072 m_pCueDefault = new ControlPushButton(ConfigKey(_group, "cue_default")); 00073 connect(m_pCueDefault, SIGNAL(valueChanged(double)), 00074 this, SLOT(cueDefault(double)), 00075 Qt::DirectConnection); 00076 00077 connect(m_pPlayButton, SIGNAL(valueChanged(double)), 00078 this, SLOT(cuePlay(double)), 00079 Qt::DirectConnection); 00080 } 00081 00082 CueControl::~CueControl() { 00083 delete m_pCuePoint; 00084 delete m_pCueMode; 00085 delete m_pCueSet; 00086 delete m_pCueGoto; 00087 delete m_pCueGotoAndStop; 00088 delete m_pCueSimple; 00089 delete m_pCuePreview; 00090 delete m_pCueCDJ; 00091 delete m_pCueDefault; 00092 while (m_hotcueControl.size() > 0) { 00093 HotcueControl* pControl = m_hotcueControl.takeLast(); 00094 delete pControl; 00095 } 00096 } 00097 00098 void CueControl::createControls() { 00099 for (int i = 0; i < m_iNumHotCues; ++i) { 00100 HotcueControl* pControl = new HotcueControl(getGroup(), i); 00101 00102 connect(pControl, SIGNAL(hotcuePositionChanged(HotcueControl*, double)), 00103 this, SLOT(hotcuePositionChanged(HotcueControl*, double)), 00104 Qt::DirectConnection); 00105 connect(pControl, SIGNAL(hotcueSet(HotcueControl*, double)), 00106 this, SLOT(hotcueSet(HotcueControl*, double)), 00107 Qt::DirectConnection); 00108 connect(pControl, SIGNAL(hotcueGoto(HotcueControl*, double)), 00109 this, SLOT(hotcueGoto(HotcueControl*, double)), 00110 Qt::DirectConnection); 00111 connect(pControl, SIGNAL(hotcueGotoAndStop(HotcueControl*, double)), 00112 this, SLOT(hotcueGotoAndStop(HotcueControl*, double)), 00113 Qt::DirectConnection); 00114 connect(pControl, SIGNAL(hotcueActivate(HotcueControl*, double)), 00115 this, SLOT(hotcueActivate(HotcueControl*, double)), 00116 Qt::DirectConnection); 00117 connect(pControl, SIGNAL(hotcueActivatePreview(HotcueControl*, double)), 00118 this, SLOT(hotcueActivatePreview(HotcueControl*, double)), 00119 Qt::DirectConnection); 00120 connect(pControl, SIGNAL(hotcueClear(HotcueControl*, double)), 00121 this, SLOT(hotcueClear(HotcueControl*, double)), 00122 Qt::DirectConnection); 00123 00124 m_hotcueControl.append(pControl); 00125 } 00126 } 00127 00128 void CueControl::attachCue(Cue* pCue, int hotCue) { 00129 Q_ASSERT(hotCue >= 0 && hotCue < m_iNumHotCues); 00130 HotcueControl* pControl = m_hotcueControl[hotCue]; 00131 if (pControl->getCue() != NULL) { 00132 detachCue(pControl->getHotcueNumber()); 00133 } 00134 pControl->setCue(pCue); 00135 connect(pCue, SIGNAL(updated()), 00136 this, SLOT(cueUpdated()), 00137 Qt::DirectConnection); 00138 00139 pControl->getPosition()->set(pCue->getPosition()); 00140 pControl->getEnabled()->set(pCue->getPosition() == -1 ? 0.0 : 1.0); 00141 } 00142 00143 void CueControl::detachCue(int hotCue) { 00144 Q_ASSERT(hotCue >= 0 && hotCue < m_iNumHotCues); 00145 HotcueControl* pControl = m_hotcueControl[hotCue]; 00146 Cue* pCue = pControl->getCue(); 00147 if (!pCue) 00148 return; 00149 disconnect(pCue, 0, this, 0); 00150 pControl->setCue(NULL); 00151 pControl->getPosition()->set(-1); 00152 pControl->getEnabled()->set(0); 00153 } 00154 00155 void CueControl::loadTrack(TrackPointer pTrack) { 00156 Q_ASSERT(pTrack); 00157 00158 QMutexLocker lock(&m_mutex); 00159 if (m_pLoadedTrack) 00160 unloadTrack(m_pLoadedTrack); 00161 00162 m_pLoadedTrack = pTrack; 00163 connect(pTrack.data(), SIGNAL(cuesUpdated()), 00164 this, SLOT(trackCuesUpdated()), 00165 Qt::DirectConnection); 00166 00167 Cue* loadCue = NULL; 00168 const QList<Cue*>& cuePoints = pTrack->getCuePoints(); 00169 QListIterator<Cue*> it(cuePoints); 00170 while (it.hasNext()) { 00171 Cue* pCue = it.next(); 00172 if (pCue->getType() == Cue::LOAD) { 00173 loadCue = pCue; 00174 } else if (pCue->getType() != Cue::CUE) { 00175 continue; 00176 } 00177 int hotcue = pCue->getHotCue(); 00178 if (hotcue != -1) 00179 attachCue(pCue, hotcue); 00180 } 00181 00182 if (loadCue != NULL) { 00183 m_pCuePoint->set(loadCue->getPosition()); 00184 } else { 00185 m_pCuePoint->set(0.0f); 00186 } 00187 00188 int cueRecall = getConfig()->getValueString( 00189 ConfigKey("[Controls]","CueRecall")).toInt(); 00190 //If cue recall is ON in the prefs, then we're supposed to seek to the cue 00191 //point on song load. Note that cueRecall == 0 corresponds to "ON", not OFF. 00192 if (loadCue && cueRecall == 0) { 00193 double loadCuePoint = loadCue->getPosition(); 00194 00195 // Need to unlock before emitting any signals to prevent deadlock. 00196 lock.unlock(); 00197 00198 emit(seekAbs(loadCuePoint)); 00199 } 00200 } 00201 00202 void CueControl::unloadTrack(TrackPointer pTrack) { 00203 QMutexLocker lock(&m_mutex); 00204 disconnect(pTrack.data(), 0, this, 0); 00205 for (int i = 0; i < m_iNumHotCues; ++i) { 00206 detachCue(i); 00207 } 00208 00209 // Store the cue point in a load cue. 00210 double cuePoint = m_pCuePoint->get(); 00211 00212 if (cuePoint != -1 && cuePoint != 0.0f) { 00213 Cue* loadCue = NULL; 00214 const QList<Cue*>& cuePoints = pTrack->getCuePoints(); 00215 QListIterator<Cue*> it(cuePoints); 00216 while (it.hasNext()) { 00217 Cue* pCue = it.next(); 00218 if (pCue->getType() == Cue::LOAD) { 00219 loadCue = pCue; 00220 break; 00221 } 00222 } 00223 if (!loadCue) { 00224 loadCue = pTrack->addCue(); 00225 loadCue->setType(Cue::LOAD); 00226 loadCue->setLength(0); 00227 } 00228 loadCue->setPosition(cuePoint); 00229 } 00230 00231 m_pLoadedTrack.clear(); 00232 } 00233 00234 void CueControl::cueUpdated() { 00235 //QMutexLocker lock(&m_mutex); 00236 // We should get a trackCuesUpdated call anyway, so do nothing. 00237 } 00238 00239 void CueControl::trackCuesUpdated() { 00240 QMutexLocker lock(&m_mutex); 00241 QSet<int> active_hotcues; 00242 00243 if (!m_pLoadedTrack) 00244 return; 00245 00246 const QList<Cue*>& cuePoints = m_pLoadedTrack->getCuePoints(); 00247 QListIterator<Cue*> it(cuePoints); 00248 while (it.hasNext()) { 00249 Cue* pCue = it.next(); 00250 00251 if (pCue->getType() != Cue::CUE && pCue->getType() != Cue::LOAD) 00252 continue; 00253 00254 int hotcue = pCue->getHotCue(); 00255 if (hotcue != -1) { 00256 HotcueControl* pControl = m_hotcueControl[hotcue]; 00257 Cue* pOldCue = pControl->getCue(); 00258 00259 // If the old hotcue is different than this one. 00260 if (pOldCue != pCue) { 00261 // If the old hotcue exists, detach it 00262 if (pOldCue != NULL) 00263 detachCue(hotcue); 00264 attachCue(pCue, hotcue); 00265 } else { 00266 // If the old hotcue is the same, then we only need to update 00267 double dOldPosition = pControl->getPosition()->get(); 00268 double dOldEnabled = pControl->getEnabled()->get(); 00269 double dPosition = pCue->getPosition(); 00270 double dEnabled = dPosition == -1 ? 0.0 : 1.0; 00271 if (dEnabled != dOldEnabled) { 00272 pControl->getEnabled()->set(dEnabled); 00273 } 00274 if (dPosition != dOldPosition) { 00275 pControl->getPosition()->set(dPosition); 00276 } 00277 } 00278 // Add the hotcue to the list of active hotcues 00279 active_hotcues.insert(hotcue); 00280 } 00281 } 00282 00283 // Detach all hotcues that are no longer present 00284 for (int i = 0; i < m_iNumHotCues; ++i) { 00285 if (!active_hotcues.contains(i)) 00286 detachCue(i); 00287 } 00288 } 00289 00290 void CueControl::hotcueSet(HotcueControl* pControl, double v) { 00291 //qDebug() << "CueControl::hotcueSet" << v; 00292 00293 if (!v) 00294 return; 00295 00296 QMutexLocker lock(&m_mutex); 00297 if (!m_pLoadedTrack) 00298 return; 00299 00300 int hotcue = pControl->getHotcueNumber(); 00301 detachCue(hotcue); 00302 Cue* pCue = m_pLoadedTrack->addCue(); 00303 double cuePosition = 00304 (m_pQuantizeEnabled->get() > 0.0 && m_pClosestBeat->get() != -1) ? 00305 floorf(m_pClosestBeat->get()) : floorf(getCurrentSample()); 00306 if (!even(cuePosition)) 00307 cuePosition--; 00308 pCue->setPosition(cuePosition); 00309 pCue->setHotCue(hotcue); 00310 pCue->setLabel(""); 00311 pCue->setType(Cue::CUE); 00312 // TODO(XXX) deal with spurious signals 00313 attachCue(pCue, hotcue); 00314 00315 // If quantize is enabled and we are not playing, jump to the cue point 00316 // since it's not necessarily where we currently are. TODO(XXX) is this 00317 // potentially invalid for vinyl control? 00318 bool playing = m_pPlayButton->get() > 0; 00319 if (!playing && m_pQuantizeEnabled->get() > 0.0) { 00320 lock.unlock(); // prevent deadlock. 00321 emit(seekAbs(cuePosition)); 00322 } 00323 } 00324 00325 void CueControl::hotcueGoto(HotcueControl* pControl, double v) { 00326 if (!v) 00327 return; 00328 00329 QMutexLocker lock(&m_mutex); 00330 if (!m_pLoadedTrack) 00331 return; 00332 00333 Cue* pCue = pControl->getCue(); 00334 00335 // Need to unlock before emitting any signals to prevent deadlock. 00336 lock.unlock(); 00337 00338 if (pCue) { 00339 int position = pCue->getPosition(); 00340 if (position != -1) { 00341 emit(seekAbs(position)); 00342 } 00343 } 00344 } 00345 00346 void CueControl::hotcueGotoAndStop(HotcueControl* pControl, double v) { 00347 if (!v) 00348 return; 00349 00350 QMutexLocker lock(&m_mutex); 00351 if (!m_pLoadedTrack) 00352 return; 00353 00354 Cue* pCue = pControl->getCue(); 00355 00356 // Need to unlock before emitting any signals to prevent deadlock. 00357 lock.unlock(); 00358 00359 if (pCue) { 00360 int position = pCue->getPosition(); 00361 if (position != -1) { 00362 m_pPlayButton->set(0.0); 00363 emit(seekAbs(position)); 00364 } 00365 } 00366 } 00367 00368 void CueControl::hotcueActivate(HotcueControl* pControl, double v) { 00369 //qDebug() << "CueControl::hotcueActivate" << v; 00370 00371 QMutexLocker lock(&m_mutex); 00372 00373 if (!m_pLoadedTrack) 00374 return; 00375 00376 Cue* pCue = pControl->getCue(); 00377 00378 lock.unlock(); 00379 00380 if (pCue) { 00381 if (v) { 00382 m_bHotcueCancel = false; 00383 if (pCue->getPosition() == -1) { 00384 hotcueSet(pControl, v); 00385 } else { 00386 if (!m_bPreviewingHotcue && m_pPlayButton->get() == 1.0f) { 00387 hotcueGoto(pControl, v); 00388 } else { 00389 hotcueActivatePreview(pControl, v); 00390 } 00391 } 00392 } else { 00393 if (pCue->getPosition() != -1) { 00394 hotcueActivatePreview(pControl, v); 00395 } 00396 } 00397 } else { 00398 if (v) { 00399 // just in case 00400 m_bHotcueCancel = false; 00401 hotcueSet(pControl, v); 00402 } else if (m_bPreviewingHotcue) { 00403 // The cue is non-existent, yet we got a release for it and are 00404 // currently previewing a hotcue. This is indicative of a corner 00405 // case where the cue was detached while we were pressing it. Let 00406 // hotcueActivatePreview handle it. 00407 hotcueActivatePreview(pControl, v); 00408 } 00409 } 00410 } 00411 00412 void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { 00413 QMutexLocker lock(&m_mutex); 00414 if (!m_pLoadedTrack) 00415 return; 00416 Cue* pCue = pControl->getCue(); 00417 00418 if (v) { 00419 if (pCue && pCue->getPosition() != -1) { 00420 m_iCurrentlyPreviewingHotcues++; 00421 int iPosition = pCue->getPosition(); 00422 m_pPlayButton->set(1.0); 00423 m_bPreviewingHotcue = true; 00424 pControl->setPreviewing(true); 00425 pControl->setPreviewingPosition(iPosition); 00426 00427 // Need to unlock before emitting any signals to prevent deadlock. 00428 lock.unlock(); 00429 00430 emit(seekAbs(iPosition)); 00431 } 00432 } else if (m_bPreviewingHotcue) { 00433 // This is a activate release and we are previewing at least one 00434 // hotcue. If this hotcue is previewing: 00435 if (pControl->isPreviewing()) { 00436 // Mark this hotcue as not previewing. 00437 int iPosition = pControl->getPreviewingPosition(); 00438 pControl->setPreviewing(false); 00439 pControl->setPreviewingPosition(-1); 00440 00441 // If this is the last hotcue to leave preview. 00442 if (--m_iCurrentlyPreviewingHotcues == 0) { 00443 bool bHotcueCancel = m_bHotcueCancel; 00444 m_bPreviewingHotcue = false; 00445 m_bHotcueCancel = false; 00446 // If hotcue cancel is marked then do not snap back to the 00447 // hotcue and stop. Otherwise, seek back to the start point and 00448 // stop. 00449 if (bHotcueCancel) { 00450 // Re-trigger the play button value so controllers get the correct one 00451 // after. 00452 m_pPlayButton->set(m_pPlayButton->get()); 00453 } else { 00454 m_pPlayButton->set(0.0); 00455 // Need to unlock before emitting any signals to prevent deadlock. 00456 lock.unlock(); 00457 emit(seekAbs(iPosition)); 00458 } 00459 } 00460 } 00461 } 00462 } 00463 00464 void CueControl::hotcueClear(HotcueControl* pControl, double v) { 00465 if (!v) 00466 return; 00467 00468 QMutexLocker lock(&m_mutex); 00469 if (!m_pLoadedTrack) 00470 return; 00471 00472 Cue* pCue = pControl->getCue(); 00473 if (pCue) { 00474 pCue->setHotCue(-1); 00475 } 00476 00477 detachCue(pControl->getHotcueNumber()); 00478 } 00479 00480 void CueControl::hotcuePositionChanged(HotcueControl* pControl, double newPosition) { 00481 QMutexLocker lock(&m_mutex); 00482 if (!m_pLoadedTrack) 00483 return; 00484 00485 Cue* pCue = pControl->getCue(); 00486 if (pCue) { 00487 // Setting the position to -1 is the same as calling hotcue_x_clear 00488 if (newPosition == -1) { 00489 pCue->setHotCue(-1); 00490 detachCue(pControl->getHotcueNumber()); 00491 } else if (newPosition > 0 && newPosition < m_pTrackSamples->get()) { 00492 int position = newPosition; 00493 // People writing from MIDI land, elsewhere might be careless. 00494 if (position % 2 != 0) { 00495 position--; 00496 } 00497 pCue->setPosition(position); 00498 } 00499 } 00500 } 00501 00502 void CueControl::hintReader(QList<Hint>& hintList) { 00503 QMutexLocker lock(&m_mutex); 00504 00505 Hint cue_hint; 00506 double cuePoint = m_pCuePoint->get(); 00507 if (cuePoint >= 0) { 00508 cue_hint.sample = m_pCuePoint->get(); 00509 cue_hint.length = 0; 00510 cue_hint.priority = 10; 00511 hintList.append(cue_hint); 00512 } 00513 00514 for (int i = 0; i < m_iNumHotCues; ++i) { 00515 HotcueControl* pControl = m_hotcueControl[i]; 00516 Cue *pCue = pControl->getCue(); 00517 if (pCue != NULL) { 00518 double position = pControl->getPosition()->get(); 00519 if (position != -1) { 00520 cue_hint.sample = position; 00521 if (cue_hint.sample % 2 != 0) 00522 cue_hint.sample--; 00523 cue_hint.length = 0; 00524 cue_hint.priority = 10; 00525 hintList.push_back(cue_hint); 00526 } 00527 } 00528 } 00529 } 00530 00531 void CueControl::saveCuePoint(double cuePoint) { 00532 if (m_pLoadedTrack) { 00533 m_pLoadedTrack->setCuePoint(cuePoint); 00534 } 00535 } 00536 00537 void CueControl::cueSet(double v) { 00538 if (!v) 00539 return; 00540 00541 QMutexLocker lock(&m_mutex); 00542 double cue = (m_pQuantizeEnabled->get() > 0.0 && m_pClosestBeat->get() != -1) ? 00543 floorf(m_pClosestBeat->get()) : floorf(getCurrentSample()); 00544 if (!even(cue)) 00545 cue--; 00546 m_pCuePoint->set(cue); 00547 saveCuePoint(cue); 00548 } 00549 00550 void CueControl::cueGoto(double v) 00551 { 00552 if (!v) 00553 return; 00554 00555 QMutexLocker lock(&m_mutex); 00556 // Set cue point if play is not pressed 00557 if (m_pPlayButton->get()==0.) { 00558 // Set the cue point and play 00559 cueSet(v); 00560 m_pPlayButton->set(1.0); 00561 } else { 00562 // Seek to cue point 00563 double cuePoint = m_pCuePoint->get(); 00564 00565 // Need to unlock before emitting any signals to prevent deadlock. 00566 lock.unlock(); 00567 00568 emit(seekAbs(cuePoint)); 00569 } 00570 } 00571 00572 void CueControl::cueGotoAndStop(double v) 00573 { 00574 if (!v) 00575 return; 00576 00577 QMutexLocker lock(&m_mutex); 00578 m_pPlayButton->set(0.0); 00579 double cuePoint = m_pCuePoint->get(); 00580 00581 // Need to unlock before emitting any signals to prevent deadlock. 00582 lock.unlock(); 00583 00584 emit(seekAbs(cuePoint)); 00585 } 00586 00587 void CueControl::cuePreview(double v) 00588 { 00589 QMutexLocker lock(&m_mutex); 00590 00591 if (v) { 00592 m_pPlayButton->set(1.0); 00593 m_bPreviewing = true; 00594 } else if (!v && m_bPreviewing) { 00595 m_pPlayButton->set(0.0); 00596 m_bPreviewing = false; 00597 } 00598 00599 double cuePoint = m_pCuePoint->get(); 00600 00601 // Need to unlock before emitting any signals to prevent deadlock. 00602 lock.unlock(); 00603 00604 emit(seekAbs(cuePoint)); 00605 } 00606 00607 void CueControl::cueSimple(double v) { 00608 if (!v) 00609 return; 00610 00611 QMutexLocker lock(&m_mutex); 00612 // Simple cueing is if the player is not playing, set the cue point -- 00613 // otherwise seek to the cue point. 00614 if (m_pPlayButton->get() == 0.0f) { 00615 return cueSet(v); 00616 } 00617 00618 double cuePoint = m_pCuePoint->get(); 00619 00620 // Need to unlock before emitting any signals to prevent deadlock. 00621 lock.unlock(); 00622 00623 emit(seekAbs(cuePoint)); 00624 } 00625 00626 void CueControl::cueCDJ(double v) { 00627 /* This is how CDJ cue buttons work: 00628 * If pressed while playing, stop playback and go to cue. 00629 * If pressed while stopped and at cue, play while pressed. 00630 * If pressed while stopped and not at cue, set new cue point. 00631 * If play is pressed while holding cue, the deck is now playing. (Handled in cuePlay().) 00632 */ 00633 00634 QMutexLocker lock(&m_mutex); 00635 bool playing = (m_pPlayButton->get() == 1.0); 00636 double cuePoint = m_pCuePoint->get(); 00637 00638 if (v) { 00639 if (playing) { 00640 m_pPlayButton->set(0.0); 00641 00642 // Just in case. 00643 m_bPreviewing = false; 00644 00645 // Need to unlock before emitting any signals to prevent deadlock. 00646 lock.unlock(); 00647 00648 emit(seekAbs(cuePoint)); 00649 } else { 00650 if (fabs(getCurrentSample() - m_pCuePoint->get()) < 1.0f) { 00651 m_pPlayButton->set(1.0); 00652 m_bPreviewing = true; 00653 } else { 00654 cueSet(v); 00655 // Just in case. 00656 m_bPreviewing = false; 00657 00658 // If quantize is enabled, jump to the cue point since it's not 00659 // necessarily where we currently are 00660 if (m_pQuantizeEnabled->get() > 0.0) { 00661 lock.unlock(); // prevent deadlock. 00662 emit(seekAbs(m_pCuePoint->get())); 00663 } 00664 } 00665 } 00666 } else if (m_bPreviewing) { 00667 m_pPlayButton->set(0.0); 00668 m_bPreviewing = false; 00669 00670 // Need to unlock before emitting any signals to prevent deadlock. 00671 lock.unlock(); 00672 00673 emit(seekAbs(cuePoint)); 00674 } 00675 else { 00676 // Re-trigger the play button value so controllers get the correct one 00677 // after cuePlay() changes it. 00678 m_pPlayButton->set(m_pPlayButton->get()); 00679 } 00680 } 00681 00682 void CueControl::cuePlay(double v) { 00683 Q_UNUSED(v); 00684 00685 QMutexLocker lock(&m_mutex); 00686 00687 if (m_bPreviewing) { 00688 // we're previewing? Then stop previewing and go into normal play mode. 00689 m_pPlayButton->set(1.0); 00690 m_bPreviewing = false; 00691 } 00692 00693 if (m_bPreviewingHotcue) { 00694 m_pPlayButton->set(1.0); 00695 m_bHotcueCancel = true; 00696 } 00697 00698 lock.unlock(); 00699 } 00700 00701 void CueControl::cueDefault(double v) { 00702 // Decide which cue implementation to call based on the user preference 00703 if (m_pCueMode->get() == 0.0f) { 00704 cueCDJ(v); 00705 } else { 00706 cueSimple(v); 00707 } 00708 } 00709 00710 ConfigKey HotcueControl::keyForControl(int hotcue, QString name) { 00711 ConfigKey key; 00712 key.group = m_pGroup; 00713 // Add one to hotcue so that we dont have a hotcue_0 00714 key.item = QString("hotcue_%1_%2").arg(hotcue+1).arg(name); 00715 return key; 00716 } 00717 00718 HotcueControl::HotcueControl(const char* pGroup, int i) 00719 : m_pGroup(pGroup), 00720 m_iHotcueNumber(i), 00721 m_pCue(NULL), 00722 m_bPreviewing(false), 00723 m_iPreviewingPosition(-1) { 00724 m_hotcuePosition = new ControlObject(keyForControl(i, "position")); 00725 connect(m_hotcuePosition, SIGNAL(valueChanged(double)), 00726 this, SLOT(slotHotcuePositionChanged(double)), 00727 Qt::DirectConnection); 00728 m_hotcuePosition->set(-1); 00729 00730 m_hotcueEnabled = new ControlObject(keyForControl(i, "enabled")); 00731 m_hotcueEnabled->set(0); 00732 00733 m_hotcueSet = new ControlPushButton(keyForControl(i, "set")); 00734 connect(m_hotcueSet, SIGNAL(valueChanged(double)), 00735 this, SLOT(slotHotcueSet(double)), 00736 Qt::DirectConnection); 00737 00738 m_hotcueGoto = new ControlPushButton(keyForControl(i, "goto")); 00739 connect(m_hotcueGoto, SIGNAL(valueChanged(double)), 00740 this, SLOT(slotHotcueGoto(double)), 00741 Qt::DirectConnection); 00742 00743 m_hotcueGotoAndStop = new ControlPushButton(keyForControl(i, "gotoandstop")); 00744 connect(m_hotcueGotoAndStop, SIGNAL(valueChanged(double)), 00745 this, SLOT(slotHotcueGotoAndStop(double)), 00746 Qt::DirectConnection); 00747 00748 m_hotcueActivate = new ControlPushButton(keyForControl(i, "activate")); 00749 connect(m_hotcueActivate, SIGNAL(valueChanged(double)), 00750 this, SLOT(slotHotcueActivate(double)), 00751 Qt::DirectConnection); 00752 00753 m_hotcueActivatePreview = new ControlPushButton(keyForControl(i, "activate_preview")); 00754 connect(m_hotcueActivatePreview, SIGNAL(valueChanged(double)), 00755 this, SLOT(slotHotcueActivatePreview(double)), 00756 Qt::DirectConnection); 00757 00758 m_hotcueClear = new ControlPushButton(keyForControl(i, "clear")); 00759 connect(m_hotcueClear, SIGNAL(valueChanged(double)), 00760 this, SLOT(slotHotcueClear(double)), 00761 Qt::DirectConnection); 00762 } 00763 00764 HotcueControl::~HotcueControl() { 00765 delete m_hotcuePosition; 00766 delete m_hotcueEnabled; 00767 delete m_hotcueSet; 00768 delete m_hotcueGoto; 00769 delete m_hotcueGotoAndStop; 00770 delete m_hotcueActivate; 00771 delete m_hotcueActivatePreview; 00772 delete m_hotcueClear; 00773 } 00774 00775 void HotcueControl::slotHotcueSet(double v) { 00776 emit(hotcueSet(this, v)); 00777 } 00778 00779 void HotcueControl::slotHotcueGoto(double v) { 00780 emit(hotcueGoto(this, v)); 00781 } 00782 00783 void HotcueControl::slotHotcueGotoAndStop(double v) { 00784 emit(hotcueGotoAndStop(this, v)); 00785 } 00786 00787 void HotcueControl::slotHotcueActivate(double v) { 00788 emit(hotcueActivate(this, v)); 00789 } 00790 00791 void HotcueControl::slotHotcueActivatePreview(double v) { 00792 emit(hotcueActivatePreview(this, v)); 00793 } 00794 00795 void HotcueControl::slotHotcueClear(double v) { 00796 emit(hotcueClear(this, v)); 00797 } 00798 00799 void HotcueControl::slotHotcuePositionChanged(double newPosition) { 00800 emit(hotcuePositionChanged(this, newPosition)); 00801 }