#ifndef GAMMA_OSCILLATOR_H_INC
#define GAMMA_OSCILLATOR_H_INC

/*	Gamma - Generic processing library
	See COPYRIGHT file for authors and license information */

#include <functional> // std::function
#include "Gamma/gen.h"
#include "Gamma/scl.h"
#include "Gamma/tbl.h"
#include "Gamma/Strategy.h"
#include "Gamma/Domain.h"
#include "Gamma/Types.h"

namespace gam{

/// Periodic waveforms to be used as sound or modulation sources

/// \defgroup Oscillator


/// Fixed-point phase accumulator

/// This is a linear phase accumulator that uses integer (fixed-point) 
/// arithmetic. The advantage of using fixed-point versus floating-point is that
/// the phase is wrapped automatically when the integer overflows. As long as
/// we used unsigned integers, this wrapping behavior is well-defined--all 
/// results of addition are taken modulo the maximum size of the integer.
/// The frequency resolution is SR/2^32. For SR=44100 Hz, this equates to
/// a frequency resolution of ~10^-5 Hz which has a period of ~27 hours.
///
/// \tparam Sp	Phase increment strategy (e.g., phsInc::Loop, phsInc::Oneshot)
/// \tparam Td	Domain type
/// \ingroup Oscillator
template <class Sp = phsInc::Loop, class Td = GAM_DEFAULT_DOMAIN>
class Accum : public Td {
public:

	/// \param[in] frq		Frequency
	/// \param[in] phs		Phase in [0, 1)
	Accum(float frq=440, float phs=0);


	void freq(float v);				///< Set frequency
	void freqI(uint32_t v);			///< Set fixed-point frequency
	void freqAdd(float v);			///< Add value to frequency for 1 sample
	void freqMul(float v);			///< Multiply frequency by value for 1 sample
	void phase(float v);			///< Set phase from [0, 1) of one period
	void phaseMax();				///< Set phase to maximum value
	void phaseAdd(float v);			///< Add value to phase [0, 1)
	void period(float v);			///< Set period length

	void reset(){ mPhaseI=0; mSp.reset(); }	///< Reset phase accumulator
	void finish(){ phaseMax(); }	///< Set phase to end (maximum value)

	Sp& phsInc(){ return mSp; }		///< Get phase increment strategy

	bool done() const;				///< Returns true if done cycling
	bool cycled() const;			///< Returns whether phase cycled on last iteration

	float freq() const;				///< Get frequency
	uint32_t freqI() const;			///< Get fixed-point frequency
	float freqUnit() const;			///< Get frequency in [0, 1)
	float period() const;			///< Get period
	float phase() const;			///< Get phase in [0, 1)
	uint32_t phaseI() const;		///< Get fixed-point phase

	/// Iterates accumulator; \returns true on phase wrap, false otherwise
	bool operator()();

	uint32_t nextPhase();			///< Increment phase and return updated phase
	uint32_t nextPhase(float freqOffset);
	uint32_t cycles();				///< Get 1 to 0 transitions of all accumulator bits
	bool cycle();
	bool once();

	/// Returns sequence of 32 triggers based on a pattern of bits

	/// The 5 MSBs of the phase are used to determine how much to right
	/// bit-shift the pattern value to check its bit.
	/// This means we get a pattern of 32 triggers over one oscillation period.
	/// If the oscillation frequency is positive then the pattern bits are
	/// scanned from the LSB (bit 0) to the MSB (bit 31). If the frequency is
	/// negative, then the bits are scanned (perhaps more intuitively) from the 
	/// MSB to the LSB.
	/// The following shows all 4-bit patterns made from hex values:
	///\verbatim
	///		hex pattern		hex	pattern		hex pattern		hex pattern
	///		0	. . . .		4	. / . .		8	/ . . .		c	/ / . .
	///		1	. . . /		5	. / . /		9	/ . . /		d	/ / . /
	///		2	. . / .		6	. / / .		a	/ . / .		e	/ / / .
	///		3	. . / /		7	. / / /		b	/ . / /		f	/ / / /			\endverbatim
	bool seq(uint32_t pattern);

	void onDomainChange(double r);

//protected:
private:
	float mFreq;		// Current frequency
	double mFreqToInt;
	uint32_t mPhaseI;	// Current fixed-point phase in [0, 2^32)
	uint32_t mFreqI;	// Current fixed-point frequency
	Sp mSp;

	uint32_t mapFreq(float v) const;
};

#define ACCUM_INHERIT\
	using Accum<Sp,Td>::phaseI;\
	using Accum<Sp,Td>::freqI;\
	using Accum<Sp,Td>::nextPhase;


/// Linear sweep in interval [0,1)

/// \tparam Sp	Phase increment strategy (e.g., phsInc::Loop, phsInc::Oneshot)
/// \tparam Td	Domain type
///\ingroup Oscillator
template <class Sp = phsInc::Loop, class Td = GAM_DEFAULT_DOMAIN>
class Sweep : public Accum<Sp, Td> {
public:
	/// \param[in] frq		Frequency
	/// \param[in] phs		Phase in [0,1)
	Sweep(float frq=440, float phs=0)
	:	Accum<Sp, Td>(frq, phs){}

	float operator()(){
		float r = this->phase();
		this->nextPhase();
		return r;
	}
};


/// Floating-point phase accumulator with output in [-A, A)

/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
///\ingroup Oscillator
template <class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
class AccumPhase : public Td{
public:
	/// \param[in] frq		Frequency
	/// \param[in] phs		Phase in [0, 1)
	/// \param[in] radius	Output range in [-radius, radius)
	AccumPhase(Tv frq=440, Tv phs=0, Tv rad=M_PI);

	
	/// Generate next sample. Stored phase is post-incremented.
	Tv nextPhase();
	
	/// Generate next sample with a frequency offset
	Tv nextPhase(Tv frqOffset);

	void freq(Tv v);		///< Set frequency
	void freqAdd(Tv v);		///< Add value to frequency for 1 sample
	void freqMul(Tv v);		///< Multiply frequency by value for 1 sample
	void period(Tv v);		///< Set period length
	void phase(Tv v);		///< Set phase from [0, 1) of one period
	void phaseAdd(Tv v);	///< Add value to unit phase
	void radius(Tv v);		///< Set output range to be in [-radius, radius)
	
	Tv freq() const;		///< Get frequency
	Tv freqUnit() const;	///< Get frequency in [0, 1)
	Tv period() const;		///< Get period
	Tv phase() const ;		///< Get normalized phase in [0, 1)
	Tv radius() const;		///< Get radius of output
	
	void onDomainChange(double r);
	void print(FILE * fp = stdout, const char * append = "\n");
	
protected:
	Tv mInc, mPhase, mRadius;
	Tv mFreqToInc;
	void recache();
	Tv mapFreq(Tv v) const;
	Tv mapPhase(Tv v) const;
	Tv nextPhaseUsing(Tv frq);
};



/// Tabulated function oscillator

/// This generator produces a periodic signal by reading values from a table.
/// Its advantage over other types of waveform generators is that it can
/// produce arbitrary periodic waveforms with a fixed computational cost. Its
/// main weakness is lack of parametric control over the waveform timbre.
/// This generator is named after the generator of the same name in the MUSIC
/// series of compilers. [Mathews, M. (1969). The Technology of Computer Music. 
/// The M.I.T. Press, Boston.]
///
/// \tparam Tv	Table element type
/// \tparam Si	Interpolation strategy
/// \tparam Sp	Phase increment strategy
/// \tparam Td	Domain type
/// \ingroup Oscillator Envelope
/// \sa Other ways to synthesize sine waves: TableSine, CSine, LFO, Sine, SineR
/// \sa Functions for building waveforms in tables with additive synthesis: 
///		addSine, addSines, addSinesPow, addWave
template<
	class Tv = gam::real,
	template<class> class Si = ipl::Linear,
	class Sp = phsInc::Loop,
	class Td = GAM_DEFAULT_DOMAIN
>
class Osc : public Accum<Sp,Td>, public ArrayPow2<Tv>{
public:

