// --------------------------------------------------------------
// --------------------------------------------------------------
#ifndef _VOICE_H_
#define	_VOICE_H_

#include "synth_defs.h"
#include "env.h"
#include "vco.h"
#include "vcf.h"
#include "lfo.h"
#include "smooth.h"

#define VOICE_OSC_SPREAD_PHASE_AMT		0.01
// --------------------------------------------------------------
// Types
// --------------------------------------------------------------
enum
{
	VOICE_PARAM_MASTER_TUNE = 0,
	VOICE_PARAM_MASTER_FREF,
	VOICE_PARAM_VOICE_PAN,
	VOICE_PARAM_PORTAMENTO_TIME,
	VOICE_PARAM_OSC_0_ENABLE,
	VOICE_PARAM_OSC_1_ENABLE,
	VOICE_PARAM_OSC_0_RESTART_ON_TRIGGER,
	VOICE_PARAM_OSC_1_RESTART_ON_TRIGGER,
	VOICE_PARAM_OSC_0_LEVEL,
	VOICE_PARAM_OSC_1_LEVEL,
	VOICE_PARAM_OSC_0_PHASE,
	VOICE_PARAM_OSC_1_PHASE,
	VOICE_PARAM_OSC_0_DUTYCYCLE,
	VOICE_PARAM_OSC_1_DUTYCYCLE,
	VOICE_PARAM_OSC_0_DETUNE,
	VOICE_PARAM_OSC_1_DETUNE,
	VOICE_PARAM_OSC_0_TRANSPOSE,
	VOICE_PARAM_OSC_1_TRANSPOSE,
	VOICE_PARAM_OSC_0_SCALE,
	VOICE_PARAM_OSC_1_SCALE,
	VOICE_PARAM_OSC_0_WAVEFORM,
	VOICE_PARAM_OSC_1_WAVEFORM,
	VOICE_PARAM_OSC_0_FM_AMT_0,
	VOICE_PARAM_OSC_1_FM_AMT_0,
	VOICE_PARAM_OSC_0_FM_AMT_1,
	VOICE_PARAM_OSC_1_FM_AMT_1,
	VOICE_PARAM_OSC_0_FM_SRC_0,
	VOICE_PARAM_OSC_1_FM_SRC_0,
	VOICE_PARAM_OSC_0_FM_SRC_1,
	VOICE_PARAM_OSC_1_FM_SRC_1,
	VOICE_PARAM_OSC_0_FM_SRC_OP,
	VOICE_PARAM_OSC_1_FM_SRC_OP,
	VOICE_PARAM_OSC_0_AM_AMT_0,
	VOICE_PARAM_OSC_1_AM_AMT_0,
	VOICE_PARAM_OSC_0_AM_AMT_1,
	VOICE_PARAM_OSC_1_AM_AMT_1,
	VOICE_PARAM_OSC_0_AM_SRC_0,
	VOICE_PARAM_OSC_1_AM_SRC_0,
	VOICE_PARAM_OSC_0_AM_SRC_1,
	VOICE_PARAM_OSC_1_AM_SRC_1,
	VOICE_PARAM_OSC_0_AM_SRC_OP,
	VOICE_PARAM_OSC_1_AM_SRC_OP,
	VOICE_PARAM_OSC_0_PWM_AMT_0,
	VOICE_PARAM_OSC_1_PWM_AMT_0,
	VOICE_PARAM_OSC_0_PWM_AMT_1,
	VOICE_PARAM_OSC_1_PWM_AMT_1,
	VOICE_PARAM_OSC_0_PWM_SRC_0,
	VOICE_PARAM_OSC_1_PWM_SRC_0,
	VOICE_PARAM_OSC_0_PWM_SRC_1,
	VOICE_PARAM_OSC_1_PWM_SRC_1,
	VOICE_PARAM_OSC_0_PWM_SRC_OP,
	VOICE_PARAM_OSC_1_PWM_SRC_OP,
	VOICE_PARAM_NOISE_ENABLE,
	VOICE_PARAM_NOISE_LEVEL,
	VOICE_PARAM_NOISE_SHAPE,
	VOICE_PARAM_KEY,
	VOICE_PARAM_VCA_ENV_GAIN,
	VOICE_PARAM_VCA_AM_AMT_0,
	VOICE_PARAM_VCA_AM_SRC_0,
	VOICE_PARAM_VCA_PAN_AMT_0,
	VOICE_PARAM_VCA_PAN_SRC_0,
	VOICE_PARAM_ENV_0_A, VOICE_PARAM_VCF_ENV_A = VOICE_PARAM_ENV_0_A,
	VOICE_PARAM_ENV_1_A, VOICE_PARAM_VCA_ENV_A = VOICE_PARAM_ENV_1_A,
	VOICE_PARAM_ENV_2_A,
	VOICE_PARAM_ENV_3_A,
	VOICE_PARAM_ENV_0_S, VOICE_PARAM_VCF_ENV_S = VOICE_PARAM_ENV_0_S,
	VOICE_PARAM_ENV_1_S, VOICE_PARAM_VCA_ENV_S = VOICE_PARAM_ENV_1_S,
	VOICE_PARAM_ENV_2_S,
	VOICE_PARAM_ENV_3_S,
	VOICE_PARAM_ENV_0_D, VOICE_PARAM_VCF_ENV_D = VOICE_PARAM_ENV_0_D,
	VOICE_PARAM_ENV_1_D, VOICE_PARAM_VCA_ENV_D = VOICE_PARAM_ENV_1_D,
	VOICE_PARAM_ENV_2_D,
	VOICE_PARAM_ENV_3_D,
	VOICE_PARAM_ENV_0_R, VOICE_PARAM_VCF_ENV_R = VOICE_PARAM_ENV_0_R,
	VOICE_PARAM_ENV_1_R, VOICE_PARAM_VCA_ENV_R = VOICE_PARAM_ENV_1_R,
	VOICE_PARAM_ENV_2_R,
	VOICE_PARAM_ENV_3_R,
	VOICE_PARAM_VCF_TYPE,
	VOICE_PARAM_VCF_ORDER,
	VOICE_PARAM_VCF_F,
	VOICE_PARAM_VCF_Q,
	VOICE_PARAM_VCF_Q_GAIN_0,
	VOICE_PARAM_VCF_Q_CTRL_0,
	VOICE_PARAM_VCF_ENV_GAIN,
	VOICE_PARAM_VCF_F_AMT_0,
	VOICE_PARAM_VCF_F_AMT_1,
	VOICE_PARAM_VCF_F_SRC_0,
	VOICE_PARAM_VCF_F_SRC_1,
	VOICE_PARAM_VCF_F_SRC_OP,
	VOICE_PARAM_VCF_Q_AMT_0,
	VOICE_PARAM_VCF_Q_AMT_1,
	VOICE_PARAM_VCF_Q_SRC_0,
	VOICE_PARAM_VCF_Q_SRC_1,
	VOICE_PARAM_VCF_Q_SRC_OP,
	VOICE_PARAM_LFO_0_SPEED,
	VOICE_PARAM_LFO_1_SPEED,
	VOICE_PARAM_LFO_2_SPEED,
	VOICE_PARAM_LFO_3_SPEED,
	VOICE_PARAM_LFO_0_SMOOTH,
	VOICE_PARAM_LFO_1_SMOOTH,
	VOICE_PARAM_LFO_2_SMOOTH,
	VOICE_PARAM_LFO_3_SMOOTH,
	VOICE_PARAM_LFO_0_DELAY,
	VOICE_PARAM_LFO_1_DELAY,
	VOICE_PARAM_LFO_2_DELAY,
	VOICE_PARAM_LFO_3_DELAY,
	VOICE_PARAM_LFO_0_ATTACK,
	VOICE_PARAM_LFO_1_ATTACK,
	VOICE_PARAM_LFO_2_ATTACK,
	VOICE_PARAM_LFO_3_ATTACK,
	VOICE_PARAM_LFO_0_SHAPE,
	VOICE_PARAM_LFO_1_SHAPE,
	VOICE_PARAM_LFO_2_SHAPE,
	VOICE_PARAM_LFO_3_SHAPE,
	VOICE_PARAM_LFO_0_MODE,
	VOICE_PARAM_LFO_1_MODE,
	VOICE_PARAM_LFO_2_MODE,
	VOICE_PARAM_LFO_3_MODE,
	VOICE_PARAM_LFO_0_SYNC,
	VOICE_PARAM_LFO_1_SYNC,
	VOICE_PARAM_LFO_2_SYNC,
	VOICE_PARAM_LFO_3_SYNC,
	VOICE_PARAM_LFO_0_SYMMETRY,
	VOICE_PARAM_LFO_1_SYMMETRY,
	VOICE_PARAM_LFO_2_SYMMETRY,
	VOICE_PARAM_LFO_3_SYMMETRY,
	VOICE_PARAM_LFO_0_MIDISYNC_MODE,
	VOICE_PARAM_LFO_1_MIDISYNC_MODE,
	VOICE_PARAM_LFO_2_MIDISYNC_MODE,
	VOICE_PARAM_LFO_3_MIDISYNC_MODE,
	VOICE_PARAM_LFO_0_MIDISYNC_BEATDIV,
	VOICE_PARAM_LFO_1_MIDISYNC_BEATDIV,
	VOICE_PARAM_LFO_2_MIDISYNC_BEATDIV,
	VOICE_PARAM_LFO_3_MIDISYNC_BEATDIV,
	VOICE_NUM_PARAMS
};

