Skip to content

Commit

Permalink
Merge pull request #214 from paulfd/note-stealing
Browse files Browse the repository at this point in the history
Improve the note stealing
  • Loading branch information
paulfd authored May 9, 2020
2 parents f1e87b4 + e4f0b0c commit d6c24be
Show file tree
Hide file tree
Showing 19 changed files with 445 additions and 195 deletions.
3 changes: 2 additions & 1 deletion benchmarks/BM_filterModulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "OnePoleFilter.h"
#include "SfzFilter.h"
#include "ScopedFTZ.h"
#include "SfzHelpers.h"
#include <benchmark/benchmark.h>
#include <random>
#include <numeric>
Expand Down Expand Up @@ -57,7 +58,7 @@ BENCHMARK_DEFINE_F(FilterFixture, OnePole_VA)(benchmark::State& state) {
const auto sentinel = cutoff.data() + blockSize;
while (cutoffPtr < sentinel)
{
const auto gain = sfz::OnePoleFilter<float>::normalizedGain(*cutoffPtr, sampleRate);
const auto gain = sfz::vaGain(*cutoffPtr, sampleRate);
filter.setGain(gain);
filter.processLowpass({ inputPtr, step }, { outputPtr, step } );
cutoffPtr += step;
Expand Down
51 changes: 32 additions & 19 deletions lv2/sfizz.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
#define PITCH_BUILD_AND_CENTER(first_byte, last_byte) (int)(((unsigned int)last_byte << 7) + (unsigned int)first_byte) - 8192
#define MAX_BLOCK_SIZE 8192
#define MAX_PATH_SIZE 1024
#define MAX_VOICES 256
#define MAX_VOICES 512
#define DEFAULT_VOICES 64
#define DEFAULT_OVERSAMPLING SFIZZ_OVERSAMPLING_X1
#define DEFAULT_PRELOAD 8192
Expand Down Expand Up @@ -584,7 +584,7 @@ sfizz_lv2_check_num_voices(sfizz_plugin_t* self)
num_voices_atom.body = num_voices;
if (self->worker->schedule_work(self->worker->handle,
lv2_atom_total_size((LV2_Atom *)&num_voices_atom),
&num_voices_atom) == LV2_WORKER_SUCCESS)
&num_voices_atom) != LV2_WORKER_SUCCESS)
{
lv2_log_error(&self->logger, "[sfizz] There was an issue changing the number of voices\n");
}
Expand Down Expand Up @@ -906,8 +906,7 @@ work(LV2_Handle instance,
const void *data)
{
sfizz_plugin_t *self = (sfizz_plugin_t *)instance;
if (!data)
{
if (!data) {
lv2_log_error(&self->logger, "[sfizz] Ignoring empty data in the worker thread\n");
return LV2_WORKER_ERR_UNKNOWN;
}
Expand All @@ -922,12 +921,9 @@ work(LV2_Handle instance,

const char *sfz_file_path = LV2_ATOM_BODY_CONST(atom);
self->changing_state = true;
if (sfizz_load_file(self->synth, sfz_file_path))
{
if (sfizz_load_file(self->synth, sfz_file_path)) {
sfizz_lv2_update_file_info(self, sfz_file_path);
}
else
{
} else {
lv2_log_error(&self->logger, "[sfizz] Error with %s; no file should be loaded\n", sfz_file_path);
}
self->changing_state = false;
Expand All @@ -939,12 +935,18 @@ work(LV2_Handle instance,
return LV2_WORKER_SUCCESS;
}

self->changing_state = true;
const int num_voices = *(const int *)LV2_ATOM_BODY_CONST(atom);
if (sfizz_get_num_voices(self->synth) == num_voices) {
return LV2_WORKER_SUCCESS; // Nothing to do
}

self->changing_state = true;
sfizz_set_num_voices(self->synth, num_voices);
if (sfizz_get_num_voices(self->synth) == num_voices) {
self->num_voices = num_voices;
lv2_log_note(&self->logger, "[sfizz] Number of voices changed to: %d\n", num_voices);
} else {
lv2_log_error(&self->logger, "[sfizz] Error changing the number of voices\n");
}
self->changing_state = false;
}
Expand All @@ -955,12 +957,18 @@ work(LV2_Handle instance,
return LV2_WORKER_SUCCESS;
}

self->changing_state = true;
const unsigned int preload_size = *(const unsigned int *)LV2_ATOM_BODY_CONST(atom);
if (sfizz_get_preload_size(self->synth) == preload_size) {
return LV2_WORKER_SUCCESS; // Nothing to do
}

self->changing_state = true;
sfizz_set_preload_size(self->synth, preload_size);
if (sfizz_get_preload_size(self->synth) == preload_size) {
self->preload_size = preload_size;
lv2_log_note(&self->logger, "[sfizz] Preload size changed to: %d\n", preload_size);
} else {
lv2_log_error(&self->logger, "[sfizz] Error changing the preload size\n");
}
self->changing_state = false;
}
Expand All @@ -970,13 +978,20 @@ work(LV2_Handle instance,
respond(handle, size, data); // send back so that we reschedule the check
return LV2_WORKER_SUCCESS;
}
self->changing_state = true;

const sfizz_oversampling_factor_t oversampling =
*(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom);
if (sfizz_get_oversampling_factor(self->synth) == oversampling) {
return LV2_WORKER_SUCCESS; // Nothing to do
}

self->changing_state = true;
sfizz_set_oversampling_factor(self->synth, oversampling);
if (sfizz_get_oversampling_factor(self->synth) == oversampling) {
self->oversampling = oversampling;
lv2_log_note(&self->logger, "[sfizz] Oversampling changed to: %d\n", oversampling);
} else {
lv2_log_error(&self->logger, "[sfizz] Error changing the oversampling\n");
}
self->changing_state = false;
}
Expand All @@ -992,13 +1007,12 @@ work(LV2_Handle instance,
if (self->changing_state)
return LV2_WORKER_SUCCESS;

lv2_log_note(&self->logger, "[sfizz] File %s seems to have been updated, reloading\n", self->sfz_file_path);
if (sfizz_load_file(self->synth, self->sfz_file_path))
{
lv2_log_note(&self->logger,
"[sfizz] File %s seems to have been updated, reloading\n",
self->sfz_file_path);
if (sfizz_load_file(self->synth, self->sfz_file_path)) {
sfizz_lv2_update_file_info(self, self->sfz_file_path);
}
else
{
} else {
lv2_log_error(&self->logger, "[sfizz] Error with %s; no file should be loaded\n", self->sfz_file_path);
}
}
Expand All @@ -1012,7 +1026,6 @@ work(LV2_Handle instance,
self->unmap->unmap(self->unmap->handle, atom->type));
return LV2_WORKER_ERR_UNKNOWN;
}

return LV2_WORKER_SUCCESS;
}

