www.pudn.com > virtual_gameboy-0.8.8.zip > IBMADLIB.C


/* IbmAdlib.c 
   This file is part of the VGB-DOS project 
   Copyright (C) Marcel de Kogel (m.dekogel@student.utwente.nl), 1996 
   You may not use this file for commercial purposes 
   Please notify me if you make any changes to this file */ 
 
#include "GB.h" 
#include "IbmMsdos.h" 
 
#define NUM_CHANNELS            18 
 
#include  
#include  
#include  
 
int stereomode=1; 
static int got_sb=0; 
static byte gotadlib=0; 
static byte Sound_Reg[0x27]; 
static byte kbf[NUM_CHANNELS];                 /* KEY_BLOCK_F-NUMBER */ 
static int ChannelFreq[NUM_CHANNELS]; 
static int ChannelEnv[NUM_CHANNELS]; 
static int freqsweep[NUM_CHANNELS]; 
static int envsweep[NUM_CHANNELS]; 
static int envsweepparam[NUM_CHANNELS]; 
static byte channel_on[NUM_CHANNELS]; 
static byte tone_off[NUM_CHANNELS];     /* bit 1: sound on/off (reg 0x16) 
                                           bit 2: pan (reg 0x15) 
                                           bit 3: mode 3 on/off (reg 0x1A) 
                                           bit 4: speaker on/off (reg 0x14) */ 
static byte key_on[NUM_CHANNELS]; 
static word FMPoort=0x388; 
static byte sound_on=1; 
static byte sound_is_on=1; 
static byte vol_is_nul[NUM_CHANNELS]; 
static byte *channel_voice[NUM_CHANNELS]; 
static byte OPL3=1; 
static byte WriteSoundBusy=0; 
 
static word OpAd[]= 
{ 0x000,0x001,0x002,0x008,0x009,0x00A,0x010,0x011,0x012, 
  0x100,0x101,0x102,0x108,0x109,0x10A,0x110,0x111,0x112 }; 
 
static word ChanAd[]= 
{ 0x000,0x001,0x002,0x003,0x004,0x005,0x006,0x007,0x008, 
  0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107,0x108 }; 
 
static byte Sound_Melodic[11]= 
{ 
  0x23,0x21,    /* AM_VIB_EG-TYP_KSR_MULTI */ 
  0x1E,0x00,    /* KSL_TL                  */ 
  0xFF,0xFF,    /* AR_DR                   */ 
  0x08,0x08,    /* SL_RR                   */ 
  0x00,0x00,    /* WS                      */ 
  0x0E          /* FB_FM                   */ 
}; 
 
static byte Sound_Wave[11]= 
{ 
  0x23,0x21,    /* AM_VIB_EG-TYP_KSR_MULTI */ 
  0x1E,0x00,    /* KSL_TL                  */ 
  0xFF,0xFF,    /* AR_DR                   */ 
  0x08,0x08,    /* SL_RR                   */ 
  0x00,0x00,    /* WS                      */ 
  0x0A          /* FB_FM                   */ 
}; 
 
static byte Sound_Noise[11]= 
{ 
  0x2E,0x2E,    /* AM_VIB_EG-TYP_KSR_MULTI */ 
  0x40,0x03,    /* KSL_TL                  */ 
  0xFF,0xFF,    /* AR_DR                   */ 
  0x0F,0x0F,    /* SL_RR                   */ 
  0x00,0x03,    /* WS                      */ 
  0x0E          /* FB_FM                   */ 
}; 
 
static byte Sound_Melodic_OPL3[11]= 
{ 
  0x21,0x21,    /* AM_VIB_EG-TYP_KSR_MULTI */ 
  0x00,0x16,    /* KSL_TL                  */ 
  0xFF,0xFF,    /* AR_DR                   */ 
  0x0A,0x0A,    /* SL_RR                   */ 
  0x06,0x00,    /* WS                      */ 
  0x01          /* FB_FM                   */ 
}; 
 
static byte Sound_Wave_OPL3[11]= 
{ 
  0x21,0x21,    /* AM_VIB_EG-TYP_KSR_MULTI */ 
  0x06,0x10,    /* KSL_TL                  */ 
  0xFF,0xFF,    /* AR_DR                   */ 
  0x0A,0x0A,    /* SL_RR                   */ 
  0x06,0x00,    /* WS                      */ 
  0x01          /* FB_FM                   */ 
}; 
 
