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

GRAOUMF TRACKER 2

Copyright (c) 1996 - 2002 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

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



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

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

#include "archi.h"
#include "base.h"
#include "base_ct.h"
#include "file.h"
#include "log.h"
#include "samp.h"
#include	"spl_avr.h"
#include "spl_raw.h"
#include "splstruc.h"
#include	"WaveForm.h"



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



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

typedef struct
{
	char		id [4];				/* "2BIT" */
	char		name [8];
	WORD		tracks;
	WORD		nbits;
	WORD		signe;
	WORD		loop;
	WORD		midi_note;
	LWORD		freq;
	ULWORD	length;
	ULWORD	repeat_start;
	ULWORD	repeat_end;
	char		reserved [26];
	char		user [64];
} SPLS_AVR_HEADER;



/*\\\ PROTOTYPES DES FONCTIONS PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ VARIABLES EXTERNES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

const char	*SPLAVR_sample_name_0 = "Audio Visual Research";
const char	*SPLAVR_sample_extension_0 = "*.avr";



/*\\\ VARIABLES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ FONCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: SPLAVR_save_sample                                             */
/*      Description: Sauve un sample en AVR.                                */
/*      Parametres en entree:                                               */
/*        - file_ptr: pointeur du fichier a sauver.                         */
/*        - sample: numero du sample concerne.                              */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	SPLAVR_save_sample (FILE *file_ptr, int sample)
{
	void		*mem_data_ptr;
	FILE		*file_data_ptr;
	SPLS_PRIMARY_INFO	sample_info;

	SPLS_init_primary_info (&sample_info, sample);

	if (SAMP_get_sample_type (sample) == 1)
	{
		mem_data_ptr = NULL;
		file_data_ptr = SAMP_get_sample_file_ptr (sample);
		if (fseek (file_data_ptr, SAMP_get_sample_file_data_offset (sample), SEEK_SET) != 0)
		{
			LOG_printf ("SPLAVR_save_sample: Error: couldn't set file position.\n");
			return (-1);
		}
	}
	else
	{
		mem_data_ptr = SAMP_get_sample_data_adr (sample);
		file_data_ptr = NULL;
	}
	
	if (SPLAVR_save_sample_header (file_ptr, &sample_info))
	{
		LOG_printf ("SPLAVR_save_sample: Error: couldn't save sample header.\n");
		return (-1);
	}

	sample_info.position = 0;
	sample_info.block_len = sample_info.length;

	if (SPLAVR_save_sample_data (file_ptr, &sample_info, mem_data_ptr, file_data_ptr))
	{
		LOG_printf ("SPLAVR_save_sample: Error: couldn't save sample data.\n");
		return (-1);
	}

	if (SPLAVR_save_sample_tail (file_ptr, &sample_info))
	{
		LOG_printf ("SPLAVR_save_sample: Error: couldn't save sample tail.\n");
		return (-1);
	}

	return (0);
}



