diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index ebba447f0761..0669f9b8cbb9 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -213,6 +213,8 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) tr("Cue button (CDJ mode)"), cueMenu); addDeckControl("play_stutter", tr("Stutter Cue"), tr("Stutter cue"), cueMenu); + addDeckControl("cue_play", tr("Cue (Cue Play)"), + tr("Go to cue point and play after release"), cueMenu); // Hotcues QMenu* hotcueMenu = addSubmenu(tr("Hotcues")); diff --git a/src/engine/cuecontrol.cpp b/src/engine/cuecontrol.cpp index 7725ac20c551..10dbca100009 100644 --- a/src/engine/cuecontrol.cpp +++ b/src/engine/cuecontrol.cpp @@ -18,6 +18,7 @@ static const double CUE_MODE_PIONEER = 1.0; static const double CUE_MODE_DENON = 2.0; static const double CUE_MODE_NUMARK = 3.0; static const double CUE_MODE_MIXXX_NO_BLINK = 4.0; +static const double CUE_MODE_CUP = 5.0; CueControl::CueControl(QString group, UserSettingsPointer pConfig) : @@ -63,6 +64,12 @@ CueControl::CueControl(QString group, this, SLOT(cueGotoAndPlay(double)), Qt::DirectConnection); + m_pCuePlay = + new ControlPushButton(ConfigKey(group, "cue_play")); + connect(m_pCuePlay, SIGNAL(valueChanged(double)), + this, SLOT(cuePlay(double)), + Qt::DirectConnection); + m_pCueGotoAndStop = new ControlPushButton(ConfigKey(group, "cue_gotoandstop")); connect(m_pCueGotoAndStop, SIGNAL(valueChanged(double)), @@ -102,6 +109,7 @@ CueControl::~CueControl() { delete m_pCueSet; delete m_pCueGoto; delete m_pCueGotoAndPlay; + delete m_pCuePlay; delete m_pCueGotoAndStop; delete m_pCuePreview; delete m_pCueCDJ; @@ -797,11 +805,47 @@ void CueControl::cueDenon(double v) { } } +void CueControl::cuePlay(double v) { + // This is how CUP button works: + // If playing, press to go to cue and stop. + // If stopped, press to set as cue point. + // On release, start playing from cue point. + + + QMutexLocker lock(&m_mutex); + bool playing = (m_pPlayButton->toBool()); + + // pressed + if (v) { + if (playing) { + 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() && getCurrentSample() <= getTotalSamples()) { + // Pause not at cue point and not at end position + cueSet(v); + // Just in case. + m_bPreviewing = false; + } + } else if (isTrackAtCue()){ + m_bPreviewing = false; + m_pPlayButton->set(1.0); + lock.unlock(); + + } +} + void CueControl::cueDefault(double v) { double cueMode = m_pCueMode->get(); // Decide which cue implementation to call based on the user preference if (cueMode == CUE_MODE_DENON || cueMode == CUE_MODE_NUMARK) { cueDenon(v); + } else if (cueMode == CUE_MODE_CUP) { + cuePlay(v); } else { // The modes CUE_MODE_PIONEER and CUE_MODE_MIXXX are similar // are handled inside cueCDJ(v) diff --git a/src/engine/cuecontrol.h b/src/engine/cuecontrol.h index 8235f7d1f37b..1252dac68482 100644 --- a/src/engine/cuecontrol.h +++ b/src/engine/cuecontrol.h @@ -115,6 +115,7 @@ class CueControl : public EngineControl { void cuePreview(double v); void cueCDJ(double v); void cueDenon(double v); + void cuePlay(double v); void cueDefault(double v); void pause(double v); void playStutter(double v); @@ -149,6 +150,7 @@ class CueControl : public EngineControl { ControlIndicator* m_pPlayIndicator; ControlPushButton* m_pCueGoto; ControlPushButton* m_pCueGotoAndPlay; + ControlPushButton* m_pCuePlay; ControlPushButton* m_pCueGotoAndStop; ControlPushButton* m_pCuePreview; ControlProxy* m_pVinylControlEnabled; diff --git a/src/preferences/dialog/dlgprefcontrols.cpp b/src/preferences/dialog/dlgprefcontrols.cpp index e336072ceca4..0b7ee074d2f5 100644 --- a/src/preferences/dialog/dlgprefcontrols.cpp +++ b/src/preferences/dialog/dlgprefcontrols.cpp @@ -242,6 +242,7 @@ DlgPrefControls::DlgPrefControls(QWidget * parent, MixxxMainWindow * mixxx, ComboBoxCueDefault->addItem(tr("Pioneer mode"), 1); ComboBoxCueDefault->addItem(tr("Denon mode"), 2); ComboBoxCueDefault->addItem(tr("Numark mode"), 3); + ComboBoxCueDefault->addItem(tr("CUP mode"), 5); const int cueDefaultIndex = cueDefaultIndexByData(cueDefaultValue); ComboBoxCueDefault->setCurrentIndex(cueDefaultIndex); slotSetCueDefault(cueDefaultIndex); diff --git a/src/skin/tooltips.cpp b/src/skin/tooltips.cpp index ff591316ed4d..f16bff8f58b4 100644 --- a/src/skin/tooltips.cpp +++ b/src/skin/tooltips.cpp @@ -400,7 +400,7 @@ void Tooltips::addStandardTooltips() { add("cue_default_cue_gotoandstop") << tr("Cue") << QString("%1 %2: %3").arg(leftClick, whilePlaying, tr("Stops track at cue point.")) - << QString("%1 %2: %3").arg(leftClick, whileStopped, tr("Set cue point (Pioneer/Mixxx mode) OR preview from it (Denon mode).")) + << QString("%1 %2: %3").arg(leftClick, whileStopped, tr("Set cue point (Pioneer/Mixxx mode), set cue point and play (CUP mode) OR preview from it (Denon mode).")) << tr("Hint: Change the default cue mode in Preferences -> Interface.") << quantizeSnap << QString("%1: %2").arg(rightClick, tr("Seeks the track to the cue-point and stops."));