enum
{
	VOICE_ENV_ENV_0 = 0,
	VOICE_ENV_VCF = VOICE_ENV_ENV_0,
	VOICE_ENV_ENV_1,
	VOICE_ENV_VCA = VOICE_ENV_ENV_1,
	VOICE_ENV_2,
	VOICE_ENV_3,
};

enum 
{
	VOICE_MOD_SRC_ZEROS = 0,
	VOICE_MOD_SRC_LFO_0,
	VOICE_MOD_SRC_LFO_1,
	VOICE_MOD_SRC_LFO_2,
	VOICE_MOD_SRC_LFO_3,
	VOICE_MOD_SRC_ENV_0,
	VOICE_MOD_SRC_ENV_1,
	VOICE_MOD_SRC_ENV_2,
	VOICE_MOD_SRC_ENV_3,
	VOICE_MOD_SRC_VCO_0,
	VOICE_MOD_SRC_VCO_1,
	VOICE_NUM_MOD_SOURCES
};

enum 
{
	VOICE_MOD_SRC_0_DISABLED = 0,
	VOICE_MOD_SRC_0_LFO_0,
	VOICE_MOD_SRC_0_LFO_1,
	VOICE_MOD_SRC_0_LFO_2,
	VOICE_MOD_SRC_0_LFO_3,
	VOICE_MOD_SRC_0_ENV_0,
	VOICE_MOD_SRC_0_ENV_1,
	VOICE_MOD_SRC_0_ENV_2,
	VOICE_MOD_SRC_0_ENV_3,
	VOICE_MOD_SRC_0_VCO_0,
	VOICE_NUM_MOD_SOURCES_0
};