	/// Default constructor does not allocate table memory
	Osc()
	:	ArrayPow2<Tv>(defaultArray<Tv>(), 1)
	{}

	/// Constructor that allocates an internal table

	/// \param[in]	frq			Frequency
	/// \param[in]	phs			Phase in [0, 1)
	/// \param[in]	size		Size of table (actual number is power of 2 ceiling)
	Osc(float frq, float phs=0, uint32_t size=512)
	:	Accum<Sp,Td>(frq, phs), ArrayPow2<Tv>(size, Tv())
	{}

	/// Constructor that references an external table

	/// \param[in]	frq			Frequency
	/// \param[in]	phs			Phase in [0, 1)
	/// \param[in]	src			A table to use as a reference
	Osc(float frq, float phs, ArrayPow2<Tv>& src)
	:	Accum<Sp,Td>(frq, phs), ArrayPow2<Tv>(src.elems(), src.size())
	{}


	/// Generate next sample
	Tv operator()(){
		Tv r = val();
		this->nextPhase();
		return r;
	}

	/// Get current value
	Tv val() const { return atPhaseI(this->phaseI()); }

	/// Get table value at fixed-point phase
	Tv atPhaseI(uint32_t v) const { return mIpol(table(), v); }
	
	/// Add sine to table
	
	/// \param[in] cycles	number of cycles
	/// \param[in] amp		amplitude
	/// \param[in] phs		unit phase, [0, 1)
	Osc& addSine(double cycles, double amp=1, double phs=0){
		double f = cycles/this->size();
		for(unsigned i=0; i<this->size(); ++i){
			double p = (f*i + phs)*M_2PI;
			(*this)[i] += sin(p) * amp;
		}
		return *this;
	}

	/// Get reference to table
	ArrayPow2<Tv>& table(){ return *this; }
	const ArrayPow2<Tv>& table() const { return *this; }

protected:
	Si<Tv> mIpol;
};



/// Complex sinusoid oscillator

/// This oscillator outputs a (decaying) complex sinusoid whose real and
/// imaginary components correspond to a cosine and sine wave, respectively.
/// The complex sinusoid is generated by recursively multiplying two complex
/// numbers and thus requires only four multiplications and two additions per
/// iteration. One disadvantage of this oscillator is that it is expensive to
/// change its frequency. Another is that the amplitude may drift over time.
/// This, however, can be mostly resolved by using double precision.
///
/// Reference: Mathews, M., Smith, J. 2003. "Methods for synthesizing very high
/// Q parametrically well behaved two pole filters."
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
///  \sa Osc, TableSine, CSine, LFO, Sine, SineR
template<class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
class CSine : public Td{
public:

	typedef Complex<Tv> complex;

	/// \param[in] frq		Frequency
	/// \param[in] amp		Amplitude
	/// \param[in] dcy		-60 dB decay length (negative for no decay)
	/// \param[in] phs		Phase in [0, 1)
	CSine(Tv frq=440, Tv amp=1, Tv dcy=-1, Tv phs=0);


	complex val;				///< Current value

	complex operator()();		///< Generate next sample

	void amp(Tv v);				///< Set amplitude
	void decay(Tv v);			///< Set -60 dB decay length (negative for no decay)
	void freq(Tv v);			///< Set frequency
	void freq(complex v){ mInc=v; }
	void phase(Tv v);			///< Set unit phase, in [0,1]
	void reset();				///< Reset amplitude and set phase to 0
	void set(Tv frq, Tv phs, Tv amp, Tv dcy);

	Tv amp() const {return mAmp;}		///< Get amplitude
	Tv decay() const {return mDcy60;}	///< Get decay length
	Tv freq() const {return mFreq;}		///< Get frequency

	void onDomainChange(double r);

protected:
	Tv mAmp, mFreq, mDcy60;
	Tv mDcy;			// phasor amp
	complex mInc;		// rotation increment
};



/// Computed sine wave oscillator.

/// This oscillator uses a polynomial approximation to compute sine values. 
/// Computation time is about as much as a linearly-interpolating table lookup.
/// In addition, polynomial approximations are often more spectrally pure than 
/// table lookup methods since the distortion arises as harmonics.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
/// \sa Osc, TableSine, CSine, LFO, SineR
template<class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
class Sine : public AccumPhase<Tv,Td> {
public:
	/// \param[in]	frq		Frequency
	/// \param[in]	phs		Phase in [0, 1)
	Sine(Tv frq=440, Tv phs=0) : AccumPhase<Tv,Td>(frq, phs, Tv(1)){}

	/// Generate next sample with a frequency offset
	Tv operator()(Tv frqOffset = Tv(0)){
		//return ::sin(this->nextPhase(frqOffset)/*M_PI*/); // 260%
		//return scl::sinT7(this->nextPhase(frqOffset)/*M_PI*/); // 140%
		return scl::sinP9(this->nextPhase(frqOffset)); // 110%
		//return scl::sinP7(this->nextPhase(frqOffset)); // 100%
		//return scl::sinFast(this->nextPhase(frqOffset)/*M_PI*/); // 95%
	}
};



/// Sine oscillator based on an efficient recursion equation.

/// This oscillator is based on a recursion equation requiring only one
/// multiply and add per sample computation. While computation time and quality
/// are near ideal, parameter updates are expensive and 64-bit precision is
/// required to prevent growing or decaying in amplitude over time.  This
/// generator is ideal in situations where a stationary sinusoid is all that is
/// required, e.g. a grain or modulator.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
/// \sa Osc, TableSine, CSine, LFO, Sine, SineRs (Synthesizes multiple sines)
template <class Tv = double, class Td = GAM_DEFAULT_DOMAIN>
class SineR : public gen::RSin<Tv>, Td{
public:

	/// \param[in]	frq		Frequency
	/// \param[in]	amp		Amplitude
	/// \param[in]	phs		Phase in [0, 1)
	SineR(Tv frq=440, Tv amp=1, Tv phs=0){ set(frq, amp, phs); }

	/// Get frequency
	Tv freq() const { return Base::freq() * Td::spu(); }

	/// Set amplitude and phase
	void ampPhase(Tv a=1, Tv p=0){ set(freq(), a, p); }

	/// Set frequency
	void freq(Tv v){ Base::freq(v*Td::ups()); }

	/// Set period
	void period(Tv v){ Base::freq(Td::ups()/v); }

	/// Set all control parameters
	void set(Tv frq, Tv amp, Tv phs=0){ Base::set(frq*Td::ups(), amp, phs); }


	void onDomainChange(double ratio){ Base::freq(Base::freq()/ratio); }

private:
	typedef gen::RSin<Tv> Base;
};



/// Multiple SineRs

/// This is a dynamically-sized bank of SineR objects.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
/// \sa SineR (synthesizes a single sine)
template <class Tv = double, class Td = GAM_DEFAULT_DOMAIN>
class SineRs : public Array<SineR<Tv, Domain1> >, Td{
public:

	SineRs(){}

	/// \param[in]	num		Number of resonators
	SineRs(unsigned num): Base(num){ onDomainChange(1); }

	/// Generate next sum of all oscillators
	Tv operator()(){
		Tv r = Tv(0);
		for(unsigned i=0; i<this->size(); ++i) r += (*this)[i]();
		return r;
	}

	/// Get last output of oscillator i
	Tv last(unsigned i) const { return (*this)[i].val; }

	/// Set all control parameters of oscillator i
	void set(unsigned i, Tv frq, Tv amp=1, Tv phs=0){
		(*this)[i].set(frq*Td::ups(), amp, phs);
	}


