
#ifndef GUS_H_INCLUDED

#define MaxChannels  32
#define MaxPeriod    1000           // Max & Min period for Amiga limits
#define MinPeriod    20

#define ActiveVoice  0x102
#define Command      0x103
#define DataLow      0x104
#define DataHigh     0x105
#define DRamIo       0x107

extern unsigned char AmpliferVolume;
extern unsigned char DefaultPanning;           // Default Panning;  0..7
extern unsigned short UltraBase;               // GUS Base Address
extern unsigned short ModError;                // 0..3 and 255

extern unsigned short ActiveVoice2;
extern unsigned short Command2;
extern unsigned short DataLow2;
extern unsigned short DataHigh2;
extern unsigned short DRamIo2;

extern int TopAdress;                 // Next free address in GUS mem
extern int GUSBank;

extern unsigned char GUSInfo[8];
extern unsigned short GUSVolume[65];

struct Channel
{
  unsigned char  Vol;             // Current Volume 0..64
  unsigned char  Note;            // Current Note 1--"C1" to 48--"B4"
  unsigned short Per, DesPer;     // Period & Destination period for portamentos
  unsigned char  Sample;          // Current Sample number
  unsigned char  Pan;             // GUS Panning option
  unsigned char  Fx, FxData;
  unsigned char  FxSl2, FxVib;    // Slide To & Vibrato, FX data
  unsigned char  VibWave;         // Vibrato WaveForm
  unsigned char  VibCnt;          // Vibrato Counter
  unsigned char  RetrigCnt;       // Retrig Counter
  unsigned char  Arp1, Arp2;      // Arpeggio Parametrs
  unsigned char  ArpeggioCnt;     // Arpeggio Counter
  unsigned char  FxStart;         // Tick to start for channel
  unsigned char  On;              // When 0 = channel is muted
  unsigned char  Bar;             // Volume Bar
  unsigned char  Hit;
  unsigned char  NoFx;            // 1 = Don't get new FX
};

struct MODSample
{
  char  Name[40];        // Name of sample
  int   Addr;            // Address in GUS Mem
  unsigned short Length;
  unsigned short LoopStart;
  unsigned short LoopEnd;
  unsigned char  FTune;
  unsigned char  Volume;
};

struct MODNote
{
  unsigned short Per;
  unsigned char  Note;
  unsigned char  Sample;
  unsigned char  Fx, FxData;
};

struct MODHeader
{
  char Name[20];
  unsigned char Length;
  char Tag[5];                    // e.g. "6CHN" Tag Field
  unsigned char Chns;             // Number of channels in MOD, 4..12
  unsigned char Samples;          // 15 or 31
};

typedef struct MODNote MODPattern[64][MaxChannels];

char _HI_(short);
void _CLI_(void);
void _STI_(void);
short swap(short);
#pragma aux _HI_ = "mov al,ah" parm caller [ax] value [al];
#pragma aux _CLI_ = "cli";
#pragma aux _STI_ = "sti";
#pragma aux swap = "xchg al,ah" parm caller [ax] value [ax];

void GUSDelay(void);
#pragma aux GUSDelay = "mov dx,UltraBase"\
                       "add dx,0x100"\
                       "in  al,dx"\
                       "in  al,dx"\
                       "in  al,dx"\
                       "in  al,dx"\
                       "in  al,dx"\
                       "in  al,dx"\
                       "in  al,dx"\
                       modify [ax dx];

void GUSSetFreq(char, short);
#pragma aux GUSSetFreq = "cli"\
                         "mov  dx,ActiveVoice2"\
                         "out  dx,al"\
                         "mov  dx,Command2"\
                         "mov  al,1"\
                         "out  dx,al"\
                         "mov  dx,DataLow2"\
                         "mov  ax,bx"\
                         "out  dx,ax"\
                         "sti"\
                         parm caller [al] [bx] modify [ax dx];

void GUSVoiceControl(char, char);
#pragma aux GUSVoiceControl = "cli"\
                              "mov   dx,UltraBase"\
                              "add   dx,0x102"\
                              "out   dx,al"\
                              "out   dx,al"\
                              "out   dx,al"\
                              "inc   dx"\
                              "xor   al,al"\
                              "out   dx,al"\
                              "add   dx,2"\
                              "mov   al,ah"\
                              "out   dx,al"\
                              "sti"\
                              parm caller [al] [ah] modify [ax dx];

