forked from mixxxdj/mixxx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* eliminate unnecessary allocation in `EffectKnobParameterSlot` * remove unnecessary allocation in `SoftTakeoverTest*` * eliminate checks in `SoftTakeoverCtrl::enable` by encoding constraints in the type system * deduplicate common code in `SoftTakeoverTest`. Now bundled as `SoftTakeoverTestWithValue` * remove unnecessary allocation in `SoftTakeoverCtrl` * many more miscellaneous improvements to `SoftTakeover(-Ctrl)`.
- Loading branch information
Showing
16 changed files
with
356 additions
and
586 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,97 @@ | ||
#pragma once | ||
|
||
#include <QHash> | ||
#include <chrono> | ||
#include <gsl/pointers> | ||
#include <unordered_map> | ||
|
||
#include "util/duration.h" | ||
#include "util/assert.h" | ||
#include "util/time.h" | ||
|
||
class ControlObject; | ||
class ControlPotmeter; | ||
|
||
class SoftTakeover { | ||
public: | ||
// I would initialize it here but that's C++11 coolness. (Because it's a double.) | ||
static const double kDefaultTakeoverThreshold; | ||
// 3/128 units away from the current is enough to catch fast non-sequential moves | ||
// but not cause an audibly noticeable jump, determined experimentally with | ||
// slow-refresh controllers. | ||
// TODO (XXX): Expose this to the controller mapping environment? | ||
static constexpr double kDefaultTakeoverThreshold = 3.0 / 128; | ||
|
||
SoftTakeover(); | ||
bool ignore(ControlObject* control, double newParameter); | ||
void ignoreNext(); | ||
void setThreshold(double threshold); | ||
SoftTakeover() = default; | ||
bool ignore(const ControlObject& control, double newParameter); | ||
void ignoreNext() { | ||
m_time = kFirstValueTime; | ||
} | ||
void setThreshold(double threshold) { | ||
m_dThreshold = threshold; | ||
} | ||
|
||
struct TestAccess; | ||
// TODO (XXX): find a better testing solution than this TestAccess | ||
// front-door coupled to `mixxx::Time`. | ||
struct TestAccess { | ||
static constexpr auto getTimeThreshold() { | ||
return kSubsequentValueOverrideTime; | ||
} | ||
template<class Rep = mixxx::Time::rep, | ||
class Period = mixxx::Time::period> | ||
static void advanceTimePastThreshold( | ||
std::chrono::duration<Rep, Period> offset = | ||
std::chrono::nanoseconds(0)) { | ||
mixxx::Time::addTestTime(getTimeThreshold() + offset); | ||
} | ||
}; | ||
|
||
private: | ||
using ClockT = mixxx::Time; | ||
// If a new value is received within this amount of time, jump to it | ||
// regardless. This allows quickly whipping controls to work while retaining | ||
// the benefits of soft-takeover for slower movements. Setting this too | ||
// high will defeat the purpose of soft-takeover. | ||
static const mixxx::Duration kSubsequentValueOverrideTime; | ||
static constexpr ClockT::duration kSubsequentValueOverrideTime = std::chrono::milliseconds(50); | ||
static constexpr ClockT::time_point kFirstValueTime = ClockT::time_point::min(); | ||
|
||
mixxx::Duration m_time; | ||
double m_prevParameter; | ||
double m_dThreshold; | ||
}; | ||
|
||
struct SoftTakeover::TestAccess { | ||
static mixxx::Duration getTimeThreshold() { | ||
return kSubsequentValueOverrideTime; | ||
} | ||
ClockT::time_point m_time{kFirstValueTime}; | ||
double m_prevParameter{0}; | ||
double m_dThreshold{kDefaultTakeoverThreshold}; | ||
}; | ||
|
||
class SoftTakeoverCtrl { | ||
public: | ||
SoftTakeoverCtrl(); | ||
~SoftTakeoverCtrl(); | ||
SoftTakeoverCtrl() = default; | ||
|
||
// Enable soft-takeover for the given Control. | ||
// This does nothing on a control that already has soft-takeover enabled. | ||
void enable(ControlObject* control); | ||
void enable(gsl::not_null<ControlPotmeter*> control); | ||
// Disable soft-takeover for the given Control | ||
void disable(ControlObject* control); | ||
void disable(ControlObject* control) { | ||
m_softTakeoverHash.erase(control); | ||
} | ||
// Check to see if the new value for the Control should be ignored | ||
bool ignore(ControlObject* control, double newMidiParameter); | ||
bool ignore(ControlObject* control, double newParameter) { | ||
auto coIt = m_softTakeoverHash.find(control); | ||
if (coIt == m_softTakeoverHash.end()) { | ||
return false; | ||
} | ||
VERIFY_OR_DEBUG_ASSERT(control) { | ||
return false; | ||
} | ||
return coIt->second.ignore(*control, newParameter); | ||
} | ||
// Ignore the next supplied parameter | ||
void ignoreNext(ControlObject* control); | ||
void ignoreNext(ControlObject* control) { | ||
auto coIt = m_softTakeoverHash.find(control); | ||
if (coIt == m_softTakeoverHash.end()) { | ||
return; | ||
} | ||
|
||
coIt->second.ignoreNext(); | ||
} | ||
|
||
private: | ||
QHash<ControlObject*, SoftTakeover*> m_softTakeoverHash; | ||
// ControlObjects are borrowed. They must outlive this object. | ||
// Note that even though we can only enable softTakeover on | ||
// `ControlPotmeter`s, we store the base ControlObject to not force the user | ||
// to downcast for `disable()` and `ignore()`/`ignoreNext()`. | ||
std::unordered_map<ControlObject*, SoftTakeover> m_softTakeoverHash; | ||
}; |
Oops, something went wrong.