#ifndef GENLIB_OPS_H
#define GENLIB_OPS_H 1
#include "genlib_common.h"
#include "genlib.h"
#ifdef clamp
#undef clamp
#endif
#define GENLIB_DBL_EPSILON (__DBL_EPSILON__)
#define GENLIB_FLT_EPSILON (__FLT_EPSILON__)
#ifdef GENLIB_USE_DOUBLE
#define GENLIB_EPSILON GENLIB_DBL_EPSILON
#else
#define GENLIB_EPSILON GENLIB_FLT_EPSILON
#endif
#define GENLIB_PI (3.14159265358979323846264338327950288)
#define GENLIB_PI_OVER_2 (1.57079632679489661923132169163975144)
#define GENLIB_PI_OVER_4 (0.785398163397448309615660845819875721)
#define GENLIB_1_OVER_LOG_2 (1.442695040888963)
#if defined(MSP_ON_CLANG) || defined(ARM_CORTEX)
#define GENLIB_NO_DENORM_TEST 1
#endif
#ifdef GENLIB_USE_DOUBLE
#define GENLIB_IS_NAN_DOUBLE(v) (((((uint32_t *)&(v))[1])&0x7fe00000)==0x7fe00000)
#define GENLIB_FIX_NAN_DOUBLE(v) ((v)=GENLIB_IS_NAN_DOUBLE(v)?0.:(v))
#ifdef GENLIB_NO_DENORM_TEST
#define GENLIB_IS_DENORM_DOUBLE(v) (v)
#define GENLIB_FIX_DENORM_DOUBLE(v) (v)
#else
#define GENLIB_IS_DENORM_DOUBLE(v) ((((((uint32_t *)&(v))[1])&0x7fe00000)==0)&&((v)!=0.))
#define GENLIB_FIX_DENORM_DOUBLE(v) ((v)=GENLIB_IS_DENORM_DOUBLE(v)?0.f:(v))
#endif
#define GENLIB_IS_NAN GENLIB_IS_NAN_DOUBLE
#define GENLIB_FIX_NAN GENLIB_FIX_NAN_DOUBLE
#define GENLIB_IS_DENORM GENLIB_IS_DENORM_DOUBLE
#define GENLIB_FIX_DENORM GENLIB_FIX_DENORM_DOUBLE
#else
#define GENLIB_IS_NAN_FLOAT(v) ((v)!=(v))
#define GENLIB_FIX_NAN_FLOAT(v) ((v)=GENLIB_IS_NAN_FLOAT(v)?0.:(v))
#ifdef GENLIB_NO_DENORM_TEST
#define GENLIB_IS_DENORM_FLOAT(v) (v)
#define GENLIB_FIX_DENORM_FLOAT(v) (v)
#else
#define GENLIB_IS_DENORM_FLOAT(v) ((v)!=0.&&fabs(v)<__FLT_MIN__)
#define GENLIB_FIX_DENORM_FLOAT(v) ((v)=GENLIB_IS_DENORM_FLOAT(v)?0.f:(v))
#endif
#define GENLIB_IS_NAN GENLIB_IS_NAN_FLOAT
#define GENLIB_FIX_NAN GENLIB_FIX_NAN_FLOAT
#define GENLIB_IS_DENORM GENLIB_IS_DENORM_FLOAT
#define GENLIB_FIX_DENORM GENLIB_FIX_DENORM_FLOAT
#endif
#define GENLIB_QUANT(f1,f2) (floor((f1)*(f2)+0.5)/(f2))
inline t_sample genlib_isnan(t_sample v) { return GENLIB_IS_NAN(v); }
inline t_sample fixnan(t_sample v) { return GENLIB_FIX_NAN(v); }
inline t_sample fixdenorm(t_sample v) { return GENLIB_FIX_DENORM(v); }
inline t_sample isdenorm(t_sample v) { return GENLIB_IS_DENORM(v); }
inline t_sample fasterpow(t_sample x, t_sample p);
inline t_sample fasterexp(t_sample x);
inline t_sample fastercosfull(t_sample x);
inline t_sample fastersinfull(t_sample x);
inline t_sample fastertanfull(t_sample x);
inline t_sample safemod(t_sample f, t_sample m) {
if (m > GENLIB_DBL_EPSILON || m < -GENLIB_DBL_EPSILON) {
if (m<0)
m = -m; if (f>=m) {
if (f>=(m*2.)) {
t_sample d = f / m;
d = d - (long) d;
f = d * m;
}
else {
f -= m;
}
}
else if (f<=(-m)) {
if (f<=(-m*2.)) {
t_sample d = f / m;
d = d - (long) d;
f = d * m;
}
else {
f += m;
}
}
} else {
f = 0.0; }
return f;
}
inline t_sample safediv(t_sample num, t_sample denom) {
return denom == 0. ? 0. : num/denom;
}
inline t_sample safepow(t_sample base, t_sample exponent) {
return fixnan(powf(base, exponent));
}
inline t_sample absdiff(t_sample a, t_sample b) { return fabs(a-b); }
inline t_sample sign(t_sample v) {
return v > t_sample(0) ? t_sample(1) : v < t_sample(0) ? t_sample(-1) : t_sample(0);
}
inline long is_poweroftwo(long x) {
return (x & (x - 1)) == 0;
}
inline uint64_t next_power_of_two(uint64_t v) {
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
v++;
return v;
}
inline t_sample fold(t_sample v, t_sample lo1, t_sample hi1){
t_sample lo;
t_sample hi;
if(lo1 == hi1){ return lo1; }
if (lo1 > hi1) {
hi = lo1; lo = hi1;
} else {
lo = lo1; hi = hi1;
}
const t_sample range = hi - lo;
long numWraps = 0;
if(v >= hi){
v -= range;
if(v >= hi){
numWraps = (long)((v - lo)/range);
v -= range * (t_sample)numWraps;
}
numWraps++;
} else if(v < lo){
v += range;
if(v < lo){
numWraps = (long)((v - lo)/range) - 1;
v -= range * (t_sample)numWraps;
}
numWraps--;
}
if(numWraps & 1) v = hi + lo - v; return v;
}
inline t_sample wrap(t_sample v, t_sample lo1, t_sample hi1){
t_sample lo;
t_sample hi;
if(lo1 == hi1) return lo1;
if (lo1 > hi1) {
hi = lo1; lo = hi1;
} else {
lo = lo1; hi = hi1;
}
const t_sample range = hi - lo;
if (v >= lo && v < hi) return v;
if (range <= 0.000000001) return lo; const long numWraps = long((v-lo)/range) - (v < lo);
return v - range * t_sample(numWraps);
}
inline t_sample genlib_wrapfew(t_sample v, t_sample lo, t_sample hi){
const t_sample range = hi - lo;
while (v >= hi) v -= range;
while (v < lo) v += range;
return v;
}
inline t_sample phasewrap(t_sample val) {
const t_sample twopi = GENLIB_PI*2.;
const t_sample oneovertwopi = 1./twopi;
if (val>= twopi || val <= twopi) {
t_sample d = val * oneovertwopi; d = d - (long)d;
val = d * twopi;
}
if (val > GENLIB_PI) val -= twopi;
if (val < -GENLIB_PI) val += twopi;
return val;
}
inline t_sample genlib_cosT8(t_sample r) {
const t_sample t84 = 56.;
const t_sample t83 = 1680.;
const t_sample t82 = 20160.;
const t_sample t81 = 2.4801587302e-05;
const t_sample t73 = 42.;
const t_sample t72 = 840.;
const t_sample t71 = 1.9841269841e-04;
if(r < GENLIB_PI_OVER_4 && r > -GENLIB_PI_OVER_4){
t_sample rr = r*r;
return 1. - rr * t81 * (t82 - rr * (t83 - rr * (t84 - rr)));
}
else if(r > 0.){
r -= GENLIB_PI_OVER_2;
t_sample rr = r*r;
return -r * (1. - t71 * rr * (t72 - rr * (t73 - rr)));
}
else{
r += GENLIB_PI_OVER_2;
t_sample rr = r*r;
return r * (1. - t71 * rr * (t72 - rr * (t73 - rr)));
}
}
inline t_sample genlib_cosT8_safe(t_sample r) { return genlib_cosT8(phasewrap(r)); }
inline float genlib_fastersin (float x) {
static const float fouroverpi = 1.2732395447351627f;
static const float fouroverpisq = 0.40528473456935109f;
static const float q = 0.77633023248007499f;
union { float f; uint32_t i; } p = { 0.22308510060189463f };
union { float f; uint32_t i; } vx = { x };
uint32_t sign = vx.i & 0x80000000;
vx.i &= 0x7FFFFFFF;
float qpprox = fouroverpi * x - fouroverpisq * x * vx.f;
p.i |= sign;
return qpprox * (q + p.f * qpprox);
}
inline float genlib_fastercos (float x) {
static const float twooverpi = 0.63661977236758134f;
static const float p = 0.54641335845679634f;
union { float f; uint32_t i; } vx = { x };
vx.i &= 0x7FFFFFFF;
float qpprox = 1.0f - twooverpi * vx.f;
return qpprox + p * qpprox * (1.0f - qpprox * qpprox);
}
inline float genlib_fastersinfull (float x) {
static const float twopi = 6.2831853071795865f;
static const float invtwopi = 0.15915494309189534f;
int k = x * invtwopi;
float half = (x < 0) ? -0.5f : 0.5f;
return genlib_fastersin ((half + k) * twopi - x);
}
inline float genlib_fastercosfull (float x) {
static const float halfpi = 1.5707963267948966f;
return genlib_fastersinfull (x + halfpi);
}
inline float genlib_fastertanfull (float x) {
static const float twopi = 6.2831853071795865f;
static const float invtwopi = 0.15915494309189534f;
int k = x * invtwopi;
float half = (x < 0) ? -0.5f : 0.5f;
float xnew = x - (half + k) * twopi;
return genlib_fastersin (xnew) / genlib_fastercos (xnew);
}
#define cast_uint32_t static_cast<uint32_t>
inline float genlib_fasterpow2 (float p) {
float clipp = (p < -126) ? -126.0f : p;
union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 126.94269504f) ) };
return v.f;
}
inline float genlib_fasterexp (float p) {
return genlib_fasterpow2 (1.442695040f * p);
}
inline float genlib_fasterlog2 (float x) {
union { float f; uint32_t i; } vx = { x };
float y = vx.i;
y *= 1.1920928955078125e-7f;
return y - 126.94269504f;
}
inline float genlib_fasterpow (float x, float p) {
return genlib_fasterpow2(p * genlib_fasterlog2 (x));
}
inline t_sample fastertanfull(t_sample x) {
return (t_sample)genlib_fastertanfull((float)x);
}
inline t_sample fastersinfull(t_sample x) {
return (t_sample)genlib_fastersinfull((float)x);
}
inline t_sample fastercosfull(t_sample x) {
return (t_sample)genlib_fastercosfull((float)x);
}
inline t_sample fasterexp(t_sample x) {
return (t_sample)genlib_fasterexp((float)x);
}
inline t_sample fasterpow(t_sample x, t_sample p) {
return (t_sample)genlib_fasterpow((float)x, (float)p);
}
inline t_sample minimum(t_sample x, t_sample y) { return (y<x?y:x); }
inline t_sample maximum(t_sample x, t_sample y) { return (x<y?y:x); }
inline t_sample clamp(t_sample x, t_sample minVal, t_sample maxVal) {
return minimum(maximum(x,minVal),maxVal);
}
template<typename T>
inline T smoothstep(t_sample e0, t_sample e1, T x) {
T t = clamp( safediv(x-T(e0),T(e1-e0)), 0., 1. );
return t*t*(T(3) - T(2)*t);
}
inline t_sample mix(t_sample x, t_sample y, t_sample a) {
return x+a*(y-x);
}
inline t_sample scale(t_sample in, t_sample inlow, t_sample inhigh, t_sample outlow, t_sample outhigh, t_sample power)
{
t_sample value;
t_sample inscale = safediv(1., inhigh - inlow);
t_sample outdiff = outhigh - outlow;
value = (in - inlow) * inscale;
if (value > 0.0)
value = powf(value, power);
else if (value < 0.0)
value = -powf(-value, power);
value = (value * outdiff) + outlow;
return value;
}
inline t_sample linear_interp(t_sample a, t_sample x, t_sample y) {
return x+a*(y-x);
}
inline t_sample cosine_interp(t_sample a, t_sample x, t_sample y) {
const t_sample a2 = (t_sample(1.)-genlib_cosT8_safe(a*t_sample(GENLIB_PI)))/t_sample(2.);
return(x*(t_sample(1.)-a2)+y*a2);
}
inline t_sample cubic_interp(t_sample a, t_sample w, t_sample x, t_sample y, t_sample z) {
const t_sample a2 = a*a;
const t_sample f0 = z - y - w + x;
const t_sample f1 = w - x - f0;
const t_sample f2 = y - w;
const t_sample f3 = x;
return(f0*a*a2 + f1*a2 + f2*a + f3);
}
inline t_sample spline_interp(t_sample a, t_sample w, t_sample x, t_sample y, t_sample z) {
const t_sample a2 = a*a;
const t_sample f0 = t_sample(-0.5)*w + t_sample(1.5)*x - t_sample(1.5)*y + t_sample(0.5)*z;
const t_sample f1 = w - t_sample(2.5)*x + t_sample(2)*y - t_sample(0.5)*z;
const t_sample f2 = t_sample(-0.5)*w + t_sample(0.5)*y;
return(f0*a*a2 + f1*a2 + f2*a + x);
}
template<typename T1, typename T2>
inline T1 neqp(T1 x, T2 y) {
return ((((x) != T1(y))) ? (x) : T1(0));
}
template<typename T1, typename T2>
inline T1 gtp(T1 x, T2 y) { return ((((x) > T1(y))) ? (x) : T1(0)); }
template<typename T1, typename T2>
inline T1 gtep(T1 x, T2 y) { return ((((x) >= T1(y))) ? (x) : T1(0)); }
template<typename T1, typename T2>
inline T1 ltp(T1 x, T2 y) { return ((((x) < T1(y))) ? (x) : T1(0)); }
template<typename T1, typename T2>
inline T1 ltep(T1 x, T2 y) { return ((((x) <= T1(y))) ? (x) : T1(0)); }
inline t_sample fract(t_sample x) { float unused; return (t_sample)modff((float)x, &unused); }
template<typename T>
inline T log2(T x) {
return logf(x)*GENLIB_1_OVER_LOG_2;
}
inline t_sample atodb(t_sample in) {
return (in <=0.) ? -999. : (20. * log10f(in));
}
inline t_sample dbtoa(t_sample in) {
return powf(10., in * 0.05);
}
inline t_sample ftom(t_sample in, t_sample tuning=440.) {
return 69. + 17.31234050465299 * logf(safediv(in, tuning));
}
inline t_sample mtof(t_sample in, t_sample tuning=440.) {
return tuning * expf(.057762265 * (in - 69.0));
}
inline t_sample mstosamps(t_sample ms, t_sample samplerate=44100.) {
return samplerate * ms * t_sample(0.001);
}
inline t_sample sampstoms(t_sample s, t_sample samplerate=44100.) {
return t_sample(1000.) * s / samplerate;
}
inline t_sample triangle(t_sample phase, t_sample p1) {
phase = wrap(phase, 0., 1.);
p1 = clamp(p1, 0., 1.);
if (phase < p1)
return (p1) ? phase/p1 : 0.;
else
return (p1==1.) ? phase : 1. - ((phase - p1) / (1. - p1));
}
struct Delta {
t_sample history;
Delta() { reset(); }
inline void reset(t_sample init=0) { history=init; }
inline t_sample operator()(t_sample in1) {
t_sample ret = in1 - history;
history = in1;
return ret;
}
};
struct Change {
t_sample history;
Change() { reset(); }
inline void reset(t_sample init=0) { history=init; }
inline t_sample operator()(t_sample in1) {
t_sample ret = in1 - history;
history = in1;
return sign(ret);
}
};
struct Rate {
t_sample phase, diff, mult, invmult, prev;
int wantlock, quant;
Rate() { reset(); }
inline void reset() {
phase = diff = prev = 0;
mult = invmult = 1;
wantlock = 1;
quant = 1;
}
inline t_sample perform_lock(t_sample in1, t_sample in2) {
if (in2 != mult && !genlib_isnan(in2)) {
mult = in2;
invmult = safediv(1., mult);
wantlock = 1;
}
t_sample diff = in1 - prev;
if (diff < t_sample(-0.5)) {
diff += t_sample(1);
} else if (diff > t_sample(0.5)) {
diff -= t_sample(1);
}
if (wantlock) {
phase = (in1 - GENLIB_QUANT(in1, quant)) * invmult
+ GENLIB_QUANT(in1, quant * mult);
diff = 0;
wantlock = 0;
} else {
phase += diff * invmult;
}
if (phase > t_sample(1.) || phase < t_sample(-0.)) {
phase = phase - (long)(phase);
}
prev = in1;
return phase;
}
inline t_sample perform_cycle(t_sample in1, t_sample in2) {
if (in2 != mult && !genlib_isnan(in2)) {
mult = in2;
invmult = safediv(1., mult);
wantlock = 1;
}
t_sample diff = in1 - prev;
if (diff < t_sample(-0.5)) {
if (wantlock) {
wantlock = 0;
phase = in1 * invmult;
diff = t_sample(0);
} else {
diff += t_sample(1);
}
} else if (diff > t_sample(0.5)) {
if (wantlock) {
wantlock = 0;
phase = in1 * invmult;
diff = t_sample(0);
} else {
diff -= t_sample(1);
}
}
phase += diff * invmult;
if (phase > t_sample(1.) || phase < t_sample(-0.)) {
phase = phase - (long)(phase);
}
prev = in1;
return phase;
}
inline t_sample perform_off(t_sample in1, t_sample in2) {
if (in2 != mult && !genlib_isnan(in2)) {
mult = in2;
invmult = safediv(1., mult);
wantlock = 1;
}
t_sample diff = in1 - prev;
if (diff < t_sample(-0.5)) {
diff += t_sample(1);
} else if (diff > t_sample(0.5)) {
diff -= t_sample(1);
}
phase += diff * invmult;
if (phase > t_sample(1.) || phase < t_sample(-0.)) {
phase = phase - (long)(phase);
}
prev = in1;
return phase;
}
};
struct DCBlock {
t_sample x1, y1;
DCBlock() { reset(); }
inline void reset() { x1=0; y1=0; }
inline t_sample operator()(t_sample in1) {
t_sample y = in1 - x1 + y1*t_sample(0.9997);
x1 = in1;
y1 = y;
return y;
}
};
struct Noise {
unsigned long last;
static long uniqueTickCount(void) {
static long lasttime = 0;
long time = genlib_ticks();
return (time <= lasttime) ? (++lasttime) : (lasttime = time);
}
Noise() { reset(); }
Noise(t_sample seed) { reset(seed); }
void reset() { last = uniqueTickCount() * uniqueTickCount(); }
void reset(t_sample seed) { last = seed; }
inline t_sample operator()() {
last = 1664525L * last + 1013904223L;
union {
uint32_t ui32;
float f;
} u = { 0x3f800000 | (0x007fffff & last) };
return (u.f * 2.f) - 3.f;
}
};
struct Phasor {
t_sample phase;
Phasor() { reset(); }
void reset(t_sample v=0.) { phase=v; }
inline t_sample operator()(t_sample freq, t_sample invsamplerate) {
const t_sample pincr = freq * invsamplerate;
phase = wrap(phase + pincr, 0., 1.);
return phase;
}
};
struct PlusEquals {
t_sample count;
PlusEquals() { reset(); }
void reset(t_sample v=0.) { count=v; }
inline t_sample post(t_sample incr, t_sample reset, t_sample min, t_sample max) {
count = reset ? min : wrap(count+incr, min, max);
return count;
}
inline t_sample post(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
count = reset ? min : count+incr;
return count;
}
inline t_sample pre(t_sample incr, t_sample reset, t_sample min, t_sample max) {
count = reset ? min+incr : wrap(count+incr, min, max);
return count;
}
inline t_sample pre(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
count = reset ? min+incr : count+incr;
return count;
}
};
struct MulEquals {
t_sample count;
MulEquals() { reset(); }
void reset(t_sample v=0.) { count=v; }
inline t_sample post(t_sample incr, t_sample reset, t_sample min, t_sample max) {
count = reset ? min : wrap(fixdenorm(count*incr), min, max);
return count;
}
inline t_sample post(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
count = reset ? min : fixdenorm(count*incr);
return count;
}
inline t_sample pre(t_sample incr, t_sample reset, t_sample min, t_sample max) {
count = reset ? min*incr : wrap(fixdenorm(count*incr), min, max);
return count;
}
inline t_sample pre(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
count = reset ? min*incr : fixdenorm(count*incr);
return count;
}
};
struct Sah {
t_sample prev, output;
Sah() { reset(); }
void reset(t_sample o=0.) {
output = prev = o;
}
inline t_sample operator()(t_sample in, t_sample trig, t_sample thresh) {
if (prev <= thresh && trig > thresh) {
output = in;
}
prev = trig;
return output;
}
};
struct Train {
t_sample phase, state;
Train() { reset(); }
void reset(t_sample p=0) { phase = p; state = 0.; }
inline t_sample operator()(t_sample pulseinterval, t_sample width, t_sample pulsephase) {
if (width <= t_sample(0.)) {
state = t_sample(0.); } else if (width >= 1.) {
state = t_sample(1.); } else {
const t_sample interval = maximum(pulseinterval, t_sample(1.)); const t_sample p1 = clamp(pulsephase, t_sample(0.), t_sample(1.)); const t_sample p2 = p1+width; const t_sample pincr = t_sample(1.)/interval; phase += pincr; if (state) { if (phase > p2) {
state = t_sample(0.); phase -= (int)(1.+phase-p2); }
} else { if (phase > p1) {
state = t_sample(1.); }
}
}
return state;
}
};
struct Delay {
t_sample * memory;
long size, wrap, maxdelay;
long reader, writer;
t_genlib_data * dataRef;
Delay() : memory(0) {
size = wrap = maxdelay = 0;
reader = writer = 0;
dataRef = 0;
}
~Delay() {
if (dataRef != 0) {
genlib_data_setcursor(dataRef, writer);
genlib_data_release(dataRef);
}
}
inline void reset(const char * name, long d) {
if (dataRef == 0) {
void * ref = genlib_obtain_reference_from_string(name);
dataRef = genlib_obtain_data_from_reference(ref);
if (dataRef == 0) {
genlib_report_error("failed to acquire data");
return;
}
maxdelay = d;
size = maxdelay < 2 ? 2 : maxdelay;
size = next_power_of_two(size);
genlib_data_resize(dataRef, size, 1);
t_genlib_data_info info;
if (genlib_data_getinfo(dataRef, &info) == GENLIB_ERR_NONE) {
if (info.dim != size) {
genlib_report_error("delay memory size error");
memory = 0;
return;
}
memory = info.data;
writer = genlib_data_getcursor(dataRef);
} else {
genlib_report_error("failed to acquire data info");
}
} else {
set_zero64(memory, size);
writer = 0;
}
reader = writer;
wrap = size-1;
}
inline void step() {
reader++;
if (reader >= size) reader = 0;
}
inline void write(t_sample x) {
writer = reader; memory[writer] = x;
}
inline t_sample read_step(t_sample d) {
const t_sample r = t_sample(size + reader) - clamp(d-t_sample(0.5), (reader != writer), maxdelay);
long r1 = long(r);
return memory[r1 & wrap];
}
inline t_sample read_linear(t_sample d) {
t_sample c = clamp(d, (reader != writer), maxdelay);
const t_sample r = t_sample(size + reader) - c;
long r1 = long(r);
long r2 = r1+1;
t_sample a = r - (t_sample)r1;
t_sample x = memory[r1 & wrap];
t_sample y = memory[r2 & wrap];
return linear_interp(a, x, y);
}
inline t_sample read_cosine(t_sample d) {
const t_sample r = t_sample(size + reader) - clamp(d, (reader != writer), maxdelay);
long r1 = long(r);
long r2 = r1+1;
t_sample a = r - (t_sample)r1;
t_sample x = memory[r1 & wrap];
t_sample y = memory[r2 & wrap];
return cosine_interp(a, x, y);
}
inline t_sample read_cubic(t_sample d) {
const t_sample r = t_sample(size + reader) - clamp(d, t_sample(1.)+t_sample(reader != writer), maxdelay);
long r1 = long(r);
long r2 = r1+1;
long r3 = r1+2;
long r4 = r1+3;
t_sample a = r - (t_sample)r1;
t_sample w = memory[r1 & wrap];
t_sample x = memory[r2 & wrap];
t_sample y = memory[r3 & wrap];
t_sample z = memory[r4 & wrap];
return cubic_interp(a, w, x, y, z);
}
inline t_sample read_spline(t_sample d) {
const t_sample r = t_sample(size + reader) - clamp(d, t_sample(1.)+t_sample(reader != writer), maxdelay);
long r1 = long(r);
long r2 = r1+1;
long r3 = r1+2;
long r4 = r1+3;
t_sample a = r - (t_sample)r1;
t_sample w = memory[r1 & wrap];
t_sample x = memory[r2 & wrap];
t_sample y = memory[r3 & wrap];
t_sample z = memory[r4 & wrap];
return spline_interp(a, w, x, y, z);
}
};
template<typename T=t_sample>
struct DataInterface {
long dim, channels;
T * mData;
void * mDataReference; int modified;
DataInterface() : dim(0), channels(1), mData(0), modified(0) { mDataReference = 0; }
inline t_sample read(long index, long channel=0) const {
return mData[channel+index*channels];
}
inline void write(T value, long index, long channel=0) {
mData[channel+index*channels] = value;
modified = 1;
}
inline void overdub(T value, long index, long channel=0) {
mData[channel+index*channels] += value;
modified = 1;
}
inline void blend(T value, long index, long channel, t_sample alpha) {
long offset = channel+index*channels;
const T old = mData[offset];
mData[offset] = old + alpha * (value - old);
modified = 1;
}
inline void read_ok(long index, long channel=0, bool ok=1) const {
return ok ? mData[channel+index*channels] : T(0);
}
inline void write_ok(T value, long index, long channel=0, bool ok=1) {
if (ok) mData[channel+index*channels] = value;
}
inline void overdub_ok(T value, long index, long channel=0, bool ok=1) {
if (ok) mData[channel+index*channels] += value;
}
inline long index_clamp(long index) const { return clamp(index, 0, dim-1); }
inline long index_wrap(long index) const { return wrap(index, 0, dim); }
inline long index_fold(long index) const { return fold(index, 0, dim); }
inline bool index_oob(long index) const { return (index < 0 || index >= dim); }
inline bool index_inbounds(long index) const { return (index >=0 && index < dim); }
inline long channel_clamp(long c) const { return clamp(c, 0, channels-1); }
inline long channel_wrap(long c) const { return wrap(c, 0, channels); }
inline long channel_fold(long c) const { return fold(c, 0, channels); }
inline bool channel_oob(long c) const { return (c < 0 || c >= channels); }
inline bool channel_inbounds(long c) const { return !channel_oob(c); }
inline t_sample phase2index(t_sample phase) const { return phase * t_sample(dim-1); }
inline t_sample subphase2index(t_sample phase, long min, long max) const {
min = index_clamp(min);
max = index_clamp(max);
return t_sample(min) + phase * t_sample(max-min);
}
inline t_sample signal2index(t_sample signal) const { return phase2index((signal+t_sample(1.)) * t_sample(0.5)); }
inline T peek(t_sample index, long channel=0) const {
const long i = (long)index;
if (index_oob(i) || channel_oob(channel)) {
return 0.;
} else {
return read(i, channel);
}
}
inline T index(t_sample index, long channel=0) const {
channel = channel_clamp(channel);
long i = (long)index;
i = index_clamp(i);
return read(i, channel);
}
inline T cell(t_sample index, long channel=0) const {
channel = channel_clamp(channel);
long i = (long)index;
i = index_wrap(i);
return read(i, channel);
}
inline T cycle(t_sample phase, long channel=0) const {
channel = channel_clamp(channel);
t_sample index = phase2index(phase);
long i1 = (long)index;
long i2 = i1+1;
const t_sample alpha = index - (t_sample)i1;
i1 = index_wrap(i1);
i2 = index_wrap(i2);
T v1 = read(i1, channel);
T v2 = read(i2, channel);
return mix(v1, v2, alpha);
}
inline T lookup(t_sample signal, long channel=0) const {
channel = channel_clamp(channel);
t_sample index = signal2index(signal);
long i1 = (long)index;
long i2 = i1+1;
t_sample alpha = index - (t_sample)i1;
i1 = index_clamp(i1);
i2 = index_clamp(i2);
T v1 = read(i1, channel);
T v2 = read(i2, channel);
return mix(v1, v2, alpha);
}
inline void poke(t_sample value, t_sample index, long channel=0) {
const long i = (long)index;
if (!(index_oob(i) || channel_oob(channel))) {
write(fixdenorm(value), i, channel);
}
}
inline void splat_adding(t_sample value, t_sample phase, long channel=0) {
const t_sample valuef = fixdenorm(value);
channel = channel_clamp(channel);
t_sample index = phase2index(phase);
long i1 = (long)index;
long i2 = i1+1;
const t_sample alpha = index - (t_sample)i1;
i1 = index_wrap(i1);
i2 = index_wrap(i2);
overdub(valuef*(1.-alpha), i1, channel);
overdub(valuef*alpha, i2, channel);
}
inline void splat(t_sample value, t_sample phase, long channel=0) {
const t_sample valuef = fixdenorm(value);
channel = channel_clamp(channel);
t_sample index = phase2index(phase);
long i1 = (long)index;
long i2 = i1+1;
const t_sample alpha = index - (t_sample)i1;
i1 = index_wrap(i1);
i2 = index_wrap(i2);
const T v1 = read(i1, channel);
const T v2 = read(i2, channel);
write(v1 + (1.-alpha)*(valuef-v1), i1, channel);
write(v2 + (alpha)*(valuef-v2), i2, channel);
}
};
#define DATA_MAXIMUM_ELEMENTS (33554432)
struct Data : public DataInterface<t_sample> {
t_genlib_data * dataRef;
Data() : DataInterface<t_sample>() {
dataRef = 0;
}
~Data() {
if (dataRef != 0) {
genlib_data_release(dataRef);
}
}
void reset(const char * name, long s, long c) {
if (dataRef == 0) {
void * ref = genlib_obtain_reference_from_string(name);
dataRef = genlib_obtain_data_from_reference(ref);
if (dataRef == 0) {
genlib_report_error("failed to acquire data");
return;
}
}
genlib_data_resize(dataRef, s, c);
getinfo();
}
bool setbuffer(void * bufferRef) {
if (dataRef == 0) {
return false;
}
genlib_data_setbuffer(dataRef, bufferRef);
getinfo();
return true;
}
void getinfo() {
t_genlib_data_info info;
if (genlib_data_getinfo(dataRef, &info) == GENLIB_ERR_NONE) {
mData = info.data;
dim = info.dim;
channels = info.channels;
} else {
genlib_report_error("failed to acquire data info");
}
}
};
struct DataLocal : public DataInterface<t_sample> {
DataLocal() : DataInterface<t_sample>() {}
~DataLocal() {
if (mData) sysmem_freeptr(mData);
mData = 0;
}
void reset(long s, long c) {
mData=0;
resize(s, c);
}
void resize(long s, long c) {
if (s * c > DATA_MAXIMUM_ELEMENTS) {
s = DATA_MAXIMUM_ELEMENTS/c;
genlib_report_message("warning: resizing data to < 256MB");
}
if (mData) {
sysmem_resizeptr(mData, sizeof(t_sample) * s * c);
} else {
mData = (t_sample *)sysmem_newptr(sizeof(t_sample) * s * c);
}
if (!mData) {
genlib_report_error("out of memory");
resize(512, 1);
return;
} else {
dim = s;
channels = c;
}
set_zero64(mData, dim * channels);
}
bool setbuffer(void *dataReference) {
mDataReference = dataReference; bool result = false;
t_genlib_buffer * b;
t_genlib_buffer_info info;
if (mDataReference != 0) {
b = (t_genlib_buffer *)genlib_obtain_buffer_from_reference(mDataReference);
if (b) {
if (genlib_buffer_edit_begin(b)==GENLIB_ERR_NONE) {
if (genlib_buffer_getinfo(b, &info)==GENLIB_ERR_NONE) {
float * samples = info.b_samples;
long frames = info.b_frames;
long nchans = info.b_nchans;
if (mData == 0) resize(frames, nchans);
long frames_safe = frames < dim ? frames : dim;
long channels_safe = nchans < channels ? nchans : channels;
for (int f=0; f<frames_safe; f++) {
for (int c=0; c<channels_safe; c++) {
t_sample value = samples[c+f*nchans];
write(value, f, c);
}
}
result = true;
} else {
genlib_report_message("couldn't get info for buffer\n");
}
genlib_buffer_edit_end(b, 1);
} else {
genlib_report_message("buffer locked\n");
}
}
} else {
genlib_report_message("buffer reference not valid");
}
return result;
}
};
struct Buffer : public DataInterface<float> {
t_genlib_buffer * mBuf;
t_genlib_buffer_info mInfo;
float mDummy;
Buffer() : DataInterface<float>() {}
void reset(const char * name) {
dim = 1;
channels = 1;
mData = &mDummy;
mDummy = 0.f;
mBuf = 0;
mDataReference = genlib_obtain_reference_from_string(name);
}
void setbuffer(void * ref) {
mDataReference = ref;
}
void begin() {
t_genlib_buffer * b = genlib_obtain_buffer_from_reference(mDataReference);
mBuf = 0;
if (b) {
if (genlib_buffer_perform_begin(b) == GENLIB_ERR_NONE) {
mBuf = b;
} else {
}
} else {
}
if (mBuf && genlib_buffer_getinfo(mBuf, &mInfo)==GENLIB_ERR_NONE) {
mBuf = b;
mData = mInfo.b_samples;
dim = mInfo.b_frames;
channels = mInfo.b_nchans;
} else {
mBuf = 0;
mData = &mDummy;
dim = 1;
channels = 1;
}
}
void end() {
if (mBuf) {
genlib_buffer_perform_end(mBuf);
if (modified) {
genlib_buffer_dirty(mBuf);
}
modified = 0;
}
mBuf = 0;
}
};
struct SineData : public DataLocal {
SineData() : DataLocal() {
const int costable_size = 1 << 14; mData=0;
resize(costable_size, 1);
for (int i=0; i<dim; i++) {
mData[i] = cos(i * GENLIB_PI * 2. / (t_sample)(dim));
}
}
~SineData() {
if (mData) sysmem_freeptr(mData);
mData = 0;
}
};
template<typename T>
inline int dim(const T& data) { return data.dim; }
template<typename T>
inline int channels(const T& data) { return data.channels; }
struct SineCycle {
uint32_t phasei, pincr;
t_sample f2i;
void reset(t_sample samplerate, t_sample init = 0) {
phasei = init * t_sample(4294967296.0);
pincr = 0;
f2i = t_sample(4294967296.0) / samplerate;
}
inline void freq(t_sample f) {
pincr = f * f2i;
}
inline void phase(t_sample f) {
phasei = f * t_sample(4294967296.0);
}
inline t_sample phase() const {
return phasei * t_sample(0.232830643653869629e-9);
}
template<typename T>
inline t_sample operator()(const DataInterface<T>& buf) {
T * data = buf.mData;
uint32_t idx = phasei >> 18;
const t_sample frac = t_sample(phasei & 262143) * t_sample(3.81471181759574e-6);
const t_sample y0 = data[idx];
const t_sample y1 = data[(idx+1) & 16383];
const t_sample y = linear_interp(frac, y0, y1);
phasei += pincr;
return y;
}
};
#endif