static word FMFreqs[] = 
{ 
 #include "FMFreqs.h" 
}; 
 
static void WriteFM_OPL2 (byte value,byte index) 
{ 
 int i; 
 outportb (FMPoort,index); 
 for (i=0;i<6;++i) 
  inportb (FMPoort); 
 outportb (FMPoort+1,value); 
 for (i=0;i<35;++i) 
  inportb (FMPoort); 
} 
 
static void WriteFM_OPL3_1 (byte value,byte index) 
{ 
 outportb (FMPoort,index); 
 inportb (FMPoort); 
 outportb (FMPoort+1,value); 
 inportb (FMPoort); 
 inportb (FMPoort); 
} 
 
static void WriteFM_OPL3_2 (byte value,byte index) 
{ 
 outportb (FMPoort+2,index); 
 inportb (FMPoort); 
 outportb (FMPoort+3,value); 
 inportb (FMPoort); 
 inportb (FMPoort); 
} 
 
static void WriteFM (byte value,word index) 
{ 
 if (OPL3) 
 { 
  if (index&0x100) 
   WriteFM_OPL3_2 (value,(byte)index); 
  else 
   WriteFM_OPL3_1 (value,(byte)index); 
 } 
 else 
 { 
  if ((index&0x100)==0) 
   WriteFM_OPL2 (value,(byte)index); 
 } 
} 
 
static byte ReadFM (void) 
{ 
 return inportb (FMPoort); 
} 
 
static void Adlib_ChannelOff (byte channel) 
{ 
 WriteFM (kbf[channel],0xB0+ChanAd[channel]); 
 key_on[channel]=0; 
} 
 
static void Adlib_ChannelOn (byte channel) 
{ 
 if (!sound_on) 
  return; 
 if (vol_is_nul[channel]) 
  return; 
 if (!channel_on[channel]) 
  return; 
 WriteFM (kbf[channel]|32,0xB0+ChanAd[channel]); 
 key_on[channel]=1; 
} 
 
void Adlib_SoundOff (void) 
{ 
 int i; 
 if (!gotadlib) 
  return; 
 sound_is_on=0; 
 for (i=0;i<4;++i) 
  Adlib_ChannelOff (i); 
} 
 
void Adlib_SoundOn (void) 
{ 
 int i; 
 if (!gotadlib) 
  return; 
 if (!sound_on) 
  return; 
 sound_is_on=1; 
 for (i=0;i<4;++i) 
  if (!tone_off[i]) 
   Adlib_ChannelOn (i); 
} 
 
void Adlib_ToggleSound (void) 
{ 
 if (!gotadlib) 
  return; 
 sound_on^=1; 
 if (sound_on) 
  Adlib_SoundOn (); 
 else 
  Adlib_SoundOff (); 
} 
 
void Adlib_ToggleChannel (int channel) 
{ 
 if (!gotadlib) 
  return; 
 if (!sound_on) 
  return; 
 if (!sound_is_on) 
  return; 
 channel_on[channel]^=1; 
 if (channel_on[channel]) 
  Adlib_ChannelOn (channel); 
 else 
  Adlib_ChannelOff (channel); 
} 
 
static void WriteVolume (byte vol,byte reg,byte index) 
{ 
 unsigned tl; 
/* 
 tl=63-(reg&63); 
 tl*=(vol&63); 
 tl/=64; 
 if (tl>=64) 
  tl=63; 
 tl=63-tl; 
*/ 
 if (vol==0) 
  tl=63; 
 else 
 { 
  if (vol>63) 
   vol=63; 
  tl=(reg&63)+(63-vol); 
  if (tl>63) 
   tl=63; 
 } 
 WriteFM ((reg&0xC0)|tl,index); 
} 
 
static void Adlib_SetVolume (byte channel,byte vol) 
{ 
 ChannelEnv[channel]=vol; 
 if (vol==0) 
 { 
  vol_is_nul[channel]=1; 
  if (!tone_off[channel]) 
   Adlib_ChannelOff (channel); 
  return; 
 } 
 if (vol_is_nul[channel]) 
 { 
  vol_is_nul[channel]=0; 
  if (!tone_off[channel]) 
   Adlib_ChannelOn (channel); 
 } 
 if (channel_voice[channel][10]&1)  /* additive synthesis */ 
  WriteVolume (vol,channel_voice[channel][2],0x40+OpAd[channel]); 
 WriteVolume (vol,channel_voice[channel][3],0x43+OpAd[channel]); 
} 
 
