Remove the event envelopes \o/
This commit is contained in:
parent
bd85a97db3
commit
16b8cc1cfc
5 changed files with 0 additions and 431 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue