Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/engine/sync/enginesync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,19 @@ EngineChannel* EngineSync::pickNonSyncSyncTarget(EngineChannel* pDontPick) const
// had a BPM.
return pFirstNonplayingDeck;
}

bool EngineSync::otherSyncedPlaying(const QString& group) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to validate the test, insert return false; here.

bool othersInSync = false;
for (Syncable* theSyncable : m_syncables) {
if (theSyncable->getGroup() == group) {
if (theSyncable->getSyncMode() == SYNC_NONE) {
return false;
}
continue;
}
if (theSyncable->isPlaying() && (theSyncable->getSyncMode() != SYNC_NONE)) {
othersInSync = true;
}
}
return othersInSync;
}
4 changes: 4 additions & 0 deletions src/engine/sync/enginesync.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ class EngineSync : public BaseSyncableListener {
// Used to pick a sync target for non-master-sync mode.
EngineChannel* pickNonSyncSyncTarget(EngineChannel* pDontPick) const;

// Used to test whether changing the rate of a Syncable would change the rate
// of other Syncables that are playing
bool otherSyncedPlaying(const QString& group);

private:
// Activate a specific syncable as master.
void activateMaster(Syncable* pSyncable);
Expand Down
25 changes: 11 additions & 14 deletions src/mixer/basetrackplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "util/sandbox.h"
#include "effects/effectsmanager.h"
#include "vinylcontrol/defs_vinylcontrol.h"
#include "engine/sync/enginesync.h"

BaseTrackPlayer::BaseTrackPlayer(QObject* pParent, const QString& group)
: BasePlayer(pParent, group) {
Expand All @@ -32,6 +33,7 @@ BaseTrackPlayerImpl::BaseTrackPlayerImpl(QObject* pParent,
bool defaultHeadphones)
: BaseTrackPlayer(pParent, group),
m_pConfig(pConfig),
m_pEngineMaster(pMixingEngine),
m_pLoadedTrack(),
m_pLowFilter(NULL),
m_pMidFilter(NULL),
Expand Down Expand Up @@ -289,24 +291,19 @@ void BaseTrackPlayerImpl::slotTrackLoaded(TrackPointer pNewTrack,
int reset = m_pConfig->getValueString(ConfigKey(
"[Controls]", "SpeedAutoReset"),
QString("%1").arg(RESET_PITCH)).toInt();
switch (reset) {
case RESET_PITCH_AND_SPEED:
// Note: speed may affect pitch
if (m_pRateSlider != NULL) {
m_pRateSlider->set(0.0);
if (reset == RESET_SPEED || reset == RESET_PITCH_AND_SPEED) {
// Avoid reseting speed if master sync is enabled and other decks with sync enabled
// are playing, as this would change the speed of already playing decks.
if (! m_pEngineMaster->getEngineSync()->otherSyncedPlaying(getGroup())) {
if (m_pRateSlider != NULL) {
m_pRateSlider->set(0.0);
}
}
M_FALLTHROUGH_INTENDED;
case RESET_PITCH:
}
if (reset == RESET_PITCH || reset == RESET_PITCH_AND_SPEED) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if

Copy link
Copy Markdown
Contributor Author

@Be-ing Be-ing Sep 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this should remain a separate if statement. else if would require a third branch with duplicate code for RESET_PITCH_AND_SPEED

if (m_pPitchAdjust != NULL) {
m_pPitchAdjust->set(0.0);
}
break;
case RESET_SPEED:
// Note: speed may affect pitch
if (m_pRateSlider != NULL) {
m_pRateSlider->set(0.0);
}
break;
}
emit(newTrackLoaded(m_pLoadedTrack));
} else {
Expand Down
1 change: 1 addition & 0 deletions src/mixer/basetrackplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class BaseTrackPlayerImpl : public BaseTrackPlayer {
void setReplayGain(double value);

UserSettingsPointer m_pConfig;
EngineMaster* m_pEngineMaster;
TrackPointer m_pLoadedTrack;

// Waveform display related controls
Expand Down
116 changes: 116 additions & 0 deletions src/test/enginesynctest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "test/mockedenginebackendtest.h"
#include "test/mixxxtest.h"
#include "track/beatfactory.h"
#include "mixer/basetrackplayer.h"


class EngineSyncTest : public MockedEngineBackendTest {
Expand Down Expand Up @@ -792,6 +793,121 @@ TEST_F(EngineSyncTest, LoadTrackInitializesMaster) {
ControlObject::getControl(ConfigKey(m_sGroup2, "bpm"))->get());
}

TEST_F(EngineSyncTest, LoadTrackResetTempoOption) {
// Make sure playing decks with master sync enabled do not change tempo when
// the "Reset Speed/Tempo" preference is set and a track is loaded to another
// deck with master sync enabled.
m_pConfig->set(ConfigKey("[Controls]", "SpeedAutoReset"),
ConfigValue(BaseTrackPlayer::RESET_SPEED));

// Enable sync on two stopped decks
m_pMixerDeck1->setupEqControls();
QScopedPointer<ControlProxy> pButtonSyncEnabled1(getControlProxy(
ConfigKey(m_sGroup1, "sync_enabled")));
pButtonSyncEnabled1->slotSet(1.0);

m_pMixerDeck2->setupEqControls();
QScopedPointer<ControlProxy> pButtonSyncEnabled2(getControlProxy(
ConfigKey(m_sGroup2, "sync_enabled")));
pButtonSyncEnabled2->slotSet(1.0);

// If sync is on and we load a track, that should initialize master.
TrackPointer track1 = m_pChannel1->getEngineBuffer()->loadFakeTrack(140.0);
m_pMixerDeck1->slotLoadTrack(track1, true);
m_pMixerDeck1->slotTrackLoaded(track1, m_pTrack1);

EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sInternalClockGroup, "bpm"))->get());
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sGroup1, "bpm"))->get());

