Add the modifier helpers to another file
This commit is contained in:
parent
9d6b2ede2f
commit
232eada0c4
7 changed files with 240 additions and 254 deletions
234
src/sfizz/ModifierHelpers.h
Normal file
234
src/sfizz/ModifierHelpers.h
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Range.h"
|
||||||
|
#include "Defaults.h"
|
||||||
|
#include "SfzHelpers.h"
|
||||||
|
#include "Resources.h"
|
||||||
|
#include "absl/types/span.h"
|
||||||
|
|
||||||
|
namespace sfz {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute a crossfade in value with respect to a crossfade range (note, velocity, cc, ...)
|
||||||
|
*/
|
||||||
|
template <class T, class U>
|
||||||
|
float crossfadeIn(const sfz::Range<T>& crossfadeRange, U value, SfzCrossfadeCurve curve)
|
||||||
|
{
|
||||||
|
if (value < crossfadeRange.getStart())
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
const auto length = static_cast<float>(crossfadeRange.length());
|
||||||
|
if (length == 0.0f)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
else if (value < crossfadeRange.getEnd()) {
|
||||||
|
const auto crossfadePosition = static_cast<float>(value - crossfadeRange.getStart()) / length;
|
||||||
|
if (curve == SfzCrossfadeCurve::power)
|
||||||
|
return sqrt(crossfadePosition);
|
||||||
|
if (curve == SfzCrossfadeCurve::gain)
|
||||||
|
return crossfadePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute a crossfade out value with respect to a crossfade range (note, velocity, cc, ...)
|
||||||
|
*/
|
||||||
|
template <class T, class U>
|
||||||
|
float crossfadeOut(const sfz::Range<T>& crossfadeRange, U value, SfzCrossfadeCurve curve)
|
||||||
|
{
|
||||||
|
if (value > crossfadeRange.getEnd())
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
const auto length = static_cast<float>(crossfadeRange.length());
|
||||||
|
if (length == 0.0f)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
else if (value > crossfadeRange.getStart()) {
|
||||||
|
const auto crossfadePosition = static_cast<float>(value - crossfadeRange.getStart()) / length;
|
||||||
|
if (curve == SfzCrossfadeCurve::power)
|
||||||
|
return std::sqrt(1 - crossfadePosition);
|
||||||
|
if (curve == SfzCrossfadeCurve::gain)
|
||||||
|
return 1 - crossfadePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda)
|
||||||
|
{
|
||||||
|
ASSERT(events.size() > 0);
|
||||||
|
ASSERT(events[0].delay == 0);
|
||||||
|
if (envelope.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
||||||
|
|
||||||
|
auto lastValue = lambda(events[0].value);
|
||||||
|
auto lastDelay = events[0].delay;
|
||||||
|
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
||||||
|
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
||||||
|
const auto step = (lambda(events[i].value) - lastValue) / length;
|
||||||
|
lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
||||||
|
lastDelay += length;
|
||||||
|
}
|
||||||
|
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda, float step)
|
||||||
|
{
|
||||||
|
ASSERT(events.size() > 0);
|
||||||
|
ASSERT(events[0].delay == 0);
|
||||||
|
ASSERT(step != 0.0);
|
||||||
|
|
||||||
|
if (envelope.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto quantize = [step](float value) -> float {
|
||||||
|
return std::round(value / step) * step;
|
||||||
|
};
|
||||||
|
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
||||||
|
|
||||||
|
auto lastValue = quantize(lambda(events[0].value));
|
||||||
|
auto lastDelay = events[0].delay;
|
||||||
|
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
||||||
|
const auto nextValue = quantize(lambda(events[i].value));
|
||||||
|
const auto difference = std::abs(nextValue - lastValue);
|
||||||
|
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
||||||
|
|
||||||
|
if (difference < step) {
|
||||||
|
fill<float>(envelope.subspan(lastDelay, length), lastValue);
|
||||||
|
lastValue = nextValue;
|
||||||
|
lastDelay += length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto numSteps = static_cast<int>(difference / step);
|
||||||
|
const auto stepLength = static_cast<int>(length / numSteps);
|
||||||
|
for (int i = 0; i < numSteps; ++i) {
|
||||||
|
fill<float>(envelope.subspan(lastDelay, stepLength), lastValue);
|
||||||
|
lastValue += lastValue <= nextValue ? step : -step;
|
||||||
|
lastDelay += stepLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda)
|
||||||
|
{
|
||||||
|
ASSERT(events.size() > 0);
|
||||||
|
ASSERT(events[0].delay == 0);
|
||||||
|
|
||||||
|
if (envelope.size() == 0)
|
||||||
|
return;
|
||||||
|
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
||||||
|
|
||||||
|
auto lastValue = lambda(events[0].value);
|
||||||
|
auto lastDelay = events[0].delay;
|
||||||
|
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
||||||
|
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
||||||
|
const auto nextValue = lambda(events[i].value);
|
||||||
|
const auto step = std::exp((std::log(nextValue) - std::log(lastValue)) / length);
|
||||||
|
multiplicativeRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
||||||
|
lastValue = nextValue;
|
||||||
|
lastDelay += length;
|
||||||
|
}
|
||||||
|
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda, float step)
|
||||||
|
{
|
||||||
|
ASSERT(events.size() > 0);
|
||||||
|
ASSERT(events[0].delay == 0);
|
||||||
|
ASSERT(step != 0.0f);
|
||||||
|
|
||||||
|
if (envelope.size() == 0)
|
||||||
|
return;
|
||||||
|
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
||||||
|
|
||||||
|
const auto logStep = std::log(step);
|
||||||
|
// If we assume that a = b.q^r for b in (1, q) then
|
||||||
|
// log a log b
|
||||||
|
// ----- = ----- + r
|
||||||
|
// log q log q
|
||||||
|
// and log(b)\log(q) is between 0 and 1.
|
||||||
|
auto quantize = [logStep](float value) -> float {
|
||||||
|
return std::exp(logStep * std::round(std::log(value) / logStep));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto lastValue = quantize(lambda(events[0].value));
|
||||||
|
auto lastDelay = events[0].delay;
|
||||||
|
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
||||||
|
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
||||||
|
const auto nextValue = quantize(lambda(events[i].value));
|
||||||
|
const auto difference = nextValue > lastValue ? nextValue / lastValue : lastValue / nextValue;
|
||||||
|
|
||||||
|
if (difference < step) {
|
||||||
|
fill<float>(envelope.subspan(lastDelay, length), lastValue);
|
||||||
|
lastValue = nextValue;
|
||||||
|
lastDelay += length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto numSteps = static_cast<int>(std::log(difference) / logStep);
|
||||||
|
const auto stepLength = static_cast<int>(length / numSteps);
|
||||||
|
for (int i = 0; i < numSteps; ++i) {
|
||||||
|
fill<float>(envelope.subspan(lastDelay, stepLength), lastValue);
|
||||||
|
lastValue = nextValue > lastValue ? lastValue * step : lastValue / step;
|
||||||
|
lastDelay += stepLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F>
|
||||||
|
void linearModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData, F&& lambda)
|
||||||
|
{
|
||||||
|
const auto events = resources.midiState.getCCEvents(ccData.cc);
|
||||||
|
const auto curve = resources.curves.getCurve(ccData.data.curve);
|
||||||
|
if (ccData.data.steps == 0) {
|
||||||
|
linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
||||||
|
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const float stepSize { ccData.data.value / ccData.data.steps };
|
||||||
|
linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
||||||
|
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
||||||
|
}, stepSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F>
|
||||||
|
void multiplicativeModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData, F&& lambda)
|
||||||
|
{
|
||||||
|
const auto events = resources.midiState.getCCEvents(ccData.cc);
|
||||||
|
const auto curve = resources.curves.getCurve(ccData.data.curve);
|
||||||
|
if (ccData.data.steps == 0) {
|
||||||
|
multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
||||||
|
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// FIXME: not sure about this step size for multiplicative envelopes
|
||||||
|
const float stepSize { ccData.data.value / ccData.data.steps };
|
||||||
|
multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
||||||
|
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
||||||
|
}, stepSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void linearModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData)
|
||||||
|
{
|
||||||
|
linearModifier(resources, span, ccData, [](float x) { return x; });
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void multiplicativeModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData)
|
||||||
|
{
|
||||||
|
multiplicativeModifier(resources, span, ccData, [](float x) { return x; });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,13 +5,12 @@
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "Defaults.h"
|
|
||||||
#include "MathHelpers.h"
|
#include "MathHelpers.h"
|
||||||
#include "Macros.h"
|
#include "Macros.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Opcode.h"
|
#include "Opcode.h"
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
#include "MidiState.h"
|
#include "ModifierHelpers.h"
|
||||||
#include "absl/strings/str_replace.h"
|
#include "absl/strings/str_replace.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "absl/algorithm/container.h"
|
#include "absl/algorithm/container.h"
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
#include "Opcode.h"
|
#include "Opcode.h"
|
||||||
#include "AudioBuffer.h"
|
#include "AudioBuffer.h"
|
||||||
#include "MidiState.h"
|
#include "MidiState.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/types/optional.h"
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <absl/types/optional.h>
|
|
||||||
#include <random>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -264,200 +264,5 @@ bool findDefine(absl::string_view line, absl::string_view& variable, absl::strin
|
||||||
*/
|
*/
|
||||||
bool findInclude(absl::string_view line, std::string& path);
|
bool findInclude(absl::string_view line, std::string& path);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief multiply a value by a factor, in cents. To be used for pitch variations.
|
|
||||||
*
|
|
||||||
* @param base
|
|
||||||
* @param modifier
|
|
||||||
*/
|
|
||||||
inline CXX14_CONSTEXPR float multiplyByCentsModifier(int modifier, float base)
|
|
||||||
{
|
|
||||||
return base * centsFactor(modifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline CXX14_CONSTEXPR float gainModifier(T modifier, float value)
|
|
||||||
{
|
|
||||||
return value * modifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compute a crossfade in value with respect to a crossfade range (note, velocity, cc, ...)
|
|
||||||
*/
|
|
||||||
template <class T, class U>
|
|
||||||
float crossfadeIn(const sfz::Range<T>& crossfadeRange, U value, SfzCrossfadeCurve curve)
|
|
||||||
{
|
|
||||||
if (value < crossfadeRange.getStart())
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
const auto length = static_cast<float>(crossfadeRange.length());
|
|
||||||
if (length == 0.0f)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
else if (value < crossfadeRange.getEnd()) {
|
|
||||||
const auto crossfadePosition = static_cast<float>(value - crossfadeRange.getStart()) / length;
|
|
||||||
if (curve == SfzCrossfadeCurve::power)
|
|
||||||
return sqrt(crossfadePosition);
|
|
||||||
if (curve == SfzCrossfadeCurve::gain)
|
|
||||||
return crossfadePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compute a crossfade out value with respect to a crossfade range (note, velocity, cc, ...)
|
|
||||||
*/
|
|
||||||
template <class T, class U>
|
|
||||||
float crossfadeOut(const sfz::Range<T>& crossfadeRange, U value, SfzCrossfadeCurve curve)
|
|
||||||
{
|
|
||||||
if (value > crossfadeRange.getEnd())
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
const auto length = static_cast<float>(crossfadeRange.length());
|
|
||||||
if (length == 0.0f)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
else if (value > crossfadeRange.getStart()) {
|
|
||||||
const auto crossfadePosition = static_cast<float>(value - crossfadeRange.getStart()) / length;
|
|
||||||
if (curve == SfzCrossfadeCurve::power)
|
|
||||||
return std::sqrt(1 - crossfadePosition);
|
|
||||||
if (curve == SfzCrossfadeCurve::gain)
|
|
||||||
return 1 - crossfadePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda)
|
|
||||||
{
|
|
||||||
ASSERT(events.size() > 0);
|
|
||||||
ASSERT(events[0].delay == 0);
|
|
||||||
if (envelope.size() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
|
||||||
|
|
||||||
auto lastValue = lambda(events[0].value);
|
|
||||||
auto lastDelay = events[0].delay;
|
|
||||||
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
|
||||||
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
|
||||||
const auto step = (lambda(events[i].value) - lastValue) / length;
|
|
||||||
lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
|
||||||
lastDelay += length;
|
|
||||||
}
|
|
||||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda, float step)
|
|
||||||
{
|
|
||||||
ASSERT(events.size() > 0);
|
|
||||||
ASSERT(events[0].delay == 0);
|
|
||||||
ASSERT(step != 0.0);
|
|
||||||
|
|
||||||
if (envelope.size() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto quantize = [step](float value) -> float {
|
|
||||||
return std::round(value / step) * step;
|
|
||||||
};
|
|
||||||
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
|
||||||
|
|
||||||
auto lastValue = quantize(lambda(events[0].value));
|
|
||||||
auto lastDelay = events[0].delay;
|
|
||||||
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
|
||||||
const auto nextValue = quantize(lambda(events[i].value));
|
|
||||||
const auto difference = std::abs(nextValue - lastValue);
|
|
||||||
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
|
||||||
|
|
||||||
if (difference < step) {
|
|
||||||
fill<float>(envelope.subspan(lastDelay, length), lastValue);
|
|
||||||
lastValue = nextValue;
|
|
||||||
lastDelay += length;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto numSteps = static_cast<int>(difference / step);
|
|
||||||
const auto stepLength = static_cast<int>(length / numSteps);
|
|
||||||
for (int i = 0; i < numSteps; ++i) {
|
|
||||||
fill<float>(envelope.subspan(lastDelay, stepLength), lastValue);
|
|
||||||
lastValue += lastValue <= nextValue ? step : -step;
|
|
||||||
lastDelay += stepLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda)
|
|
||||||
{
|
|
||||||
ASSERT(events.size() > 0);
|
|
||||||
ASSERT(events[0].delay == 0);
|
|
||||||
|
|
||||||
if (envelope.size() == 0)
|
|
||||||
return;
|
|
||||||
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
|
||||||
|
|
||||||
auto lastValue = lambda(events[0].value);
|
|
||||||
auto lastDelay = events[0].delay;
|
|
||||||
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
|
||||||
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
|
||||||
const auto nextValue = lambda(events[i].value);
|
|
||||||
const auto step = std::exp((std::log(nextValue) - std::log(lastValue)) / length);
|
|
||||||
multiplicativeRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
|
||||||
lastValue = nextValue;
|
|
||||||
lastDelay += length;
|
|
||||||
}
|
|
||||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelope, F&& lambda, float step)
|
|
||||||
{
|
|
||||||
ASSERT(events.size() > 0);
|
|
||||||
ASSERT(events[0].delay == 0);
|
|
||||||
ASSERT(step != 0.0f);
|
|
||||||
|
|
||||||
if (envelope.size() == 0)
|
|
||||||
return;
|
|
||||||
const auto maxDelay = static_cast<int>(envelope.size() - 1);
|
|
||||||
|
|
||||||
const auto logStep = std::log(step);
|
|
||||||
// If we assume that a = b.q^r for b in (1, q) then
|
|
||||||
// log a log b
|
|
||||||
// ----- = ----- + r
|
|
||||||
// log q log q
|
|
||||||
// and log(b)\log(q) is between 0 and 1.
|
|
||||||
auto quantize = [logStep](float value) -> float {
|
|
||||||
return std::exp(logStep * std::round(std::log(value) / logStep));
|
|
||||||
};
|
|
||||||
|
|
||||||
auto lastValue = quantize(lambda(events[0].value));
|
|
||||||
auto lastDelay = events[0].delay;
|
|
||||||
for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++i) {
|
|
||||||
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
|
||||||
const auto nextValue = quantize(lambda(events[i].value));
|
|
||||||
const auto difference = nextValue > lastValue ? nextValue / lastValue : lastValue / nextValue;
|
|
||||||
|
|
||||||
if (difference < step) {
|
|
||||||
fill<float>(envelope.subspan(lastDelay, length), lastValue);
|
|
||||||
lastValue = nextValue;
|
|
||||||
lastDelay += length;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto numSteps = static_cast<int>(std::log(difference) / logStep);
|
|
||||||
const auto stepLength = static_cast<int>(length / numSteps);
|
|
||||||
for (int i = 0; i < numSteps; ++i) {
|
|
||||||
fill<float>(envelope.subspan(lastDelay, stepLength), lastValue);
|
|
||||||
lastValue = nextValue > lastValue ? lastValue * step : lastValue / step;
|
|
||||||
lastDelay += stepLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sfz
|
} // namespace sfz
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,14 @@
|
||||||
// license. You should have receive a LICENSE.md file along with the code.
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#include "Macros.h"
|
|
||||||
#include "Voice.h"
|
#include "Voice.h"
|
||||||
#include "AudioSpan.h"
|
#include "Macros.h"
|
||||||
#include "Config.h"
|
|
||||||
#include "Defaults.h"
|
#include "Defaults.h"
|
||||||
|
#include "ModifierHelpers.h"
|
||||||
#include "MathHelpers.h"
|
#include "MathHelpers.h"
|
||||||
#include "SIMDHelpers.h"
|
#include "SIMDHelpers.h"
|
||||||
#include "SfzHelpers.h"
|
#include "SfzHelpers.h"
|
||||||
#include "absl/algorithm/container.h"
|
#include "absl/algorithm/container.h"
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
sfz::Voice::Voice(sfz::Resources& resources)
|
sfz::Voice::Voice(sfz::Resources& resources)
|
||||||
: resources(resources)
|
: resources(resources)
|
||||||
|
|
@ -249,51 +247,6 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class F>
|
|
||||||
void linearModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData, F&& lambda)
|
|
||||||
{
|
|
||||||
const auto events = resources.midiState.getCCEvents(ccData.cc);
|
|
||||||
const auto curve = resources.curves.getCurve(ccData.data.curve);
|
|
||||||
if (ccData.data.steps == 0) {
|
|
||||||
linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
|
||||||
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const float stepSize { ccData.data.value / ccData.data.steps };
|
|
||||||
linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
|
||||||
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
|
||||||
}, stepSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class F>
|
|
||||||
void multiplicativeModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData, F&& lambda)
|
|
||||||
{
|
|
||||||
const auto events = resources.midiState.getCCEvents(ccData.cc);
|
|
||||||
const auto curve = resources.curves.getCurve(ccData.data.curve);
|
|
||||||
if (ccData.data.steps == 0) {
|
|
||||||
multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
|
||||||
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// FIXME: not sure about this step size for multiplicative envelopes
|
|
||||||
const float stepSize { ccData.data.value / ccData.data.steps };
|
|
||||||
multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
|
||||||
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
|
||||||
}, stepSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void linearModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData)
|
|
||||||
{
|
|
||||||
linearModifier(resources, span, ccData, [](float x) { return x; });
|
|
||||||
}
|
|
||||||
|
|
||||||
void multiplicativeModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData)
|
|
||||||
{
|
|
||||||
multiplicativeModifier(resources, span, ccData, [](float x) { return x; });
|
|
||||||
}
|
|
||||||
|
|
||||||
void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
|
void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
|
||||||
{
|
{
|
||||||
const auto numSamples = modulationSpan.size();
|
const auto numSamples = modulationSpan.size();
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@
|
||||||
#include "HistoricalBuffer.h"
|
#include "HistoricalBuffer.h"
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "AudioBuffer.h"
|
#include "AudioBuffer.h"
|
||||||
#include "MidiState.h"
|
|
||||||
#include "Wavetables.h"
|
|
||||||
#include "Resources.h"
|
#include "Resources.h"
|
||||||
#include "AudioSpan.h"
|
#include "AudioSpan.h"
|
||||||
#include "LeakDetector.h"
|
#include "LeakDetector.h"
|
||||||
#include <absl/types/span.h>
|
#include "absl/types/span.h"
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
// license. You should have receive a LICENSE.md file along with the code.
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#include "sfizz/SfzHelpers.h"
|
#include "sfizz/ModifierHelpers.h"
|
||||||
#include "sfizz/Buffer.h"
|
#include "sfizz/Buffer.h"
|
||||||
#include "catch2/catch.hpp"
|
#include "catch2/catch.hpp"
|
||||||
#include <absl/algorithm/container.h>
|
#include <absl/algorithm/container.h>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue