diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index e805f5f567b..4314d6419b7 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -237,12 +237,55 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) // BPM / Beatgrid QMenu* pBpmMenu = addSubmenu(tr("BPM / Beatgrid")); - addDeckAndSamplerControl("bpm", tr("BPM"), tr("BPM"), pBpmMenu, true); - addDeckAndSamplerControl("bpm_up", tr("BPM +1"), tr("Increase BPM by 1"), pBpmMenu); - addDeckAndSamplerControl("bpm_down", tr("BPM -1"), tr("Decrease BPM by 1"), pBpmMenu); - addDeckAndSamplerControl("bpm_up_small", tr("BPM +0.1"), tr("Increase BPM by 0.1"), pBpmMenu); - addDeckAndSamplerControl("bpm_down_small", tr("BPM -0.1"), tr("Decrease BPM by 0.1"), pBpmMenu); - addDeckAndSamplerControl("bpm_tap", tr("BPM Tap"), tr("BPM tap button"), pBpmMenu); + addDeckAndSamplerControl("bpm", + tr("BPM"), + tr("BPM"), + pBpmMenu, + true); + addDeckAndSamplerControl("bpm_up", + tr("BPM +1"), + tr("Increase BPM by 1"), + pBpmMenu); + addDeckAndSamplerControl("bpm_down", + tr("BPM -1"), + tr("Decrease BPM by 1"), + pBpmMenu); + addDeckAndSamplerControl("bpm_up_small", + tr("BPM +0.1"), + tr("Increase BPM by 0.1"), + pBpmMenu); + addDeckAndSamplerControl("bpm_down_small", + tr("BPM -0.1"), + tr("Decrease BPM by 0.1"), + pBpmMenu); + addDeckAndSamplerControl("bpm_tap", + tr("BPM Tap"), + tr("BPM tap button"), + pBpmMenu); + addDeckAndSamplerControl("beats_set_halve", + tr("Halve BPM"), + tr("Multiply current BPM by 0.5"), + pBpmMenu); + addDeckAndSamplerControl("beats_set_twothirds", + tr("2/3 BPM"), + tr("Multiply current BPM by 0.666"), + pBpmMenu); + addDeckAndSamplerControl("beats_set_threefourths", + tr("3/4 BPM"), + tr("Multiply current BPM by 0.75"), + pBpmMenu); + addDeckAndSamplerControl("beats_set_fourthirds", + tr("4/3 BPM"), + tr("Multiply current BPM by 1.333"), + pBpmMenu); + addDeckAndSamplerControl("beats_set_threehalves", + tr("3/2 BPM"), + tr("Multiply current BPM by 1.5"), + pBpmMenu); + addDeckAndSamplerControl("beats_set_double", + tr("Double BPM"), + tr("Multiply current BPM by 2"), + pBpmMenu); pBpmMenu->addSeparator(); addDeckAndSamplerControl("beats_adjust_faster", tr("Adjust Beatgrid Faster +.01"), diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index aba923fcb71..b6ab7c8e604 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -67,25 +67,39 @@ BpmControl::BpmControl(const QString& group, m_pLoopEndPosition = new ControlProxy(group, "loop_end_position", this); m_pLocalBpm = new ControlObject(ConfigKey(group, "local_bpm")); - m_pAdjustBeatsFaster = new ControlPushButton(ConfigKey(group, "beats_adjust_faster"), false); + + m_pAdjustBeatsFaster = std::make_unique( + ConfigKey(group, "beats_adjust_faster"), false); m_pAdjustBeatsFaster->setKbdRepeatable(true); - connect(m_pAdjustBeatsFaster, &ControlObject::valueChanged, - this, &BpmControl::slotAdjustBeatsFaster, + connect(m_pAdjustBeatsFaster.get(), + &ControlObject::valueChanged, + this, + &BpmControl::slotAdjustBeatsFaster, Qt::DirectConnection); - m_pAdjustBeatsSlower = new ControlPushButton(ConfigKey(group, "beats_adjust_slower"), false); + m_pAdjustBeatsSlower = std::make_unique( + ConfigKey(group, "beats_adjust_slower"), false); m_pAdjustBeatsSlower->setKbdRepeatable(true); - connect(m_pAdjustBeatsSlower, &ControlObject::valueChanged, - this, &BpmControl::slotAdjustBeatsSlower, + connect(m_pAdjustBeatsSlower.get(), + &ControlObject::valueChanged, + this, + &BpmControl::slotAdjustBeatsSlower, Qt::DirectConnection); - m_pTranslateBeatsEarlier = new ControlPushButton(ConfigKey(group, "beats_translate_earlier"), false); + + m_pTranslateBeatsEarlier = std::make_unique( + ConfigKey(group, "beats_translate_earlier"), false); m_pTranslateBeatsEarlier->setKbdRepeatable(true); - connect(m_pTranslateBeatsEarlier, &ControlObject::valueChanged, - this, &BpmControl::slotTranslateBeatsEarlier, + connect(m_pTranslateBeatsEarlier.get(), + &ControlObject::valueChanged, + this, + &BpmControl::slotTranslateBeatsEarlier, Qt::DirectConnection); - m_pTranslateBeatsLater = new ControlPushButton(ConfigKey(group, "beats_translate_later"), false); + m_pTranslateBeatsLater = std::make_unique( + ConfigKey(group, "beats_translate_later"), false); m_pTranslateBeatsLater->setKbdRepeatable(true); - connect(m_pTranslateBeatsLater, &ControlObject::valueChanged, - this, &BpmControl::slotTranslateBeatsLater, + connect(m_pTranslateBeatsLater.get(), + &ControlObject::valueChanged, + this, + &BpmControl::slotTranslateBeatsLater, Qt::DirectConnection); m_pTranslateBeatsMove = new ControlEncoder(ConfigKey(group, "beats_translate_move"), false); connect(m_pTranslateBeatsMove, @@ -94,6 +108,66 @@ BpmControl::BpmControl(const QString& group, &BpmControl::slotTranslateBeatsMove, Qt::DirectConnection); + m_pBeatsHalve = std::make_unique(ConfigKey(group, "beats_set_halve"), false); + connect(m_pBeatsHalve.get(), + &ControlObject::valueChanged, + this, + [this](int value) { + if (value > 0) { + slotScaleBpm(mixxx::Beats::BpmScale::Halve); + } + }); + m_pBeatsTwoThirds = std::make_unique( + ConfigKey(group, "beats_set_twothirds"), false); + connect(m_pBeatsTwoThirds.get(), + &ControlObject::valueChanged, + this, + [this](int value) { + if (value > 0) { + slotScaleBpm(mixxx::Beats::BpmScale::TwoThirds); + } + }); + m_pBeatsThreeFourths = std::make_unique( + ConfigKey(group, "beats_set_threefourths"), false); + connect(m_pBeatsThreeFourths.get(), + &ControlObject::valueChanged, + this, + [this](int value) { + if (value > 0) { + slotScaleBpm(mixxx::Beats::BpmScale::ThreeFourths); + } + }); + m_pBeatsFourThirds = std::make_unique( + ConfigKey(group, "beats_set_fourthirds"), false); + connect(m_pBeatsFourThirds.get(), + &ControlObject::valueChanged, + this, + [this](int value) { + if (value > 0) { + slotScaleBpm(mixxx::Beats::BpmScale::FourThirds); + } + }); + m_pBeatsThreeHalves = std::make_unique( + ConfigKey(group, "beats_set_threehalves"), false); + connect(m_pBeatsThreeHalves.get(), + &ControlObject::valueChanged, + this, + [this](int value) { + if (value > 0) { + slotScaleBpm(mixxx::Beats::BpmScale::ThreeHalves); + } + }); + m_pBeatsDouble = std::make_unique( + ConfigKey(group, "beats_set_double"), false); + connect(m_pBeatsDouble.get(), + &ControlObject::valueChanged, + this, + [this](int value) { + if (value > 0) { + slotScaleBpm(mixxx::Beats::BpmScale::Double); + } + }); + // Pick a wide range (kBpmRangeMin to kBpmRangeMax) and allow out of bounds sets. This lets you // map a soft-takeover MIDI knob to the BPM. This also creates bpm_up and // bpm_down controls. @@ -156,11 +230,7 @@ BpmControl::~BpmControl() { delete m_pButtonTap; delete m_pTranslateBeats; delete m_pBeatsTranslateMatchAlignment; - delete m_pTranslateBeatsEarlier; - delete m_pTranslateBeatsLater; delete m_pTranslateBeatsMove; - delete m_pAdjustBeatsFaster; - delete m_pAdjustBeatsSlower; delete m_pBeatsUndo; } @@ -291,6 +361,22 @@ void BpmControl::slotTapFilter(double averageLength, int numSamples) { pTrack->trySetBeats(*newBeats); } +void BpmControl::slotScaleBpm(mixxx::Beats::BpmScale bpmScale) { + const TrackPointer pTrack = getEngineBuffer()->getLoadedTrack(); + if (!pTrack) { + return; + } + const mixxx::BeatsPointer pBeats = pTrack->getBeats(); + if (!pBeats) { + return; + } + const auto newBeats = pBeats->tryScale(bpmScale); + if (!newBeats) { + return; + } + pTrack->trySetBeats(*newBeats); +} + // static double BpmControl::shortestPercentageChange(const double& current_percentage, const double& target_percentage) { diff --git a/src/engine/controls/bpmcontrol.h b/src/engine/controls/bpmcontrol.h index d5fa7c08a88..c499b6fc63b 100644 --- a/src/engine/controls/bpmcontrol.h +++ b/src/engine/controls/bpmcontrol.h @@ -121,6 +121,7 @@ class BpmControl : public EngineControl { } double calcSyncAdjustment(bool userTweakingSync); void adjustBeatsBpm(double deltaBpm); + void slotScaleBpm(mixxx::Beats::BpmScale bpmScale); friend class SyncControl; @@ -142,13 +143,20 @@ class BpmControl : public EngineControl { // The average bpm around the current playposition; ControlObject* m_pLocalBpm; - ControlPushButton* m_pAdjustBeatsFaster; - ControlPushButton* m_pAdjustBeatsSlower; - ControlPushButton* m_pTranslateBeatsEarlier; - ControlPushButton* m_pTranslateBeatsLater; + std::unique_ptr m_pAdjustBeatsFaster; + std::unique_ptr m_pAdjustBeatsSlower; + std::unique_ptr m_pTranslateBeatsEarlier; + std::unique_ptr m_pTranslateBeatsLater; ControlEncoder* m_pTranslateBeatsMove; ControlPushButton* m_pBeatsUndo; + std::unique_ptr m_pBeatsHalve; + std::unique_ptr m_pBeatsTwoThirds; + std::unique_ptr m_pBeatsThreeFourths; + std::unique_ptr m_pBeatsFourThirds; + std::unique_ptr m_pBeatsThreeHalves; + std::unique_ptr m_pBeatsDouble; + std::unique_ptr m_pBpmLock; // The current effective BPM of the engine