static void Adlib_SetFreq (byte channel, word freq) 
{ 
 int block,f; 
 ChannelFreq[channel]=freq; 
 f=FMFreqs[freq*2+1]; 
 block=FMFreqs[freq*2]; 
 WriteFM (f&0xFF,0xA0+ChanAd[channel]); 
 kbf[channel]=(f>>8)+(block<<2); 
 if (!tone_off[channel]) 
 { 
  if (f) 
   Adlib_ChannelOn (channel); 
  else 
   Adlib_ChannelOff (channel); 
 } 
} 
 
static void Adlib_SetVoice (char *voice,int channel) 
{ 
 WriteFM (voice[0],0x20+OpAd[channel]); 
 WriteFM (voice[1],0x23+OpAd[channel]); 
 WriteFM (voice[2],0x40+OpAd[channel]); 
 WriteFM (voice[3],0x43+OpAd[channel]); 
 WriteFM (voice[4],0x60+OpAd[channel]); 
 WriteFM (voice[5],0x63+OpAd[channel]); 
 WriteFM (voice[6],0x80+OpAd[channel]); 
 WriteFM (voice[7],0x83+OpAd[channel]); 
 WriteFM (voice[8],0xE0+OpAd[channel]); 
 WriteFM (voice[9],0xE3+OpAd[channel]); 
 if (OPL3) 
  WriteFM (voice[10]|0x30,0xC0+ChanAd[channel]); 
 else 
  WriteFM (voice[10],0xC0+ChanAd[channel]); 
 channel_voice[channel]=voice; 
} 
 
static void Adlib_SetVoices (void) 
{ 
 if (OPL3) 
 { 
  memcpy (Sound_Melodic,Sound_Melodic_OPL3,sizeof(Sound_Melodic)); 
  memcpy (Sound_Wave,Sound_Wave_OPL3,sizeof(Sound_Wave)); 
 } 
 Adlib_SetVoice (Sound_Melodic,0); 
 Adlib_SetVolume (0,15); 
 Adlib_SetVoice (Sound_Melodic,1); 
 Adlib_SetVolume (1,15); 
 Adlib_SetVoice (Sound_Wave,2); 
 Adlib_SetVolume (2,15); 
 Adlib_SetVoice (Sound_Noise,3); 
 Adlib_SetVolume (3,15); 
} 
 
static int Reset_Adlib (void) 
{ 
 byte tmp1,tmp2; 
 int i; 
 WriteFM (0,1); 
 WriteFM (0x60,4); 
 WriteFM (0x80,4); 
 tmp1=ReadFM (); 
 WriteFM (0xFF,2); 
 WriteFM (0x21,4); 
 for (i=0;i<300;++i) 
  ReadFM (); 
 tmp2=ReadFM (); 
 WriteFM (0x60,4); 
 WriteFM (0x80,4); 
 if ((tmp1&0xE0)!=0) 
  return 0; 
 if ((tmp2&0xE0)!=0xC0) 
  return 0; 
 WriteFM (0,1); 
 return 1; 
} 
 
int Adlib_Init (void) 
{ 
 if (SB_Info.baseport) 
 { 
  if (SB_Info.type>=4) 
   FMPoort=SB_Info.baseport; 
  else 
  { 
   FMPoort=SB_Info.baseport+8; 
   OPL3=0; 
  } 
 } 
 if (!Reset_Adlib()) 
  return 0; 
 if (OPL3) 
 { 
  if ((ReadFM()&6)==0) 
  { 
   WriteFM (1,0x105); 
   WriteFM (0,0x104); 
  } 
  else 
   OPL3=0; 
 } 
 memset (vol_is_nul,0,sizeof(vol_is_nul)); 
 memset (tone_off,0,sizeof(tone_off)); 
 memset (ChannelFreq,0,sizeof(ChannelFreq)); 
 memset (ChannelEnv,0,sizeof(ChannelEnv)); 
 memset (freqsweep,0,sizeof(freqsweep)); 
 memset (envsweep,0,sizeof(envsweep)); 
 memset (envsweepparam,0,sizeof(envsweepparam)); 
 memset (channel_on,1,sizeof(channel_on)); 
 WriteFM (0x00,0xBD); 
 WriteFM (0,8); 
 Adlib_SetVoices (); 
 gotadlib=1; 
 got_sb=sb_init (); 
 return FMPoort+(OPL3<<16)+(got_sb<<17); 
} 
 
