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 <string>
|
||||
#include <cmath>
|
||||
|
||||
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 {
|
||||
// A value which changes linearly within a given index range (e.g. a block)
|
||||
@ -20,7 +98,7 @@ namespace stfx {
|
||||
public:
|
||||
LinearSegment(double offset, double gradient) : offset(offset), gradient(gradient) {}
|
||||
|
||||
double at(int i) {
|
||||
double at(double i) {
|
||||
return offset + i*gradient;
|
||||
}
|
||||
bool changing() {
|
||||
@ -119,7 +197,7 @@ namespace stfx {
|
||||
}
|
||||
struct DoNothingEvent {
|
||||
int offset = 0;
|
||||
void operator ()() {}
|
||||
void operator()() {}
|
||||
};
|
||||
DoNothingEvent operator [](int) {
|
||||
return DoNothingEvent();
|
||||
@ -142,7 +220,7 @@ namespace stfx {
|
||||
}
|
||||
template<class EventList, class ...Others>
|
||||
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
|
||||
const Block & split() const {
|
||||
@ -170,7 +248,7 @@ namespace stfx {
|
||||
current = v;
|
||||
return *this;
|
||||
}
|
||||
// Return the
|
||||
// Return the current fade
|
||||
Value from() const {
|
||||
return _from;
|
||||
}
|
||||
@ -178,6 +256,11 @@ namespace stfx {
|
||||
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
|
||||
bool _libStartFade() {
|
||||
_from = _to;
|
||||
@ -220,7 +303,7 @@ namespace stfx {
|
||||
return *this;
|
||||
}
|
||||
template<typename ...Args>
|
||||
PInfoPlaceholder & names(Args ...) {
|
||||
PInfoPlaceholder & label(Args ...) {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
@ -228,11 +311,14 @@ namespace stfx {
|
||||
}
|
||||
|
||||
/// Base class for our effect to inherit from. Provides parameter classes and some default config.
|
||||
template<typename SampleType>
|
||||
class LibraryEffectBase {
|
||||
protected:
|
||||
using ParamRange = LibraryParam<double>;
|
||||
using ParamSteps = LibraryParam<int>;
|
||||
using ParamStepped = LibraryParam<int>;
|
||||
public:
|
||||
using Sample = SampleType;
|
||||
|
||||
ParamRange bpm{120};
|
||||
|
||||
double paramFadeMs() {
|
||||
@ -250,10 +336,10 @@ namespace stfx {
|
||||
};
|
||||
|
||||
/// 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>
|
||||
class LibraryEffect : public EffectTemplate<Sample, stfx::LibraryEffectBase, ExtraConfig...> {
|
||||
using EffectClass = EffectTemplate<Sample, stfx::LibraryEffectBase, ExtraConfig...>;
|
||||
class LibraryEffect : public EffectTemplate<stfx::LibraryEffectBase<Sample>, 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
|
||||
class CollectParams {
|
||||
@ -262,12 +348,12 @@ namespace stfx {
|
||||
std::vector<LibraryParam<int> *> stepParams;
|
||||
|
||||
// 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;
|
||||
rangeParams.push_back(¶m);
|
||||
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;
|
||||
stepParams.push_back(¶m);
|
||||
return {};
|
||||
@ -275,23 +361,28 @@ namespace stfx {
|
||||
|
||||
// The effect might ask us to store/fetch the serialisation version, we just echo it back
|
||||
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
|
||||
void operator ()(bool) {}
|
||||
void operator ()(int) {}
|
||||
void operator ()(long) {}
|
||||
void operator ()(double) {}
|
||||
void operator ()(float) {}
|
||||
void operator()(const char *, bool) {}
|
||||
void operator()(const char *, int) {}
|
||||
void operator()(const char *, long) {}
|
||||
void operator()(const char *, double) {}
|
||||
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
|
||||
template<class OtherObject>
|
||||
void operator ()(OtherObject &obj) {
|
||||
void operator()(const char *, OtherObject &obj) {
|
||||
obj.state(*this);
|
||||
}
|
||||
// Drop all names/labels we're given
|
||||
template<class V>
|
||||
void operator ()(const char *, V &v) {
|
||||
(*this)(v);
|
||||
}
|
||||
template<class Fn>
|
||||
void group(const char *, Fn fn) {
|
||||
fn(*this);
|
||||
@ -317,7 +408,7 @@ namespace stfx {
|
||||
std::vector<int> auxInputs, auxOutputs;
|
||||
int maxBlockSize = 256;
|
||||
|
||||
bool operator ==(const Config &other) {
|
||||
bool operator ==(const Config &other) const {
|
||||
return sampleRate == other.sampleRate
|
||||
&& inputChannels == other.inputChannels
|
||||
&& 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)`.
|
||||
/// It actually accepts any objects which support `inputs[channel][index]`, so you could write adapters for interleaved buffers etc.
|
||||
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?
|
||||
double fadeSamples = EffectClass::paramFadeMs()*0.001*config.sampleRate;
|
||||
// Fade position at the end of the block
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user