diff --git a/src/sfizz/EventEnvelopes.cpp b/src/sfizz/EventEnvelopes.cpp deleted file mode 100644 index c64a5415..00000000 --- a/src/sfizz/EventEnvelopes.cpp +++ /dev/null @@ -1,277 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// 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 - -#include "EventEnvelopes.h" -#include "SIMDHelpers.h" -#include "MathHelpers.h" -#include - -namespace sfz { - -template -EventEnvelope::EventEnvelope() -{ - setMaxCapacity(maxCapacity); -} - -template -EventEnvelope::EventEnvelope(int maxCapacity, std::function function) -{ - setMaxCapacity(maxCapacity); - setFunction(function); -} - -template -void EventEnvelope::setMaxCapacity(int maxCapacity) -{ - events.reserve(maxCapacity); - this->maxCapacity = maxCapacity; -} - -template -void EventEnvelope::setFunction(std::function function) -{ - this->function = function; -} - -template -void EventEnvelope::registerEvent(int timestamp, Type inputValue) -{ - if (resetEvents) - clear(); - - if (static_cast(events.size()) < maxCapacity) - events.emplace_back(timestamp, function(inputValue)); -} - -template -void EventEnvelope::prepareEvents(int blockLength) -{ - if (resetEvents) - clear(); - - absl::c_stable_sort(events, [](const std::pair& lhs, const std::pair& rhs) { - return lhs.first < rhs.first; - }); - - auto eventIt = events.begin(); - while (eventIt < events.end()) { - if (eventIt->first >= blockLength) { - eventIt->first = blockLength - 1; - eventIt->second = events.back().second; - ++eventIt; - break; - } - - auto nextEventIt = std::next(eventIt); - while (nextEventIt < events.end() && eventIt->first == nextEventIt->first ) { - eventIt->second = nextEventIt->second; - ++nextEventIt; - } - ++eventIt; - } - events.resize(std::distance(events.begin(), eventIt)); - - resetEvents = true; -} - -template -void EventEnvelope::clear() -{ - events.clear(); - resetEvents = false; -} - -template -void EventEnvelope::reset(Type value) -{ - clear(); - currentValue = function(value); - resetEvents = false; -} - -template -void EventEnvelope::getBlock(absl::Span output) -{ - prepareEvents(output.size()); -} - -template -void EventEnvelope::getQuantizedBlock(absl::Span output, Type) -{ - prepareEvents(output.size()); -} - -template -void LinearEnvelope::getBlock(absl::Span output) -{ - EventEnvelope::getBlock(output); - auto& events = EventEnvelope::events; - auto& currentValue = EventEnvelope::currentValue; - - int index { 0 }; - for (auto& event : events) { - const auto length = min(event.first, static_cast(output.size())) - index; - if (length == 0) { - currentValue = event.second; - continue; - } - - const auto step = (event.second - currentValue) / length; - currentValue = linearRamp(output.subspan(index, length), currentValue, step); - index += length; - } - - if (index < static_cast(output.size())) - fill(output.subspan(index), currentValue); -} - -template -void LinearEnvelope::getQuantizedBlock(absl::Span output, Type quantizationStep) -{ - EventEnvelope::getQuantizedBlock(output, quantizationStep); - auto& events = EventEnvelope::events; - auto& currentValue = EventEnvelope::currentValue; - - ASSERT(quantizationStep != 0.0); - int index { 0 }; - - auto quantize = [quantizationStep](Type value) -> Type { - return std::round(value / quantizationStep) * quantizationStep; - }; - - const auto outputSize = static_cast(output.size()); - for (auto& event : events) { - const auto newValue = quantize(event.second); - - if (event.first > outputSize) { - fill(output.subspan(index), currentValue); - currentValue = newValue; - index = outputSize; - continue; - } - - const auto length = event.first - index - 1; - if (length <= 0) { - currentValue = newValue; - continue; - } - - const auto difference = std::abs(newValue - currentValue); - if (difference < quantizationStep) { - fill(output.subspan(index, length), currentValue); - currentValue = newValue; - index += length; - continue; - } - - const auto numSteps = static_cast(difference / quantizationStep); - const auto stepLength = static_cast(length / numSteps); - for (int i = 0; i < numSteps; ++i) { - fill(output.subspan(index, stepLength), currentValue); - const auto delta = quantizationStep + currentValue - quantize(currentValue); - currentValue += currentValue <= newValue ? delta : -delta; - index += stepLength; - } - } - - if (index < outputSize) - fill(output.subspan(index), currentValue); -} - -template -MultiplicativeEnvelope::MultiplicativeEnvelope() -{ - EventEnvelope::reset(1.0); -} - -template -void MultiplicativeEnvelope::getBlock(absl::Span output) -{ - EventEnvelope::getBlock(output); - auto& events = EventEnvelope::events; - auto& currentValue = EventEnvelope::currentValue; - - int index { 0 }; - for (auto& event : events) { - const auto length = min(event.first, static_cast(output.size())) - index; - if (length == 0) { - currentValue = event.second; - continue; - } - - const auto step = std::exp((std::log(event.second) - std::log(currentValue)) / length); - multiplicativeRamp(output.subspan(index, length), currentValue, step); - currentValue = event.second; - index += length; - } - - if (index < static_cast(output.size())) - fill(output.subspan(index), currentValue); -} - -template -void MultiplicativeEnvelope::getQuantizedBlock(absl::Span output, Type quantizationStep) -{ - EventEnvelope::getQuantizedBlock(output, quantizationStep); - auto& events = EventEnvelope::events; - auto& currentValue = EventEnvelope::currentValue; - - ASSERT(quantizationStep != 0.0); - int index { 0 }; - - const auto logStep = std::log(quantizationStep); - // 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](Type value) -> Type { - return std::exp(logStep * std::round(std::log(value)/logStep)); - }; - - const auto outputSize = static_cast(output.size()); - for (auto& event : events) { - const auto newValue = quantize(event.second); - - if (event.first > outputSize) { - fill(output.subspan(index), currentValue); - currentValue = newValue; - index = outputSize; - continue; - } - - const auto length = event.first - index - 1; - if (length <= 0) { - currentValue = newValue; - continue; - } - - const auto difference = newValue > currentValue ? newValue / currentValue : currentValue / newValue; - if (difference < quantizationStep) { - fill(output.subspan(index, length), currentValue); - currentValue = newValue; - index += length; - continue; - } - - const auto numSteps = static_cast(std::log(difference) / logStep); - const auto stepLength = static_cast(length / numSteps); - for (int i = 0; i < numSteps; ++i) { - fill(output.subspan(index, stepLength), currentValue); - const auto delta = newValue > currentValue ? - quantize(currentValue) / currentValue * quantizationStep : - quantize(currentValue) / currentValue / quantizationStep ; - currentValue *= delta; - index += stepLength; - } - } - - if (index < outputSize) - fill(output.subspan(index), currentValue); -} - -} diff --git a/src/sfizz/EventEnvelopes.h b/src/sfizz/EventEnvelopes.h deleted file mode 100644 index c56d1dd6..00000000 --- a/src/sfizz/EventEnvelopes.h +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause - -// This code is part of the sfizz library and is licensed under a BSD 2-clause -// 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 - -#pragma once -#include "Config.h" -#include "LeakDetector.h" -#include -#include -#include -#include - -namespace sfz { -/** - * @brief Describes a simple envelope that can be polled in a blockwise - * manner. It works by storing "events" in the immediate future and linearly - * interpolating between these events. This envelope can also transform its - * incoming target points through a lambda, although the lambda function is applied before the interpolation. - * - * The way to use this class is by repeatedly calling `registerEvent` and then - * `getBlock` to get a block of interpolated values in between the specified events. - * You should only register events whose timestamps are below the size of the block - * you will require when calling `getBlock`. - * - * @tparam Type - */ -template -class EventEnvelope { -public: - /** - * @brief Construct a new linear envelope with a default memory size for - * incoming events. - * - */ - EventEnvelope(); - /** - * @brief Construct a new linear envelope with a specific memory size for - * incoming events as well as a transformation function for incoming events. - * - * @param maxCapacity - * @param function - */ - EventEnvelope(int maxCapacity, std::function function); - /** - * @brief Set the maximum memory size for incoming events - * - * @param maxCapacity - */ - void setMaxCapacity(int maxCapacity); - /** - * @brief Set the transformation function for the value of incoming events. - * - * @param function - */ - void setFunction(std::function function); - /** - * @brief Register a new event. Note that the timestamp of the new value should - * be less than the future call to `getBlock` otherwise the event will be ignored. - * - * @param timestamp - * @param inputValue - */ - void registerEvent(int timestamp, Type inputValue); - /** - * @brief Clear all events in memory - * - */ - void clear(); - /** - * @brief Reset the envelope and clears the memory. - * - * @param value - */ - void reset(Type value = 0.0); - /** - * @brief Get a block of interpolated values between events previously registered - * using `registerEvent`. - * - * @param output - */ - virtual void getBlock(absl::Span output); - /** - * @brief Get a block of interpolated values with a forced quantization. The - * values within the block will vary in quantization steps. - * - * @param output - * @param quantizationStep - */ - virtual void getQuantizedBlock(absl::Span output, Type quantizationStep); -protected: - std::vector> events; - Type currentValue { 0.0 }; -private: - static_assert(std::is_arithmetic::value, "Type should be arithmetic"); - std::function function { [](Type input) -> Type { return input; } }; - int maxCapacity { config::defaultSamplesPerBlock }; - void prepareEvents(int blockLength); - bool resetEvents { false }; - LEAK_DETECTOR(EventEnvelope); -}; - - -/** - * @brief Describes a simple linear envelope. - * - * @tparam Type - */ -template -class LinearEnvelope: public EventEnvelope { -public: - void getBlock(absl::Span output) final; - void getQuantizedBlock(absl::Span output, Type quantizationStep) final; -}; - -/** - * @brief Describes a simple multiplicative envelope. - * - * @tparam Type - */ -template -class MultiplicativeEnvelope: public EventEnvelope { -public: - MultiplicativeEnvelope(); - void getBlock(absl::Span output) final; - void getQuantizedBlock(absl::Span output, Type quantizationStep) final; -}; -} diff --git a/src/sfizz/FloatEnvelopes.cpp b/src/sfizz/FloatEnvelopes.cpp index 54e98fd9..e4c5289c 100644 --- a/src/sfizz/FloatEnvelopes.cpp +++ b/src/sfizz/FloatEnvelopes.cpp @@ -4,29 +4,13 @@ // 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 -/** - * @file FloatEnvelopes.cpp - * @author Paul Ferrand (paul@ferrand.cc) - * @brief Force the instantiations of the ADSR and linear envelopes for floats - * @version 0.1 - * @date 2019-11-30 - * - * @copyright Copyright (c) 2019 Paul Ferrand - * - */ - -#include "EventEnvelopes.h" #include "ADSREnvelope.h" // Include the generic implementations -#include "EventEnvelopes.cpp" #include "ADSREnvelope.cpp" // And explicitely instantiate the float version namespace sfz { - template class EventEnvelope; - template class MultiplicativeEnvelope; - template class LinearEnvelope; template class ADSREnvelope; } diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 242d045d..7afcd24e 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -7,7 +7,6 @@ #pragma once #include "Config.h" #include "ADSREnvelope.h" -#include "EventEnvelopes.h" #include "HistoricalBuffer.h" #include "Region.h" #include "AudioBuffer.h" @@ -282,13 +281,6 @@ private: std::vector equalizers; ADSREnvelope egEnvelope; - LinearEnvelope amplitudeEnvelope; // linear events - LinearEnvelope crossfadeEnvelope; - LinearEnvelope panEnvelope; - LinearEnvelope positionEnvelope; - LinearEnvelope widthEnvelope; - MultiplicativeEnvelope pitchBendEnvelope; - MultiplicativeEnvelope volumeEnvelope; float bendStepFactor { centsFactor(1) }; WavetableOscillator waveOscillator; diff --git a/tests/EventEnvelopesT.cpp b/tests/EventEnvelopesT.cpp index a2916165..d4efd80a 100644 --- a/tests/EventEnvelopesT.cpp +++ b/tests/EventEnvelopesT.cpp @@ -4,7 +4,6 @@ // 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 -#include "sfizz/EventEnvelopes.h" #include "sfizz/SfzHelpers.h" #include "sfizz/Buffer.h" #include "catch2/catch.hpp"