Skip to content

Commit

Permalink
Fix display of waveform playmarker shown outside loop, while track is…
Browse files Browse the repository at this point in the history
… inside loop

Unified some symbols naming
  • Loading branch information
JoergAtGithub committed Aug 19, 2023
1 parent 7b1239f commit 38a9391
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 32 deletions.
6 changes: 6 additions & 0 deletions src/engine/controls/loopingcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
35 changes: 24 additions & 11 deletions src/engine/enginebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}
}

Expand All @@ -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;
}
}
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);

Expand All @@ -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<SINT>(m_slipPosition.toLowerFrameBoundary().value());
hint.frame = static_cast<SINT>(m_slipPos.toLowerFrameBoundary().value());
hint.type = Hint::Type::SlipPosition;
if (m_dSlipRate >= 0) {
hint.frameCount = Hint::kFrameCountForward;
Expand Down
2 changes: 1 addition & 1 deletion src/engine/enginebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
46 changes: 36 additions & 10 deletions src/waveform/visualplayposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(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;

Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down
25 changes: 15 additions & 10 deletions src/waveform/visualplayposition.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

#include <QTime>
#include <QMap>
#include <QAtomicPointer>
#include <QMap>
#include <QTime>

#include "util/performancetimer.h"
#include "control/controlvalue.h"
#include "util/performancetimer.h"

class ControlProxy;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
Expand All @@ -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;
};
Expand All @@ -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);

Expand Down

0 comments on commit 38a9391

Please sign in to comment.