From 38a9391a097d90e96421e5a34d3e75b5dbd5b9c8 Mon Sep 17 00:00:00 2001 From: Joerg Date: Sat, 19 Aug 2023 10:18:21 +0200 Subject: [PATCH] Fix display of waveform playmarker shown outside loop, while track is inside loop Unified some symbols naming --- src/engine/controls/loopingcontrol.h | 6 ++++ src/engine/enginebuffer.cpp | 35 ++++++++++++++------- src/engine/enginebuffer.h | 2 +- src/waveform/visualplayposition.cpp | 46 ++++++++++++++++++++++------ src/waveform/visualplayposition.h | 25 +++++++++------ 5 files changed, 82 insertions(+), 32 deletions(-) diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 5ee34ec94e3..45c4da1b605 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -58,6 +58,12 @@ class LoopingControl : public EngineControl { void setLoop(mixxx::audio::FramePos startPosition, mixxx::audio::FramePos endPosition, bool enabled); + mixxx::audio::FramePos getLoopStartPosition() { + return m_loopInfo.getValue().startPosition; + } + mixxx::audio::FramePos getLoopEndPosition() { + return m_loopInfo.getValue().endPosition; + } void setRateControl(RateControl* rateControl); bool isLoopingEnabled(); bool isLoopRollActive(); diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index a5187117dbc..0ca470b5b07 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -87,7 +87,7 @@ EngineBuffer::EngineBuffer(const QString& group, m_baserate_old(0), m_rate_old(0.), m_trackEndPositionOld(mixxx::audio::kInvalidFramePos), - m_slipPosition(mixxx::audio::kStartFramePos), + m_slipPos(mixxx::audio::kStartFramePos), m_dSlipRate(1.0), m_bSlipEnabledProcessing(false), m_pRepeat(nullptr), @@ -553,7 +553,7 @@ void EngineBuffer::slotTrackLoaded(TrackPointer pTrack, // Reset slip mode m_pSlipButton->set(0); m_bSlipEnabledProcessing = false; - m_slipPosition = mixxx::audio::kStartFramePos; + m_slipPos = mixxx::audio::kStartFramePos; m_dSlipRate = 0; m_queuedSeek.setValue(kNoQueuedSeek); @@ -585,7 +585,7 @@ void EngineBuffer::ejectTrack() { TrackPointer pOldTrack = m_pCurrentTrack; m_pause.lock(); - m_visualPlayPos->set(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + m_visualPlayPos->set(0.0, 0.0, 0.0, 0.0, 0.0, false, 0.0, 0.0, 0.0, 0.0); doSeekPlayPos(mixxx::audio::kStartFramePos, SEEK_EXACT); m_pCurrentTrack.reset(); @@ -1189,12 +1189,12 @@ void EngineBuffer::processSlip(int iBufferSize) { if (enabled != m_bSlipEnabledProcessing) { m_bSlipEnabledProcessing = enabled; if (enabled) { - m_slipPosition = m_playPosition; + m_slipPos = m_playPosition; m_dSlipRate = m_rate_old; } else { // TODO(owen) assuming that looping will get canceled properly - seekExact(m_slipPosition.toNearestFrameBoundary()); - m_slipPosition = mixxx::audio::kStartFramePos; + seekExact(m_slipPos.toNearestFrameBoundary()); + m_slipPos = mixxx::audio::kStartFramePos; } } @@ -1214,12 +1214,12 @@ void EngineBuffer::processSlip(int iBufferSize) { // Simulate looping if a regular loop is active if (m_pLoopingControl->isLoopingEnabled() && !m_pLoopingControl->isLoopRollActive()) { - const mixxx::audio::FramePos newPos = m_slipPosition + slipDelta; - m_slipPosition = m_pLoopingControl->adjustedPositionForCurrentLoop( + const mixxx::audio::FramePos newPos = m_slipPos + slipDelta; + m_slipPos = m_pLoopingControl->adjustedPositionForCurrentLoop( newPos, m_dSlipRate < 0); } else { - m_slipPosition += slipDelta; + m_slipPos += slipDelta; } } } @@ -1387,7 +1387,17 @@ void EngineBuffer::updateIndicators(double speed, int iBufferSize) { m_iSamplesSinceLastIndicatorUpdate += iBufferSize; const double fFractionalPlaypos = fractionalPlayposFromAbsolute(m_playPosition); - const double fFractionalSlipPos = fractionalPlayposFromAbsolute(m_slipPosition); + const double fFractionalSlipPos = fractionalPlayposFromAbsolute(m_slipPos); + double fFractionalLoopStartPos = 0.0; + auto loopStartPos = m_pLoopingControl->getLoopStartPosition(); + if (loopStartPos.isValid()) { + fFractionalLoopStartPos = fractionalPlayposFromAbsolute(loopStartPos); + } + double fFractionalLoopEndPos = 0.0; + auto loopEndPos = m_pLoopingControl->getLoopEndPosition(); + if (loopEndPos.isValid()) { + fFractionalLoopEndPos = fractionalPlayposFromAbsolute(loopEndPos); + } const double tempoTrackSeconds = m_trackEndPositionOld.value() / m_trackSampleRateOld / getRateRatio(); @@ -1420,6 +1430,9 @@ void EngineBuffer::updateIndicators(double speed, int iBufferSize) { m_trackEndPositionOld.toEngineSamplePos(), fFractionalSlipPos, effectiveSlipRate, + m_pLoopingControl->isLoopingEnabled(), + fFractionalLoopStartPos, + fFractionalLoopEndPos, tempoTrackSeconds, iBufferSize / kSamplesPerFrame / m_sampleRate.toDouble() * 1000000.0); @@ -1437,7 +1450,7 @@ void EngineBuffer::hintReader(const double dRate) { //if slipping, hint about virtual position so we're ready for it if (m_bSlipEnabledProcessing) { Hint hint; - hint.frame = static_cast(m_slipPosition.toLowerFrameBoundary().value()); + hint.frame = static_cast(m_slipPos.toLowerFrameBoundary().value()); hint.type = Hint::Type::SlipPosition; if (m_dSlipRate >= 0) { hint.frameCount = Hint::kFrameCountForward; diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index a5866a737aa..86aed63d8f8 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -352,7 +352,7 @@ class EngineBuffer : public EngineObject { int m_iSamplesSinceLastIndicatorUpdate; // The location where the track would have been had slip not been engaged - mixxx::audio::FramePos m_slipPosition; + mixxx::audio::FramePos m_slipPos; // Saved value of rate for slip mode double m_dSlipRate; // m_bSlipEnabledProcessing is only used by the engine processing thread. diff --git a/src/waveform/visualplayposition.cpp b/src/waveform/visualplayposition.cpp index 6a816e1d525..97f8c53d365 100644 --- a/src/waveform/visualplayposition.cpp +++ b/src/waveform/visualplayposition.cpp @@ -25,21 +25,27 @@ VisualPlayPosition::~VisualPlayPosition() { } void VisualPlayPosition::set( - double playPos, - double rate, + double playPosition, + double playRate, double positionStep, double slipPosition, double slipRate, + bool loopEnabled, + double loopStartPosition, + double loopEndPosition, double tempoTrackSeconds, double audioBufferMicroS) { VisualPlayPositionData data; data.m_referenceTime = m_timeInfoTime; data.m_callbackEntrytoDac = static_cast(m_dCallbackEntryToDacSecs * 1000000); // s to µs - data.m_enginePlayPos = playPos; - data.m_rate = rate; + data.m_playPos = playPosition; + data.m_playRate = playRate; data.m_slipRate = slipRate; data.m_positionStep = positionStep; - data.m_slipPosition = slipPosition; + data.m_slipPos = slipPosition; + data.m_loopEnabled = loopEnabled; + data.m_loopStartPos = loopStartPosition; + data.m_loopEndPos = loopEndPosition; data.m_tempoTrackSeconds = tempoTrackSeconds; data.m_audioBufferMicroS = audioBufferMicroS; @@ -77,7 +83,27 @@ double VisualPlayPosition::getAtNextVSync(VSyncThread* pVSyncThread) { if (m_valid) { const VisualPlayPositionData data = m_data.getValue(); const double offset = calcOffsetAtNextVSync(pVSyncThread, data); - return data.m_enginePlayPos + offset * data.m_rate; + + double interpolatedPlayPos = data.m_playPos + offset * data.m_playRate; + + if (data.m_loopEnabled) { + double loopSize = data.m_loopEndPos - data.m_loopStartPos; + if (loopSize > 0) { + if (interpolatedPlayPos < data.m_loopStartPos) { + interpolatedPlayPos = data.m_loopEndPos - + std::remainder( + data.m_loopStartPos - interpolatedPlayPos, + loopSize); + } + if (interpolatedPlayPos > data.m_loopEndPos) { + interpolatedPlayPos = data.m_loopStartPos + + std::remainder( + interpolatedPlayPos - data.m_loopEndPos, + loopSize); + } + } + } + return interpolatedPlayPos; } return -1; } @@ -88,15 +114,15 @@ void VisualPlayPosition::getPlaySlipAtNextVSync(VSyncThread* pVSyncThread, if (m_valid) { const VisualPlayPositionData data = m_data.getValue(); const double offset = calcOffsetAtNextVSync(pVSyncThread, data); - *pPlayPosition = data.m_enginePlayPos + offset * data.m_rate; - *pSlipPosition = data.m_slipPosition + offset * data.m_slipRate; + *pPlayPosition = data.m_playPos + offset * data.m_playRate; + *pSlipPosition = data.m_slipPos + offset * data.m_slipRate; } } double VisualPlayPosition::getEnginePlayPos() { if (m_valid) { VisualPlayPositionData data = m_data.getValue(); - return data.m_enginePlayPos; + return data.m_playPos; } else { return -1; } @@ -105,7 +131,7 @@ double VisualPlayPosition::getEnginePlayPos() { void VisualPlayPosition::getTrackTime(double* pPlayPosition, double* pTempoTrackSeconds) { if (m_valid) { VisualPlayPositionData data = m_data.getValue(); - *pPlayPosition = data.m_enginePlayPos; + *pPlayPosition = data.m_playPos; *pTempoTrackSeconds = data.m_tempoTrackSeconds; } else { *pPlayPosition = 0; diff --git a/src/waveform/visualplayposition.h b/src/waveform/visualplayposition.h index 9c2ca6ab672..72c5b7a3c9a 100644 --- a/src/waveform/visualplayposition.h +++ b/src/waveform/visualplayposition.h @@ -1,11 +1,11 @@ #pragma once -#include -#include #include +#include +#include -#include "util/performancetimer.h" #include "control/controlvalue.h" +#include "util/performancetimer.h" class ControlProxy; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) @@ -32,11 +32,14 @@ class VisualPlayPositionData { public: PerformanceTimer m_referenceTime; int m_callbackEntrytoDac; // Time from Audio Callback Entry to first sample of Buffer is transferred to DAC - double m_enginePlayPos; // Play position of fist Sample in Buffer - double m_rate; + double m_playPos; // Play position of first Sample in Buffer + double m_playRate; double m_positionStep; - double m_slipPosition; + double m_slipPos; double m_slipRate; + bool m_loopEnabled; + double m_loopStartPos; + double m_loopEndPos; double m_tempoTrackSeconds; // total track time, taking the current tempo into account double m_audioBufferMicroS; }; @@ -50,12 +53,14 @@ class VisualPlayPosition : public QObject { // WARNING: Not thread safe. This function must be called only from the // engine thread. - void set( - double playPos, - double rate, + void set(double playPos, + double playRate, double positionStep, - double slipPosition, + double slipPos, double slipRate, + bool loopEnabled, + double loopStartPos, + double loopEndPos, double tempoTrackSeconds, double audioBufferMicroS);