linearEnvelope is now a free function
This commit is contained in:
parent
922cbde6c5
commit
1523a14ee8
3 changed files with 42 additions and 40 deletions
|
|
@ -8,8 +8,6 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "CCMap.h"
|
#include "CCMap.h"
|
||||||
#include "Range.h"
|
#include "Range.h"
|
||||||
#include "absl/types/span.h"
|
|
||||||
#include "SIMDHelpers.h"
|
|
||||||
|
|
||||||
namespace sfz
|
namespace sfz
|
||||||
{
|
{
|
||||||
|
|
@ -125,25 +123,6 @@ public:
|
||||||
|
|
||||||
const EventVector& getEvents(int ccIdx) const noexcept;
|
const EventVector& getEvents(int ccIdx) const noexcept;
|
||||||
|
|
||||||
template<class T, class F>
|
|
||||||
void linearEnvelope(T&& modifier, absl::Span<float> envelope, F&& lambda) const
|
|
||||||
{
|
|
||||||
const auto eventList = getEvents(modifier.cc);
|
|
||||||
ASSERT(eventList.size() > 0);
|
|
||||||
ASSERT(eventList[0].delay == 0);
|
|
||||||
|
|
||||||
auto lastValue = lambda(modifier.value, eventList[0].value);
|
|
||||||
auto lastDelay = eventList[0].delay;
|
|
||||||
for (unsigned i = 1; i < eventList.size(); ++ i) {
|
|
||||||
const auto event = eventList[i];
|
|
||||||
const auto length = event.delay - lastDelay;
|
|
||||||
const auto step = (lambda(modifier.value, event.value) - lastValue)/ length;
|
|
||||||
lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
|
||||||
lastDelay += length;
|
|
||||||
}
|
|
||||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "Macros.h"
|
#include "Macros.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "MathHelpers.h"
|
#include "MathHelpers.h"
|
||||||
|
#include "SIMDHelpers.h"
|
||||||
#include "absl/meta/type_traits.h"
|
#include "absl/meta/type_traits.h"
|
||||||
#include "Defaults.h"
|
#include "Defaults.h"
|
||||||
|
|
||||||
|
|
@ -342,5 +343,23 @@ float crossfadeOut(const sfz::Range<T>& crossfadeRange, U value, SfzCrossfadeCur
|
||||||
return 1.0f;
|
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);
|
||||||
|
|
||||||
|
auto lastValue = lambda(events[0].value);
|
||||||
|
auto lastDelay = events[0].delay;
|
||||||
|
for (unsigned i = 1; i < events.size(); ++ i) {
|
||||||
|
const auto event = events[i];
|
||||||
|
const auto length = event.delay - lastDelay;
|
||||||
|
const auto step = (lambda(event.value) - lastValue)/ length;
|
||||||
|
lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
||||||
|
lastDelay += length;
|
||||||
|
}
|
||||||
|
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sfz
|
} // namespace sfz
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -262,10 +262,7 @@ void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
const auto numSamples = buffer.getNumFrames();
|
const auto numSamples = buffer.getNumFrames();
|
||||||
const auto leftBuffer = buffer.getSpan(0);
|
const auto leftBuffer = buffer.getSpan(0);
|
||||||
|
const auto xfCurve = region->crossfadeCCCurve;
|
||||||
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);
|
|
||||||
|
|
||||||
auto modulationSpan = resources.bufferPool.getBuffer(numSamples);
|
auto modulationSpan = resources.bufferPool.getBuffer(numSamples);
|
||||||
auto tempSpan = resources.bufferPool.getBuffer(numSamples);
|
auto tempSpan = resources.bufferPool.getBuffer(numSamples);
|
||||||
|
|
@ -275,7 +272,8 @@ void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
fill<float>(*modulationSpan, baseGain);
|
fill<float>(*modulationSpan, baseGain);
|
||||||
for (auto& mod : region->amplitudeCC) {
|
for (auto& mod : region->amplitudeCC) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, gainModifier<float>);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
applyGain<float>(*modulationSpan, leftBuffer);
|
applyGain<float>(*modulationSpan, leftBuffer);
|
||||||
|
|
@ -283,11 +281,13 @@ void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
|
||||||
// Crossfade envelopes
|
// Crossfade envelopes
|
||||||
fill<float>(*modulationSpan, 1.0f);
|
fill<float>(*modulationSpan, 1.0f);
|
||||||
for (auto& mod : region->crossfadeCCInRange) {
|
for (auto& mod : region->crossfadeCCInRange) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, xfinBind);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
for (auto& mod : region->crossfadeCCOutRange) {
|
for (auto& mod : region->crossfadeCCOutRange) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, xfoutBind);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
applyGain<float>(*modulationSpan, leftBuffer);
|
applyGain<float>(*modulationSpan, leftBuffer);
|
||||||
|
|
@ -307,20 +307,18 @@ void sfz::Voice::ampStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
|
|
||||||
const auto numSamples = buffer.getNumFrames();
|
const auto numSamples = buffer.getNumFrames();
|
||||||
|
|
||||||
|
const auto xfCurve = region->crossfadeCCCurve;
|
||||||
|
|
||||||
auto modulationSpan = resources.bufferPool.getBuffer(numSamples);
|
auto modulationSpan = resources.bufferPool.getBuffer(numSamples);
|
||||||
auto tempSpan = resources.bufferPool.getBuffer(numSamples);
|
auto tempSpan = resources.bufferPool.getBuffer(numSamples);
|
||||||
if (!modulationSpan || !tempSpan)
|
if (!modulationSpan || !tempSpan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
// Amplitude envelope
|
// Amplitude envelope
|
||||||
fill<float>(*modulationSpan, baseGain);
|
fill<float>(*modulationSpan, baseGain);
|
||||||
for (auto& mod : region->amplitudeCC) {
|
for (auto& mod : region->amplitudeCC) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, gainModifier<float>);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
buffer.applyGain(*modulationSpan);
|
buffer.applyGain(*modulationSpan);
|
||||||
|
|
@ -329,11 +327,13 @@ void sfz::Voice::ampStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// Crossfade envelopes
|
// Crossfade envelopes
|
||||||
fill<float>(*modulationSpan, 1.0f);
|
fill<float>(*modulationSpan, 1.0f);
|
||||||
for (auto& mod : region->crossfadeCCInRange) {
|
for (auto& mod : region->crossfadeCCInRange) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, xfinBind);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
for (auto& mod : region->crossfadeCCOutRange) {
|
for (auto& mod : region->crossfadeCCOutRange) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, xfoutBind);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); });
|
||||||
applyGain<float>(*tempSpan, *modulationSpan);
|
applyGain<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
buffer.applyGain(*modulationSpan);
|
buffer.applyGain(*modulationSpan);
|
||||||
|
|
@ -366,7 +366,8 @@ void sfz::Voice::panStageMono(AudioSpan<float> buffer) noexcept
|
||||||
// Apply panning
|
// Apply panning
|
||||||
fill<float>(*modulationSpan, region->pan);
|
fill<float>(*modulationSpan, region->pan);
|
||||||
for (auto& mod : region->panCC) {
|
for (auto& mod : region->panCC) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, gainModifier<float>);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||||
|
|
@ -388,7 +389,8 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// panningModulation(*modulationSpan);
|
// panningModulation(*modulationSpan);
|
||||||
fill<float>(*modulationSpan, region->pan);
|
fill<float>(*modulationSpan, region->pan);
|
||||||
for (auto& mod : region->panCC) {
|
for (auto& mod : region->panCC) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, gainModifier<float>);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||||
|
|
@ -397,7 +399,8 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// widthModulation(*modulationSpan);
|
// widthModulation(*modulationSpan);
|
||||||
fill<float>(*modulationSpan, region->width);
|
fill<float>(*modulationSpan, region->width);
|
||||||
for (auto& mod : region->widthCC) {
|
for (auto& mod : region->widthCC) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, gainModifier<float>);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
width<float>(*modulationSpan, leftBuffer, rightBuffer);
|
width<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||||
|
|
@ -405,7 +408,8 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||||
// positionModulation(*modulationSpan);
|
// positionModulation(*modulationSpan);
|
||||||
fill<float>(*modulationSpan, region->position);
|
fill<float>(*modulationSpan, region->position);
|
||||||
for (auto& mod : region->positionCC) {
|
for (auto& mod : region->positionCC) {
|
||||||
resources.midiState.linearEnvelope(mod, *tempSpan, gainModifier<float>);
|
const auto events = resources.midiState.getEvents(mod.cc);
|
||||||
|
linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; });
|
||||||
add<float>(*tempSpan, *modulationSpan);
|
add<float>(*tempSpan, *modulationSpan);
|
||||||
}
|
}
|
||||||
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue