// --------------------------------------------------------------
// --------------------------------------------------------------
#include <string.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>

#include "synth_defs.h"

#include "vcf.h"
#include "voice.h"
#include "param_scale.h"

static const param_info_t param_info[] =
{
	{
		SYNTH_PARAM_VOLUME,
		7,
		"Master Volume",
		/*Base*/10.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1,
	},
	{
		SYNTH_PARAM_VOICE_PAN_SPREAD,
		0,
		"Voice Pan Spread",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_TUNE,
		0,
		"Master Tune",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_TOTAL_NUM_VOICES,
		-1,
		"Total num. Voices",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/MAX_POLYPHONY, /*interval*/1
	},
	{
		SYNTH_PARAM_HUMANIZE_ENABLE,
		-1,
		"Humanize Enable",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_HUMANIZE_VAR_VCO,
		0,
		"Humanize Spread VCO",
		/*Base*/10.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_HUMANIZE_VAR_VCF,
		0,
		"Humanize Spread VCF",
		/*Base*/10.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_HUMANIZE_VAR_ENV,
		0,
		"Humanize Spread ENV",
		/*Base*/10.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_MONOPHONIC_ENABLE,
		-1,
		"Monophonic Enable",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_MONOPHONIC_RETRIGGER_ENABLE,
		-1,
		"Monophonic Retrigger Enable",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_UNISONO_ENABLE,
		-1,
		"Unisono Enable",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_UNISONO_NUM_VOICES,
		-1,
		"Unisono num. Voices",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/MAX_POLYPHONY, /*interval*/1
	},
	{
		SYNTH_PARAM_PORTAMENTO_TIME,
		0,
		"Portamento Time",
		/*Base*/10.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0.001, /*pcenter*/-1, /*max*/0.5, /*interval*/0.001
	},
	{
		SYNTH_PARAM_OSC_0_ENABLE,
		-1,
		"OSC1 enable",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_ENABLE,
		-1,
		"OSC2 enable",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_RESTART_ON_TRIGGER,
		-1,
		"OSC1 restart on trigger",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_RESTART_ON_TRIGGER,
		-1,
		"OSC2 restart on trigger",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_LEVEL,
		0,
		"OSC1 level",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_1_LEVEL,
		0,
		"OSC2 level",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_0_DUTYCYCLE,
		0,
		"OSC1 pulse width",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_1_DUTYCYCLE,
		0,
		"OSC2 pulse width",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_0_DETUNE,
		0,
		"OSC1 detune",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-50, /*pcenter*/0, /*max*/+50, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_1_DETUNE,
		0,
		"OSC2 detune",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-50, /*pcenter*/0, /*max*/+50, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_0_TRANSPOSE,
		0,
		"OSC1 transpose",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-48.0, /*pcenter*/0, /*max*/+48.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_TRANSPOSE,
		0,
		"OSC2 transpose",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-48.0, /*pcenter*/0, /*max*/+48.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_WAVEFORM,
		-1,
		"OSC1 shape",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/OSC_NUM_WAVEFORMS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_WAVEFORM,
		-1,
		"OSC2 shape",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/OSC_NUM_WAVEFORMS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_PB_RANGE_MIN,
		-1,
		"OSC1 pitch bender minimum",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-48.0, /*pcenter*/0, /*max*/+48.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_PB_RANGE_MIN,
		-1,
		"OSC2 pitch bender minimum",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-48.0, /*pcenter*/0, /*max*/+48.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_PB_RANGE_MAX,
		-1,
		"OSC1 pitch bender maximum",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-48.0, /*pcenter*/0, /*max*/+48.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_PB_RANGE_MAX,
		-1,
		"OSC2 pitch bender maximum",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-48.0, /*pcenter*/0, /*max*/+48.0, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_FM_AMT_0,
		0,
		"OSC1 FM amt 1",
		/*Base*/10, /*kexp*/2.5, /*scenter*/0.5, /*min*/-48, /*pcenter*/0, /*max*/+48, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_1_FM_AMT_0,
		0,
		"OSC2 FM amt 1",
		/*Base*/10, /*kexp*/2.5, /*scenter*/0.5, /*min*/-48, /*pcenter*/0, /*max*/+48, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_0_FM_AMT_1,
		0,
		"OSC1 FM amt 2",
		/*Base*/1, /*kexp*/1, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_1_FM_AMT_1,
		0,
		"OSC2 FM amt 2",
		/*Base*/1, /*kexp*/1, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_0_FM_SRC_0,
		-1,
		"OSC1 FM src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_FM_SRC_0,
		-1,
		"OSC2 FM src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_FM_SRC_1,
		-1,
		"OSC1 FM src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_FM_SRC_1,
		-1,
		"OSC2 FM src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_FM_SRC_OP,
		-1,
		"OSC1 FM src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_FM_SRC_OP,
		-1,
		"OSC2 FM src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_AM_AMT_0,
		0,
		"OSC1 AM amt 1",
		/*Base*/1, /*kexp*/1, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_1_AM_AMT_0,
		0,
		"OSC2 AM amt 1",
		/*Base*/1, /*kexp*/1, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_0_AM_AMT_1,
		0,
		"OSC1 AM amt 2",
		/*Base*/1, /*kexp*/1, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_1_AM_AMT_1,
		0,
		"OSC2 AM amt 2",
		/*Base*/1, /*kexp*/1, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.01
	},
	{
		SYNTH_PARAM_OSC_0_AM_SRC_0,
		-1,
		"OSC1 AM src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_AM_SRC_0,
		-1,
		"OSC2 AM src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_AM_SRC_1,
		-1,
		"OSC1 AM src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_AM_SRC_1,
		-1,
		"OSC2 AM src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_AM_SRC_OP,
		-1,
		"OSC1 AM src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_AM_SRC_OP,
		-1,
		"OSC2 AM src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_PWM_AMT_0,
		0,
		"OSC1 PWM amt 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_1_PWM_AMT_0,
		0,
		"OSC2 PWM amt 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_0_PWM_AMT_1,
		0,
		"OSC1 PWM amt 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_1_PWM_AMT_1,
		0,
		"OSC2 PWM amt 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/+100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_OSC_0_PWM_SRC_0,
		-1,
		"OSC1 PWM src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_PWM_SRC_0,
		-1,
		"OSC2 PWM src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_PWM_SRC_1,
		-1,
		"OSC1 PWM src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_PWM_SRC_1,
		-1,
		"OSC2 PWM src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_0_PWM_SRC_OP,
		-1,
		"OSC1 PWM src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_OSC_1_PWM_SRC_OP,
		-1,
		"OSC2 PWM src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_NOISE_ENABLE,
		-1,
		"Noise enable",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/1, /*interval*/1
	},
	{
		SYNTH_PARAM_NOISE_LEVEL,
		0,
		"Noise level",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_NOISE_SHAPE,
		-1,
		"Noise shape",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NOISE_NUM_SHAPES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCA_ENV_AMT,
		0,
		"VCA Env amt",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCA_AM_AMT_0,
		0,
		"VCA AM amt 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCA_AM_SRC_0,
		-1,
		"VCA AM src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCA_PAN_AMT_0,
		0,
		"VCA PAN amt 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCA_PAN_SRC_0,
		-1,
		"VCA PAN src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCA_ENV_A,
		0,
		"VCA Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_VCA_ENV_D,
		0,
		"VCA Decay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_VCA_ENV_S,
		0,
		"VCA Sustain",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_ENV_A,
		0,
		"VCF Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_ENV_D,
		0,
		"VCF Decay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_ENV_S,
		0,
		"VCF Sustain",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_ENV_R,
		0,
		"VCF Release",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_ENV_2_A,
		0,
		"ENV 2 Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_ENV_2_D,
		0,
		"ENV 2 Decay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_ENV_2_S,
		0,
		"ENV 2 Sustain",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_ENV_2_R,
		0,
		"ENV 2 Release",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_ENV_3_A,
		0,
		"ENV 3 Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_ENV_3_D,
		0,
		"ENV 3 Decay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_ENV_3_S,
		0,
		"ENV 3 Sustain",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_ENV_3_R,
		0,
		"ENV 3 Release",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_VCA_ENV_R,
		0,
		"VCA Release",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/5, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_TYPE,
		-1,
		"VCF type",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VCF_NUM_FILTERTYPES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_ORDER,
		-1,
		"VCF order",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VCF_NUM_FILTERORDER-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_F,
		0,
		"VCF Cutoff",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/FILTER_F_MIN, /*pcenter*/-1, /*max*/FILTER_F_MAX, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_Q,
		0,
		"VCF Res",
		/*Base*/10, /*kexp*/2.0, /*scenter*/0.0, /*min*/FILTER_Q_MIN, /*pcenter*/-1, /*max*/FILTER_Q_MAX, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_ENV_AMT,
		0,
		"VCF Env amt",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_F_AMT_0,
		0,
		"VCF Cutoff amt 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_F_AMT_1,
		0,
		"VCF Cutoff amt 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_F_SRC_0,
		-1,
		"VCF Cutoff src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_F_SRC_1,
		-1,
		"VCF Cutoff src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_F_SRC_OP,
		-1,
		"VCF Cutoff src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_Q_AMT_0,
		0,
		"VCF Resonance amt 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_Q_AMT_1,
		0,
		"VCF Resonance amt 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_VCF_Q_SRC_0,
		-1,
		"VCF Resonance src 1",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_SOURCES_0-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_Q_SRC_1,
		-1,
		"VCF Resonance src 2",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/(VOICE_NUM_MOD_SOURCES_1-1)*VOICE_NUM_MOD_OPS + 1-1, /*interval*/1
	},
	{
		SYNTH_PARAM_VCF_Q_SRC_OP,
		-1,
		"VCF Resonance src OP",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_NUM_MOD_OPS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_0_SPEED,
		0,
		"LFO 1 speed",
		/*Base*/20, /*kexp*/1.0, /*scenter*/0.0, /*min*/0.01, /*pcenter*/-1, /*max*/200.0, /*interval*/0.01
	},
	{
		SYNTH_PARAM_LFO_1_SPEED,
		0,
		"LFO 2 speed",
		/*Base*/20, /*kexp*/1.0, /*scenter*/0.0, /*min*/0.01, /*pcenter*/-1, /*max*/200.0, /*interval*/0.01
	},
	{
		SYNTH_PARAM_LFO_2_SPEED,
		0,
		"LFO 3 speed",
		/*Base*/20, /*kexp*/1.0, /*scenter*/0.0, /*min*/0.01, /*pcenter*/-1, /*max*/200.0, /*interval*/0.01
	},
	{
		SYNTH_PARAM_LFO_3_SPEED,
		0,
		"LFO 4 speed",
		/*Base*/20, /*kexp*/1.0, /*scenter*/0.0, /*min*/0.01, /*pcenter*/-1, /*max*/200.0, /*interval*/0.01
	},
	{
		SYNTH_PARAM_LFO_0_SMOOTH,
		0,
		"LFO 1 smooth",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_1_SMOOTH,
		0,
		"LFO 2 smooth",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_2_SMOOTH,
		0,
		"LFO 3 smooth",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_3_SMOOTH,
		0,
		"LFO 4 smooth",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_0_DELAY,
		0,
		"LFO 1 Delay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_1_DELAY,
		0,
		"LFO 2 Delay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_2_DELAY,
		0,
		"LFO 3 Delay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_3_DELAY,
		0,
		"LFO 4 Delay",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/30000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_0_ATTACK,
		0,
		"LFO 1 Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_1_ATTACK,
		0,
		"LFO 2 Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_2_ATTACK,
		0,
		"LFO 3 Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_3_ATTACK,
		0,
		"LFO 4 Attack",
		/*Base*/150, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/10000, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_0_SHAPE,
		-1,
		"LFO 1 shape",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_WAVEFORMS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_1_SHAPE,
		-1,
		"LFO 2 shape",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_WAVEFORMS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_2_SHAPE,
		-1,
		"LFO 3 shape",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_WAVEFORMS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_3_SHAPE,
		-1,
		"LFO 4 shape",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_WAVEFORMS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_0_MODE,
		-1,
		"LFO 1 mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_1_MODE,
		-1,
		"LFO 2 mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_2_MODE,
		-1,
		"LFO 3 mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_3_MODE,
		-1,
		"LFO 4 mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_0_SYNC,
		-1,
		"LFO 1 sync",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_SYNCS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_1_SYNC,
		-1,
		"LFO 2 sync",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_SYNCS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_2_SYNC,
		-1,
		"LFO 3 sync",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_SYNCS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_3_SYNC,
		-1,
		"LFO 4 sync",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/VOICE_LFO_NUM_SYNCS-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_0_SYMMETRY,
		0,
		"LFO 1 symmetry",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_1_SYMMETRY,
		0,
		"LFO 2 symmetry",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_2_SYMMETRY,
		0,
		"LFO 3 symmetry",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_3_SYMMETRY,
		0,
		"LFO 4 symmetry",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.5, /*min*/-100, /*pcenter*/0, /*max*/100, /*interval*/0.1
	},
	{
		SYNTH_PARAM_LFO_0_MIDISYNC_MODE,
		-1,
		"LFO 1 Midi Sync Mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_SYNC_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_1_MIDISYNC_MODE,
		-1,
		"LFO 2 Midi Sync Mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_SYNC_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_2_MIDISYNC_MODE,
		-1,
		"LFO 3 Midi Sync Mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_SYNC_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_3_MIDISYNC_MODE,
		-1,
		"LFO 4 Midi Sync Mode",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/0, /*pcenter*/-1, /*max*/LFO_NUM_SYNC_MODES-1, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_0_MIDISYNC_BEATDIV,
		0,
		"LFO 1 Midi Sync Beat Divisor",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/32, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_1_MIDISYNC_BEATDIV,
		0,
		"LFO 2 Midi Sync Beat Divisor",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/32, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_2_MIDISYNC_BEATDIV,
		0,
		"LFO 3 Midi Sync Beat Divisor",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/32, /*interval*/1
	},
	{
		SYNTH_PARAM_LFO_3_MIDISYNC_BEATDIV,
		0,
		"LFO 4 Midi Sync Beat Divisor",
		/*Base*/1.0, /*kexp*/1.0, /*scenter*/0.0, /*min*/1, /*pcenter*/-1, /*max*/32, /*interval*/1
	},
};