	void onDomainChange(double ratio){
		for(unsigned i=0; i<this->size(); ++i){
			(*this)[i].onDomainChange(ratio);
		}
	}
private:
	typedef Array<SineR<Tv, Domain1> > Base;
};



/// Damped sine oscillator based on an efficient recursion equation.

/// This oscillator is similar to SineR, however, it has an extra multiply
/// in its sample generation to allow the oscillator to decay.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
/// \sa SineR, SineDs
template <class Tv = double, class Td = GAM_DEFAULT_DOMAIN>
class SineD : public gen::RSin2<Tv>, Td{
public:

	/// \param[in]	frq		Frequency
	/// \param[in]	amp		Amplitude
	/// \param[in]	dcy		T60 decay length (negative == no decay)
	/// \param[in]	phs		Phase in [0, 1)
	SineD(Tv frq=440, Tv amp=1, Tv dcy=-1, Tv phs=0)
	{ set(frq, amp, dcy, phs); }


	/// Get frequency
	Tv freq() const { return Base::freq() * Td::spu(); }

	/// Set amplitude and phase
	void ampPhase(Tv a=1, Tv p=0){ set(freq(), a, Base::decay(), p); }

	/// Set decay length
	void decay(Tv v){ Base::decay(decayFactor(v)); }

	/// Set frequency
	void freq(Tv v){ Base::freq(v*Td::ups()); }

	/// Set period
	void period(Tv v){ Base::freq(Td::ups()/v); }

	/// Set all control parameters

	/// \param[in]	frq		Frequency
	/// \param[in]	amp		Amplitude
	/// \param[in]	dcy		T60 decay length (negative == no decay)
	/// \param[in]	phs		Phase in [0, 1)
	void set(Tv frq, Tv amp, Tv dcy, Tv phs=0){
		Base::set(
			frq * Td::ups(),
			amp,
			decayFactor(dcy),
			phs
		);
	}

	void onDomainChange(double ratio){
		Base::freq(Base::freq()/ratio);
		//printf("%g\n", Base::decay());
		//printf("%g %g %g\n", Base::decay(), ratio, ::pow(Base::decay(), 1./ratio));
		// double radius60(double dcy, double ups){ return ::exp(M_LN001/dcy * ups); }
		//		same as (0.001)^(ups/dcy)
		Base::decay(::pow(Base::decay(), 1./ratio));
	}

private:
	typedef gen::RSin2<Tv> Base;
	Tv decayFactor(Tv length){
		return length > Tv(0) ? Tv(scl::radius60(length, Td::ups())) : Tv(1);
	}
};



/// Multiple SineDs

/// This is a dynamically-sized bank of SineD objects.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator
/// \sa SineD
template <class Tv = double, class Td = GAM_DEFAULT_DOMAIN>
class SineDs : public Array<SineD<Tv, Domain1> >, Td{
public:

	SineDs(){}

	/// \param[in]	num		Number of resonators
	SineDs(unsigned num): Base(num){
		onDomainChange(1);
		for(unsigned i=0; i<num; ++i) set(i, 0,0,0);
	}


	/// Generate next sum of all oscillators
	Tv operator()(){
		Tv r=Tv(0);
		for(unsigned j=0; j<this->size(); ++j) r+=(*this)[j]();
		return r;
	}

	/// Get last output of oscillator i
	Tv last(unsigned i) const { return (*this)[i].val; }

	/// Set all control parameters of oscillator i

	/// \param[in] i		index of oscillator
	/// \param[in] frq		Frequency
	/// \param[in] amp		Amplitude
	/// \param[in] dcy		T60 decay length (negative == no decay)
	/// \param[in] phs		Phase in [0, 1)
	void set(unsigned i, Tv frq, Tv amp, Tv dcy, Tv phs=0){
		(*this)[i].set(frq*Td::ups(), amp, dcy*Td::spu(), phs);
	}


	void onDomainChange(double ratio){
		for(unsigned i=0; i<this->size(); ++i){
			(*this)[i].onDomainChange(ratio);
		}
	}
private:
	typedef Array<SineD<Tv, Domain1> > Base;
};



/// Swept sinusoid with Gaussian envelope

/// This generates a sinusoid with a linear frequency sweep and Gaussian
/// envelope. Only two complex multiplies are required per sample.
/// Single-precision should be used only for very short envelopes due to
/// accumulation error.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator
template<class Tv = double, class Td = GAM_DEFAULT_DOMAIN>
class Chirplet : public Td{
public:

	typedef Complex<Tv> complex;

	/// \param[in] frq1		Start frequency
	/// \param[in] frq2		End frequency
	/// \param[in] amp		Amplitude
	/// \param[in] len		Length
	/// \param[in] phs		Phase in [0, 1)
	Chirplet(Tv frq1=440, Tv frq2=880, Tv amp=1, Tv len=1, Tv phs=0){
		freq(frq1, frq2);
		this->amp(amp);
		length(len);
	}


	/// Set start and end frequencies
	Chirplet& freq(double start, double end){
		mFreq1 = start;
		mFreq2 = end;
		mRGauss.mul1.arg(freqToRad(start));
		mRGauss.mul2.arg(freqToRad(end-start)/mRGauss.length());
		//printf("(%g, %g), (%g, %g)\n", mRGauss.mul2.mag(), mRGauss.mul2.arg()/2/M_PI, mRGauss.mul1.mag(), mRGauss.mul1.arg()/2/M_PI);
		return *this;
	}

	/// Set frequency
	Chirplet& freq(double v){
		mFreq1 = v;
		mFreq2 = v;
		mRGauss.mul1.arg(freqToRad(v));
		mRGauss.mul2.arg(0);
		return *this;
	}

	/// Set envelope length
	Chirplet& length(double v, const complex& offset=complex(0.01)){
		mLength = v;
		mRGauss.set(v*Td::spu(), offset);
		return *this;
	}

	/// Set amplitude
	Chirplet& amp(double v){
		mRGauss.mul1.mag(v);
		return *this;
	}

	/// Get next sample
	complex operator()(){
		return mRGauss();
	}

	/// Reset envelope
	Chirplet& reset(){ return length(mLength); }

	/// Returns true if envelope done
	bool done(float thresh=0.001) const { return mRGauss.done(); }

	/// Get length
	Tv length() const { return mLength; }

	void onDomainChange(double r){
		//Tv A = mRGauss.mul1.mag();
		length(mLength);
		freq(mFreq1, mFreq2);
		//amp(A);
	}

protected:
	gen::RGauss<complex> mRGauss;
	Tv mFreq1, mFreq2, mLength;
	double freqToRad(double v){ return v * 2*M_PI*Td::ups(); }
};



/// Low-frequency oscillator

/// This object generates various waveform types by mapping the output of a 
/// an accumulator through mathematical functions. The resulting waveforms are
/// non-band-limited.
///
/// \tparam Sp	Phase increment strategy (e.g., phsInc::Loop, phsInc::Oneshot)
/// \tparam Td	Domain type
/// \ingroup Oscillator 
/// \sa Osc, TableSine, CSine, Sine, SineR
template <class Sp = phsInc::Loop, class Td = GAM_DEFAULT_DOMAIN>
class LFO : public Accum<Sp,Td>{
public:

	LFO();
	
	/// \param[in] frq		Frequency
	/// \param[in] phase	Phase in [0, 1)
	/// \param[in] mod		Modifier amount in [0, 1)
	LFO(double frq, double phase=0, double mod=0.5);


	/// Set frequency, phase and modifier amount
	LFO& set(float f, float p, float m);

	LFO& mod(double n);		///< Set modifier from unit value
	LFO& modI(uint32_t v);	///< Set modifier from integer

	/// Get modifier value
	uint32_t modI() const { return mMod; }
	double mod() const { return mMod / 4294967296.; }

