Skip to content

Commit

Permalink
Avoid frequent allocation of little vectors of pointers in stretch
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul-Licameli committed Oct 10, 2023
1 parent f1d08d1 commit 01f5e2a
Show file tree
Hide file tree
Showing 10 changed files with 31 additions and 32 deletions.
5 changes: 2 additions & 3 deletions libraries/lib-stretching-sequence/AudioSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@ class STRETCHING_SEQUENCE_API AudioSegment
/**
* @brief Fills `buffers` with as many as `numSamples` or the number of
* remaining samples, whichever is smaller.
* @param buffers A vector of pointers to buffers, one for each channel.
* @param buffers Pointers to buffers, one for each channel.
* @param numSamples The max. number of samples to write to each buffer.
* @pre `buffers.size() == GetWidth()`
* @return The number of samples actually provided in each buffer.
*/
virtual size_t
GetFloats(std::vector<float*>& buffers, size_t numSamples) = 0;
GetFloats(float *const *buffers, size_t numSamples) = 0;

/**
* @brief The number of channels in the segment.
Expand Down
5 changes: 2 additions & 3 deletions libraries/lib-stretching-sequence/ClipSegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,11 @@ ClipSegment::ClipSegment(
{
}

size_t ClipSegment::GetFloats(std::vector<float*>& buffers, size_t numSamples)
size_t ClipSegment::GetFloats(float *const *buffers, size_t numSamples)
{
assert(buffers.size() == mSource.GetWidth());
const auto numSamplesToProduce = limitSampleBufferSize(
numSamples, mTotalNumSamplesToProduce - mTotalNumSamplesProduced);
mStretcher->GetSamples(buffers.data(), numSamplesToProduce);
mStretcher->GetSamples(buffers, numSamplesToProduce);
mTotalNumSamplesProduced += numSamplesToProduce;
return numSamplesToProduce;
}
Expand Down
2 changes: 1 addition & 1 deletion libraries/lib-stretching-sequence/ClipSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class STRETCHING_SEQUENCE_API ClipSegment final : public AudioSegment
const ClipInterface&, double durationToDiscard, PlaybackDirection);

// AudioSegment
size_t GetFloats(std::vector<float*>& buffers, size_t numSamples) override;
size_t GetFloats(float *const *buffers, size_t numSamples) override;
bool Empty() const override;
size_t GetWidth() const override;

Expand Down
3 changes: 1 addition & 2 deletions libraries/lib-stretching-sequence/SilenceSegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ SilenceSegment::SilenceSegment(size_t numChannels, sampleCount numSamples)
}

size_t
SilenceSegment::GetFloats(std::vector<float*>& buffers, size_t numSamples)
SilenceSegment::GetFloats(float *const *buffers, size_t numSamples)
{
assert(buffers.size() == mNumChannels);
const size_t numSamplesToProduce =
std::min<long long>(mNumRemainingSamples.as_long_long(), numSamples);
for (auto i = 0u; i < mNumChannels; ++i)
Expand Down
2 changes: 1 addition & 1 deletion libraries/lib-stretching-sequence/SilenceSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class STRETCHING_SEQUENCE_API SilenceSegment final : public AudioSegment
{
public:
SilenceSegment(size_t numChannels, sampleCount numSamples);
size_t GetFloats(std::vector<float*>& buffers, size_t numSamples) override;
size_t GetFloats(float *const *buffers, size_t numSamples) override;
bool Empty() const override;
size_t GetWidth() const override;

Expand Down
19 changes: 11 additions & 8 deletions libraries/lib-stretching-sequence/StretchingSequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@

namespace
{
std::vector<float*>
GetOffsetBuffer(float* const* buffer, size_t numChannels, size_t offset)
#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))

void
GetOffsetBuffer(float **offsetBuffer,
float* const* buffer, size_t numChannels, size_t offset)
{
std::vector<float*> offsetBuffer(numChannels);
for (auto i = 0u; i < numChannels; ++i)
offsetBuffer[i] = buffer[i] + offset;
return offsetBuffer;
}
} // namespace

Expand Down Expand Up @@ -54,8 +55,9 @@ bool StretchingSequence::GetNext(
mActiveAudioSegmentIt != mAudioSegments.end())
{
const auto& segment = *mActiveAudioSegmentIt;
auto offsetBuffers =
GetOffsetBuffer(buffers, mSequence.NChannels(), numProcessedSamples);
const auto offsetBuffers = stackAllocate(float *, mSequence.NChannels());
GetOffsetBuffer(offsetBuffers,
buffers, mSequence.NChannels(), numProcessedSamples);
numProcessedSamples += segment->GetFloats(
offsetBuffers,
numSamples - numProcessedSamples); // No need to reverse, we feed the
Expand All @@ -67,8 +69,9 @@ bool StretchingSequence::GetNext(
const auto remaining = numSamples - numProcessedSamples;
if (remaining > 0u)
{
const auto offsetBuffers =
GetOffsetBuffer(buffers, mSequence.NChannels(), numProcessedSamples);
const auto offsetBuffers = stackAllocate(float *, mSequence.NChannels());
GetOffsetBuffer(
offsetBuffers, buffers, mSequence.NChannels(), numProcessedSamples);
for (auto i = 0u; i < mSequence.NChannels(); ++i)
std::fill(offsetBuffers[i], offsetBuffers[i] + remaining, 0.f);
}
Expand Down
4 changes: 2 additions & 2 deletions libraries/lib-stretching-sequence/tests/ClipSegmentTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ TEST_CASE("ClipSegment")
FloatVectorVector { { 1.f, 2.f, 3.f }, { -1.f, -2.f, -3.f } });
ClipSegment sut { *clip, 0., direction };
AudioContainer output(sampleRate, numChannels);
REQUIRE(sut.GetFloats(output.channelPointers, sampleRate) == sampleRate);
REQUIRE(sut.GetFloats(output.channelPointers.data(), sampleRate) == sampleRate);
if (numChannels == 1u)
{
const auto expected = direction == PlaybackDirection::forward ?
Expand Down Expand Up @@ -69,7 +69,7 @@ TEST_CASE("ClipSegment")
constexpr auto playbackOffset = 2 / static_cast<double>(sampleRate);
ClipSegment sut { *clip, playbackOffset, direction };
AudioContainer output(numSamples, 1u);
REQUIRE(sut.GetFloats(output.channelPointers, numSamples) == 3);
REQUIRE(sut.GetFloats(output.channelPointers.data(), numSamples) == 3);
const auto expected = direction == PlaybackDirection::forward ?
std::vector<float> { 3.f, 4.f, 5.f, 0.f, 0.f } :
std::vector<float> { 3.f, 2.f, 1.f, 0.f, 0.f };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
class NiceAudioSegment final : public AudioSegment
{
public:
size_t GetFloats(std::vector<float*>&, size_t numSamples) override
size_t GetFloats(float *const *, size_t numSamples) override
{
return numSamples;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ TEST_CASE("SilenceSegment", "behaves as expected")
SilenceSegment sut(numChannels, silenceSegmentLength);
REQUIRE(!sut.Empty());
AudioContainer container(3u, numChannels);
REQUIRE(sut.GetFloats(container.channelPointers, 1) == 1);
REQUIRE(sut.GetFloats(container.channelPointers.data(), 1) == 1);
REQUIRE(!sut.Empty());
REQUIRE(sut.GetFloats(container.channelPointers, 3) == 2);
REQUIRE(sut.GetFloats(container.channelPointers.data(), 3) == 2);
REQUIRE(sut.Empty());
}
17 changes: 8 additions & 9 deletions libraries/lib-time-and-pitch/StaffPadTimeAndPitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ namespace
// to be specified in the `setup` call.)
constexpr auto maxBlockSize = 1024;

std::vector<float*>
GetOffsetBuffer(float* const* buffer, size_t numChannels, size_t offset)
#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))

void
GetOffsetBuffer(float **offsetBuffer,
float* const* buffer, size_t numChannels, size_t offset)
{
std::vector<float*> offsetBuffer(numChannels);
for (auto i = 0u; i < numChannels; ++i)
{
offsetBuffer[i] = buffer[i] + offset;
}
return offsetBuffer;
}

std::unique_ptr<staffpad::TimeAndPitch> MaybeCreateTimeAndPitch(
Expand Down Expand Up @@ -82,9 +81,9 @@ void StaffPadTimeAndPitch::GetSamples(float* const* output, size_t outputLen)
const auto numSamplesToGet =
std::min({ maxBlockSize, numOutputSamplesAvailable,
static_cast<int>(outputLen - numOutputSamples) });
const auto buffer =
GetOffsetBuffer(output, mNumChannels, numOutputSamples);
mTimeAndPitch->retrieveAudio(buffer.data(), numSamplesToGet);
const auto buffer = stackAllocate(float*, mNumChannels);
GetOffsetBuffer(buffer, output, mNumChannels, numOutputSamples);
mTimeAndPitch->retrieveAudio(buffer, numSamplesToGet);
numOutputSamplesAvailable -= numSamplesToGet;
numOutputSamples += numSamplesToGet;
}
Expand Down

0 comments on commit 01f5e2a

Please sign in to comment.