// If sync is on two decks and we load a track while one is playing,
// that should not change the playing deck.
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0);

TrackPointer track2 = m_pChannel2->getEngineBuffer()->loadFakeTrack(128.0);
m_pMixerDeck2->slotLoadTrack(track2, false);
m_pMixerDeck2->slotTrackLoaded(track2, m_pTrack2);

EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sInternalClockGroup, "bpm"))->get());
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sGroup1, "bpm"))->get());
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sGroup2, "bpm"))->get());

// Repeat with RESET_PITCH_AND_SPEED
m_pConfig->set(ConfigKey("[Controls]", "SpeedAutoReset"),
ConfigValue(BaseTrackPlayer::RESET_PITCH_AND_SPEED));
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(0.0);
ControlObject::getControl(ConfigKey(m_sGroup1, "rate"))->set(getRateSliderValue(1.0));
m_pMixerDeck1->slotLoadTrack(track1, true);
m_pMixerDeck1->slotTrackLoaded(track1, m_pTrack1);
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0);
m_pMixerDeck2->slotLoadTrack(track2, false);
m_pMixerDeck2->slotTrackLoaded(track2, m_pTrack2);
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sInternalClockGroup, "bpm"))->get());
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sGroup1, "bpm"))->get());
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sGroup2, "bpm"))->get());

// Repeat with RESET_NONE
m_pConfig->set(ConfigKey("[Controls]", "SpeedAutoReset"),
ConfigValue(BaseTrackPlayer::RESET_NONE));
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(0.0);
ControlObject::getControl(ConfigKey(m_sGroup1, "rate"))->set(getRateSliderValue(1.0));
ControlObject::getControl(ConfigKey(m_sGroup2, "rate"))->set(getRateSliderValue(1.0));
m_pMixerDeck1->slotLoadTrack(track1, true);
m_pMixerDeck1->slotTrackLoaded(track1, m_pTrack1);
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0);
m_pMixerDeck2->slotLoadTrack(track2, false);
m_pMixerDeck2->slotTrackLoaded(track2, m_pTrack2);
EXPECT_FLOAT_EQ(128.0,
ControlObject::getControl(ConfigKey(m_sInternalClockGroup, "bpm"))->get());
EXPECT_FLOAT_EQ(128.0,
ControlObject::getControl(ConfigKey(m_sGroup1, "bpm"))->get());
EXPECT_FLOAT_EQ(128.0,
ControlObject::getControl(ConfigKey(m_sGroup2, "bpm"))->get());

// Load two tracks with sync off and RESET_SPEED
m_pConfig->set(ConfigKey("[Controls]", "SpeedAutoReset"),
ConfigValue(BaseTrackPlayer::RESET_SPEED));
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(0.0);
ControlObject::getControl(ConfigKey(m_sGroup1, "rate"))->set(getRateSliderValue(1.5));
ControlObject::getControl(ConfigKey(m_sGroup2, "rate"))->set(getRateSliderValue(1.5));
pButtonSyncEnabled1->slotSet(0.0);
pButtonSyncEnabled2->slotSet(0.0);
m_pMixerDeck1->slotLoadTrack(track1, true);
m_pMixerDeck1->slotTrackLoaded(track1, m_pTrack1);
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0);
m_pMixerDeck2->slotLoadTrack(track2, false);
m_pMixerDeck2->slotTrackLoaded(track2, m_pTrack2);
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sGroup1, "bpm"))->get());
EXPECT_FLOAT_EQ(128.0,
ControlObject::getControl(ConfigKey(m_sGroup2, "bpm"))->get());

