Update STFX library
This commit is contained in:
parent
ba22c38a61
commit
b79063c97b
139
stfx-library.h
139
stfx-library.h
@ -10,8 +10,86 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace stfx {
|
namespace stfx {
|
||||||
|
// Convenient units for range parameters - not really part of the main STFX API
|
||||||
|
namespace units {
|
||||||
|
static inline double dbToGain(double db) {
|
||||||
|
return std::pow(10, db*0.05);
|
||||||
|
}
|
||||||
|
static inline double gainToDb(double gain) {
|
||||||
|
return std::log10(std::max<double>(gain, 1e-10))*20;
|
||||||
|
}
|
||||||
|
static inline double dbToEnergy(double db) {
|
||||||
|
return std::pow(10, db*0.1);
|
||||||
|
}
|
||||||
|
static inline double energyToDb(double gain) {
|
||||||
|
return std::log10(std::max<double>(gain, 1e-10))*10;
|
||||||
|
}
|
||||||
|
static inline double pcToRatio(double percent) {
|
||||||
|
return percent*0.01;
|
||||||
|
}
|
||||||
|
static inline double ratioToPc(double linear) {
|
||||||
|
return linear*100;
|
||||||
|
}
|
||||||
|
static inline double kHzToHz(double kHz) {
|
||||||
|
return kHz*1000;
|
||||||
|
}
|
||||||
|
static inline double hzToKHz(double hz) {
|
||||||
|
return hz*0.001;
|
||||||
|
}
|
||||||
|
static inline double sToMs(double sec) {
|
||||||
|
return sec*1000;
|
||||||
|
}
|
||||||
|
static inline double msToS(double ms) {
|
||||||
|
return ms*0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class RangeParam>
|
||||||
|
RangeParam & rangeGain(RangeParam ¶m) {
|
||||||
|
return param
|
||||||
|
.unit("dB", 1, dbToGain, gainToDb) // default display is dB
|
||||||
|
.unit("%", 0, pcToRatio, ratioToPc)
|
||||||
|
.exact(0, "off")
|
||||||
|
.unit("x"); // Allow things like "2x" (~6dB) for text-input
|
||||||
|
}
|
||||||
|
template<class RangeParam>
|
||||||
|
RangeParam & rangeHz(RangeParam ¶m) {
|
||||||
|
return param
|
||||||
|
.unit("Hz", 0, 10, 1000)
|
||||||
|
.unit("Hz", 1, 1, 10)
|
||||||
|
.unit("Hz", 2, 0, 1)
|
||||||
|
.unit("kHz", 1, kHzToHz, hzToKHz, 10000, 1e100)
|
||||||
|
.unit("kHz", 2, kHzToHz, hzToKHz, 1000, 10000);
|
||||||
|
}
|
||||||
|
template<class RangeParam>
|
||||||
|
RangeParam & rangePercent(RangeParam ¶m) {
|
||||||
|
return param
|
||||||
|
.unit("%", 0, pcToRatio, ratioToPc)
|
||||||
|
.unit("x");
|
||||||
|
}
|
||||||
|
template<class RangeParam>
|
||||||
|
RangeParam & rangeMs(RangeParam ¶m) {
|
||||||
|
return param
|
||||||
|
.unit("ms", 2, 0, 1)
|
||||||
|
.unit("ms", 1, 1, 10)
|
||||||
|
.unit("ms", 0, 10, 1000)
|
||||||
|
.unit("seconds", 2, sToMs, msToS, 0, 1)
|
||||||
|
.unit("seconds", 1, sToMs, msToS, 1, 10)
|
||||||
|
.unit("seconds", 0, sToMs, msToS, 10, 1e100);
|
||||||
|
}
|
||||||
|
template<class RangeParam>
|
||||||
|
RangeParam & rangeSec(RangeParam ¶m) {
|
||||||
|
return param
|
||||||
|
.unit("seconds", 2, 0, 1)
|
||||||
|
.unit("seconds", 1, 1, 10)
|
||||||
|
.unit("seconds", 0, 10, 1e100)
|
||||||
|
.unit("ms", 2, msToS, sToMs, 0, 0.001)
|
||||||
|
.unit("ms", 1, msToS, sToMs, 0.001, 0.01)
|
||||||
|
.unit("ms", 0, msToS, sToMs, 0.01, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// A value which changes linearly within a given index range (e.g. a block)
|
// A value which changes linearly within a given index range (e.g. a block)
|
||||||
@ -20,7 +98,7 @@ namespace stfx {
|
|||||||
public:
|
public:
|
||||||
LinearSegment(double offset, double gradient) : offset(offset), gradient(gradient) {}
|
LinearSegment(double offset, double gradient) : offset(offset), gradient(gradient) {}
|
||||||
|
|
||||||
double at(int i) {
|
double at(double i) {
|
||||||
return offset + i*gradient;
|
return offset + i*gradient;
|
||||||
}
|
}
|
||||||
bool changing() {
|
bool changing() {
|
||||||
@ -119,7 +197,7 @@ namespace stfx {
|
|||||||
}
|
}
|
||||||
struct DoNothingEvent {
|
struct DoNothingEvent {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
void operator ()() {}
|
void operator()() {}
|
||||||
};
|
};
|
||||||
DoNothingEvent operator [](int) {
|
DoNothingEvent operator [](int) {
|
||||||
return DoNothingEvent();
|
return DoNothingEvent();
|
||||||
@ -142,7 +220,7 @@ namespace stfx {
|
|||||||
}
|
}
|
||||||
template<class EventList, class ...Others>
|
template<class EventList, class ...Others>
|
||||||
const Block & split(EventList &&list, Others &&...others) const {
|
const Block & split(EventList &&list, Others &&...others) const {
|
||||||
return split(list).split(std::forward<Others>(others)...);
|
return split(list, list.size()).split(std::forward<Others>(others)...);
|
||||||
}
|
}
|
||||||
/// Base-case for templated recursion
|
/// Base-case for templated recursion
|
||||||
const Block & split() const {
|
const Block & split() const {
|
||||||
@ -170,7 +248,7 @@ namespace stfx {
|
|||||||
current = v;
|
current = v;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
// Return the
|
// Return the current fade
|
||||||
Value from() const {
|
Value from() const {
|
||||||
return _from;
|
return _from;
|
||||||
}
|
}
|
||||||
@ -178,6 +256,11 @@ namespace stfx {
|
|||||||
return _to;
|
return _to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Storage>
|
||||||
|
void state(Storage &storage) {
|
||||||
|
storage("value", current);
|
||||||
|
}
|
||||||
|
|
||||||
// Shuffle the internal values along to start a new fade, return whether it's actually changing
|
// Shuffle the internal values along to start a new fade, return whether it's actually changing
|
||||||
bool _libStartFade() {
|
bool _libStartFade() {
|
||||||
_from = _to;
|
_from = _to;
|
||||||
@ -220,7 +303,7 @@ namespace stfx {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
PInfoPlaceholder & names(Args ...) {
|
PInfoPlaceholder & label(Args ...) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -228,11 +311,14 @@ namespace stfx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Base class for our effect to inherit from. Provides parameter classes and some default config.
|
/// Base class for our effect to inherit from. Provides parameter classes and some default config.
|
||||||
|
template<typename SampleType>
|
||||||
class LibraryEffectBase {
|
class LibraryEffectBase {
|
||||||
protected:
|
protected:
|
||||||
using ParamRange = LibraryParam<double>;
|
using ParamRange = LibraryParam<double>;
|
||||||
using ParamSteps = LibraryParam<int>;
|
using ParamStepped = LibraryParam<int>;
|
||||||
public:
|
public:
|
||||||
|
using Sample = SampleType;
|
||||||
|
|
||||||
ParamRange bpm{120};
|
ParamRange bpm{120};
|
||||||
|
|
||||||
double paramFadeMs() {
|
double paramFadeMs() {
|
||||||
@ -250,10 +336,10 @@ namespace stfx {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Creates an effect class from an effect template, with optional extra config.
|
/// Creates an effect class from an effect template, with optional extra config.
|
||||||
/// The effect template takes `EffectTemplate<Sample, BaseClass, ...ExtraConfig>`
|
/// The effect template takes `EffectTemplate<BaseClass, ...ExtraConfig>`
|
||||||
template<typename Sample, template <class, class...> class EffectTemplate, class ...ExtraConfig>
|
template<typename Sample, template <class, class...> class EffectTemplate, class ...ExtraConfig>
|
||||||
class LibraryEffect : public EffectTemplate<Sample, stfx::LibraryEffectBase, ExtraConfig...> {
|
class LibraryEffect : public EffectTemplate<stfx::LibraryEffectBase<Sample>, ExtraConfig...> {
|
||||||
using EffectClass = EffectTemplate<Sample, stfx::LibraryEffectBase, ExtraConfig...>;
|
using EffectClass = EffectTemplate<stfx::LibraryEffectBase<Sample>, ExtraConfig...>;
|
||||||
|
|
||||||
// This is passed to the effect's `.state()` method during initialisation, and collects pointers to the effect's parameters
|
// This is passed to the effect's `.state()` method during initialisation, and collects pointers to the effect's parameters
|
||||||
class CollectParams {
|
class CollectParams {
|
||||||
@ -262,12 +348,12 @@ namespace stfx {
|
|||||||
std::vector<LibraryParam<int> *> stepParams;
|
std::vector<LibraryParam<int> *> stepParams;
|
||||||
|
|
||||||
// Add registered parameters to the list
|
// Add registered parameters to the list
|
||||||
PInfoPlaceholder param(const char *, LibraryParam<double> ¶m, const char *codeExpr=nullptr) {
|
PInfoPlaceholder range(const char *, LibraryParam<double> ¶m, const char *codeExpr=nullptr) {
|
||||||
(void)codeExpr;
|
(void)codeExpr;
|
||||||
rangeParams.push_back(¶m);
|
rangeParams.push_back(¶m);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
PInfoPlaceholder param(const char *, LibraryParam<int> ¶m, const char *codeExpr=nullptr) {
|
PInfoPlaceholder stepped(const char *, LibraryParam<int> ¶m, const char *codeExpr=nullptr) {
|
||||||
(void)codeExpr;
|
(void)codeExpr;
|
||||||
stepParams.push_back(¶m);
|
stepParams.push_back(¶m);
|
||||||
return {};
|
return {};
|
||||||
@ -275,23 +361,28 @@ namespace stfx {
|
|||||||
|
|
||||||
// The effect might ask us to store/fetch the serialisation version, we just echo it back
|
// The effect might ask us to store/fetch the serialisation version, we just echo it back
|
||||||
static int version(int v) {return v;}
|
static int version(int v) {return v;}
|
||||||
|
// Ignore the UI/synchronisation stuff
|
||||||
|
static bool extra() {return false;}
|
||||||
|
static void invalidate(const char *) {}
|
||||||
|
|
||||||
// We ignore any basic type
|
// We ignore any basic type
|
||||||
void operator ()(bool) {}
|
void operator()(const char *, bool) {}
|
||||||
void operator ()(int) {}
|
void operator()(const char *, int) {}
|
||||||
void operator ()(long) {}
|
void operator()(const char *, long) {}
|
||||||
void operator ()(double) {}
|
void operator()(const char *, double) {}
|
||||||
void operator ()(float) {}
|
void operator()(const char *, float) {}
|
||||||
|
// And strings
|
||||||
|
void operator()(const char *, std::string &) {}
|
||||||
|
// Iterate through vectors
|
||||||
|
template<class Item>
|
||||||
|
void operator()(const char *label, std::vector<Item> &vector) {
|
||||||
|
for (auto &item : vector) (*this)(label, item);
|
||||||
|
}
|
||||||
// Assume all other arguments have a `.state()`, and recurse into it
|
// Assume all other arguments have a `.state()`, and recurse into it
|
||||||
template<class OtherObject>
|
template<class OtherObject>
|
||||||
void operator ()(OtherObject &obj) {
|
void operator()(const char *, OtherObject &obj) {
|
||||||
obj.state(*this);
|
obj.state(*this);
|
||||||
}
|
}
|
||||||
// Drop all names/labels we're given
|
|
||||||
template<class V>
|
|
||||||
void operator ()(const char *, V &v) {
|
|
||||||
(*this)(v);
|
|
||||||
}
|
|
||||||
template<class Fn>
|
template<class Fn>
|
||||||
void group(const char *, Fn fn) {
|
void group(const char *, Fn fn) {
|
||||||
fn(*this);
|
fn(*this);
|
||||||
@ -317,7 +408,7 @@ namespace stfx {
|
|||||||
std::vector<int> auxInputs, auxOutputs;
|
std::vector<int> auxInputs, auxOutputs;
|
||||||
int maxBlockSize = 256;
|
int maxBlockSize = 256;
|
||||||
|
|
||||||
bool operator ==(const Config &other) {
|
bool operator ==(const Config &other) const {
|
||||||
return sampleRate == other.sampleRate
|
return sampleRate == other.sampleRate
|
||||||
&& inputChannels == other.inputChannels
|
&& inputChannels == other.inputChannels
|
||||||
&& outputChannels == other.outputChannels
|
&& outputChannels == other.outputChannels
|
||||||
@ -373,7 +464,7 @@ namespace stfx {
|
|||||||
/// Wraps the common `process(float** inputs, float** outputs, int length)` call into the `.process(io, config, block)`.
|
/// Wraps the common `process(float** inputs, float** outputs, int length)` call into the `.process(io, config, block)`.
|
||||||
/// It actually accepts any objects which support `inputs[channel][index]`, so you could write adapters for interleaved buffers etc.
|
/// It actually accepts any objects which support `inputs[channel][index]`, so you could write adapters for interleaved buffers etc.
|
||||||
template<class Inputs, class Outputs>
|
template<class Inputs, class Outputs>
|
||||||
void process(Inputs inputs, Outputs outputs, int blockLength) {
|
void process(Inputs &&inputs, Outputs &&outputs, int blockLength) {
|
||||||
// How long should the parameter fade take?
|
// How long should the parameter fade take?
|
||||||
double fadeSamples = EffectClass::paramFadeMs()*0.001*config.sampleRate;
|
double fadeSamples = EffectClass::paramFadeMs()*0.001*config.sampleRate;
|
||||||
// Fade position at the end of the block
|
// Fade position at the end of the block
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user