enum 
{
	VOICE_MOD_SRC_1_DISABLED = 0,
	VOICE_MOD_SRC_1_LFO_0,
	VOICE_MOD_SRC_1_LFO_1,
	VOICE_MOD_SRC_1_LFO_2,
	VOICE_MOD_SRC_1_LFO_3,
	VOICE_MOD_SRC_1_ENV_0,
	VOICE_MOD_SRC_1_ENV_1,
	VOICE_MOD_SRC_1_ENV_2,
	VOICE_MOD_SRC_1_ENV_3,
	VOICE_NUM_MOD_SOURCES_1
};

enum 
{
	VOICE_MOD_SRC_OP_ADD = 0,
	VOICE_MOD_SRC_OP_MUL,
	VOICE_NUM_MOD_OPS
};

enum 
{
	VOICE_LFO_MODE_GLOBAL,
	VOICE_LFO_MODE_INDIVIDUAL,
	VOICE_LFO_NUM_MODES
};

enum 
{
	VOICE_LFO_SYNC_FREE,
	VOICE_LFO_SYNC_RESTART,
	VOICE_LFO_NUM_SYNCS
};

enum 
{
	VOICE_LFO_MIDISYNC_OFF,
	VOICE_LFO_MIDISYNC_F,
	VOICE_LFO_MIDISYNC_P,
	VOICE_LFO_MIDISYNC_F_P,
	VOICE_LFO_NUM_MIDISYNC
};