// --------------------------------------------------------------
// Exported functions
// --------------------------------------------------------------
synth_float_t quantizeParam(param_info_t *pObj, synth_float_t p)
{
	synth_float_t k, pq;
	if (pObj->pinterval == 0)
		return p;

	k = (synth_float_t)1/(pObj->pinterval - 0);

	if (p < 0)
		pq = ((int)(p*k - 0.5))*pObj->pinterval;
	else
		pq = ((int)(p*k + 0.5))*pObj->pinterval;

	return pq;
}

synth_float_t clampParam(param_info_t *pObj, synth_float_t p)
{
	return (synth_float_t)jsy_min(pObj->pmax, jsy_max(pObj->pmin, quantizeParam(pObj, p)));
}

synth_float_t toParam(param_info_t *pObj, synth_float_t s)
{
	synth_float_t p, pcenter;
	synth_float_t pmax, pmin, base, kexp, scenter;

	pmax = pObj->pmax;
	pmin = pObj->pmin;
	if (pmin == pmax)
		pmax += 1E-9;
	base = pObj->base;
	kexp = pObj->kexp;
	if (kexp == 0)
		kexp = 1E-9;
	scenter = pObj->scenter;
	pcenter = pObj->pcenter;

	if ((pcenter < pmin) || (pcenter > pmax))
	    pcenter = pmax*scenter + pmin*(1-scenter);

	s = (synth_float_t)jsy_min(1, jsy_max(0, s));
	if (s < scenter)
	{
		if (base == 1)
		{
			// pcenter-(pcenter-pmin)*(scenter-s)/scenter;
			p = pcenter-(pcenter-pmin)*(scenter-s)/scenter;
		}
		else
		{
			// pcenter-(pcenter-pmin)*(B^(k*(scenter-s)/scenter)-1)/(B^k-1);
			p = pcenter-(pcenter-pmin)*(pow(base,kexp*(scenter-s)/scenter)-1)/(pow(base,kexp)-1);
		}
	}
	else
	{
		if (base == 1)
		{
			// pcenter+(pmax-pcenter)*(-scenter+s)/(1-scenter);
			p = pcenter+(pmax-pcenter)*(-scenter+s)/(1-scenter);
		}
		else
		{
			// pcenter+(pmax-pcenter)*(B^(k*(-scenter+s)/(1-scenter))-1)/(B^k-1);
			p = pcenter+(pmax-pcenter)*(pow(base,kexp*(-scenter+s)/(1-scenter))-1)/(pow(base,kexp)-1);
		}
	}

	return quantizeParam(pObj, p);
}
synth_float_t toSlider(param_info_t *pObj, synth_float_t p)
{
	synth_float_t s, pcenter;
	synth_float_t pmax, pmin, base, kexp, scenter;

	pmax = pObj->pmax;
	pmin = pObj->pmin;
	if (pmin == pmax)
		pmax += 1E-9;
	base = pObj->base;
	kexp = pObj->kexp;
	if (kexp == 0)
		kexp = 1E-9;
	scenter = pObj->scenter;
	pcenter = pObj->pcenter;

if ((pcenter < pmin) || (pcenter > pmax))
		pcenter = pmax*scenter + pmin*(1-scenter);

	p = clampParam(pObj, p);
	if (p < pcenter)
	{
		if (base == 1)
		{
			// (-pmin+p)*scenter/(pcenter-pmin);
			s = (-pmin+p)*scenter/(pcenter-pmin);
		}
		else
		{
			// scenter*(log(B)*k-log(-(-pcenter*B^k+pmin+p*B^k-p)/(pcenter-pmin)))/log(B)/k;
			s = scenter*(log(base)*kexp-log(-(-pcenter*pow(base,kexp)+pmin+p*pow(base,kexp)-p)/(pcenter-pmin)))/log(base)/kexp;
		}
	}
	else
	{
		if (base == 1)
		{
			// (pcenter-scenter*pmax-p+scenter*p)/(-pmax+pcenter);
			s = (pcenter-scenter*pmax-p+scenter*p)/(-pmax+pcenter);
		}
		else
		{
			// (k*log(B)*scenter+log(-(-pcenter*B^k+pmax+p*B^k-p)/(-pmax+pcenter))-log(-(-pcenter*B^k+pmax+p*B^k-p)/(-pmax+pcenter))*scenter)/log(B)/k;
			s = (kexp*log(base)*scenter+log(-(-pcenter*pow(base,kexp)+pmax+p*pow(base,kexp)-p)/(-pmax+pcenter))-log(-(-pcenter*pow(base,kexp)+pmax+p*pow(base,kexp)-p)/(-pmax+pcenter))*scenter)/log(base)/kexp;
		}
	}

	return s;

}