void Adlib_Reset (void) 
{ 
 int i; 
 if (!gotadlib) 
  return; 
 for (i=0;i<4;++i) 
 { 
  Adlib_ChannelOff (i); 
  Adlib_SetVolume (i,0); 
 } 
 if (OPL3) 
  WriteFM (0,0x105); 
 OPL3=0; 
 Reset_Adlib (); 
 WriteFM (0x00,0xBD); 
 WriteFM (0,8); 
 if (got_sb) 
  sb_exit (); 
} 
 
/* High nibble: AND mask */ 
/* Low nibble: OR mask */ 
static void Adlib_ToneOn (byte channel,byte state,int keyon) 
{ 
 int oldstate,newstate; 
 oldstate=(tone_off[channel])? 1:0; 
 tone_off[channel]|=(state&0x0F); 
 tone_off[channel]&=(state>>4); 
 newstate=(tone_off[channel])? 1:0; 
/* if (oldstate!=newstate) */ 
 { 
  if (keyon) 
  { 
   if (!tone_off[channel]) 
    Adlib_ChannelOn (channel); 
   else 
    Adlib_ChannelOff (channel); 
  } 
  else 
   Adlib_ChannelOff (channel); 
 } 
} 
 
static void Adlib_SetPan (int channel,int left,int right) 
{ 
 byte regval; 
 if (OPL3) 
 { 
  regval=channel_voice[channel][10]; 
  if (left) 
   regval|=(stereomode==1)? 0x10:0x20; 
  if (right) 
   regval|=(stereomode==1)? 0x20:0x10; 
  if (!stereomode && (left || right)) 
   regval|=0x30; 
  WriteFM (regval,0xC0+ChanAd[channel]); 
 } 
 else 
  Adlib_ToneOn (channel,(left | right)? 0xD0:0xF2,1); 
} 
 
static byte GetSoundVolume (byte v) 
{ 
 const byte voltable[16] = 
 { 0,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60 }; 
 return voltable[(v>>4)&15]; 
} 
 
static int GetEnvSweep (byte channel,byte v) 
{ 
 const int envsweeptabel[8]={ 0,1,3,5,7,9,11,13 }; 
/* printf ("EnvSweep %u,%02x\n",channel,v); */ 
 return (envsweeptabel[v&7])*((v&8)? 1:-1); 
} 
 
static int GetFreqSweep (byte v) 
{ 
 const int freqsweeptabel[8]= { 0,7,4,3,2,1,1,1 }; 
 return (v&7)*freqsweeptabel[(v&30)>>4]*((v&0x08)? -1:1); 
} 
 
