📄 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 <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 + -