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.
|
// 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
|
// 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 "ADSREnvelope.h"
|
||||||
|
|
||||||
// Include the generic implementations
|
// Include the generic implementations
|
||||||
#include "EventEnvelopes.cpp"
|
|
||||||
#include "ADSREnvelope.cpp"
|
#include "ADSREnvelope.cpp"
|
||||||
|
|
||||||
// And explicitely instantiate the float version
|
// And explicitely instantiate the float version
|
||||||
namespace sfz
|
namespace sfz
|
||||||
{
|
{
|
||||||
template class EventEnvelope<float>;
|
|
||||||
template class MultiplicativeEnvelope<float>;
|
|
||||||
template class LinearEnvelope<float>;
|
|
||||||
template class ADSREnvelope<float>;
|
template class ADSREnvelope<float>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "ADSREnvelope.h"
|
#include "ADSREnvelope.h"
|
||||||
#include "EventEnvelopes.h"
|
|
||||||
#include "HistoricalBuffer.h"
|
#include "HistoricalBuffer.h"
|
||||||
#include "Region.h"
|
#include "Region.h"
|
||||||
#include "AudioBuffer.h"
|
#include "AudioBuffer.h"
|
||||||
|
|
@ -282,13 +281,6 @@ private:
|
||||||
std::vector<EQHolderPtr> equalizers;
|
std::vector<EQHolderPtr> equalizers;
|
||||||
|
|
||||||
ADSREnvelope<float> egEnvelope;
|
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) };
|
float bendStepFactor { centsFactor(1) };
|
||||||
|
|
||||||
WavetableOscillator waveOscillator;
|
WavetableOscillator waveOscillator;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
// license. You should have receive a LICENSE.md file along with the code.
|
// 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
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#include "sfizz/EventEnvelopes.h"
|
|
||||||
#include "sfizz/SfzHelpers.h"
|
#include "sfizz/SfzHelpers.h"
|
||||||
#include "sfizz/Buffer.h"
|
#include "sfizz/Buffer.h"
|
||||||
#include "catch2/catch.hpp"
|
#include "catch2/catch.hpp"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue