Library parameters are atomic
This commit is contained in:
parent
bfb88d6fe1
commit
767906a31e
@ -9,6 +9,25 @@
|
||||
#include <map>
|
||||
|
||||
namespace stfx {
|
||||
class UnitRangeMap {
|
||||
double a, b, d;
|
||||
public:
|
||||
UnitRangeMap() : a(0), b(1), d(0) {} // identity
|
||||
UnitRangeMap(double min, double mid, double max) {
|
||||
double k = (mid - min)/(max - mid);
|
||||
a = min;
|
||||
b = max*k - min;
|
||||
d = k - 1;
|
||||
}
|
||||
|
||||
double toUnit(double value) const {
|
||||
return (value - a)/(b - value*d);
|
||||
}
|
||||
double fromUnit(double unit) const {
|
||||
return (a + unit*b)/(1 + unit*d);
|
||||
}
|
||||
};
|
||||
|
||||
struct RangeParamInfo {
|
||||
double defaultValue;
|
||||
double low, mid, high;
|
||||
@ -38,12 +57,12 @@ namespace stfx {
|
||||
}
|
||||
|
||||
typedef double((*DoubleMap)(double));
|
||||
RangeParamInfo & unit(std::string suffix, int precision=2, DoubleMap fromUnit=identityMap, DoubleMap toUnit=identityMap, double validLow=doubleLowest, double validHigh=doubleMax) {
|
||||
unitOptions.emplace_back(suffix, fromUnit, toUnit, validLow, validHigh, precision);
|
||||
RangeParamInfo & unit(std::string suffix, int precision=2, DoubleMap fromDisplay=identityMap, DoubleMap toDisplay=identityMap, double validLow=doubleLowest, double validHigh=doubleMax) {
|
||||
unitOptions.emplace_back(suffix, fromDisplay, toDisplay, validLow, validHigh, precision);
|
||||
return *this;
|
||||
}
|
||||
RangeParamInfo & unit(std::string suffix, DoubleMap fromUnit, DoubleMap toUnit, double validLow=doubleLowest, double validHigh=doubleMax) {
|
||||
return unit(suffix, 2, fromUnit, toUnit, validLow, validHigh);
|
||||
RangeParamInfo & unit(std::string suffix, DoubleMap fromDisplay, DoubleMap toDisplay, double validLow=doubleLowest, double validHigh=doubleMax) {
|
||||
return unit(suffix, 2, fromDisplay, toDisplay, validLow, validHigh);
|
||||
}
|
||||
RangeParamInfo & unit(std::string suffix, int precision, double validLow, double validHigh) {
|
||||
return unit(suffix, precision, identityMap, identityMap, validLow, validHigh);
|
||||
@ -130,7 +149,7 @@ namespace stfx {
|
||||
|
||||
for (const auto &u : unitOptions) {
|
||||
if (u.unit == unit) {
|
||||
return u.fromUnit(result);
|
||||
return u.fromDisplay(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -152,10 +171,10 @@ namespace stfx {
|
||||
}
|
||||
|
||||
double toUnit(double value) const {
|
||||
return rangeMap.toUnitRange(value);
|
||||
return rangeMap.toUnit(value);
|
||||
}
|
||||
double fromUnit(double unit) const {
|
||||
return rangeMap.fromUnitRange(unit);
|
||||
return rangeMap.fromUnit(unit);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -166,25 +185,7 @@ namespace stfx {
|
||||
}
|
||||
|
||||
// A map from [0, 1] to another range with specified midpoint, based on a 1/x curve
|
||||
class UnitRangeMapReciprocal {
|
||||
double vMin, vTopFactor, vBottomFactor;
|
||||
public:
|
||||
UnitRangeMapReciprocal() : vMin(0), vTopFactor(1), vBottomFactor(0) {} // identity
|
||||
UnitRangeMapReciprocal(double min, double mid, double max) {
|
||||
vMin = min;
|
||||
double k = (mid - min)/(max - mid);
|
||||
vTopFactor = max*k - min;
|
||||
vBottomFactor = k - 1;
|
||||
}
|
||||
|
||||
double toUnitRange(double value) const {
|
||||
return (value - vMin)/(vTopFactor - value*vBottomFactor);
|
||||
}
|
||||
double fromUnitRange(double unit) const {
|
||||
return (vMin + unit*vTopFactor)/(1 + unit*vBottomFactor);
|
||||
}
|
||||
};
|
||||
UnitRangeMapReciprocal rangeMap;
|
||||
UnitRangeMap rangeMap;
|
||||
|
||||
protected:
|
||||
struct ExactEntry {
|
||||
@ -196,12 +197,12 @@ namespace stfx {
|
||||
std::string fixedDisplay = "";
|
||||
std::string unit;
|
||||
bool addSpace = false, useFixed = false, keepZeros = false;
|
||||
DoubleMap fromUnit, toUnit;
|
||||
DoubleMap fromDisplay, toDisplay;
|
||||
double validLow, validHigh;
|
||||
int precision;
|
||||
double precisionOffset = 0;
|
||||
|
||||
UnitEntry(std::string unit, DoubleMap fromUnit, DoubleMap toUnit, double validLow, double validHigh, int precision=2) : unit(unit), fromUnit(fromUnit), toUnit(toUnit), validLow(validLow), validHigh(validHigh), precision(precision) {
|
||||
UnitEntry(std::string unit, DoubleMap fromDisplay, DoubleMap toDisplay, double validLow, double validHigh, int precision=2) : unit(unit), fromDisplay(fromDisplay), toDisplay(toDisplay), validLow(validLow), validHigh(validHigh), precision(precision) {
|
||||
if (validLow > validHigh) {
|
||||
std::swap(validLow, validHigh);
|
||||
keepZeros = true;
|
||||
@ -223,9 +224,9 @@ namespace stfx {
|
||||
oss << std::fixed;
|
||||
double offset = 0;
|
||||
if (precision > 0) {
|
||||
oss << toUnit(value) + offset;
|
||||
oss << toDisplay(value) + offset;
|
||||
} else {
|
||||
oss << (int)(toUnit(value) + offset);
|
||||
oss << (int)(toDisplay(value) + offset);
|
||||
}
|
||||
valueString = oss.str();
|
||||
// Strip trailing zeroes
|
||||
@ -324,13 +325,6 @@ namespace stfx {
|
||||
}
|
||||
}
|
||||
|
||||
double toUnit(int value) const {
|
||||
return (value - low)/double(high - low);
|
||||
}
|
||||
int fromUnit(double unit) const {
|
||||
double value = low + unit*(high - low);
|
||||
return int(std::round(value));
|
||||
}
|
||||
private:
|
||||
int nameIndex;
|
||||
protected:
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <atomic>
|
||||
|
||||
namespace stfx {
|
||||
// Convenient units for range parameters - not really part of the main STFX API
|
||||
@ -285,17 +286,18 @@ namespace stfx {
|
||||
// Parameters can be assigned using `=`, and store their own history for transitions
|
||||
template<typename Value>
|
||||
class LibraryParam {
|
||||
Value current, prevBlock;
|
||||
std::atomic<Value> current;
|
||||
Value prevBlock; // inter-block fade
|
||||
// Used for the 20ms parameter fade
|
||||
Value _from, _to;
|
||||
public:
|
||||
LibraryParam(const Value &initial, const Value &) : LibraryParam(initial) {}
|
||||
LibraryParam(const Value &initial) : current(initial), prevBlock(initial), _from(initial), _to(initial) {}
|
||||
operator Value () const {
|
||||
return current;
|
||||
return current.load(std::memory_order_relaxed);
|
||||
}
|
||||
LibraryParam & operator =(const Value &v) {
|
||||
current = v;
|
||||
current.store(v, std::memory_order_relaxed);
|
||||
return *this;
|
||||
}
|
||||
// Return the current fade
|
||||
@ -308,21 +310,25 @@ namespace stfx {
|
||||
|
||||
template<class Storage>
|
||||
void state(Storage &storage) {
|
||||
storage("value", current);
|
||||
auto v = current.load(std::memory_order_relaxed);
|
||||
auto vPrev = v;
|
||||
storage("value", v);
|
||||
if (v != vPrev) current.store(v);
|
||||
}
|
||||
|
||||
// The following are only called from `.process()`
|
||||
// Shuffle the internal values along to start a new fade, return whether it's actually changing
|
||||
bool _libStartFade() {
|
||||
_from = _to;
|
||||
_to = current;
|
||||
_to = current.load(std::memory_order_relaxed);
|
||||
return (_to != _from);
|
||||
}
|
||||
// Store previous value for block-level automation
|
||||
void _libEndBlock() {
|
||||
prevBlock = current;
|
||||
prevBlock = current.load(std::memory_order_relaxed);
|
||||
}
|
||||
Value _libCurrent() {
|
||||
return current;
|
||||
return current.load(std::memory_order_relaxed);
|
||||
}
|
||||
Value _libPrevBlock() {
|
||||
return prevBlock;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user