Skip to content

Commit

Permalink
Preallocate scratch buffers in the main thread before playback...
Browse files Browse the repository at this point in the history
... These can be big buffers on the free store, bigger than alloca calls allow,
so the non-realtime worker thread might do big batches of work, maybe more
economically

(cherry picked from commit d452ab9;
modified for Tenacity)
Signed-off-by: Avery King <[email protected]>
  • Loading branch information
Paul-Licameli authored and generic-pers0n committed Aug 27, 2024
1 parent 16f72bc commit 240c3f0
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 13 deletions.
12 changes: 12 additions & 0 deletions libraries/lib-math/SampleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ class SampleBuffer {
{
Free();
}
SampleBuffer(SampleBuffer &&other)
{
mPtr = other.mPtr;
other.mPtr = nullptr;
}
SampleBuffer &operator=(SampleBuffer &&other)
{
auto ptr = other.mPtr;
other.mPtr = nullptr;
mPtr = ptr;
return *this;
}

// WARNING! May not preserve contents.
SampleBuffer &Allocate(size_t count, sampleFormat format)
Expand Down
37 changes: 26 additions & 11 deletions src/AudioIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,8 @@ int AudioIO::StartStream(const TransportTracks &tracks,
});

mPlaybackBuffers.reset();
mScratchBuffers.clear();
mScratchPointers.clear();
mPlaybackMixers.clear();
mCaptureBuffers.reset();
mResample.reset();
Expand Down Expand Up @@ -949,6 +951,16 @@ bool AudioIO::AllocateBuffers(
// Always make at least one playback buffer
mPlaybackBuffers.reinit(
std::max<size_t>(1, mPlaybackTracks.size()));
// Number of scratch buffers depends on device playback channels
if (mNumPlaybackChannels > 0) {
mScratchBuffers.resize(mNumPlaybackChannels * 2);
mScratchPointers.clear();
for (auto &buffer : mScratchBuffers) {
buffer.Allocate(playbackBufferSize, floatSample);
mScratchPointers.push_back(
reinterpret_cast<float*>(buffer.ptr()));
}
}
mPlaybackMixers.clear();
mPlaybackMixers.resize(mPlaybackTracks.size());

Expand Down Expand Up @@ -1071,6 +1083,8 @@ void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
mpTransportState.reset();

mPlaybackBuffers.reset();
mScratchBuffers.clear();
mScratchPointers.clear();
mPlaybackMixers.clear();
mCaptureBuffers.reset();
mResample.reset();
Expand Down Expand Up @@ -1218,6 +1232,8 @@ void AudioIO::StopStream()
if (mPlaybackTracks.size() > 0)
{
mPlaybackBuffers.reset();
mScratchBuffers.clear();
mScratchPointers.clear();
mPlaybackMixers.clear();
mPlaybackSchedule.mTimeQueue.mData.reset();
}
Expand Down Expand Up @@ -1929,11 +1945,11 @@ void AudioIoCallback::UpdateBuffers()
mTrackChannelsBuffer.resize(channels);
}

mScratchBufferAllocator.DeallocateAll();
mScratchBuffers.resize(mNumPlaybackChannels);
for (auto& buffer : mScratchBuffers)
mAudioScratchBufferAllocator.DeallocateAll();
mAudioScratchBuffers.resize(mNumPlaybackChannels);
for (auto& buffer : mAudioScratchBuffers)
{
buffer = mScratchBufferAllocator.Allocate(true, newBufferSize);
buffer = mAudioScratchBufferAllocator.Allocate(true, newBufferSize);
}

mBuffersPrepared = true;
Expand Down Expand Up @@ -2031,8 +2047,7 @@ bool AudioIoCallback::FillOutputBuffers(
if ( lastChannel && (numPlaybackChannels>1))
{
// TODO: more-than-two-channels
auto buf = mScratchBuffers[1];
memset(buf, 0, framesPerBuffer * sizeof(float));
memset(mAudioScratchBuffers[1], 0, framesPerBuffer * sizeof(float));
}
drop = TrackShouldBeSilent( *vt );
dropQuickly = drop;
Expand All @@ -2051,7 +2066,7 @@ bool AudioIoCallback::FillOutputBuffers(
}
else
{
len = mPlaybackBuffers[t]->Get((samplePtr)mScratchBuffers[chanCnt],
len = mPlaybackBuffers[t]->Get((samplePtr)mAudioScratchBuffers[chanCnt],
floatSample,
toGet);
// assert( len == toGet );
Expand All @@ -2063,7 +2078,7 @@ bool AudioIoCallback::FillOutputBuffers(
// real-time demand in this thread (see bug 1932). We
// must supply something to the sound card, so pad it with
// zeroes and not random garbage.
memset((void*)&mScratchBuffers[chanCnt][len], 0,
memset((void*)&mAudioScratchBuffers[chanCnt][len], 0,
(framesPerBuffer - len) * sizeof(float));
}
chanCnt++;
Expand All @@ -2087,7 +2102,7 @@ bool AudioIoCallback::FillOutputBuffers(
// Do realtime effects
if( !dropQuickly && len > 0 ) {
if (pScope)
pScope->Process(mTrackChannelsBuffer[0], mScratchBuffers.data(), len);
pScope->Process(mTrackChannelsBuffer[0], mAudioScratchBuffers.data(), len);
// Mix the results with the existing output (software playthrough) and
// apply panning. If post panning effects are desired, the panning would
// need to be be split out from the mixing and applied in a separate step.
Expand All @@ -2110,12 +2125,12 @@ bool AudioIoCallback::FillOutputBuffers(
if (vt->GetChannelIgnoringPan() == Track::LeftChannel ||
vt->GetChannelIgnoringPan() == Track::MonoChannel )
AddToOutputChannel( 0, outputMeterFloats, outputFloats,
mScratchBuffers[c], drop, len, *vt);
mAudioScratchBuffers[c], drop, len, *vt);

if (vt->GetChannelIgnoringPan() == Track::RightChannel ||
vt->GetChannelIgnoringPan() == Track::MonoChannel )
AddToOutputChannel( 1, outputMeterFloats, outputFloats,
mScratchBuffers[c], drop, len, *vt);
mAudioScratchBuffers[c], drop, len, *vt);
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/AudioIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ class TENACITY_DLL_API AudioIoCallback /* not final */

// Buffers
std::vector<WaveTrack*> mTrackChannelsBuffer;
std::vector<float*> mScratchBuffers;
AutoAllocator<float> mScratchBufferAllocator;
std::vector<float*> mAudioScratchBuffers;
AutoAllocator<float> mAudioScratchBufferAllocator;
std::shared_ptr<float> mTemporaryBuffer;

// Bufer preparation status
Expand All @@ -263,6 +263,9 @@ class TENACITY_DLL_API AudioIoCallback /* not final */
WaveTrackArray mCaptureTracks;
ArrayOf<std::unique_ptr<RingBuffer>> mPlaybackBuffers;
WaveTrackArray mPlaybackTracks;
// Temporary buffers, each as large as the playback buffers
std::vector<SampleBuffer> mScratchBuffers;
std::vector<float *> mScratchPointers; //!< pointing into mScratchBuffers

std::vector<std::unique_ptr<Mixer>> mPlaybackMixers;
static int mNextStreamToken;
Expand Down

0 comments on commit 240c3f0

Please sign in to comment.