// soun.h
#ifndef __soun_h__
#define __soun_h__

#ifndef __tags_h__
#include "tags.h"
#endif

#ifndef __BYTE_SWAPPING_H__
#include "byte_swapping.h"
#endif

#ifndef __ttageditform_h__
#include "TTagEditForm.h"
#endif

#ifndef __myth_defs_h__
#include "myth_defs.h"
#endif

/* ---------- constants */

enum
{
	SOUND_DEFINITION_GROUP_TAG= 0x736f756e, // 'soun' (looks like text)
	SOUND_DEFINITION_VERSION_NUMBER= 1,
	
	MAXIMUM_SOUND_DEFINITIONS_PER_MAP= 270,

	MAXIMUM_PERMUTATIONS_PER_SOUND= 5,
	MAXIMUM_SOUND_PERMUTATION_NAME_LENGTH= 25,
	NUMBER_OF_IMA_SAMPLES_PER_PACKET= 64,
	NUMBER_OF_IMA_SAMPLES_PER_BYTE= 2,
	
	_sample_rate_22k= 0x56220000
};

enum // loudness
{
	_sound_is_quiet,
	_sound_is_normal,
	_sound_is_loud,
	_sound_is_narration,
	NUMBER_OF_SOUND_LOUDNESSES
};

enum // flags
{
	_sound_cannot_be_restarted_bit, // if this sound is already going, leave it alone no matter what
	_sound_can_occupy_multiple_channels_bit, // can be playing in more than one channel at a time
	_sound_stopped_when_source_disappears_bit,
	_sound_cannot_be_media_obstructed_bit,
	_sound_is_ambient_background_loop_bit,
	_sound_is_ambient_random_bit,
	_sound_all_permutations_use_same_subtitle_bit,	
	NUMBER_OF_SOUND_DEFINITION_FLAGS, // <=16

	_sound_cannot_be_restarted_flag= FLAG(_sound_cannot_be_restarted_bit),
	_sound_can_occupy_multiple_channels_flag= FLAG(_sound_can_occupy_multiple_channels_bit),
	_sound_stopped_when_source_disappears_flag= FLAG(_sound_stopped_when_source_disappears_bit),
	_sound_cannot_be_media_obstructed_flag= FLAG(_sound_cannot_be_media_obstructed_bit),
	_sound_is_ambient_background_loop_flag= FLAG(_sound_is_ambient_background_loop_bit),
	_sound_is_ambient_random_flag= FLAG(_sound_is_ambient_random_bit),
	_sound_all_permutations_use_same_subtitle_flag= FLAG(_sound_all_permutations_use_same_subtitle_bit)
};

enum
{ // sampled_sound_header flags
	_sound_is_ima_compressed_bit,
	NUMBER_OF_SAMPLED_SOUND_HEADER_FLAGS,
	_sound_is_ima_compressed_flag= FLAG(_sound_is_ima_compressed_bit)
};

enum
{
	LOAD_SOUND_ERROR_SUCCESS = 0,
	LOAD_SOUND_ERROR_FAILURE,
	LOAD_SOUND_ERROR_NOT_16_BIT,
	LOAD_SOUND_ERROR_NOT_22050,
};

#define SIZEOF_STRUCT_SAMPLED_SOUND_HEADER 32
struct sampled_sound_header
{
	unsigned long flags;
	
	short logical_bits_per_sample; // 8 or 16
	short physical_bytes_per_sample_minus_one;
	short channels;
	word pad;
	
	fixed sample_rate;
	long number_of_samples;

	long loop_start, loop_end;

	void *samples;
};

#define SIZEOF_APPLE_IMA_PACKET_CHUNK 34
struct apple_ima_packet_chunk {	
	short state;
	char samples[NUMBER_OF_IMA_SAMPLES_PER_PACKET/NUMBER_OF_IMA_SAMPLES_PER_BYTE];
};

#define SIZEOF_STRUCT_SOUND_PERMUTATION_DATA 32
struct sound_permutation_data
{
	word flags;
	fixed_fraction skip_fraction;
	
	short unused[1];
	
	char name[MAXIMUM_SOUND_PERMUTATION_NAME_LENGTH+1];
};

#define SIZEOF_STRUCT_SOUND_DEFINITION 64
struct sound_definition
{
	unsigned long flags;

	short loudness; // also used as priority
	fixed_fraction play_fraction; // not played if .play_fraction<local_random()

	short_fixed external_frequency_modifier; // cannot change frequencies if zero
	short_fixed pitch_lower_bound, pitch_delta;
	short_fixed volume_lower_bound, volume_delta; // only intended for random sounds
	 
	short first_subtitle_within_string_list_index;
	
	long sound_offset;
	long sound_size;
	
	file_tag subtitle_string_list_tag;
	
	short subtitle_string_list_index;
	word unused;
	
	long number_of_permutations, permutations_offset, permutations_size;
	struct sound_permutation_data *sound_permutations;

	short reference_count;
	word permutations_played_flags;
	unsigned long local_tick_last_played; // for theoretical disposing of least recently used sounds
	struct sampled_sound_header *sampled_sound_headers; // for the current encoding, NULL if not loaded
};

enum
{
	DECOMPRESSION_BUFFER_SIZE= ((int)(1*MEG/(2*SIZEOF_APPLE_IMA_PACKET_CHUNK)))*2*SIZEOF_APPLE_IMA_PACKET_CHUNK
};

#if OPT_WINOS

// this is kinda weird
#define BYTES_PER_SAMPLE 128
#endif

extern byte_swap_code sound_definition_byte_swapping_data[];
extern sound_definition default_soun;


//=====================================================================================================
class TsounEditForm: public TTagEditForm {
	public:
							TsounEditForm( struct tag_entry *e );
							~TsounEditForm();
				
		void 				UpdatePermutationControls();

		DECLAREDISPATCH
		virtual long		DoControlClick( long arg, void *ptr );
		virtual long		DoListSelect( int arg, void *ptr );
		virtual long		DoKeyClick( int arg, char *str );
		
		
		virtual void		CommitToTag();
		virtual void		ReloadTag();
		virtual bool		NeedCommit();
		virtual void		DoFormInitialize();
		
	protected:
		void				SetValues();
		void				GetValues();
//		bool				LoadSoundFile( XGFileSpecifier *fs, int index = -1 );
		void				PlaySoundFile();
		
		sound_definition	def;
};

bool read_sound_definition( sound_definition* def, tag id );
bool save_sound_definition( sound_definition* def, tag id );

bool read_sound_definition( sound_definition* def, tag_entry* e );
bool save_sound_definition( sound_definition* def, tag_entry* e );

#if OPT_MACOS
#endif

#if OPT_WINOS
bool read_wave_file( XGFileSpecifier *fs, WAVEFORMAT **ppwf, byte **ppData, long *plSize );
#endif

#if OPT_XWIN
#endif

void decompress_mono( long lPackets, void *samples, void *pvBuf1, unsigned long cBuf1, void *pvBuf2, unsigned long cBuf2 );
void decompress_stereo( long lPackets, void *samples, void *pvBuf1, unsigned long cBuf1, void *pvBuf2, unsigned long cBuf2 );

#endif