Remove the event envelopes \o/

This commit is contained in:
Paul Ferrand 2020-03-31 00:33:26 +02:00
parent bd85a97db3
commit 16b8cc1cfc
5 changed files with 0 additions and 431 deletions

View file

@ -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 <absl/algorithm/container.h>
namespace sfz {
template <class Type>
EventEnvelope<Type>::EventEnvelope()
{
setMaxCapacity(maxCapacity);
}
template <class Type>
EventEnvelope<Type>::EventEnvelope(int maxCapacity, std::function<Type(Type)> function)
{
setMaxCapacity(maxCapacity);
setFunction(function);
}
template <class Type>
void EventEnvelope<Type>::setMaxCapacity(int maxCapacity)
{
events.reserve(maxCapacity);
this->maxCapacity = maxCapacity;
}
template <class Type>
void EventEnvelope<Type>::setFunction(std::function<Type(Type)> function)
{
this->function = function;
}
template <class Type>
void EventEnvelope<Type>::registerEvent(int timestamp, Type inputValue)
{
if (resetEvents)
clear();
if (static_cast<int>(events.size()) < maxCapacity)
events.emplace_back(timestamp, function(inputValue));
}
template <class Type>
void EventEnvelope<Type>::prepareEvents(int blockLength)
{
if (resetEvents)
clear();
absl::c_stable_sort(events, [](const std::pair<int, Type>& lhs, const std::pair<int, Type>& 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 <class Type>
void EventEnvelope<Type>::clear()
{
events.clear();
resetEvents = false;
}
template <class Type>
void EventEnvelope<Type>::reset(Type value)
{
clear();
currentValue = function(value);
resetEvents = false;
}
template <class Type>
void EventEnvelope<Type>::getBlock(absl::Span<Type> output)
{
prepareEvents(output.size());
}
template <class Type>
void EventEnvelope<Type>::getQuantizedBlock(absl::Span<Type> output, Type)
{
prepareEvents(output.size());
}
template <class Type>
void LinearEnvelope<Type>::getBlock(absl::Span<Type> output)
{
EventEnvelope<Type>::getBlock(output);
auto& events = EventEnvelope<Type>::events;
auto& currentValue = EventEnvelope<Type>::currentValue;
int index { 0 };
for (auto& event : events) {
const auto length = min(event.first, static_cast<int>(output.size())) - index;
if (length == 0) {
currentValue = event.second;
continue;
}
const auto step = (event.second - currentValue) / length;
currentValue = linearRamp<Type>(output.subspan(index, length), currentValue, step);
index += length;
}
if (index < static_cast<int>(output.size()))
fill<Type>(output.subspan(index), currentValue);
}
template <class Type>
void LinearEnvelope<Type>::getQuantizedBlock(absl::Span<Type> output, Type quantizationStep)
{
EventEnvelope<Type>::getQuantizedBlock(output, quantizationStep);
auto& events = EventEnvelope<Type>::events;
auto& currentValue = EventEnvelope<Type>::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<int>(output.size());
for (auto& event : events) {
const auto newValue = quantize(event.second);
if (event.first > outputSize) {
fill<Type>(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<Type>(output.subspan(index, length), currentValue);
currentValue = newValue;
index += length;
continue;
}
const auto numSteps = static_cast<int>(difference / quantizationStep);
const auto stepLength = static_cast<int>(length / numSteps);
for (int i = 0; i < numSteps; ++i) {
fill<Type>(output.subspan(index, stepLength), currentValue);
const auto delta = quantizationStep + currentValue - quantize(currentValue);
currentValue += currentValue <= newValue ? delta : -delta;
index += stepLength;
}
}
if (index < outputSize)
fill<Type>(output.subspan(index), currentValue);
}
template <class Type>
MultiplicativeEnvelope<Type>::MultiplicativeEnvelope()
{
EventEnvelope<Type>::reset(1.0);
}
template <class Type>
void MultiplicativeEnvelope<Type>::getBlock(absl::Span<Type> output)
{
EventEnvelope<Type>::getBlock(output);
auto& events = EventEnvelope<Type>::events;
auto& currentValue = EventEnvelope<Type>::currentValue;
int index { 0 };
for (auto& event : events) {
const auto length = min(event.first, static_cast<int>(output.size())) - index;
if (length == 0) {
currentValue = event.second;
continue;
}
const auto step = std::exp((std::log(event.second) - std::log(currentValue)) / length);
multiplicativeRamp<Type>(output.subspan(index, length), currentValue, step);
currentValue = event.second;
index += length;
}
if (index < static_cast<int>(output.size()))
fill<Type>(output.subspan(index), currentValue);
}
template <class Type>
void MultiplicativeEnvelope<Type>::getQuantizedBlock(absl::Span<Type> output, Type quantizationStep)
{
EventEnvelope<Type>::getQuantizedBlock(output, quantizationStep);
auto& events = EventEnvelope<Type>::events;
auto& currentValue = EventEnvelope<Type>::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<int>(output.size());
for (auto& event : events) {
const auto newValue = quantize(event.second);
if (event.first > outputSize) {
fill<Type>(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<Type>(output.subspan(index, length), currentValue);
currentValue = newValue;
index += 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<Type>(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<Type>(output.subspan(index), currentValue);
}
}

View file

@ -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 <absl/types/span.h>
#include <functional>
#include <type_traits>
#include <vector>
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 Type>
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<Type(Type)> 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<Type(Type)> 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<Type> 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<Type> output, Type quantizationStep);
protected:
std::vector<std::pair<int, Type>> events;
Type currentValue { 0.0 };
private:
static_assert(std::is_arithmetic<Type>::value, "Type should be arithmetic");
std::function<Type(Type)> 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 Type>
class LinearEnvelope: public EventEnvelope<Type> {
public:
void getBlock(absl::Span<Type> output) final;
void getQuantizedBlock(absl::Span<Type> output, Type quantizationStep) final;
};
/**
* @brief Describes a simple multiplicative envelope.
*
* @tparam Type
*/
template <class Type>
class MultiplicativeEnvelope: public EventEnvelope<Type> {
public:
MultiplicativeEnvelope();
void getBlock(absl::Span<Type> output) final;
void getQuantizedBlock(absl::Span<Type> output, Type quantizationStep) final;
};
}

View file

@ -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<float>;
template class MultiplicativeEnvelope<float>;
template class LinearEnvelope<float>;
template class ADSREnvelope<float>;
}

View file

@ -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<EQHolderPtr> equalizers;
ADSREnvelope<float> egEnvelope;
LinearEnvelope<float> amplitudeEnvelope; // linear events
LinearEnvelope<float> crossfadeEnvelope;
LinearEnvelope<float> panEnvelope;
LinearEnvelope<float> positionEnvelope;
LinearEnvelope<float> widthEnvelope;
MultiplicativeEnvelope<float> pitchBendEnvelope;
MultiplicativeEnvelope<float> volumeEnvelope;
float bendStepFactor { centsFactor(1) };
WavetableOscillator waveOscillator;

View file

@ -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"