#ifndef MIKMOD_H
#define MIKMOD_H

#include <stdio.h>
#include "mtypes.h"			/* include atomic mikmod types */

#define SAMPLE MSAMPLE
#define mikbanner \
"=======================================================================\n" \
"MIKMOD v2.10 - Portable version -  Programmed by MikMak of HaRDCoDE '95\n" \
"=======================================================================\n" \
"This program is SHAREWARE - Read MIKMOD.TXT for more info\n" \
"E-Mail : mikmak@stack.urc.tue.nl\n"


/*
	error variables:
	===============
*/

extern char *ERROR_ALLOC_STRUCT;
extern char *ERROR_LOADING_PATTERN;
extern char *ERROR_LOADING_TRACK;
extern char *ERROR_LOADING_HEADER;
extern char *ERROR_NOT_A_MODULE;
extern char *ERROR_LOADING_SAMPLEINFO;
extern char *ERROR_OUT_OF_HANDLES;
extern char *ERROR_SAMPLE_TOO_BIG;
extern char *myerr;



#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET)
int  _mm_fseek(FILE *stream,long offset,int whence);
void _mm_setiobase(long iobase);
long _mm_ftell(FILE *stream);


extern SBYTE  _mm_read_SBYTE   (FILE *fp);
extern UBYTE _mm_read_UBYTE  (FILE *fp);

extern SWORD  _mm_read_M_SWORD (FILE *fp);
extern SWORD  _mm_read_I_SWORD (FILE *fp);

extern UWORD _mm_read_M_UWORD(FILE *fp);
extern UWORD _mm_read_I_UWORD(FILE *fp);

extern SLONG  _mm_read_M_SLONG (FILE *fp);
extern SLONG  _mm_read_I_SLONG (FILE *fp);

extern ULONG _mm_read_M_ULONG(FILE *fp);
extern ULONG _mm_read_I_ULONG(FILE *fp);

extern int _mm_read_str(char *str, int size, FILE *fp);

extern int _mm_read_SBYTES    (SBYTE  *buffer, int number, FILE *fp);
extern int _mm_read_UBYTES   (UBYTE *buffer, int number, FILE *fp);

extern int _mm_read_M_SWORDS  (SWORD  *buffer, int number, FILE *fp);
extern int _mm_read_I_SWORDS  (SWORD  *buffer, int number, FILE *fp);

extern int _mm_read_M_UWORDS (UWORD *buffer, int number, FILE *fp);
extern int _mm_read_I_UWORDS (UWORD *buffer, int number, FILE *fp);

extern int _mm_read_M_SLONGS  (SLONG  *buffer, int number, FILE *fp);
extern int _mm_read_I_SLONGS  (SLONG  *buffer, int number, FILE *fp);

extern int _mm_read_M_ULONGS (ULONG *buffer, int number, FILE *fp);
extern int _mm_read_I_ULONGS (ULONG *buffer, int number, FILE *fp);


extern void _mm_write_SBYTE		(SBYTE data,FILE *fp);
extern void _mm_write_UBYTE 	(UBYTE data,FILE *fp);

extern void _mm_write_M_SWORD	(SWORD data,FILE *fp);
extern void _mm_write_I_SWORD	(SWORD data,FILE *fp);

extern void _mm_write_M_UWORD	(UWORD data,FILE *fp);
extern void _mm_write_I_UWORD	(UWORD data,FILE *fp);

extern void _mm_write_M_SLONG	(SLONG data,FILE *fp);
extern void _mm_write_I_SLONG	(SLONG data,FILE *fp);

extern void _mm_write_M_ULONG	(ULONG data,FILE *fp);
extern void _mm_write_I_ULONG	(ULONG data,FILE *fp);

extern void _mm_write_SBYTES		(SBYTE *data,  int number,FILE *fp);
extern void _mm_write_UBYTES 	(UBYTE *data, int number,FILE *fp);

extern void _mm_write_M_SWORDS	(SWORD *data,  int number,FILE *fp);
extern void _mm_write_I_SWORDS	(SWORD *data,  int number,FILE *fp);

extern void _mm_write_M_UWORDS	(UWORD *data, int number,FILE *fp);
extern void _mm_write_I_UWORDS	(UWORD *data, int number,FILE *fp);

extern void _mm_write_M_SLONGS	(SLONG *data,  int number,FILE *fp);
extern void _mm_write_I_SLONGS	(SLONG *data,  int number,FILE *fp);

extern void _mm_write_M_ULONGS	(ULONG *data, int number,FILE *fp);
extern void _mm_write_I_ULONGS	(ULONG *data, int number,FILE *fp);


/**************************************************************************
****** Unitrack stuff: ****************************************************
**************************************************************************/

/*
	prototypes:
*/

void 	UniSetRow(UBYTE *t);
UBYTE	UniGetByte(void);
UBYTE  *UniFindRow(UBYTE *t,UWORD row);
void   	UniReset(void);
void   	UniWrite(UBYTE data);
void   	UniNewline(void);
void 	UniInstrument(UBYTE ins);
void 	UniNote(UBYTE note);
void 	UniPTEffect(UBYTE eff,UBYTE dat);
UBYTE  *UniDup(void);
void 	UniSkipOpcode(UBYTE op);
BOOL	UniInit(void);
void	UniCleanup(void);
UWORD   TrkLen(UBYTE *t);
BOOL    MyCmp(UBYTE *a,UBYTE *b,UWORD l);

/*
	all known effects:
*/

enum {
		UNI_NOTE=1,
		UNI_INSTRUMENT,
		UNI_PTEFFECT0,
		UNI_PTEFFECT1,
		UNI_PTEFFECT2,
		UNI_PTEFFECT3,
		UNI_PTEFFECT4,
		UNI_PTEFFECT5,
		UNI_PTEFFECT6,
		UNI_PTEFFECT7,
		UNI_PTEFFECT8,
		UNI_PTEFFECT9,
		UNI_PTEFFECTA,
		UNI_PTEFFECTB,
		UNI_PTEFFECTC,
		UNI_PTEFFECTD,
		UNI_PTEFFECTE,
		UNI_PTEFFECTF,
		UNI_S3MEFFECTA,
		UNI_S3MEFFECTD,
		UNI_S3MEFFECTE,
		UNI_S3MEFFECTF,
		UNI_S3MEFFECTI,
		UNI_S3MEFFECTQ,
		UNI_S3MEFFECTT,
		UNI_XMEFFECTA,
		UNI_XMEFFECTP
};


/**************************************************************************
****** mikmod types: ******************************************************
**************************************************************************/


/*
	Sample format flags:
*/

#define SF_16BITS       1
#define SF_SIGNED   	2
#define SF_DELTA        4
#define SF_BIG_ENDIAN	8
#define SF_LOOP         16
#define SF_BIDI         32
#define SF_OWNPAN       64
#define SF_REVERSE		128


/*
	Envelope flags:
*/

#define EF_ON           1
#define EF_SUSTAIN      2
#define EF_LOOP         4


/*
	Unimod flags
*/

#define UF_XMPERIODS    1               /* if set use XM periods/finetuning */
#define UF_LINEAR       2               /* if set use LINEAR periods */


typedef struct ENVPT{
	SWORD pos;
	SWORD val;
} ENVPT;


typedef struct MSAMPLE{
	UWORD c2spd;            /* finetune frequency */
	SBYTE transpose;        /* transpose value */
	UBYTE volume;           /* volume 0-64 */
	UBYTE panning;          /* panning */
	ULONG length;           /* length of sample (in samples!) */
	ULONG loopstart;        /* repeat position (relative to start, in samples) */
	ULONG loopend;          /* repeat end */
	UWORD flags;            /* sample format */
	ULONG seekpos;			/* seek position in file */
	char *samplename;       /* name of the sample */
	SWORD handle;           /* sample handle */
} MSAMPLE;


typedef struct INSTRUMENT{
	UBYTE numsmp;
	UBYTE samplenumber[96];

	UBYTE volflg;           /* bit 0: on 1: sustain 2: loop */
	UBYTE volpts;
	UBYTE volsus;
	UBYTE volbeg;
	UBYTE volend;
	ENVPT volenv[12];

	UBYTE panflg;           /* bit 0: on 1: sustain 2: loop */
	UBYTE panpts;
	UBYTE pansus;
	UBYTE panbeg;
	UBYTE panend;
	ENVPT panenv[12];

	UBYTE vibtype;
	UBYTE vibsweep;
	UBYTE vibdepth;
	UBYTE vibrate;

	UWORD volfade;
	char  *insname;
    MSAMPLE *samples;
} INSTRUMENT;


/*
	MikMod UNImod types:
	====================
*/

typedef struct UNIMOD{
	UBYTE		numchn;			/* number of channels */
	UWORD       numpos;         /* number of positions in this song */
	UWORD		reppos;			/* restart position */
	UWORD       numpat;         /* number of patterns in this song */
	UWORD       numtrk;         /* number of tracks */
	UWORD       numins;         /* number of samples */
	UBYTE       initspeed;      /* */
	UBYTE       inittempo;      /* */
	UBYTE       positions[256]; /* all positions */
	UBYTE       panning[32];  	/* 32 panning positions */
	UBYTE       flags;          /* */
	char       *songname;       /* name of the song */
	char       *modtype;        /* string type of module */
	char       *comment;        /* module comments */
	INSTRUMENT *instruments;    /* all samples */
	UWORD      *patterns;       /* array of PATTERN */
	UWORD      *pattrows;       /* array of number of rows for each pattern */
	UBYTE     **tracks;         /* array of pointers to tracks */
} UNIMOD;