	float cos();		///< Cosine-like wave based on 3rd order polynomial
	float down();		///< Downward ramp (1 to -1); S1 Clausen function
	float even3();		///< Even harmonic sine-like wave (3rd order); S3 Clausen function
	float even5();		///< Even harmonic sine-like wave (5th order)
	float imp();		///< Impulse train with aliasing reduction
	float line2();		///< 2-segment line; 'mod' changes wave from down to tri to up
	float para();		///< Parabolic wave; C2 Clausen function
	float pulse();		///< Pulse (up + down). 'mod' controls pulse width
	float pulseRange(); ///< Pulse (up + down). 'mod' controls pulse width. amplitude doesn't change with mod.
	float saw(){ return down(); } ///< Saw wave (downward ramp)
	float sinPara();	///< Sine-like wave constructed from parabolas; integral of triangle
	float stair();		///< Stair (square + square). 'mod' controls pulse width
	float sqr();		///< Square (-1 to 1)
	float tri();		///< Triangle (starts at 1 goes down to -1 then up to 1)
	float up();			///< Upward ramp
	float up2();		///< Dual upward ramp (up + up). 'mod' controls pulse width.

	float S1();			///< S1 Clausen function; sum_k sin(kt)/k^1
	float C2();			///< C2 Clausen function; sum_k cos(kt)/k^2
	float S3();			///< S3 Clausen function; sum_k sin(kt)/k^3
	float C4();			///< C4 Clausen function; sum_k cos(kt)/k^4
	float S5();			///< S5 Clausen function; sum_k sin(kt)/k^5

	float cosU();		///< Unipolar cosine-like wave based on 3rd order polynomial
	float downU();		///< Unipolar downward ramp
	float hann();		///< Hann-like window based on 3rd order polynomial
	float impU();		///< Unipolar impulse train
	float line2U();		///< Unipolar line2
	float paraU();		///< Unipolar parabolic wave
	float pulseU();		///< Unipolar pulse
	float stairU();		///< Unipolar stair
	float sqrU();		///< Unipolar square
	float triU();		///< Unipolar triangle (starts at 1 going down then up)
	float upU();		///< Unipolar upward ramp
	float up2U();		///< Unipolar upward ramp2

	float patU();
	float patU(uint32_t mul);
	float sineT9();
	float sineP9();

	ACCUM_INHERIT
private:
	typedef Accum<Sp,Td> Base;
	uint32_t mMod;			// Modifier parameter
};



/// Differenced wave oscillator

/// This oscillator uses a difference between two waveforms to reduce aliasing.
/// Computation time is higher than that of an LFO unit generator, however,
/// the output exhibits far less aliasing at high frequencies.
template <class Sp = phsInc::Loop, class Td = GAM_DEFAULT_DOMAIN>
class DWO : public Accum<Sp,Td>{
public:

	DWO();
	
	/// \param[in] frq		Frequency
	/// \param[in] phase	Phase in [0, 1)
	/// \param[in] mod		Modifier amount in [0, 1)
	DWO(float frq, float phase=0, float mod=0.5);


	DWO& mod(double n);		///< Set modifier from unit value
	DWO& modI(uint32_t v);	///< Set modifier from integer

	/// Get modifier value
	uint32_t modI() const { return mMod; }
	double mod() const { return mMod / 4294967296.; }

	/// Set frequency
	void freq(float v);
	void period(float v){ freq(1.f/v); }

	float up();				///< Upward saw
	float down();			///< Downward saw
	float saw(){ return down(); } ///< Saw
	float sqr();			///< Square
	float para();			///< Parabolic
	float tri();			///< Triangle
	float pulse();			///< Pulse
	float imp();			///< Impulse train

	void onDomainChange(double r);

private:
	typedef Accum<Sp,Td> Base;
	uint32_t mMod;			// Modifier parameter
	float mGain;
	//float mPrev;
	//float diff(float v);
};



/// Sum of cosine waves

/// This produces a finite sum of harmonic, equi-amplitude cosine waves that 
/// approach the shape of a periodic impulse train. The algorithm uses a 
/// closed-form solution to the sum thus its computational complexity is always
/// O(1) (constant) regardless of the number of harmonics.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
template<class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
class Buzz : public AccumPhase<Tv,Td> {
public:

	/// \param[in]	frq			Frequency
	/// \param[in]	phase		Phase in [0, 1)
	/// \param[in]	harmonics	Number of harmonics
	Buzz(Tv frq=440, Tv phase=0, Tv harmonics=8);
	virtual ~Buzz(){}

	void antialias();			///< Adjust number of harmonics to prevent aliasing
	void harmonics(Tv num);		///< Set number of harmonics
	void harmonicsMax();		///< Set number of harmonics to fill Nyquist range
	void normalize(bool v);		///< Whether to normalize amplitude

	Tv operator()();			///< Returns next sample of all harmonic impulse
	Tv odd();					///< Returns next sample of odd harmonic impulse
	Tv saw(Tv intg=0.999);		///< Returns next sample of saw waveform
	Tv square(Tv intg=0.999);	///< Returns next sample of square waveform
	
	Tv maxHarmonics() const;	///< Get number of harmonics below Nyquist based on current settings

	void onDomainChange(double r);

protected:
	Tv mAmp;			// amplitude normalization factor
	Tv mN;				// actual number of harmonics
	Tv mNDesired;		// desired number of harmonics
	Tv mNFrac;		
	Tv mSPU_2;			// cached local
	Tv mPrev;			// previous output for integration
	bool mNormalize;
	void setAmp();
private: typedef AccumPhase<Tv,Td> Base;
};



/// Band-limited impulse train

/// This produces a Fourier representation of an impulse train where the number
/// of harmonics is adjusted automatically to prevent aliasing.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator
/// \sa Buzz
template <class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
struct Impulse : public Buzz<Tv,Td>{
public:

	/// \param[in] frq		Frequency
	/// \param[in] phs		Phase, in [0, 1)
	Impulse(Tv frq=440, Tv phs=0): Base(frq, phs){ onDomainChange(1); }

	/// Set frequency
	void freq(Tv v){ Base::freq(v); Base::harmonicsMax(); }

	void onDomainChange(double r){
		Base::onDomainChange(r);
		freq(AccumPhase<Tv,Td>::freq());
	}

	using Buzz<Tv,Td>::freq; // needed for getter

private: typedef Buzz<Tv,Td> Base;
};



/// Band-limited saw wave

/// This produces a Fourier representation of a saw wave where the number of
/// harmonics is adjusted automatically to prevent aliasing.
/// Due to numerical issues, this generator should not be used for producing 
/// very low frequency modulation signals. For that purpose, it is better to use
/// the LFO class.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
template <class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
struct Saw : public Impulse<Tv,Td> {

	/// \param[in] frq		Frequency
	/// \param[in] phs		Phase, in [0, 1)
	Saw(Tv frq=440, Tv phs=0): Impulse<Tv, Td>(frq, phs){}

	/// Generate next sample
	
	/// \param[in] itg		Leaky integration factor
	///
	Tv operator()(Tv itg=0.999){ return Impulse<Tv,Td>::saw(itg); }
};



/// Band-limited square wave

/// This produces a Fourier representation of a square wave where the number of
/// harmonics is adjusted automatically to prevent aliasing.
/// Due to numerical issues, this generator should not be used for producing 
/// very low frequency modulation signals. For that purpose, it is better to use
/// the LFO class.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
template <class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
struct Square : public Impulse<Tv,Td> {

	/// \param[in] frq		Frequency
	/// \param[in] phs		Phase, in [0, 1)
	Square(Tv frq=440, Tv phs=0) : Impulse<Tv,Td>(frq, phs){}

	/// Generate next sample
	
