From 46887e3a82c736918679cf787b55de24b0dc9cc7 Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Tue, 10 Aug 2021 15:28:06 +0200 Subject: [PATCH] EngineBuffer: Use mixxx::audio::FramePos internally --- src/engine/controls/bpmcontrol.cpp | 6 +- src/engine/enginebuffer.cpp | 159 ++++++++++++++--------------- src/engine/enginebuffer.h | 20 ++-- src/engine/readaheadmanager.cpp | 9 ++ src/engine/readaheadmanager.h | 7 ++ 5 files changed, 104 insertions(+), 97 deletions(-) diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 2a6160637efe..7c161341f6d2 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -723,8 +723,7 @@ mixxx::audio::FramePos BpmControl::getNearestPositionInPhase( return thisPosition; } - const auto otherPosition = mixxx::audio::FramePos::fromEngineSamplePos( - pOtherEngineBuffer->getExactPlayPos()); + const auto otherPosition = pOtherEngineBuffer->getExactPlayPos(); if (!BpmControl::getBeatContext(otherBeats, otherPosition, nullptr, @@ -909,8 +908,7 @@ mixxx::audio::FramePos BpmControl::getBeatMatchPosition( return thisPosition; } - const auto otherPosition = mixxx::audio::FramePos::fromEngineSamplePos( - pOtherEngineBuffer->getExactPlayPos()); + const auto otherPosition = pOtherEngineBuffer->getExactPlayPos(); const mixxx::audio::SampleRate thisSampleRate = m_pBeats->getSampleRate(); // Seek our next beat to the other next beat near our beat. diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index deb776eaf0b1..c7613046263c 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -46,6 +46,12 @@ namespace { const mixxx::Logger kLogger("EngineBuffer"); +// This value is used to make sure the initial seek after loading a track is +// not omitted. Therefore this value must be different for 0.0 or any likely +// value for the main cue +constexpr auto kInitialPlayPosition = mixxx::audio::FramePos{ + std::numeric_limits::lowest()}; + constexpr double kLinearScalerElipsis = 1.00058; // 2^(0.01/12): changes < 1 cent allows a linear scaler @@ -70,7 +76,7 @@ EngineBuffer::EngineBuffer(const QString& group, m_pKeyControl(nullptr), m_pReadAheadManager(nullptr), m_pReader(nullptr), - m_filepos_play(kInitalSamplePosition), + m_playPosition(kInitialPlayPosition), m_speed_old(0), m_tempo_ratio_old(1.), m_scratching_old(false), @@ -78,8 +84,8 @@ EngineBuffer::EngineBuffer(const QString& group, m_pitch_old(0), m_baserate_old(0), m_rate_old(0.), - m_trackSamplesOld(0), - m_dSlipPosition(0.), + m_trackEndPositionOld(mixxx::audio::kInvalidFramePos), + m_slipPosition(mixxx::audio::kStartFramePos), m_dSlipRate(1.0), m_bSlipEnabledProcessing(false), m_pRepeat(nullptr), @@ -94,6 +100,9 @@ EngineBuffer::EngineBuffer(const QString& group, m_pCrossfadeBuffer(SampleUtil::alloc(MAX_BUFFER_LEN)), m_bCrossfadeReady(false), m_iLastBufferSize(0) { + // This should be a static assertion, but isValid() is not constexpr. + DEBUG_ASSERT(kInitialPlayPosition.isValid()); + m_queuedSeek.setValue(kNoQueuedSeek); // zero out crossfade buffer @@ -453,32 +462,30 @@ void EngineBuffer::readToCrossfadeBuffer(const int iBufferSize) { // (Must be called only once per callback) m_pScale->scaleBuffer(m_pCrossfadeBuffer, iBufferSize); // Restore the original position that was lost due to scaleBuffer() above - m_pReadAheadManager->notifySeek(m_filepos_play); + m_pReadAheadManager->notifySeek(m_playPosition); m_bCrossfadeReady = true; } } void EngineBuffer::seekCloneBuffer(EngineBuffer* pOtherBuffer) { - const auto position = mixxx::audio::FramePos::fromEngineSamplePos( - pOtherBuffer->getExactPlayPos()); - doSeekPlayPos(position, SEEK_EXACT); + doSeekPlayPos(pOtherBuffer->getExactPlayPos(), SEEK_EXACT); } // WARNING: This method is not thread safe and must not be called from outside // the engine callback! -void EngineBuffer::setNewPlaypos(double newpos) { +void EngineBuffer::setNewPlaypos(mixxx::audio::FramePos position) { if (kLogger.traceEnabled()) { - kLogger.trace() << m_group << "EngineBuffer::setNewPlaypos" << newpos; + kLogger.trace() << m_group << "EngineBuffer::setNewPlaypos" << position; } - m_filepos_play = newpos; + m_playPosition = position; if (m_rate_old != 0.0) { // Before seeking, read extra buffer for crossfading // this also sets m_pReadAheadManager to newpos readToCrossfadeBuffer(m_iLastBufferSize); } else { - m_pReadAheadManager->notifySeek(m_filepos_play); + m_pReadAheadManager->notifySeek(m_playPosition); } m_pScale->clear(); @@ -486,9 +493,8 @@ void EngineBuffer::setNewPlaypos(double newpos) { m_iSamplesSinceLastIndicatorUpdate = 1000000; // Must hold the engineLock while using m_engineControls - const auto playPosition = mixxx::audio::FramePos::fromEngineSamplePos(m_filepos_play); for (const auto& pControl: qAsConst(m_engineControls)) { - pControl->notifySeek(playPosition); + pControl->notifySeek(m_playPosition); } verifyPlay(); // verify or update play button and indicator @@ -521,7 +527,7 @@ void EngineBuffer::slotTrackLoading() { // Set play here, to signal the user that the play command is adopted m_playButton->set((double)m_bPlayAfterLoading); - m_pTrackSamples->set(0); // Stop renderer + setTrackEndPosition(mixxx::audio::kInvalidFramePos); // Stop renderer } void EngineBuffer::loadFakeTrack(TrackPointer pTrack, bool bPlay) { @@ -547,7 +553,7 @@ void EngineBuffer::slotTrackLoaded(TrackPointer pTrack, m_pause.lock(); m_visualPlayPos->setInvalid(); - m_filepos_play = kInitalSamplePosition; // for execute seeks to 0.0 + m_playPosition = kInitialPlayPosition; // for execute seeks to 0.0 m_pCurrentTrack = pTrack; m_pTrackSamples->set(iTrackNumSamples); m_pTrackSampleRate->set(iTrackSampleRate); @@ -556,7 +562,7 @@ void EngineBuffer::slotTrackLoaded(TrackPointer pTrack, // Reset slip mode m_pSlipButton->set(0); m_bSlipEnabledProcessing = false; - m_dSlipPosition = 0.; + m_slipPosition = mixxx::audio::kStartFramePos; m_dSlipRate = 0; m_queuedSeek.setValue(kNoQueuedSeek); @@ -592,7 +598,7 @@ void EngineBuffer::ejectTrack() { doSeekPlayPos(mixxx::audio::kStartFramePos, SEEK_EXACT); m_pCurrentTrack.reset(); - m_pTrackSamples->set(0); + setTrackEndPosition(mixxx::audio::kInvalidFramePos); m_pTrackSampleRate->set(0); m_pTrackLoaded->forceSet(0); @@ -625,14 +631,11 @@ void EngineBuffer::notifyTrackLoaded( // First inform engineControls directly // Note: we are still in a worker thread. - const auto currentPosition = mixxx::audio::FramePos::fromEngineSamplePos(m_filepos_play); - const auto trackEndPosition = - mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid( - m_pTrackSamples->get()); + const auto trackEndPosition = getTrackEndPosition(); const auto sampleRate = mixxx::audio::SampleRate::fromDouble(m_pTrackSampleRate->get()); for (const auto& pControl : qAsConst(m_engineControls)) { pControl->trackLoaded(pNewTrack); - pControl->setFrameInfo(currentPosition, trackEndPosition, sampleRate); + pControl->setFrameInfo(m_playPosition, trackEndPosition, sampleRate); } if (pNewTrack) { @@ -672,13 +675,13 @@ void EngineBuffer::seekExact(mixxx::audio::FramePos position) { doSeekPlayPos(position, SEEK_EXACT); } -double EngineBuffer::fractionalPlayposFromAbsolute(double absolutePlaypos) { - double fFractionalPlaypos = 0.0; - if (m_trackSamplesOld != 0) { - fFractionalPlaypos = math_min(absolutePlaypos, m_trackSamplesOld); - fFractionalPlaypos /= m_trackSamplesOld; +double EngineBuffer::fractionalPlayposFromAbsolute(mixxx::audio::FramePos absolutePlaypos) { + if (!m_trackEndPositionOld.isValid()) { + return 0.0; } - return fFractionalPlaypos; + + const auto position = std::min(absolutePlaypos, m_trackEndPositionOld); + return position.value() / m_trackEndPositionOld.value(); } void EngineBuffer::doSeekFractional(double fractionalPos, enum SeekRequest seekType) { @@ -688,8 +691,7 @@ void EngineBuffer::doSeekFractional(double fractionalPos, enum SeekRequest seekT } // FIXME: Use maybe invalid here - const auto trackEndPosition = - mixxx::audio::FramePos::fromEngineSamplePos(m_pTrackSamples->get()); + const mixxx::audio::FramePos trackEndPosition = getTrackEndPosition(); VERIFY_OR_DEBUG_ASSERT(trackEndPosition.isValid()) { return; } @@ -717,7 +719,7 @@ bool EngineBuffer::updateIndicatorsAndModifyPlay(bool newPlay, bool oldPlay) { const QueuedSeek queuedSeek = m_queuedSeek.getValue(); if ((!m_pCurrentTrack && atomicLoadRelaxed(m_iTrackLoading) == 0) || (m_pCurrentTrack && atomicLoadRelaxed(m_iTrackLoading) == 0 && - m_filepos_play >= m_pTrackSamples->get() && + m_playPosition >= getTrackEndPosition() && queuedSeek.seekType == SEEK_NONE) || m_pPassthroughEnabled->toBool()) { // play not possible @@ -809,7 +811,7 @@ void EngineBuffer::processTrackLocked( ScopedTimer t("EngineBuffer::process_pauselock"); m_trackSampleRateOld = mixxx::audio::SampleRate::fromDouble(m_pTrackSampleRate->get()); - m_trackSamplesOld = m_pTrackSamples->get(); + m_trackEndPositionOld = getTrackEndPosition(); double baserate = 0.0; if (sampleRate.isValid()) { @@ -835,7 +837,7 @@ void EngineBuffer::processTrackLocked( // Update the slipped position and seek if it was disabled. processSlip(iBufferSize); - // Note: This may effects the m_filepos_play, play, scaler and crossfade buffer + // Note: This may effects the m_playPosition, play, scaler and crossfade buffer processSeek(paused); // speed is the ratio between track-time and real-time @@ -1015,11 +1017,12 @@ void EngineBuffer::processTrackLocked( rate = m_rate_old; } - bool at_end = m_filepos_play >= m_trackSamplesOld; + const mixxx::audio::FramePos trackEndPosition = getTrackEndPosition(); + bool atEnd = m_playPosition >= trackEndPosition; bool backwards = rate < 0; bool bCurBufferPaused = false; - if (at_end && !backwards) { + if (atEnd && !backwards) { // do not play past end bCurBufferPaused = true; } else if (rate == 0 && !is_scratching) { @@ -1034,28 +1037,25 @@ void EngineBuffer::processTrackLocked( // If the buffer is not paused, then scale the audio. if (!bCurBufferPaused) { // Perform scaling of Reader buffer into buffer. - double framesRead = - m_pScale->scaleBuffer(pOutput, iBufferSize); + const auto framesRead = m_pScale->scaleBuffer(pOutput, iBufferSize); // TODO(XXX): The result framesRead might not be an integer value. // Converting to samples here does not make sense. All positional // calculations should be done in frames instead of samples! Otherwise // rounding errors might occur when converting from samples back to // frames later. - double samplesRead = framesRead * kSamplesPerFrame; if (m_bScalerOverride) { // If testing, we don't have a real log so we fake the position. - m_filepos_play += samplesRead; + m_playPosition += framesRead; } else { // Adjust filepos_play by the amount we processed. - m_filepos_play = - m_pReadAheadManager->getFilePlaypositionFromLog( - m_filepos_play, samplesRead); + m_playPosition = + m_pReadAheadManager->getFilePlaypositionFromLog(m_playPosition, framesRead); } // Note: The last buffer of a track is padded with silence. // This silence is played together with the last samples in the last - // callback and the m_filepos_play is advanced behind the end of the track. + // callback and the m_playPosition is advanced behind the end of the track. if (m_bCrossfadeReady) { // Bring pOutput with the new parameters in and fade out the old one, @@ -1080,29 +1080,27 @@ void EngineBuffer::processTrackLocked( } } - const auto currentPosition = mixxx::audio::FramePos::fromEngineSamplePos(m_filepos_play); - const auto trackEndPosition = mixxx::audio::FramePos::fromEngineSamplePos(m_trackSamplesOld); for (const auto& pControl: qAsConst(m_engineControls)) { - pControl->setFrameInfo(currentPosition, trackEndPosition, m_trackSampleRateOld); - pControl->process(rate, currentPosition, iBufferSize); + pControl->setFrameInfo(m_playPosition, trackEndPosition, m_trackSampleRateOld); + pControl->process(rate, m_playPosition, iBufferSize); } m_scratching_old = is_scratching; // Handle repeat mode - bool at_start = m_filepos_play <= 0; - at_end = m_filepos_play >= m_trackSamplesOld; + const bool atStart = m_playPosition <= mixxx::audio::kStartFramePos; + atEnd = m_playPosition >= trackEndPosition; bool repeat_enabled = m_pRepeat->toBool(); bool end_of_track = //(at_start && backwards) || - (at_end && !backwards); + (atEnd && !backwards); // If playbutton is pressed, check if we are at start or end of track if ((m_playButton->toBool() || (m_fwdButton->toBool() || m_backButton->toBool())) && end_of_track) { if (repeat_enabled) { - double fractionalPos = at_start ? 1.0 : 0; + double fractionalPos = atStart ? 1.0 : 0; doSeekFractional(fractionalPos, SEEK_STANDARD); } else { m_playButton->set(0.); @@ -1190,21 +1188,19 @@ void EngineBuffer::processSlip(int iBufferSize) { if (enabled != m_bSlipEnabledProcessing) { m_bSlipEnabledProcessing = enabled; if (enabled) { - m_dSlipPosition = m_filepos_play; + m_slipPosition = m_playPosition; m_dSlipRate = m_rate_old; } else { // TODO(owen) assuming that looping will get canceled properly - const auto newPlayPosition = - mixxx::audio::FramePos::fromEngineSamplePos( - m_dSlipPosition); - seekExact(newPlayPosition.toNearestFrameBoundary()); - m_dSlipPosition = 0; + seekExact(m_slipPosition.toNearestFrameBoundary()); + m_slipPosition = mixxx::audio::kStartFramePos; } } // Increment slip position even if it was just toggled -- this ensures the position is correct. if (enabled) { - m_dSlipPosition += static_cast(iBufferSize) * m_dSlipRate; + m_slipPosition += static_cast(iBufferSize) * m_dSlipRate / + mixxx::kEngineChannelCount; } } @@ -1258,7 +1254,7 @@ void EngineBuffer::processSeek(bool paused) { return; case SEEK_PHASE: // only adjust phase - position = mixxx::audio::FramePos::fromEngineSamplePos(m_filepos_play); + position = m_playPosition; break; case SEEK_STANDARD: if (m_pQuantize->toBool()) { @@ -1281,12 +1277,8 @@ void EngineBuffer::processSeek(bool paused) { return; } - const auto trackEndPosition = mixxx::audio::FramePos::fromEngineSamplePos(m_trackSamplesOld); - // Don't allow the playposition to go past the end. - if (position > trackEndPosition) { - position = trackEndPosition; - } + position = std::min(position, m_trackEndPositionOld); if (!paused && (seekType & SEEK_PHASE)) { if (kLogger.traceEnabled()) { @@ -1297,15 +1289,15 @@ void EngineBuffer::processSeek(bool paused) { position = m_pLoopingControl->getSyncPositionInsideLoop(position, syncPosition); if (kLogger.traceEnabled()) { kLogger.trace() - << "EngineBuffer::processSeek" << getGroup() << "seek info:" << m_filepos_play + << "EngineBuffer::processSeek" << getGroup() << "seek info:" << m_playPosition << "->" << position; } } - if (position.toEngineSamplePos() != m_filepos_play) { + if (position != m_playPosition) { if (kLogger.traceEnabled()) { kLogger.trace() << "EngineBuffer::processSeek" << getGroup() << "Seek to" << position; } - setNewPlaypos(position.toEngineSamplePos()); + setNewPlaypos(position); m_previousBufferSeek = true; } // Reset the m_queuedSeek value after it has been processed in @@ -1363,10 +1355,10 @@ void EngineBuffer::updateIndicators(double speed, int iBufferSize) { // Increase samplesCalculated by the buffer size m_iSamplesSinceLastIndicatorUpdate += iBufferSize; - const double fFractionalPlaypos = fractionalPlayposFromAbsolute(m_filepos_play); + const double fFractionalPlaypos = fractionalPlayposFromAbsolute(m_playPosition); - const double tempoTrackSeconds = m_trackSamplesOld / kSamplesPerFrame - / m_trackSampleRateOld / m_tempo_ratio_old; + const double tempoTrackSeconds = m_trackEndPositionOld.value() / + m_trackSampleRateOld / m_tempo_ratio_old; if(speed > 0 && fFractionalPlaypos == 1.0) { // At Track end speed = 0; @@ -1389,18 +1381,19 @@ void EngineBuffer::updateIndicators(double speed, int iBufferSize) { // Update visual control object, this needs to be done more often than the // playpos slider - m_visualPlayPos->set(fFractionalPlaypos, speed * m_baserate_old, - (double)iBufferSize / m_trackSamplesOld, - fractionalPlayposFromAbsolute(m_dSlipPosition), + m_visualPlayPos->set(fFractionalPlaypos, + speed * m_baserate_old, + static_cast(iBufferSize) / + m_trackEndPositionOld.toEngineSamplePos(), + fractionalPlayposFromAbsolute(m_slipPosition), tempoTrackSeconds); // TODO: Especially with long audio buffers, jitter is visible. This can be fixed by moving the // ClockControl::updateIndicators into the waveform update loop which is synced with the display refresh rate. // Via the visual play position it's possible to access to the sample that is currently played, // and not the one that have been processed as in the current solution. - const auto currentPosition = mixxx::audio::FramePos::fromEngineSamplePos(m_filepos_play); const auto sampleRate = mixxx::audio::SampleRate::fromDouble(m_pSampleRate->get()); - m_pClockControl->updateIndicators(speed * m_baserate_old, currentPosition, sampleRate); + m_pClockControl->updateIndicators(speed * m_baserate_old, m_playPosition, sampleRate); } void EngineBuffer::hintReader(const double dRate) { @@ -1410,7 +1403,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 = SampleUtil::floorPlayPosToFrame(m_dSlipPosition); + hint.frame = static_cast(m_slipPosition.toLowerFrameBoundary().value()); hint.priority = 1; if (m_dSlipRate >= 0) { hint.frameCount = Hint::kFrameCountForward; @@ -1467,19 +1460,23 @@ void EngineBuffer::slotEjectTrack(double v) { } } -double EngineBuffer::getExactPlayPos() const { +mixxx::audio::FramePos EngineBuffer::getExactPlayPos() const { if (!m_visualPlayPos->isValid()) { - return 0.0; + return mixxx::audio::kStartFramePos; } - return m_visualPlayPos->getEnginePlayPos() * getTrackSamples(); + return getTrackEndPosition() * m_visualPlayPos->getEnginePlayPos(); } double EngineBuffer::getVisualPlayPos() const { return m_visualPlayPos->getEnginePlayPos(); } -double EngineBuffer::getTrackSamples() const { - return m_pTrackSamples->get(); +mixxx::audio::FramePos EngineBuffer::getTrackEndPosition() const { + return mixxx::audio::FramePos::fromEngineSamplePosMaybeInvalid(m_pTrackSamples->get()); +} + +void EngineBuffer::setTrackEndPosition(mixxx::audio::FramePos position) { + m_pTrackSamples->set(position.toEngineSamplePosMaybeInvalid()); } double EngineBuffer::getUserOffset() const { diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 563d0f5db07f..9683a7d3b75a 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -80,11 +80,6 @@ class EngineBuffer : public EngineObject { KEYLOCK_ENGINE_COUNT, }; - // This value is used to make sure the initial seek after loading a track is - // not omitted. Therefore this value must be different for 0.0 or any likely - // value for the main cue - static constexpr double kInitalSamplePosition = -DBL_MAX; - EngineBuffer(const QString& group, UserSettingsPointer pConfig, EngineChannel* pChannel, EngineMaster* pMixingEngine); virtual ~EngineBuffer(); @@ -128,9 +123,10 @@ class EngineBuffer : public EngineObject { bool isTrackLoaded() const; TrackPointer getLoadedTrack() const; - double getExactPlayPos() const; + mixxx::audio::FramePos getExactPlayPos() const; double getVisualPlayPos() const; - double getTrackSamples() const; + mixxx::audio::FramePos getTrackEndPosition() const; + void setTrackEndPosition(mixxx::audio::FramePos position); double getUserOffset() const; double getRateRatio() const; @@ -213,7 +209,7 @@ class EngineBuffer : public EngineObject { void ejectTrack(); - double fractionalPlayposFromAbsolute(double absolutePlaypos); + double fractionalPlayposFromAbsolute(mixxx::audio::FramePos position); void doSeekFractional(double fractionalPos, enum SeekRequest seekType); void doSeekPlayPos(mixxx::audio::FramePos position, enum SeekRequest seekType); @@ -227,7 +223,7 @@ class EngineBuffer : public EngineObject { void seekCloneBuffer(EngineBuffer* pOtherBuffer); // Reset buffer playpos and set file playpos. - void setNewPlaypos(double playpos); + void setNewPlaypos(mixxx::audio::FramePos playpos); void processSyncRequests(); void processSeek(bool paused); @@ -284,7 +280,7 @@ class EngineBuffer : public EngineObject { HintVector m_hintList; // The current sample to play in the file. - double m_filepos_play; + mixxx::audio::FramePos m_playPosition; // The previous callback's speed. Used to check if the scaler parameters // need updating. @@ -311,7 +307,7 @@ class EngineBuffer : public EngineObject { double m_rate_old; // Copy of length of file - double m_trackSamplesOld; + mixxx::audio::FramePos m_trackEndPositionOld; // Copy of file sample rate mixxx::audio::SampleRate m_trackSampleRateOld; @@ -323,7 +319,7 @@ class EngineBuffer : public EngineObject { int m_iSamplesSinceLastIndicatorUpdate; // The location where the track would have been had slip not been engaged - double m_dSlipPosition; + mixxx::audio::FramePos m_slipPosition; // Saved value of rate for slip mode double m_dSlipRate; // m_bSlipEnabledProcessing is only used by the engine processing thread. diff --git a/src/engine/readaheadmanager.cpp b/src/engine/readaheadmanager.cpp index 2462bded14b8..8958ea44ac86 100644 --- a/src/engine/readaheadmanager.cpp +++ b/src/engine/readaheadmanager.cpp @@ -279,3 +279,12 @@ double ReadAheadManager::getFilePlaypositionFromLog( return filePlayposition; } + +mixxx::audio::FramePos ReadAheadManager::getFilePlaypositionFromLog( + mixxx::audio::FramePos currentPosition, + mixxx::audio::FrameDiff_t numConsumedFrames) { + const double positionSamples = + getFilePlaypositionFromLog(currentPosition.toEngineSamplePos(), + numConsumedFrames * mixxx::kEngineChannelCount); + return mixxx::audio::FramePos::fromEngineSamplePos(positionSamples); +} diff --git a/src/engine/readaheadmanager.h b/src/engine/readaheadmanager.h index 49f5b98c64ff..fa673dcca852 100644 --- a/src/engine/readaheadmanager.h +++ b/src/engine/readaheadmanager.h @@ -4,6 +4,7 @@ #include #include +#include "audio/frame.h" #include "engine/cachingreader/cachingreader.h" #include "util/math.h" #include "util/types.h" @@ -46,6 +47,9 @@ class ReadAheadManager { } virtual void notifySeek(double seekPosition); + virtual void notifySeek(mixxx::audio::FramePos position) { + notifySeek(position.toEngineSamplePos()); + } /// hintReader allows the ReadAheadManager to provide hints to the reader to /// indicate that the given portion of a song is about to be read. @@ -54,6 +58,9 @@ class ReadAheadManager { virtual double getFilePlaypositionFromLog( double currentFilePlayposition, double numConsumedSamples); + mixxx::audio::FramePos getFilePlaypositionFromLog( + mixxx::audio::FramePos currentPosition, + mixxx::audio::FrameDiff_t numConsumedFrames); private: /// An entry in the read log indicates the virtual playposition the read