void GUSSetBalance(unsigned char, unsigned char);
#pragma aux GUSSetBalance = "cli"\
                            "mov  dx,ActiveVoice2"\
                            "out  dx,al"\
                            "mov  dx,Command2"\
                            "mov  al,0xC"\
                            "out  dx,al"\
                            "mov  dx,DataHigh2"\
                            "mov  al,ah"\
                            "out  dx,al"\
                            "sti"\
                            parm caller [al] [ah] modify [ax dx];

void GUSSetVolume(char, short);
#pragma aux GUSSetVolume = "cli"\
                           "mov  dx,ActiveVoice2"\
                           "out  dx,al"\
                           "mov  dx,Command2"\
                           "mov  al,9"\
                           "out  dx,al"\
                           "mov  dx,DataLow2"\
                           "mov  ax,bx"\
                           "out  dx,ax"\
                           "sti"\
                           parm caller [al] [bx] modify [ax dx];

void GUSSetLoopMode(char);
#pragma aux GUSSetLoopMode = "cli"\
                             "mov dx,UltraBase"\
                             "add dx,0x102"\
                             "out dx,al"\
                             "out dx,al"\
                             "out dx,al"\
                             "inc dx"\
                             "mov al,0x80"\
                             "out dx,al"\
                             "add dx,2"\
                             "in  al,dx"\
                             "mov ah,al"\
                             "xor al,al"\
                             "sub dx,2"\
                             "out dx,al"\
                             "add dx,2"\
                             "and ah,0xE7"\
                             "mov al,ah"\
                             "out dx,al"\
                             "sti"\
                             parm caller [al] modify [ax dx];

void GUSRelVoices(char);                // bl - number of voices
#pragma aux GUSRelVoices = "onevoice:"\
                           "mov  dx,UltraBase"\
                           "add  dx,0x102"\
                           "mov  al,bl"\
                           "out  dx,al"\
                           "inc  dx"\
                           "mov  al,0x80"\
                           "out  dx,al"\
                           "add  dx,2"\
                           "in   al,dx"\
                           "xor  al,al"\
                           "sub  dx,2"\
                           "out  dx,al"\
                           "add  dx,2"\
                           "mov  cl,al"\
                           "and  cl,0xFD"\
                           "mov  al,cl"\
                           "out  dx,al"\
                           "dec  bl"\
                           "jnz  onevoice"\
                           parm caller [bl] modify [ax dx bx cx];

void SetTimer(unsigned short Ticks);
#pragma aux SetTimer = "cli"\
                       "mov  al,36h"\
                       "out  43h,al"\
                       "nop"\
                       "nop"\
                       "nop"\
                       "mov  al,cl"\
                       "out  40h,al"\
                       "nop"\
                       "nop"\
                       "nop"\
                       "mov  al,ch"\
                       "out  40h,al"\
                       "nop"\
                       "nop"\
                       "nop"\
                       "sti"\
                       parm caller [cx] modify [ax];

void Load2GUS(int, char*);
#pragma aux Load2GUS = "byteload:"\
                       "mov   eax,TopAdress"\
                       "mov   edi,eax"\
                       "shr   eax,16"\
                       "and   eax,0xFF"\
                       "mov   ebx,eax"\
                       "mov   dx,Command2"\
                       "mov   al,43h"\
                       "out   dx,al"\
                       "mov   dx,DataLow2"\
                       "mov   eax,edi"\
                       "out   dx,ax"\
                       "mov   dx,Command2"\
                       "mov   al,44h"\
                       "out   dx,al"\
                       "mov   dx,DataHigh2"\
                       "mov   eax,ebx"\
                       "out   dx,ax"\
                       "inc   TopAdress"\
                       "mov   dx,DRamIo2"\
                       "outsb"\
                       "loop  byteload"\
                       parm caller [ecx] [esi] modify [eax ebx ecx edx esi edi];

extern int VoicePos(unsigned char V);
extern char GUSPeek(unsigned int Loc);
extern void GUSPoke(unsigned int Loc, unsigned char B);
extern int GUSProbe(unsigned short Adr);
extern void GUSFind(void);
extern int GUSFindMem(void);
extern void GUSStopVoice(unsigned char V);
extern void GUSPlayVoice(unsigned char V, unsigned char Mode, unsigned int VBegin,
                         unsigned int VStart, unsigned int VEnd);
extern void GUSPlayAll(unsigned char V, unsigned char Mode, unsigned int VBegin,
                       unsigned int VStart, unsigned int VEnd, unsigned short Freq,
                       unsigned short Vol);
extern void GUSRelVoice(unsigned char V);
extern void GUSSetOfs(unsigned char V, unsigned int VBegin);
extern void GUSReset(void);
extern void GUSDeInit(void);

#define GUS_H_INCLUDED

#endif
