Skip to content

Commit

Permalink
Merge pull request #3899 from ywwg/stopped-explicit
Browse files Browse the repository at this point in the history
Fix issues with half/double and Sync Lock
  • Loading branch information
daschuer authored Jun 15, 2021
2 parents 747dd04 + 3e331c9 commit d8a9fd3
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 51 deletions.
2 changes: 1 addition & 1 deletion res/skins/LateNight/decks/deck.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<WidgetGroup>
<Layout>vertical</Layout>
<MaximumSize>,208</MaximumSize>
<MaximumSize>,230</MaximumSize>
<Children>

<Template src="skin:/decks/deck_singletons.xml">
Expand Down
87 changes: 87 additions & 0 deletions res/skins/LateNight/palemoon/buttons/btn__leader_deck.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 10 additions & 3 deletions res/skins/LateNight/style_classic.qss
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ WPushButton#PlayIndicator,
WPushButton#CueDeck,
#PlayCueMini WPushButton,
WPushButton#LoopActivate,
#RateControls WPushButton,
WPushButton#RateControls WPushButton,
WPushButton#SyncDeck,
WPushButton#SyncLeader,
WPushButton#SyncSampler,
Expand Down Expand Up @@ -1378,10 +1378,17 @@ WPushButton#SkinSettingsToggle[displayValue="0"] {
background-color: #262626;
}

/* Orange for 'partially active' status */
#SyncLeader[value="1"] {
background-color: #db7700;
}

/* Red for 'active' status */
#BeatgridControls WPushButton[value="1"],
#RateControls WPushButton[value="1"],
#SyncDeck[value="1"], #SyncSampler[displayValue="1"],
#SyncDeck[value="1"],
#SyncLeader[value="2"],
#SyncSampler[displayValue="1"],
WPushButton#PlayDeck[displayValue="1"],
WPushButton#PlayDeckMini[displayValue="1"],
WPushButton#PlaySampler[displayValue="1"],
Expand Down Expand Up @@ -1662,7 +1669,7 @@ WPushButton#SamplerExpand[displayValue="0"],
}

#SyncLeader {
background: url(skin:/classic/buttons/btn__leader_deck.svg) no-repeat center center;
image: url(skin:/classic/buttons/btn__leader_deck.svg) no-repeat center center;
}

#SyncSampler {
Expand Down
12 changes: 10 additions & 2 deletions res/skins/LateNight/style_palemoon.qss
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,9 @@ WPushButton#CueDeck,
#PlayCueMini WPushButton,
WPushButton#LoopActivate,
WPushButton#RateControls WPushButton,
WPushButton#SyncDeck, WPushButton#SyncSampler,
WPushButton#SyncDeck,
WPushButton#SyncLeader,
WPushButton#SyncSampler,
#MixerContainer WPushButton,
#FxUnitContainer WPushButton,
#Sampler WPushButton,
Expand Down Expand Up @@ -1631,6 +1633,8 @@ WPushButton#Reverse[pressed="true"],
#LoopActivate[value="1"],
#Reloop[value="1"],
#SyncSampler[displayValue="1"],
#SyncDeck[value="1"],
#SyncLeader[value="2"],
#MicTalk[value="1"], #AuxPlay[value="1"],
#MicDucking[value="1"],
#MicDucking[value="2"],
Expand All @@ -1649,7 +1653,7 @@ QPushButton#pushButtonAnalyze:checked {
}
/* dim orange for momentary controls */
#KeyControls WPushButton[pressed="true"],
#SyncDeck[value="1"],
#SyncLeader[value="1"],
WPushButton#LoopIn[pressed="true"],
WPushButton#LoopOut[pressed="true"],
#BeatjumpControls WPushButton[value="1"],
Expand Down Expand Up @@ -2103,6 +2107,10 @@ WPushButton#PlayDeck[value="0"] {
image: url(skin:/palemoon/buttons/btn__sync_deck_active.svg) no-repeat center center;
}

#SyncLeader {
image: url(skin:/palemoon/buttons/btn__leader_deck.svg) no-repeat center center;
}

