Skip to content

Commit

Permalink
SyncLock: Don't recalc half/double multiplier on every callback
Browse files Browse the repository at this point in the history
  • Loading branch information
ywwg committed Mar 15, 2021
1 parent 6cd5ac1 commit 8e46045
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 65 deletions.
11 changes: 8 additions & 3 deletions src/engine/controls/bpmcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,11 +444,11 @@ double BpmControl::calcSyncedRate(double userTweak) {
}

// Now we have all we need to calculate the sync adjustment if any.
double adjustment = calcSyncAdjustment(m_dUserTweakingSync);
double adjustment = calcSyncAdjustment(rate < 0.0, m_dUserTweakingSync);
return (rate + userTweak) * adjustment;
}

double BpmControl::calcSyncAdjustment(bool userTweakingSync) {
double BpmControl::calcSyncAdjustment(bool reversed, bool userTweakingSync) {
int resetSyncAdjustment = m_resetSyncAdjustment.fetchAndStoreRelaxed(0);
if (resetSyncAdjustment) {
m_dLastSyncAdjustment = 1.0;
Expand All @@ -470,6 +470,11 @@ double BpmControl::calcSyncAdjustment(bool userTweakingSync) {
double syncTargetBeatDistance = m_dSyncTargetBeatDistance.getValue();
// We want the untweaked beat distance, so we have to add the offset here.
double thisBeatDistance = m_pThisBeatDistance->get() + m_dUserOffset.getValue();
// If we are moving backwards, we have to invert the calculations.
if (reversed) {
syncTargetBeatDistance = 1.0 - syncTargetBeatDistance;
thisBeatDistance = 1.0 - thisBeatDistance;
}
double shortest_distance = shortestPercentageChange(
syncTargetBeatDistance, thisBeatDistance);

Expand Down Expand Up @@ -1094,7 +1099,7 @@ void BpmControl::setTargetBeatDistance(double beatDistance) {
m_dSyncTargetBeatDistance.setValue(beatDistance);
}

void BpmControl::setInstantaneousBpm(double instantaneousBpm) {
void BpmControl::updateInstantaneousBpm(double instantaneousBpm) {
m_dSyncInstantaneousBpm = instantaneousBpm;
}

Expand Down
4 changes: 2 additions & 2 deletions src/engine/controls/bpmcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class BpmControl : public EngineControl {
double getBeatDistance(double dThisPosition) const;

void setTargetBeatDistance(double beatDistance);
void setInstantaneousBpm(double instantaneousBpm);
void updateInstantaneousBpm(double instantaneousBpm);
void resetSyncAdjustment();
double updateLocalBpm();
/// updateBeatDistance is adjusted to include the user offset so
Expand Down Expand Up @@ -106,7 +106,7 @@ class BpmControl : public EngineControl {
return toSynchronized(getSyncMode());
}
bool syncTempo();
double calcSyncAdjustment(bool userTweakingSync);
double calcSyncAdjustment(bool reversed, bool userTweakingSync);

friend class SyncControl;

Expand Down
20 changes: 10 additions & 10 deletions src/engine/sync/basesyncablelistener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ BaseSyncableListener::BaseSyncableListener(UserSettingsPointer pConfig)
m_pInternalClock(new InternalClock(kInternalClockGroup, this)),
m_pMasterSyncable(nullptr) {
qRegisterMetaType<SyncMode>("SyncMode");
m_pInternalClock->setMasterBpm(124.0);
m_pInternalClock->updateMasterBpm(124.0);
}

BaseSyncableListener::~BaseSyncableListener() {
Expand Down Expand Up @@ -87,57 +87,57 @@ double BaseSyncableListener::masterBaseBpm() const {
void BaseSyncableListener::setMasterBpm(Syncable* pSource, double bpm) {
//qDebug() << "BaseSyncableListener::setMasterBpm" << pSource << bpm;
if (pSource != m_pInternalClock) {
m_pInternalClock->setMasterBpm(bpm);
m_pInternalClock->updateMasterBpm(bpm);
}
foreach (Syncable* pSyncable, m_syncables) {
if (pSyncable == pSource ||
!pSyncable->isSynchronized()) {
continue;
}
pSyncable->setMasterBpm(bpm);
pSyncable->updateMasterBpm(bpm);
}
}

void BaseSyncableListener::setMasterInstantaneousBpm(Syncable* pSource, double bpm) {
if (pSource != m_pInternalClock) {
m_pInternalClock->setInstantaneousBpm(bpm);
m_pInternalClock->updateInstantaneousBpm(bpm);
}
foreach (Syncable* pSyncable, m_syncables) {
if (pSyncable == pSource ||
!pSyncable->isSynchronized()) {
continue;
}
pSyncable->setInstantaneousBpm(bpm);
pSyncable->updateInstantaneousBpm(bpm);
}
}

void BaseSyncableListener::setMasterBeatDistance(Syncable* pSource, double beatDistance) {
if (pSource != m_pInternalClock) {
m_pInternalClock->setMasterBeatDistance(beatDistance);
m_pInternalClock->updateMasterBeatDistance(beatDistance);
}
foreach (Syncable* pSyncable, m_syncables) {
if (pSyncable == pSource ||
!pSyncable->isSynchronized()) {
continue;
}
pSyncable->setMasterBeatDistance(beatDistance);
pSyncable->updateMasterBeatDistance(beatDistance);
}
}

void BaseSyncableListener::setMasterParams(Syncable* pSource) {
void BaseSyncableListener::reinitMasterParams(Syncable* pSource) {
const double beatDistance = pSource->getBeatDistance();
const double baseBpm = pSource->getBaseBpm();
const double bpm = pSource->getBpm() > 0 ? pSource->getBpm() : pSource->getBaseBpm();
// qDebug() << "BaseSyncableListener::setMasterParams, source is"
// << pSource->getGroup() << beatDistance << baseBpm << bpm;
if (pSource != m_pInternalClock) {
m_pInternalClock->setMasterParams(beatDistance, baseBpm, bpm);
m_pInternalClock->reinitMasterParams(beatDistance, baseBpm, bpm);
}
foreach (Syncable* pSyncable, m_syncables) {
if (pSyncable == pSource || !pSyncable->isSynchronized()) {
continue;
}
pSyncable->setMasterParams(beatDistance, baseBpm, bpm);
pSyncable->reinitMasterParams(beatDistance, baseBpm, bpm);
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/engine/sync/basesyncablelistener.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ class BaseSyncableListener : public SyncableListener {
// pSource.
void setMasterBeatDistance(Syncable* pSource, double beatDistance);

// Update the master parameters using the provided syncable as the source.
void setMasterParams(Syncable* pSource);
// Initialize the master parameters using the provided syncable as the source.
// This should only be called for "major" updates, like a new track or change in
// master. Should not be called on every buffer callback.
void reinitMasterParams(Syncable* pSource);

// Check if there is only one playing syncable deck, and return it if so.
Syncable* getUniquePlayingSyncable();
Expand Down
4 changes: 2 additions & 2 deletions src/engine/sync/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ class Clock {
virtual ~Clock() = default;

virtual double getBeatDistance() const = 0;
virtual void setMasterBeatDistance(double beatDistance) = 0;
virtual void updateMasterBeatDistance(double beatDistance) = 0;

virtual double getBpm() const = 0;
virtual void setMasterBpm(double bpm) = 0;
virtual void updateMasterBpm(double bpm) = 0;
};
21 changes: 14 additions & 7 deletions src/engine/sync/enginesync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,13 @@ void EngineSync::requestSyncMode(Syncable* pSyncable, SyncMode mode) {

// Now that all of the decks have their assignments, reinit master params if needed.
if (pParamsSyncable) {
setMasterParams(pParamsSyncable);
pSyncable->setInstantaneousBpm(pParamsSyncable->getBpm());
if (kLogger.traceEnabled()) {
kLogger.trace()
<< "EngineSync::requestSyncMode setting master params from "
<< pParamsSyncable->getGroup();
}
reinitMasterParams(pParamsSyncable);
pSyncable->updateInstantaneousBpm(pParamsSyncable->getBpm());
if (pParamsSyncable != pSyncable) {
pSyncable->requestSync();
}
Expand Down Expand Up @@ -335,7 +340,7 @@ void EngineSync::notifyPlaying(Syncable* pSyncable, bool playing) {
// If there is only one remaining syncable, it should reinit the
// master parameters.
unique_syncable->notifyOnlyPlayingSyncable();
setMasterParams(unique_syncable);
reinitMasterParams(unique_syncable);
}

pSyncable->requestSync();
Expand Down Expand Up @@ -380,11 +385,13 @@ void EngineSync::requestBpmUpdate(Syncable* pSyncable, double bpm) {
}

if (mbaseBpm != 0.0) {
// resync to current master
pSyncable->setMasterParams(beatDistance, mbaseBpm, mbpm);
// update from current master
pSyncable->updateMasterBeatDistance(beatDistance);
pSyncable->updateMasterBpm(mbpm);
} else {
// There is no other master, adopt this bpm as master
pSyncable->setMasterParams(0.0, 0.0, bpm);
// There is no master, adopt this bpm as master values
pSyncable->updateMasterBeatDistance(0.0);
pSyncable->updateMasterBpm(bpm);
}
}

Expand Down
16 changes: 8 additions & 8 deletions src/engine/sync/internalclock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ double InternalClock::getBeatDistance() const {
return m_dClockPosition / m_dBeatLength;
}

void InternalClock::setMasterBeatDistance(double beatDistance) {
void InternalClock::updateMasterBeatDistance(double beatDistance) {
if (kLogger.traceEnabled()) {
kLogger.trace() << "InternalClock::setMasterBeatDistance" << beatDistance;
}
Expand All @@ -117,7 +117,7 @@ double InternalClock::getBpm() const {
return m_pClockBpm->get();
}

void InternalClock::setMasterBpm(double bpm) {
void InternalClock::updateMasterBpm(double bpm) {
if (kLogger.traceEnabled()) {
kLogger.trace() << "InternalClock::setBpm" << bpm;
}
Expand All @@ -128,24 +128,24 @@ void InternalClock::setMasterBpm(double bpm) {
updateBeatLength(m_iOldSampleRate, bpm);
}

void InternalClock::setInstantaneousBpm(double bpm) {
void InternalClock::updateInstantaneousBpm(double bpm) {
if (kLogger.traceEnabled()) {
kLogger.trace() << "InternalClock::setInstantaneousBpm" << bpm;
}
// Do nothing.
Q_UNUSED(bpm);
}

void InternalClock::setMasterParams(double beatDistance, double baseBpm, double bpm) {
void InternalClock::reinitMasterParams(double beatDistance, double baseBpm, double bpm) {
if (kLogger.traceEnabled()) {
kLogger.trace() << "InternalClock::setMasterParams" << beatDistance << baseBpm << bpm;
}
if (bpm == 0) {
return;
}
m_dBaseBpm = baseBpm;
setMasterBpm(bpm);
setMasterBeatDistance(beatDistance);
updateMasterBpm(bpm);
updateMasterBeatDistance(beatDistance);
}

void InternalClock::slotBaseBpmChanged(double baseBpm) {
Expand All @@ -161,7 +161,7 @@ void InternalClock::slotBeatDistanceChanged(double beatDistance) {
if (beatDistance < 0.0 || beatDistance > 1.0) {
return;
}
setMasterBeatDistance(beatDistance);
updateMasterBeatDistance(beatDistance);
}

void InternalClock::updateBeatLength(int sampleRate, double bpm) {
Expand Down Expand Up @@ -197,7 +197,7 @@ void InternalClock::updateBeatLength(int sampleRate, double bpm) {
m_iOldSampleRate = sampleRate;

// Restore the old beat distance.
setMasterBeatDistance(oldBeatDistance);
updateMasterBeatDistance(oldBeatDistance);
}

void InternalClock::onCallbackStart(int sampleRate, int bufferSize) {
Expand Down
8 changes: 4 additions & 4 deletions src/engine/sync/internalclock.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ class InternalClock : public QObject, public Clock, public Syncable {
}

double getBeatDistance() const override;
void setMasterBeatDistance(double beatDistance) override;
void updateMasterBeatDistance(double beatDistance) override;

double getBaseBpm() const override;
void setMasterBpm(double bpm) override;
void updateMasterBpm(double bpm) override;
double getBpm() const override;
void setInstantaneousBpm(double bpm) override;
void setMasterParams(double beatDistance, double baseBpm, double bpm) override;
void updateInstantaneousBpm(double bpm) override;
void reinitMasterParams(double beatDistance, double baseBpm, double bpm) override;

void onCallbackStart(int sampleRate, int bufferSize);
void onCallbackEnd(int sampleRate, int bufferSize);
Expand Down
16 changes: 9 additions & 7 deletions src/engine/sync/syncable.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,23 @@ class Syncable {
// current Sync Master.
// Must never result in a call to
// SyncableListener::notifyBeatDistanceChanged or signal loops could occur.
virtual void setMasterBeatDistance(double beatDistance) = 0;
virtual void updateMasterBeatDistance(double beatDistance) = 0;

// Update the current playback speed (not including scratch values)
// of the current master.
// Must never result in a call to SyncableListener::notifyBpmChanged or
// signal loops could occur.
virtual void setMasterBpm(double bpm) = 0;
virtual void updateMasterBpm(double bpm) = 0;

// Combines the above three calls into one, since they are often set
// simultaneously. Avoids redundant recalculation that would occur by
// using the three calls separately.
virtual void setMasterParams(double beatDistance, double baseBpm, double bpm) = 0;
// Perform a reset of Master parameters. This function also triggers recalculation
// of half-double multiplier.
virtual void reinitMasterParams(double beatDistance, double baseBpm, double bpm) = 0;

// Update the playback speed of the master, including scratch values.
// Must never result in a call to
// SyncableListener::notifyInstantaneousBpmChanged or signal loops could
// occur.
virtual void setInstantaneousBpm(double bpm) = 0;
virtual void updateInstantaneousBpm(double bpm) = 0;
};

/// SyncableListener is an interface class used by EngineSync to receive
Expand Down
27 changes: 15 additions & 12 deletions src/engine/sync/synccontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ namespace {
const mixxx::Logger kLogger("SyncControl");
} // namespace

SyncControl::SyncControl(const QString& group, UserSettingsPointer pConfig,
EngineChannel* pChannel, SyncableListener* pEngineSync)
SyncControl::SyncControl(const QString& group,
UserSettingsPointer pConfig,
EngineChannel* pChannel,
SyncableListener* pEngineSync)
: EngineControl(group, pConfig),
m_sGroup(group),
m_pChannel(pChannel),
Expand Down Expand Up @@ -179,7 +181,7 @@ void SyncControl::requestSync() {
if (isPlaying() && m_pQuantize->toBool()) {
// only sync phase if the deck is playing and if quantize is enabled.
// this way the it is up to the user to decide if a seek is desired or not.
// This is helpful if the beatgrid of the track doe not fit at the current
// This is helpful if the beatgrid of the track does not fit at the current
// playposition
m_pChannel->getEngineBuffer()->requestSyncPhase();
}
Expand All @@ -193,7 +195,7 @@ double SyncControl::adjustSyncBeatDistance(double beatDistance) const {
// Similar to adjusting the target beat distance, when we report our beat
// distance we need to adjust it by the master bpm adjustment factor. If
// we've been doubling the master bpm, we need to divide it in half. If
// we'be been halving the master bpm, we need to double it. Both operations
// we've been halving the master bpm, we need to double it. Both operations
// also need to account for if the longer beat is past its halfway point.
//
// This is the inverse of the updateTargetBeatDistance function below.
Expand All @@ -220,7 +222,7 @@ double SyncControl::getBaseBpm() const {
return m_pLocalBpm->get() / m_masterBpmAdjustFactor;
}

void SyncControl::setMasterBeatDistance(double beatDistance) {
void SyncControl::updateMasterBeatDistance(double beatDistance) {
if (kLogger.traceEnabled()) {
kLogger.trace() << getGroup() << "SyncControl::setMasterBeatDistance"
<< beatDistance;
Expand All @@ -233,7 +235,7 @@ void SyncControl::setMasterBeatDistance(double beatDistance) {
updateTargetBeatDistance();
}

void SyncControl::setMasterBpm(double bpm) {
void SyncControl::updateMasterBpm(double bpm) {
if (kLogger.traceEnabled()) {
kLogger.trace() << getGroup() << "SyncControl::setMasterBpm" << bpm;
}
Expand All @@ -254,7 +256,7 @@ void SyncControl::setMasterBpm(double bpm) {
}
}

void SyncControl::setMasterParams(
void SyncControl::reinitMasterParams(
double beatDistance, double baseBpm, double bpm) {
double masterBpmAdjustFactor = determineBpmMultiplier(fileBpm(), baseBpm);
if (isMaster(getSyncMode())) {
Expand All @@ -265,8 +267,8 @@ void SyncControl::setMasterParams(
// in Follower mode we keep the factor when reporting our BPM
m_masterBpmAdjustFactor = masterBpmAdjustFactor;
}
setMasterBpm(bpm);
setMasterBeatDistance(beatDistance);
updateMasterBpm(bpm);
updateMasterBeatDistance(beatDistance);
}

double SyncControl::determineBpmMultiplier(double myBpm, double targetBpm) const {
Expand Down Expand Up @@ -320,14 +322,15 @@ void SyncControl::updateTargetBeatDistance() {

double SyncControl::getBpm() const {
if (kLogger.traceEnabled()) {
kLogger.trace() << getGroup() << "SyncControl::getBpm()";
kLogger.trace() << getGroup() << "SyncControl::getBpm()"
<< m_pBpm->get() / m_masterBpmAdjustFactor;
}
return m_pBpm->get() / m_masterBpmAdjustFactor;
}

void SyncControl::setInstantaneousBpm(double bpm) {
void SyncControl::updateInstantaneousBpm(double bpm) {
// Adjust the incoming bpm by the multiplier.
m_pBpmControl->setInstantaneousBpm(bpm * m_masterBpmAdjustFactor);
m_pBpmControl->updateInstantaneousBpm(bpm * m_masterBpmAdjustFactor);
}

// called from an engine worker thread
Expand Down
Loading

0 comments on commit 8e46045

Please sign in to comment.