mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-25 16:48:44 +02:00
Scrub queue records positions as sampleCount not long
This commit is contained in:
commit
92aa05237b
@ -383,12 +383,12 @@ struct AudioIO::ScrubQueue
|
|||||||
, mUpdating()
|
, mUpdating()
|
||||||
, mMaxDebt { maxDebt }
|
, mMaxDebt { maxDebt }
|
||||||
{
|
{
|
||||||
const long s0 = std::max(options.minSample, std::min(options.maxSample,
|
const auto s0 = std::max(options.minSample, std::min(options.maxSample,
|
||||||
lrint(t0 * mRate)
|
sampleCount(lrint(t0 * mRate))
|
||||||
));
|
));
|
||||||
const long s1 = lrint(t1 * mRate);
|
const auto s1 = sampleCount(lrint(t1 * mRate));
|
||||||
Duration dd { *this };
|
Duration dd { *this };
|
||||||
long actualDuration = std::max(1L, dd.duration);
|
auto actualDuration = std::max(sampleCount{1}, dd.duration);
|
||||||
auto success = mEntries[mMiddleIdx].Init(nullptr,
|
auto success = mEntries[mMiddleIdx].Init(nullptr,
|
||||||
s0, s1, actualDuration, options);
|
s0, s1, actualDuration, options);
|
||||||
if (success)
|
if (success)
|
||||||
@ -439,14 +439,14 @@ struct AudioIO::ScrubQueue
|
|||||||
auto previous = &mEntries[(mLeadingIdx + Size - 1) % Size];
|
auto previous = &mEntries[(mLeadingIdx + Size - 1) % Size];
|
||||||
|
|
||||||
// Use the previous end as NEW start.
|
// Use the previous end as NEW start.
|
||||||
const long s0 = previous->mS1;
|
const auto s0 = previous->mS1;
|
||||||
Duration dd { *this };
|
Duration dd { *this };
|
||||||
const auto &origDuration = dd.duration;
|
const auto &origDuration = dd.duration;
|
||||||
if (origDuration <= 0)
|
if (origDuration <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto actualDuration = origDuration;
|
auto actualDuration = origDuration;
|
||||||
const long s1 = options.enqueueBySpeed
|
const sampleCount s1 = options.enqueueBySpeed
|
||||||
? s0 + lrint(origDuration * end) // end is a speed
|
? s0 + lrint(origDuration * end) // end is a speed
|
||||||
: lrint(end * mRate); // end is a time
|
: lrint(end * mRate); // end is a time
|
||||||
auto success =
|
auto success =
|
||||||
@ -487,7 +487,8 @@ struct AudioIO::ScrubQueue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transformer(long &startSample, long &endSample, long &duration,
|
void Transformer(sampleCount &startSample, sampleCount &endSample,
|
||||||
|
sampleCount &duration,
|
||||||
Maybe<wxMutexLocker> &cleanup)
|
Maybe<wxMutexLocker> &cleanup)
|
||||||
{
|
{
|
||||||
// Audio thread is ready for the next interval.
|
// Audio thread is ready for the next interval.
|
||||||
@ -537,7 +538,7 @@ struct AudioIO::ScrubQueue
|
|||||||
auto &start = entry.mS0;
|
auto &start = entry.mS0;
|
||||||
const auto end = entry.mS1;
|
const auto end = entry.mS1;
|
||||||
const auto ratio = static_cast<double>(toDiscard) / static_cast<double>(dur);
|
const auto ratio = static_cast<double>(toDiscard) / static_cast<double>(dur);
|
||||||
const auto adjustment = static_cast<long>(std::abs(end - start) * ratio);
|
const sampleCount adjustment = std::abs(end - start) * ratio;
|
||||||
if (start <= end)
|
if (start <= end)
|
||||||
start += adjustment;
|
start += adjustment;
|
||||||
else
|
else
|
||||||
@ -584,7 +585,7 @@ struct AudioIO::ScrubQueue
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
Entry *pEntry = &mEntries[mTrailingIdx];
|
Entry *pEntry = &mEntries[mTrailingIdx];
|
||||||
unsigned long remaining = pEntry->mDuration - pEntry->mPlayed;
|
auto remaining = pEntry->mDuration - pEntry->mPlayed;
|
||||||
if (frames >= remaining)
|
if (frames >= remaining)
|
||||||
{
|
{
|
||||||
frames -= remaining;
|
frames -= remaining;
|
||||||
@ -614,8 +615,8 @@ private:
|
|||||||
, mPlayed(0)
|
, mPlayed(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool Init(Entry *previous, long s0, long s1,
|
bool Init(Entry *previous, sampleCount s0, sampleCount s1,
|
||||||
long &duration /* in/out */,
|
sampleCount &duration /* in/out */,
|
||||||
const ScrubbingOptions &options)
|
const ScrubbingOptions &options)
|
||||||
{
|
{
|
||||||
const bool &adjustStart = options.adjustStart;
|
const bool &adjustStart = options.adjustStart;
|
||||||
@ -671,7 +672,7 @@ private:
|
|||||||
if (adjustedSpeed && !adjustStart)
|
if (adjustedSpeed && !adjustStart)
|
||||||
{
|
{
|
||||||
// adjust s1
|
// adjust s1
|
||||||
const long diff = lrint(speed * duration);
|
const sampleCount diff = lrint(speed * duration);
|
||||||
if (s0 < s1)
|
if (s0 < s1)
|
||||||
s1 = s0 + diff;
|
s1 = s0 + diff;
|
||||||
else
|
else
|
||||||
@ -685,11 +686,11 @@ private:
|
|||||||
// (Assume s0 is in bounds, because it equals the last scrub's s1 which was checked.)
|
// (Assume s0 is in bounds, because it equals the last scrub's s1 which was checked.)
|
||||||
if (s1 != s0)
|
if (s1 != s0)
|
||||||
{
|
{
|
||||||
long newDuration = duration;
|
auto newDuration = duration;
|
||||||
const long newS1 = std::max(options.minSample, std::min(options.maxSample, s1));
|
const auto newS1 = std::max(options.minSample, std::min(options.maxSample, s1));
|
||||||
if(s1 != newS1)
|
if(s1 != newS1)
|
||||||
newDuration = std::max(0L,
|
newDuration = std::max<sampleCount>(0,
|
||||||
static_cast<long>(duration * static_cast<double>(newS1 - s0) / (s1 - s0))
|
(duration * double(newS1 - s0) / (s1 - s0))
|
||||||
);
|
);
|
||||||
// When playback follows a fast mouse movement by "stuttering"
|
// When playback follows a fast mouse movement by "stuttering"
|
||||||
// at maximum playback, don't make stutters too short to be useful.
|
// at maximum playback, don't make stutters too short to be useful.
|
||||||
@ -710,7 +711,8 @@ private:
|
|||||||
if (adjustStart && !silent)
|
if (adjustStart && !silent)
|
||||||
{
|
{
|
||||||
// Limit diff because this is seeking.
|
// Limit diff because this is seeking.
|
||||||
const long diff = lrint(std::min(options.maxSpeed, speed) * duration);
|
const sampleCount diff =
|
||||||
|
lrint(std::min(options.maxSpeed, speed) * duration);
|
||||||
if (s0 < s1)
|
if (s0 < s1)
|
||||||
s0 = s1 - diff;
|
s0 = s1 - diff;
|
||||||
else
|
else
|
||||||
@ -724,7 +726,7 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitSilent(const Entry &previous, long duration)
|
void InitSilent(const Entry &previous, sampleCount duration)
|
||||||
{
|
{
|
||||||
mGoal = previous.mGoal;
|
mGoal = previous.mGoal;
|
||||||
mS0 = mS1 = previous.mS1;
|
mS0 = mS1 = previous.mS1;
|
||||||
@ -741,20 +743,20 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// These sample counts are initialized in the UI, producer, thread:
|
// These sample counts are initialized in the UI, producer, thread:
|
||||||
long mS0;
|
sampleCount mS0;
|
||||||
long mS1;
|
sampleCount mS1;
|
||||||
long mGoal;
|
sampleCount mGoal;
|
||||||
// This field is initialized in the UI thread too, and
|
// This field is initialized in the UI thread too, and
|
||||||
// this work queue item corresponds to exactly this many samples of
|
// this work queue item corresponds to exactly this many samples of
|
||||||
// playback output:
|
// playback output:
|
||||||
long mDuration;
|
sampleCount mDuration;
|
||||||
|
|
||||||
// The middleman Audio thread does not change these entries, but only
|
// The middleman Audio thread does not change these entries, but only
|
||||||
// changes indices in the queue structure.
|
// changes indices in the queue structure.
|
||||||
|
|
||||||
// This increases from 0 to mDuration as the PortAudio, consumer,
|
// This increases from 0 to mDuration as the PortAudio, consumer,
|
||||||
// thread catches up. When they are equal, this entry can be discarded:
|
// thread catches up. When they are equal, this entry can be discarded:
|
||||||
long mPlayed;
|
sampleCount mPlayed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Duration {
|
struct Duration {
|
||||||
@ -769,7 +771,7 @@ private:
|
|||||||
|
|
||||||
ScrubQueue &queue;
|
ScrubQueue &queue;
|
||||||
const wxLongLong clockTime { ::wxGetLocalTimeMillis() };
|
const wxLongLong clockTime { ::wxGetLocalTimeMillis() };
|
||||||
const long duration { static_cast<long>
|
const sampleCount duration { static_cast<long long>
|
||||||
(queue.mRate * (clockTime - queue.mLastScrubTimeMillis).ToDouble() / 1000.0)
|
(queue.mRate * (clockTime - queue.mLastScrubTimeMillis).ToDouble() / 1000.0)
|
||||||
};
|
};
|
||||||
bool cancelled { false };
|
bool cancelled { false };
|
||||||
@ -784,8 +786,8 @@ private:
|
|||||||
wxLongLong mLastScrubTimeMillis;
|
wxLongLong mLastScrubTimeMillis;
|
||||||
|
|
||||||
wxLongLong mLastTransformerTimeMillis { -1LL };
|
wxLongLong mLastTransformerTimeMillis { -1LL };
|
||||||
long mCredit { 0L };
|
sampleCount mCredit { 0 };
|
||||||
long mDebt { 0L };
|
sampleCount mDebt { 0 };
|
||||||
const long mMaxDebt;
|
const long mMaxDebt;
|
||||||
|
|
||||||
mutable wxMutex mUpdating;
|
mutable wxMutex mUpdating;
|
||||||
@ -3494,12 +3496,12 @@ void AudioIO::FillBuffers()
|
|||||||
Maybe<wxMutexLocker> cleanup;
|
Maybe<wxMutexLocker> cleanup;
|
||||||
do {
|
do {
|
||||||
// How many samples to produce for each channel.
|
// How many samples to produce for each channel.
|
||||||
long frames = available;
|
size_t frames = available;
|
||||||
bool progress = true;
|
bool progress = true;
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
if (mPlayMode == PLAY_SCRUB)
|
if (mPlayMode == PLAY_SCRUB)
|
||||||
// scrubbing does not use warped time and length
|
// scrubbing does not use warped time and length
|
||||||
frames = std::min(frames, mScrubDuration);
|
frames = limitSampleBufferSize(frames, mScrubDuration);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@ -3513,8 +3515,6 @@ void AudioIO::FillBuffers()
|
|||||||
!(mPlayMode == PLAY_LOOPED &&
|
!(mPlayMode == PLAY_LOOPED &&
|
||||||
mWarpedTime == 0.0 && frames == 0);
|
mWarpedTime == 0.0 && frames == 0);
|
||||||
mWarpedTime = mWarpedLength;
|
mWarpedTime = mWarpedLength;
|
||||||
if (frames < 0) // this should never happen
|
|
||||||
frames = 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mWarpedTime += deltat;
|
mWarpedTime += deltat;
|
||||||
@ -3577,7 +3577,7 @@ void AudioIO::FillBuffers()
|
|||||||
done = (available == 0);
|
done = (available == 0);
|
||||||
if (!done && mScrubDuration <= 0)
|
if (!done && mScrubDuration <= 0)
|
||||||
{
|
{
|
||||||
long startSample, endSample;
|
sampleCount startSample, endSample;
|
||||||
mScrubQueue->Transformer(startSample, endSample, mScrubDuration, cleanup);
|
mScrubQueue->Transformer(startSample, endSample, mScrubDuration, cleanup);
|
||||||
if (mScrubDuration < 0)
|
if (mScrubDuration < 0)
|
||||||
{
|
{
|
||||||
|
@ -688,7 +688,7 @@ private:
|
|||||||
std::unique_ptr<ScrubQueue> mScrubQueue;
|
std::unique_ptr<ScrubQueue> mScrubQueue;
|
||||||
|
|
||||||
bool mSilentScrub;
|
bool mSilentScrub;
|
||||||
long mScrubDuration;
|
sampleCount mScrubDuration;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ Paul Licameli split from TrackPanel.cpp
|
|||||||
|
|
||||||
#include "../../Experimental.h"
|
#include "../../Experimental.h"
|
||||||
#include "../../widgets/Overlay.h"
|
#include "../../widgets/Overlay.h"
|
||||||
|
#include "../../../include/audacity/Types.h"
|
||||||
|
|
||||||
class AudacityProject;
|
class AudacityProject;
|
||||||
|
|
||||||
@ -37,8 +38,8 @@ struct ScrubbingOptions {
|
|||||||
bool adjustStart {};
|
bool adjustStart {};
|
||||||
|
|
||||||
// usually from TrackList::GetEndTime()
|
// usually from TrackList::GetEndTime()
|
||||||
long maxSample {};
|
sampleCount maxSample {};
|
||||||
long minSample {};
|
sampleCount minSample {};
|
||||||
|
|
||||||
bool enqueueBySpeed {};
|
bool enqueueBySpeed {};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user