/* GSI - general sound interface
 *
 * gsif.h
 *
 * ** GSI file functions **
 *
 *
 * By W.H.Scholten 1998 - 1999
 *
 * This file is released to the public domain.
 */


#ifndef _GSI__gsif__gsif_h
#define _GSI__gsif__gsif_h

#ifdef _cplusplus
extern "C" {
#endif /* __cplusplus */

#include <gsi/pcm_data.h>

/* status/errors: */
#define GSIF_OK                                    0
#define GSIF_ERROR_STATUS_UNKNOWN                 -1
#define GSIF_ERROR_OUT_OF_MEMORY                  -2

#define GSIF_ERROR_BAD_ARGUMENTS                  -3

#define GSIF_ERROR_NO_SUCH_FILE                  -15
#define GSIF_ERROR_NULL_DEREFERENCE              -16 /* you passed structures with bad pointers */
#define GSIF_ERROR_FILE_CORRUPT                  -17 /* some internal problem in the file */
#define GSIF_ERROR_UNHANDLED_FILE_TYPE           -18 /* the function can't handle the given file */



#define GSIFMIDI_ERROR_TRACK_CORRUPT             -32

#define GSIFMIDI_STATUS_NO_MORE_EVENTS             2
#define GSIFMIDI_STATUS_NO_EVENTS_WITHIN_LIMIT     1



/* midi instrument names: */
extern char *gsi_gmvoice_names[128];
extern char *gsi_gmdrum_names[];

/* samples: */
enum { GSI_FILE_RAW, GSI_FILE_AU, GSI_FILE_AIFF, GSI_FILE_VOC, GSI_FILE_WAV };
/* ======== RENAME: GSIF_FILE_RAW, GSIF_FILE_AU, etc. */


/*
 * Should the following names not be gsif_block instead of gsi_block etc ?
 */
typedef struct gsi_block {
	int   samplerate;
	int   channels;
	int   type;

	unsigned char *data;
	unsigned long  data_length;
	unsigned long  data_offset; /* to (re)load the data from file (relative to the gsi_sound's offset) */

	int   block_type;           /* 0=samples, 1=silence. */

	struct gsi_block *next;
	struct gsi_block *prev;
} gsi_block_t;
/* for silence: duration = (data_length/(channels * bytes))/rate; as normal. */


typedef struct gsi_sound {
	char *filename;
	long  offset;              /* offset into the file were the header is located */

	int   file_format;
	char *comment;

	int  blocks;               /* number of blocks */
	struct gsi_block **block;  /* 'blocks' pointers to gsi_block structs. */

	struct gsi_block  *first;  /* alternative access: linked list */
	struct gsi_block  *last;
} gsi_sound_t;


/* songs: */
enum { GSI_FILE_MIDI, GSI_FILE_HMP, GSI_FILE_MUS };
/* ======== RENAME: GSIF_FILE_MIDI, GSIF_FILE_HMP, GSIF_FILE_MUS */

struct gsi_track {
	unsigned char *data;
	unsigned long  data_length;     /* length of track (bytes) */
	unsigned long  data_offset;     /* offset into the file were the track is located */
};

struct gsi_song {
	char *filename;
	unsigned long  offset;     /* offset into the file were the header is located */

	int   file_format;
	char *comment;
	int   tracks;              /* number of tracks in the song. */
	struct gsi_track **track;  /* 'tracks' pointers to tracks with midi data. */

	unsigned char *data;       /* from a file: the midi data, all tracks (not needed after copying to the tracks). */
	int   data_length;         /* length of the midi data (also not needed after copying to the tracks) */

	int   midi_division;       /* time base division */
	int   midi_format;         /* type */

	struct gsi_track  *first;  /* alternative access: linked list. */
	struct gsi_track  *last;
};


/*---------------------------------------------------------------------------*
 *      Functions for samples:
 *      Load, save, identify and convert between sample/file formats.
 *---------------------------------------------------------------------------*/
struct gsi_sound *gsif_load_sample (char *filename, int offset);
/*   NB. This loads a file in the progam that makes this call (i.e. a client,
 *   or the GSI server itself which uses these functions too). */

// => int gsif_load_sample (gsi_sound_t **snd, char *filename, int offset);

struct gsi_sound *gsif_load_raw_sample (char *filename, int offset, int length, int snd_samplerate, int snd_channels, int snd_type);
/*   NB. This loads a file in the progam that makes this call (i.e. a client,
 *   or the GSI server itself which uses these functions too). */

// => int gsif_load_raw_sample (struct gsi_sound **snd, char *filename, int offset, int length, int snd_samplerate, int snd_channels, int snd_type);


struct gsi_sound *gsif_get_sample_structure (char *filename, int offset);
/*   gives a gsi_sound and gsi_blocks with all the information from the file
 *   without loading the actual sound fragments into any gsi_block.
 *   Returns NULL for an unidentified file format. */

// => int gsif_get_sample_structure (gsi_sound_t **snd, char *filename, int offset);


struct gsi_sound *gsif_get_structure (char *filename, int read_header, int data_offset, int data_len, int samplerate, int channels, int type);
/*   This function is called by gsif_load_sample, gsif_load_raw_sample,
 *   gsif_get_sample_structure.
 *   If read_header = 0 then a raw sample is loaded using the given samplerate
 *   etc. If not, the program set load the sample information using the format
 *   information in the file, except for filenames *.raw which are interpreted
 *   as samplerate-channels-type raw sample. */

// => int  gsif_get_structure (gsi_sound_t **snd, char *filename, int read_header, int data_offset, int data_len, int samplerate, int channels, int type);


int  gsif_save_raw_sample (char *filename, int save_format, int rate, int channels, int type, char *data, int data_length, int offset);
/*   [ NOT YET IMPLEMENTED ]
 *   The file snd->filename may already exist, in which case the sample is
 *   written in the file (which may be extended by this) at the given offset.
 *   Returns 0 if ok, -1 if unable to save the file (e.g. unsupported save
 *   format, or no write permission). */

int  gsif_save_sample (struct gsi_sound *snd, int file_type, int offset);
/*   [ NOT YET IMPLEMENTED ]
 *   The file snd->filename may already exist, in which case the sample is
 *   written in the file (which may be extended by this) at the given offset.
 *   Returns 0 if ok, -1 if unable to save the file (e.g. unsupported save
 *   format, or no write permission). */

int  gsif_load_sound_in_block (struct gsi_sound *snd, struct gsi_block *blk, int samplerate, int channels, int type);
/*   Load sample data from all blocks, convert to one format (the best format,
 *   based on the highest type, highest bits, highest channels from all blocks)
 *   and store it in one block. If samplerate>=0 then this overrides the best
 *   samplerate and ditto for channels, type. */

int  gsif_load_sound_data (struct gsi_sound *snd);
/*   load sample data of all blocks in the sound (calls gsif_load_block_data).
 */


/* ======== unsigned char *gsif_convert_data (int input_type, int input_endian, unsigned char *input_data, int samples, int output_type, int output_endian, int *converted_size); */

int  gsif_load_block_data (int fd, struct gsi_sound *snd, int block);
/*   load sample data of the given block number using the give file descriptor. */

/*  ======== struct gsi_block *gsif_convert_block (struct gsi_block *blk, int samplerate, int channels, int type); */

int  gsif_convert_block (struct gsi_block *blk, struct gsi_block *new_blk, int samplerate, int channels, int type);
/*   Convert a sample to the given type. */



/* Convenience functions to manipulate sound structures:
 * -----------------------------------------------------
 * Note that you can malloc/free yourself. All dynamic memory handling by GSI
 * is done with malloc & free. */

/* free allocated memory: */
int  gsif_free_sound (struct gsi_sound *snd);
/*   free a sound, all its blocks and allocated data for samples.
 *   NB. if you want to preserve some data in the sound, just copy the
 *   relevant pointer and make the one in snd NULL first. */

int  gsif_free_block (struct gsi_sound *snd, int i);
/*   Frees a block and allocated data. Does not reorganize the linked/linear
 *   lists. */


/* low level manipulation: */
int  gsif_add_block (struct gsi_sound *snd, int samplerate, int channels, int type, int data_start, int data_length);
/*   add block at the end of the linked list. Sample data is not loaded. */

int  gsif_make_linked_block_list (struct gsi_sound *snd);
/*   array of blocks (block) => linked list of blocks (prev,next) */

int  gsif_make_block_list (struct gsi_sound *snd);
/*   linked list of blocks (prev,next) => array of blocks (block) */


/*---------------------------------------------------------------------------*
 *      Functions for songs:
 *      Loading/converting.
 *---------------------------------------------------------------------------*/
struct gsi_song *gsif_load_song (char *filename, int offset);
/*   loads a song (which is currently a midi/hmp) */
/* CHANGE TO:
 * ======== int gsif_load_song (char *filename, int offset, struct gsi_song **new_sng);
 * OR:
 * ======== int gsif_load_song (struct gsi_song **sng, char *filename, int offset);
 */


int  gsif_convert_song_to_tracks (struct gsi_song *sng);
/*   splits a midi buffer into tracks */


/* Convenience functions to manipulate song structures:
 * ----------------------------------------------------
 * As with samples: this is all done with malloc/free. */

/* Free data: */
int  gsif_free_song (struct gsi_song *sng);
/*   free a song, all its blocks and allocated data for tracks.
 *   NB. if you want to preserve some data in the sound, just copy the
 *   relevant pointer and make the one in sng NULL first. */

int  gsif_free_track (struct gsi_song *sng, int i);
/*   Frees a track and allocated data. Does not reorganize the linked/linear
 *   lists. */


/* low level manipulation: */
/* CHANGE TO: gsi_insert_track (sng, trk, data, data_length); ? */
void gsif_add_track (struct gsi_sound *sng, int data, int data_length);
/*   add track at the end of the linked list. Song data is not loaded. */

void gsif_make_linked_track_list (struct gsi_sound *sng);
/*   array of tracks (track) => linked list of tracks (prev,next) */

void gsif_make_track_list (struct gsi_sound *sng);
/*   linked list of tracks (prev,next) => array of tracks (track) */


/*---------------------------------------------------------------------------*
 *      Miscellaneous functions:
 *---------------------------------------------------------------------------*/
int  gsif_sizeof_sample (int format);
/*   Bytes used per sample: 0 = query for invalid/unknown format, GSI_8BIT
 *   Returns 1, GSI_16BIT 2 etc. */

int  gsif_fill_buffer (unsigned char *buffer, int num_samples, int channels, int type, int value);
/*   Fills a buffer with a given 32 bit value (rounded down to whatever
 *   accuracy the buffer uses). That is, to fill a 8 bit unsigned buffer with 1
 *   you do: gsif_fill_buffer(buf, n, ch, type, 1<<24); To fill a buffer with
 *   silence: gsif_fill_buffer(buf, n, ch, type, 0); */


/* TEMPORARY FUNCTIONS:
 * --------------------
 * NB. These are INTERNAL functions. They are only available publicly for
 * testing. */
int  gsif_save_aiff (struct gsi_sound *snd);
int  gsif_save_au (struct gsi_sound *snd);
int  gsif_save_midi (struct gsi_song *sng);
/* INTERNAL! you have been warned. */

#ifdef _cplusplus
}
#endif /* __cplusplus */

#endif /* _GSI__gsif__gsif_h */