/*==========================================================================*/
/*      Nom: SPLAVR_save_sample_header                                      */
/*      Description: Sauve le header du sample.                             */
/*      Parametres en entree/sortie:                                        */
/*        - file_ptr: pointeur sur le fichier a sauver.                     */
/*        - sample_info_ptr: pointeur sur les informations sur le sample,   */
/*                           qui doivent etre deja initialisees. Cette      */
/*                           routine fixe le bloc a sauver a la totalite du */
/*                           sample.                                        */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	SPLAVR_save_sample_header (FILE *file_ptr, SPLS_PRIMARY_INFO *sample_info_ptr)
{
	SPLS_AVR_HEADER	header;

	memcpy (header.id, "2BIT", 4);
	memset (header.name, ' ', 8);
	header.tracks = BASE_moto_word (  sample_info_ptr->tracks == 1
	                                ? 0
	                                : sample_info_ptr->tracks);
	header.nbits = BASE_moto_word (sample_info_ptr->nbits);
	header.signe = BASE_moto_word ((WORD) (sample_info_ptr->signed_flag != 0));
	header.midi_note = BASE_moto_word (sample_info_ptr->midi_note);
	header.freq = BASE_moto_lword (sample_info_ptr->freq);
	header.length = BASE_moto_lword (sample_info_ptr->length);

	if (sample_info_ptr->loop_type != WaveForm_LOOP_TYPE_NONE)
	{
		header.loop = BASE_moto_word (1);
		header.repeat_start = BASE_moto_lword (sample_info_ptr->repeat);
		header.repeat_end = BASE_moto_lword (sample_info_ptr->repeat + sample_info_ptr->replen);
	}
	else
	{
		header.loop = BASE_moto_word (0);
		header.repeat_start = BASE_moto_lword (0);
		header.repeat_end = BASE_moto_lword (0);
	}

	memset (header.reserved, 0, 26);
	memset (header.user, ' ', 64);
	memcpy (header.user, "Sample edited with Graoumf Tracker 2 - (c) Laurent de Soras 1999", 64);	/* Tout juste 64 octets */

	if (fseek (file_ptr, 0, SEEK_SET) != 0)
	{
		LOG_printf ("SPLAVR_save_sample_header: Error: couldn't position on file header.\n");
		return (-1);
	}

	if (fwrite (&header, sizeof (header), 1, file_ptr) != 1)
	{
		LOG_printf ("SPLAVR_save_sample_header: Error: couldn't save file header.\n");
		return (-1);
	}

	sample_info_ptr->data_offset = sizeof (header);
	sample_info_ptr->byte_order = 0;

	return (0);
}



/*==========================================================================*/
/*      Nom: SPLAVR_save_sample_data                                        */
/*      Description: Sauve les donnees d'un sample                          */
/*      Parametres en entree:                                               */
/*        - mem_data_ptr: pointeur sur le bloc a sauver. NULL si le sample  */
/*                        est sur disque.                                   */
/*        - file_data_ptr: pointeur sur le fichier qui contient le bloc     */
/*                         a sauver, positionne au debut du bloc. NULL si   */
/*                         le sample est en memoire.                        */
/*      Parametres en entree/sortie:                                        */
/*        - file_ptr: pointeur sur le fichier a sauver. Celui-ci est        */
/*                    place automatiquement au bon endroit.                 */
/*        - sample_info_ptr: pointeur sur la structure d'informations sur   */
/*                           le sample. Les champs position et block_len    */
/*                           indiquent la partie du sample a sauver.        */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	SPLAVR_save_sample_data (FILE *file_ptr, SPLS_PRIMARY_INFO *sample_info_ptr, void *mem_data_ptr, FILE *file_data_ptr)
{
	return (SPLRAW_save_sample_data (file_ptr, sample_info_ptr, mem_data_ptr, file_data_ptr));
}



/*==========================================================================*/
/*      Nom: SPLAVR_save_sample_tail                                        */
/*      Description: Sauve les informations finales d'un sample.            */
/*      Parametres en entree:                                               */
/*        - sample_info_ptr: pointeur sur la structure d'informations sur   */
/*                           le sample.                                     */
/*      Parametres en entree/sortie:                                        */
/*        - file_ptr: pointeur sur le fichier. Celui-ci est positionne au   */
/*                    bon endroit.                                          */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	SPLAVR_save_sample_tail (FILE *file_ptr, const SPLS_PRIMARY_INFO *sample_info_ptr)
{
	if (fflush (file_ptr))
	{
		LOG_printf ("SPLAVR_save_sample_tail: Error: couldn't flush file buffer.\n");
		return (-1);	/* Erreur d'ecriture */
	}

	return (0);
}



