Avoid shared pointers and get a span "pointer" directly from the buffer pool

This commit is contained in:
Paul Ferrand 2020-03-30 15:14:33 +02:00
parent e54c27b1f2
commit 9c17201c63
5 changed files with 188 additions and 195 deletions

View file

@ -11,141 +11,122 @@
#include "AudioBuffer.h"
#include <array>
#include <memory>
#include <functional>
#include "absl/algorithm/container.h"
#ifndef NDEBUG
#include "absl/algorithm/container.h"
#include "MathHelpers.h"
#endif
namespace sfz
{
template<class T>
class SpanHolder
{
public:
SpanHolder() {}
SpanHolder(const SpanHolder<T>&) = delete;
SpanHolder<T>& operator=(const SpanHolder<T>&) = delete;
SpanHolder(SpanHolder<T>&&) = delete;
SpanHolder<T>& operator=(SpanHolder<T>&&) = 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<sfz::Buffer<float>>(config::defaultSamplesPerBlock);
}
for (auto& buffer : indexBuffers) {
buffer = std::make_shared<sfz::Buffer<int>>(config::defaultSamplesPerBlock);
}
for (auto& buffer : stereoBuffers) {
buffer = std::make_shared<sfz::AudioBuffer<float>>(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<sfz::Buffer<float>> getBuffer(size_t numFrames) const
SpanHolder<absl::Span<float>> 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<int>(1 + absl::c_count_if(buffers, [&](const std::shared_ptr<sfz::Buffer<float>>& 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<sfz::Buffer<int>> getIndexBuffer(size_t numFrames) const
SpanHolder<absl::Span<int>> 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<int>(1 + absl::c_count_if(indexBuffers, [&](const std::shared_ptr<sfz::Buffer<int>>& 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<sfz::AudioBuffer<float>> getStereoBuffer(size_t numFrames) const
SpanHolder<AudioSpan<float>> 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<int>(1 + absl::c_count_if(stereoBuffers, [&](const std::shared_ptr<sfz::AudioBuffer<float>>& 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<float>(stereoBuffers[freeIndex]).first(numFrames), &*availableIt };
}
#ifndef NDEBUG
@ -156,10 +137,34 @@ public:
DBG("Max stereo buffers used: " << maxStereoBuffersUsed);
}
#endif
private:
std::array<std::shared_ptr<sfz::Buffer<float>>, config::bufferPoolSize> buffers;
std::array<std::shared_ptr<sfz::Buffer<int>>, config::bufferPoolSize> indexBuffers;
std::array<std::shared_ptr<sfz::AudioBuffer<float>>, 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<sfz::Buffer<float>, config::bufferPoolSize> monoBuffers;
std::vector<int> monoAvailable;
std::array<sfz::Buffer<int>, config::bufferPoolSize> indexBuffers;
std::vector<int> indexAvailable;
std::array<sfz::AudioBuffer<float>, config::stereoBufferPoolSize> stereoBuffers;
std::vector<int> stereoAvailable;
#ifndef NDEBUG
mutable int maxBuffersUsed { 0 };
mutable int maxIndexBuffersUsed { 0 };

View file

@ -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 };

View file

@ -176,8 +176,6 @@ public:
const EventVector& getEvents(int ccIdx) const noexcept;
private:
template<class T, class F>
void linearEnvelope(T&& modifier, absl::Span<float> envelope, F&& lambda) const
{
@ -196,6 +194,10 @@ private:
}
fill<float>(envelope.subspan(lastDelay), lastValue);
}
private:
int activeNotes { 0 };
/**

View file

@ -548,16 +548,12 @@ void sfz::Synth::renderBlock(AudioSpan<float> 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<float>(*tempBuffer).first(numFrames);
auto tempMixNode = AudioSpan<float>(*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<float> 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<float> 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<float> 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<float> 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));

View file

@ -258,12 +258,11 @@ void sfz::Voice::processMono(AudioSpan<float> 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<float, float>, _1, _2, region->crossfadeCCCurve);
const auto xfoutBind = std::bind(crossfadeIn<float, float>, _1, _2, region->crossfadeCCCurve);
@ -272,26 +271,26 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
ScopedTiming logger { amplitudeDuration };
// Amplitude envelope
fill<float>(modulationSpan, baseGain);
resources.midiState.multiplicativeModifiers(region->amplitudeCC, modulationSpan, tempSpan);
DBG("Final gain: " << modulationSpan.back());
fill<float>(*modulationSpan, baseGain);
resources.midiState.multiplicativeModifiers(region->amplitudeCC, *modulationSpan, *tempSpan);
DBG("Final gain: " << modulationSpan->back());
applyGain<float>(modulationSpan, leftBuffer);
// Crossfade envelopes
// crossfadeEnvelope.getBlock(modulationSpan);
fill<float>(modulationSpan, 1.0f);
resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, modulationSpan, tempSpan, xfinBind);
resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, modulationSpan, tempSpan, xfoutBind);
DBG("XF: " << modulationSpan.back());
fill<float>(*modulationSpan, 1.0f);
resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, *modulationSpan, *tempSpan, xfinBind);
resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, *modulationSpan, *tempSpan, xfoutBind);
DBG("XF: " << modulationSpan->back());
applyGain<float>(modulationSpan, leftBuffer);
// Volume envelope
volumeEnvelope.getBlock(modulationSpan);
applyGain<float>(modulationSpan, leftBuffer);
volumeEnvelope.getBlock(*modulationSpan);
applyGain<float>(*modulationSpan, leftBuffer);
// AmpEG envelope
egEnvelope.getBlock(modulationSpan);
applyGain<float>(modulationSpan, leftBuffer);
egEnvelope.getBlock(*modulationSpan);
applyGain<float>(*modulationSpan, leftBuffer);
}
{ // Filtering and EQ
@ -315,10 +314,10 @@ void sfz::Voice::processMono(AudioSpan<float> buffer) noexcept
copy<float>(leftBuffer, rightBuffer);
// Apply panning
fill<float>(modulationSpan, region->pan);
resources.midiState.additiveModifiers(region->panCC, modulationSpan, tempSpan);
DBG("Pan: " << modulationSpan.back());
pan<float>(modulationSpan, leftBuffer, rightBuffer);
fill<float>(*modulationSpan, region->pan);
resources.midiState.additiveModifiers(region->panCC, *modulationSpan, *tempSpan);
DBG("Pan: " << modulationSpan->back());
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
}
}
@ -328,12 +327,10 @@ void sfz::Voice::processStereo(AudioSpan<float> 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<float, float>, _1, _2, region->crossfadeCCCurve);
@ -343,45 +340,44 @@ void sfz::Voice::processStereo(AudioSpan<float> buffer) noexcept
ScopedTiming logger { amplitudeDuration };
// Amplitude envelope
fill<float>(modulationSpan, baseGain);
resources.midiState.multiplicativeModifiers(region->amplitudeCC, modulationSpan, tempSpan);
DBG("Final gain: " << modulationSpan.back());
buffer.applyGain(modulationSpan);
fill<float>(*modulationSpan, baseGain);
resources.midiState.multiplicativeModifiers(region->amplitudeCC, *modulationSpan, *tempSpan);
buffer.applyGain(*modulationSpan);
// Crossfade envelopes
fill<float>(modulationSpan, 1.0f);
resources.midiState.multiplicativeModifiers(region->crossfadeCCInRange, modulationSpan, tempSpan, xfinBind);
resources.midiState.multiplicativeModifiers(region->crossfadeCCOutRange, modulationSpan, tempSpan, xfoutBind);
buffer.applyGain(modulationSpan);
fill<float>(*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<float>(modulationSpan, region->pan);
resources.midiState.additiveModifiers(region->panCC, modulationSpan, tempSpan);
pan<float>(modulationSpan, leftBuffer, rightBuffer);
// panningModulation(*modulationSpan);
fill<float>(*modulationSpan, region->pan);
resources.midiState.additiveModifiers(region->panCC, *modulationSpan, *tempSpan);
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
// Apply the width/position process
// widthModulation(modulationSpan);
fill<float>(modulationSpan, region->width);
resources.midiState.additiveModifiers(region->widthCC, modulationSpan, tempSpan);
width<float>(modulationSpan, leftBuffer, rightBuffer);
// widthModulation(*modulationSpan);
fill<float>(*modulationSpan, region->width);
resources.midiState.additiveModifiers(region->widthCC, *modulationSpan, *tempSpan);
width<float>(*modulationSpan, leftBuffer, rightBuffer);
// positionModulation(modulationSpan);
fill<float>(modulationSpan, region->position);
resources.midiState.additiveModifiers(region->positionCC, modulationSpan, tempSpan);
pan<float>(modulationSpan, leftBuffer, rightBuffer);
// positionModulation(*modulationSpan);
fill<float>(*modulationSpan, region->position);
resources.midiState.additiveModifiers(region->positionCC, *modulationSpan, *tempSpan);
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
}
{ // Filtering and EQ
@ -412,37 +408,33 @@ void sfz::Voice::fillWithData(AudioSpan<float> 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<float>(jumps, pitchRatio * speedRatio);
fill<float>(*jumps, pitchRatio * speedRatio);
if (region->bendStep > 1)
pitchBendEnvelope.getQuantizedBlock(bends, bendStepFactor);
pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor);
else
pitchBendEnvelope.getBlock(bends);
pitchBendEnvelope.getBlock(*bends);
applyGain<float>(bends, jumps);
jumps[0] += floatPositionOffset;
cumsum<float>(jumps, jumps);
sfzInterpolationCast<float>(jumps, indices, leftCoeffs, rightCoeffs);
add<int>(sourcePosition, indices);
applyGain<float>(*bends, *jumps);
jumps->front() += floatPositionOffset;
cumsum<float>(*jumps, *jumps);
sfzInterpolationCast<float>(*jumps, *indices, *leftCoeffs, *rightCoeffs);
add<int>(sourcePosition, *indices);
if (region->shouldLoop() && region->loopEnd(currentPromise->oversamplingFactor) <= source.getNumFrames()) {
const auto loopEnd = static_cast<int>(region->loopEnd(currentPromise->oversamplingFactor));
const auto offset = loopEnd - static_cast<int>(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<size_t>(std::distance(index, indices.end()));
const auto remainingElements = static_cast<size_t>(std::distance(index, indices->end()));
subtract<int>(offset, { index, remainingElements });
}
}
@ -451,46 +443,46 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
static_cast<int>(region->trueSampleEnd(currentPromise->oversamplingFactor)),
static_cast<int>(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<int>(std::distance(indices.begin(), index)));
const auto remainingElements = static_cast<size_t>(std::distance(index, indices.end()));
release(static_cast<int>(std::distance(indices->begin(), index)));
const auto remainingElements = static_cast<size_t>(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<int>(indices.last(remainingElements), sampleEnd);
fill<float>(leftCoeffs.last(remainingElements), 0.0f);
fill<float>(rightCoeffs.last(remainingElements), 1.0f);
fill<int>(indices->last(remainingElements), sampleEnd);
fill<float>(leftCoeffs->last(remainingElements), 0.0f);
fill<float>(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<float> buffer) noexcept
@ -504,24 +496,22 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> 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<float>(frequencies, pitchRatio * keycenterFrequency);
fill<float>(*frequencies, pitchRatio * keycenterFrequency);
if (region->bendStep > 1)
pitchBendEnvelope.getQuantizedBlock(bends, bendStepFactor);
pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor);
else
pitchBendEnvelope.getBlock(bends);
pitchBendEnvelope.getBlock(*bends);
applyGain<float>(bends, frequencies);
applyGain<float>(*bends, *frequencies);
waveOscillator.processModulated(frequencies.data(), leftSpan.data(), buffer.getNumFrames());
waveOscillator.processModulated(frequencies->data(), leftSpan.data(), buffer.getNumFrames());
copy<float>(leftSpan, rightSpan);
}
}