📄 snd_gus.c
字号:
get_field_string(s,ts);
break;
}
// If we reach the end of the section, start over
if (feof(f) || is_section(ts,"*"))
fseek(f,section_buffers[current_section].offset,SEEK_SET);
if (ftell(f)==start_pos)
return;
}
}
}
//=============================================================================
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long
#define BUFFER_SIZE 4096
#define CODEC_ADC_INPUT_CONTROL_LEFT 0x00
#define CODEC_ADC_INPUT_CONTROL_RIGHT 0x01
#define CODEC_AUX1_INPUT_CONTROL_LEFT 0x02
#define CODEC_AUX1_INPUT_CONTROL_RIGHT 0x03
#define CODEC_AUX2_INPUT_CONTROL_LEFT 0x04
#define CODEC_AUX2_INPUT_CONTROL_RIGHT 0x05
#define CODEC_DAC_OUTPUT_CONTROL_LEFT 0x06
#define CODEC_DAC_OUTPUT_CONTROL_RIGHT 0x07
#define CODEC_FS_FORMAT 0x08
#define CODEC_INTERFACE_CONFIG 0x09
#define CODEC_PIN_CONTROL 0x0A
#define CODEC_ERROR_STATUS_AND_INIT 0x0B
#define CODEC_MODE_AND_ID 0x0C
#define CODEC_LOOPBACK_CONTROL 0x0D
#define CODEC_PLAYBACK_UPPER_BASE_COUNT 0x0E
#define CODEC_PLAYBACK_LOWER_BASE_COUNT 0x0F
#define SET_CONTROL 0x00
#define SET_FREQUENCY 0x01
#define SET_START_HIGH 0x02
#define SET_START_LOW 0x03
#define SET_END_HIGH 0x04
#define SET_END_LOW 0x05
#define SET_VOLUME_RATE 0x06
#define SET_VOLUME_START 0x07
#define SET_VOLUME_END 0x08
#define SET_CURR_VOLUME 0x09
#define SET_VOLUME 0x09
#define SET_ACC_HIGH 0x0A
#define SET_ACC_LOW 0x0B
#define SET_BALANCE 0x0C
#define SET_VOLUME_CONTROL 0x0D
#define SET_VOICES 0x0E
#define DMA_CONTROL 0x41
#define SET_DMA_ADDRESS 0x42
#define SET_DRAM_LOW 0x43
#define SET_DRAM_HIGH 0x44
#define ADLIB_CONTROL 0x45
#define ADLIB_TIMER1 0x46
#define ADLIB_TIMER2 0x47
#define SET_RECORD_RATE 0x48
#define RECORD_CONTROL 0x49
#define SET_JOYSTICK 0x4B
#define MASTER_RESET 0x4C
#define GET_CONTROL 0x80
#define GET_FREQUENCY 0x81
#define GET_START_HIGH 0x82
#define GET_START_LOW 0x83
#define GET_END_HIGH 0x84
#define GET_END_LOW 0x85
#define GET_VOLUME_RATE 0x86
#define GET_VOLUME_START 0x87
#define GET_VOLUME_END 0x88
#define GET_VOLUME 0x89
#define GET_ACC_HIGH 0x8A
#define GET_ACC_LOW 0x8B
#define GET_BALANCE 0x8C
#define GET_VOLUME_CONTROL 0x8D
#define GET_VOICES 0x8E
#define GET_IRQV 0x8F
struct CodecRateStruct
{
WORD Rate;
BYTE FSVal;
};
struct Gf1RateStruct
{
WORD Rate;
BYTE Voices;
};
//=============================================================================
// Reference variables in SND_DOS.C
//=============================================================================
extern short *dma_buffer;
//=============================================================================
// GUS-only variables
//=============================================================================
static BYTE HaveCodec=0;
static WORD CodecRegisterSelect;
static WORD CodecData;
static WORD CodecStatus;
static WORD Gf1TimerControl;
static WORD Gf1PageRegister;
static WORD Gf1RegisterSelect;
static WORD Gf1DataLow;
static WORD Gf1DataHigh;
static BYTE DmaChannel;
static BYTE PageRegs[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
static BYTE AddrRegs[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc };
static BYTE CountRegs[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce };
static WORD AddrReg;
static WORD CountReg;
static WORD ModeReg;
static WORD DisableReg;
static WORD ClearReg;
static struct CodecRateStruct CodecRates[]=
{
{ 5512,0x01},
{ 6620,0x0F},
{ 8000,0x00},
{ 9600,0x0E},
{11025,0x03},
{16000,0x02},
{18900,0x05},
{22050,0x07},
{27420,0x04},
{32000,0x06},
{33075,0x0D},
{37800,0x09},
{44100,0x0B},
{48000,0x0C},
{ 0,0x00} // End marker
};
static struct Gf1RateStruct Gf1Rates[]=
{
{19293,32},
{19916,31},
{20580,30},
{21289,29},
{22050,28},
{22866,27},
{23746,26},
{24696,25},
{25725,24},
{26843,23},
{28063,22},
{29400,21},
{30870,20},
{32494,19},
{34300,18},
{36317,17},
{38587,16},
{41160,15},
{44100,14},
{0,0}
};
//=============================================================================
// Basic GF1 functions
//=============================================================================
void SetGf18(BYTE reg,BYTE data)
{
dos_outportb(Gf1RegisterSelect,reg);
dos_outportb(Gf1DataHigh,data);
}
void SetGf116(BYTE reg,WORD data)
{
dos_outportb(Gf1RegisterSelect,reg);
dos_outportw(Gf1DataLow,data);
}
BYTE GetGf18(BYTE reg)
{
dos_outportb(Gf1RegisterSelect,reg);
return(dos_inportb(Gf1DataHigh));
}
WORD GetGf116(BYTE reg)
{
dos_outportb(Gf1RegisterSelect,reg);
return(dos_inportw(Gf1DataLow));
}
void Gf1Delay(void)
{
int i;
for (i=0;i<27;i++)
dos_inportb(Gf1TimerControl);
}
DWORD ConvertTo16(DWORD Address)
{
return( ((Address>>1) & 0x0001FFFF) | (Address & 0x000C0000L) );
}
void ClearGf1Ints(void)
{
int i;
SetGf18(DMA_CONTROL,0x00);
SetGf18(ADLIB_CONTROL,0x00);
SetGf18(RECORD_CONTROL,0x00);
GetGf18(DMA_CONTROL);
GetGf18(RECORD_CONTROL);
for (i=0;i<32;i++);
GetGf18(GET_IRQV);
}
//=============================================================================
// Get Interwave (UltraSound PnP) configuration if any
//=============================================================================
static qboolean GUS_GetIWData(void)
{
char *Interwave,s[INI_STRING_SIZE];
FILE *IwFile;
int CodecBase,CodecDma,i;
Interwave=getenv("INTERWAVE");
if (Interwave==NULL)
return(false);
// Open IW.INI
IwFile=ini_fopen(Interwave,"rt");
if (IwFile==NULL)
return(false);
// Read codec base and codec DMA
ini_fgets(IwFile,"setup 0","CodecBase",s);
sscanf(s,"%X",&CodecBase);
ini_fgets(IwFile,"setup 0","DMA2",s);
sscanf(s,"%i",&CodecDma);
ini_fclose(IwFile);
// Make sure numbers OK
if (CodecBase==0 || CodecDma==0)
return(false);
CodecRegisterSelect=CodecBase;
CodecData=CodecBase+1;
CodecStatus=CodecBase+2;
DmaChannel=CodecDma;
// Make sure there is a CODEC at the CODEC base
// Clear any pending IRQs
dos_inportb(CodecStatus);
dos_outportb(CodecStatus,0);
// Wait for 'INIT' bit to clear
for (i=0;i<0xFFFF;i++)
if ((dos_inportb(CodecRegisterSelect) & 0x80) == 0)
break;
if (i==0xFFFF)
return(false);
// Get chip revision - can not be zero
dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
if ((dos_inportb(CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID)
return(false);
if ((dos_inportb(CodecData) & 0x0F) == 0)
return(false);
HaveCodec=1;
Con_Printf("Sound Card is UltraSound PnP\n");
return(true);
}
//=============================================================================
// Get UltraSound MAX configuration if any
//=============================================================================
static qboolean GUS_GetMAXData(void)
{
char *Ultrasnd,*Ultra16;
int i;
int GusBase,Dma1,Dma2,Irq1,Irq2;
int CodecBase,CodecDma,CodecIrq,CodecType;
BYTE MaxVal;
Ultrasnd=getenv("ULTRASND");
Ultra16=getenv("ULTRA16");
if (Ultrasnd==NULL || Ultra16==NULL)
return(false);
sscanf(Ultrasnd,"%x,%i,%i,%i,%i",&GusBase,&Dma1,&Dma2,&Irq1,&Irq2);
sscanf(Ultra16,"%x,%i,%i,%i",&CodecBase,&CodecDma,&CodecIrq,&CodecType);
if (CodecType==0 && CodecDma!=0)
DmaChannel=CodecDma & 0x07;
else
DmaChannel=Dma2 & 0x07;
// Make sure there is a GUS at GUS base
dos_outportb(GusBase+0x08,0x55);
if (dos_inportb(GusBase+0x0A)!=0x55)
return(false);
dos_outportb(GusBase+0x08,0xAA);
if (dos_inportb(GusBase+0x0A)!=0xAA)
return(false);
// Program CODEC control register
MaxVal=((CodecBase & 0xF0)>>4) | 0x40;
if (Dma1 > 3)
MaxVal|=0x10;
if (Dma2 > 3)
MaxVal|=0x20;
dos_outportb(GusBase+0x106,MaxVal);
CodecRegisterSelect=CodecBase;
CodecData=CodecBase+1;
CodecStatus=CodecBase+2;
// Make sure there is a CODEC at the CODEC base
// Clear any pending IRQs
dos_inportb(CodecStatus);
dos_outportb(CodecStatus,0);
// Wait for 'INIT' bit to clear
for (i=0;i<0xFFFF;i++)
if ((dos_inportb(CodecRegisterSelect) & 0x80) == 0)
break;
if (i==0xFFFF)
return(false);
// Get chip revision - can not be zero
dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
if ((dos_inportb(CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID)
return(false);
if ((dos_inportb(CodecData) & 0x0F) == 0)
return(false);
HaveCodec=1;
Con_Printf("Sound Card is UltraSound MAX\n");
return(true);
}
//=============================================================================
// Get regular UltraSound configuration if any
//=============================================================================
static qboolean GUS_GetGUSData(void)
{
char *Ultrasnd;
int GusBase,Dma1,Dma2,Irq1,Irq2,i;
Ultrasnd=getenv("ULTRASND");
if (Ultrasnd==NULL)
return(false);
sscanf(Ultrasnd,"%x,%i,%i,%i,%i",&GusBase,&Dma1,&Dma2,&Irq1,&Irq2);
DmaChannel=Dma1 & 0x07;
// Make sure there is a GUS at GUS base
dos_outportb(GusBase+0x08,0x55);
if (dos_inportb(GusBase+0x0A)!=0x55)
return(false);
dos_outportb(GusBase+0x08,0xAA);
if (dos_inportb(GusBase+0x0A)!=0xAA)
return(false);
Gf1TimerControl = GusBase+0x008;
Gf1PageRegister = GusBase+0x102;
Gf1RegisterSelect = GusBase+0x103;
Gf1DataLow = GusBase+0x104;
Gf1DataHigh = GusBase+0x105;
// Reset the GUS
SetGf18(MASTER_RESET,0x00);
Gf1Delay();
Gf1Delay();
SetGf18(MASTER_RESET,0x01);
Gf1Delay();
Gf1Delay();
// Set to max (32) voices
SetGf18(SET_VOICES,0xDF);
// Clear any pending IRQ's
ClearGf1Ints();
// Set all registers to known values
for (i=0;i<32;i++)
{
dos_outportb(Gf1PageRegister,i);
SetGf18(SET_CONTROL,0x03);
SetGf18(SET_VOLUME_CONTROL,0x03);
Gf1Delay();
SetGf18(SET_CONTROL,0x03);
SetGf18(SET_VOLUME_CONTROL,0x03);
SetGf116(SET_START_HIGH,0);
SetGf116(SET_START_LOW,0);
SetGf116(SET_END_HIGH,0);
SetGf116(SET_END_LOW,0);
SetGf116(SET_ACC_HIGH,0);
SetGf116(SET_ACC_LOW,0);
SetGf18(SET_VOLUME_RATE,63);
SetGf18(SET_VOLUME_START,5);
SetGf18(SET_VOLUME_END,251);
SetGf116(SET_VOLUME,5<<8);
}
// Clear any pending IRQ's
ClearGf1Ints();
// Enable DAC etc.
SetGf18(MASTER_RESET,0x07);
// Enable line output so we can hear something
dos_outportb(GusBase,0x08);
HaveCodec=0;
Con_Printf("Sound Card is UltraSound\n");
return(true);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -