Avoid shared pointers and get a span "pointer" directly from the buffer pool
This commit is contained in:
parent
e54c27b1f2
commit
9c17201c63
5 changed files with 188 additions and 195 deletions
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue