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

        GRAOUMF TRACKER 2

        player.h
        Copyright (c) 1996-2008 Laurent de Soras

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Contact the author : laurent@ohmforce.com
More information about this license : http://www.gnu.org/licenses/gpl.html

*Tab=3***********************************************************************/



#if ! defined (Player_HEADER_INCLUDED)
#define	Player_HEADER_INCLUDED

#if defined (_MSC_VER)
	#pragma once
	#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include	"archi.h"
#include	"EnvSet.h"
#include	"FxPreset.h"
#include	"gt_limit.h"
#include	"gtracker.h"
#include	"mods_ct.h"
#include	"Pattern.h"
#include	"play_ct.h"
#include	"ReconstructionFilter.h"
#include	"splhandl.h"
#include	"Thread.h"
#include	"ThreadCbInterface.h"
#include	"tracks.h"
#include	"Voice.h"

#include	<list>
#include	<vector>

#include	<cstdio>

class ConfigKey;



class Player
:	public ThreadCbInterface
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

	// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	// Constants

	enum {			MIN_TEMPO				= 32	};
	enum {			MAX_TEMPO				= 999	};
	enum {			INIT_TEMPO				= 125	};

	enum {			MIN_SPEED				= 1	};
	enum {			MAX_SPEED				= 255	};
	enum {			INIT_SPEED				= 6	};

	enum {			MIN_TIME_HIGH			= 1	};
	enum {			MAX_TIME_HIGH			= 16	};
	enum {			INIT_TIME_HIGH			= 4	};

	enum {			MIN_TIME_LOW			= 1	};
	enum {			MAX_TIME_LOW			= 16	};
	enum {			INIT_TIME_LOW			= 4	};

	enum {			LIN_PER_NOTE			= 0x100	};		// Nombre de periodes lineaires entre 2 1/2 tons
	enum {			REF_PERIOD				= 0x1AC0L	};	// Periode Amiga de reference
	enum {			REF_LIN_PERIOD			= (8L*12 * LIN_PER_NOTE)	};	// Periode lineaire de reference
	enum {			MIN_PERIOD				= 0x40L	};
	enum {			MAX_PERIOD				= 0x1FFFFL		};

	enum {			INIT_LINEAR_PERIOD_FLAG	= true	};

	enum {			MODE_STOP_ALL			= -1	};
	enum {			MODE_STOP				= 0	};
	enum {			MODE_SONG				= 1	};
	enum {			MODE_PATTERN			= 2	};

	enum {			NBR_GLOBAL_TRACKS		= GTK_NBRTRACKS_MAXI + GTK_NBROUT_MAXI	};
	enum {			MAX_NBR_VOICES			= GTK_NBRTRACKS_MAXI	};	// Must be >= GTK_NBRTRACKS_MAXI

	// Mode d'application d'un preset de mixage
	enum {			MIX_PRESET_MASK		= 0x0003	};	// Masque pour le test des valeurs suivantes
	enum {			MIX_PRESET_REPL		= 0x0000	};	// Remplace les pistes par celles du nouveau preset (exclusion mutuelle)
	enum {			MIX_PRESET_ADD			= 0x0001	};	// Ajoute les pistes a celles deja existantes (exclusion mutuelle)
	enum {			MIX_PRESET_NO_MOD		= 0x0002	};	// Ne change pas la config des entrees (ne modifie que leurs parametres) (exclusion mutuelle)

	enum {			MIX_PRESET_NO_DEST	= 0x0004	};	// N'affecte pas les parametres de la piste destination
	enum {			MIX_PRESET_NO_VOL		= 0x0008	};	// Ne modifie pas les parametres de volume
	enum {			MIX_PRESET_NO_PAN		= 0x0010	};	// Ne modifie pas les parametres de panning

	// Nombres de parametres d'increment/decrement pour chaque type de fonction
	enum {			FX_NBR_TIME_SPEED		= 1	};
	enum {			FX_NBR_FREQ_SPEED		= 2	};

	// Types des parametres des commandes
	enum {			FX_TIME_PARAMETER		= 0x01 << 16	};	// Indique un effet agissant sur un parametre temporel
	enum {			FX_FREQ_PARAMETER		= 0x02 << 16	};	// Indique un effet agissant sur un parametre frequentiel
	enum {			FX_DOUBLE_PARAMETER_2D	= 0x04 << 16	};	// Effet a parametre general en virgule flottante, 2 decimale
	enum {			FX_DOUBLE_PARAMETER_3D	= 0x08 << 16	};	// Effet a parametre general en virgule flottante, 3 decimales
	enum {			FX_INT_PARAMETER			= 0x10 << 16	};	// Effet a parametre general entier

	enum {			FX_RESFILT_INT_BUF_LEN	= 1 << 2	};	// Taille des buffers des filtres. Doit etre une puissance de 2.



	// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	// Types

	//----------------------------------------------
	// Effects
	//----------------------------------------------

	// Delay, configuration interne
	class FxInternalDelay
	{
	public:
		float *	buf_ptr;		// Pointeur sur le buffer
		LWORD		buf_len;		// Taille du buffer, en samples
		LWORD		write_pos;	// Position courante d'ecriture dans le buffer
		LWORD		delay;		// Ecart entre la position de replay et d'ecriture. <= buf_len
		ULWORD	feedback;	// 0...FFFFFFFF <-> 0...100 %
	};

	// Filtres resonnants, configuration interne
	class FxInternalResFilt
	{
	public:
		double	l_num [3];	// Fraction rationnelle en p pour les calculs intermediaires.
		double	l_den [3];
		bool		mix_cell_flag;	// Indique qu'on doit mixer les filtrages de chaque cellule et non les superposer (pour le mode Band-Pass)
		struct
		{
			double	x_coef [3];	// Stockage des coefficients du filtre.
			double	y_coef [3];
			double	y_buffer [FX_RESFILT_INT_BUF_LEN * 2];	// Buffers de filtrage, stereo
			float		x_buffer [FX_RESFILT_INT_BUF_LEN * 2];
			int		nbr_coef;
			int		buffer_pos;
		}			biquad [FxPreset_RESFILT_MAX_BIQUAD];
	};

	class FxInternalDisto
	{
	public:
		double	g;					// Gain qui sert au coeur du log ou du sin
		double	k;					// Gain post-distorsion pour normaliser le signal
		double	p;					// Pente reele du gain secondaire
	};

	//----------------------------------------------
	// Generic
	//----------------------------------------------

	class TrackInfoSpl
	{
	public:
		enum {			MAX_GHOST_VOICES	= 16	};

		int				nbr_voices;	// [1 ; MAX_GHOST_VOICES]. Non-spl tracks have always one and only one voice.
		int				voice_index_arr [MAX_GHOST_VOICES];	// Index in _voice_arr. Position 0: main (controlled) voice
	};

	// Information de mixage pour les pistes d'Audio In
	class TrackInfoAIn
	{
	public:
		// Nothing
	};

	// Informations de mixage pour les pistes d'Audio Out et d'effets
	class TrackInfoSrc
	{
	public:
		WORD		nbr_s_tracks;	// Nombre de voies sources
		PLAY_SOURCE_TRACK_CONF_BLOCK	track_conf [GTK_NBRTRACKS_MAXI];	// Config des sources
	};

	// Information de mixage pour les pistes d'effets
	class TrackInfoFx
	{
	public:
		FxPreset_EFFECT_CONF	conf;	// Configuration de l'effet, vue par la partition
		union
		{
			FxInternalDelay		delay;
			FxInternalResFilt		resfilt;
			FxInternalDisto		disto;
		}			internal;		// Configuration interne de l'effet
		WORD		old_effect;		// Numero de l'ancien effet, permet de savoir quand on doit de/reinstaller les effets
		WORD		effect;			// Numero de l'effet
		bool		bypass_flag;	// Indique que l'effet est court-circuite
		bool		update_flag;	// Indique que certains parametres ou buffers doivent etre recalcules avant application de l'effet.
		bool		bad_init_flag;	// Indique que les buffers n'ont pas pu etre alloues correctement. L'init est a refaire au prochain tick. En attendant, l'effet ne doit pas etre effectue.
	};

	// Information sur chaque piste (mixage seulement)
	class TrackInfoMix
	{
	public:
		TrackInfoSpl	spl;		// Actually this part is common for all kinds of voices. Only the sample part of the voice is specific to the SPL tracks.
		TrackInfoAIn	ain;
		TrackInfoFx		fx;
		TrackInfoSrc	src;
	};

	// Informations sur chaque piste (partition seulement)
	class TrackInfoScore
	{
	public:
		class Score
		{
		public:
			WORD		note;			// Note
			WORD		instr;		// Instrument
			UWORD		effect;		// Effet + Parametre (mot du type de la machine)
			UWORD		effect_par;	// Parametre de l'effet, en clair
			WORD		volume;		// Volume
			ULWORD	fx_data;		// Effet pour les pistes d'effets (mot du type de la machine)
			LWORD		fx_par;		// Parametre de l'effet, en clair
			ULWORD	mid_data;	// Donnees Midi pour les pistes MIDI (mot du type de la machine)
		};
		Score		score;			// Donnees directement prelevees sur la partition

		WORD		instr;			// Numero de l'instrument courant
		WORD		note;				// La note MIDI courante
		WORD		velocity_lin;	// Velocite de la note, lineaire 000...800
		WORD		velocity_log;	// Velocite de la note, logarithmique 000...800
		WORD		velocity_loc;	// Velocite locale, lineaire. Modifiee par les tremolos 000...800
		float		period;        // Periode de la note
		float		period_loc;		// Periode locale. Modifiee par les vibratos et arpeggios
		bool		changed_volume_flag;	// Mis a 1 si on change une composante du volume et qu'il faut le recalculer

		class Track
		{
		public:
			UWORD		volume_lin;	// Volume de la piste, lineaire 0000...1000...FFFF
			UWORD		volume_log;	// Volume de la piste, logarithmique 0000...C00...1000.
			UWORD		panning;		// Panning de la piste 0000...8000...FFFF
			UWORD		dryvol_lin;	// Volume dry de la piste, lineaire (FX seulement)
			UWORD		dryvol_log;	// Volume dry de la piste, logarithmique (FX seulement)
			UWORD		drypan;		// Panning dry de la piste 0000...8000...FFFF (FX seulement)
			UWORD		lin_vol_speed;			// Vitesse des slides de volume lineaires
			UWORD		lin_vol_fine_speed;	// Vitesse des fine slides de volume lineaires
			UWORD		log_vol_speed;			// Vitesse des slides de volume logarithmiques
			UWORD		log_vol_fine_speed;	// Vitesse des fine slides de volume logarithmiques
		};
		Track		track;

		class Sample
		{
		public:
			WORD		number;		// Numero du sample
			WORD		volume;		// Volume 000...100...FFF
			SWORD		transp;		// Transposition
			SWORD		finetune;	// Finetune
		};
		Sample	sample;			// Sample courant

		class Offset
		{
		public:
			LWORD		pos_int;		// Position entiere
			ULWORD	pos_frac;	// Position fractionnelle
		};
		Offset	offset;			// Dernier parametre des commandes Sample offset

		WORD		arpeggio_cnt;	// Compteur de l'arpeggio

		class Porta
		{
		public:
			WORD		note;			// Note MIDI a atteindre
			float		period;		// Periode a atteindre ...1AC0...
			WORD		speed;		// Vitesse 0...FF0
			WORD		fine_speed;	// Vitesse du Fine Tone Portamento
		};
		Porta		porta;			// Portamento et Tone Portamento

		class Vibrato
		{
		public:
			UBYTE		speed;		// Vitesse 0...40
			UBYTE		cnt;			// Compteur 0...FF
			UBYTE		amp;			// Amplitude 0...F
			UBYTE		waveform;	// Forme d'onde 0...3
		};
		Vibrato	vibrato;

		class Tremolo
		{
		public:
			UBYTE		speed;		// Vitesse 0...40
			UBYTE		cnt;			// Compteur 0...FF
			UBYTE		amp;			// Amplitude 0...F
			UBYTE		waveform;	// Forme d'onde 0...3
		};
		Tremolo	tremolo;

		class Tremor
		{
		public:
			WORD			cnt;		// Compteur
			UBYTE			on;		// Nombre de ticks pendant lesquels la note est active
			UBYTE			period;	// Periode totale ( >= on)
		};
		Tremor	tremor;

		class Roll
		{
		public:
			UBYTE		speed;		// Vitesse
			UBYTE		cnt;			// Compteur
			SWORD		nbr;			// Nombre de roulement restant a jouer. Negatif: pas de limite.
		};
		Roll		roll;				// Roulements

		class Delay
		{
		public:
			WORD		play;			// Nombre de ticks avant de jouer la note
			WORD		cut;			// Nombre de ticks avant de couper la note
		};
		Delay		delay;

		class PLoop
		{
		public:
			SWORD		songpos;		// Position de repetition. Si elle est negative, aucun debut de boucle n'a ete enregistre.
			WORD		linepos;		// Ligne de repetition
			WORD		cnt;			// Compteur
		};
		PLoop		ploop;			// Pattern Loop

		class VolSlide
		{
		public:
			WORD		speed;		// Vitesse du Volume Slide
			WORD		fine_speed;	// Vitesse du Fine Volume Slide
		};
		VolSlide	vol_slide;

		class PanSlide
		{
		public:
			WORD		speed;		// Vitesse du Panning Slide
		};
		PanSlide	pan_slide;

		class Filter
		{
		public:
			bool		filter_flag;	// Indique que le filtre est actif
			bool		freq_vol_flag;	// Indique que la velocite influe sur la frequence
			bool		q_vol_flag;	// Indique que la velocite influe sur la resonnance
			double	freq [2];	// Frequences aux volumes max et min. <= 20.0 : multiple de la frequence de la note
			double	q [2];		// Resonnance aux volumes max et min
		};
		Filter	lpf;				// Filtre passe-bas

		class Effect
		{
		public:
			class Time
			{
			public:
				double	speed;	// Parametres par defaut pour des increments/decrements de temps
				double	time;		// Temps a atteindre en cas de portamento
			};
			Time		time [FX_NBR_TIME_SPEED];

			class Freq
			{
			public:
				double	speed;	// Parametres par defaut pour des increments/decrements de frequence
				double	freq;		// Frequence a atteindre en cas de portamento
			};
			Freq		freq [FX_NBR_FREQ_SPEED];
		};
		Effect	fx;				// Partie reservee aux effets
	};

	// Informations sur chaque piste (totales)
	class TrackInfo
	{
	public:
		TrackInfoMix	mix;
		TrackInfoScore	score;
		WORD				track;			// Numero de la piste dans sa categorie
		WORD				track_type;		// Type de la piste
		WORD				stereo;			// Stereo (1 ou 2)
		UWORD				outvol;			// Volume instantane de sortie 0...1000...FFFF = volume piste * velocite * enveloppes. Pour les pistes de sample, c'est le Voice::_outvol qui est utilise.
		UWORD				outpan;			// Balance instantanee de sortie 0...8000...FFFF. Pour les pistes de sample, c'est le Voice::_outpan qui est utilise.
		UWORD				dry_outvol;		// Volume instantane de sortie dry 0...1000...FFFF (FX seulement)
		UWORD				dry_outpan;		// Balance instantanee de sortie dry 0...8000...FFFF (FX seulement)
		bool				wet_mute_flag;	// Mute wet
		bool				dry_mute_flag;	// Mute dry (FX seulement)
		char				name [TRK_NAME_LEN];	// Nom de la piste
	};

	// Informations sur la partition
	class ScoreInfo
	{
	public:
		LWORD		tick_len_int;	// Longueur du tick, en samples
		ULWORD	tick_len_frac;	// Longueur du tick, partie fractionnaire
		LWORD		frame_pos_int;	// Position de la frame courante dans le tick (en samples)
		ULWORD	frame_pos_frac;	// Partie fracionnaire de la position de la frame dans le tick. Ne sert que pour les caculs inter_ticks
		LWORD		frame_len;		// Longueur de la frame courante (en samples)

		WORD		tempo_int;		// Tempo (BPM), partie entiere
		UWORD		tempo_frac;		// Partie fractionnelle du tempo
		WORD		frame_counter;	// Incremente a chaque frame 0 <= counter < nbr
		WORD		nbr_frames;		// Nombre de frames par tick
		WORD		time_high;		// Nombre de temps par mesure
		WORD		time_low;		// Subdivision de la ronde donnant le temps. Ne peut etre qu'une puissance de 2, de 1 (ronde) a 16 (double-croche = ligne)

		WORD		tick_counter;	// Incremente a chaque tick. 0 <= counter < speed
		WORD		speed;			// Nombre de ticks par ligne
		WORD		pattern_delay;	// Multiplicateur - 1 de la duree de la ligne. Normalement a 0.
		WORD		current_line;	// Numero de la ligne actuelle
		WORD		current_pos;	// Numero de la position actuelle dans la partition
		WORD		next_line;		// Calcul de la prochaine ligne. Est mise a 0 par defaut.
		WORD		next_pos;		// Calcul de la prochaine position
		bool		next_flag;		// true indique qu'on a devie de la trajectoire habituelle et qu'on doit chercher la prochaine ligne dans next_...
		bool		linear_period_flag;	// true indique que la periode est lineaire (false = amiga)

		WORD		current_pattern;	// Numero du pattern courant

		int		current_play_mode;	// Mode de replay (song, pattern, stop)
	};



	// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	// Functions

	virtual			~Player () {}
	static Player &
						use_instance ();

	int				read_conf (const std::list <ConfigKey> &key_list);

	int				first_init ();
	void				first_restore ();
	int				second_init ();
	void				second_restore ();
	int				start_player ();
	void				stop_player ();
	bool				get_player_started_flag ();

	void				add_new_track (int track_type, int nbr_tracks);
	void				set_replay_freq (long freq);
	void				main_interrupt ();
	void				handle_score ();

	/*** To do: Virer les parametres TrackInfo ? En faire des fonction membres ? ***/
	void				set_new_note (TrackInfo &track_info);
	void				set_lin_velocity (TrackInfo &track_info, int velo);
	void				set_log_velocity (TrackInfo &track_info, int velo);
	void				set_lin_volume (TrackInfo &track_info, long lin_vol);
	void				set_log_volume (TrackInfo &track_info, int log_vol);
	void				set_dry_lin_volume (TrackInfo &track_info, long lin_vol);
	void				set_dry_log_volume (TrackInfo &track_info, int log_vol);
	void				set_period (TrackInfo &track_info, float period);
	void				set_panning (TrackInfo &track_info, bool dry_flag, long pan);

	//----------------------------------------------
	// Interfacage avec l'exterieur
	//----------------------------------------------

	int				get_play_mode () const;
	void				set_play_mode (int play_mode, int position, int line, bool cont_flag);
	void				wait_for_new_play_mode ();
	void				clear_all_effects ();
	void				silence_all_effect_buffers ();
	int				get_song_position () const;
	void				set_song_position (int songpos);
	int				get_line_position () const;
	void				set_line_position (int linepos);
	int				get_current_tick () const;
	void				get_elapsed_time (int &minutes, int &seconds, int &miliseconds) const;
	void				reset_elapsed_time ();
	void				reset_mix_parameters ();
	int				add_source_track (int track_type, int track_nbr, const PLAY_SOURCE_TRACK_CONF_BLOCK *new_track_conf_ptr, int flags);
	int				change_source_track (int track_type, int track_nbr, int position, const PLAY_SOURCE_TRACK_CONF_BLOCK *new_track_conf_ptr);
	int				remove_source_track (int track_type, int track_nbr, const PLAY_SOURCE_TRACK_CONF_BLOCK *new_track_conf_ptr);
	bool				check_track_validity (int track_type, int track_nbr) const;
	int				check_track_is_in_sources (int track_type, int track_nbr, int *position_ptr, const PLAY_SOURCE_TRACK_CONF_BLOCK *new_track_conf_ptr);
	int				find_track_to_add (int track_type, int track_nbr, PLAY_SOURCE_TRACK_CONF_BLOCK *new_track_conf_ptr);
	bool				find_track_loop (int track, int track_to_find);
	int				get_track_nbr_s_tracks (int track_type, int track_nbr, int *nbr_s_tracks_ptr, PLAY_SOURCE_TRACK_CONF_BLOCK **track_conf_ptr_ptr);
	int				load_mix_preset (int track_type, int track_nbr, int preset_nbr, int flags);
	int				save_mix_preset (int track_type, int track_nbr, int preset_nbr);
	int				update_aou_source_tracks_with_aou_source_conf (int track_nbr);
	int				update_aou_source_conf_with_aou_source_tracks (int track_nbr);
	void				get_track_name (int track_type, int track_nbr, char *name_0) const;
	void				set_track_name (int track_type, int track_nbr, const char *name_0);
	bool				get_track_onoff (int track_type, int track_nbr, bool dry_flag) const;
	void				set_track_onoff (int track_type, int track_nbr, bool dry_flag, bool state);
	LWORD				get_track_panning (int track_type, int track_nbr, bool dry_flag) const;
	void				set_track_panning (int track_type, int track_nbr, bool dry_flag, LWORD pan);
	LWORD				get_track_lin_volume (int track_type, int track_nbr, bool dry_flag) const;
	void				set_track_lin_volume (int track_type, int track_nbr, bool dry_flag, LWORD volume);
	LWORD				get_track_log_volume (int track_type, int track_nbr, bool dry_flag) const;
	void				set_track_log_volume (int track_type, int track_nbr, bool dry_flag, LWORD volume);
	static LWORD	lin_to_log_volume (LWORD lin_vol);
	static LWORD	log_to_lin_volume (LWORD log_vol);
	int				get_track_stereo (int track_type, int track_nbr, bool dry_flag) const;
	int				set_track_stereo (int track_type, int track_nbr, int stereo);
	double			get_tempo () const;
	void				set_tempo (double tempo);
	int				get_speed () const;
	void				set_speed (int speed);
	LWORD				get_lin_master_volume ();
	void				set_lin_master_volume (LWORD vol);
	LWORD				get_log_master_volume ();
	void				set_log_master_volume (LWORD vol);
	bool				get_interpolation_flag (int track);
	void				set_interpolation_flag (int track, bool interpol_flag);
	void				set_interpolation_flag (TrackInfo &track_info, bool interpol_flag);
	void				no_mute ();
	void				invert_all_mute ();
	void				default_interpolation ();
	float				get_clipping_level (int track) const;
	void				set_clipping_level (int track, float level);
	float				get_max_clipping_level () const;
	void				set_max_clipping_level (float level);
	void				get_bar_time (int &high, int &low) const;
	void				set_bar_time (int high, int low);
	int				get_bar_length () const;
	int				get_fx_preset (int track, int preset) const;
	int				set_fx_preset (int track, int preset, long auto_val = 0);
	bool				get_bypass_flag (int track) const;
	void				set_bypass_flag (int track, bool bypass_flag);

	void				play_sound (int track, int sample, long start_pos);
	void				play_pattern_line_spl ();
	void				play_pattern_line_ain ();
	void				play_pattern_line_fx ();
	void				play_pattern_line_mid ();

	bool				get_linear_period_flag () const;
	void				set_linear_period_flag (bool flag);

	//----------------------------------------------
	// Misc
	//----------------------------------------------

	int				convert_freq_to_note (double freq, double &finetune) const;
	double			convert_note_to_freq (int note, double finetune) const;
	double			convert_period_to_freq (float period) const;
	double			convert_rel_freq_to_period (double freq) const;
	double			convert_period_to_rel_freq (float period) const;
	double			convert_period_to_rel_per (float period) const;
	double			convert_period_to_time (float period) const;
	double			convert_note_to_internal_period (int note, int finetune) const;



	// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	// Data

	int				_track_info_list [GTK_NBR_MIX_TRACK_TYPE] [GTK_NBRTRACKS_MAXI];	// Tableau des numeros de _track_info pour chaque type de piste
	TrackInfo		_track_info [NBR_GLOBAL_TRACKS];	// Blocs d'informations de chaque piste
	Voice				_voice_arr [MAX_NBR_VOICES];	// Resampling voices (for SPL tracks)
	ScoreInfo		_score_info;	// Bloc d'info pour la partition

	// Lignes de pattern pour le replay de notes instantanne
	volatile UBYTE	_new_spl_notes [GTK_NBRTRACKS_MAXI * MODS_GT2_SPL_NOTE_LEN];
	volatile UBYTE	_new_ain_notes [GTK_NBRTRACKS_MAXI * MODS_GT2_AIN_NOTE_LEN];
	volatile UBYTE	_new_fx_notes [GTK_NBRTRACKS_MAXI * MODS_GT2_FX_NOTE_LEN];
	volatile UBYTE	_new_mid_notes [GTK_NBRTRACKS_MAXI * MODS_GT2_MID_NOTE_LEN];
	volatile UBYTE	_new_line_flag [Pattern_NBR_TYPES];	// Les flags indiquent qu'une des lignes a ete remplie
	volatile UBYTE	_new_note_flag [Pattern_NBR_TYPES] [GTK_NBRTRACKS_MAXI];	// Les flags indiquent les nouvelles notes pour chaque ligne

	static const SWORD
						_sin_table [4] [64];

	static UBYTE	_fx_command_format_ptr [FxPreset_NBR_TYPES] [0x100];	// Tableau donnant le type de sous-format pour les parametres de chaque effet



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:

	// ThreadCbInterface
	virtual void	do_run_thread ();



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

	// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	// Types

	typedef	void (Player::*TrackFncPtr) (TrackInfo &track_info);
	typedef	TrackFncPtr	TrackFncPtrFxCmdArr [0x100] [2];

	class TrackTypeAddDel
	{
	public:
		int		track_type;
		bool		wet_flag;
	};



	// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	// Functions

						Player ();

	//----------------------------------------------
	// Generic
	//----------------------------------------------

	int				set_replay_format ();

	void				copy_line_to_track_info ();

	void				handle_effects_1st_tick ();
	void				handle_effects_all_ticks ();

	void				compute_final_parameters ();
	void				compute_final_parameters_track (int track_type, int track);

	void				reset_all_tracks ();
	void				reset_track_partition_info (TrackInfo &track_info);

	int				set_nbr_source_tracks (int track_type, int track_nbr, int nbr_src);

	int				allocate_voice ();
	void				deallocate_voice (int voice_index);
	void				init_filter (TrackInfo &track_info);
	int				cut_note (TrackInfo &track_info);
	int				retrig_note (TrackInfo &track_info);
	int				cut_or_dup_note (TrackInfo &track_info, bool dup_flag);
	void				kill_inactive_ghost_voices ();
	Voice &			use_main_voice (TrackInfo &track_info);

	static void		init_constants ();
	static void		copy_track_conf_without_state (PLAY_SOURCE_TRACK_CONF_BLOCK &dst, const PLAY_SOURCE_TRACK_CONF_BLOCK &src);	/*** To do: make it a member of the structure ***/

	//----------------------------------------------
	// Envelopes
	//----------------------------------------------

	void				env_manage_all_envelopes ();
	void				env_manage_envelope (int track_type, int track);

	//----------------------------------------------
	// Commands
	//----------------------------------------------

	// Main acces
	void				cmd_manage_effects_1st_tick_spl (int track);
	void				cmd_manage_effects_1st_tick_ain (int track);
	void				cmd_manage_effects_1st_tick_fx (int track);
	void				cmd_manage_effects_1st_tick_mid (int track);

	void				cmd_manage_effects_all_ticks_spl (int track);
	void				cmd_manage_effects_all_ticks_ain (int track);
	void				cmd_manage_effects_all_ticks_fx (int track);
	void				cmd_manage_effects_all_ticks_mid (int track);

	// Effets, premier tick de la ligne
	void				cmd_nop (TrackInfo &track_info);
	void				cmd_detune (TrackInfo &track_info);
	void				cmd_delay_init (TrackInfo &track_info);
	void				cmd_cut_note_init (TrackInfo &track_info);
	void				cmd_jump_pos (TrackInfo &track_info);
	void				cmd_set_vibrato_waveform (TrackInfo &track_info);
	void				cmd_break_pattern (TrackInfo &track_info);
	void				cmd_set_tremolo_waveform (TrackInfo &track_info);
	void				cmd_set_tempo (TrackInfo &track_info);
	void				cmd_arpeggio_init (TrackInfo &track_info);
	void				cmd_fine_porta_up (TrackInfo &track_info);
	void				cmd_fine_porta_down (TrackInfo &track_info);
	void				cmd_roll_vol_slide_init (TrackInfo &track_info);
	void				cmd_fine_lin_vol_slide_up (TrackInfo &track_info);
	void				cmd_fine_lin_vol_slide_down (TrackInfo &track_info);
	void				cmd_fine_lin_master_vol_slide_up (TrackInfo &track_info);
	void				cmd_fine_lin_master_vol_slide_down (TrackInfo &track_info);
	void				cmd_set_nbr_ticks (TrackInfo &track_info);
	void				cmd_set_fine_tempo (TrackInfo &track_info);
	void				cmd_pattern_delay (TrackInfo &track_info);
	void				cmd_tremor_init (TrackInfo &track_info);
	void				cmd_pattern_loop (TrackInfo &track_info);
	void				cmd_set_flags (TrackInfo &track_info);
	void				cmd_set_vol_env (TrackInfo &track_info);
	void				cmd_set_tone_env (TrackInfo &track_info);
	void				cmd_set_pan_env (TrackInfo &track_info);
	void				cmd_set_cutoff_env (TrackInfo &track_info);
	void				cmd_set_reso_env (TrackInfo &track_info);
	void				cmd_demo_synchro (TrackInfo &track_info);
	void				cmd_fine_sample_offset (TrackInfo &track_info);
	void				cmd_very_fine_sample_offset (TrackInfo &track_info);
	void				cmd_inc_sample_pos (TrackInfo &track_info);
	void				cmd_dec_sample_pos (TrackInfo &track_info);
	void				cmd_set_mix_preset (TrackInfo &track_info);
	void				cmd_set_lin_track_vol (TrackInfo &track_info);
	void				cmd_set_log_track_vol (TrackInfo &track_info);
	void				cmd_fine_log_track_vol_slide_up (TrackInfo &track_info);
	void				cmd_fine_log_track_vol_slide_down (TrackInfo &track_info);
	void				cmd_set_lin_vol (TrackInfo &track_info);
	void				cmd_set_log_vol (TrackInfo &track_info);
	void				cmd_set_pan (TrackInfo &track_info);
	void				cmd_set_lin_master_vol (TrackInfo &track_info);
	void				cmd_set_log_master_vol (TrackInfo &track_info);
	void				cmd_roll_init (TrackInfo &track_info);
	void				cmd_roll_vol_slide_set_pan_init (TrackInfo &track_info);
	void				cmd_set_mix_preset_source_only (TrackInfo &track_info);
	void				cmd_add_source_tracks (TrackInfo &track_info);
	void				cmd_change_source_track_vol (TrackInfo &track_info);
	void				cmd_change_source_track_pan (TrackInfo &track_info);
	void				cmd_sample_offset (TrackInfo &track_info);

	// Effets, tous les ticks
	void				cmd_porta_up (TrackInfo &track_info);
	void				cmd_porta_down (TrackInfo &track_info);
	void				cmd_tone_porta (TrackInfo &track_info);
	void				cmd_vibrato (TrackInfo &track_info);
	void				cmd_tone_porta_vibrato (TrackInfo &track_info);
	void				cmd_vibrato_tone_porta (TrackInfo &track_info);
	void				cmd_tremolo (TrackInfo &track_info);
	void				cmd_delay (TrackInfo &track_info);
	void				cmd_cut_note (TrackInfo &track_info);
	void				cmd_arpeggio (TrackInfo &track_info);
	void				cmd_roll_vol_slide (TrackInfo &track_info);
	void				cmd_lin_vol_slide_up (TrackInfo &track_info);
	void				cmd_lin_vol_slide_down (TrackInfo &track_info);
	void				cmd_log_vol_slide_up (TrackInfo &track_info);
	void				cmd_log_vol_slide_down (TrackInfo &track_info);
	void				cmd_lin_vol_slide_up_tone_porta (TrackInfo &track_info);
	void				cmd_lin_vol_slide_down_tone_porta (TrackInfo &track_info);
	void				cmd_log_vol_slide_up_tone_porta (TrackInfo &track_info);
	void				cmd_log_vol_slide_down_tone_porta (TrackInfo &track_info);
	void				cmd_lin_vol_slide_up_vibrato (TrackInfo &track_info);
	void				cmd_lin_vol_slide_down_vibrato (TrackInfo &track_info);
	void				cmd_log_vol_slide_up_vibrato (TrackInfo &track_info);
	void				cmd_log_vol_slide_down_vibrato (TrackInfo &track_info);
	void				cmd_lin_master_vol_slide_up (TrackInfo &track_info);
	void				cmd_lin_master_vol_slide_down (TrackInfo &track_info);
	void				cmd_extra_fine_tone_porta (TrackInfo &track_info);
	void				cmd_extra_fine_porta_up (TrackInfo &track_info);
	void				cmd_extra_fine_porta_down (TrackInfo &track_info);
	void				cmd_left_balance_move (TrackInfo &track_info);
	void				cmd_right_balance_move (TrackInfo &track_info);
	void				cmd_tremor (TrackInfo &track_info);
	void				cmd_auto_tempo (TrackInfo &track_info);
	void				cmd_auto_period (TrackInfo &track_info);
	void				cmd_lin_track_vol_slide_up (TrackInfo &track_info);
	void				cmd_lin_track_vol_slide_down (TrackInfo &track_info);
	void				cmd_log_track_vol_slide_up (TrackInfo &track_info);
	void				cmd_log_track_vol_slide_down (TrackInfo &track_info);
	void				cmd_change_sample_direction (TrackInfo &track_info);
	void				cmd_roll (TrackInfo &track_info);
	void				cmd_roll_vol_slide_set_pan (TrackInfo &track_info);

	// Effets de la colonne de volume, premier tick de la ligne
	void				cmd_volfx_fine_lin_vol_slide_down (TrackInfo &track_info);
	void				cmd_volfx_fine_lin_vol_slide_up (TrackInfo &track_info);
	void				cmd_volfx_set_panning (TrackInfo &track_info);

	// Effets de la colonne de volume, tous les ticks
	void				cmd_volfx_vol_slide_down (TrackInfo &track_info);
	void				cmd_volfx_vol_slide_up (TrackInfo &track_info);
	void				cmd_volfx_set_vibrato_speed (TrackInfo &track_info);
	void				cmd_volfx_vibrato (TrackInfo &track_info);
	void				cmd_volfx_pan_slide_left (TrackInfo &track_info);
	void				cmd_volfx_pan_slide_right (TrackInfo &track_info);
	void				cmd_volfx_tone_portamento (TrackInfo &track_info);

	// Fonctions communes a plusieurs effets
	void				cmd_do_sample_offset (TrackInfo &track_info, LWORD pos_int, ULWORD pos_frac);
	void				cmd_do_tone_porta (TrackInfo &track_info, int speed);
	void				cmd_do_vibrato (TrackInfo &track_info, int param);
	void				cmd_do_lin_vol_slide_up (TrackInfo &track_info, int speed);
	void				cmd_do_lin_vol_slide_down (TrackInfo &track_info, int speed);
	void				cmd_do_pan_slide_left (TrackInfo &track_info, long speed);
	void				cmd_do_pan_slide_right (TrackInfo &track_info, long speed);
	void				cmd_do_set_mix_preset (TrackInfo &track_info, int preset, int flags);

	//----------------------------------------------
	// Effect commands
	//----------------------------------------------

	//=== Main access ===//

	int				fx_init ();
	void				fx_restore ();

	// Routines generales
	void				fx_fx_set_preset (TrackInfo &track_info, const FxPreset_EFFECT_CONF &conf, int effect_type, long auto_val = 0);
	void				fx_fx_get_preset (const TrackInfo &track_info, FxPreset_EFFECT_CONF &conf, int &effect_type) const;
	void				fx_fx_set_default_parameters (TrackInfo &track_info);
	int				fx_fx_init (TrackInfo &track_info);
	int				fx_fx_set_stereo (TrackInfo &track_info, int stereo);
	int				fx_fx_silence (TrackInfo &track_info);
	int				fx_fx_update (TrackInfo &track_info);
	void				fx_fx_restore (TrackInfo &track_info);

	void				fx_manage_1st_tick (TrackInfo &track_info);
	void				fx_manage_all_ticks (TrackInfo &track_info);

	// Delay
	void				fx_delay_set_default_parameters (TrackInfo &track_info);
	int				fx_delay_init (TrackInfo &track_info);
	int				fx_delay_set_stereo (TrackInfo &track_info, int stereo);
	int				fx_delay_silence (TrackInfo &track_info);
	int				fx_delay_update (TrackInfo &track_info);
	void				fx_delay_restore (TrackInfo &track_info);

	// Filtre resonnant
	void				fx_resfilt_set_default_parameters (TrackInfo &track_info);
	int				fx_resfilt_init (TrackInfo &track_info);
	int				fx_resfilt_set_stereo (TrackInfo &track_info, int stereo);
	int				fx_resfilt_silence (TrackInfo &track_info);
	int				fx_resfilt_update (TrackInfo &track_info);
	void				fx_resfilt_restore (TrackInfo &track_info);

	// Distorsion
	void				fx_disto_set_default_parameters (TrackInfo &track_info);
	int				fx_disto_init (TrackInfo &track_info);
	int				fx_disto_set_stereo (TrackInfo &track_info, int stereo);
	int				fx_disto_silence (TrackInfo &track_info);
	int				fx_disto_update (TrackInfo &track_info);
	void				fx_disto_restore (TrackInfo &track_info);

	//=== Internal ===//

	// Gengeral
	void				fx_general_add_track (TrackInfo &track_info);
	void				fx_general_remove_track (TrackInfo &track_info);
	void				fx_general_apply_preset (TrackInfo &track_info);
	void				fx_general_remove_fx (TrackInfo &track_info);
	void				fx_general_mute_input_tracks (TrackInfo &track_info);
	void				fx_general_set_stereo (TrackInfo &track_info);

	// Delay
	void				fx_delay_activate (TrackInfo &track_info);
	void				fx_delay_modify_time_1st_tick (TrackInfo &track_info);
	void				fx_delay_modify_feedback_1st_tick (TrackInfo &track_info);
					
	void				fx_delay_modify_time_all_ticks (TrackInfo &track_info);
	void				fx_delay_modify_feedback_all_ticks (TrackInfo &track_info);
					
	void				fx_delay_do_set_time (TrackInfo &track_info, double delay_time);
	void				fx_delay_do_set_feedback (TrackInfo &track_info, double feedback);

	// Filtre resonnant
	void				fx_resfilt_activate (TrackInfo &track_info);
	void				fx_resfilt_modify_freq_1st_tick (TrackInfo &track_info);
	void				fx_resfilt_modify_q_1st_tick (TrackInfo &track_info);
	void				fx_resfilt_modify_nbr_biq_1st_tick (TrackInfo &track_info);
	void				fx_resfilt_modify_lfo_freq_1st_tick (TrackInfo &track_info);
	void				fx_resfilt_modify_lfo_depth_1st_tick (TrackInfo &track_info);
	void				fx_resfilt_set_lfo_waveform (TrackInfo &track_info);
	void				fx_resfilt_set_lfo_phase (TrackInfo &track_info);
	void				fx_resfilt_modify_cell_ratio_1st_tick (TrackInfo &track_info);
					
	void				fx_resfilt_modify_freq_all_ticks (TrackInfo &track_info);
	void				fx_resfilt_modify_q_all_ticks (TrackInfo &track_info);
	void				fx_resfilt_modify_nbr_biq_all_ticks (TrackInfo &track_info);
	void				fx_resfilt_modify_lfo_freq_all_ticks (TrackInfo &track_info);
	void				fx_resfilt_modify_lfo_depth_all_ticks (TrackInfo &track_info);
	void				fx_resfilt_modify_cell_ratio_all_ticks (TrackInfo &track_info);

	// Distorsion
	void				fx_disto_activate (TrackInfo &track_info);
	void				fx_disto_modify_gain_1st_tick (TrackInfo &track_info);
	void				fx_disto_modify_sec_gain_1st_tick (TrackInfo &track_info);
	void				fx_disto_modify_threshold_1st_tick (TrackInfo &track_info);
					
	void				fx_disto_modify_gain_all_ticks (TrackInfo &track_info);
	void				fx_disto_modify_sec_gain_all_ticks (TrackInfo &track_info);
	void				fx_disto_modify_threshold_all_ticks (TrackInfo &track_info);

	// Divers
	bool				fx_param_to_double_1st_tick (LWORD param, double &val, double &inc, double scale, bool zero_flag);
	bool				fx_param_to_double_all_ticks (LWORD param, double &val, double &inc, double scale);
	bool				fx_param_to_int_1st_tick (LWORD param, int &val, int &inc, int scale);
	bool				fx_param_to_int_all_ticks (LWORD param, int &val, int &inc, int scale);
	bool				fx_param_to_time_1st_tick (TrackInfo &track_info, LWORD param, double &val, double &inc, double &to_reach);
	bool				fx_param_to_time_all_ticks (TrackInfo &track_info, LWORD param, double &val, double &inc, double to_reach);
	bool				fx_param_to_freq_1st_tick (TrackInfo &track_info, LWORD param, double &val, double &inc, double &to_reach);
	bool				fx_param_to_freq_all_ticks (TrackInfo &track_info, LWORD param, double &val, double &inc, double to_reach);
					
	bool				fx_beat_to_freq (LWORD param, double &freq);
	bool				fx_beat_to_time (LWORD param, double &sec);



	// -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	// Data

	Thread			_player_thread;
	int				_player_thread_state;	// Indique l'etat du thread. 0 = en cours d'init, 1 = ok, -1 = erreur d'init
	bool				_player_started_flag;	// Indique que le player est demarre

	volatile int	_current_linepos;	// Donnee valide en mode Pattern et Song
	volatile int	_current_songpos;	// Donnee valide en mode Pattern

	// Nouveau mode de replay
	volatile int	_new_play_mode;
	volatile	bool	_new_play_mode_flag;
	volatile bool	_new_play_mode_cont_flag;
	volatile int	_new_linepos;
	volatile int	_new_songpos;

	/* Tableau indiquant si une voie de sortie a clippe ou pas.
		S'il n'y a pas clipping, la variable vaut 0 ou toute autre valeur positive
		representable sur 24 bits signes. En cas de clipping, la valeur indique la
		valeur absolue du plus haut pic atteint. */
	float				_clipping_level [GTK_NBROUT_MAXI];

	/* Memorisation du niveau de clipping pour toutes les voies. Ce niveau n'est
		remis a 0 que par l'utilisateur exterieur (interface) */
	volatile float	_max_clipping_level;

	// Duree ecoulee depuis le debut du playback
	volatile long	_elapsed_time;	// Samples

	// Indique l'etat d'interpolation par defaut des pistes
	bool				_default_interpolation_flag;

	// Stack of free voices. Memory is pre-reserved so it can be grown real-time.
	std::vector <int>
						_free_voice_stack;

	// Table des periodes. De C#-2 a G+8 en 16emes de ton, +/- 3/2 tons de securite
	static float	_note_period_table [(3+(GTK_NBRNOTES_MAXI-1)+3)*8];
	// Table des periodes pour chaque finetune, indexee a partir de 0
	static float *	_note_period_table_ref;

	// Tables exp/log
	static UWORD	_instr_vol_table_exp [0x801];	// exp(x): volumes instruments
	static UWORD	_instr_vol_table_log [0x801];	// ln(x): volumes instruments
	static UWORD	_track_vol_table_exp [0x100];	// exp(x): volumes pistes
	static UWORD	_track_vol_table_log [0x100];	// ln(x): volumes pistes

	// Effets: 00xx-1Fxx, A0xx-CFxx, 0xxx-Fxxx
	static const TrackFncPtr
						_cmd_effect_1st_tick_ptr [3] [0x60];
	static const TrackFncPtr
						_cmd_effect_all_ticks_ptr [3] [0x60];

	// Effets de la colonne de volume (a partir de 0x6?)
	static const TrackFncPtr
						_cmd_vol_effect_1st_tick_ptr [3] [10];
	static const TrackFncPtr
						_cmd_vol_effect_all_ticks_ptr [3] [10];

	// Granularite du buffer de delay, en samples. Doit etre une puissance de 2
	static const long
						_fx_delay_buffer_granul;
	// Pointeurs sur les fonctions des commandes generales
	static const TrackFncPtr
						_fx_general_command_ptr [0x40] [2];

	// Pointeur sur un tableau de pointeurs sur les fonctions de gestion des commandes des effets
	static TrackFncPtrFxCmdArr
						_fx_effect_command_ptr [FxPreset_NBR_TYPES];

	// Types de pistes a utiliser dans les commandes d'effets
	static const TrackTypeAddDel
						_fx_track_type_list [4];



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

						Player (const Player &other);
	Player &			operator = (const Player &other);
	bool				operator == (const Player &other);
	bool				operator != (const Player &other);

};	// class Player



//#include	"Player.hpp"



#endif	// Player_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
