gen-rack

Create VCV Rack modules from gen~ exports
Log | Files | Refs | README | LICENSE

genlib_ops.h (46718B)


      1 /*******************************************************************************************************************
      2 Cycling '74 License for Max-Generated Code for Export
      3 Copyright (c) 2016 Cycling '74
      4 The code that Max generates automatically and that end users are capable of exporting and using, and any
      5   associated documentation files (the “Software”) is a work of authorship for which Cycling '74 is the author
      6   and owner for copyright purposes.  A license is hereby granted, free of charge, to any person obtaining a
      7   copy of the Software (“Licensee”) to use, copy, modify, merge, publish, and distribute copies of the Software,
      8   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
      9 The Software is licensed to Licensee only for non-commercial use. Users who wish to make commercial use of the
     10   Software must contact the copyright owner to determine if a license for commercial use is available, and the
     11   terms and conditions for same, which may include fees or royalties. For commercial use, please send inquiries
     12   to licensing@cycling74.com.  The determination of whether a use is commercial use or non-commercial use is based
     13   upon the use, not the user. The Software may be used by individuals, institutions, governments, corporations, or
     14   other business whether for-profit or non-profit so long as the use itself is not a commercialization of the
     15   materials or a use that generates or is intended to generate income, revenue, sales or profit.
     16 The above copyright notice and this license shall be included in all copies or substantial portions of the Software.
     17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
     18   THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     19   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     20   CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21   DEALINGS IN THE SOFTWARE.
     22 *******************************************************************************************************************/
     23 
     24 #ifndef GENLIB_OPS_H
     25 #define GENLIB_OPS_H 1
     26 
     27 #include "genlib_common.h"
     28 #include "genlib.h"
     29 
     30 #ifndef MSP_ON_CLANG
     31 #	include <cmath>
     32 #endif
     33 
     34 //////////// genlib_ops.h ////////////
     35 
     36 // system constants
     37 #define GENLIB_DBL_EPSILON (__DBL_EPSILON__)
     38 #define GENLIB_FLT_EPSILON (__FLT_EPSILON__)
     39 
     40 // denormal numbers cannot occur when hosted in MSP, nor on ARM Cortex processors:
     41 #if defined(MSP_ON_CLANG) || defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7)
     42 #	define GENLIB_NO_DENORM_TEST 1
     43 #endif // defined(MSP_ON_CLANG) || defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7)
     44 
     45 #ifdef GENLIB_USE_FLOAT32
     46 #	define GENLIB_EPSILON GENLIB_FLT_EPSILON
     47 #else
     48 #	define GENLIB_EPSILON GENLIB_DBL_EPSILON
     49 #endif
     50 
     51 #define GENLIB_PI (t_sample(3.14159265358979323846264338327950288))
     52 #define GENLIB_PI_OVER_2 (t_sample(1.57079632679489661923132169163975144))
     53 #define GENLIB_PI_OVER_4 (t_sample(0.785398163397448309615660845819875721))
     54 #define GENLIB_1_OVER_LOG_2 (t_sample(1.442695040888963))
     55 
     56 // assumes v is a 64-bit double:
     57 #ifdef GENLIB_USE_FLOAT32
     58 #	define GENLIB_IS_NAN_FLOAT(v)			((v)!=(v))
     59 #	define GENLIB_FIX_NAN_FLOAT(v)			((v)=GENLIB_IS_NAN_FLOAT(v)?0.f:(v))
     60 
     61 #	ifdef GENLIB_NO_DENORM_TEST
     62 #		define GENLIB_IS_DENORM_FLOAT(v)	(v)
     63 #		define GENLIB_FIX_DENORM_FLOAT(v)	(v)
     64 #	else
     65 #		ifdef WIN32
     66 #			define __FLT_MIN__	(FLT_MIN)
     67 #		endif
     68 #		define GENLIB_IS_DENORM_FLOAT(v)	((v)!=0.&&fabs(v)<__FLT_MIN__)
     69 #		define GENLIB_FIX_DENORM_FLOAT(v)	((v)=GENLIB_IS_DENORM_FLOAT(v)?0.f:(v))
     70 #	endif // GENLIB_NO_DENORM_TEST
     71 
     72 #	define GENLIB_IS_NAN		GENLIB_IS_NAN_FLOAT
     73 #	define GENLIB_FIX_NAN		GENLIB_FIX_NAN_FLOAT
     74 #	define GENLIB_IS_DENORM	GENLIB_IS_DENORM_FLOAT
     75 #	define GENLIB_FIX_DENORM	GENLIB_FIX_DENORM_FLOAT
     76 #else // GENLIB_USE_FLOAT32
     77 #	define GENLIB_IS_NAN_DOUBLE(v)			(((((uint32_t *)&(v))[1])&0x7fe00000)==0x7fe00000)
     78 #	define GENLIB_FIX_NAN_DOUBLE(v)		((v)=GENLIB_IS_NAN_DOUBLE(v)?0.:(v))
     79 
     80 #	ifdef GENLIB_NO_DENORM_TEST
     81 #		define GENLIB_IS_DENORM_DOUBLE(v)	(v)
     82 #		define GENLIB_FIX_DENORM_DOUBLE(v)	(v)
     83 #	else // GENLIB_NO_DENORM_TEST
     84 #		define GENLIB_IS_DENORM_DOUBLE(v)	((((((uint32_t *)&(v))[1])&0x7fe00000)==0)&&((v)!=0.))
     85 #		define GENLIB_FIX_DENORM_DOUBLE(v)	((v)=GENLIB_IS_DENORM_DOUBLE(v)?0.f:(v))
     86 #	endif
     87 
     88 #	define GENLIB_IS_NAN		GENLIB_IS_NAN_DOUBLE
     89 #	define GENLIB_FIX_NAN		GENLIB_FIX_NAN_DOUBLE
     90 #	define GENLIB_IS_DENORM	GENLIB_IS_DENORM_DOUBLE
     91 #	define GENLIB_FIX_DENORM	GENLIB_FIX_DENORM_DOUBLE
     92 #endif // GENLIB_USE_FLOAT32
     93 
     94 #define GENLIB_QUANT(f1,f2)			t_sample(floor((f1)*(f2)+0.5)/(f2))
     95 
     96 inline t_sample genlib_isnan(t_sample v) { return GENLIB_IS_NAN(v); }
     97 inline t_sample fixnan(t_sample v) { return GENLIB_FIX_NAN(v); }
     98 inline t_sample fixdenorm(t_sample v) { return GENLIB_FIX_DENORM(v); }
     99 inline t_sample isdenorm(t_sample v) { return GENLIB_IS_DENORM(v); }
    100 
    101 inline t_sample fasterpow(t_sample x, t_sample p);
    102 inline t_sample fasterexp(t_sample x);
    103 inline t_sample fastercosfull(t_sample x);
    104 inline t_sample fastersinfull(t_sample x);
    105 inline t_sample fastertanfull(t_sample x);
    106 
    107 inline t_sample safemod(t_sample f, t_sample m) {
    108 	if (m > GENLIB_DBL_EPSILON || m < -GENLIB_DBL_EPSILON) {
    109 		if (m<0)
    110 			m = -m; // modulus needs to be absolute value
    111 		if (f>=m) {
    112 			if (f>=(m*2.)) {
    113 				t_sample d = f / m;
    114 				d = d - (long) d;
    115 				f = d * m;
    116 			}
    117 			else {
    118 				f -= m;
    119 			}
    120 		}
    121 		else if (f<=(-m)) {
    122 			if (f<=(-m*2.)) {
    123 				t_sample d = f / m;
    124 				d = d - (long) d;
    125 				f = d * m;
    126 			}
    127 			 else {
    128 				f += m;
    129 			}
    130 		}
    131 	} else {
    132 		f = 0.0; //don't divide by zero
    133 	}
    134 	return f;
    135 }
    136 
    137 inline t_sample safediv(t_sample num, t_sample denom) {
    138 	return denom == 0. ? (t_sample)0. : (t_sample)(num/denom);
    139 }
    140 
    141 // fixnan for case of negative base and non-integer exponent:
    142 inline t_sample safepow(t_sample base, t_sample exponent) {
    143 	return fixnan(pow(base, exponent));
    144 }
    145 
    146 inline t_sample absdiff(t_sample a, t_sample b) { return fabs(a-b); }
    147 
    148 #ifndef WIN32
    149 inline t_sample exp2(t_sample v) { return pow(2., v); }
    150 
    151 inline t_sample trunc(t_sample v) {
    152 	t_sample epsilon = (v<0.0) * -2 * 1E-9 + 1E-9;
    153 	// copy to long so it gets truncated (probably cheaper than floor())
    154 	long val = v + epsilon;
    155 	return val;
    156 }
    157 #endif // WIN32
    158 
    159 inline t_sample sign(t_sample v) {
    160 	return v > t_sample(0) ? t_sample(1) : v < t_sample(0) ? t_sample(-1) : t_sample(0);
    161 }
    162 
    163 inline long is_poweroftwo(long x) {
    164 	return (x & (x - 1)) == 0;
    165 }
    166 
    167 inline uint64_t next_power_of_two(uint64_t v) {
    168     v--;
    169     v |= v >> 1;
    170     v |= v >> 2;
    171     v |= v >> 4;
    172     v |= v >> 8;
    173     v |= v >> 16;
    174     v |= v >> 32;
    175     v++;
    176     return v;
    177 }
    178 
    179 inline t_sample fold(t_sample v, t_sample lo1, t_sample hi1){
    180 	t_sample lo;
    181 	t_sample hi;
    182 	if(lo1 == hi1){ return lo1; }
    183 	if (lo1 > hi1) {
    184 		hi = lo1; lo = hi1;
    185 	} else {
    186 		lo = lo1; hi = hi1;
    187 	}
    188 	const t_sample range = hi - lo;
    189 	long numWraps = 0;
    190 	if(v >= hi){
    191 		v -= range;
    192 		if(v >= hi){
    193 			numWraps = (long)((v - lo)/range);
    194 			v -= range * (t_sample)numWraps;
    195 		}
    196 		numWraps++;
    197 	} else if(v < lo){
    198 		v += range;
    199 		if(v < lo){
    200 			numWraps = (long)((v - lo)/range) - 1;
    201 			v -= range * (t_sample)numWraps;
    202 		}
    203 		numWraps--;
    204 	}
    205 	if(numWraps & 1) v = hi + lo - v;	// flip sign for odd folds
    206 	return v;
    207 }
    208 
    209 inline t_sample wrap(t_sample v, t_sample lo1, t_sample hi1){
    210 	t_sample lo;
    211 	t_sample hi;
    212 	if(lo1 == hi1) return lo1;
    213 	if (lo1 > hi1) {
    214 		hi = lo1; lo = hi1;
    215 	} else {
    216 		lo = lo1; hi = hi1;
    217 	}
    218 	const t_sample range = hi - lo;
    219 	if (v >= lo && v < hi) return v;
    220 	if (range <= 0.000000001) return lo;	// no point...
    221 	const long numWraps = long((v-lo)/range) - (v < lo);
    222 	return v - range * t_sample(numWraps);
    223 }
    224 
    225 // this version gives far better performance when wrapping is relatively rare
    226 // and typically double of wraps is very low (>1%)
    227 // but catastrophic if wraps is high (1000%+)
    228 inline t_sample genlib_wrapfew(t_sample v, t_sample lo, t_sample hi){
    229 	const t_sample range = hi - lo;
    230 	while (v >= hi) v -= range;
    231 	while (v < lo) v += range;
    232 	return v;
    233 }
    234 
    235 inline t_sample phasewrap(t_sample val) {
    236 	const t_sample twopi = GENLIB_PI*2.;
    237 	const t_sample oneovertwopi = t_sample(1./twopi);
    238 	if (val>= twopi || val <= twopi) {
    239 		t_sample d = val * oneovertwopi;	//multiply faster
    240 		d = d - (long)d;
    241 		val = d * twopi;
    242 	}
    243 	if (val > GENLIB_PI) val -= twopi;
    244 	if (val < -GENLIB_PI) val += twopi;
    245 	return val;
    246 }
    247 
    248 /// 8th order Taylor series approximation to a cosine.
    249 /// r must be in [-pi, pi].
    250 inline t_sample genlib_cosT8(t_sample r) {
    251 	const t_sample t84 = 56.;
    252 	const t_sample t83 = 1680.;
    253 	const t_sample t82 = 20160.;
    254 	const t_sample t81 = t_sample(2.4801587302e-05);
    255 	const t_sample t73 = 42.;
    256 	const t_sample t72 = 840.;
    257 	const t_sample t71 = t_sample(1.9841269841e-04);
    258 	if (r < GENLIB_PI_OVER_4 && r > -GENLIB_PI_OVER_4){
    259 		t_sample rr = r*r;
    260 		return t_sample(1. - rr * t81 * (t82 - rr * (t83 - rr * (t84 - rr))));
    261 	}
    262 	else if (r > 0.){
    263 		r -= GENLIB_PI_OVER_2;
    264 		t_sample rr = r*r;
    265 		return t_sample(-r * (1. - t71 * rr * (t72 - rr * (t73 - rr))));
    266 	}
    267 	else {
    268 		r += GENLIB_PI_OVER_2;
    269 		t_sample rr = r*r;
    270 		return t_sample(r * (1. - t71 * rr * (t72 - rr * (t73 - rr))));
    271 	}
    272 }
    273 
    274 //inline double genlib_sin_fast(const double r){
    275 //	const double y = (4./GENLIB_PI) * r + (-4./(GENLIB_PI*GENLIB_PI)) * r * fabs(r);
    276 //	return 0.225 * (y * fabs(y) - y) + y;   // Q * y + P * y * abs(y)
    277 //}
    278 //
    279 //inline t_sample genlib_sinP7(t_sample n){
    280 //	t_sample nn = n*n;
    281 //	return n * (t_sample(3.138982) + nn * (t_sample(-5.133625) + nn * (t_sample(2.428288) - nn * t_sample(0.433645))));
    282 //}
    283 //
    284 //inline t_sample genlib_sinP9(t_sample n){
    285 //	t_sample nn = n*n;
    286 //	return n * (GENLIB_PI + nn * (t_sample(-5.1662729) + nn * (t_sample(2.5422065) + nn * (t_sample(-0.5811243) + nn * t_sample(0.0636716)))));
    287 //}
    288 //
    289 //inline t_sample genlib_sinT7(t_sample r){
    290 //	const t_sample t84 = 56.;
    291 //	const t_sample t83 = 1680.;
    292 //	const t_sample t82 = 20160.;
    293 //	const t_sample t81 = 2.4801587302e-05;
    294 //	const t_sample t73 = 42.;
    295 //	const t_sample t72 = 840.;
    296 //	const t_sample t71 = 1.9841269841e-04;
    297 //	if(r < GENLIB_PI_OVER_4 && r > -GENLIB_PI_OVER_4){
    298 //		t_sample rr = r*r;
    299 //		return r * (1. - t71 * rr * (t72 - rr * (t73 - rr)));
    300 //	}
    301 //	else if(r > 0.){
    302 //		r -= GENLIB_PI_OVER_2;
    303 //		t_sample rr = r*r;
    304 //		return t_sample(1.) - rr * t81 * (t82 - rr * (t83 - rr * (t84 - rr)));
    305 //	}
    306 //	else{
    307 //		r += GENLIB_PI_OVER_2;
    308 //		t_sample rr = r*r;
    309 //		return t_sample(-1.) + rr * t81 * (t82 - rr * (t83 - rr * (t84 - rr)));
    310 //	}
    311 //}
    312 
    313 // use these if r is not known to be in [-pi, pi]:
    314 inline t_sample genlib_cosT8_safe(t_sample r) { return genlib_cosT8(phasewrap(r)); }
    315 //inline double genlib_sin_fast_safe(double r) { return genlib_sin_fast(phasewrap(r)); }
    316 //inline t_sample genlib_sinP7_safe(t_sample r) { return genlib_sinP7(phasewrap(r)); }
    317 //inline t_sample genlib_sinP9_safe(t_sample r) { return genlib_sinP9(phasewrap(r)); }
    318 //inline t_sample genlib_sinT7_safe(t_sample r) { return genlib_sinT7(phasewrap(r)); }
    319 
    320 
    321 
    322 /*=====================================================================*
    323  *                   Copyright (C) 2011 Paul Mineiro                   *
    324  * All rights reserved.                                                *
    325  *                                                                     *
    326  * Redistribution and use in source and binary forms, with             *
    327  * or without modification, are permitted provided that the            *
    328  * following conditions are met:                                       *
    329  *                                                                     *
    330  *     * Redistributions of source code must retain the                *
    331  *     above copyright notice, this list of conditions and             *
    332  *     the following disclaimer.                                       *
    333  *                                                                     *
    334  *     * Redistributions in binary form must reproduce the             *
    335  *     above copyright notice, this list of conditions and             *
    336  *     the following disclaimer in the documentation and/or            *
    337  *     other materials provided with the distribution.                 *
    338  *                                                                     *
    339  *     * Neither the name of Paul Mineiro nor the names                *
    340  *     of other contributors may be used to endorse or promote         *
    341  *     products derived from this software without specific            *
    342  *     prior written permission.                                       *
    343  *                                                                     *
    344  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND              *
    345  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,         *
    346  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES               *
    347  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE             *
    348  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER               *
    349  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,                 *
    350  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES            *
    351  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE           *
    352  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR                *
    353  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF          *
    354  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           *
    355  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY              *
    356  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE             *
    357  * POSSIBILITY OF SUCH DAMAGE.                                         *
    358  *                                                                     *
    359  * Contact: Paul Mineiro <paul@mineiro.com>                            *
    360  *=====================================================================*/
    361 
    362 inline float genlib_fastersin(float x) {
    363 	static const float fouroverpi = 1.2732395447351627f;
    364 	static const float fouroverpisq = 0.40528473456935109f;
    365 	static const float q = 0.77633023248007499f;
    366 	union { float f; uint32_t i; } p = { 0.22308510060189463f };
    367 	union { float f; uint32_t i; } vx = { x };
    368 	uint32_t sign = vx.i & 0x80000000;
    369 	vx.i &= 0x7FFFFFFF;
    370 	float qpprox = fouroverpi * x - fouroverpisq * x * vx.f;
    371 	p.i |= sign;
    372 	return qpprox * (q + p.f * qpprox);
    373 }
    374 
    375 inline float genlib_fastercos(float x) {
    376 	static const float twooverpi = 0.63661977236758134f;
    377 	static const float p = 0.54641335845679634f;
    378 	union { float f; uint32_t i; } vx = { x };
    379 	vx.i &= 0x7FFFFFFF;
    380 	float qpprox = 1.0f - twooverpi * vx.f;
    381 	return qpprox + p * qpprox * (1.0f - qpprox * qpprox);
    382 }
    383 
    384 inline float genlib_fastersinfull(float x) {
    385 	static const float twopi = 6.2831853071795865f;
    386 	static const float invtwopi = 0.15915494309189534f;
    387 	int k = int(x * invtwopi);
    388 	float half = (x < 0) ? -0.5f : 0.5f;
    389 	return genlib_fastersin ((half + k) * twopi - x);
    390 }
    391 
    392 inline float genlib_fastercosfull(float x) {
    393 	static const float halfpi = 1.5707963267948966f;
    394 	return genlib_fastersinfull (x + halfpi);
    395 }
    396 
    397 inline float genlib_fastertanfull(float x) {
    398 	static const float twopi = 6.2831853071795865f;
    399 	static const float invtwopi = 0.15915494309189534f;
    400 	int k = int(x * invtwopi);
    401 	float half = (x < 0) ? -0.5f : 0.5f;
    402 	float xnew = x - (half + k) * twopi;
    403 	return genlib_fastersin (xnew) / genlib_fastercos (xnew);
    404 }
    405 
    406 
    407 #define cast_uint32_t static_cast<uint32_t>
    408 inline float genlib_fasterpow2(float p) {
    409 	float clipp = (p < -126) ? -126.0f : p;
    410 	union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 126.94269504f) ) };
    411 	return v.f;
    412 }
    413 
    414 inline float genlib_fasterexp(float p) {
    415 	return genlib_fasterpow2 (1.442695040f * p);
    416 }
    417 
    418 inline float genlib_fasterlog2(float x) {
    419 	union { float f; uint32_t i; } vx = { x };
    420 	float y = float(vx.i);
    421 	y *= 1.1920928955078125e-7f;
    422 	return y - 126.94269504f;
    423 }
    424 
    425 inline float genlib_fasterpow(float x, float p) {
    426 	return genlib_fasterpow2(p * genlib_fasterlog2 (x));
    427 }
    428 
    429 // from http://dspguru.com/dsp/tricks/fixed-point-atan2-with-self-normalization
    430 inline float genlib_fasteratan2(float y, float x) {
    431 	const float coeff_1 = (float)(GENLIB_PI/4);
    432 	const float coeff_2 = 3 * (float)(GENLIB_PI/4);
    433 	float abs_y = fabs(y) + 1e-10; // kludge to prevent 0/0 condition
    434 	float r, angle;
    435 	if (x >= 0) {
    436 		r = (x - abs_y) / (x + abs_y);
    437 		angle = coeff_1 - coeff_1 * r;
    438 	}
    439 	else {
    440 		r = (x + abs_y) / (abs_y - x);
    441 		angle = coeff_2 - coeff_1 * r;
    442 	}
    443 	if (y < 0) {
    444 		return (-angle); // negate if in quad III or IV
    445 	}
    446 	else {
    447 		return (angle);
    448 	}
    449 }
    450 
    451 // http://math.stackexchange.com/questions/107292/rapid-approximation-of-tanhx
    452 inline float genlib_fastertanh(float x) {
    453 	return (-.67436811832e-5 + (.2468149110712040 + (.583691066395175e-1 + .3357335044280075e-1 * x) * x) * x) /
    454 			(.2464845986383725 + (.609347197060491e-1 + (.1086202599228572 + .2874707922475963e-1 * x) * x) * x);
    455 }
    456 
    457 ////////////////////////////////////////////////////////////////
    458 
    459 inline t_sample fastertanfull(t_sample x) {
    460 	return (t_sample)genlib_fastertanfull((float)x);
    461 }
    462 
    463 inline t_sample fastersinfull(t_sample x) {
    464 	return (t_sample)genlib_fastersinfull((float)x);
    465 }
    466 
    467 inline t_sample fastercosfull(t_sample x) {
    468 	return (t_sample)genlib_fastercosfull((float)x);
    469 }
    470 
    471 inline t_sample fasterexp(t_sample x) {
    472 	return (t_sample)genlib_fasterexp((float)x);
    473 }
    474 
    475 inline t_sample fasterlog2(t_sample x) {
    476 	return (t_sample)genlib_fasterlog2((float)x);
    477 }
    478 
    479 inline t_sample fasterpow(t_sample x, t_sample p) {
    480 	return (t_sample)genlib_fasterpow((float)x, (float)p);
    481 }
    482 
    483 inline t_sample fasterpow2(t_sample p) {
    484 	return (t_sample)genlib_fasterpow2((float)p);
    485 }
    486 
    487 inline t_sample fasteratan2(t_sample y, t_sample x) {
    488 	return (t_sample)genlib_fasteratan2(y, x);
    489 }
    490 
    491 inline t_sample fastertanh(t_sample x) {
    492 	return (t_sample)genlib_fastertanh((float)x);
    493 }
    494 
    495 /****************************************************************/
    496 
    497 
    498 
    499 inline t_sample minimum(t_sample x, t_sample y) { return (y<x?y:x); }
    500 inline t_sample maximum(t_sample x, t_sample y) { return (x<y?y:x); }
    501 
    502 inline t_sample clamp(t_sample x, t_sample minVal, t_sample maxVal) {
    503 	return minimum(maximum(x,minVal),maxVal);
    504 }
    505 
    506 template<typename T>
    507 inline T smoothstep(t_sample e0, t_sample e1, T x) {
    508 	T t = clamp( safediv(x-T(e0),T(e1-e0)), 0., 1. );
    509 	return t*t*(T(3) - T(2)*t);
    510 }
    511 
    512 inline t_sample mix(t_sample x, t_sample y, t_sample a) {
    513 	return x+a*(y-x);
    514 }
    515 
    516 inline t_sample scale(t_sample in, t_sample inlow, t_sample inhigh, t_sample outlow, t_sample outhigh, t_sample power)
    517 {
    518 	t_sample value;
    519 	t_sample inscale = safediv(1., inhigh - inlow);
    520 	t_sample outdiff = outhigh - outlow;
    521 
    522 	value = (in - inlow) * inscale;
    523 	if (value > 0.0)
    524 		value = pow(value, power);
    525 	else if (value < 0.0)
    526 		value = -pow(-value, power);
    527 	value = (value * outdiff) + outlow;
    528 
    529 	return value;
    530 }
    531 
    532 inline t_sample linear_interp(t_sample a, t_sample x, t_sample y) {
    533 	return x+a*(y-x);
    534 }
    535 
    536 inline t_sample cosine_interp(t_sample a, t_sample x, t_sample y) {
    537 	const t_sample a2 = (t_sample(1.)-genlib_cosT8_safe(a*t_sample(GENLIB_PI)))/t_sample(2.);
    538 	return(x*(t_sample(1.)-a2)+y*a2);
    539 }
    540 
    541 inline t_sample cubic_interp(t_sample a, t_sample w, t_sample x, t_sample y, t_sample z) {
    542 	const t_sample a1 = t_sample(1.) + a;
    543 	const t_sample aa = a * a1;
    544 	const t_sample b = t_sample(1.) - a;
    545 	const t_sample b1 = t_sample(2.) - a;
    546 	const t_sample bb = b * b1;
    547 	const t_sample fw = t_sample(-.1666667) * bb * a;
    548 	const t_sample fx = t_sample(.5) * bb * a1;
    549 	const t_sample fy = t_sample(.5) * aa * b1;
    550 	const t_sample fz = t_sample(-.1666667) * aa * b;
    551 	return w * fw + x * fx + y * fy + z * fz;
    552 }
    553 
    554 // deprecated, as it shows some instability with feedback
    555 inline t_sample fastcubic_interp(t_sample a, t_sample w, t_sample x, t_sample y, t_sample z) {
    556 	const t_sample a2 = a*a;
    557 	const t_sample f0 = z - y - w + x;
    558 	const t_sample f1 = w - x - f0;
    559 	const t_sample f2 = y - w;
    560 	const t_sample f3 = x;
    561 	return(f0*a*a2 + f1*a2 + f2*a + f3);
    562 }
    563 
    564 // Breeuwsma catmull-rom spline interpolation
    565 inline t_sample spline_interp(t_sample a, t_sample w, t_sample x, t_sample y, t_sample z) {
    566 	const t_sample c0 = x;
    567 	const t_sample c1 = t_sample(0.5) * (y - w);
    568 	const t_sample c2 = w - t_sample(2.5) * x + y + y - t_sample(0.5) * z;
    569 	const t_sample c3 = t_sample(0.5) * (z - w) + t_sample(1.5) * (x - y);
    570 	return (((c3 * a + c2) * a + c1) * a + c0);
    571 }
    572 
    573 // 6-point, 5th-order B-spline
    574 inline t_sample spline6_interp(t_sample a, t_sample y0, t_sample y1, t_sample y2, t_sample y3, t_sample y4, t_sample y5) {
    575 	// http://yehar.com/blog/wp-content/uploads/2009/08/deip.pdf
    576 	// 6-point, 5th-order B-spline (x-form)
    577 	const t_sample ym2py2 = y0+y4;
    578 	const t_sample ym1py1 = y1+y3;
    579 	const t_sample y2mym2 = y4-y0;
    580 	const t_sample y1mym1 = y3-y1;
    581 	const t_sample sixthym1py1 = 1/6.0*ym1py1;
    582 	const t_sample c0 = 1/120.0*ym2py2 + 13/60.0*ym1py1 + 11/20.0*y2;
    583 	const t_sample c1 = 1/24.0*y2mym2 + 5/12.0*y1mym1;
    584 	const t_sample c2 = 1/12.0*ym2py2 + sixthym1py1 - 1/2.0*y2;
    585 	const t_sample c3 = 1/12.0*y2mym2 - 1/6.0*y1mym1;
    586 	const t_sample c4 = 1/24.0*ym2py2 - sixthym1py1 + 1/4.0*y2;
    587 	const t_sample c5 = 1/120.0*(y5-y0) + 1/24.0*(y1-y4) + 1/12.0*(y3-y2);
    588 	return ((((c5*a+c4)*a+c3)*a+c2)*a+c1)*a+c0;
    589 }
    590 
    591 template<typename T1, typename T2>
    592 inline T1 neqp(T1 x, T2 y) {
    593 	return ((((x) != T1(y))) ? (x) : T1(0));
    594 }
    595 
    596 template<typename T1, typename T2>
    597 inline T1 gtp(T1 x, T2 y) { return ((((x) > T1(y))) ? (x) : T1(0)); }
    598 template<typename T1, typename T2>
    599 inline T1 gtep(T1 x, T2 y) { return ((((x) >= T1(y))) ? (x) : T1(0)); }
    600 template<typename T1, typename T2>
    601 inline T1 ltp(T1 x, T2 y) { return ((((x) < T1(y))) ? (x) : T1(0)); }
    602 template<typename T1, typename T2>
    603 inline T1 ltep(T1 x, T2 y) { return ((((x) <= T1(y))) ? (x) : T1(0)); }
    604 
    605 inline t_sample fract(t_sample x) { double unused; return (t_sample)modf((double)x, &unused); }
    606 
    607 // log2(x) = log(x)/log(2)
    608 template<typename T>
    609 inline T log2(T x) {
    610 	return log(x)*GENLIB_1_OVER_LOG_2;
    611 }
    612 
    613 inline t_sample atodb(t_sample in) {
    614 	return t_sample((in <= 0.) ? -999. : (20. * log10(in)));
    615 }
    616 
    617 inline t_sample dbtoa(t_sample in) {
    618 	return t_sample(pow(10., in * 0.05));
    619 }
    620 
    621 inline t_sample ftom(t_sample in, t_sample tuning=440.) {
    622 	return t_sample(69. + 17.31234050465299 * log(safediv(in, tuning)));
    623 }
    624 
    625 inline t_sample mtof(t_sample in, t_sample tuning=440.) {
    626 	return t_sample(tuning * exp(.057762265 * (in - 69.0)));
    627 }
    628 
    629 inline t_sample mstosamps(t_sample ms, t_sample samplerate=44100.) {
    630 	return t_sample(samplerate * ms * t_sample(0.001));
    631 }
    632 
    633 inline t_sample sampstoms(t_sample s, t_sample samplerate=44100.) {
    634 	return t_sample(t_sample(1000.) * s / samplerate);
    635 }
    636 
    637 inline t_sample triangle(t_sample phase, t_sample p1) {
    638 	phase = wrap(phase, 0., 1.);
    639 	p1 = clamp(p1, 0., 1.);
    640 	if (phase < p1)
    641 		return t_sample((p1) ? phase/p1 : 0.);
    642 	else
    643 		return t_sample((p1==1.) ? phase : 1. - ((phase - p1) / (1. - p1)));
    644 }
    645 
    646 struct Delta {
    647 	t_sample history;
    648 	Delta() { reset(); }
    649 	inline void reset(t_sample init=0) { history=init; }
    650 
    651 	inline t_sample operator()(t_sample in1) {
    652 		t_sample ret = in1 - history;
    653 		history = in1;
    654 		return ret;
    655 	}
    656 };
    657 struct Change {
    658 	t_sample history;
    659 	Change() { reset(); }
    660 	inline void reset(t_sample init=0) { history=init; }
    661 
    662 	inline t_sample operator()(t_sample in1) {
    663 		t_sample ret = in1 - history;
    664 		history = in1;
    665 		return sign(ret);
    666 	}
    667 };
    668 
    669 struct Rate {
    670 	t_sample phase, diff, mult, invmult, prev;
    671 	int wantlock, quant;
    672 
    673 	Rate() { reset(); }
    674 
    675 	inline void reset() {
    676 		phase = diff = prev = 0;
    677 		mult = invmult = 1;
    678 		wantlock = 1;
    679 		quant = 1;
    680 	}
    681 
    682 	inline t_sample perform_lock(t_sample in1, t_sample in2) {
    683 		// did multiplier change?
    684 		if (in2 != mult && !genlib_isnan(in2)) {
    685 			mult = in2;
    686 			invmult = safediv(1., mult);
    687 			wantlock = 1;
    688 		}
    689 		t_sample diff = in1 - prev;
    690 
    691 		if (diff < t_sample(-0.5)) {
    692 			diff += t_sample(1);
    693 		} else if (diff > t_sample(0.5)) {
    694 			diff -= t_sample(1);
    695 		}
    696 
    697 		if (wantlock) {
    698 			// recalculate phase
    699 			phase = (in1 - GENLIB_QUANT(in1, quant)) * invmult
    700 						+ GENLIB_QUANT(in1, quant * mult);
    701 			diff = 0;
    702 			wantlock = 0;
    703 		} else {
    704 			// diff is always between -0.5 and 0.5
    705 			phase += diff * invmult;
    706 		}
    707 
    708 		if (phase > t_sample(1.) || phase < t_sample(-0.)) {
    709 			phase = phase - (long)(phase);
    710 		}
    711 
    712 		prev = in1;
    713 
    714 		return phase;
    715 	}
    716 
    717 	inline t_sample perform_cycle(t_sample in1, t_sample in2) {
    718 		// did multiplier change?
    719 		if (in2 != mult && !genlib_isnan(in2)) {
    720 			mult = in2;
    721 			invmult = safediv(1., mult);
    722 			wantlock = 1;
    723 		}
    724 		t_sample diff = in1 - prev;
    725 
    726 		if (diff < t_sample(-0.5)) {
    727 			if (wantlock) {
    728 				wantlock = 0;
    729 				phase = in1 * invmult;
    730 				diff = t_sample(0);
    731 			} else {
    732 				diff += t_sample(1);
    733 			}
    734 		} else if (diff > t_sample(0.5)) {
    735 			if (wantlock) {
    736 				wantlock = 0;
    737 				phase = in1 * invmult;
    738 				diff = t_sample(0);
    739 			} else {
    740 				diff -= t_sample(1);
    741 			}
    742 		}
    743 
    744 		// diff is always between -0.5 and 0.5
    745 		phase += diff * invmult;
    746 
    747 		if (phase > t_sample(1.) || phase < t_sample(-0.)) {
    748 			phase = phase - (long)(phase);
    749 		}
    750 
    751 		prev = in1;
    752 
    753 		return phase;
    754 	}
    755 
    756 	inline t_sample perform_off(t_sample in1, t_sample in2) {
    757 		// did multiplier change?
    758 		if (in2 != mult && !genlib_isnan(in2)) {
    759 			mult = in2;
    760 			invmult = safediv(1., mult);
    761 			wantlock = 1;
    762 		}
    763 		t_sample diff = in1 - prev;
    764 
    765 		if (diff < t_sample(-0.5)) {
    766 			diff += t_sample(1);
    767 		} else if (diff > t_sample(0.5)) {
    768 			diff -= t_sample(1);
    769 		}
    770 
    771 		phase += diff * invmult;
    772 
    773 		if (phase > t_sample(1.) || phase < t_sample(-0.)) {
    774 			phase = phase - (long)(phase);
    775 		}
    776 
    777 		prev = in1;
    778 
    779 		return phase;
    780 	}
    781 };
    782 
    783 struct DCBlock {
    784 	t_sample x1, y1;
    785 	DCBlock() { reset(); }
    786 	inline void reset() { x1=0; y1=0; }
    787 
    788 	inline t_sample operator()(t_sample in1) {
    789 		t_sample y = in1 - x1 + y1*t_sample(0.9997);
    790 		x1 = in1;
    791 		y1 = y;
    792 		return y;
    793 	}
    794 };
    795 
    796 struct Noise {
    797 	unsigned long last;
    798 	static long uniqueTickCount(void) {
    799 		static long lasttime = 0;
    800 		long time = genlib_ticks();
    801 		return (time <= lasttime) ? (++lasttime) : (lasttime = time);
    802 	}
    803 
    804 	Noise() { reset(); }
    805 	Noise(t_sample seed) { reset(seed); }
    806 	void reset() { last = uniqueTickCount() * uniqueTickCount(); }
    807 	void reset(t_sample seed) { last = (unsigned long)(seed); }
    808 
    809 	inline t_sample operator()() {
    810 		last = 1664525L * last + 1013904223L;
    811 		union {
    812 			uint32_t ui32;
    813 			float f;
    814 		} u = { uint32_t(0x3f800000 | (0x007fffff & last)) }; // type-punning
    815 
    816 		return (u.f * 2.f) - 3.f;
    817 	}
    818 };
    819 
    820 struct Phasor {
    821 	t_sample phase;
    822 	Phasor() { reset(); }
    823 	void reset(t_sample v=0.) { phase=v; }
    824 	inline t_sample operator()(t_sample freq, t_sample invsamplerate) {
    825 		const t_sample pincr = freq * invsamplerate;
    826 		//phase = genlib_wrapfew(phase + pincr, 0., 1.); // faster for low frequencies, but explodes with high frequencies
    827 		phase = wrap(phase + pincr, 0., 1.);
    828 		return phase;
    829 	}
    830 };
    831 
    832 struct PlusEquals {
    833 	t_sample count;
    834 	PlusEquals() { reset(); }
    835 	void reset(t_sample v=0.) { count=v; }
    836 
    837 	// reset post-application mode:
    838 	inline t_sample post(t_sample incr, t_sample reset, t_sample min, t_sample max) {
    839 		count = reset ? min : wrap(count+incr, min, max);
    840 		return count;
    841 	}
    842 	inline t_sample post(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
    843 		count = reset ? min : count+incr;
    844 		return count;
    845 	}
    846 
    847 	// reset pre-application mode:
    848 	inline t_sample pre(t_sample incr, t_sample reset, t_sample min, t_sample max) {
    849 		count = reset ? min+incr : wrap(count+incr, min, max);
    850 		return count;
    851 	}
    852 	inline t_sample pre(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
    853 		count = reset ? min+incr : count+incr;
    854 		return count;
    855 	}
    856 };
    857 
    858 struct MulEquals {
    859 	t_sample count;
    860 	MulEquals() { reset(); }
    861 	void reset(t_sample v=0.) { count=v; }
    862 
    863 	// reset post-application mode:
    864 	inline t_sample post(t_sample incr, t_sample reset, t_sample min, t_sample max) {
    865 		count = reset ? min : wrap(fixdenorm(count*incr), min, max);
    866 		return count;
    867 	}
    868 	inline t_sample post(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
    869 		count = reset ? min : fixdenorm(count*incr);
    870 		return count;
    871 	}
    872 
    873 	// reset pre-application mode:
    874 	inline t_sample pre(t_sample incr, t_sample reset, t_sample min, t_sample max) {
    875 		count = reset ? min*incr : wrap(fixdenorm(count*incr), min, max);
    876 		return count;
    877 	}
    878 	inline t_sample pre(t_sample incr=1., t_sample reset=0., t_sample min=0.) {
    879 		count = reset ? min*incr : fixdenorm(count*incr);
    880 		return count;
    881 	}
    882 };
    883 
    884 struct Sah {
    885 	t_sample prev, output;
    886 	Sah() { reset(); }
    887 	void reset(t_sample o=0.) {
    888 		output = prev = o;
    889 	}
    890 
    891 	inline t_sample operator()(t_sample in, t_sample trig, t_sample thresh) {
    892 		if (prev <= thresh && trig > thresh) {
    893 			output = in;
    894 		}
    895 		prev = trig;
    896 		return output;
    897 	}
    898 };
    899 
    900 struct Train {
    901 	t_sample phase, state;
    902 	Train() { reset(); }
    903 	void reset(t_sample p=0) { phase = p; state = 0.; }
    904 
    905 	inline t_sample operator()(t_sample pulseinterval, t_sample width, t_sample pulsephase) {
    906 		if (width <= t_sample(0.)) {
    907 			state = t_sample(0.);	// no pulse!
    908 		} else if (width >= 1.) {
    909 			state = t_sample(1.); // constant pulse!
    910 		} else {
    911 			const t_sample interval = maximum(pulseinterval, t_sample(1.));	// >= 1.
    912 			const t_sample p1 = clamp(pulsephase, t_sample(0.), t_sample(1.));	// [0..1]
    913 			const t_sample p2 = p1+width;						// (p1..p1+1)
    914 			const t_sample pincr = t_sample(1.)/interval;			// (0..1]
    915 			phase += pincr;								// +ve
    916 			if (state) {	// on:
    917 				if (phase > p2) {
    918 					state = t_sample(0.);				// turn off
    919 					phase -= (int)(1.+phase-p2);		// wrap phase back down
    920 				}
    921 			} else {		// off:
    922 				if (phase > p1) {
    923 					state = t_sample(1.);				// turn on.
    924 				}
    925 			}
    926 		}
    927 		return state;
    928 	}
    929 };
    930 
    931 struct Delay {
    932 	t_sample *memory;
    933 	long size, wrap, maxdelay;
    934 	long reader, writer;
    935 
    936 	t_genlib_data *dataRef;
    937 
    938 	Delay() : memory(0) {
    939 		size = wrap = maxdelay = 0;
    940 		reader = writer = 0;
    941 		dataRef = 0;
    942 	}
    943 	~Delay() {
    944 		if (dataRef != 0) {
    945 			// store write position for persistence:
    946 			genlib_data_setcursor(dataRef, writer);
    947 			// decrement reference count:
    948 			genlib_data_release(dataRef);
    949 		}
    950 	}
    951 
    952 	inline void reset(const char *name, long d) {
    953 		// if needed, acquire the Data's global reference:
    954 		if (dataRef == 0) {
    955 
    956 			void *ref = genlib_obtain_reference_from_string(name);
    957 			dataRef = genlib_obtain_data_from_reference(ref);
    958 			if (dataRef == 0) {
    959 				genlib_report_error("failed to acquire data");
    960 				return;
    961 			}
    962 
    963 			// scale maxdelay to next highest power of 2:
    964 			maxdelay = d;
    965 			size = maxdelay < 2 ? 2 : maxdelay;
    966 			size = long(next_power_of_two(size));
    967 
    968 			// first reset should resize the memory:
    969 			genlib_data_resize(dataRef, size, 1);
    970 
    971 			t_genlib_data_info info;
    972 			if (genlib_data_getinfo(dataRef, &info) == GENLIB_ERR_NONE) {
    973 				if (info.dim != size) {
    974 					// at this point, could resolve by reducing to
    975 					// maxdelay = size = next_power_of_two(info.dim+1)/2;
    976 					// but really, if this happens, it means more than one
    977 					// object is referring to the same t_gen_dsp_data.
    978 					// which is probably bad news.
    979 					genlib_report_error("delay memory size error");
    980 					memory = 0;
    981 					return;
    982 				}
    983 				memory = info.data;
    984 				writer = genlib_data_getcursor(dataRef);
    985 			} else {
    986 				genlib_report_error("failed to acquire data info");
    987 			}
    988 
    989 		} else {
    990 			// subsequent reset should zero the memory & heads:
    991 			set_zero64(memory, size);
    992 			writer = 0;
    993 		}
    994 
    995 		reader = writer;
    996 		wrap = size-1;
    997 	}
    998 
    999 	// called at bufferloop end, updates read pointer time
   1000 	inline void step() {
   1001 		reader++;
   1002 		if (reader >= size) reader = 0;
   1003 	}
   1004 
   1005 	inline void write(t_sample x) {
   1006 		writer = reader;	// update write ptr
   1007 		memory[writer] = x;
   1008 	}
   1009 
   1010 	inline t_sample read_step(t_sample d) {
   1011 		// extra half for nice rounding:
   1012 		// min 1 sample delay for read before write (r != w)
   1013 		const t_sample r = t_sample(size + reader) - clamp(d-t_sample(0.5), t_sample(reader != writer), t_sample(maxdelay));
   1014 		long r1 = long(r);
   1015 		return memory[r1 & wrap];
   1016 	}
   1017 
   1018 	inline t_sample read_linear(t_sample d) {
   1019 		// min 1 sample delay for read before write (r != w)
   1020 		t_sample c = t_sample(clamp(d, t_sample(reader != writer), t_sample(maxdelay)));
   1021 		const t_sample r = t_sample(size + reader) - c;
   1022 		long r1 = long(r);
   1023 		long r2 = r1+1;
   1024 		t_sample a = r - (t_sample)r1;
   1025 		t_sample x = memory[r1 & wrap];
   1026 		t_sample y = memory[r2 & wrap];
   1027 		return linear_interp(a, x, y);
   1028 	}
   1029 
   1030 	inline t_sample read_cosine(t_sample d) {
   1031 		// min 1 sample delay for read before write (r != w)
   1032 		const t_sample r = t_sample(size + reader) - clamp(d, t_sample(reader != writer), t_sample(maxdelay));
   1033 		long r1 = long(r);
   1034 		long r2 = r1+1;
   1035 		t_sample a = r - (t_sample)r1;
   1036 		t_sample x = memory[r1 & wrap];
   1037 		t_sample y = memory[r2 & wrap];
   1038 		return cosine_interp(a, x, y);
   1039 	}
   1040 
   1041 	// cubic requires extra sample of compensation:
   1042 	inline t_sample read_fastcubic(t_sample d) {
   1043 		// min 1 sample delay for read before write (r != w)
   1044 		// plus extra 1 sample compensation for 4-point interpolation
   1045 		const t_sample r = t_sample(size + reader) - clamp(d, t_sample(1.) + t_sample(reader != writer), t_sample(maxdelay));
   1046 		long r1 = long(r);
   1047 		long r2 = r1+1;
   1048 		long r3 = r1+2;
   1049 		long r4 = r1+3;
   1050 		t_sample a = r - (t_sample)r1;
   1051 		t_sample w = memory[r1 & wrap];
   1052 		t_sample x = memory[r2 & wrap];
   1053 		t_sample y = memory[r3 & wrap];
   1054 		t_sample z = memory[r4 & wrap];
   1055 		return fastcubic_interp(a, w, x, y, z);
   1056 	}
   1057 	
   1058 	// cubic requires extra sample of compensation:
   1059 	inline t_sample read_cubic(t_sample d) {
   1060 		// min 1 sample delay for read before write (r != w)
   1061 		// plus extra 1 sample compensation for 4-point interpolation
   1062 		const t_sample r = t_sample(size + reader) - clamp(d, t_sample(1.) + t_sample(reader != writer), t_sample(maxdelay));
   1063 		long r1 = long(r);
   1064 		long r2 = r1+1;
   1065 		long r3 = r1+2;
   1066 		long r4 = r1+3;
   1067 		t_sample a = r - (t_sample)r1;
   1068 		t_sample w = memory[r1 & wrap];
   1069 		t_sample x = memory[r2 & wrap];
   1070 		t_sample y = memory[r3 & wrap];
   1071 		t_sample z = memory[r4 & wrap];
   1072 		return cubic_interp(a, w, x, y, z);
   1073 	}
   1074 
   1075 	// spline requires extra sample of compensation:
   1076 	inline t_sample read_spline(t_sample d) {
   1077 		// min 1 sample delay for read before write (r != w)
   1078 		// plus extra 1 sample compensation for 4-point interpolation
   1079 		const t_sample r = t_sample(size + reader) - clamp(d, t_sample(1.) + t_sample(reader != writer), t_sample(maxdelay));
   1080 		long r1 = long(r);
   1081 		long r2 = r1+1;
   1082 		long r3 = r1+2;
   1083 		long r4 = r1+3;
   1084 		t_sample a = r - (t_sample)r1;
   1085 		t_sample w = memory[r1 & wrap];
   1086 		t_sample x = memory[r2 & wrap];
   1087 		t_sample y = memory[r3 & wrap];
   1088 		t_sample z = memory[r4 & wrap];
   1089 		return spline_interp(a, w, x, y, z);
   1090 	}
   1091 	
   1092 	// spline requires extra sample of compensation:
   1093 	inline t_sample read_spline6(t_sample d) {
   1094 		// min 1 sample delay for read before write (r != w)
   1095 		// plus extra 1 sample compensation for 4-point interpolation
   1096 		const t_sample r = t_sample(size + reader) - clamp(d, t_sample(1.) + t_sample(reader != writer), t_sample(maxdelay));
   1097 		long r0 = long(r);
   1098 		long r1 = r1+1;
   1099 		long r2 = r1+2;
   1100 		long r3 = r1+3;
   1101 		long r4 = r1+4;
   1102 		long r5 = r1+5;
   1103 		t_sample a = r - (t_sample)r0;
   1104 		t_sample y0 = memory[r0 & wrap];
   1105 		t_sample y1 = memory[r1 & wrap];
   1106 		t_sample y2 = memory[r2 & wrap];
   1107 		t_sample y3 = memory[r3 & wrap];
   1108 		t_sample y4 = memory[r4 & wrap];
   1109 		t_sample y5 = memory[r5 & wrap];
   1110 		return spline6_interp(a, y0, y1, y2, y3, y4, y5);
   1111 	}
   1112 };
   1113 
   1114 template<typename T=t_sample>
   1115 struct DataInterface {
   1116 	long dim, channels;
   1117 	T *mData;
   1118 	void *mDataReference;		// this was t_symbol *mName
   1119 	int modified;
   1120 
   1121 	DataInterface() : dim(0), channels(1), mData(0), modified(0) { mDataReference = 0; }
   1122 
   1123 	// raw reading/writing/overdubbing (internal use only, no bounds checking)
   1124 	inline t_sample read(long index, long channel=0) const {
   1125 		return mData[channel+index*channels];
   1126 	}
   1127 	inline void write(T value, long index, long channel=0) {
   1128 		mData[channel+index*channels] = value;
   1129 		modified = 1;
   1130 	}
   1131 	// NO LONGER USED:
   1132 	inline void overdub(T value, long index, long channel=0) {
   1133 		mData[channel+index*channels] += value;
   1134 		modified = 1;
   1135 	}
   1136 
   1137 	// averaging overdub (used by splat)
   1138 	inline void blend(T value, long index, long channel, t_sample alpha) {
   1139 		long offset = channel+index*channels;
   1140 		const T old = mData[offset];
   1141 		mData[offset] = old + alpha * (value - old);
   1142 		modified = 1;
   1143 	}
   1144 
   1145 	// NO LONGER USED:
   1146 	inline void read_ok(long index, long channel=0, bool ok=1) const {
   1147 		return ok ? mData[channel+index*channels] : T(0);
   1148 	}
   1149 	inline void write_ok(T value, long index, long channel=0, bool ok=1) {
   1150 		if (ok) mData[channel+index*channels] = value;
   1151 	}
   1152 	inline void overdub_ok(T value, long index, long channel=0, bool ok=1) {
   1153 		if (ok) mData[channel+index*channels] += value;
   1154 	}
   1155 
   1156 	// Bounds strategies:
   1157 	inline long index_clamp(long index) const { return clamp(index, 0, dim-1); }
   1158 	inline long index_wrap(long index) const { return wrap(index, 0, dim); }
   1159 	inline long index_fold(long index) const { return fold(index, 0, dim); }
   1160 	inline bool index_oob(long index) const { return (index < 0 || index >= dim); }
   1161 	inline bool index_inbounds(long index) const { return (index >=0 && index < dim); }
   1162 
   1163 	// channel bounds:
   1164 	inline long channel_clamp(long c) const { return clamp(c, 0, channels-1); }
   1165 	inline long channel_wrap(long c) const { return wrap(c, 0, channels); }
   1166 	inline long channel_fold(long c) const { return fold(c, 0, channels); }
   1167 	inline bool channel_oob(long c) const { return (c < 0 || c >= channels); }
   1168 	inline bool channel_inbounds(long c) const { return !channel_oob(c); }
   1169 
   1170 	// Indexing strategies:
   1171 	// [0..1] -> [0..(dim-1)]
   1172 	inline t_sample phase2index(t_sample phase) const { return phase * t_sample(dim-1); }
   1173 	// [0..1] -> [min..max]
   1174 	inline t_sample subphase2index(t_sample phase, long min, long max) const {
   1175 		min = index_clamp(min);
   1176 		max = index_clamp(max);
   1177 		return t_sample(min) + phase * t_sample(max-min);
   1178 	}
   1179 	// [-1..1] -> [0..(dim-1)]
   1180 	inline t_sample signal2index(t_sample signal) const { return phase2index((signal+t_sample(1.)) * t_sample(0.5)); }
   1181 
   1182 	inline T peek(t_sample index, long channel=0) const {
   1183 		const long i = (long)index;
   1184 		if (index_oob(i) || channel_oob(channel)) {
   1185 			return 0.;
   1186 		} else {
   1187 			return read(i, channel);
   1188 		}
   1189 	}
   1190 
   1191 	inline T index(t_sample index, long channel=0) const {
   1192 		channel = channel_clamp(channel);
   1193 		// no-interp:
   1194 		long i = (long)index;
   1195 		// bound:
   1196 		i = index_clamp(i);
   1197 		return read(i, channel);
   1198 	}
   1199 
   1200 	inline T cell(t_sample index, long channel=0) const {
   1201 		channel = channel_clamp(channel);
   1202 		// no-interp:
   1203 		long i = (long)index;
   1204 		// bound:
   1205 		i = index_wrap(i);
   1206 		return read(i, channel);
   1207 	}
   1208 
   1209 	inline T cycle(t_sample phase, long channel=0) const {
   1210 		channel = channel_clamp(channel);
   1211 		t_sample index = phase2index(phase);
   1212 		// interp:
   1213 		long i1 = (long)index;
   1214 		long i2 = i1+1;
   1215 		const t_sample alpha = index - (t_sample)i1;
   1216 		// bound:
   1217 		i1 = index_wrap(i1);
   1218 		i2 = index_wrap(i2);
   1219 		// interp:
   1220 		T v1 = read(i1, channel);
   1221 		T v2 = read(i2, channel);
   1222 		return mix(v1, v2, alpha);
   1223 	}
   1224 
   1225 	inline T lookup(t_sample signal, long channel=0) const {
   1226 		channel = channel_clamp(channel);
   1227 		t_sample index = signal2index(signal);
   1228 		// interp:
   1229 		long i1 = (long)index;
   1230 		long i2 = i1+1;
   1231 		t_sample alpha = index - (t_sample)i1;
   1232 		// bound:
   1233 		i1 = index_clamp(i1);
   1234 		i2 = index_clamp(i2);
   1235 		// interp:
   1236 		T v1 = read(i1, channel);
   1237 		T v2 = read(i2, channel);
   1238 		return mix(v1, v2, alpha);
   1239 	}
   1240 	// NO LONGER USED:
   1241 	inline void poke(t_sample value, t_sample index, long channel=0) {
   1242 		const long i = (long)index;
   1243 		if (!(index_oob(i) || channel_oob(channel))) {
   1244 			write(fixdenorm(value), i, channel);
   1245 		}
   1246 	}
   1247 	// NO LONGER USED:
   1248 	inline void splat_adding(t_sample value, t_sample phase, long channel=0) {
   1249 		const t_sample valuef = fixdenorm(value);
   1250 		channel = channel_clamp(channel);
   1251 		t_sample index = phase2index(phase);
   1252 		// interp:
   1253 		long i1 = (long)index;
   1254 		long i2 = i1+1;
   1255 		const t_sample alpha = index - (t_sample)i1;
   1256 		// bound:
   1257 		i1 = index_wrap(i1);
   1258 		i2 = index_wrap(i2);
   1259 		// interp:
   1260 		overdub(valuef*(1.-alpha), i1, channel);
   1261 		overdub(valuef*alpha,      i2, channel);
   1262 	}
   1263 	// NO LONGER USED:
   1264 	inline void splat(t_sample value, t_sample phase, long channel=0) {
   1265 		const t_sample valuef = fixdenorm(value);
   1266 		channel = channel_clamp(channel);
   1267 		t_sample index = phase2index(phase);
   1268 		// interp:
   1269 		long i1 = (long)index;
   1270 		long i2 = i1+1;
   1271 		const t_sample alpha = index - (t_sample)i1;
   1272 		// bound:
   1273 		i1 = index_wrap(i1);
   1274 		i2 = index_wrap(i2);
   1275 		// interp:
   1276 		const T v1 = read(i1, channel);
   1277 		const T v2 = read(i2, channel);
   1278 		write(v1 + (1.-alpha)*(valuef-v1), i1, channel);
   1279 		write(v2 + (alpha)*(valuef-v2), i2, channel);
   1280 	}
   1281 };
   1282 
   1283 // DATA_MAXIMUM_ELEMENTS * 8 bytes = 256 mb limit
   1284 #define DATA_MAXIMUM_ELEMENTS	(33554432)
   1285 
   1286 struct Data : public DataInterface<t_sample> {
   1287 	t_genlib_data * dataRef;	// a pointer to some external source of the data
   1288 
   1289 	Data() : DataInterface<t_sample>() {
   1290 		dataRef = 0;
   1291 	}
   1292 	~Data() {
   1293 		//genlib_report_message("releasing data handle %d", dataRef);
   1294 		if (dataRef != 0) {
   1295 			genlib_data_release(dataRef);
   1296 		}
   1297 	}
   1298 	void reset(const char * name, long s, long c) {
   1299 		// if needed, acquire the Data's global reference:
   1300 		if (dataRef == 0) {
   1301 			void *ref = genlib_obtain_reference_from_string(name);
   1302 			dataRef = genlib_obtain_data_from_reference(ref);
   1303 			if (dataRef == 0) {
   1304 				genlib_report_error("failed to acquire data");
   1305 				return;
   1306 			}
   1307 		}
   1308 		genlib_data_resize(dataRef, s, c);
   1309 		getinfo();
   1310 	}
   1311 	bool setbuffer(void *bufferRef) {
   1312 		//genlib_report_message("set buffer %p", bufferRef);
   1313 		if (dataRef == 0) {
   1314 			// error: no data, or obtain?
   1315 			return false;
   1316 		}
   1317 		genlib_data_setbuffer(dataRef, bufferRef);
   1318 		getinfo();
   1319 		return true;
   1320 	}
   1321 
   1322 	void getinfo() {
   1323 		t_genlib_data_info info;
   1324 		if (genlib_data_getinfo(dataRef, &info) == GENLIB_ERR_NONE) {
   1325 			mData = info.data;
   1326 			dim = info.dim;
   1327 			channels = info.channels;
   1328 		} else {
   1329 			genlib_report_error("failed to acquire data info");
   1330 		}
   1331 	}
   1332 };
   1333 
   1334 // Used by SineData
   1335 struct DataLocal : public DataInterface<t_sample> {
   1336 	DataLocal() : DataInterface<t_sample>() {}
   1337 	~DataLocal() {
   1338 		if (mData) sysmem_freeptr(mData);
   1339 		mData = 0;
   1340 	}
   1341 
   1342 	void reset(long s, long c) {
   1343 		mData=0;
   1344 		resize(s, c);
   1345 	}
   1346 
   1347 	void resize(long s, long c) {
   1348 		if (s * c > DATA_MAXIMUM_ELEMENTS) {
   1349 			s = DATA_MAXIMUM_ELEMENTS/c;
   1350 			genlib_report_message("warning: resizing data to < 256MB");
   1351 		}
   1352 		if (mData) {
   1353 			sysmem_resizeptr(mData, sizeof(t_sample) * s * c);
   1354 		} else {
   1355 			mData = (t_sample *)sysmem_newptr(sizeof(t_sample) * s * c);
   1356 		}
   1357 		if (!mData) {
   1358 			genlib_report_error("out of memory");
   1359 			resize(512, 1);
   1360 			return;
   1361 		} else {
   1362 			dim = s;
   1363 			channels = c;
   1364 		}
   1365 		set_zero64(mData, dim * channels);
   1366 	}
   1367 
   1368 	// copy from a buffer~
   1369 	// resizing is safe only during initialization!
   1370 	bool setbuffer(void *dataReference) {
   1371 		mDataReference = dataReference; // replaced mName
   1372 		bool result = false;
   1373 		t_genlib_buffer *b;
   1374 		t_genlib_buffer_info info;
   1375 		if (mDataReference != 0) {
   1376 			b = (t_genlib_buffer *)genlib_obtain_buffer_from_reference(mDataReference);
   1377 			if (b) {
   1378 				if (genlib_buffer_edit_begin(b)==GENLIB_ERR_NONE) {
   1379 					if (genlib_buffer_getinfo(b, &info)==GENLIB_ERR_NONE) {
   1380 						float *samples = info.b_samples;
   1381 						long frames = info.b_frames;
   1382 						long nchans = info.b_nchans;
   1383 						//long size = info.b_size;
   1384 						//long modtime = info.b_modtime;	// cache & compare?
   1385 
   1386 						// resizing is safe only during initialization!
   1387 						if (mData == 0) resize(frames, nchans);
   1388 
   1389 						long frames_safe = frames < dim ? frames : dim;
   1390 						long channels_safe = nchans < channels ? nchans : channels;
   1391 						// copy:
   1392 						for (int f=0; f<frames_safe; f++) {
   1393 							for (int c=0; c<channels_safe; c++) {
   1394 								t_sample value = samples[c+f*nchans];
   1395 								write(value, f, c);
   1396 							}
   1397 						}
   1398 						result = true;
   1399 					} else {
   1400 						genlib_report_message("couldn't get info for buffer\n");
   1401 					}
   1402 					genlib_buffer_edit_end(b, 1);
   1403 				} else {
   1404 					genlib_report_message("buffer locked\n");
   1405 				}
   1406 			}
   1407 		} else {
   1408 			genlib_report_message("buffer reference not valid");
   1409 		}
   1410 		return result;
   1411 	}
   1412 };
   1413 
   1414 struct Buffer : public DataInterface<float> {
   1415 	t_genlib_buffer* mBuf;
   1416 	t_genlib_buffer_info mInfo;
   1417 	float mDummy;		// safe access in case buffer is not valid
   1418 
   1419 	Buffer() : DataInterface<float>() {}
   1420 
   1421 	void reset(const char *name) {
   1422 		dim = 1;
   1423 		channels = 1;
   1424 		mData = &mDummy;
   1425 		mDummy = 0.f;
   1426 		mBuf = 0;
   1427 
   1428 		// call into genlib:
   1429 		mDataReference = genlib_obtain_reference_from_string(name);
   1430 	}
   1431 
   1432 	void setbuffer(void *ref) {
   1433 		mDataReference = ref;
   1434 	}
   1435 
   1436 	void begin() {
   1437 		t_genlib_buffer *b = genlib_obtain_buffer_from_reference(mDataReference);
   1438 		mBuf = 0;
   1439 		if (b) {
   1440 			if (genlib_buffer_perform_begin(b) == GENLIB_ERR_NONE) {
   1441 				mBuf = b;
   1442 			} else {
   1443 				//genlib_report_message ("not a buffer~ %s", mName->s_name);
   1444 			}
   1445 		} else {
   1446 			//genlib_report_message("no object %s\n", mName->s_name);
   1447 		}
   1448 
   1449 		if (mBuf && genlib_buffer_getinfo(mBuf, &mInfo)==GENLIB_ERR_NONE) {
   1450 			// grab data:
   1451 			mBuf = b;
   1452 			mData = mInfo.b_samples;
   1453 			dim = mInfo.b_frames;
   1454 			channels = mInfo.b_nchans;
   1455 		} else {
   1456 			//genlib_report_message("couldn't get info");
   1457 			mBuf = 0;
   1458 			mData = &mDummy;
   1459 			dim = 1;
   1460 			channels = 1;
   1461 		}
   1462 	}
   1463 
   1464 	void end() {
   1465 		if (mBuf) {
   1466 			genlib_buffer_perform_end(mBuf);
   1467 			if (modified) {
   1468 				genlib_buffer_dirty(mBuf);
   1469 			}
   1470 			modified = 0;
   1471 		}
   1472 		mBuf = 0;
   1473 	}
   1474 };
   1475 
   1476 struct SineData : public DataLocal {
   1477 	SineData() : DataLocal() {
   1478 		const int costable_size = 1 << 14;	// 14 bit index (noise floor at around -156 dB)
   1479 		mData = 0;
   1480 		resize(costable_size, 1);
   1481 		for (int i=0; i<dim; i++) {
   1482 			mData[i] = t_sample(cos(i * GENLIB_PI * 2. / (t_sample)(dim)));
   1483 		}
   1484 	}
   1485 
   1486 	~SineData() {
   1487 		if (mData) sysmem_freeptr(mData);
   1488 		mData = 0;
   1489 	}
   1490 };
   1491 
   1492 template<typename T>
   1493 inline int dim(const T& data) { return data.dim; }
   1494 
   1495 template<typename T>
   1496 inline int channels(const T& data) { return data.channels; }
   1497 
   1498 // used by cycle when no buffer/data is specified:
   1499 struct SineCycle {
   1500 
   1501 	uint32_t phasei, pincr;
   1502 	t_sample f2i;
   1503 
   1504 	void reset(t_sample samplerate, t_sample init = 0) {
   1505 		phasei = uint32_t(init * t_sample(4294967296.0));
   1506 		pincr = 0;
   1507 		f2i = t_sample(4294967296.0) / samplerate;
   1508 	}
   1509 
   1510 	inline void freq(t_sample f) {
   1511 		pincr = uint32_t(f * f2i);
   1512 	}
   1513 
   1514 	inline void phase(t_sample f) {
   1515 		phasei = uint32_t(f * t_sample(4294967296.0));
   1516 	}
   1517 
   1518 	inline t_sample phase() const {
   1519 		return t_sample(phasei * t_sample(0.232830643653869629e-9));
   1520 	}
   1521 
   1522 	template<typename T>
   1523 	inline t_sample operator()(const DataInterface<T>& buf) {
   1524 		T *data = buf.mData;
   1525 		// divide uint32_t range down to buffer size (32-bit to 14-bit)
   1526 		uint32_t idx = phasei >> 18;
   1527 		// compute fractional portion and divide by 18-bit range
   1528 		const t_sample frac = t_sample(phasei & 262143) * t_sample(3.81471181759574e-6);
   1529 		// index safely in 14-bit range:
   1530 		const t_sample y0 = data[idx];
   1531 		const t_sample y1 = data[(idx+1) & 16383];
   1532 		const t_sample y = linear_interp(frac, y0, y1);
   1533 		phasei += pincr;
   1534 		return y;
   1535 	}
   1536 };
   1537 
   1538 #endif
   1539