/*****************************************************************************

        GRAOUMF TRACKER 2
        Author: Laurent de Soras, 1996-2016

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*****************************************************************************/



/*\\\ FICHIERS INCLUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include	<stdio.h>
#include	<string.h>
#include	<math.h>

#include	"base.h"
#include	"base_ct.h"
#include	"filter.h"
#include	"FxPreset.h"
#include	"log.h"
#include	"WaveForm.h"



/*\\\ CONSTANTES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

const char	*const FxPreset::effect_name_0 [FxPreset_NBR_TYPES] =
{
	"None",
	"Delay",
	"Resonant filter",
	"Distortion"
};



/*\\\ CONSTANTES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ TYPES & STRUCTURES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ DEFINITION DES VARIABLES DE CLASSE PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ DEFINITION DES VARIABLES DE CLASSE PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ METHODES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: (constructeur)                                                 */
/*      Description: Initialise                                             */
/*      Parametres en entree:                                               */
/*        - number: numero du preset.                                       */
/*==========================================================================*/

FxPreset::FxPreset (int number)
{
	_number = number;
	memset (_name, ' ', FxPreset_NAME_LEN);
	_type = FxPreset_TYPE_NONE;
}



/*==========================================================================*/
/*      Nom: (destructeur)                                                  */
/*      Description: Detruit                                                */
/*==========================================================================*/

FxPreset::~FxPreset (void)
{
	/* Rien a faire, ici */
}



/*==========================================================================*/
/*      Nom: check_ok                                                       */
/*      Description: Verifie l'intergrite de l'objet.                       */
/*      Retour: 0 si l'objet parait correct.                                */
/*==========================================================================*/

signed int	FxPreset::check_ok (void) const
{
	if (this == NULL)
	{
		LOG_printf ("FxPreset::check_ok: Error: \"this\" pointer is NULL.\n");
		return (-1);
	}

	return (0);
}



/*==========================================================================*/
/*      Nom: self_display                                                   */
/*      Description: Affiche "textuellement" le contenu courant de l'objet. */
/*==========================================================================*/

void	FxPreset::self_display (void) const
{

	/*** A faire ***/

}



void	FxPreset::get_name (char name_0 [FxPreset_NAME_LEN+1])
{
	BASE_copy_string (_name, name_0,
							FxPreset_NAME_LEN, FxPreset_NAME_LEN);
	name_0 [FxPreset_NAME_LEN] = 0;
}



void	FxPreset::set_name (const char *name_0)
{
	BASE_copy_string (name_0, _name, strlen (name_0), FxPreset_NAME_LEN);
}



int	FxPreset::get_number (void)
{
	return (_number);
}



void	FxPreset::set_number (int number)
{
	_number = number;
}



int	FxPreset::get_effect_type (void)
{
	return (_type);
}



void	FxPreset::set_effect_type (int type)
{
	_type = type;
}



const FxPreset_EFFECT_CONF	&FxPreset::get_parameters (void)
{
	return (_conf);
}



void	FxPreset::set_parameters (const FxPreset_EFFECT_CONF &conf)
{
	_conf = conf;
}



void	FxPreset::validate_parameters (void)
{
	FxPreset::validate_parameters (_conf, _type);
}