/*==========================================================================*/
/*      Nom: SPLAVR_get_primary_info                                        */
/*      Description: Recupere les informations de base sur un sample AVR.   */
/*                   Ne modifie que ce qui est donne par le header mais     */
/*                   peut utiliser le contenu entrant du bloc d'infos (ex:  */
/*                   RAW).                                                  */
/*      Parametres en entree:                                               */
/*        - file_ptr: pointeur de fichier du sample.                        */
/*      Parametres en entree/sortie:                                        */
/*        - sample_info_ptr: pointeur sur le bloc d'information a	remplir.  */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	SPLAVR_get_primary_info (FILE *file_ptr, SPLS_PRIMARY_INFO *sample_info_ptr)
{
	LWORD		file_length;
	LWORD		header_length;
	SPLS_AVR_HEADER		header;

	/* Lecture du header */
	memset (&header, 0, sizeof (header));
	file_length = FILE_get_file_length (file_ptr);
	header_length = MIN (sizeof (header), file_length);
	if (fseek (file_ptr, 0, SEEK_SET))
	{
		LOG_printf ("SPLAVR_get_primary_info: Error: couldn't position on file header.\n");
		return (-1);	/* Erreur de positionnement dans le fichier */
	}
	if ((LWORD) fread (&header, 1, header_length, file_ptr) != header_length)
	{
		LOG_printf ("SPLAVR_get_primary_info: Error: couldn't read file header.\n");
		return (-1);	/* Erreur de lecture */
	}

	/* Recuperation des informations */
	sample_info_ptr->signed_flag = (BASE_moto_word (header.signe) != 0);
	sample_info_ptr->nbits = BASE_moto_word (header.nbits) & 0xFFF8;
	sample_info_ptr->tracks =   BASE_moto_word (header.tracks) == 0
	                          ? 1
	                          : 2;
	sample_info_ptr->freq = BASE_moto_lword (header.freq) & 0xFFFFFF;
	sample_info_ptr->length = BASE_moto_lword (header.length);
	sample_info_ptr->length = MIN (sample_info_ptr->length,
												(file_length - (LWORD)sizeof (header))
											 / (  sample_info_ptr->tracks
												 * (sample_info_ptr->nbits >> 3)));

	/* MIDI Note */
	if ((BASE_moto_word (header.midi_note) & 0xFF) != 0xFF)
	{
		sample_info_ptr->midi_note = BASE_moto_word (header.midi_note) & 0xFF;
	}

	/* Bouclage */
	if (   header.loop != 0
		 && sample_info_ptr->length > 0)
	{
		sample_info_ptr->repeat = BASE_moto_lword (header.repeat_start);
		sample_info_ptr->repeat = MIN (sample_info_ptr->repeat, sample_info_ptr->length - 1);
		sample_info_ptr->replen =   BASE_moto_lword (header.repeat_end)
										  - sample_info_ptr->repeat;
		sample_info_ptr->replen = MIN (sample_info_ptr->replen,
												 sample_info_ptr->length - sample_info_ptr->repeat);
		sample_info_ptr->replen = MAX (sample_info_ptr->replen, 1);
		sample_info_ptr->loop_type = WaveForm_LOOP_TYPE_FWD;
	}
	else
	{
		sample_info_ptr->repeat = 0;
		sample_info_ptr->replen = 0;
		sample_info_ptr->loop_type = WaveForm_LOOP_TYPE_NONE;
	}
	sample_info_ptr->data_offset = sizeof (SPLS_AVR_HEADER);
	sample_info_ptr->byte_order = 0;
	sample_info_ptr->pack_type = SPLS_PACK_TYPE_PCM;
	sample_info_ptr->special = 0;

	sample_info_ptr->position = 0;
	sample_info_ptr->block_len = sample_info_ptr->length;

	return (0);
}



/*==========================================================================*/
/*      Nom: SPLAVR_load_sample                                             */
/*      Description: Charge un sample en AVR.                               */
/*      Parametres en entree:                                               */
/*        - file_ptr: pointeur du fichier a charger.                        */
/*        - sample: numero du sample concerne.                              */
/*        - sample_info_ptr: pointeur sur les informations du sample.       */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	SPLAVR_load_sample (FILE *file_ptr, int sample, SPLS_PRIMARY_INFO	*sample_info_ptr)
{
	if (SPLRAW_load_sample (file_ptr, sample, sample_info_ptr))
	{
		LOG_printf ("SPLAVR_load_sample: Error: couldn't load sample data.\n");
		return (-1);
	}

	return (0);
}



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



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