Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/engine/cuecontrol.cpp

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines