From 6f6e857ae2c959b05bb0dd8387a2fb0c0f4382de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 24 Mar 2021 15:21:23 +0100 Subject: Allow quantized play from the pre-roll in beatmap tracks fixes lp1920084. --- src/engine/controls/bpmcontrol.cpp | 54 +++++++++++++++++++++++++------------- src/test/enginesynctest.cpp | 25 ++++++++++++------ 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 2bb58317d9..d723a94dbb 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -859,7 +859,23 @@ double BpmControl::getBeatMatchPosition( return dThisPosition; } - double dOtherPosition = pOtherEngineBuffer->getExactPlayPos(); + const double dOtherPosition = pOtherEngineBuffer->getExactPlayPos(); + const double dThisSampleRate = m_pBeats->getSampleRate(); + const double dThisRateRatio = m_pRateRatio->get(); + + // Seek our next beat to the other next beat near our beat. + // This is the only thing we can do if the track has different BPM, + // playing the next beat together. + + // First calculate the position in the other track where this next beat will be. + const double thisSecs2ToNextBeat = (dThisNextBeat - dThisPosition) / + dThisSampleRate / dThisRateRatio; + const double dOtherPositionOfThisNextBeat = + thisSecs2ToNextBeat * otherBeats->getSampleRate() * pOtherEngineBuffer->getRateRatio() + + dOtherPosition; + + qDebug() << "dOtherPositionOfThisNextBeat" << dOtherPositionOfThisNextBeat + << thisSecs2ToNextBeat; double dOtherPrevBeat = -1; double dOtherNextBeat = -1; @@ -867,7 +883,7 @@ double BpmControl::getBeatMatchPosition( double dOtherBeatFraction = -1; if (!BpmControl::getBeatContext( otherBeats, - dOtherPosition, + dOtherPositionOfThisNextBeat, &dOtherPrevBeat, &dOtherNextBeat, &dOtherBeatLength, @@ -880,29 +896,28 @@ double BpmControl::getBeatMatchPosition( return dThisPosition; } - double dThisSampleRate = m_pBeats->getSampleRate(); - double dThisRateRatio = m_pRateRatio->get(); + qDebug() << "other" << dOtherBeatFraction << dOtherPosition; - // Seek our next beat to the other next beat - // This is the only thing we can do if the track has different BPM, - // playing the next beat together. - double thisDivSec = (dThisNextBeat - dThisPosition) / - dThisSampleRate / dThisRateRatio; - - if (dOtherBeatFraction < 1.0 / 8) { - // the user has probably pressed play too late, sync the previous beat - dOtherBeatFraction += 1.0; + // We can either match the past beat with dOtherBeatFraction 1.0 + // or the next beat with dOtherBeatFraction 0.0 + // We prefer the next because this is what will be played, + // unless we are close to the previous. + // This happens if the user presses play too late. + if (dOtherBeatFraction > 7 / 8.0) { + // match the past beat + dOtherBeatFraction -= 1.0; } - dOtherBeatFraction += m_dUserOffset.getValue(); - double otherDivSec = (1 - dOtherBeatFraction) * + double otherDivSec2 = dOtherBeatFraction * dOtherBeatLength / otherBeats->getSampleRate() / pOtherEngineBuffer->getRateRatio(); + // Transform for this track + double seekMatch = otherDivSec2 * dThisSampleRate * dThisRateRatio; - // This matches the next beat in of both tracks. - double seekMatch = (thisDivSec - otherDivSec) * - dThisSampleRate * dThisRateRatio; + qDebug() << seekMatch << m_dUserOffset.getValue() << dOtherBeatFraction; if (dThisBeatLength > 0) { + // restore phase adjustment + seekMatch += (dThisBeatLength * m_dUserOffset.getValue()); if (dThisBeatLength / 2 < seekMatch) { // seek to previous beat, because of shorter distance seekMatch -= dThisBeatLength; @@ -954,6 +969,9 @@ double BpmControl::getBeatMatchPosition( // loops are catching } } + + qDebug() << "dNewPlaypos" << dNewPlaypos << dThisPosition; + return dNewPlaypos; } diff --git a/src/test/enginesynctest.cpp b/src/test/enginesynctest.cpp index b34cafc1b2..667bd8f6c9 100644 --- a/src/test/enginesynctest.cpp +++ b/src/test/enginesynctest.cpp @@ -2213,9 +2213,10 @@ TEST_F(EngineSyncTest, QuantizeImpliesSyncPhase) { EXPECT_DOUBLE_EQ(100, ControlObject::get(ConfigKey(m_sGroup2, "bpm"))); // we align here to the past beat, because beat_distance < 1.0/8 - EXPECT_DOUBLE_EQ( + EXPECT_NEAR( ControlObject::get(ConfigKey(m_sGroup1, "beat_distance")) / 130 * 100, - ControlObject::get(ConfigKey(m_sGroup2, "beat_distance"))); + ControlObject::get(ConfigKey(m_sGroup2, "beat_distance")), + 1e-15); } TEST_F(EngineSyncTest, SeekStayInPhase) { @@ -2234,7 +2235,8 @@ TEST_F(EngineSyncTest, SeekStayInPhase) { ProcessBuffer(); // We expect to be two buffers ahead in a beat near 0.2 - EXPECT_DOUBLE_EQ(0.050309901738473183, ControlObject::get(ConfigKey(m_sGroup1, "beat_distance"))); + EXPECT_DOUBLE_EQ(0.050309901738473162, + ControlObject::get(ConfigKey(m_sGroup1, "beat_distance"))); EXPECT_DOUBLE_EQ(0.18925937554508981, ControlObject::get(ConfigKey(m_sGroup1, "playposition"))); // The same again with a stopped track loaded in Channel 2 @@ -2257,7 +2259,7 @@ TEST_F(EngineSyncTest, SeekStayInPhase) { ProcessBuffer(); // We expect to be two buffers ahead in a beat near 0.2 - EXPECT_DOUBLE_EQ(0.050309901738473183, + EXPECT_DOUBLE_EQ(0.050309901738473162, ControlObject::get(ConfigKey(m_sGroup1, "beat_distance"))); EXPECT_DOUBLE_EQ(0.18925937554508981, ControlObject::get(ConfigKey(m_sGroup1, "playposition"))); } @@ -2323,9 +2325,12 @@ TEST_F(EngineSyncTest, QuantizeHotCueActivate) { pHotCue2Activate->set(1.0); ProcessBuffer(); + // Beat_distance is the distance to the previous beat wich has already passed. + // We compare here the distance to the next beat (1 - beat_distance) and + // scale it by the different tempos. EXPECT_NEAR( - ControlObject::get(ConfigKey(m_sGroup1, "beat_distance")) / 130 * 100, - ControlObject::get(ConfigKey(m_sGroup2, "beat_distance")), + (1 - ControlObject::get(ConfigKey(m_sGroup1, "beat_distance"))) / 130 * 100, + (1 - ControlObject::get(ConfigKey(m_sGroup2, "beat_distance"))), 1e-15); pHotCue2Activate->set(0.0); @@ -2440,8 +2445,12 @@ TEST_F(EngineSyncTest, BeatMapQantizePlay) { ProcessBuffer(); - EXPECT_DOUBLE_EQ(m_pChannel1->getEngineBuffer()->m_pSyncControl->getBeatDistance(), - m_pChannel2->getEngineBuffer()->m_pSyncControl->getBeatDistance()); + // Beat Distance shall be still 0, because we are before the first beat. + // This was fixed in https://bugs.launchpad.net/mixxx/+bug/1920084 + EXPECT_DOUBLE_EQ(m_pChannel2->getEngineBuffer()->m_pSyncControl->getBeatDistance(), 0); + EXPECT_DOUBLE_EQ( + ControlObject::get(ConfigKey(m_sGroup1, "playposition")), + ControlObject::get(ConfigKey(m_sGroup2, "playposition"))); } TEST_F(EngineSyncTest, BpmAdjustFactor) { -- cgit v1.2.3 From abc8eafe18e41e66b7a6a3dbd9d83f1670e76d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 24 Mar 2021 20:51:18 +0100 Subject: silence debug message --- src/engine/controls/bpmcontrol.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index d723a94dbb..55a9d34764 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -874,9 +874,6 @@ double BpmControl::getBeatMatchPosition( thisSecs2ToNextBeat * otherBeats->getSampleRate() * pOtherEngineBuffer->getRateRatio() + dOtherPosition; - qDebug() << "dOtherPositionOfThisNextBeat" << dOtherPositionOfThisNextBeat - << thisSecs2ToNextBeat; - double dOtherPrevBeat = -1; double dOtherNextBeat = -1; double dOtherBeatLength = -1; @@ -896,8 +893,6 @@ double BpmControl::getBeatMatchPosition( return dThisPosition; } - qDebug() << "other" << dOtherBeatFraction << dOtherPosition; - // We can either match the past beat with dOtherBeatFraction 1.0 // or the next beat with dOtherBeatFraction 0.0 // We prefer the next because this is what will be played, @@ -913,8 +908,6 @@ double BpmControl::getBeatMatchPosition( // Transform for this track double seekMatch = otherDivSec2 * dThisSampleRate * dThisRateRatio; - qDebug() << seekMatch << m_dUserOffset.getValue() << dOtherBeatFraction; - if (dThisBeatLength > 0) { // restore phase adjustment seekMatch += (dThisBeatLength * m_dUserOffset.getValue()); @@ -969,9 +962,6 @@ double BpmControl::getBeatMatchPosition( // loops are catching } } - - qDebug() << "dNewPlaypos" << dNewPlaypos << dThisPosition; - return dNewPlaypos; } -- cgit v1.2.3 From 8209eb1e1db7c903e411fa644863791fef5f61a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 24 Mar 2021 21:51:04 +0100 Subject: Introduce a const for matching the past beat --- src/engine/controls/bpmcontrol.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 55a9d34764..de125a80c5 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -39,6 +39,11 @@ constexpr int kBpmTapFilterLength = 5; // the actual number of beats is this x2. constexpr int kLocalBpmSpan = 4; constexpr SINT kSamplesPerFrame = 2; + +// If we are 1 / 8.0 beat fraction near the previous beat we match that instead +// of the next beat. +constexpr double kPastBeatMatchThreshold = 1 / 8.0; + } // namespace BpmControl::BpmControl(const QString& group, @@ -898,7 +903,7 @@ double BpmControl::getBeatMatchPosition( // We prefer the next because this is what will be played, // unless we are close to the previous. // This happens if the user presses play too late. - if (dOtherBeatFraction > 7 / 8.0) { + if (dOtherBeatFraction > 1.0 - kPastBeatMatchThreshold) { // match the past beat dOtherBeatFraction -= 1.0; } -- cgit v1.2.3 From fddd32eb3037b1c2d8f95171b68a2b41529ca0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 26 Mar 2021 18:50:15 +0100 Subject: remove unused m_dUserTweakingSync --- src/engine/controls/bpmcontrol.cpp | 6 ++---- src/engine/controls/bpmcontrol.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index de125a80c5..86e54c1b0f 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -51,8 +51,7 @@ BpmControl::BpmControl(const QString& group, : EngineControl(group, pConfig), m_tapFilter(this, kBpmTapFilterLength, kBpmTapMaxInterval), m_dSyncInstantaneousBpm(0.0), - m_dLastSyncAdjustment(1.0), - m_dUserTweakingSync(false) { + m_dLastSyncAdjustment(1.0) { m_dSyncTargetBeatDistance.setValue(0.0); m_dUserOffset.setValue(0.0); @@ -412,7 +411,6 @@ double BpmControl::calcSyncedRate(double userTweak) { if (kLogger.traceEnabled()) { kLogger.trace() << getGroup() << "BpmControl::calcSyncedRate, tweak " << userTweak; } - m_dUserTweakingSync = userTweak != 0.0; double rate = 1.0; // Don't know what to do if there's no bpm. if (m_pLocalBpm->toBool()) { @@ -449,7 +447,7 @@ 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(userTweak != 0.0); return (rate + userTweak) * adjustment; } diff --git a/src/engine/controls/bpmcontrol.h b/src/engine/controls/bpmcontrol.h index 156fdca700..62b2fe8367 100644 --- a/src/engine/controls/bpmcontrol.h +++ b/src/engine/controls/bpmcontrol.h @@ -161,7 +161,6 @@ class BpmControl : public EngineControl { // used in the engine thread only double m_dSyncInstantaneousBpm; double m_dLastSyncAdjustment; - bool m_dUserTweakingSync; // m_pBeats is written from an engine worker thread mixxx::BeatsPointer m_pBeats; -- cgit v1.2.3 From 858f7ff83483e2e67363d7862e8700c9e781e6ae Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Mon, 5 Apr 2021 16:24:07 +0200 Subject: Reorder cmake_policy() before project() Some of them might affect how project() works. Additional changes: - Require CMake minimum version 3.16 instead of 3.16.0 - Reorder list by CMP numbers - Add documentation for CMP0069 --- CMakeLists.txt | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 33a0aa636a..b7e12ef7df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,4 @@ -cmake_minimum_required(VERSION 3.16.0) -project(mixxx VERSION 2.3.0) -set(CMAKE_PROJECT_HOMEPAGE_URL "https://www.mixxx.org") -set(CMAKE_PROJECT_DESCRIPTION "Mixxx is Free DJ software that gives you everything you need to perform live mixes.") - -# Used for force control of color output -set(BUILD_COLORS "auto" CACHE STRING "Try to use colors auto/always/no") -# Option to disable symlinks -set(USE_SYMLINKS ON CACHE BOOL "Use symlinks in build directory when possible") - -# Support new IN_LIST if() operator -if(POLICY CMP0057) - cmake_policy(SET CMP0057 NEW) -endif() - -# Let AUTOMOC and AUTOUIC process GENERATED files -if(POLICY CMP0071) - cmake_policy(SET CMP0071 NEW) -endif() +cmake_minimum_required(VERSION 3.16) # CMAKE_CXX_COMPILER_ID: Distinguish between "AppleClang" and "Clang" if(POLICY CMP0025) @@ -28,10 +10,31 @@ if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() +# Support new IN_LIST if() operator +if(POLICY CMP0057) + cmake_policy(SET CMP0057 NEW) +endif() + +# Enforce interprocedural optimization if(POLICY CMP0069) cmake_policy(SET CMP0069 NEW) endif() +# Let AUTOMOC and AUTOUIC process GENERATED files +if(POLICY CMP0071) + cmake_policy(SET CMP0071 NEW) +endif() + +project(mixxx VERSION 2.3.0) + +set(CMAKE_PROJECT_HOMEPAGE_URL "https://www.mixxx.org") +set(CMAKE_PROJECT_DESCRIPTION "Mixxx is Free DJ software that gives you everything you need to perform live mixes.") + +# Used for force control of color output +set(BUILD_COLORS "auto" CACHE STRING "Try to use colors auto/always/no") +# Option to disable symlinks +set(USE_SYMLINKS ON CACHE BOOL "Use symlinks in build directory when possible") + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") include(CMakeDependentOption) include(CheckSymbolExists) -- cgit v1.2.3