#ifndef _MOD_H
#define _MOD_H

/*
 *  Offsets for various data
 */

#define MOD31_OFFSET_NAME              0
#define MOD31_OFFSET_SAMPLEINFO       20
#define MOD31_OFFSET_SONGLENGTH      950
#define MOD31_OFFSET_RESTARTPOS      951
#define MOD31_OFFSET_PATTERNTABLE    952
#define MOD31_OFFSET_MAGIC          1080
#define MOD31_OFFSET_PATTERNDATA    1084

#define MOD_SAMPLEINFO_SIZE           30

/*
 *  Constants for effects
 */

#define EFX_ARPEGGIO          0x00
#define EFX_PORTAUP           0x01
#define EFX_PORTADOWN         0x02
#define EFX_PORTANOTE         0x03
#define EFX_VIBRATO           0x04
#define EFX_PORTANOTEVOLSLIDE 0x05
#define EFX_VIBRATOVOLSLIDE   0x06
#define EFX_TREMOLO           0x07
#define EFX_UNUSED1           0x08 /* Unused EFX # */
#define EFX_SAMPLEOFFSET      0x09
#define EFX_VOLSLIDE          0x0a
#define EFX_JUMP              0x0b
#define EFX_VOLUME            0x0c
#define EFX_BREAK             0x0d
#define EFX_EXTENDED          0x0e /* should never appear in code */
#define EFX_SPEED             0x0f

#define EFX_FILTER            0x10 /* NOT SUPPORTED */
#define EFX_FINEPORTAUP       0x11
#define EFX_FINEPORTADOWN     0x12
#define EFX_GLISSANDO         0x13
#define EFX_VIBWAVEFORM       0x14
#define EFX_FINETUNE          0x15
#define EFX_LOOP              0x16
#define EFX_TREMWAVEFORM      0x17
#define EFX_UNUSED2           0x18 /* KarplusStrong in PT3.0; NOT SUPPORTED */
#define EFX_RETRIGGER         0x19
#define EFX_FINEVOLSLIDEUP    0x1a
#define EFX_FINEVOLSLIDEDOWN  0x1b
#define EFX_NOTECUT           0x1c
#define EFX_NOTEDELAY         0x1d
#define EFX_PATTERNDELAY      0x1e
#define EFX_INVERTEDLOOP      0x1f /* NOT SUPPORTED */

#define NR_EFX 32

#define WAVEFORM_SINE   0
#define WAVEFORM_RAMP   1
#define WAVEFORM_SQUARE 2
#define WAVEFORM_RANDOM 3

/*
 *  Structures used to store the module in memory.
 *  Notes are accessed with M.voice_pattern[voice][pattern].line[line]
 */

struct event {
    unsigned char note;
    unsigned char sample;
    unsigned char effect;
    unsigned char arg;
};

struct patternvoice {
    struct event line[64];
};

struct sample_info {
    char           name[23];
    char           finetune;
    unsigned short length;
    unsigned char  volume;
    char           valid;
    unsigned short repeat_start;
    unsigned short repeat_end;
    char           *data;
};

#define MAX_VOICES 8
#define MAX_SAMPLE 31

struct pos_info {
    int speed, tempo;
};

struct mod_info {
    char           name[21];
    char           filename[256];
    unsigned char  nr_voices;
    unsigned char  songlength;
    unsigned char  restartpos;
    unsigned short nr_patterns;
    unsigned short nr_samples;

    struct sample_info sample[31+1];    /* sample[0] not used     */
    unsigned char  patterntable[128];   /* order to play patterns */

    struct pos_info songpos_info[128];  /* info about speed etc. at
					 * different positions
					 */
    struct patternvoice *voice_pattern[MAX_VOICES];
    
    char           *sampledata; /* Not used currently, as samples are stored
				 * in GUS dram. Might come in handy with
				 * other soundcards later.
				 */
};

/*
 *  Structures used to play module
 */

struct voice {
    int sample;                /* Current sample    */
    char finetune;             /* Current finetune  */
    unsigned char volume;      /* Current volume    */
    unsigned char real_volume; /* Current volume used to play note */

