Skip to content

Commit

Permalink
AutoDJProcessor: Add option to reset the crossfader to neutral
Browse files Browse the repository at this point in the history
  • Loading branch information
cr7pt0gr4ph7 committed May 3, 2024
1 parent ebd51e1 commit ae70792
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 19 deletions.
86 changes: 67 additions & 19 deletions src/library/autodj/autodjprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
namespace {
const char* kTransitionPreferenceName = "Transition";
const char* kTransitionModePreferenceName = "TransitionMode";
const char* kResetFaderPreferenceName = "ResetFaderToNeutralOnIdle";
constexpr double kTransitionPreferenceDefault = 10.0;
constexpr double kKeepPosition = -1.0;

// A track needs to be longer than two callbacks to not stop AutoDJ
constexpr double kMinimumTrackDurationSec = 0.2;

constexpr double kCrossfaderLeftOnly = -1.0;
constexpr double kCrossfaderNeutral = 0.0;
constexpr double kCrossfaderRightOnly = 1.0;

constexpr bool sDebug = false;
} // anonymous namespace

Expand Down Expand Up @@ -209,6 +214,26 @@ void AutoDJProcessor::setCrossfader(double value) {
m_pCOCrossfader->set(value);
}

void AutoDJProcessor::setCrossfaderToIdle(double value) {
DEBUG_ASSERT(value == kCrossfaderLeftOnly || value == kCrossfaderRightOnly);

// Depending on the user's preferences, the idle position
// of the crossfader is either fully to the left/right,
// or in the middle.
const bool resetFaderToNeutralOnIdle = m_pConfig->getValue<bool>(
ConfigKey(kConfigKey, kResetFaderPreferenceName),
false);

if (resetFaderToNeutralOnIdle) {
// Move crossfader to neutral. Crossfader will be moved
// to the left/right just before starting a crossfade.
setCrossfader(kCrossfaderNeutral);
} else {
// Move crossfader fully to the left/right
setCrossfader(value);
}
}

