mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-01 08:29:27 +02:00
Explicit scrub shut-down signal replaces the "nudge"
This commit is contained in:
parent
303ac9367a
commit
4e461f8755
@ -549,15 +549,6 @@ struct AudioIO::ScrubState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is for avoiding deadlocks while starting a scrub:
|
|
||||||
// Audio stream needs to be unblocked
|
|
||||||
void Nudge()
|
|
||||||
{
|
|
||||||
wxMutexLocker locker(mUpdating);
|
|
||||||
mNudged = true;
|
|
||||||
mAvailable.Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Update(double end, const ScrubbingOptions &options)
|
bool Update(double end, const ScrubbingOptions &options)
|
||||||
{
|
{
|
||||||
// Main thread indicates a scrubbing interval
|
// Main thread indicates a scrubbing interval
|
||||||
@ -617,14 +608,14 @@ struct AudioIO::ScrubState
|
|||||||
if (!cleanup) {
|
if (!cleanup) {
|
||||||
cleanup.create(mUpdating);
|
cleanup.create(mUpdating);
|
||||||
}
|
}
|
||||||
while(!mNudged && mMiddleIdx == mLeadingIdx)
|
while(! mStopped.load( std::memory_order_relaxed )&&
|
||||||
|
mMiddleIdx == mLeadingIdx)
|
||||||
mAvailable.Wait();
|
mAvailable.Wait();
|
||||||
|
|
||||||
mNudged = false;
|
|
||||||
|
|
||||||
auto now = ::wxGetLocalTimeMillis();
|
auto now = ::wxGetLocalTimeMillis();
|
||||||
|
|
||||||
if (mMiddleIdx != mLeadingIdx) {
|
if ( ! mStopped.load( std::memory_order_relaxed ) &&
|
||||||
|
mMiddleIdx != mLeadingIdx ) {
|
||||||
Data &entry = mEntries[mMiddleIdx];
|
Data &entry = mEntries[mMiddleIdx];
|
||||||
if (entry.mDuration > 0) {
|
if (entry.mDuration > 0) {
|
||||||
// First use of the entry
|
// First use of the entry
|
||||||
@ -646,11 +637,18 @@ struct AudioIO::ScrubState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We got the shut-down signal, or we got nudged, or we discarded all the work.
|
// We got the shut-down signal, or we discarded all the work.
|
||||||
startSample = endSample = duration = -1L;
|
startSample = endSample = duration = -1L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
mStopped.store( true, std::memory_order_relaxed );
|
||||||
|
wxMutexLocker locker(mUpdating);
|
||||||
|
mAvailable.Signal();
|
||||||
|
}
|
||||||
|
|
||||||
double LastTrackTime() const
|
double LastTrackTime() const
|
||||||
{
|
{
|
||||||
// Needed by the main thread sometimes
|
// Needed by the main thread sometimes
|
||||||
@ -832,12 +830,12 @@ private:
|
|||||||
unsigned mTrailingIdx;
|
unsigned mTrailingIdx;
|
||||||
unsigned mMiddleIdx;
|
unsigned mMiddleIdx;
|
||||||
unsigned mLeadingIdx;
|
unsigned mLeadingIdx;
|
||||||
|
std::atomic<bool> mStopped { false };
|
||||||
const double mRate;
|
const double mRate;
|
||||||
wxLongLong mLastScrubTimeMillis;
|
wxLongLong mLastScrubTimeMillis;
|
||||||
|
|
||||||
mutable wxMutex mUpdating;
|
mutable wxMutex mUpdating;
|
||||||
mutable wxCondition mAvailable { mUpdating };
|
mutable wxCondition mAvailable { mUpdating };
|
||||||
bool mNudged { false };
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2006,9 +2004,17 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
|||||||
mAudioThreadShouldCallFillBuffersOnce = true;
|
mAudioThreadShouldCallFillBuffersOnce = true;
|
||||||
|
|
||||||
while( mAudioThreadShouldCallFillBuffersOnce ) {
|
while( mAudioThreadShouldCallFillBuffersOnce ) {
|
||||||
if (mScrubState)
|
#ifndef USE_SCRUB_THREAD
|
||||||
mScrubState->Nudge();
|
// Yuck, we either have to poll "by hand" when scrub polling doesn't
|
||||||
wxMilliSleep( 50 );
|
// work with a thread, or else yield to timer messages, but that would
|
||||||
|
// execute too much else
|
||||||
|
if (mScrubState) {
|
||||||
|
mOwningProject->GetScrubber().ContinueScrubbingPoll();
|
||||||
|
wxMilliSleep( Scrubber::ScrubPollInterval_ms );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
wxMilliSleep( 50 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mNumPlaybackChannels > 0 || mNumCaptureChannels > 0) {
|
if(mNumPlaybackChannels > 0 || mNumCaptureChannels > 0) {
|
||||||
@ -2513,8 +2519,6 @@ void AudioIO::StopStream()
|
|||||||
//
|
//
|
||||||
|
|
||||||
mAudioThreadFillBuffersLoopRunning = false;
|
mAudioThreadFillBuffersLoopRunning = false;
|
||||||
if (mScrubState)
|
|
||||||
mScrubState->Nudge();
|
|
||||||
|
|
||||||
// Audacity can deadlock if it tries to update meters while
|
// Audacity can deadlock if it tries to update meters while
|
||||||
// we're stopping PortAudio (because the meter updating code
|
// we're stopping PortAudio (because the meter updating code
|
||||||
@ -2622,8 +2626,6 @@ void AudioIO::StopStream()
|
|||||||
{
|
{
|
||||||
// LLL: Experienced recursive yield here...once.
|
// LLL: Experienced recursive yield here...once.
|
||||||
wxGetApp().Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error.
|
wxGetApp().Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error.
|
||||||
if (mScrubState)
|
|
||||||
mScrubState->Nudge();
|
|
||||||
wxMilliSleep( 50 );
|
wxMilliSleep( 50 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2768,6 +2770,12 @@ bool AudioIO::UpdateScrub
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioIO::StopScrub()
|
||||||
|
{
|
||||||
|
if (mScrubState)
|
||||||
|
mScrubState->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
double AudioIO::GetLastScrubTime() const
|
double AudioIO::GetLastScrubTime() const
|
||||||
{
|
{
|
||||||
if (mScrubState)
|
if (mScrubState)
|
||||||
|
@ -261,6 +261,8 @@ class AUDACITY_DLL_API AudioIO final {
|
|||||||
*/
|
*/
|
||||||
bool UpdateScrub(double endTimeOrSpeed, const ScrubbingOptions &options);
|
bool UpdateScrub(double endTimeOrSpeed, const ScrubbingOptions &options);
|
||||||
|
|
||||||
|
void StopScrub();
|
||||||
|
|
||||||
/** \brief return the ending time of the last scrub interval.
|
/** \brief return the ending time of the last scrub interval.
|
||||||
*/
|
*/
|
||||||
double GetLastScrubTime() const;
|
double GetLastScrubTime() const;
|
||||||
|
@ -51,9 +51,7 @@ enum {
|
|||||||
ScrubSpeedStepsPerOctave = 4,
|
ScrubSpeedStepsPerOctave = 4,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ScrubPollInterval_ms = 50,
|
kOneSecondCountdown = 1000 / Scrubber::ScrubPollInterval_ms,
|
||||||
|
|
||||||
kOneSecondCountdown = 1000 / ScrubPollInterval_ms,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const double MinStutter = 0.2;
|
static const double MinStutter = 0.2;
|
||||||
@ -657,6 +655,7 @@ void Scrubber::StopPolling()
|
|||||||
|
|
||||||
void Scrubber::StopScrubbing()
|
void Scrubber::StopScrubbing()
|
||||||
{
|
{
|
||||||
|
gAudioIO->StopScrub();
|
||||||
StopPolling();
|
StopPolling();
|
||||||
|
|
||||||
if (HasMark() && !mCancelled) {
|
if (HasMark() && !mCancelled) {
|
||||||
|
@ -72,6 +72,8 @@ struct ScrubbingOptions {
|
|||||||
class Scrubber : public wxEvtHandler
|
class Scrubber : public wxEvtHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr unsigned ScrubPollInterval_ms = 50;
|
||||||
|
|
||||||
Scrubber(AudacityProject *project);
|
Scrubber(AudacityProject *project);
|
||||||
~Scrubber();
|
~Scrubber();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user