	/// \param[in] itg		Leaky integration factor
	///
	Tv operator()(Tv itg=0.999){ return Impulse<Tv,Td>::square(itg); }
};



/// Discrete summation formula (DSF) oscillator

/// This produces a finite sum of harmonics whose amplitudes follow a geometric
/// series. The amplitude of harmonic i is ar^i where 'ar' is called the 
/// amplitude ratio. The frequency of harmonic i is (i * fr + 1) where 'fr' is
/// called the frequency ratio. Harmonics run from i=0 (the fundamental) to
/// the maximum specified harmonic.
///
/// \tparam Tv	Value (sample) type
/// \tparam Td	Domain type
/// \ingroup Oscillator 
template<class Tv = gam::real, class Td = GAM_DEFAULT_DOMAIN>
class DSF : public AccumPhase<Tv,Td> {
public:

	/// \param[in]	frq			Frequency
	/// \param[in]	freqRatio	Frequency ratio of partials
	/// \param[in]	ampRatio	Amplitude ratio of partials
	/// \param[in]	harmonics	Number of harmonics
	DSF(Tv frq=440, Tv freqRatio=1, Tv ampRatio=0.5, Tv harmonics=8);
	
	Tv operator()();			///< Generate next sample
	
	void ampRatio(Tv v);		///< Set amplitude ratio of partials
	void antialias();			///< Adjust harmonics so partials do not alias
	void freq(Tv v);			///< Set frequency of fundamental
	void freqRatio(Tv v);		///< Set frequency ratio of partials
	void harmonics(Tv v);		///< Set number of harmonics
	void harmonicsMax();		///< Set number of harmonics to fill Nyquist range

	Tv ampRatio() const;		///< Get amplitude ratio
	Tv freqRatio() const;		///< Get frequency ratio
	Tv harmonics() const;		///< Get current number of harmonics
	Tv maxHarmonics() const;	///< Get maximum number of harmonics for current settings
	
	void onDomainChange(double r);

protected:
	typedef AccumPhase<Tv,Td> Base;

	Tv mN, mNDesired;		// actual and desired # harmonics
	Tv mFreqRatio;			// frequency ratio
	Tv mA;					// Partial amplitude ratio
	Tv mBeta, mBetaInc;		// "detune" accumulator
	Tv mAPow, mASqP1;		// cached vars
	
	void updateAPow();
	void updateBetaInc();
};



/// Upsamples and interpolates a signal

/// This interpolates between the samples of a lower-rate signal. Use cases
/// include a sample-and-hold and a low-frequency noise generator.
///
/// \tparam Gen	Signal generator
/// \tparam Si	Sequence interpolation strategy
/// \tparam Sp	Phase increment strategy
/// \tparam Td	Domain type
/// \ingroup Oscillator
template <
	class Gen = gen::Default<>,
	template <typename> class Si = iplSeq::Linear,
	class Sp = phsInc::Loop,
	class Td = GAM_DEFAULT_DOMAIN
>
class Upsample : public Accum<Sp,Td>{
public:

	typedef typename Gen::value_type value_type;

	/// \param[in] frq		Frequency of lower-rate signal
	Upsample(float frq=440)
	:	Accum<Sp,Td>(frq)
	{
		this->finish();
		mIpl.push(0);
	}

	// Upsample an external generator
	template <class SampleGen>
	value_type operator()(SampleGen& gen){
		if(this->cycle()) mIpl.push(gen());
		return mIpl(this->phase());
	}

	// Upsample an external function
	value_type operator()(const std::function<value_type(void)>& onCycle){
		if(this->cycle()) mIpl.push(onCycle());
		return mIpl(this->phase());
	}

	// Sample and interpolate a signal
	value_type operator()(value_type in){
		return (*this)(gen::Val<value_type>(in));
	}

	// Upsample internal generator
	value_type operator()(){
		return (*this)(mGen);
	}