AutoDJProcessor::AutoDJError AutoDJProcessor::shufflePlaylist(
const QModelIndexList& selectedIndices) {
QModelIndex exclude;
Expand Down Expand Up @@ -543,8 +568,11 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) {
// playerPositionChanged for deck1 after the track is loaded.
m_eState = ADJ_ENABLE_P1LOADED;

// Move crossfader to the left.
setCrossfader(-1.0);
// Move crossfader to its idle position (either to the left,
// or in the middle, depending on the user's preferences).
// We will set it fully to the left just before starting
// a crossfade anyway.
setCrossfaderToIdle(kCrossfaderLeftOnly);

// Load track into the left deck and play. Once it starts playing,
// we will receive a playerPositionChanged update for deck 1 which
Expand All @@ -557,13 +585,21 @@ AutoDJProcessor::AutoDJError AutoDJProcessor::toggleAutoDJ(bool enable) {
if (leftDeckPlaying) {
// Load track into the right deck.
emitLoadTrackToPlayer(nextTrack, pRightDeck->group, false);
// Move crossfader to the left.
setCrossfader(-1.0);

// Move crossfader to its idle position (either to the left,
// or in the middle, depending on the user's preferences).
// We will set it fully to the left just before starting
// a crossfade anyway.
setCrossfaderToIdle(kCrossfaderLeftOnly);
} else {
// Load track into the left deck.
emitLoadTrackToPlayer(nextTrack, pLeftDeck->group, false);
// Move crossfader to the right.
setCrossfader(1.0);

// Move crossfader to its idle position (either to the right,
// or in the middle, depending on the user's preferences).
// We will set it fully to the right just before starting
// a crossfade anyway.
setCrossfaderToIdle(kCrossfaderRightOnly);
}
}
emitAutoDJStateChanged(m_eState);
Expand Down Expand Up @@ -742,12 +778,11 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes,
// If the user stops the toDeck during a fade, let the fade continue
// and do not load the next track.
if (!otherDeckPlaying && otherDeck->isFromDeck) {
// Force crossfader all the way to the (non fading) toDeck.
if (m_eState == ADJ_RIGHT_FADING) {
setCrossfader(-1.0);
} else {
setCrossfader(1.0);
}
// Force crossfader all the way to the (non fading) toDeck,
// or to the middle, depending on the user's preferences.
setCrossfaderToIdle(m_eState == ADJ_RIGHT_FADING
? kCrossfaderLeftOnly
: kCrossfaderRightOnly);
m_eState = ADJ_IDLE;
// Invalidate threshold calculated for the old otherDeck
// This avoids starting a fade back before the new track is
Expand Down Expand Up @@ -804,12 +839,25 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes,
otherDeck->setPlayPosition(otherDeck->startPos);
}

if (!otherDeckPlaying) {
otherDeck->play();
}
const bool resetFaderToNeutralOnIdle = m_pConfig->getValue<bool>(
ConfigKey(kConfigKey, kResetFaderPreferenceName),
false);

if (thisDeck->fadeBeginPos >= thisDeck->fadeEndPos) {
setCrossfader(thisDeck->isLeft() ? 1.0 : -1.0);
// This deck has an invalid fade position, so we
// immediately switch over to the other deck.
setCrossfader(thisDeck->isLeft() ? kCrossfaderRightOnly : kCrossfaderLeftOnly);
} else if (!otherDeckPlaying && resetFaderToNeutralOnIdle) {
// The user has requested the crossfader to be reset to
// neutral as long as no automatic crossfade is in progress
// (which is handled by setCrossfaderToIdle), so we need
// to set up the crossfader here instead, right before
// starting the fade.
setCrossfader(thisDeck->isLeft() ? kCrossfaderLeftOnly : kCrossfaderRightOnly);
}

if (!otherDeckPlaying) {
otherDeck->play();
}

// Now that we have started the other deck playing, remove the track
Expand All @@ -827,9 +875,9 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes,

double crossfaderTarget;
if (m_eState == ADJ_LEFT_FADING) {
crossfaderTarget = 1.0;
crossfaderTarget = kCrossfaderRightOnly;
} else if (m_eState == ADJ_RIGHT_FADING) {
crossfaderTarget = -1.0;
crossfaderTarget = kCrossfaderLeftOnly;
} else {
// this happens if the not playing track is cued into the outro region,
// calculated for the swapped roles.
Expand All @@ -847,7 +895,7 @@ void AutoDJProcessor::playerPositionChanged(DeckAttributes* pAttributes,
m_transitionProgress = 1.0;
// Note: If the user has stopped the toDeck during the transition.
// this deck just stops as well. In this case a stopped AutoDJ is accepted
// because the use did it intentionally
// because the user did it intentionally
} else {
// We are in Fading state.
// Calculate the current transitionProgress, the place between begin
Expand Down
1 change: 1 addition & 0 deletions src/library/autodj/autodjprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ class AutoDJProcessor : public QObject {
// every time)
double getCrossfader() const;
void setCrossfader(double value);
void setCrossfaderToIdle(double value);

// Following functions return seconds computed from samples or -1 if
// track in deck has invalid sample rate (<= 0)
Expand Down
13 changes: 13 additions & 0 deletions src/preferences/dialog/dlgprefautodj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ DlgPrefAutoDJ::DlgPrefAutoDJ(QWidget* pParent,
m_pConfig(pConfig) {
setupUi(this);

// Whether to reset the crossfader to neutral when not fading
ResetFaderToNeutralOnIdleCheckBox->setChecked(m_pConfig->getValue(
ConfigKey("[Auto DJ]", "ResetFaderToNeutralOnIdle"), false));
connect(ResetFaderToNeutralOnIdleCheckBox,
&QCheckBox::stateChanged,
this,
&DlgPrefAutoDJ::slotToggleResetFaderToNeutralOnIdle);

// The minimum available for randomly-selected tracks
MinimumAvailableSpinBox->setValue(
m_pConfig->getValue(
Expand Down Expand Up @@ -154,6 +162,11 @@ void DlgPrefAutoDJ::slotToggleRequeueIgnore(int buttonState) {
RequeueIgnoreTimeEdit->setEnabled(checked);
}

void DlgPrefAutoDJ::slotToggleResetFaderToNeutralOnIdle(int buttonState) {
bool checked = buttonState == Qt::Checked;
m_pConfig->setValue(ConfigKey("[Auto DJ]", "ResetFaderToNeutralOnIdle"), checked);
}

void DlgPrefAutoDJ::slotSetRequeueIgnoreTime(const QTime& a_rTime) {
QString str = a_rTime.toString(RequeueIgnoreTimeEdit->displayFormat());
m_pConfig->set(ConfigKey("[Auto DJ]", "IgnoreTimeBuff"), str);
Expand Down
1 change: 1 addition & 0 deletions src/preferences/dialog/dlgprefautodj.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class DlgPrefAutoDJ : public DlgPreferencePage, public Ui::DlgPrefAutoDJDlg {
private slots:
void slotSetMinimumAvailable(int);
void slotToggleRequeueIgnore(int buttonState);
void slotToggleResetFaderToNeutralOnIdle(int buttonState);
void slotSetRequeueIgnoreTime(const QTime& a_rTime);
void slotSetRandomQueueMin(int);
void slotConsiderRepeatPlaylistState(bool);
Expand Down
59 changes: 59 additions & 0 deletions src/preferences/dialog/dlgprefautodjdlg.ui
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,65 @@
</property>
<layout class="QVBoxLayout" name="AutoDJGridLayout">

<item>
<widget class="QGroupBox" name="CrossfaderOptions">
<property name="title">
<string>Crossfader</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<layout class="QGridLayout" name="CrossfaderGridLayout">

<item row="0" column="0">
<widget class="QLabel" name="ResetFaderToNeutralOnIdleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Check to always reset the crossfader to neutral when no fade is in progress.</string>
</property>
<property name="text">
<string>Reset fader to neutral after crossfading</string>
</property>
<property name="buddy">
<cstring>ResetFaderToNeutralOnIdleCheckBox</cstring>
</property>
</widget>
</item>

<item row="0" column="1">
<widget class="QCheckBox" name="ResetFaderToNeutralOnIdleCheckBox">
<property name="toolTip">
<string>Check to always reset the crossfader to neutral when no fade is in progress.</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>

<item row="1" column="2">
<spacer name="horizontalSpacerCrossfader">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</spacer>
</item>

</layout>
</widget>
</item>

<item>
<widget class="QGroupBox" name="RequeueOptions">
<property name="title">
Expand Down

0 comments on commit ae70792

Please sign in to comment.