/**************************************************************************
****** Loader stuff: ******************************************************
**************************************************************************/

/*
	loader structure:
*/

typedef struct LOADER{
	struct LOADER *next;
	char	*type;
	char 	*version;
	BOOL    (*Init)(void);
	BOOL	(*Test)(void);
	BOOL	(*Load)(void);
	void	(*Cleanup)(void);
} LOADER;


/*
	public loader variables:
*/

extern UNIMOD of;
extern FILE *modfp;
extern UWORD finetune[16];


/*
	main loader prototypes:
*/

void 	ML_InfoLoader(void);
void 	ML_RegisterLoader(LOADER *ldr);
UNIMOD	*ML_LoadFP(FILE *fp);
UNIMOD	*ML_LoadFN(char *filename);
void 	ML_Free(UNIMOD *mf);


/*
	other loader prototypes: (used by the loader modules)
*/

BOOL 	InitTracks(void);
void 	AddTrack(UBYTE *tr);
BOOL 	ReadComment(UWORD len);
BOOL 	AllocPatterns(void);
BOOL 	AllocTracks(void);
BOOL 	AllocInstruments(void);
BOOL 	AllocSamples(INSTRUMENT *i);
char    *DupStr(char *s,UWORD len);
void 	*MyMalloc(size_t size);
void 	*MyCalloc(size_t nitems,size_t size);


/*
	Declare external loaders:
*/
extern LOADER load_uni;
extern LOADER load_mod;
extern LOADER load_m15;
extern LOADER load_mtm;
extern LOADER load_s3m;
extern LOADER load_stm;
extern LOADER load_ult;
extern LOADER load_xm;


/**************************************************************************
****** Wavload stuff: *****************************************************
**************************************************************************/

MSAMPLE *MW_LoadWavFP(FILE *fp);
MSAMPLE *MW_LoadWavFN(char *filename);
void MW_FreeWav(MSAMPLE *si);


/**************************************************************************
****** Driver stuff: ******************************************************
**************************************************************************/

/*
	max. number of handles a driver has to provide. (not strict)
*/

#define MAXSAMPLEHANDLES 128


/*
	possible mixing mode bits:
*/

#define DMODE_STEREO    1
#define DMODE_16BITS    2
#define DMODE_INTERP	4


/*
	driver structure:
*/

typedef struct DRIVER{
	struct DRIVER *next;
	char    *Name;
	char    *Version;
	BOOL    (*IsPresent)            (void);
	SWORD   (*SampleLoad)           (FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags);
	void    (*SampleUnLoad)         (SWORD handle);
	BOOL    (*Init)                 (void);
	void    (*Exit)                 (void);
	void    (*PlayStart)            (void);
	void    (*PlayStop)             (void);
	void    (*Update)               (void);
	void 	(*VoiceSetVolume)		(UBYTE voice,UBYTE vol);
	void 	(*VoiceSetFrequency)	(UBYTE voice,ULONG frq);
	void 	(*VoiceSetPanning)		(UBYTE voice,UBYTE pan);
	void	(*VoicePlay)			(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags);
} DRIVER;


/*
	public driver variables:
*/

extern DRIVER *md_driver;
extern UWORD md_device;
extern UWORD md_mixfreq;
extern UWORD md_dmabufsize;
extern UWORD md_mode;
extern UBYTE md_numchn;
extern UBYTE md_bpm;
extern void (*md_player)(void);

/*
	main driver prototypes:
*/

void MD_InfoDriver(void);
void MD_RegisterDriver(DRIVER *drv);
void MD_RegisterPlayer(void (*plr)(void));
SWORD MD_SampleLoad(FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags);
void MD_SampleUnLoad(SWORD handle);
BOOL MD_Init(void);
void MD_Exit(void);
void MD_PlayStart(void);
void MD_PlayStop(void);
void MD_SetBPM(UBYTE bpm);
void MD_Update(void);
void MD_VoiceSetVolume(UBYTE voice,UBYTE ivol);
void MD_VoiceSetFrequency(UBYTE voice,ULONG frq);
void MD_VoiceSetPanning(UBYTE voice,ULONG pan);
void MD_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags);
void SL_Init(FILE *fp,UWORD infmt,UWORD outfmt);
void SL_Load(void *buffer,ULONG length);

/*
	Declare external drivers:
*/