void Adlib_WriteSoundReg (byte r,word v) 
{ 
 static byte Mode3_VolTable[4]= { 0,54,52,50 }; 
 static int fmvol[8]= { 0,9,10,11,12,13,14,15 }; 
 if (!gotadlib) 
  return; 
 WriteSoundBusy=1; 
 switch (r) 
 { 
  case 0x00:    /* mode 1 frequency sweep */ 
   freqsweep[0]=GetFreqSweep(v); 
   break; 
  case 0x01:    /* mode 1 len / duty */ 
   break; 
  case 0x02:    /* mode 1 envelope sweep */ 
   Adlib_SetVolume (0,GetSoundVolume(v)); 
   envsweep[0]=GetEnvSweep(0,v); 
   break; 
  case 0x03:    /* mode 1 freq lo */ 
   Adlib_SetFreq (0,v | ((Sound_Reg[4]&7)<<8)); 
   break; 
  case 0x04:    /* mode 1 freq hi */ 
   if (v&0x80) 
   { 
/*    Adlib_ChannelOff (0); */ 
    if (envsweep[0]) 
     Adlib_SetVolume (0,GetSoundVolume(Sound_Reg[2])); 
   } 
   Adlib_SetFreq (0,((v&7)<<8) | Sound_Reg[3]); 
   break; 
  case 0x05:    /* mode 2 frequency sweep (?) */ 
   freqsweep[1]=GetFreqSweep(v); 
   break; 
  case 0x06:    /* mode 2 len / duty */ 
   break; 
  case 0x07:    /* mode 2 envelope sweep */ 
   Adlib_SetVolume (1,GetSoundVolume(v)); 
   envsweep[1]=GetEnvSweep(1,v); 
   break; 
  case 0x08:    /* mode 2 freq lo */ 
   Adlib_SetFreq (1,v | ((Sound_Reg[9]&7)<<8)); 
   break; 
  case 0x09:    /* mode 2 freq hi */ 
   if (v&0x80) 
   { 
/*    Adlib_ChannelOff (1); */ 
    if (envsweep[1]) 
     Adlib_SetVolume (1,GetSoundVolume(Sound_Reg[7])); 
   } 
   Adlib_SetFreq (1,((v&7)<<8) | Sound_Reg[8]); 
   break; 
  case 0x0A:    /* mode 3 on/off */ 
   Adlib_ToneOn (2,(v&0x80)? 0xB0:0xF4,1); 
   break; 
  case 0x0B:    /* mode 3 len */ 
   break; 
  case 0x0C:    /* mode 3 output level */ 
   Adlib_SetVolume (2,Mode3_VolTable[(v&0x60)>>5]); 
   break; 
  case 0x0D:    /* mode 3 freq lo */ 
   Adlib_SetFreq (2,v | ((Sound_Reg[0x0E]&7)<<8)); 
   break; 
  case 0x0E:    /* mode 3 freq hi */ 
   if (v&0x80) 
   { 
    Adlib_ChannelOff (2); 
   } 
   Adlib_SetFreq (2,((v&7)<<8) | Sound_Reg[0x0D]); 
   break; 
  case 0x10:    /* mode 4 len */ 
   break; 
  case 0x11:    /* mode 4 envelope */ 
   Adlib_SetVolume (3,GetSoundVolume(v)); 
   envsweep[3]=GetEnvSweep(3,v); 
   break; 
  case 0x12:    /* mode 4 polynomial counter */ 
   Adlib_SetFreq (3,1100); 
   break; 
  case 0x13:    /* mode 4 counter initial */ 
   break; 
  case 0x14:    /* channel control */ 
   if (got_sb) 
    sb_setfmvolume (fmvol[(v&0x70)>>4],fmvol[v&0x07]); 
   break; 
  case 0x15:    /* selection of sound output terminal */ 
   Adlib_SetPan (0,v&0x10,v&0x01); 
   Adlib_SetPan (1,v&0x20,v&0x02); 
   Adlib_SetPan (2,v&0x40,v&0x04); 
   Adlib_SetPan (3,v&0x80,v&0x08); 
   break; 
  case 0x16:    /* sound on/off */ 
   if ((v&0x80)==0) 
   { 
    Adlib_ToneOn (0,0xF1,1); 
    Adlib_ToneOn (1,0xF1,1); 
    Adlib_ToneOn (2,0xF1,1); 
    Adlib_ToneOn (3,0xF1,1); 
   } 
   else 
   { 
    Adlib_ToneOn (0,0xE0,key_on[0]); 
    Adlib_ToneOn (1,0xE0,key_on[1]); 
    Adlib_ToneOn (2,0xE0,key_on[2]); 
    Adlib_ToneOn (3,0xE0,key_on[3]); 
   } 
   break; 
 } 
 Sound_Reg[r]=v; 
 WriteSoundBusy=0; 
} 
 
#define envperiod       1 
#define freqperiod      2 
void Adlib_InterruptRoutine (void) 
{ 
 int i,tmp; 
 static int envcount=1; 
 static int freqcount=1; 
 if (WriteSoundBusy) 
  return; 
 WriteSoundBusy=1; 
 __enable (); 
 if (!--envcount) 
 { 
  envcount=envperiod; 
  for (i=0;i63) 
      tmp=63; 
     if (tmp!=ChannelEnv[i]) 
      Adlib_SetVolume (i,tmp); 
    } 
   } 
  } 
 } 
 if (!--freqcount) 
 { 
  freqcount=freqperiod; 
  for (i=0;i2047) 
     tmp=2047; 
    if (tmp!=ChannelFreq[i]) 
     Adlib_SetFreq (i,tmp); 
   } 
  } 
 } 
 WriteSoundBusy=0; 
} 
 
void Adlib_DecreaseVolume (void) 
{ 
 if (got_sb) 
  sb_decreasemastervolume (); 
} 
 
void Adlib_IncreaseVolume (void) 
{ 
 if (got_sb) 
  sb_increasemastervolume (); 
}