1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-21 14:02:57 +02:00

Fewer calls to RingBuffer::Put in case of trailing zeroes...

... so there is only one update per track of the atomics in RingBuffer in each
pass of the loop in FillBuffers, which will be needed to synchronize RingBuffer
and TimeQueue correctly.
This commit is contained in:
Paul Licameli
2018-08-13 18:05:11 -04:00
parent b2df5e0673
commit 389ab0c8d0
4 changed files with 33 additions and 44 deletions

View File

@@ -3987,10 +3987,12 @@ void AudioIO::FillBuffers()
// How many samples to produce for each channel.
auto frames = available;
bool progress = true;
auto toProcess = frames;
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
if (mPlaybackSchedule.Interactive())
// scrubbing and play-at-speed are not limited by the real time
// and length accumulators
toProcess =
frames = limitSampleBufferSize(frames, mScrubDuration);
else
#endif
@@ -3999,6 +4001,7 @@ void AudioIO::FillBuffers()
if (deltat > realTimeRemaining)
{
frames = realTimeRemaining * mRate;
toProcess = frames;
// Don't fall into an infinite loop, if loop-playing a selection
// that is so short, it has no samples: detect that case
progress =
@@ -4012,53 +4015,29 @@ void AudioIO::FillBuffers()
}
if (!progress)
frames = available;
frames = available, toProcess = 0;
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
else if ( mPlaybackSchedule.Interactive() && mSilentScrub)
toProcess = 0;
#endif
for (i = 0; i < mPlaybackTracks.size(); i++)
{
// The mixer here isn't actually mixing: it's just doing
// resampling, format conversion, and possibly time track
// warping
decltype(mPlaybackMixers[i]->Process(frames))
processed = 0;
samplePtr warpedSamples;
//don't do anything if we have no length. In particular, Process() will fail an wxAssert
//that causes a crash since this is not the GUI thread and wxASSERT is a GUI call.
// don't generate either if scrubbing at zero speed.
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
const bool silent =
mPlaybackSchedule.Interactive() && mSilentScrub;
#else
const bool silent = false;
#endif
if (progress && !silent && frames > 0)
if (frames > 0)
{
processed = mPlaybackMixers[i]->Process(frames);
wxASSERT(processed <= frames);
size_t processed = 0;
if ( toProcess )
processed = mPlaybackMixers[i]->Process( toProcess );
//wxASSERT(processed <= toProcess);
warpedSamples = mPlaybackMixers[i]->GetBuffer();
const auto put = mPlaybackBuffers[i]->Put
(warpedSamples, floatSample, processed);
// wxASSERT(put == processed);
// but we can't assert in this thread
wxUnusedVar(put);
}
//if looping and processed is less than the full chunk/block/buffer that gets pulled from
//other longer tracks, then we still need to advance the ring buffers or
//we'll trip up on ourselves when we start them back up again.
//if not looping we never start them up again, so its okay to not do anything
// If scrubbing, we may be producing some silence. Otherwise this should not happen,
// but makes sure anyway that we produce equal
// numbers of samples for all channels for this pass of the do-loop.
if(processed < frames && !mPlaybackSchedule.PlayingStraight())
{
mSilentBuf.Resize(frames, floatSample);
ClearSamples(mSilentBuf.ptr(), floatSample, 0, frames);
const auto put = mPlaybackBuffers[i]->Put
(mSilentBuf.ptr(), floatSample, frames - processed);
// wxASSERT(put == frames - processed);
const auto put = mPlaybackBuffers[i]->Put(
warpedSamples, floatSample, processed, frames - processed);
// wxASSERT(put == frames);
// but we can't assert in this thread
wxUnusedVar(put);
}

View File

@@ -778,8 +778,6 @@ private:
bool mInputMixerWorks;
float mMixerOutputVol;
GrowableSampleBuffer mSilentBuf;
AudioIOListener* mListener;
friend class AudioThread;

View File

@@ -69,16 +69,18 @@ size_t RingBuffer::AvailForPut()
}
size_t RingBuffer::Put(samplePtr buffer, sampleFormat format,
size_t samplesToCopy)
size_t samplesToCopy, size_t padding)
{
auto start = mStart.load( std::memory_order_acquire );
auto end = mEnd.load( std::memory_order_relaxed );
samplesToCopy = std::min( samplesToCopy, Free( start, end ) );
const auto free = Free( start, end );
samplesToCopy = std::min( samplesToCopy, free );
padding = std::min( padding, free - samplesToCopy );
auto src = buffer;
size_t copied = 0;
auto pos = end;
while(samplesToCopy) {
while ( samplesToCopy ) {
auto block = std::min( samplesToCopy, mBufferSize - pos );
CopySamples(src, format,
@@ -91,6 +93,14 @@ size_t RingBuffer::Put(samplePtr buffer, sampleFormat format,
copied += block;
}
while ( padding ) {
const auto block = std::min( padding, mBufferSize - pos );
ClearSamples( mBuffer.ptr(), mFormat, pos, block );
pos = (pos + block) % mBufferSize;
padding -= block;
copied += block;
}
// Atomically update the end pointer with release, so the nonatomic writes
// just done to the buffer don't get reordered after
mEnd.store(pos, std::memory_order_release);

View File

@@ -24,7 +24,9 @@ class RingBuffer {
//
size_t AvailForPut();
size_t Put(samplePtr buffer, sampleFormat format, size_t samples);
size_t Put(samplePtr buffer, sampleFormat format, size_t samples,
// optional number of trailing zeroes
size_t padding = 0);
size_t Clear(sampleFormat format, size_t samples);
//