	/// Get internal generator
	Gen& gen(){ return mGen; }

private:
	Gen mGen;
	Si<value_type> mIpl;
};



// Implementation_______________________________________________________________

namespace{

// Convert unit floating-point to fixed-point integer.
// 32-bit float is good enough here since [0.f, 1.f) uses 29 bits.
inline uint32_t mapFI(float v){
	//return scl::unitToUInt(v);
	//return (uint32_t)(v * 4294967296.);
	return castIntRound(v * 4294967296.);
}

// Convert fixed-point integer to unit floating-point.
inline double mapIF(uint32_t v){
	return v/4294967296.;
	//return uintToUnit<float>(v); // not enough precision
}

};


//---- Accum
template<class Sp, class Td>
Accum<Sp,Td>::Accum(float f, float p)
:	mFreq(f), mFreqToInt(4294967296.), mFreqI(0)
{
	onDomainChange(1);
	phase(p);
}

template<class Sp, class Td>
inline uint32_t Accum<Sp,Td>::mapFreq(float v) const {
	//return mapFI(v * Td::ups());
	return castIntRound(v * mFreqToInt);
}

template<class Sp, class Td>
void Accum<Sp,Td>::onDomainChange(double /*r*/){ //printf("Accum: onDomainChange (%p)\n", this);
	mFreqToInt = 4294967296. / Td::spu();
	freq(mFreq);
}

template<class Sp, class Td>
inline void Accum<Sp,Td>::freq(float v){
	mFreq = v;
	mFreqI= mapFreq(v);
}

template<class Sp, class Td>
inline void Accum<Sp,Td>::freqI(uint32_t v){
	mFreqI= v;
	mFreq = mapIF(v) * Td::spu();
}

template<class Sp, class Td> inline void Accum<Sp,Td>::freqAdd(float v){ phaseAdd(v*Td::ups()); }
template<class Sp, class Td> inline void Accum<Sp,Td>::freqMul(float v){ freqAdd((v-1.f)*freq()); }

template<class Sp, class Td> inline void Accum<Sp,Td>::period(float v){ freq(1.f/v); }
template<class Sp, class Td> inline void Accum<Sp,Td>::phase(float v){ mPhaseI = mapFI(v); }
template<class Sp, class Td> inline void Accum<Sp,Td>::phaseAdd(float v){ mSp(mPhaseI, mapFI(v)); }
template<class Sp, class Td> void Accum<Sp,Td>::phaseMax(){ mPhaseI = 0xffffffff; }

template<class Sp, class Td>
inline bool Accum<Sp,Td>::done() const { return mSp.done(phaseI()); }

template<class Sp, class Td>
inline bool Accum<Sp,Td>::cycled() const {
	uint32_t prev = phaseI();
	Sp temp = mSp;
	temp(prev, ~freqI());
	return ((~phaseI() & prev) & 0x80000000) != 0;
}

template<class Sp, class Td> inline float Accum<Sp,Td>::freq() const { return mFreq; }
template<class Sp, class Td> inline uint32_t Accum<Sp,Td>::freqI() const { return mFreqI; }
template<class Sp, class Td> inline float Accum<Sp,Td>::freqUnit() const { return float(mapIF(mFreqI)); }
template<class Sp, class Td> inline float Accum<Sp,Td>::period() const { return 1.f/freq(); }
template<class Sp, class Td> inline float Accum<Sp,Td>::phase() const { return float(mapIF(mPhaseI)); }
template<class Sp, class Td> inline uint32_t Accum<Sp,Td>::phaseI() const { return mPhaseI; }

template<class Sp, class Td> inline uint32_t Accum<Sp,Td>::nextPhase(float frqOffset){
	uint32_t p = mPhaseI;
	mSp(mPhaseI, mFreqI + mapFreq(frqOffset)); // apply phase inc strategy
	return p;
}

template<class Sp, class Td> inline uint32_t Accum<Sp,Td>::nextPhase(){
	uint32_t p = mPhaseI;
	mSp(mPhaseI, mFreqI); // apply phase inc strategy
	return p;
}

template<class Sp, class Td> inline bool Accum<Sp,Td>::operator()(){ return cycle(); }

template<class Sp, class Td> inline bool Accum<Sp,Td>::cycle(){ return (cycles() & 0x80000000) != 0; }

//template<class Sp, class Td> inline uint32_t Accum<Sp,Td>::cycle(uint32_t mask){
//	return cycles() & mask;
//}

template<class Sp, class Td> inline uint32_t Accum<Sp,Td>::cycles(){
	uint32_t prev = phaseI();
	nextPhase();
	return ~phaseI() & prev;
}

template<class Sp, class Td> inline bool Accum<Sp,Td>::once(){
	uint32_t prev = phaseI();
	bool c = cycle();
	if(c) mPhaseI = prev;
	return c;
}

template<class Sp, class Td> inline bool Accum<Sp,Td>::seq(uint32_t pat){
	uint32_t prev = phaseI();
	nextPhase();

	// Did any of the 5 MSBs change?
	if((phaseI() ^ prev) & 0xf8000000){
		return (pat >> (phaseI()>>27)) & 0x1;
	}
	return false;
}





//---- AccumPhase

template<class Tv, class Td>
AccumPhase<Tv, Td>::AccumPhase(Tv f, Tv p, Tv r)
:	mInc(f), mRadius(r), mFreqToInc(1)
{
	onDomainChange(1);
	this->phase(p);
}

template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::mapFreq(Tv v) const {
	return v*mFreqToInc;
}

template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::mapPhase(Tv v) const {
	return v*Tv(2)*mRadius;
}

template<class Tv, class Td>
inline Tv AccumPhase<Tv, Td>::nextPhaseUsing(Tv inc){
	mPhase = scl::wrap(mPhase, mRadius,-mRadius); // guarantees that result is in [-A, A)
	Tv r = mPhase;
	mPhase += inc;
	return r;
}

template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::nextPhase(){
	return nextPhaseUsing(mInc);
}

template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::nextPhase(Tv frqMod){
	return nextPhaseUsing(mInc + mapFreq(frqMod));
}

template<class Tv, class Td> inline void AccumPhase<Tv, Td>::freq(Tv v){ mInc = mapFreq(v); }
template<class Tv, class Td> inline void AccumPhase<Tv, Td>::freqAdd(Tv v){
	nextPhaseUsing(mapFreq(v));
}
template<class Tv, class Td> inline void AccumPhase<Tv, Td>::freqMul(Tv v){
	nextPhaseUsing((v-Tv(1))*mInc);
}
template<class Tv, class Td> inline void AccumPhase<Tv, Td>::period(Tv v){ freq(Tv(1)/v); }
template<class Tv, class Td> inline void AccumPhase<Tv, Td>::phase(Tv v){ mPhase = mapPhase(v); }
template<class Tv, class Td> inline void AccumPhase<Tv, Td>::phaseAdd(Tv v){ mPhase += mapPhase(v); }
template<class Tv, class Td> inline void AccumPhase<Tv, Td>::radius(Tv v){
	Tv f = freq();
	mRadius=v;
	recache();
	freq(f);
}

template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::freq() const { return mInc/mFreqToInc; }
template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::freqUnit() const { return freq()*this->ups(); }
template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::period() const { return Tv(1)/freq(); }
template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::phase() const { return mPhase/(Tv(2)*mRadius); }
template<class Tv, class Td> inline Tv AccumPhase<Tv, Td>::radius() const { return mRadius; }

template<class Tv, class Td> void AccumPhase<Tv, Td>::onDomainChange(double /*r*/){
	Tv f=freq();
	recache();
	freq(f);
}
template<class Tv, class Td> void AccumPhase<Tv, Td>::recache(){
	mFreqToInc = Tv(Td::ups() * Tv(2)*mRadius);
}

template<class Tv, class Td> void AccumPhase<Tv, Td>::print(FILE * fp, const char * append){
	fprintf(fp, "%f %f %f%s", freq(), phase(), mInc, append);
}


//---- CSine

template<class Tv, class Td> CSine<Tv, Td>::CSine(Tv f, Tv a, Tv dcy60, Tv p)
	: val(a, 0), mAmp(a), mFreq(f), mDcy60(dcy60)
{
	onDomainChange(1);
	this->phase(p);
}

template<class Tv, class Td> void CSine<Tv, Td>::amp(Tv v){
	if(scl::abs(mAmp) > Tv(0.000001)){
		Tv factor = v / mAmp;
		val *= factor;
	} else {
		val(v, Tv(0));
	}
	mAmp = v;
}

template<class Tv, class Td> void CSine<Tv, Td>::decay(Tv v){
	mDcy60 = v;
	mDcy = v > Tv(0) ? Tv(scl::t60(v * Td::spu())) : Tv(1);
	freq(mFreq);
}

template<class Tv, class Td> void CSine<Tv, Td>::freq(Tv v){
	mFreq = v;
	Tv phaseInc = v * Td::ups() * Tv(M_2PI);
	mInc.fromPolar(mDcy, phaseInc);
	//printf("%f %f %f %f\n", phaseInc, mDcy, c1, s1);
}

template<class Tv, class Td> void CSine<Tv, Td>::phase(Tv v){
	// set phase without changing current magnitude
	val.fromPolar(val.norm(), v*Tv(M_2PI));
}

template<class Tv, class Td> void CSine<Tv, Td>::reset(){ val(mAmp, Tv(0)); }

template<class Tv, class Td> void CSine<Tv, Td>::set(Tv frq, Tv phase, Tv amp, Tv dcy60){
	mFreq = frq;
	decay(dcy60);
	this->amp(amp);
	this->phase(phase);
}

template<class Tv, class Td> inline Complex<Tv> CSine<Tv, Td>::operator()(){
	complex c = val;
	val *= mInc;
	return c;
}

template<class Tv, class Td> void CSine<Tv, Td>::onDomainChange(double /*r*/){
	decay(mDcy60); // this sets frequency as well
}




//---- LFO
#define TLFO LFO<Sp,Td>
template<class Sp, class Td> TLFO::LFO(): Base(){ mod(0.5); }
template<class Sp, class Td> TLFO::LFO(double f, double p, double m): Base(f, p){ mod(m); }

template<class Sp, class Td> inline TLFO& TLFO::set(float f, float p, float m){
	this->freq(f);
	this->phase(p);
	return mod(m);
}
template<class Sp, class Td> inline TLFO& TLFO::mod(double v){
	return modI(castIntRound(v*4294967296.));
}
template<class Sp, class Td> inline TLFO& TLFO::modI(uint32_t v){
	mMod=v;
	return *this;
}

template<class Sp, class Td> inline float TLFO::line2(){
	uint32_t m = scl::clip<uint32_t>(mMod, 0xffefffff, 512); // avoid div by zero

	/* Starts at 1
	float r1 = scl::rampDown(phaseI());
	float r2 = scl::rampDown(phaseI() + m); //*/

	//* Starts at -1 (better for creating attack/decay like envelopes)
	float r1 = scl::rampDown(phaseI() - m);
	float r2 = scl::rampDown(phaseI()); //*/

	float p  = punUF(Expo2<float>() | (m >> 9)) - 2.f; // [0, 2);
	float r = (r1*r1 - r2*r2)/(p*(2.f - p));
	nextPhase();
	return r;
}

template<class Sp, class Td> inline float TLFO::line2U(){ return line2()*0.5f+0.5f; }

#define DEF(name, exp) template<class Sp, class Td> inline float TLFO::name{ float r = exp; return r; }
//DEF(cos(),		tri(); r *= 0.5f * r*r - 1.5f)
//DEF(cos(),		up(); r=scl::abs(r*r) )//r = -1.f - scl::pow2(2.f*r)*(scl::abs(r)-1.5f) )
DEF(cos(),		up(); r = -1.f - r*r*(4.f*scl::abs(r)-6.f) )
DEF(down(),		scl::rampDown(nextPhase()))
DEF(even3(),	up(); float c=-2.598076211353315;/*-1.50*pow(3,0.50)*/ r *= (1.f-r*r)*c;)
DEF(even5(),	up(); float c=-1.869185976526527;/*-1.25*pow(5,0.25)*/ r *= (1.f-scl::pow4(r))*c;)
DEF(imp(),		scl::pulse(nextPhase(), this->freqI()) )
DEF(para(),		paraU()*1.5f - 0.5f)
DEF(pulse(),	scl::pulse(nextPhase(), mMod))
DEF(sinPara(),	scl::sinPara(nextPhase()))
DEF(stair(),	scl::stair(nextPhase(), mMod))
DEF(sqr(),		scl::square(nextPhase()))
DEF(tri(),		scl::triangle(nextPhase()))
DEF(up(),		scl::rampUp(nextPhase()))
DEF(up2(),		scl::rampUp2(nextPhase(), mMod))
DEF(S1(),		up(); float c=          -M_PI /  2; r = c*r)
DEF(C2(),		up(); float c= scl::pow2(M_PI)/  4; r = c*(r*r - 1.f/3))
DEF(S3(),		up(); float c= scl::pow3(M_PI)/ 12; r = c*(r*r*r - r))
DEF(C4(),		up(); float c=-scl::pow4(M_PI)/ 48; float rr=r*r; r = c*(rr*(rr - 2.f) + 7.f/15))
DEF(S5(),		up(); float c=-scl::pow5(M_PI)/240; float rr=r*r; r = c*r*(rr*(rr - 10.f/3) + 7.f/3))
DEF(cosU(),		up(); r = r*r*(-2.f*scl::abs(r)+3.f))
DEF(downU(),	scl::rampDownU(nextPhase()))
//DEF(hann(),	tri(); r = r * (0.25f * r*r - 0.75f) + 0.5f)
DEF(hann(),		up(); r = 1.f + r*r*(2.f*scl::abs(r)-3.f))
DEF(impU(),		scl::pulseU(nextPhase(), this->freqI()) )
DEF(paraU(),	up(); r*=r;)
DEF(pulseU(),	scl::pulseU(nextPhase(), mMod))
DEF(pulseRange(), scl::pulseRange(nextPhase(), mMod))
DEF(sqrU(),		scl::squareU(nextPhase()))
DEF(stairU(),	scl::stairU(nextPhase(), mMod))
DEF(triU(),		scl::triangleU(nextPhase()))
DEF(upU(),		scl::rampUpU(nextPhase()))
DEF(up2U(),		scl::rampUp2U(nextPhase(), mMod))
DEF(patU(),		scl::rampUpU(nextPhase() & mMod))

DEF(patU(uint32_t mul), scl::rampUpU((nextPhase() & mMod) * mul))

/* The input domain for these is [-1,1] corresponding to [-pi,pi], but that will
give us an upside-down sine. We therefore use a downward ramp to flip the wave
on the time axis.*/
DEF(sineT9(),	down(); r = scl::sinT9(r * M_PI))
DEF(sineP9(),	down(); r = scl::sinP9(r))

#undef DEF
#undef TLFO



template <class Sp, class Td>
DWO<Sp,Td>::DWO()
//:	mPrev(0)
{
	mod(0.5);
}

template<class Sp, class Td>
DWO<Sp,Td>::DWO(float f, float p, float m)
//:	mPrev(0)
{
	freq(f);
	this->phase(p);
	mod(m);
}

template<class Sp, class Td>
inline DWO<Sp,Td>& DWO<Sp,Td>::mod(double v){
	return modI(castIntRound(v*4294967296.));
}
template<class Sp, class Td>
inline DWO<Sp,Td>& DWO<Sp,Td>::modI(uint32_t v){
	mMod=v;
	return *this;
}

template <class Sp, class Td>
inline void DWO<Sp,Td>::freq(float v){
	Base::freq(v);
	float freq1 = this->freqUnit();
	// Very low freq will produce quantization noise
	if(freq1 < 1e-5) freq1 = 1e-5;
	mGain = -0.25/freq1;
}

/* Ideally we would use a differencing filter, however, it has a serious shortcoming. Any sudden changes in phase (or frequency) will lead a large amplitude impulse in the output which becomes worse the lower the frequency. A related problem is what to initialize the filter's previous input sample to. Instead of a filter, we use an analytic approach which subtracts two phase-shifted waveforms.
*/
namespace{
	inline float para01(uint32_t p){
		float s = scl::rampUp(p);
		return s*s;
	}
	inline float triangle02(uint32_t p){
		p = Expo4<float>() | (p >> 9); // [4, 8)
		return scl::abs(punUF(p) - 6.f);
	}
}

template <class Sp, class Td>
inline float DWO<Sp,Td>::up(){
	/*
	float s = para01(this->nextPhase());
	return diff(s);//*/
	//*
	uint32_t p = this->nextPhase();
	float s = para01(p);
	float t = para01(p + this->freqI());
	return (s - t)*mGain;//*/
}

template <class Sp, class Td>
inline float DWO<Sp,Td>::down(){
	/*float s = para01(this->nextPhase());
	return diff(-s);*/
	uint32_t p = this->nextPhase();
	float s = para01(p);
	float t = para01(p + this->freqI());
	return (t - s)*mGain;
}

template <class Sp, class Td>
inline float DWO<Sp,Td>::sqr(){
	/*
	float s = triangle02(this->nextPhase());
	return diff(s);//*/
	//*
	uint32_t p = this->nextPhase();
	float s = triangle02(p);
	float t = triangle02(p + this->freqI());
	return (t - s)*mGain;//*/
}

template <class Sp, class Td>
inline float DWO<Sp,Td>::para(){
	static const float c = (-M_PI*M_PI*M_PI/12.)*0.5;
	uint32_t p = this->nextPhase();
	float s = scl::rampUp(p);
	s = s*s*s - s;
	float t = scl::rampUp(p + this->freqI());
	t = t*t*t - t;
	return (t - s)*c*mGain;
}

template <class Sp, class Td>
inline float DWO<Sp,Td>::tri(){
	/*
	float s = scl::sinPara(this->nextPhase())*0.5f;
	return diff(s);//*/
	//*
	uint32_t p = this->nextPhase();
	float s = scl::sinPara(p);
	float t = scl::sinPara(p + this->freqI());
	return (t - s)*-0.5f*mGain;//*/
}

template <class Sp, class Td>
inline float DWO<Sp,Td>::pulse(){
	/*
	uint32_t p = this->nextPhase();
	float s1 = para01(p);
	float s2 = para01(p + mMod);
	return diff((s1 - s2)*0.5f);//*/
	//*
	uint32_t p = this->nextPhase();
	float s1 = para01(p);
	float s2 = para01(p - mMod);
	float s  = s1 - s2;
	uint32_t q = p + this->freqI();
	float t1 = para01(q);
	float t2 = para01(q - mMod);
	float t  = t1 - t2;
	return (t - s)*0.5f*mGain;//*/
}

template <class Sp, class Td>
inline float DWO<Sp,Td>::imp(){
	return scl::pulse(this->nextPhase(), this->freqI());
}

/*template <class Sp, class Td>
inline float DWO<Sp,Td>::diff(float v){
	float res = (v - mPrev)*mGain;
	mPrev = v;
	return res;
}*/

template<class Sp, class Td>
void DWO<Sp,Td>::onDomainChange(double r){
	Base::onDomainChange(r);
	freq(Base::freq());
}


//---- Buzz

template<class Tv, class Td> Buzz<Tv,Td>::Buzz(Tv f, Tv p, Tv harmonics)
:	Base(f, p), mAmp(0), mPrev(Tv(0)), mNormalize(true)
{
	onDomainChange(1);
	this->harmonics(harmonics);
}

template<class Tv, class Td> inline void Buzz<Tv,Td>::harmonics(Tv v){
	mNDesired = v;
	mN = scl::floor(v);
	mNFrac = v - mN;
	setAmp();
}

template<class Tv, class Td> inline void Buzz<Tv,Td>::harmonicsMax(){
	harmonics(maxHarmonics());
}

template<class Tv, class Td> inline void Buzz<Tv,Td>::antialias(){
	Tv newN = maxHarmonics();
	newN = mNDesired > newN ? newN : mNDesired;

	mN = scl::floor(newN);
	mNFrac = newN - mN;
	setAmp();
}

template<class Tv, class Td> void Buzz<Tv,Td>::normalize(bool v){
	mNormalize = v;
	setAmp();
}

template<class Tv, class Td> inline Tv Buzz<Tv,Td>::maxHarmonics() const {
	return mSPU_2 / this->freq();
}

template<class Tv, class Td> inline void Buzz<Tv,Td>::setAmp(){

	if(mNormalize){
		// Normally, the amplitude is 1/(2N), but we will linearly interpolate
		// based on fractional harmonics to avoid sudden changes in amplitude to
		// the lower harmonics which is very noticeable.
		mAmp = (mN != Tv(0)) ? (Tv(0.5) / (mN+mNFrac)) : 0;
	}
	else{
		mAmp = Tv(0.5);
	}
}

#define EPS 0.000001
template<class Tv, class Td> inline Tv Buzz<Tv, Td>::operator()(){
	/*        1   / sin((N+0.5)x)    \
	   f(x) = -- |  ------------- - 1 |
	          2N  \   sin(0.5x)      /
	*/
	Tv theta = this->nextPhase();
	Tv result;
	Tv denom = scl::sinT7(theta * Tv(0.5));

	// denominator goes to zero when theta is an integer multiple of 2 pi
	if(scl::abs(denom) < Tv(EPS)){
		result = Tv(2) * mN * mAmp;
		//printf("Buzz::operator(): oops\n");
	}
	else{
		Tv nphase = scl::wrapPhase(theta * (mN + Tv(0.5)));
		//result = (scl::sinT7(nphase) / denom - Tv(1)) * mAmp;
		result = ((scl::sinT7(nphase) - denom) / denom) * mAmp;
	}

	//Tv fund = ((denom*denom)-0.5)*-4*mAmp;
	//result -= fund; // drop first harmonic

	// Mitigate pops when number of harmonics is changed by a small amount
	//result -= 2.f * mAmp * cos(theta * mN) * (1.f - scl::pow2(mNFrac));

	return result;
}

template<class Tv, class Td> inline Tv Buzz<Tv,Td>::odd(){
	/*        1   / sin(2N x) \
	   f(x) = -- |  ---------  |
	          2N  \   sin(x)  /
	*/
	Tv theta = this->nextPhase();
	Tv result;

	Tv n2 = scl::roundAway(mN*0.5) * 2;	
	Tv n2frac = ((mN + mNFrac) - (n2-1)); // fraction, in [0,2), btw odd harmonics

	// cos is more precise near zero-crossings
	Tv denom = scl::cosT8(scl::wrapPhaseOnce(theta - M_PI_2));
	//Tv denom = scl::sinT9(theta);
	if( scl::abs(denom) < Tv(EPS) ){
		if( theta > M_PI ) theta -= M_2PI;
		Tv A = n2 / (n2 + n2frac);
		result = (theta > -M_PI_2 && theta < M_PI_2) ? A : -A;
		//printf("Buzz::odd(): oops\n");
	}
	else result = scl::sinT7(scl::wrapPhase(n2 * theta)) / (denom * (n2 + n2frac));
	
	return result;
}
#undef EPS

template<class Tv, class Td>
inline Tv Buzz<Tv,Td>::saw(Tv b){ return mPrev=(*this)() + b*mPrev; }

template<class Tv, class Td>
inline Tv Buzz<Tv,Td>::square(Tv b){ return mPrev=odd() + b*mPrev; }

template<class Tv, class Td> void Buzz<Tv,Td>::onDomainChange(double r){
	Base::onDomainChange(r);
	mSPU_2 = Tv(Td::spu() * 0.5);
}



//---- DSF

template<class Tv, class Td> DSF<Tv,Td>::DSF(Tv frq, Tv freqRatioA, Tv ampRatioA, Tv harmonicsA)
	: Base(frq)
{
	freq(frq);
	freqRatio(freqRatioA);
	harmonics(harmonicsA);
	ampRatio(ampRatioA);

	mBeta = 0.f;
}

template<class Tv, class Td> inline void DSF<Tv,Td>::freq(Tv v){
	Base::freq(v);
	updateBetaInc();	
}

template<class Tv, class Td> inline void DSF<Tv,Td>::freqRatio(Tv v){
	mFreqRatio = v;
	updateBetaInc();
}

template<class Tv, class Td> inline void DSF<Tv,Td>::ampRatio(Tv v){
	if(v != mA){
		// if near 1, nudge away
		static const Tv epslt = 0.9997;
		static const Tv epsgt = 1/epslt;
				if(v >= 1 && v < epsgt) v = epsgt;
		else	if(v <= 1 && v > epslt) v = epslt;
		mA = v;
		mASqP1 = mA * mA + 1.f;
		updateAPow();
	}
}

template<class Tv, class Td> inline void DSF<Tv,Td>::harmonics(Tv v){
	if(v != mN){
		mN = mNDesired = v;
		updateAPow();
	}
}

template<class Tv, class Td> inline void DSF<Tv,Td>::harmonicsMax(){
	harmonics(maxHarmonics());
}

template<class Tv, class Td> inline void DSF<Tv,Td>::antialias(){
	Tv maxN = maxHarmonics();
	if(mNDesired > maxN)	mN = maxN;
	else					mN = mNDesired;
	updateAPow();
}

template<class Tv, class Td> inline Tv DSF<Tv,Td>::ampRatio() const {
	return mA;
}
template<class Tv, class Td> inline Tv DSF<Tv,Td>::freqRatio() const {
	return mFreqRatio;
}
template<class Tv, class Td> inline Tv DSF<Tv,Td>::harmonics() const {
	return mN;
}

template<class Tv, class Td> inline Tv DSF<Tv,Td>::maxHarmonics() const {
	return scl::floor((Tv(this->spu()) * Tv(0.5)/this->freq() - Tv(1))/freqRatio() + Tv(1));
}

template<class Tv, class Td> inline void DSF<Tv,Td>::updateAPow(){
	mAPow = ::pow(mA, mN);
}

template<class Tv, class Td> inline void DSF<Tv,Td>::updateBetaInc(){
	mBetaInc = this->mInc * mFreqRatio;
}

// Generalized DSF formula:
// sum{k=0, N}( a^k sin(T + k B) )
//		=  sin(T) - a sin(T - B) - a^(N+1) [sin(T + (N+1) B) - a sin(T + N B))]
//			/ 1 + a^2 - 2a cos(B)

#define SIN scl::sinT7
#define COS scl::cosT8
//#define SIN sin
//#define COS cos
template<class Tv, class Td> inline Tv DSF<Tv,Td>::operator()(){
	Tv theta = Base::nextPhase();
	mBeta = scl::wrapPhase(mBeta);

	Tv phs2 = scl::wrapPhaseOnce(theta - mBeta);
	Tv phs3 = scl::wrapPhase(theta + mN * mBeta);
	Tv phs4 = scl::wrapPhaseOnce(phs3 - mBeta);

	Tv result = SIN(theta) - mA * SIN(phs2) - mAPow * (SIN(phs3) - mA * SIN(phs4));	
	result /= mASqP1 - Tv(2) * mA * COS(mBeta);
	//result /= mA * (mA - Tv(2) * COS(mBeta)) + Tv(1);

	mBeta += mBetaInc;
	return result;
}
#undef SIN
#undef COS

template<class Tv, class Td> void DSF<Tv,Td>::onDomainChange(double r){
	Base::onDomainChange(r);
	freq(Base::freq());
	harmonics(mNDesired);
}

} // gam::
#endif