extern DRIVER drv_gus;		/* gravis ultrasound driver */
extern DRIVER drv_sb;		/* soundblaster DSP driver */
extern DRIVER drv_ss;		/* ensoniq soundscape driver */
extern DRIVER drv_nos;		/* nosound driver */
extern DRIVER drv_raw;		/* file output driver */
extern DRIVER drv_w95;		/* win95 driver */
extern DRIVER drv_awe;		/* experimental SB-AWE driver */
extern DRIVER drv_vox;		/* linux voxware driver */
extern DRIVER drv_af;       /* Dec Alpha AudioFile driver */
extern DRIVER drv_sun;      /* Sun driver */
extern DRIVER drv_os2;      /* Os2 driver */

/**************************************************************************
****** Player stuff: ******************************************************
**************************************************************************/


typedef struct ENVPR{
	UBYTE flg;          /* envelope flag */
	UBYTE pts;			/* number of envelope points */
	UBYTE sus;			/* envelope sustain index */
	UBYTE beg;			/* envelope loop begin */
	UBYTE end;			/* envelope loop end */
	SWORD p;			/* current envelope counter */
	UWORD a;			/* envelope index a */
	UWORD b;			/* envelope index b */
	ENVPT *env;			/* envelope points */
} ENVPR;


typedef struct AUDTMP{
	INSTRUMENT 	*i;
    MSAMPLE      *s;

	SWORD fadevol;		/* fading volume */

	ENVPR venv;
	ENVPR penv;

	UBYTE keyon;		/* if true=key is pressed. */
	UBYTE kick;			/* if true=sample has to be restarted */
	UBYTE sample;		/* which sample number (0-31) */
	SWORD handle;		/* which sample-handle */

	ULONG start;		/* The start byte index in the sample */

	UBYTE panning;		/* panning position */
	UBYTE pansspd;		/* panslide speed */

	SBYTE volume;		/* amiga volume (0 t/m 64) to play the sample at */
	UWORD period;		/* period to play the sample at */

	/* You should not have to use the values
	   below in the player routine */

	SBYTE transpose;

	UBYTE note;			/* */

	SWORD ownper;
	SWORD ownvol;

	UBYTE *row;			/* row currently playing on this channel */

	SBYTE retrig;		/* retrig value (0 means don't retrig) */
	UWORD c2spd;		/* what finetune to use */

	SBYTE tmpvolume;	/* tmp volume */

	UWORD tmpperiod;	/* tmp period */
	UWORD wantedperiod;	/* period to slide to (with effect 3 or 5) */

	UWORD slidespeed;	/* */
	UWORD portspeed;	/* noteslide speed (toneportamento) */

	UBYTE s3mtremor;	/* s3m tremor (effect I) counter */
	UBYTE s3mtronof;	/* s3m tremor ontime/offtime */

	UBYTE s3mvolslide;	/* last used volslide */

	UBYTE s3mrtgspeed;	/* last used retrig speed */
	UBYTE s3mrtgslide;	/* last used retrig slide */

	UBYTE glissando;	/* glissando (0 means off) */
	UBYTE wavecontrol;	/* */

	SBYTE vibpos;		/* current vibrato position */
	UBYTE vibspd;		/* "" speed */
	UBYTE vibdepth;		/* "" depth */

	SBYTE trmpos;		/* current tremolo position */
	UBYTE trmspd;		/* "" speed */
	UBYTE trmdepth;		/* "" depth */

	UWORD soffset;		/* last used sample-offset (effect 9) */
} AUDTMP;


extern AUDTMP mp_audio[32];		/* max eight channels */
extern UBYTE  mp_bpm;			/* beats-per-minute speed */
extern UWORD  mp_patpos;		/* current row number (0-63) */
extern SWORD  mp_sngpos;		/* current song position */
extern UWORD  mp_sngspd;		/* current songspeed */

extern BOOL  mp_loop;
extern BOOL  mp_panning;
extern BOOL  mp_extspd;
extern UBYTE mp_volume;

/*
	player prototypes:
*/

int	 MP_Ready(void);
void MP_NextPosition(void);
void MP_PrevPosition(void);
void MP_SetPosition(UWORD pos);
void MP_HandleTick(void);
void MP_Init(UNIMOD *m);


/**************************************************************************
****** Virtual channel stuff: *********************************************
**************************************************************************/

BOOL    VC_Init(void);
void    VC_Exit(void);

void    VC_PlayStart(void);
void    VC_PlayStop(void);

SWORD   VC_SampleLoad(FILE *fp,ULONG size,ULONG reppos,ULONG repend,UWORD flags);
void    VC_SampleUnload(SWORD handle);

void    VC_WriteSamples(SBYTE *buf,UWORD todo);
UWORD   VC_WriteBytes(SBYTE *buf,UWORD todo);

void 	VC_VoiceSetVolume(UBYTE voice,UBYTE vol);
void 	VC_VoiceSetFrequency(UBYTE voice,ULONG frq);
void 	VC_VoiceSetPanning(UBYTE voice,UBYTE pan);
void 	VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags);

#endif