enum
{
	VOICE_NOISE_SHAPE_WHITE,
	VOICE_NOISE_SHAPE_PINK,
	VOICE_NOISE_NUM_SHAPES
};

enum 
{
	note_state_idle = 0,
	note_state_triggered,
	note_state_released
};

enum
{
	voice_event_shutdown = 0,
	voice_event_trigger,
	voice_event_retrigger,
	voice_event_release
};

typedef struct _svoice_common_t
{
	synth_float_t freqTab[NUM_FREQS];

	// Global LFO
	lfo_t glfo[VOICE_NUM_LFO];
	
	// Global Envelopes
	envgen_t genv[VOICE_NUM_ENV];
	
	// Global VCF
	vcf_t gvcf[2];

	// Global Noise generator
	noise_gen_t gnoise;

	synth_float_t pBuf_zeros[SYNTH_MAX_BUFSIZE];
	synth_float_t pBuf_ones[SYNTH_MAX_BUFSIZE];
	synth_float_t *pBuf_LFO_gbl[VOICE_NUM_LFO];
	synth_float_t *pBuf_ENV_gbl[VOICE_NUM_ENV];
	synth_float_t *pBuf_VCF_gbl_in;
	synth_float_t *pBuf_VCF_gbl_out;
	synth_float_t noise_out[SYNTH_MAX_BUFSIZE];

	vco_common_t vco;
	vcf_common_t vcf;

} voice_common_t;

typedef struct _svoice_t
{
	voice_common_t *pCom;
	UINT32 id;
	UINT32 state;
	UINT32 bufsize;
	envgen_t env[VOICE_NUM_ENV];
	synth_float_t fs;
	osc_t vco[VOICE_NUM_OSC];
	lfo_t lfo[VOICE_NUM_LFO];
	vcf_t vcf;
	synth_float_t param[VOICE_NUM_PARAMS];
	synth_float_t *pBuf_Q;
	smooth_t smooth_vco_enable[VOICE_NUM_OSC];
	smooth_t smooth_vco_portamento[VOICE_NUM_OSC];
	synth_float_t vco_pitch[VOICE_NUM_OSC];
//	smooth_t *pParam_smoother[VOICE_NUM_PARAMS];
//	synth_float_t param_smoothed[VOICE_NUM_PARAMS][SYNTH_MAX_BUFSIZE];
} voice_t;

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

// --------------------------------------------------------------
// Exported functions
// --------------------------------------------------------------
void Voice_ModInit(voice_common_t *pCom);
void Voice_ModFree(voice_common_t *pCom);
void VoiceInit(voice_t *pObj, voice_common_t *pCom, UINT32 id, synth_float_t fs);
void VoiceFree(voice_t *pObj);
void VoiceSetFS(voice_t *pObj, synth_float_t fs);
void VoiceSetBufsize(voice_t *pObj, UINT32 size);
void VoiceEvent(voice_t *pObj, UINT32 type);
void VoiceParam2Set(voice_t *pObj, UINT32 type, synth_float_t value);
synth_float_t VoiceParamGet(voice_t *pObj, UINT32 type);
UINT32 VoiceStateGet(voice_t *pObj);
void VoiceProcessDataV(voice_t *pObj, float *pOut1, float *pOut2, UINT32 len);
void VoiceProcessDataV_Common(voice_t *pObj, float *pOut1, float *pOut2, UINT32 len);

#if defined(__cplusplus)
}

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

#endif // _VOICE_H_
