diff --git a/sources/LinearEnvelope.h b/sources/LinearEnvelope.h index 8950ad0b..3a6848c1 100644 --- a/sources/LinearEnvelope.h +++ b/sources/LinearEnvelope.h @@ -1,13 +1,89 @@ #include "Globals.h" +#include "Helpers.h" +#include "SIMDHelpers.h" +#include +#include +#include + namespace sfz { +template class LinearEnvelope { public: + LinearEnvelope() + { + setMaxCapacity(maxCapacity); + } + LinearEnvelope(int maxCapacity, std::function function) + { + setMaxCapacity(maxCapacity); + setFunction(function); + } + + void setMaxCapacity(int maxCapacity) + { + events.reserve(maxCapacity); + this->maxCapacity = maxCapacity; + } + + void setFunction(std::function function) + { + this->function = function; + } + + void registerEvent(int timestamp, Type inputValue) + { + if (events.size() < maxCapacity) + events.emplace_back(timestamp, function(inputValue)); + } + + void clear() + { + events.clear(); + } + + void reset(Type value) + { + clear(); + currentValue = function(value); + } + + void getBlock(absl::span output) + { + absl::c_sort(events, [](const Event& lhs, const Event& rhs) { + return lhs.timestamp < rhs.timestamp; + }); + int index { 0 }; + + for (auto& event: events) + { + const auto length = min(event.timestamp, output.size()) - index; + if (length == 0) + continue; + + const auto step = (function(event.value) - currentValue) / length; + ::linearRamp(output.subspan(index, length), currentValue, step); + } + + if (index < output.size()) + ::fill(output.subspan(index), currentValue); + + clear(); + } private: - + struct Event + { + int timestamp; + Type value; + }; + std::function function { [](Type input) { return input; } }; + static_assert(std::is_numeric::value); + std::vector events; + int maxCapacity { config::defaultSamplesPerBlock }; + Type currentValue; }; } \ No newline at end of file