#SyncSampler {
image: url(skin:/palemoon/buttons/btn__sync_sampler.svg) no-repeat center center;
}
Expand Down
6 changes: 4 additions & 2 deletions src/engine/controls/bpmcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,9 @@ double BpmControl::getBeatDistance(double dThisPosition) const {
// we don't adjust the reported distance the track will try to adjust
// sync against itself.
if (kLogger.traceEnabled()) {
kLogger.trace() << getGroup() << "BpmControl::getBeatDistance" << dThisPosition;
kLogger.trace() << getGroup()
<< "BpmControl::getBeatDistance. dThisPosition:"
<< dThisPosition;
}
double dPrevBeat = m_pPrevBeat->get();
double dNextBeat = m_pNextBeat->get();
Expand All @@ -560,7 +562,7 @@ double BpmControl::getBeatDistance(double dThisPosition) const {
}

if (kLogger.traceEnabled()) {
kLogger.trace() << getGroup() << "BpmControl::getBeatDistance"
kLogger.trace() << getGroup() << "BpmControl::getBeatDistance. dBeatPercentage:"
<< dBeatPercentage << "- offset "
<< m_dUserOffset.getValue() << " = "
<< (dBeatPercentage - m_dUserOffset.getValue());
Expand Down
3 changes: 3 additions & 0 deletions src/engine/enginemaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ void EngineMaster::processChannels(int iBufferSize) {

// Do internal master sync post-processing before the other
// channels.
// Note, because we call this on the internal clock first,
// it will have an up-to-date beatDistance, whereas the other
// Syncables will not.
m_pMasterSync->onCallbackEnd(m_iSampleRate, m_iBufferSize);

// After all the engines have been processed, trigger post-processing
Expand Down
80 changes: 63 additions & 17 deletions src/engine/sync/enginesync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ void EngineSync::requestSyncMode(Syncable* pSyncable, SyncMode mode) {
default:;
}

Syncable* pOnlyPlayer = getUniquePlayingSyncedDeck();
if (pOnlyPlayer) {
// This resets the user offset, so that if this deck gets used as the params syncable
// it will have that offset removed.
pOnlyPlayer->notifyUniquePlaying();
}

// Second, figure out what Syncable should be used to initialize the master
// parameters, if any. Usually this is the new master. (Note, that pointer might be null!)
Syncable* pParamsSyncable = m_pMasterSyncable;
Expand All @@ -96,9 +103,6 @@ void EngineSync::requestSyncMode(Syncable* pSyncable, SyncMode mode) {
}
}

if (noPlayingFollowers() && m_pMasterSyncable) {
m_pMasterSyncable->notifyOnlyPlayingSyncable();
}
}

void EngineSync::activateFollower(Syncable* pSyncable) {
Expand Down Expand Up @@ -350,11 +354,15 @@ void EngineSync::notifyPlayingAudible(Syncable* pSyncable, bool playingAudible)

if (newMaster != nullptr && newMaster != m_pMasterSyncable) {
activateMaster(newMaster, SYNC_MASTER_SOFT);
}

if (noPlayingFollowers() && m_pMasterSyncable) {
m_pMasterSyncable->notifyOnlyPlayingSyncable();
setMasterParams(m_pMasterSyncable);
setMasterParams(newMaster);
} else {
Syncable* pOnlyPlayer = getUniquePlayingSyncedDeck();
if (pOnlyPlayer) {
// Even if we didn't change master, if there is only one player (us), then we should
// reinit the beat distance.
pOnlyPlayer->notifyUniquePlaying();
setMasterBeatDistance(pOnlyPlayer, pOnlyPlayer->getBeatDistance());
}
}

pSyncable->requestSync();
Expand Down Expand Up @@ -584,6 +592,11 @@ void EngineSync::setMasterInstantaneousBpm(Syncable* pSource, double bpm) {
}

void EngineSync::setMasterBeatDistance(Syncable* pSource, double beatDistance) {
if (kLogger.traceEnabled()) {
kLogger.trace() << "EngineSync::setMasterBeatDistance"
<< (pSource ? pSource->getGroup() : "null")
<< beatDistance;
}
if (pSource != m_pInternalClock) {
m_pInternalClock->setMasterBeatDistance(beatDistance);
}
Expand All @@ -597,35 +610,68 @@ void EngineSync::setMasterBeatDistance(Syncable* pSource, double beatDistance) {
}

void EngineSync::setMasterParams(Syncable* pSource) {
const double beatDistance = pSource->getBeatDistance();
// Important note! Because of the way sync works, the new master is usually not the same
// as the Syncable setting the master parameters (here, pSource). Notify the proper Syncable
// so it can prepare itself. (This is a hack to undo half/double math so that we initialize
// based on un-multiplied bpm values).
pSource->notifyMasterParamSource();

double beatDistance = pSource->getBeatDistance();
if (!pSource->isPlaying()) {
// If the params source is not playing, but other syncables are, then we are a stopped
// explicit Master and we should not initialize the beat distance. Take it from the
// internal clock instead, because that will be up to date with the playing deck(s).
bool playingSyncables = false;
for (Syncable* pSyncable : qAsConst(m_syncables)) {
if (pSyncable == pSource) {
continue;
}
if (!pSyncable->isSynchronized()) {
continue;
}
if (pSyncable->isPlaying()) {
playingSyncables = true;
break;
}
}
if (playingSyncables) {
beatDistance = m_pInternalClock->getBeatDistance();
}
}
const double baseBpm = pSource->getBaseBpm();
double bpm = pSource->getBpm();
if (bpm <= 0) {
bpm = baseBpm;
}
// qDebug() << "BaseSyncableListener::setMasterParams, source is"
// << pSource->getGroup() << beatDistance << baseBpm << bpm;
if (kLogger.traceEnabled()) {
kLogger.trace() << "BaseSyncableListener::setMasterParams, source is"
<< pSource->getGroup() << beatDistance << baseBpm << bpm;
}
if (pSource != m_pInternalClock) {
m_pInternalClock->setMasterParams(beatDistance, baseBpm, bpm);
}
foreach (Syncable* pSyncable, m_syncables) {
if (pSyncable == pSource || !pSyncable->isSynchronized()) {
if (!pSyncable->isSynchronized()) {
continue;
}
pSyncable->setMasterParams(beatDistance, baseBpm, bpm);
}
}

bool EngineSync::noPlayingFollowers() const {
Syncable* EngineSync::getUniquePlayingSyncedDeck() const {
Syncable* onlyPlaying = nullptr;
for (Syncable* pSyncable : m_syncables) {
if (!pSyncable->isSynchronized()) {
continue;
}

if (pSyncable->isPlaying() && pSyncable->isAudible() &&
isFollower(pSyncable->getSyncMode())) {
return false;
if (pSyncable->isPlaying()) {
if (!onlyPlaying) {
onlyPlaying = pSyncable;
} else {
return nullptr;
}
}
}
return true;
return onlyPlaying;
}
5 changes: 3 additions & 2 deletions src/engine/sync/enginesync.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ class EngineSync : public SyncableListener {

void setMasterParams(Syncable* pSource);

/// Check if there are no playing followers left.
bool noPlayingFollowers() const;
/// Iff there is a single playing syncable in sync mode, return it.
/// This is used to initialize master params.
Syncable* getUniquePlayingSyncedDeck() const;

/// Only for testing. Do not use.
Syncable* getSyncableForGroup(const QString& group);
Expand Down
5 changes: 4 additions & 1 deletion src/engine/sync/internalclock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void InternalClock::setSyncMode(SyncMode mode) {
m_pSyncMasterEnabled->setAndConfirm(SyncModeToMasterLight(mode));
}

void InternalClock::notifyOnlyPlayingSyncable() {
void InternalClock::notifyUniquePlaying() {
// No action necessary.
}

Expand Down Expand Up @@ -140,6 +140,9 @@ void InternalClock::setInstantaneousBpm(double bpm) {
Q_UNUSED(bpm);
}

void InternalClock::notifyMasterParamSource() {
}

void InternalClock::setMasterParams(double beatDistance, double baseBpm, double bpm) {
if (kLogger.traceEnabled()) {
kLogger.trace() << "InternalClock::setMasterParams" << beatDistance << baseBpm << bpm;
Expand Down
3 changes: 2 additions & 1 deletion src/engine/sync/internalclock.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class InternalClock : public QObject, public Clock, public Syncable {
}

void setSyncMode(SyncMode mode) override;
void notifyOnlyPlayingSyncable() override;
void notifyUniquePlaying() override;
void requestSync() override;
SyncMode getSyncMode() const override {
return m_mode;
Expand All @@ -52,6 +52,7 @@ class InternalClock : public QObject, public Clock, public Syncable {

double getBaseBpm() const override;
void setMasterBpm(double bpm) override;
void notifyMasterParamSource() override;
double getBpm() const override;
void setInstantaneousBpm(double bpm) override;
void setMasterParams(double beatDistance, double baseBpm, double bpm) override;
Expand Down
Loading

0 comments on commit d8a9fd3

Please sign in to comment.