/*
	VOC file format library
 */


#ifndef VOC_H
#define VOC_H

#include <sys/types.h>


/*
 *	Master version number:
 */
#define VocLibraryVersionMajor          2
#define VocLibraryVersionMinor          2


/*
 *	VOC library function error codes:
 */
#define VocSuccess              0
#define VocErrorNoAccess        1
#define VocErrorNotVoc          2
#define VocErrorNoBuffers       3
#define VocErrorCorrupt         4
#define VocErrorUnsupported     5
#define VocErrorBadValue        6
#define VocErrorNoHeader        7
#define VocErrorNoData          8
#define VocErrorEndOfData       9


/*
 *	Default 'assumed' sample rate:
 */
#define VocDefaultSampleRate 11025


/*
 *      Byte value shift options for VocReadPartialData():
 */
#define VocReadUnsigned8	0
#define VocReadSigned8		1


/*
 *   VOC Header
 */

/* VOC header length in bytes. */
#define VocHeaderLength		26

/* Magic name. */
#define VocMagicName		"Creative Voice File"

/* Byte position in header containing 1A for abort printing. */
#define VocHeaderAbortPos	19


/*
 *   Byte position in header containing offset to first data block.
 *   This field is 2 bytes long in LSBF.
 */
#define VocHeaderOffsetToDataBlockPos		20

/*
 *   Byte position in header containing version number.
 *   This field is 2 bytes long, where the first byte is the minor
 *   version and the second byte is the major version.
 *
 *   The value is usually 0A 01.
 */
#define VocHeaderVersionPos	22

/*
 *   Byte position in header containing what appears to be
 *   some code or version.   This field is 2 bytes long.
 *
 *   The value is usually 29 11.
 */
#define VocHeaderExt1		24



/*
 *   Block type codes:
 *
 *	These codes are used to determine type in the voc_block_struct;
 */
#define VocBlockTypeTerminator		0x00
#define VocBlockTypeSoundData		0x01
#define VocBlockTypeSoundDataContinue	0x02
#define VocBlockTypeSilence		0x03
#define VocBlockTypeMarker		0x04
#define VocBlockTypeASCII		0x05
#define VocBlockTypeRepeat		0x06
#define VocBlockTypeEndRepeat		0x07
#define VocBlockTypeExtended		0x08



/*
 *   VOC Data Block Structure:
 *
 *	Each VOC file has several datablocks, this structure
 *	contain information of one data block.
 *
 *	NOTE: Not all members will be relevant to all data block types!
 */
typedef struct {

	int type;

	/* Size of block (note on file it is a 3 byte unsigned int). */
	u_int32_t size;


	/* Block specific info - VocBlockTypeSoundData */
	/* (Same for VocBlockTypeSoundDataContinue) */
	unsigned int sample_rate;
	unsigned char compression_type;
	double bits;	/* Calculated from compression_type. */

	off_t data_start_pos;	/* Absolute position in file to data. */
	off_t data_len;		/* Length of JUST the audio data. */



	/* Block specific info - VocBlockTypeSilence */
	u_int16_t silence_length;

	/* Block specific info - VocBlockTypeMarker */
	u_int16_t marker_num;

	/* Block specific info - VocBlockTypeASCII */
	char *str;
	unsigned int str_len;

	/* Block specific info - VocBlockTypeRepeat */
	u_int16_t repeat_count;

	/* Block specific info - VocBlockTypeExtended */
	u_int16_t time_constant;
	unsigned char pack;
	unsigned char mode;	/* 0 = mono, 1 = stereo. */


} voc_block_struct;



/*
 *  VOC Header Information.
 */
typedef struct {

	/* File info. */
	char *filename;
	FILE *fp;
	off_t filesize;


	/* Information from header. */
	unsigned char major_version;
	unsigned char minor_version;

	/* Offset to first datablock. (on file it is 2 bytes) */
	u_int16_t first_data_block;


	/* Datablocks. */
	voc_block_struct **datablock;
	int total_datablocks;


	/*
	 *   The actual data loaded by VocReadPartialData().
	 *   It will be freed and reallocated per call to
	 *   VocReadPartialData().
	 */
	char *data;
	off_t data_len;


	/*
	 *   Total data length from all blocks which contain
	 *   Audio data.
	 */
	off_t total_data_len;

} voc_data_struct;



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

/*
 *   Checks if givin file name is a valid VOC file, returns
 *   VocSuccess if it is, VocErrorNotVoc if it is not a valid
 *   VOC file, or appropriate error if an error occured..
 */
extern int VocIsFileVoc(const char *filename);


/*
 *   Gets sample rate in Hz from last data block in the
 *   voc_data_struct *vd that is of type VocBlockTypeSoundData
 *   or VocBlockTypeSoundDataContinue.
 *
 *   If no sample rate can be found or if there is an error,
 *   then VocDefaultSampleRate will be returned.
 */
extern unsigned int VocGetEnvSampleRate(voc_data_struct *vd);


/*
 *   Frees all allocated data blocks, data block sub structures,
 *   that contain allocated data, loaded data, and
 *   resets all values of immediate voc_data_struct *vd members.
 *
 *   If voc_data_struct *vd is NULL then no action will be taken.
 */
extern void VocDestroyData(voc_data_struct *vd);

/*
 *      Reads the header from the stream fp and initializes the given
 *      vd structure if fp is valid and a voc file.
 *
 *      The given filename is used only for referance purposes, it can be
 *      NULL.
 *
 *      If VocSuccess is returned then the given fp will be transfered 
 *      to the vd structure and should not be referanced again. For all
 *      other return values, the calling function is responsible for
 *      closing the given fp.
 */
extern int VocReadHeader(
	const char *filename, FILE *fp, voc_data_struct *vd
);


/*
 *   Reads a segment of data from the VOC file specified by
 *   the filename member of the givin voc_data_struct *vd structure.
 *
 *   The voc_data_struct *vd structure MUST HAVE VALID VALUES FROM
 *   A PRIOR SUCCESSFUL CALL TO VocReadHeader().
 *
 *   offset is the relative byte position FROM THE START OF THE AUDIO
 *   DATA AS A COMPLETE TRACK and not a position in the actual file.
 *
 *   max_chunk_size is the number of bytes that you want to read from
 *   offset.  If max_chunk_size should overlap several blocks of
 *   audio data the function will be smart enough to read to the next
 *   block and so on.
 *
 *   read_opt can be VocReadFormatSHV or VocReadFormatRaw.
 *   VocReadFormatSHV will read the data from the VOC file then
 *   subtract 128 from it (this is often used as a convience should
 *   mixing be desired).
 *
 *   VocReadFormatRaw will read the data 'as is' from the VOC file.
 *
 *   The loaded data will be placed into the member data of the
 *   voc_data_struct *vd with the member data_len set appropriately.
 *   If member data is not NULL, then the old data will be first free()ed
 *   automatically before loading is performed.
 */
extern int VocReadPartialData(
	voc_data_struct *vd,
	off_t offset,
	off_t max_chunk_size,
	int read_opt		/* Reading format. */
);



#endif /* VOC_H */