// Load two tracks with sync off and RESET_PITCH_AND_SPEED
m_pConfig->set(ConfigKey("[Controls]", "SpeedAutoReset"),
ConfigValue(BaseTrackPlayer::RESET_PITCH_AND_SPEED));
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(0.0);
ControlObject::getControl(ConfigKey(m_sGroup1, "rate"))->set(getRateSliderValue(1.5));
ControlObject::getControl(ConfigKey(m_sGroup2, "rate"))->set(getRateSliderValue(1.5));
pButtonSyncEnabled1->slotSet(0.0);
pButtonSyncEnabled2->slotSet(0.0);
m_pMixerDeck1->slotLoadTrack(track1, true);
m_pMixerDeck1->slotTrackLoaded(track1, m_pTrack1);
ControlObject::getControl(ConfigKey(m_sGroup1, "play"))->set(1.0);
m_pMixerDeck2->slotLoadTrack(track2, false);
m_pMixerDeck2->slotTrackLoaded(track2, m_pTrack2);
EXPECT_FLOAT_EQ(140.0,
ControlObject::getControl(ConfigKey(m_sGroup1, "bpm"))->get());
EXPECT_FLOAT_EQ(128.0,
ControlObject::getControl(ConfigKey(m_sGroup2, "bpm"))->get());
}

TEST_F(EngineSyncTest, EnableOneDeckSliderUpdates) {
// If we enable a deck to be master, the internal slider should immediately update.
QScopedPointer<ControlProxy> pButtonSyncEnabled1(getControlProxy(
Expand Down
28 changes: 15 additions & 13 deletions src/test/mockedenginebackendtest.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "engine/enginemaster.h"
#include "engine/ratecontrol.h"
#include "engine/sync/enginesync.h"
#include "mixer/deck.h"
#include "mixer/previewdeck.h"
#include "mixer/sampler.h"
#include "test/mixxxtest.h"
Expand Down Expand Up @@ -67,18 +68,16 @@ class MockedEngineBackendTest : public MixxxTest {
m_pEngineMaster = new EngineMaster(m_pConfig, "[Master]",
m_pEffectsManager, false, false);

m_pChannel1 = new EngineDeck(
m_pEngineMaster->registerChannelGroup(m_sGroup1),
m_pConfig, m_pEngineMaster, m_pEffectsManager,
EngineChannel::CENTER);
m_pChannel2 = new EngineDeck(
m_pEngineMaster->registerChannelGroup(m_sGroup2),
m_pConfig, m_pEngineMaster, m_pEffectsManager,
EngineChannel::CENTER);
m_pChannel3 = new EngineDeck(
m_pEngineMaster->registerChannelGroup(m_sGroup3),
m_pConfig, m_pEngineMaster, m_pEffectsManager,
EngineChannel::CENTER);
m_pMixerDeck1 = new Deck(NULL, m_pConfig, m_pEngineMaster, m_pEffectsManager,
EngineChannel::CENTER, m_sGroup1);
m_pMixerDeck2 = new Deck(NULL, m_pConfig, m_pEngineMaster, m_pEffectsManager,
EngineChannel::CENTER, m_sGroup2);
m_pMixerDeck3 = new Deck(NULL, m_pConfig, m_pEngineMaster, m_pEffectsManager,
EngineChannel::CENTER, m_sGroup3);
m_pChannel1 = m_pMixerDeck1->getEngineDeck();
m_pChannel2 = m_pMixerDeck2->getEngineDeck();
m_pChannel3 = m_pMixerDeck3->getEngineDeck();

m_pPreview1 = new PreviewDeck(NULL, m_pConfig,
m_pEngineMaster, m_pEffectsManager,
EngineChannel::CENTER, m_sPreviewGroup);
Expand Down Expand Up @@ -114,7 +113,6 @@ class MockedEngineBackendTest : public MixxxTest {
}

void addDeck(EngineDeck* pDeck) {
m_pEngineMaster->addChannel(pDeck);
ControlObject::getControl(ConfigKey(pDeck->getGroup(), "master"))
->set(1.0);
ControlObject::getControl(ConfigKey(pDeck->getGroup(), "rate_dir"))
Expand All @@ -125,6 +123,9 @@ class MockedEngineBackendTest : public MixxxTest {
}

virtual void TearDown() {
delete m_pMixerDeck1;
delete m_pMixerDeck2;
delete m_pMixerDeck3;
m_pChannel1 = NULL;
m_pChannel2 = NULL;
m_pChannel3 = NULL;
Expand Down Expand Up @@ -155,6 +156,7 @@ class MockedEngineBackendTest : public MixxxTest {
EffectsManager* m_pEffectsManager;
EngineSync* m_pEngineSync;
EngineMaster* m_pEngineMaster;
Deck *m_pMixerDeck1, *m_pMixerDeck2, *m_pMixerDeck3;
EngineDeck *m_pChannel1, *m_pChannel2, *m_pChannel3;
MockScaler *m_pMockScaleVinyl1, *m_pMockScaleVinyl2, *m_pMockScaleVinyl3;
MockScaler *m_pMockScaleKeylock1, *m_pMockScaleKeylock2, *m_pMockScaleKeylock3;
Expand Down