⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibmadlib.c

📁 知名gba模拟器vgba代码
💻 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 <pc.h>
#include <stdio.h>
#include <string.h>

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;i<NUM_CHANNELS;++i)
  {
   if (envsweep[i])
   {
    if (envsweepparam[i])
     --envsweepparam[i];
    else
    {
     envsweepparam[i]=abs(envsweep[i]);
     tmp=ChannelEnv[i]+((envsweep[i]<0)? -1:1);
     if (tmp<0)
      tmp=0;
     if (tmp>63)
      tmp=63;
     if (tmp!=ChannelEnv[i])
      Adlib_SetVolume (i,tmp);
    }
   }
  }
 }
 if (!--freqcount)
 {
  freqcount=freqperiod;
  for (i=0;i<NUM_CHANNELS;++i)
  {
   if (freqsweep[i])
   {
    tmp=ChannelFreq[i]+freqsweep[i];
    if (tmp<0)
     tmp=0;
    if (tmp>2047)
     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 ();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -