From 9c17201c634f3da1a7a51da140719392ea275537 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 30 Mar 2020 15:14:33 +0200 Subject: [PATCH] Avoid shared pointers and get a span "pointer" directly from the buffer pool --- src/sfizz/BufferPool.h | 179 +++++++++++++++++++++-------------------- src/sfizz/Config.h | 2 +- src/sfizz/MidiState.h | 6 +- src/sfizz/Synth.cpp | 20 ++--- src/sfizz/Voice.cpp | 176 +++++++++++++++++++--------------------- 5 files changed, 188 insertions(+), 195 deletions(-) diff --git a/src/sfizz/BufferPool.h b/src/sfizz/BufferPool.h index 752cdfce..0d35f73a 100644 --- a/src/sfizz/BufferPool.h +++ b/src/sfizz/BufferPool.h @@ -11,141 +11,122 @@ #include "AudioBuffer.h" #include #include +#include +#include "absl/algorithm/container.h" #ifndef NDEBUG - #include "absl/algorithm/container.h" #include "MathHelpers.h" #endif namespace sfz { +template +class SpanHolder +{ +public: + SpanHolder() {} + SpanHolder(const SpanHolder&) = delete; + SpanHolder& operator=(const SpanHolder&) = delete; + SpanHolder(SpanHolder&&) = delete; + SpanHolder& operator=(SpanHolder&&) = delete; + SpanHolder(T value, int* available) + : value(std::move(value)), available(available) {} + T& operator*() { return value; } + T* operator->() { return &value; } + operator bool() const { return available != nullptr; } + ~SpanHolder() + { + if (available) + *available += 1; + } +private: + T value {}; + int* available { nullptr }; +}; + class BufferPool { public: BufferPool() { - for (auto& buffer : buffers) { - buffer = std::make_shared>(config::defaultSamplesPerBlock); - } - - for (auto& buffer : indexBuffers) { - buffer = std::make_shared>(config::defaultSamplesPerBlock); - } - for (auto& buffer : stereoBuffers) { - buffer = std::make_shared>(2, config::defaultSamplesPerBlock); + buffer.addChannels(2); } + monoAvailable.resize(config::bufferPoolSize); + stereoAvailable.resize(config::stereoBufferPoolSize); + indexAvailable.resize(config::indexBufferPoolSize); + _setBufferSize(config::defaultSamplesPerBlock); } void setBufferSize(unsigned bufferSize) { - for (auto& buffer: buffers) { - // Trying to resize a buffer in use - ASSERT(buffer.use_count() == 1); - buffer->resize(bufferSize); - } - - for (auto& buffer: indexBuffers) { - // Trying to resize a buffer in use - ASSERT(buffer.use_count() == 1); - buffer->resize(bufferSize); - } - - for (auto& buffer: stereoBuffers) { - // Trying to resize a buffer in use - ASSERT(buffer.use_count() == 1); - buffer->resize(bufferSize); - } + ASSERT(absl::c_all_of(monoAvailable, [](int value) { return value == 1; })); + ASSERT(absl::c_all_of(indexAvailable, [](int value) { return value == 1; })); + ASSERT(absl::c_all_of(stereoAvailable, [](int value) { return value == 1; })); + _setBufferSize(bufferSize); } - std::shared_ptr> getBuffer(size_t numFrames) const + SpanHolder> getBuffer(size_t numFrames) { - auto bufferIt = buffers.begin(); - - if (buffers.empty()) { - DBG("[sfizz] No available buffers in the pool"); + const auto availableIt = absl::c_find(monoAvailable, 1); + if (availableIt == monoAvailable.end()) { + DBG("[sfizz] No free buffers available..."); return {}; } + const auto freeIndex = std::distance(monoAvailable.begin(), availableIt); - if (buffers[0]->size() < numFrames) { - DBG("[sfizz] Someone asked for a buffer of size " << numFrames << "; only " << buffers[0]->size() << " available..."); + if (monoBuffers[freeIndex].size() < numFrames) { + DBG("[sfizz] Someone asked for a buffer of size " << numFrames << "; only " << monoBuffers[freeIndex].size() << " available..."); return {}; } #ifndef NDEBUG - maxBuffersUsed = max(1 + absl::c_count_if(buffers, [&](const std::shared_ptr>& buffer) { - return (buffer.use_count() > 1); - }), maxBuffersUsed); + maxBuffersUsed = 1 + absl::c_count_if(monoAvailable, [](int value) { return value == 0; }); #endif - - while (bufferIt < buffers.end()) { - if (bufferIt->use_count() == 1) - return *bufferIt; - ++bufferIt; - } - - // No buffer found; debug message - DBG("[sfizz] No free buffer available!"); - return {}; + *availableIt -= 1; + return { absl::MakeSpan(monoBuffers[freeIndex]).first(numFrames), &*availableIt }; } - std::shared_ptr> getIndexBuffer(size_t numFrames) const + SpanHolder> getIndexBuffer(size_t numFrames) { - auto bufferIt = indexBuffers.begin(); - - if (indexBuffers.empty()) { + const auto availableIt = absl::c_find(indexAvailable, 1); + if (availableIt == indexAvailable.end()) { DBG("[sfizz] No available index buffers in the pool"); return {}; } + const auto freeIndex = std::distance(indexAvailable.begin(), availableIt); - if (indexBuffers[0]->size() < numFrames) { - DBG("[sfizz] Someone asked for a index buffer of size " << numFrames << "; only " << indexBuffers[0]->size() << " available..."); + if (indexBuffers[freeIndex].size() < numFrames) { + DBG("[sfizz] Someone asked for a index buffer of size " << numFrames << "; only " << indexBuffers[freeIndex].size() << " available..."); return {}; } #ifndef NDEBUG - maxIndexBuffersUsed = max(1 + absl::c_count_if(indexBuffers, [&](const std::shared_ptr>& buffer) { - return (buffer.use_count() > 1); - }), maxIndexBuffersUsed); + maxIndexBuffersUsed = 1 + absl::c_count_if(indexAvailable, [](int value) { return value == 0; }); #endif - - while (bufferIt < indexBuffers.end()) { - if (bufferIt->use_count() == 1) - return *bufferIt; - ++bufferIt; - } - - // No buffer found; debug message - DBG("[sfizz] No free index buffer available!"); - return {}; + *availableIt -= 1; + return { absl::MakeSpan(indexBuffers[freeIndex]).first(numFrames), &*availableIt }; } - std::shared_ptr> getStereoBuffer(size_t numFrames) const + SpanHolder> getStereoBuffer(size_t numFrames) { - if (stereoBuffers.empty()) { + const auto availableIt = absl::c_find(stereoAvailable, 1); + if (availableIt == stereoAvailable.end()) { DBG("[sfizz] No available stereo buffers in the pool"); return {}; } + const auto freeIndex = std::distance(stereoAvailable.begin(), availableIt); - if (stereoBuffers[0]->getNumFrames() < numFrames) { - DBG("[sfizz] Someone asked for a stereo buffer of size " << numFrames << "; only " << stereoBuffers[0]->getNumFrames() << " available..."); + if (stereoBuffers[freeIndex].getNumFrames() < numFrames) { + DBG("[sfizz] Someone asked for a stereo buffer of size " << numFrames << "; only " << stereoBuffers[freeIndex].getNumFrames() << " available..."); return {}; } -#ifndef NDEBUG - maxStereoBuffersUsed = max(1 + absl::c_count_if(stereoBuffers, [&](const std::shared_ptr>& buffer) { - return (buffer.use_count() > 1); - }), maxStereoBuffersUsed); -#endif - auto bufferIt = stereoBuffers.begin(); - while (bufferIt < stereoBuffers.end()) { - if (bufferIt->use_count() == 1) - return *bufferIt; - ++bufferIt; - } - // No buffer found; debug message - DBG("[sfizz] No free stereo buffer available!"); - return {}; +#ifndef NDEBUG + maxStereoBuffersUsed = 1 + absl::c_count_if(stereoAvailable, [](int value) { return value == 0; }); +#endif + *availableIt -= 1; + return { sfz::AudioSpan(stereoBuffers[freeIndex]).first(numFrames), &*availableIt }; } #ifndef NDEBUG @@ -156,10 +137,34 @@ public: DBG("Max stereo buffers used: " << maxStereoBuffersUsed); } #endif + + private: - std::array>, config::bufferPoolSize> buffers; - std::array>, config::bufferPoolSize> indexBuffers; - std::array>, config::stereoBufferPoolSize> stereoBuffers; + void _setBufferSize(unsigned bufferSize) + { + for (auto& buffer : monoBuffers) { + buffer.resize(bufferSize); + } + + for (auto& buffer : indexBuffers) { + buffer.resize(bufferSize); + } + + for (auto& buffer : stereoBuffers) { + buffer.resize(bufferSize); + } + + absl::c_fill(monoAvailable, 1); + absl::c_fill(stereoAvailable, 1); + absl::c_fill(indexAvailable, 1); + } + + std::array, config::bufferPoolSize> monoBuffers; + std::vector monoAvailable; + std::array, config::bufferPoolSize> indexBuffers; + std::vector indexAvailable; + std::array, config::stereoBufferPoolSize> stereoBuffers; + std::vector stereoAvailable; #ifndef NDEBUG mutable int maxBuffersUsed { 0 }; mutable int maxIndexBuffersUsed { 0 }; diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 59aeec21..a7c67223 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -28,7 +28,7 @@ namespace config { constexpr float defaultSampleRate { 48000 }; constexpr int defaultSamplesPerBlock { 1024 }; constexpr int maxBlockSize { 8192 }; - constexpr int bufferPoolSize { 8 }; + constexpr int bufferPoolSize { 4 }; constexpr int stereoBufferPoolSize { 4 }; constexpr int indexBufferPoolSize { 2 }; constexpr int preloadSize { 8192 }; diff --git a/src/sfizz/MidiState.h b/src/sfizz/MidiState.h index 18305e40..9b028527 100644 --- a/src/sfizz/MidiState.h +++ b/src/sfizz/MidiState.h @@ -176,8 +176,6 @@ public: const EventVector& getEvents(int ccIdx) const noexcept; -private: - template void linearEnvelope(T&& modifier, absl::Span envelope, F&& lambda) const { @@ -196,6 +194,10 @@ private: } fill(envelope.subspan(lastDelay), lastValue); } + +private: + + int activeNotes { 0 }; /** diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index ec44a516..b2640738 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -548,16 +548,12 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept return; size_t numFrames = buffer.getNumFrames(); - auto tempBuffer = resources.bufferPool.getStereoBuffer(numFrames); - auto tempMixNodeBuffer = resources.bufferPool.getStereoBuffer(numFrames); - if (!tempBuffer || !tempMixNodeBuffer) { + auto tempSpan = resources.bufferPool.getStereoBuffer(numFrames); + auto tempMixSpan = resources.bufferPool.getStereoBuffer(numFrames); + if (!tempSpan || !tempMixSpan) { DBG("[sfizz] Could not get a temporary buffer; exiting callback... "); return; } - - auto temp = AudioSpan(*tempBuffer).first(numFrames); - auto tempMixNode = AudioSpan(*tempMixNodeBuffer).first(numFrames); - CallbackBreakdown callbackBreakdown; { // Prepare the effect inputs. They are mixes of per-region outputs. @@ -572,7 +568,7 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept { // Main render block ScopedTiming logger { callbackBreakdown.renderMethod }; buffer.fill(0.0f); - tempMixNode.fill(0.0f); + tempSpan->fill(0.0f); resources.filePool.cleanupPromises(); for (auto& voice : voices) { @@ -582,14 +578,14 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept const Region* region = voice->getRegion(); numActiveVoices++; - voice->renderBlock(temp); + voice->renderBlock(*tempSpan); { // Add the output into the effects linked to this region ScopedTiming logger { callbackBreakdown.effects, ScopedTiming::Operation::addToDuration }; for (size_t i = 0, n = effectBuses.size(); i < n; ++i) { if (auto& bus = effectBuses[i]) { float addGain = region->getGainToEffectBus(i); - bus->addToInputs(temp, addGain, numFrames); + bus->addToInputs(*tempSpan, addGain, numFrames); } } } @@ -609,7 +605,7 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept for (auto& bus : effectBuses) { if (bus) { bus->process(numFrames); - bus->mixOutputsTo(buffer, tempMixNode, numFrames); + bus->mixOutputsTo(buffer, *tempMixSpan, numFrames); } } } @@ -618,7 +614,7 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept // -- note(jpc) the purpose of the Mix output is not known. // perhaps it's designed as extension point for custom processing? // as default behavior, it adds itself to the Main signal. - buffer.add(tempMixNode); + buffer.add(*tempMixSpan); // Apply the master volume buffer.applyGain(db2mag(volume)); diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 2307e05d..8b401bf8 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -258,12 +258,11 @@ void sfz::Voice::processMono(AudioSpan buffer) noexcept auto leftBuffer = buffer.getSpan(0); auto rightBuffer = buffer.getSpan(1); - auto modulationBuffer = resources.bufferPool.getBuffer(numSamples); - auto tempBuffer = resources.bufferPool.getBuffer(numSamples); - if (!modulationBuffer || !tempBuffer) + auto modulationSpan = resources.bufferPool.getBuffer(numSamples); + auto tempSpan = resources.bufferPool.getBuffer(numSamples); + if (!modulationSpan || !tempSpan) return; - auto modulationSpan = absl::MakeSpan(*modulationBuffer).first(numSamples); - auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples); + using namespace std::placeholders; const auto xfinBind = std::bind(crossfadeIn, _1, _2, region->crossfadeCCCurve); const auto xfoutBind = std::bind(crossfadeIn, _1, _2, region->crossfadeCCCurve); @@ -272,26 +271,26 @@ void sfz::Voice::processMono(AudioSpan buffer) noexcept ScopedTiming logger { amplitudeDuration }; // Amplitude envelope - fill(modulationSpan, baseGain); - resources.midiState.multiplicativeModifiers(region->amplitudeCC, modulationSpan, tempSpan); - DBG("Final gain: " << modulationSpan.back()); + fill(*modulationSpan, baseGain); + resources.midiState.multiplicativeModifiers(region->amplitudeCC, *modulationSpan, *tempSpan); + DBG("Final gain: " << modulationSpan->back()); applyGain(modulationSpan, leftBuffer); // Crossfade envelopes // crossfadeEnvelope.getBlock(modulationSpan); - fill(modulationSpan, 1.0f); - resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, modulationSpan, tempSpan, xfinBind); - resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, modulationSpan, tempSpan, xfoutBind); - DBG("XF: " << modulationSpan.back()); + fill(*modulationSpan, 1.0f); + resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, *modulationSpan, *tempSpan, xfinBind); + resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, *modulationSpan, *tempSpan, xfoutBind); + DBG("XF: " << modulationSpan->back()); applyGain(modulationSpan, leftBuffer); // Volume envelope - volumeEnvelope.getBlock(modulationSpan); - applyGain(modulationSpan, leftBuffer); + volumeEnvelope.getBlock(*modulationSpan); + applyGain(*modulationSpan, leftBuffer); // AmpEG envelope - egEnvelope.getBlock(modulationSpan); - applyGain(modulationSpan, leftBuffer); + egEnvelope.getBlock(*modulationSpan); + applyGain(*modulationSpan, leftBuffer); } { // Filtering and EQ @@ -315,10 +314,10 @@ void sfz::Voice::processMono(AudioSpan buffer) noexcept copy(leftBuffer, rightBuffer); // Apply panning - fill(modulationSpan, region->pan); - resources.midiState.additiveModifiers(region->panCC, modulationSpan, tempSpan); - DBG("Pan: " << modulationSpan.back()); - pan(modulationSpan, leftBuffer, rightBuffer); + fill(*modulationSpan, region->pan); + resources.midiState.additiveModifiers(region->panCC, *modulationSpan, *tempSpan); + DBG("Pan: " << modulationSpan->back()); + pan(*modulationSpan, leftBuffer, rightBuffer); } } @@ -328,12 +327,10 @@ void sfz::Voice::processStereo(AudioSpan buffer) noexcept auto leftBuffer = buffer.getSpan(0); auto rightBuffer = buffer.getSpan(1); - auto modulationBuffer = resources.bufferPool.getBuffer(numSamples); - auto tempBuffer = resources.bufferPool.getBuffer(numSamples); - if (!modulationBuffer || !tempBuffer) + auto modulationSpan = resources.bufferPool.getBuffer(numSamples); + auto tempSpan = resources.bufferPool.getBuffer(numSamples); + if (!modulationSpan || !tempSpan) return; - auto modulationSpan = absl::MakeSpan(*modulationBuffer).first(numSamples); - auto tempSpan = absl::MakeSpan(*tempBuffer).first(numSamples); using namespace std::placeholders; const auto xfinBind = std::bind(crossfadeIn, _1, _2, region->crossfadeCCCurve); @@ -343,45 +340,44 @@ void sfz::Voice::processStereo(AudioSpan buffer) noexcept ScopedTiming logger { amplitudeDuration }; // Amplitude envelope - fill(modulationSpan, baseGain); - resources.midiState.multiplicativeModifiers(region->amplitudeCC, modulationSpan, tempSpan); - DBG("Final gain: " << modulationSpan.back()); - buffer.applyGain(modulationSpan); + fill(*modulationSpan, baseGain); + resources.midiState.multiplicativeModifiers(region->amplitudeCC, *modulationSpan, *tempSpan); + buffer.applyGain(*modulationSpan); // Crossfade envelopes - fill(modulationSpan, 1.0f); - resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, modulationSpan, tempSpan, xfinBind); - resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, modulationSpan, tempSpan, xfoutBind); - buffer.applyGain(modulationSpan); + fill(*modulationSpan, 1.0f); + resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, *modulationSpan, *tempSpan, xfinBind); + resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, *modulationSpan, *tempSpan, xfoutBind); + buffer.applyGain(*modulationSpan); // Volume envelope - volumeEnvelope.getBlock(modulationSpan); - buffer.applyGain(modulationSpan); + volumeEnvelope.getBlock(*modulationSpan); + buffer.applyGain(*modulationSpan); // AmpEG envelope - egEnvelope.getBlock(modulationSpan); - buffer.applyGain(modulationSpan); + egEnvelope.getBlock(*modulationSpan); + buffer.applyGain(*modulationSpan); } { // Panning and stereo processing ScopedTiming logger { panningDuration }; // Apply panning - // panningModulation(modulationSpan); - fill(modulationSpan, region->pan); - resources.midiState.additiveModifiers(region->panCC, modulationSpan, tempSpan); - pan(modulationSpan, leftBuffer, rightBuffer); + // panningModulation(*modulationSpan); + fill(*modulationSpan, region->pan); + resources.midiState.additiveModifiers(region->panCC, *modulationSpan, *tempSpan); + pan(*modulationSpan, leftBuffer, rightBuffer); // Apply the width/position process - // widthModulation(modulationSpan); - fill(modulationSpan, region->width); - resources.midiState.additiveModifiers(region->widthCC, modulationSpan, tempSpan); - width(modulationSpan, leftBuffer, rightBuffer); + // widthModulation(*modulationSpan); + fill(*modulationSpan, region->width); + resources.midiState.additiveModifiers(region->widthCC, *modulationSpan, *tempSpan); + width(*modulationSpan, leftBuffer, rightBuffer); - // positionModulation(modulationSpan); - fill(modulationSpan, region->position); - resources.midiState.additiveModifiers(region->positionCC, modulationSpan, tempSpan); - pan(modulationSpan, leftBuffer, rightBuffer); + // positionModulation(*modulationSpan); + fill(*modulationSpan, region->position); + resources.midiState.additiveModifiers(region->positionCC, *modulationSpan, *tempSpan); + pan(*modulationSpan, leftBuffer, rightBuffer); } { // Filtering and EQ @@ -412,37 +408,33 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept } auto source = currentPromise->getData(); - auto jumpBuffer = resources.bufferPool.getBuffer(numSamples); - auto bendBuffer = resources.bufferPool.getBuffer(numSamples); - auto leftCoeffBuffer = resources.bufferPool.getBuffer(numSamples); - auto rightCoeffBuffer = resources.bufferPool.getBuffer(numSamples); - auto indexBuffer = resources.bufferPool.getIndexBuffer(numSamples); - if (!jumpBuffer || !bendBuffer || !indexBuffer || !rightCoeffBuffer || !leftCoeffBuffer) + + auto jumps = resources.bufferPool.getBuffer(numSamples); + auto bends = resources.bufferPool.getBuffer(numSamples); + auto leftCoeffs = resources.bufferPool.getBuffer(numSamples); + auto rightCoeffs = resources.bufferPool.getBuffer(numSamples); + auto indices = resources.bufferPool.getIndexBuffer(numSamples); + if (!jumps || !bends || !indices || !rightCoeffs || !leftCoeffs) return; - auto jumps = absl::MakeSpan(*jumpBuffer).first(numSamples); - auto bends = absl::MakeSpan(*bendBuffer).first(numSamples); - auto indices = absl::MakeSpan(*indexBuffer).first(numSamples); - auto leftCoeffs = absl::MakeSpan(*leftCoeffBuffer).first(numSamples); - auto rightCoeffs = absl::MakeSpan(*rightCoeffBuffer).first(numSamples); - fill(jumps, pitchRatio * speedRatio); + fill(*jumps, pitchRatio * speedRatio); if (region->bendStep > 1) - pitchBendEnvelope.getQuantizedBlock(bends, bendStepFactor); + pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor); else - pitchBendEnvelope.getBlock(bends); + pitchBendEnvelope.getBlock(*bends); - applyGain(bends, jumps); - jumps[0] += floatPositionOffset; - cumsum(jumps, jumps); - sfzInterpolationCast(jumps, indices, leftCoeffs, rightCoeffs); - add(sourcePosition, indices); + applyGain(*bends, *jumps); + jumps->front() += floatPositionOffset; + cumsum(*jumps, *jumps); + sfzInterpolationCast(*jumps, *indices, *leftCoeffs, *rightCoeffs); + add(sourcePosition, *indices); if (region->shouldLoop() && region->loopEnd(currentPromise->oversamplingFactor) <= source.getNumFrames()) { const auto loopEnd = static_cast(region->loopEnd(currentPromise->oversamplingFactor)); const auto offset = loopEnd - static_cast(region->loopStart(currentPromise->oversamplingFactor)) + 1; - for (auto* index = indices.begin(); index < indices.end(); ++index) { + for (auto* index = indices->begin(); index < indices->end(); ++index) { if (*index > loopEnd) { - const auto remainingElements = static_cast(std::distance(index, indices.end())); + const auto remainingElements = static_cast(std::distance(index, indices->end())); subtract(offset, { index, remainingElements }); } } @@ -451,46 +443,46 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept static_cast(region->trueSampleEnd(currentPromise->oversamplingFactor)), static_cast(source.getNumFrames()) ) - 2; - for (auto* index = indices.begin(); index < indices.end(); ++index) { + for (auto* index = indices->begin(); index < indices->end(); ++index) { if (*index >= sampleEnd) { - release(static_cast(std::distance(indices.begin(), index))); - const auto remainingElements = static_cast(std::distance(index, indices.end())); + release(static_cast(std::distance(indices->begin(), index))); + const auto remainingElements = static_cast(std::distance(index, indices->end())); if (source.getNumFrames() - 1 < region->trueSampleEnd(currentPromise->oversamplingFactor)) { DBG("[sfizz] Underflow: source available samples " << source.getNumFrames() << "/" << region->trueSampleEnd(currentPromise->oversamplingFactor) << " for sample " << region->sample); } - fill(indices.last(remainingElements), sampleEnd); - fill(leftCoeffs.last(remainingElements), 0.0f); - fill(rightCoeffs.last(remainingElements), 1.0f); + fill(indices->last(remainingElements), sampleEnd); + fill(leftCoeffs->last(remainingElements), 0.0f); + fill(rightCoeffs->last(remainingElements), 1.0f); break; } } } - auto ind = indices.data(); - auto leftCoeff = leftCoeffs.data(); - auto rightCoeff = rightCoeffs.data(); + auto ind = indices->data(); + auto leftCoeff = leftCoeffs->data(); + auto rightCoeff = rightCoeffs->data(); auto leftSource = source.getConstSpan(0); auto left = buffer.getChannel(0); if (source.getNumChannels() == 1) { - while (ind < indices.end()) { + while (ind < indices->end()) { *left = linearInterpolation(leftSource[*ind], leftSource[*ind + 1], *leftCoeff, *rightCoeff); incrementAll(ind, left, leftCoeff, rightCoeff); } } else { auto right = buffer.getChannel(1); auto rightSource = source.getConstSpan(1); - while (ind < indices.end()) { + while (ind < indices->end()) { *left = linearInterpolation(leftSource[*ind], leftSource[*ind + 1], *leftCoeff, *rightCoeff); *right = linearInterpolation(rightSource[*ind], rightSource[*ind + 1], *leftCoeff, *rightCoeff); incrementAll(ind, left, right, leftCoeff, rightCoeff); } } - sourcePosition = indices.back(); - floatPositionOffset = rightCoeffs.back(); + sourcePosition = indices->back(); + floatPositionOffset = rightCoeffs->back(); } void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept @@ -504,24 +496,22 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept absl::c_generate(rightSpan, [&](){ return noiseDist(Random::randomGenerator); }); } else { const auto numSamples = buffer.getNumFrames(); - auto frequencyBuffer = resources.bufferPool.getBuffer(numSamples); - auto bendBuffer = resources.bufferPool.getBuffer(numSamples); - if (!frequencyBuffer || !bendBuffer) + auto frequencies = resources.bufferPool.getBuffer(numSamples); + auto bends = resources.bufferPool.getBuffer(numSamples); + if (!frequencies || !bends) return; - auto frequencies = absl::MakeSpan(*frequencyBuffer).first(numSamples); - auto bends = absl::MakeSpan(*bendBuffer).first(numSamples); float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter); - fill(frequencies, pitchRatio * keycenterFrequency); + fill(*frequencies, pitchRatio * keycenterFrequency); if (region->bendStep > 1) - pitchBendEnvelope.getQuantizedBlock(bends, bendStepFactor); + pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor); else - pitchBendEnvelope.getBlock(bends); + pitchBendEnvelope.getBlock(*bends); - applyGain(bends, frequencies); + applyGain(*bends, *frequencies); - waveOscillator.processModulated(frequencies.data(), leftSpan.data(), buffer.getNumFrames()); + waveOscillator.processModulated(frequencies->data(), leftSpan.data(), buffer.getNumFrames()); copy(leftSpan, rightSpan); } }