void	FxPreset::validate_parameters (FxPreset_EFFECT_CONF &conf, int type)
{
	double		dummy;

	switch (type)
	{
	case	FxPreset_TYPE_DELAY:
		conf.delay.delay = MIN (conf.delay.delay, FxPreset_DELAY_MAX_TIME);
		conf.delay.delay = MAX (conf.delay.delay, FxPreset_DELAY_MIN_TIME);
		conf.delay.feedback = MIN (conf.delay.feedback, FxPreset_DELAY_MAX_FDBK);
		conf.delay.feedback = MAX (conf.delay.feedback, FxPreset_DELAY_MIN_FDBK);
		break;

	case	FxPreset_TYPE_RESFILT:
		conf.resfilt.q = MIN (conf.resfilt.q, FxPreset_RESFILT_MAX_Q);
		conf.resfilt.q = MAX (conf.resfilt.q, FxPreset_RESFILT_MIN_Q);
		conf.resfilt.freq = MIN (conf.resfilt.freq, FxPreset_RESFILT_MAX_FREQ);
		conf.resfilt.freq = MAX (conf.resfilt.freq, FxPreset_RESFILT_MIN_FREQ);
		conf.resfilt.cell_ratio = MIN (conf.resfilt.cell_ratio, FxPreset_RESFILT_MAX_CRATIO);
		conf.resfilt.cell_ratio = MAX (conf.resfilt.cell_ratio, FxPreset_RESFILT_MIN_CRATIO);
		conf.resfilt.lfo_freq = MIN (conf.resfilt.lfo_freq, FxPreset_RESFILT_MAX_LFOFREQ);
		conf.resfilt.lfo_freq = MAX (conf.resfilt.lfo_freq, FxPreset_RESFILT_MIN_LFOFREQ);
		conf.resfilt.lfo_depth = MIN (conf.resfilt.lfo_depth, FxPreset_RESFILT_MAX_LFODEPTH);
		conf.resfilt.lfo_depth = MAX (conf.resfilt.lfo_depth, FxPreset_RESFILT_MIN_LFODEPTH);
		conf.resfilt.lfo_phase = modf (conf.resfilt.lfo_phase, &dummy);
		if (conf.resfilt.lfo_phase < 0.0)
		{
			conf.resfilt.lfo_phase = 1.0 - conf.resfilt.lfo_phase;
		}
		conf.resfilt.lfo_waveform = MIN (conf.resfilt.lfo_waveform, WaveForm_NBR_BASE_FORMS - 1);
		conf.resfilt.lfo_waveform = MAX (conf.resfilt.lfo_waveform, 0);
		conf.resfilt.type = MIN (conf.resfilt.type, FILT_NBR_BIQUAD_TYPES - 1);
		conf.resfilt.type = MAX (conf.resfilt.type, 0);
		conf.resfilt.nbr_biquads = MIN (conf.resfilt.nbr_biquads, FxPreset_RESFILT_MAX_BIQUAD);
		conf.resfilt.nbr_biquads = MAX (conf.resfilt.nbr_biquads, FxPreset_RESFILT_MIN_BIQUAD);
		conf.resfilt.nbr_cells = MIN (conf.resfilt.nbr_cells, FxPreset_RESFILT_MAX_BIQUAD / conf.resfilt.nbr_biquads - 1);
		conf.resfilt.nbr_cells = MAX (conf.resfilt.nbr_cells, 0);
		break;

	case	FxPreset_TYPE_DISTO:
		conf.disto.gain = MIN (conf.disto.gain, FxPreset_DISTO_MAX_GAIN);
		conf.disto.gain = MAX (conf.disto.gain, FxPreset_DISTO_MIN_GAIN);
		conf.disto.threshold = MIN (conf.disto.threshold, FxPreset_DISTO_MAX_THRESHOLD);
		conf.disto.threshold = MAX (conf.disto.threshold, FxPreset_DISTO_MIN_THRESHOLD);
		conf.disto.sec_gain = MIN (conf.disto.sec_gain, FxPreset_DISTO_MAX_SEC_GAIN);
		conf.disto.sec_gain = MAX (conf.disto.sec_gain, FxPreset_DISTO_MIN_SEC_GAIN);
		conf.disto.type = MIN (conf.disto.type, FxPreset_DISTO_NBR_TYPES - 1);
		conf.disto.type = MAX (conf.disto.type, 0);
		break;
	}
}



void	FxPreset::reset_parameters (FxPreset_EFFECT_CONF &conf, int type)
{
	switch (type)
	{
	case	FxPreset_TYPE_DELAY:
		conf.delay.delay = 0.375;			// Delay    = 375.00 ms (croche pointee a tempo 120)
		conf.delay.feedback = 0.367879;	// Feedback =  36.79 %
		break;

	case	FxPreset_TYPE_RESFILT:
		conf.resfilt.q = 0.5;
		conf.resfilt.freq = 1000.0;
		conf.resfilt.cell_ratio = 12.0;	// Octave
		conf.resfilt.lfo_freq = 0.5;		// 1 mesure a tempo 120
		conf.resfilt.lfo_depth = 5.0;
		conf.resfilt.lfo_phase = 0.0;
		conf.resfilt.lfo_waveform = WaveForm_BASE_SIN;
		conf.resfilt.type = FILT_BIQUAD_LOWP;
		conf.resfilt.nbr_biquads = 1;
		conf.resfilt.nbr_cells = 1;
		conf.resfilt.cell_flag = false;
		conf.resfilt.lfo_flag = false;
		break;

	case	FxPreset_TYPE_DISTO:
		conf.disto.gain = 24;
		conf.disto.threshold = 24;
		conf.disto.sec_gain = 36;
		conf.disto.type = FxPreset_DISTO_TYPE_BOOST;
		break;
	}
}



void	FxPreset::copy_preset (FxPreset_EFFECT_CONF &conf, const FxPreset_EFFECT_CONF &src_conf, int type, long auto_val)
{
	FxPreset_EFFECT_CONF temp_conf;

	/* Les bits a 1 sont maintenant les valeurs
	   du preset precedant a conserver */
	auto_val = ~auto_val;

	switch (type)
	{
	case	FxPreset_TYPE_RESFILT:
		temp_conf = src_conf;
		if (auto_val & FxPreset_AUTO_VAL_RESFILT_LFO_PHASE)
		{
			temp_conf.resfilt.lfo_phase = conf.resfilt.lfo_phase;
		}
		conf = temp_conf;
		break;

	default:
		conf = src_conf;
		break;
	}
}



/*\\\ METHODES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/****************************************************************************/
/*                                                                          */
/*                                                                          */
/*                                                                          */
/****************************************************************************/



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/