void paramInfoInit(param_info_t *pObj, UINT32 id, const char *pName)
{
	pObj->id = id;
	
	pObj->pName = NULL;
	if (pName)
	{
		pObj->pName = (char*)malloc(strlen(pName)+1);
		memcpy(pObj->pName, pName, strlen(pName)+1);
	}

	pObj->base = 1;
	pObj->kexp = 1;
	pObj->scenter = 0;
	pObj->pmin = 0;
	pObj->pcenter = 0;
	pObj->pmax = 1;
	pObj->pinterval = 0;

}

void paramInfoFree(param_info_t *pObj)
{
	if (pObj->pName)
		free(pObj->pName);
}


void paramInfoSetPMIN(param_info_t *pObj, synth_float_t value)
{
	pObj->pmin = value;
}

void paramInfoSetPMAX(param_info_t *pObj, synth_float_t value)
{
	pObj->pmax = value;
}

void paramInfoSet(param_info_t *pObj, 
							synth_float_t base, 
							synth_float_t kexp, 
							synth_float_t scenter, 
							synth_float_t pmin, 
							synth_float_t pcenter,
							synth_float_t pmax,
							synth_float_t pinterval)
{
	pObj->base = base;
	pObj->kexp = kexp;
	pObj->scenter = scenter;
	pObj->pmin = pmin;
	pObj->pcenter = pcenter;
	pObj->pmax = pmax;
	pObj->pinterval = pinterval;
}

void paramInfoCopy(param_info_t *pDst, param_info_t const *pSrc)
{
	pDst->base = pSrc->base;
	pDst->kexp = pSrc->kexp;
	pDst->scenter = pSrc->scenter;
	pDst->pmin = pSrc->pmin;
	pDst->pcenter = pSrc->pcenter;
	pDst->pmax = pSrc->pmax;
	pDst->pinterval = pSrc->pinterval;
}

param_info_t* getParamInfo(UINT32 type)
{
	UINT32 i;

	if (type >= SYNTH_NUM_PARAMS)
		return NULL;

	for (i=0; i < SYNTH_NUM_PARAMS; i++)
	{
		if (param_info[i].id == type)
			break;
	}

	if (i == SYNTH_NUM_PARAMS)
		return NULL;

	return (param_info_t*)&param_info[i];
}
