// --------------------------------------------------------------
// --------------------------------------------------------------
#ifndef _LFO_H_
#define	_LFO_H_

#include "synth_defs.h"
#include "noise.h"

#define LFO_SH_ALPHA		0.002		// S&H smoothing
#define LFO_KE			((synth_float_t)(1-exp(-1)))

// --------------------------------------------------------------
// Types
// --------------------------------------------------------------
enum
{	
	LFO_WAVEFORM_SINE,
	LFO_WAVEFORM_COSINE,
	LFO_WAVEFORM_SAW,
	LFO_WAVEFORM_SQUARE,
	LFO_WAVEFORM_TRIANGLE,
	LFO_WAVEFORM_SH_UNI,
	LFO_WAVEFORM_SH_GAUSS,
	LFO_WAVEFORM_SINE_REV,
	LFO_WAVEFORM_COSINE_REV,
	LFO_WAVEFORM_SAW_REV,
	LFO_WAVEFORM_SQUARE_REV,
	LFO_WAVEFORM_TRIANGLE_REV,
	LFO_NUM_WAVEFORMS
};

enum
{
	LFO_SYNC_MODE_OFF,
	LFO_SYNC_MODE_F,
	LFO_SYNC_MODE_P,
	LFO_SYNC_MODE_F_P,
	LFO_NUM_SYNC_MODES
};

enum
{
	LFO_PARAM2_WAVEFORM,
	LFO_PARAM2_FREQ,
	LFO_PARAM2_SMOOTH,
	LFO_PARAM2_DELAY,
	LFO_PARAM2_ATTACK,
	LFO_PARAM2_SYMMETRY,
	LFO_PARAM2_MIDISYNC_MODE,
	LFO_PARAM2_MIDISYNC_BEATDIV,
	LFO_NUM_PARAMS
};

typedef struct _ssync_t
{	
	synth_float_t phase;
	synth_float_t phase_int;
	synth_float_t phase_ref;
	synth_float_t omega;
	
	synth_float_t klead;
	synth_float_t klag;
	synth_float_t accu;
	
	int phase_update;

} sync_t;

typedef struct _ssync_result_t
{
	synth_float_t phase_int;
	synth_float_t phase;
	int is_cycle_start;
	
} sync_result_t;

#if defined(__cplusplus)
extern "C" {
#endif

// --------------------------------------------------------------
// Exported functions
// --------------------------------------------------------------
void Sync_init(sync_t *pObj);
void Sync_phase_update(sync_t *pObj, synth_float_t phase_ref);
synth_float_t Sync_mod(synth_float_t x);

#if defined(__cplusplus)
}

#endif
// --------------------------------------------------------------

typedef struct _slfo_t
{
	synth_float_t param[LFO_NUM_PARAMS];
	synth_float_t omega, fs;
	synth_float_t sh_sample;
	int freq_update_req;
	synth_float_t *pOut;
	UINT32 bufsize;
	noise_gen_t noise;
	synth_float_t smooth_out, smooth_a, smooth_b;
	UINT32 smooth_is_negative;
	synth_float_t delay_x, delay_dx, attack_y, attack_a;
	synth_float_t offset;
	sync_t sync;
	sync_result_t *pPhase;
	synth_float_t *pWave;

} lfo_t;

// --------------------------------------------------------------
#if defined(__cplusplus)
extern "C" {
#endif

// --------------------------------------------------------------
// Exported functions
// --------------------------------------------------------------
void LFO_Init(lfo_t *pObj, synth_float_t fs);
void LFO_Free(lfo_t *pObj);
void LFO_SetFS(lfo_t *pObj, synth_float_t fs);
void LFO_SetBufsize(lfo_t *pObj, UINT32 bufsize);
void LFO_Reset(lfo_t *pObj, synth_float_t initial_phase);
synth_float_t LFO_sync(lfo_t *pObj, synth_float_t phase);
void LFO_Param2Set(lfo_t *pObj, UINT32 type, synth_float_t value);
synth_float_t* LFO_ProcessDataV(lfo_t *pObj, UINT32 len);
void Sync_processV(lfo_t *pObj, int len);
sync_result_t Sync_process(lfo_t *pObj);

#if defined(__cplusplus)
}

#endif
// --------------------------------------------------------------

#endif // _LFO_H_