    char note;            /* Current note(midi)*/

    int pitchbend;        /* Current pitchbend */
    int real_period;      /* Period used to calculate pitchbend */
    int period;           /* Period used to calculate effects   */

    int period_goal;      /* Period goal during toneportamento  */
    int toneporta_speed;  /* Speed of toneportamento            */
    char glissando;       /* True if glissando is on   */

    char vibrato;         /* True if we have vibrato   */
    char vibrato_retrig;  /* True if waveform is retriggered */
    int vibrato_amplitude;/* Amplitude of vibrato      */
    int vibrato_speed;    /* Speed of vibrato          */
    int vibrato_pos;      /* Position in vibratotable  */
    int vibrato_waveform; /* Waveform used for vibrato */

    char tremolo;         /* True if we have tremolo */
    char tremolo_retrig;  /* True if waveform is retriggered */
    int tremolo_amplitude;/* Amplitude of tremolo      */
    int tremolo_speed;    /* Speed of tremolo          */
    int tremolo_pos;      /* Position in vibratotable  */
    int tremolo_waveform; /* Waveform used for tremolo */

    unsigned short sampleoffset;      /* Current sample offset        */
    unsigned short last_sampleoffset; /* Last specified sample offset */

    char loopcount;       /* Remaining iterations  */
    char loopstartpos;    /* Loop restart position */
};

struct effects {
    /* The following 3 variables have the same names as in pt-replay.s to make
     * it easier for me to mimic it's behaviour. 
     */

    char PosJumpFlag; /* True when a new pattern should be activated at
		       * position PBreakPos (EFX_JMP|BREAK).
		       */
    char PBreakFlag;  /* True when we should jump back in pattern (EFX_LOOP) */
    
    char PBreakPos;   /* Line to start with in next pattern (EFX_JMP|BREAK) OR
		       * Line to jump to in current pattern (EFX_LOOP)
		       */

    char pattern_delay;

    char set_volume, set_finepitch;
    char note_delay, dont_trigger_note, kill_voice;
    unsigned char retrig_note;
};

/*
 *  Structure handling options for the current module
 */

struct options {
    char
	verbose,
	showlines,
	sync_output,
	nobpm,
	ntsc_samples,
	click_removal,
	random_mode,
	replay_forever;
    int 
	speed,
	tempo,
	start_pos,
	active_voices,
	loopcount,
	maxtime,
	speed0stop,

	format,
	low_note,
	high_note;
};

#define MAX_SONGS 256
#define BASE_NOTE (3*12)

/*
 *  16bit-word conversion from BigEndian (Motorola/Amiga)
 *  to LittleEndian (Intel/PC)
 */

#define BE2LE(a) (((a&0xff)<<8)|((a>>8)&0xff))

/*
 *  MIN - MAX macros
 */

#define MIN(x,y) (x < y ? x : y)
#define MAX(x,y) (x > y ? x : y)

/*
 *  Function prototypes
 */

/* main.c */

void play_samples(void);
void play_sample(int);

/* options.c */

void init_options(int, char *[]);
int get_next_module(void);

/* init.c */

void init_sound(void);
void cleanup_sound(void);

/* load.c */

int load_module(char *);
void process_header(char *);
int read_patterndata(int);
int read_and_upload_sample(int, int);
unsigned char period2note(unsigned int);
void fix_string(char *);
void free_module(void);

/* play.c */

void play_module(void);
void process_line(int);

int get_voice_balance(int);
void do_set_finepitch(int);
void print_line(int, int);
void print_event(char *, struct event *);

/* effects.c */

void check_tick0_efx(int);
void check_efx(int);
void check_remaining_efx(int);

void do_arpeggio(int, int);
void do_volumeslide(int, unsigned char);
void slide_volume(int, int);
void do_set_portamento(int, int);
void do_toneportamento(int);
void do_vibrato(int v);
void set_pitch(int);

#endif /* _MOD_H */