Expand Down
7 changes: 6 additions & 1 deletion lv2/sfizz.ttl.in
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ midnam:update a lv2:Feature .
lv2:portProperty pprop:expensive ;
lv2:portProperty lv2:integer ;
lv2:portProperty lv2:enumeration ;
lv2:default 64 ;
lv2:default 256 ;
lv2:minimum 8 ;
lv2:maximum 256 ;
lv2:scalePoint [ rdfs:label "8 voices",
Expand Down Expand Up @@ -147,6 +147,11 @@ midnam:update a lv2:Feature .
"256 Voci"@it;
rdf:value 256
] ;
lv2:scalePoint [ rdfs:label "512 voices",
"512 voix"@fr ,
"512 Voci"@it;
rdf:value 512
] ;
] , [
a lv2:InputPort, lv2:ControlPort ;
lv2:index 6 ;
Expand Down
26 changes: 26 additions & 0 deletions src/sfizz/AudioBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Config.h"
#include "Debug.h"
#include "LeakDetector.h"
#include "SIMDHelpers.h"
#include "absl/types/span.h"
#include "absl/memory/memory.h"
#include <array>
Expand Down Expand Up @@ -259,6 +260,15 @@ class AudioBuffer {
numChannels = 0;
}

/**
* Writes zeros in the buffer
*/
void clear()
{
for (size_t i = 0; i < numChannels; ++i)
fill<Type>(getSpan(i), Type{ 0.0 });
}

/**
* @brief Add a positive number of channels to the buffer
*
Expand All @@ -271,6 +281,22 @@ class AudioBuffer {
addChannel();
}

/**
* @brief Convert implicitly to a pointer of channels
*/
operator const float* const*() const noexcept
{
return buffers.data();
}

/**
* @brief Convert implicitly to a pointer of channels
*/
operator float* const*() noexcept
{
return buffers.data();
}

private:
using buffer_type = Buffer<Type, Alignment>;
using buffer_ptr = std::unique_ptr<buffer_type>;
Expand Down
20 changes: 15 additions & 5 deletions src/sfizz/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace config {
constexpr float defaultSampleRate { 48000 };
constexpr int defaultSamplesPerBlock { 1024 };
constexpr int maxBlockSize { 8192 };
constexpr int bufferPoolSize { 4 };
constexpr int bufferPoolSize { 6 };
constexpr int stereoBufferPoolSize { 4 };
constexpr int indexBufferPoolSize { 2 };
constexpr int preloadSize { 8192 };
Expand All @@ -37,9 +37,9 @@ namespace config {
constexpr bool loggingEnabled { false };
constexpr size_t numChannels { 2 };
constexpr int numBackgroundThreads { 4 };
constexpr int numVoices { 64 };
constexpr unsigned maxVoices { 256 };
constexpr int maxFilePromises { maxVoices * 2 };
constexpr int numVoices { 256 };
constexpr unsigned maxVoices { 512 };
constexpr int maxFilePromises { maxVoices };
constexpr int sustainCC { 64 };
constexpr int allSoundOffCC { 120 };
constexpr int resetCC { 121 };
Expand All @@ -54,11 +54,21 @@ namespace config {
constexpr Oversampling defaultOversamplingFactor { Oversampling::x1 };
constexpr float A440 { 440.0 };
constexpr size_t powerHistoryLength { 16 };
constexpr float voiceStealingThreshold { 0.00001f };
constexpr float filteredEnvelopeCutoff { 5 };
constexpr uint16_t numCCs { 512 };
constexpr int maxCurves { 256 };
constexpr int chunkSize { 1024 };
constexpr int filtersInPool { maxVoices * 2 };
/**
* @brief The threshold for age stealing.
* In percentage of the voice's max age.
*/
constexpr float stealingAgeCoeff { 0.5f };
/**
* @brief The threshold for envelope stealing.
* In percentage of the sum of all envelopes.
*/
constexpr float stealingEnvelopeCoeff { 0.5f };
constexpr int filtersPerVoice { 2 };
constexpr int eqsPerVoice { 3 };
constexpr int oscillatorsPerVoice { 9 };
Expand Down
11 changes: 11 additions & 0 deletions src/sfizz/Effects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ void EffectBus::addToInputs(const float* const addInput[], float addGain, unsign
}
}

void EffectBus::applyGain(const float* gain, unsigned nframes)
{
if (!gain)
return;

absl::Span<const float> gainSpan { gain, nframes };
for (unsigned c = 0; c < EffectChannels; ++c) {
sfz::applyGain<float>(gainSpan, _inputs.getSpan(c));
}
}

void EffectBus::setSampleRate(double sampleRate)
{
for (const auto& effectPtr : _effects)
Expand Down
5 changes: 5 additions & 0 deletions src/sfizz/Effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ class EffectBus {
*/
void addToInputs(const float* const addInput[], float addGain, unsigned nframes);

/**
@brief Apply a gain to the inputs
*/
void applyGain(const float* gain, unsigned nframes);

/**
@brief Initializes all effects in the bus with the given sample rate.
*/
Expand Down
11 changes: 10 additions & 1 deletion src/sfizz/HistoricalBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class HistoricalBuffer {
buffer.resize(size);
fill<ValueType>(absl::MakeSpan(buffer), 0.0);
index = 0;
validMean = false;
}

/**
Expand All @@ -46,6 +47,7 @@ class HistoricalBuffer {
*/
void push(ValueType value)
{
validMean = false;
if (size > 0) {
buffer[index] = value;
if (++index == size)
Expand All @@ -60,11 +62,18 @@ class HistoricalBuffer {
*/
ValueType getAverage() const
{
return mean<ValueType>(buffer);
if (!validMean) {
mean = sfz::mean<ValueType>(buffer);
validMean = true;
}

return mean;
}
private:
Buffer<ValueType> buffer;
size_t size { 0 };
size_t index { 0 };
mutable bool validMean { true };
mutable ValueType mean { 0.0 };
};
}
60 changes: 60 additions & 0 deletions src/sfizz/MathHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,66 @@ bool isValidAudio(absl::Span<Type> span)
return true;
}

/**
* @brief Finds the minimum size of 2 spans
*
* @tparam T
* @tparam U
* @param span1
* @param span2
* @return constexpr size_t
*/
template <class T, class U>
constexpr size_t minSpanSize(absl::Span<T>& span1, absl::Span<U>& span2)
{
return min(span1.size(), span2.size());
}

/**
* @brief Finds the minimum size of a list of spans.
*
* @tparam T
* @tparam Others
* @param first
* @param others
* @return constexpr size_t
*/
template <class T, class... Others>
constexpr size_t minSpanSize(absl::Span<T>& first, Others... others)
{
return min(first.size(), minSpanSize(others...));
}

template <class T>
constexpr bool _checkSpanSizes(size_t size, absl::Span<T>& span1)
{
return span1.size() == size;
}

template <class T, class... Others>
constexpr bool _checkSpanSizes(size_t size, absl::Span<T>& span1, Others... others)
{
return span1.size() == size && _checkSpanSizes(size, others...);
}

/**
* @brief Check that all spans of a compile time list have the same size
*
* @tparam T
* @tparam Others
* @param first
* @param others
* @return constexpr size_t
*/
template <class T, class... Others>
constexpr bool checkSpanSizes(const absl::Span<T>& span1, Others... others)
{
return _checkSpanSizes(span1.size(), others...);
}

#define CHECK_SPAN_SIZES(...) ASSERT(checkSpanSizes(__VA_ARGS__))


class ScopedRoundingMode {
public:
ScopedRoundingMode() = delete;
Expand Down
Loading

0 comments on commit d6c24be

Please sign in to comment.