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

        Voice.h
        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.

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



#if ! defined (Voice_HEADER_INCLUDED)
#define	Voice_HEADER_INCLUDED

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



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

#include	"archi.h"
#include	"D2dBuffer.h"
#include	"EnvSet.h"
#include	"GainSmooth.h"
#include	"splhandl.h"
#include	"StereoGain.h"

#include	<cstdio>



class ReconstructionFilter;

class Voice
{

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

public:

						Voice ();
	virtual			~Voice () {}

	void				copy_state (const Voice &other);

	void				start_sample (int spl_index);
	void				cut ();
	void				deactivate ();
	bool				is_active () const;
	bool				has_generated_something () const;
	bool				is_compatible_with_group (int group) const;

	void				process_post (float spl_ptr [], long nbr_spl, int stereo);
	void				process_post ();

	class Sample
	{
	public:

		class D2d
		{
		public:
			FILE *			file_ptr;		// Pointeur sur les informations du fichier, ou handle du fichier
			int64_t			file_data_offset;	// Offset des donnees dans le fichier
			void *			startbuf_ptr;	// Adresse du buffer de debut
			LWORD				startbuf_len;	// Longueur du buffer de debut
			LWORD				midbuf1_len;	// Longueur du buffer 1
			LWORD				midbuf2_len;	// Longueur du buffer 2

			D2dBuffer		_desc;
		};

							~Sample ();

		void				copy_state (const Sample &other);

		void				start (int spl_index);

		void				set_hq_interpolator (bool hq_flag);
		bool				has_hq_interpolator () const;

		void				set_rate (double rate);
		double			get_rate () const;

		void				set_playback_pos (long curpos_int, ULWORD curpos_frac);
		long				get_playback_pos_int () const;
		ULWORD			get_playback_pos_frac () const;
		bool				is_active () const;

		void				set_direction (bool back_flag);
		bool				is_running_backward () const;

		int				get_group () const;

		void				advance_cursor (long nbr_spl, double rate);

		void				process_block (float out_ptr [], long nbr_spl, int d_stereo, int voice_index);

		void *			sample_ptr;		// Adresse du sample (des donnees)
		void *			loopbuf_ptr;	// Adresse du buffer de bouclage
		LWORD				loopbuf_len;	// Taille du buffer de bouclage (sample)
		WORD				resol;			// Resolution (octets/sample)
		WORD				tracks;			// Stereo
		LWORD				reppos;			// Point de bouclage. Indique la longueur du sample si pas de boucle
		LWORD				replen;			// Longueur de la boucle. Doit etre nul si pas de boucle.
		LWORD				freq;				// Frequence d'echantillonnage
		WORD				loopmode;		// Type de bouclage (0 = rien, 1 = normal, 2 = ping-pong)
		bool				d2d_flag;		// Direct To Disk (flag)
		bool				interpol_flag;	// Interpolation (flag)
		ReconstructionFilter *			// Pointe sur un objet de filtre de reconstruction, NULL sinon.
							recons_filter_ptr;

		D2d				d2d;				// Uniquement D2D

	private:
		void				delete_hq_interpolator ();
		long				compute_len () const;

		int				linearise_data (SWORD *buffer_ptr, int voice_index, long nbr_spl) const;
		void				find_linear_block (int voice_index, long old_position, bool old_back_flag, long &position, bool &new_back_flag, void * &block_ptr, long &block_len, bool &back_flag) const;
		void				fill_buffer_end (SWORD *out_ptr, int d_stereo, long nbr_spl, bool back_flag) const;

		static void		resample_snh (const SWORD *in_ptr, float *out_ptr, long nbr_spl, int s_stereo, int d_stereo, SLWORD volume, ULWORD pos_frac, int freq_int, ULWORD freq_frac);
		static void		resample_lerp (const SWORD *in_ptr, float *out_ptr, long nbr_spl, int s_stereo, int d_stereo, SLWORD volume, ULWORD pos_frac, int freq_int, ULWORD freq_frac);

		int				_spl_index;
		int				_group;
		double			_rate;			// Resampling rate, > 0
		long				_curpos_int;	// Position courante (int)
		ULWORD			_curpos_frac;	// Position courante (frac)
		bool				_back_flag;		// Sens actuel de replay (false = forward, true = backward)
	};
	
	class Filter
	{
	public:
		enum {			BUF_LEN	= 1 << 2	};	// Must be a power of 2

		void				activate (double f1, double f2, double q1, double q2);
		void				deactivate ();
		bool				is_active () const;
		void				set_lerp_freq (double lerp_freq);
		void				set_lerp_q (double lerp_q);
		void				compute_final_data (double note_freq, const EnvSet &env_set);

		void				clear_buffers ();

		bool				_active_flag;
		double			_freq [2];		// Hz. <= 20: la frequence est un multiple de la frequence finale de la note
		double			_q [2];

		double			_lerp_freq;		// Lerp between frequencies, [0 ; 1]
		double			_lerp_q;			// Lerp between q's, [0 ; 1]

		double			_final_freq;	// Frequence reelle du filtre (avec les enveloppes).
		double			_final_q;		// Resonnance reelle du filtre.

		double			coef_x [3];		// Coefficients de l'IIR
		double			coef_y [3];
		double			buffer_y [BUF_LEN * 2];	// Buffers de l'IIR (mono ou stereo)
		float				buffer_x [BUF_LEN * 2];
		int				buffer_pos;
	};

	Sample			spl;
	Filter			filter;				// Filtre resonnant
	EnvSet			_env_set;

	float				_outperiod;			// Periode de sortie de la note
	int				_outvol;				// Volume instantane de sortie 0...1000...FFFF = volume piste * velocite * enveloppes.
	int				_outpan;				// Balance instantanee de sortie 0...8000...FFFF
	StereoGain		_cr;					// Anti-click gain



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

protected:



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

private:

	GainSmooth		_fadeout;
	bool				_gen_flag;



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

private:

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

};	// class Voice



//#include	"Voice.hpp"



#endif	// Voice_HEADER_INCLUDED



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