aboutsummaryrefslogtreecommitdiffstats
path: root/WinQuake/snd_gus.c
diff options
context:
space:
mode:
authorwyatt8740 <wyatt8740@yahoo.com>2014-01-06 12:02:16 -0500
committerwyatt8740 <wyatt8740@yahoo.com>2014-01-06 12:02:16 -0500
commita8f828a066773a59fdf646299359d35ae0e845af (patch)
tree86123409fc6f231cf4136e81159b63cb1e9ec102 /WinQuake/snd_gus.c
parentb2951690415054ae8705c07f8df7a4ba7cde382a (diff)
downloadquake-pum-a8f828a066773a59fdf646299359d35ae0e845af.tar.gz
Removed accidental upload of copyrighted map files
Diffstat (limited to 'WinQuake/snd_gus.c')
-rw-r--r--WinQuake/snd_gus.c2586
1 files changed, 1293 insertions, 1293 deletions
diff --git a/WinQuake/snd_gus.c b/WinQuake/snd_gus.c
index dd1376f..7c567ca 100644
--- a/WinQuake/snd_gus.c
+++ b/WinQuake/snd_gus.c
@@ -1,1293 +1,1293 @@
-/*
-Copyright (C) 1996-1997 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-//=============================================================================
-// Routines for GUS support in QUAKE
-//
-// Author(s): Jayeson Lee-Steere
-//=============================================================================
-
-#include "quakedef.h"
-#include "dosisms.h"
-
-//=============================================================================
-// Author(s): Jayeson Lee-Steere
-
-#define INI_STRING_SIZE 0x100
-
-FILE *ini_fopen(const char *filename, const char *modes);
-int ini_fclose(FILE *f);
-void ini_fgets(FILE *f, const char *section, const char *field, char *s);
-
-// Routines for reading from .INI files
-// The read routines are fairly efficient.
-//
-// Author(s): Jayeson Lee-Steere
-
-#define MAX_SECTION_WIDTH 20
-#define MAX_FIELD_WIDTH 20
-
-#define NUM_SECTION_BUFFERS 10
-#define NUM_FIELD_BUFFERS 20
-
-struct section_buffer
-{
- long offset;
- char name[MAX_SECTION_WIDTH+1];
-};
-
-struct field_buffer
-{
- long offset;
- int section;
- char name[MAX_FIELD_WIDTH+1];
-};
-
-static FILE *current_file=NULL;
-static int current_section;
-
-static int current_section_buffer=0;
-static int current_field_buffer=0;
-
-static struct section_buffer section_buffers[NUM_SECTION_BUFFERS];
-static struct field_buffer field_buffers[NUM_FIELD_BUFFERS];
-//***************************************************************************
-// Internal routines
-//***************************************************************************
-static char toupper(char c)
-{
- if (c>='a' && c<='z')
- c-=('a'-'A');
- return(c);
-}
-
-static void reset_buffer(FILE *f)
-{
- int i;
-
- for (i=0;i<NUM_SECTION_BUFFERS;i++)
- section_buffers[i].name[0]=0;
- for (i=0;i<NUM_FIELD_BUFFERS;i++)
- field_buffers[i].name[0]=0;
-
- current_file=f;
-}
-
-// Sees if the current string is section "name" (i.e. ["name"]).
-// If "name"=="*", sees if the current string is any section
-// (i.e. [....]). Returns 1 if true else 0 if false.
-static int is_section(char *s,const char *name)
-{
- int wild=0;
-
- // See if wild search
- if (strcmp("*",name)==0)
- wild=1;
-
- // Skip leading spaces
- while (s[0]==' ')
- s++;
- // Look for leading "["
- if (s[0]!='[')
- return(0);
- s++;
- // Make sure name matches
- while (s[0]!=']' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
- {
- if (!wild)
- if (toupper(s[0])!=toupper(name[0]))
- return(0);
- s++;
- if (!wild)
- name++;
- }
- if (!wild)
- if (name[0]!=0)
- return(0);
- // Skip trailing spaces
- while (s[0]==' ')
- s++;
- // Make sure we have trailing "]"
- if (s[0]!=']')
- return(0);
- return(1);
-}
-
-// Sees if the current string is field "name" (i.e. "name"=...).
-// If "name"=="*", sees if the current string is any field
-// (i.e. ...=...). Returns 1 if true else 0 if false.
-static int is_field(char *s,const char *name)
-{
- int wild=0;
-
- // See if wild search
- if (strcmp("*",name)==0)
- wild=1;
-
- // Skip leading spaces
- while (s[0]==' ')
- s++;
-
- // Make sure name matches
- while (s[0]!='=' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
- {
- if (!wild)
- if (toupper(s[0])!=toupper(name[0]))
- return(0);
- s++;
- if (!wild)
- name++;
- }
- if (!wild)
- if (name[0]!=0)
- return(0);
- // Skip trailing spaces
- while (s[0]==' ')
- s++;
- // Make sure we have an "="
- if (s[0]!='=')
- return(0);
-
- return(1);
-}
-
-// Extracts the section name from a section heading
-// e.g. in="[hey man]" gives out="hey man"
-static void get_section_name(char *out, char *in)
-{
- int i=0;
-
- // Skip spaces before '['
- while (in[0]==' ')
- in++;
- // Make sure there is a '['
- if (in[0]!='[')
- {
- out[0]=0;
- return;
- }
- // Skip past '['
- in++;
- // Copy string if any to output string.
- while (in[0]!=']' && in[0]!=13 && in[0]!=10 && in[0]!=0)
- {
- if (i<MAX_SECTION_WIDTH)
- {
- out[i]=in[0];
- i++;
- }
- in++;
- }
- // Make sure string was terminated with ']'
- if (in[0]!=']')
- {
- out[0]=0;
- return;
- }
- // Remove trailing spaces
- while (i>0 && out[i-1]==' ')
- i--;
- // Null terminate the output string.
- out[i]=0;
-}
-
-// Extracts the field name from a field line
-// e.g. in="sooty=life be in it" gives out="sooty"
-static void get_field_name(char *out, char *in)
-{
- int i=0;
-
- // Skip leading spaces
- while (in[0]==' ')
- in++;
- // Copy name to output string
- while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
- {
- if (i<MAX_FIELD_WIDTH)
- {
- out[i]=in[0];
- i++;
- }
- in++;
- }
- // Make sure we stopped on "="
- if (in[0]!='=')
- {
- out[0]=0;
- return;
- }
- // Remove trailing spaces
- while (i>0 && out[i-1]==' ')
- i--;
- // Null terminate the output string.
- out[i]=0;
-}
-
-// Returns the field data from string s.
-// e.g. in="wally = golly man" gives out="golly man"
-static void get_field_string(char *out, char *in)
-{
- int i=0;
-
- // Find '=' if it exists
- while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
- in++;
- // If there is an '=', skip past it.
- if (in[0]=='=')
- in++;
- // Skip any spaces between the '=' and string.
- while (in[0]==' ' || in[0]=='[')
- in++;
- // Copy string, if there is one, to the output string.
- while (in[0]!=13 && in[0]!=10 && in[0]!=0 && i<(INI_STRING_SIZE-1))
- {
- out[i]=in[0];
- in++;
- i++;
- }
- // Null terminate the output string.
- out[i]=0;
-}
-
-// Adds a section to the buffer
-static int add_section(char *instring, long offset)
-{
- int i;
- char section[MAX_SECTION_WIDTH+1];
-
- // Extract section name
- get_section_name(section,instring);
- // See if section already exists.
- for (i=0;i<NUM_SECTION_BUFFERS;i++)
- if (stricmp(section,section_buffers[i].name)==0)
- return(i);
- // Increment current_section_buffer
- current_section_buffer++;
- if (current_section_buffer>NUM_SECTION_BUFFERS)
- current_section_buffer=0;
- // Delete any field buffers that correspond to this section
- for (i=0;i<NUM_FIELD_BUFFERS;i++)
- if (field_buffers[i].section==current_section_buffer)
- field_buffers[i].name[0]=0;
- // Set buffer information
- strcpy(section_buffers[current_section_buffer].name,section);
- section_buffers[current_section_buffer].offset=offset;
- return(current_section_buffer);
-}
-
-// Adds a field to the buffer
-static void add_field(char *instring, int section, long offset)
-{
- int i;
- char field[MAX_FIELD_WIDTH+1];
-
- // Extract field name
- get_field_name(field,instring);
- // See if field already exists
- for (i=0;i<NUM_FIELD_BUFFERS;i++)
- if (field_buffers[i].section==section)
- if (stricmp(field_buffers[i].name,field)==0)
- return;
- // Increment current_field_buffer
- current_field_buffer++;
- if (current_field_buffer>NUM_FIELD_BUFFERS)
- current_field_buffer=0;
- // Set buffer information
- strcpy(field_buffers[current_field_buffer].name,field);
- field_buffers[current_field_buffer].section=section;
- field_buffers[current_field_buffer].offset=offset;
-}
-
-// Identical to fgets except the string is trucated at the first ';',
-// carriage return or line feed.
-static char *stripped_fgets(char *s, int n, FILE *f)
-{
- int i=0;
-
- if (fgets(s,n,f)==NULL)
- return(NULL);
-
- while (s[i]!=';' && s[i]!=13 && s[i]!=10 && s[i]!=0)
- i++;
- s[i]=0;
-
- return(s);
-}
-
-//***************************************************************************
-// Externally accessable routines
-//***************************************************************************
-// Opens an .INI file. Works like fopen
-FILE *ini_fopen(const char *filename, const char *modes)
-{
- return(fopen(filename,modes));
-}
-
-// Closes a .INI file. Works like fclose
-int ini_fclose(FILE *f)
-{
- if (f==current_file)
- reset_buffer(NULL);
- return(fclose(f));
-}
-
-// Puts "field" from "section" from .ini file "f" into "s".
-// If "section" does not exist or "field" does not exist in
-// section then s="";
-void ini_fgets(FILE *f, const char *section, const char *field, char *s)
-{
- int i;
- long start_pos,string_start_pos;
- char ts[INI_STRING_SIZE*2];
-
- if (f!=current_file)
- reset_buffer(f);
-
- // Default to "Not found"
- s[0]=0;
-
- // See if section is in buffer
- for (i=0;i<NUM_SECTION_BUFFERS;i++)
- if (strnicmp(section_buffers[i].name,section,MAX_SECTION_WIDTH)==0)
- break;
-
- // If section is in buffer, seek to it if necessary
- if (i<NUM_SECTION_BUFFERS)
- {
- if (i!=current_section)
- {
- current_section=i;
- fseek(f,section_buffers[i].offset,SEEK_SET);
- }
- }
- // else look through .ini file for it.
- else
- {
- // Make sure we are not at eof or this will cause trouble.
- if (feof(f))
- rewind(f);
- start_pos=ftell(f);
- while (1)
- {
- stripped_fgets(ts,INI_STRING_SIZE*2,f);
- // If it is a section, add it to the section buffer
- if (is_section(ts,"*"))
- current_section=add_section(ts,ftell(f));
- // If it is the section we are looking for, break.
- if (is_section(ts,section))
- break;
- // If we reach the end of the file, rewind to the start.
- if (feof(f))
- rewind(f);
- if (ftell(f)==start_pos)
- return;
- }
- }
-
- // See if field is in buffer
- for (i=0;i<NUM_FIELD_BUFFERS;i++)
- if (field_buffers[i].section==current_section)
- if (strnicmp(field_buffers[i].name,field,MAX_FIELD_WIDTH)==0)
- break;
-
- // If field is in buffer, seek to it and read it
- if (i<NUM_FIELD_BUFFERS)
- {
- fseek(f,field_buffers[i].offset,SEEK_SET);
- stripped_fgets(ts,INI_STRING_SIZE*2,f);
- get_field_string(s,ts);
- }
- else
- // else search through section for field.
- {
- // Make sure we do not start at eof or this will cause problems.
- if (feof(f))
- fseek(f,section_buffers[current_section].offset,SEEK_SET);
- start_pos=ftell(f);
- while (1)
- {
- string_start_pos=ftell(f);
- stripped_fgets(ts,INI_STRING_SIZE*2,f);
- // If it is a field, add it to the buffer
- if (is_field(ts,"*"))
- add_field(ts,current_section,string_start_pos);
- // If it is the field we are looking for, save it
- if (is_field(ts,field))
- {
- 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);
-}
-
-
-//=============================================================================
-// Programs the DMA controller to start DMAing in Auto-init mode
-//=============================================================================
-static void GUS_StartDMA(BYTE DmaChannel,short *dma_buffer,int count)
-{
- int mode;
- int RealAddr;
-
- RealAddr = ptr2real(dma_buffer);
-
- if (DmaChannel <= 3)
- {
- ModeReg = 0x0B;
- DisableReg = 0x0A;
- ClearReg = 0x0E;
- }
- else
- {
- ModeReg = 0xD6;
- DisableReg = 0xD4;
- ClearReg = 0xDC;
- }
- CountReg=CountRegs[DmaChannel];
- AddrReg=AddrRegs[DmaChannel];
-
- dos_outportb(DisableReg, DmaChannel | 4); // disable channel
-
- // set mode- see "undocumented pc", p.876
- mode = (1<<6) // single-cycle
- +(0<<5) // address increment
- +(1<<4) // auto-init dma
- +(2<<2) // read
- +(DmaChannel & 0x03); // channel #
- dos_outportb(ModeReg, mode);
-
- // set page
- dos_outportb(PageRegs[DmaChannel], RealAddr >> 16);
-
- if (DmaChannel <= 3)
- { // address is in bytes
- dos_outportb(0x0C, 0); // prepare to send 16-bit value
- dos_outportb(AddrReg, RealAddr & 0xff);
- dos_outportb(AddrReg, (RealAddr>>8) & 0xff);
-
- dos_outportb(0x0C, 0); // prepare to send 16-bit value
- dos_outportb(CountReg, (count-1) & 0xff);
- dos_outportb(CountReg, (count-1) >> 8);
- }
- else
- { // address is in words
- dos_outportb(0xD8, 0); // prepare to send 16-bit value
- dos_outportb(AddrReg, (RealAddr>>1) & 0xff);
- dos_outportb(AddrReg, (RealAddr>>9) & 0xff);
-
- dos_outportb(0xD8, 0); // prepare to send 16-bit value
- dos_outportb(CountReg, ((count>>1)-1) & 0xff);
- dos_outportb(CountReg, ((count>>1)-1) >> 8);
- }
-
- dos_outportb(ClearReg, 0); // clear write mask
- dos_outportb(DisableReg, DmaChannel & ~4);
-}
-
-//=============================================================================
-// Starts the CODEC playing
-//=============================================================================
-static void GUS_StartCODEC(int count,BYTE FSVal)
-{
- int i,j;
-
- // Clear any pending IRQs
- dos_inportb(CodecStatus);
- dos_outportb(CodecStatus,0);
-
- // Set mode to 2
- dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
- dos_outportb(CodecData,0xC0);
-
- // Stop any playback or capture which may be happening
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
- dos_outportb(CodecData,dos_inportb(CodecData) & 0xFC);
-
- // Set FS
- dos_outportb(CodecRegisterSelect,CODEC_FS_FORMAT | 0x40);
- dos_outportb(CodecData,FSVal | 0x50); // Or in stereo and 16 bit bits
-
- // Wait a bit
- for (i=0;i<10;i++)
- dos_inportb(CodecData);
-
- // Routine 1 to counter CODEC bug - wait for init bit to clear and then a
- // bit longer (i=min loop count, j=timeout
- for (i=0,j=0;i<1000 && j<0x7FFFF;j++)
- if ((dos_inportb(CodecRegisterSelect) & 0x80)==0)
- i++;
-
- // Routine 2 to counter CODEC bug - this is from Forte's code. For me it
- // does not seem to cure the problem, but is added security
- // Waits till we can modify index register
- for (j=0;j<0x7FFFF;j++)
- {
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
- if (dos_inportb(CodecRegisterSelect)==(CODEC_INTERFACE_CONFIG | 0x40))
- break;
- }
-
- // Perform ACAL
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
- dos_outportb(CodecData,0x08);
-
- // Clear MCE bit - this makes ACAL happen
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
-
- // Wait for ACAL to finish
- for (j=0;j<0x7FFFF;j++)
- {
- if ((dos_inportb(CodecRegisterSelect) & 0x80) != 0)
- continue;
- dos_outportb(CodecRegisterSelect,CODEC_ERROR_STATUS_AND_INIT);
- if ((dos_inportb(CodecData) & 0x20) == 0)
- break;
- }
-
- // Clear ACAL bit
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
- dos_outportb(CodecData,0x00);
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
-
- // Set some other junk
- dos_outportb(CodecRegisterSelect,CODEC_LOOPBACK_CONTROL);
- dos_outportb(CodecData,0x00);
- dos_outportb(CodecRegisterSelect,CODEC_PIN_CONTROL);
- dos_outportb(CodecData,0x08); // IRQ is disabled in PIN control
-
- // Set count (it doesn't really matter what value we stuff in here
- dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_LOWER_BASE_COUNT);
- dos_outportb(CodecData,count & 0xFF);
- dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_UPPER_BASE_COUNT);
- dos_outportb(CodecData,count >> 8);
-
- // Start playback
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
- dos_outportb(CodecData,0x01);
-}
-
-//=============================================================================
-// Starts the GF1 playing
-//=============================================================================
-static void GUS_StartGf1(int count,BYTE Voices)
-{
- DWORD StartAddressL,EndAddressL,StartAddressR,EndAddressR;
-
- // Set number of voices to give us the sampling rate we want
- SetGf18(SET_VOICES,0xC0 | (Voices-1));
-
- // Figure out addresses
- StartAddressL=ConvertTo16(0);
- EndAddressL=ConvertTo16(count-2-2);
- StartAddressR=ConvertTo16(2);
- EndAddressR=ConvertTo16(count-2);
-
- // Set left voice addresses
- dos_outportb(Gf1PageRegister,0);
- SetGf116(SET_START_LOW,StartAddressL<<9);
- SetGf116(SET_START_HIGH,StartAddressL>>7);
- SetGf116(SET_ACC_LOW,StartAddressL<<9);
- SetGf116(SET_ACC_HIGH,StartAddressL>>7);
- SetGf116(SET_END_LOW,EndAddressL<<9);
- SetGf116(SET_END_HIGH,EndAddressL>>7);
- // Set balance to full left
- SetGf18(SET_BALANCE,0);
- // Set volume to full
- SetGf116(SET_VOLUME,0xFFF0);
- // Set FC to 2 (so we play every second sample)
- SetGf116(SET_FREQUENCY,0x0800);
-
- // Set right voice addresses
- dos_outportb(Gf1PageRegister,1);
- SetGf116(SET_START_LOW,StartAddressR<<9);
- SetGf116(SET_START_HIGH,StartAddressR>>7);
- SetGf116(SET_ACC_LOW,StartAddressR<<9);
- SetGf116(SET_ACC_HIGH,StartAddressR>>7);
- SetGf116(SET_END_LOW,EndAddressR<<9);
- SetGf116(SET_END_HIGH,EndAddressR>>7);
- // Set balance to full right
- SetGf18(SET_BALANCE,15);
- // Set volume to full
- SetGf116(SET_VOLUME,0xFFF0);
- // Set FC to 2 (so we play every second sample)
- SetGf116(SET_FREQUENCY,0x0800);
-
- // Start voices
- dos_outportb(Gf1PageRegister,0);
- SetGf18(SET_CONTROL,0x0C);
- dos_outportb(Gf1PageRegister,1);
- SetGf18(SET_CONTROL,0x0C);
- Gf1Delay();
- dos_outportb(Gf1PageRegister,0);
- SetGf18(SET_CONTROL,0x0C);
- dos_outportb(Gf1PageRegister,1);
- SetGf18(SET_CONTROL,0x0C);
-}
-
-
-//=============================================================================
-// Figures out what kind of UltraSound we have, if any, and starts it playing
-//=============================================================================
-qboolean GUS_Init(void)
-{
- int rc;
- int RealAddr;
- BYTE FSVal,Voices;
- struct CodecRateStruct *CodecRate;
- struct Gf1RateStruct *Gf1Rate;
-
- // See what kind of UltraSound we have, if any
- if (GUS_GetIWData()==false)
- if (GUS_GetMAXData()==false)
- if (GUS_GetGUSData()==false)
- return(false);
-
- shm = &sn;
-
- if (HaveCodec)
- {
- // do 11khz sampling rate unless command line parameter wants different
- shm->speed = 11025;
- FSVal = 0x03;
- rc = COM_CheckParm("-sspeed");
- if (rc)
- {
- shm->speed = Q_atoi(com_argv[rc+1]);
-
- // Make sure rate not too high
- if (shm->speed>48000)
- shm->speed=48000;
-
- // Adjust speed to match one of the possible CODEC rates
- for (CodecRate=CodecRates;CodecRate->Rate!=0;CodecRate++)
- {
- if (shm->speed <= CodecRate->Rate)
- {
- shm->speed=CodecRate->Rate;
- FSVal=CodecRate->FSVal;
- break;
- }
- }
- }
-
-
- // Always do 16 bit stereo
- shm->channels = 2;
- shm->samplebits = 16;
-
- // allocate buffer twice the size we need so we can get aligned buffer
- dma_buffer = dos_getmemory(BUFFER_SIZE*2);
- if (dma_buffer==NULL)
- {
- Con_Printf("Couldn't allocate sound dma buffer");
- return false;
- }
-
- RealAddr = ptr2real(dma_buffer);
- RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
- dma_buffer = (short *) real2ptr(RealAddr);
-
- // Zero off DMA buffer
- memset(dma_buffer, 0, BUFFER_SIZE);
-
- shm->soundalive = true;
- shm->splitbuffer = false;
-
- shm->samplepos = 0;
- shm->submission_chunk = 1;
- shm->buffer = (unsigned char *) dma_buffer;
- shm->samples = BUFFER_SIZE/(shm->samplebits/8);
-
- GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
- GUS_StartCODEC(BUFFER_SIZE,FSVal);
- }
- else
- {
- // do 19khz sampling rate unless command line parameter wants different
- shm->speed = 19293;
- Voices=32;
- rc = COM_CheckParm("-sspeed");
- if (rc)
- {
- shm->speed = Q_atoi(com_argv[rc+1]);
-
- // Make sure rate not too high
- if (shm->speed>44100)
- shm->speed=44100;
-
- // Adjust speed to match one of the possible GF1 rates
- for (Gf1Rate=Gf1Rates;Gf1Rate->Rate!=0;Gf1Rate++)
- {
- if (shm->speed <= Gf1Rate->Rate)
- {
- shm->speed=Gf1Rate->Rate;
- Voices=Gf1Rate->Voices;
- break;
- }
- }
- }
-
- // Always do 16 bit stereo
- shm->channels = 2;
- shm->samplebits = 16;
-
- // allocate buffer twice the size we need so we can get aligned buffer
- dma_buffer = dos_getmemory(BUFFER_SIZE*2);
- if (dma_buffer==NULL)
- {
- Con_Printf("Couldn't allocate sound dma buffer");
- return false;
- }
-
- RealAddr = ptr2real(dma_buffer);
- RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
- dma_buffer = (short *) real2ptr(RealAddr);
-
- // Zero off DMA buffer
- memset(dma_buffer, 0, BUFFER_SIZE);
-
- shm->soundalive = true;
- shm->splitbuffer = false;
-
- shm->samplepos = 0;
- shm->submission_chunk = 1;
- shm->buffer = (unsigned char *) dma_buffer;
- shm->samples = BUFFER_SIZE/(shm->samplebits/8);
-
- GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
- SetGf116(SET_DMA_ADDRESS,0x0000);
- if (DmaChannel<=3)
- SetGf18(DMA_CONTROL,0x41);
- else
- SetGf18(DMA_CONTROL,0x45);
- GUS_StartGf1(BUFFER_SIZE,Voices);
- }
- return(true);
-}
-
-//=============================================================================
-// Returns the current playback position
-//=============================================================================
-int GUS_GetDMAPos(void)
-{
- int count;
-
- if (HaveCodec)
- {
- // clear 16-bit reg flip-flop
- // load the current dma count register
- if (DmaChannel < 4)
- {
- dos_outportb(0x0C, 0);
- count = dos_inportb(CountReg);
- count += dos_inportb(CountReg) << 8;
- if (shm->samplebits == 16)
- count /= 2;
- count = shm->samples - (count+1);
- }
- else
- {
- dos_outportb(0xD8, 0);
- count = dos_inportb(CountReg);
- count += dos_inportb(CountReg) << 8;
- if (shm->samplebits == 8)
- count *= 2;
- count = shm->samples - (count+1);
- }
-
- }
- else
- {
- // Read current position from GF1
- dos_outportb(Gf1PageRegister,0);
- count=(GetGf116(GET_ACC_HIGH)<<7) & 0xFFFF;
- // See which half of buffer we are in. Note that since this is 16 bit
- // data we are playing, position is in 16 bit samples
- if (GetGf18(DMA_CONTROL) & 0x40)
- {
- GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
- SetGf116(SET_DMA_ADDRESS,0x0000);
- if (DmaChannel<=3)
- SetGf18(DMA_CONTROL,0x41);
- else
- SetGf18(DMA_CONTROL,0x45);
- }
- }
-
- shm->samplepos = count & (shm->samples-1);
- return(shm->samplepos);
-}
-
-//=============================================================================
-// Stops the UltraSound playback
-//=============================================================================
-void GUS_Shutdown (void)
-{
- if (HaveCodec)
- {
- // Stop CODEC
- dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
- dos_outportb(CodecData,0x01);
- }
- else
- {
- // Stop Voices
- dos_outportb(Gf1PageRegister,0);
- SetGf18(SET_CONTROL,0x03);
- dos_outportb(Gf1PageRegister,1);
- SetGf18(SET_CONTROL,0x03);
- Gf1Delay();
- dos_outportb(Gf1PageRegister,0);
- SetGf18(SET_CONTROL,0x03);
- dos_outportb(Gf1PageRegister,1);
- SetGf18(SET_CONTROL,0x03);
-
- // Stop any DMA
- SetGf18(DMA_CONTROL,0x00);
- GetGf18(DMA_CONTROL);
- }
-
- dos_outportb(DisableReg, DmaChannel | 4); // disable dma channel
-}
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+//=============================================================================
+// Routines for GUS support in QUAKE
+//
+// Author(s): Jayeson Lee-Steere
+//=============================================================================
+
+#include "quakedef.h"
+#include "dosisms.h"
+
+//=============================================================================
+// Author(s): Jayeson Lee-Steere
+
+#define INI_STRING_SIZE 0x100
+
+FILE *ini_fopen(const char *filename, const char *modes);
+int ini_fclose(FILE *f);
+void ini_fgets(FILE *f, const char *section, const char *field, char *s);
+
+// Routines for reading from .INI files
+// The read routines are fairly efficient.
+//
+// Author(s): Jayeson Lee-Steere
+
+#define MAX_SECTION_WIDTH 20
+#define MAX_FIELD_WIDTH 20
+
+#define NUM_SECTION_BUFFERS 10
+#define NUM_FIELD_BUFFERS 20
+
+struct section_buffer
+{
+ long offset;
+ char name[MAX_SECTION_WIDTH+1];
+};
+
+struct field_buffer
+{
+ long offset;
+ int section;
+ char name[MAX_FIELD_WIDTH+1];
+};
+
+static FILE *current_file=NULL;
+static int current_section;
+
+static int current_section_buffer=0;
+static int current_field_buffer=0;
+
+static struct section_buffer section_buffers[NUM_SECTION_BUFFERS];
+static struct field_buffer field_buffers[NUM_FIELD_BUFFERS];
+//***************************************************************************
+// Internal routines
+//***************************************************************************
+static char toupper(char c)
+{
+ if (c>='a' && c<='z')
+ c-=('a'-'A');
+ return(c);
+}
+
+static void reset_buffer(FILE *f)
+{
+ int i;
+
+ for (i=0;i<NUM_SECTION_BUFFERS;i++)
+ section_buffers[i].name[0]=0;
+ for (i=0;i<NUM_FIELD_BUFFERS;i++)
+ field_buffers[i].name[0]=0;
+
+ current_file=f;
+}
+
+// Sees if the current string is section "name" (i.e. ["name"]).
+// If "name"=="*", sees if the current string is any section
+// (i.e. [....]). Returns 1 if true else 0 if false.
+static int is_section(char *s,const char *name)
+{
+ int wild=0;
+
+ // See if wild search
+ if (strcmp("*",name)==0)
+ wild=1;
+
+ // Skip leading spaces
+ while (s[0]==' ')
+ s++;
+ // Look for leading "["
+ if (s[0]!='[')
+ return(0);
+ s++;
+ // Make sure name matches
+ while (s[0]!=']' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
+ {
+ if (!wild)
+ if (toupper(s[0])!=toupper(name[0]))
+ return(0);
+ s++;
+ if (!wild)
+ name++;
+ }
+ if (!wild)
+ if (name[0]!=0)
+ return(0);
+ // Skip trailing spaces
+ while (s[0]==' ')
+ s++;
+ // Make sure we have trailing "]"
+ if (s[0]!=']')
+ return(0);
+ return(1);
+}
+
+// Sees if the current string is field "name" (i.e. "name"=...).
+// If "name"=="*", sees if the current string is any field
+// (i.e. ...=...). Returns 1 if true else 0 if false.
+static int is_field(char *s,const char *name)
+{
+ int wild=0;
+
+ // See if wild search
+ if (strcmp("*",name)==0)
+ wild=1;
+
+ // Skip leading spaces
+ while (s[0]==' ')
+ s++;
+
+ // Make sure name matches
+ while (s[0]!='=' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
+ {
+ if (!wild)
+ if (toupper(s[0])!=toupper(name[0]))
+ return(0);
+ s++;
+ if (!wild)
+ name++;
+ }
+ if (!wild)
+ if (name[0]!=0)
+ return(0);
+ // Skip trailing spaces
+ while (s[0]==' ')
+ s++;
+ // Make sure we have an "="
+ if (s[0]!='=')
+ return(0);
+
+ return(1);
+}
+
+// Extracts the section name from a section heading
+// e.g. in="[hey man]" gives out="hey man"
+static void get_section_name(char *out, char *in)
+{
+ int i=0;
+
+ // Skip spaces before '['
+ while (in[0]==' ')
+ in++;
+ // Make sure there is a '['
+ if (in[0]!='[')
+ {
+ out[0]=0;
+ return;
+ }
+ // Skip past '['
+ in++;
+ // Copy string if any to output string.
+ while (in[0]!=']' && in[0]!=13 && in[0]!=10 && in[0]!=0)
+ {
+ if (i<MAX_SECTION_WIDTH)
+ {
+ out[i]=in[0];
+ i++;
+ }
+ in++;
+ }
+ // Make sure string was terminated with ']'
+ if (in[0]!=']')
+ {
+ out[0]=0;
+ return;
+ }
+ // Remove trailing spaces
+ while (i>0 && out[i-1]==' ')
+ i--;
+ // Null terminate the output string.
+ out[i]=0;
+}
+
+// Extracts the field name from a field line
+// e.g. in="sooty=life be in it" gives out="sooty"
+static void get_field_name(char *out, char *in)
+{
+ int i=0;
+
+ // Skip leading spaces
+ while (in[0]==' ')
+ in++;
+ // Copy name to output string
+ while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
+ {
+ if (i<MAX_FIELD_WIDTH)
+ {
+ out[i]=in[0];
+ i++;
+ }
+ in++;
+ }
+ // Make sure we stopped on "="
+ if (in[0]!='=')
+ {
+ out[0]=0;
+ return;
+ }
+ // Remove trailing spaces
+ while (i>0 && out[i-1]==' ')
+ i--;
+ // Null terminate the output string.
+ out[i]=0;
+}
+
+// Returns the field data from string s.
+// e.g. in="wally = golly man" gives out="golly man"
+static void get_field_string(char *out, char *in)
+{
+ int i=0;
+
+ // Find '=' if it exists
+ while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
+ in++;
+ // If there is an '=', skip past it.
+ if (in[0]=='=')
+ in++;
+ // Skip any spaces between the '=' and string.
+ while (in[0]==' ' || in[0]=='[')
+ in++;
+ // Copy string, if there is one, to the output string.
+ while (in[0]!=13 && in[0]!=10 && in[0]!=0 && i<(INI_STRING_SIZE-1))
+ {
+ out[i]=in[0];
+ in++;
+ i++;
+ }
+ // Null terminate the output string.
+ out[i]=0;
+}
+
+// Adds a section to the buffer
+static int add_section(char *instring, long offset)
+{
+ int i;
+ char section[MAX_SECTION_WIDTH+1];
+
+ // Extract section name
+ get_section_name(section,instring);
+ // See if section already exists.
+ for (i=0;i<NUM_SECTION_BUFFERS;i++)
+ if (stricmp(section,section_buffers[i].name)==0)
+ return(i);
+ // Increment current_section_buffer
+ current_section_buffer++;
+ if (current_section_buffer>NUM_SECTION_BUFFERS)
+ current_section_buffer=0;
+ // Delete any field buffers that correspond to this section
+ for (i=0;i<NUM_FIELD_BUFFERS;i++)
+ if (field_buffers[i].section==current_section_buffer)
+ field_buffers[i].name[0]=0;
+ // Set buffer information
+ strcpy(section_buffers[current_section_buffer].name,section);
+ section_buffers[current_section_buffer].offset=offset;
+ return(current_section_buffer);
+}
+
+// Adds a field to the buffer
+static void add_field(char *instring, int section, long offset)
+{
+ int i;
+ char field[MAX_FIELD_WIDTH+1];
+
+ // Extract field name
+ get_field_name(field,instring);
+ // See if field already exists
+ for (i=0;i<NUM_FIELD_BUFFERS;i++)
+ if (field_buffers[i].section==section)
+ if (stricmp(field_buffers[i].name,field)==0)
+ return;
+ // Increment current_field_buffer
+ current_field_buffer++;
+ if (current_field_buffer>NUM_FIELD_BUFFERS)
+ current_field_buffer=0;
+ // Set buffer information
+ strcpy(field_buffers[current_field_buffer].name,field);
+ field_buffers[current_field_buffer].section=section;
+ field_buffers[current_field_buffer].offset=offset;
+}
+
+// Identical to fgets except the string is trucated at the first ';',
+// carriage return or line feed.
+static char *stripped_fgets(char *s, int n, FILE *f)
+{
+ int i=0;
+
+ if (fgets(s,n,f)==NULL)
+ return(NULL);
+
+ while (s[i]!=';' && s[i]!=13 && s[i]!=10 && s[i]!=0)
+ i++;
+ s[i]=0;
+
+ return(s);
+}
+
+//***************************************************************************
+// Externally accessable routines
+//***************************************************************************
+// Opens an .INI file. Works like fopen
+FILE *ini_fopen(const char *filename, const char *modes)
+{
+ return(fopen(filename,modes));
+}
+
+// Closes a .INI file. Works like fclose
+int ini_fclose(FILE *f)
+{
+ if (f==current_file)
+ reset_buffer(NULL);
+ return(fclose(f));
+}
+
+// Puts "field" from "section" from .ini file "f" into "s".
+// If "section" does not exist or "field" does not exist in
+// section then s="";
+void ini_fgets(FILE *f, const char *section, const char *field, char *s)
+{
+ int i;
+ long start_pos,string_start_pos;
+ char ts[INI_STRING_SIZE*2];
+
+ if (f!=current_file)
+ reset_buffer(f);
+
+ // Default to "Not found"
+ s[0]=0;
+
+ // See if section is in buffer
+ for (i=0;i<NUM_SECTION_BUFFERS;i++)
+ if (strnicmp(section_buffers[i].name,section,MAX_SECTION_WIDTH)==0)
+ break;
+
+ // If section is in buffer, seek to it if necessary
+ if (i<NUM_SECTION_BUFFERS)
+ {
+ if (i!=current_section)
+ {
+ current_section=i;
+ fseek(f,section_buffers[i].offset,SEEK_SET);
+ }
+ }
+ // else look through .ini file for it.
+ else
+ {
+ // Make sure we are not at eof or this will cause trouble.
+ if (feof(f))
+ rewind(f);
+ start_pos=ftell(f);
+ while (1)
+ {
+ stripped_fgets(ts,INI_STRING_SIZE*2,f);
+ // If it is a section, add it to the section buffer
+ if (is_section(ts,"*"))
+ current_section=add_section(ts,ftell(f));
+ // If it is the section we are looking for, break.
+ if (is_section(ts,section))
+ break;
+ // If we reach the end of the file, rewind to the start.
+ if (feof(f))
+ rewind(f);
+ if (ftell(f)==start_pos)
+ return;
+ }
+ }
+
+ // See if field is in buffer
+ for (i=0;i<NUM_FIELD_BUFFERS;i++)
+ if (field_buffers[i].section==current_section)
+ if (strnicmp(field_buffers[i].name,field,MAX_FIELD_WIDTH)==0)
+ break;
+
+ // If field is in buffer, seek to it and read it
+ if (i<NUM_FIELD_BUFFERS)
+ {
+ fseek(f,field_buffers[i].offset,SEEK_SET);
+ stripped_fgets(ts,INI_STRING_SIZE*2,f);
+ get_field_string(s,ts);
+ }
+ else
+ // else search through section for field.
+ {
+ // Make sure we do not start at eof or this will cause problems.
+ if (feof(f))
+ fseek(f,section_buffers[current_section].offset,SEEK_SET);
+ start_pos=ftell(f);
+ while (1)
+ {
+ string_start_pos=ftell(f);
+ stripped_fgets(ts,INI_STRING_SIZE*2,f);
+ // If it is a field, add it to the buffer
+ if (is_field(ts,"*"))
+ add_field(ts,current_section,string_start_pos);
+ // If it is the field we are looking for, save it
+ if (is_field(ts,field))
+ {
+ 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);
+}
+
+
+//=============================================================================
+// Programs the DMA controller to start DMAing in Auto-init mode
+//=============================================================================
+static void GUS_StartDMA(BYTE DmaChannel,short *dma_buffer,int count)
+{
+ int mode;
+ int RealAddr;
+
+ RealAddr = ptr2real(dma_buffer);
+
+ if (DmaChannel <= 3)
+ {
+ ModeReg = 0x0B;
+ DisableReg = 0x0A;
+ ClearReg = 0x0E;
+ }
+ else
+ {
+ ModeReg = 0xD6;
+ DisableReg = 0xD4;
+ ClearReg = 0xDC;
+ }
+ CountReg=CountRegs[DmaChannel];
+ AddrReg=AddrRegs[DmaChannel];
+
+ dos_outportb(DisableReg, DmaChannel | 4); // disable channel
+
+ // set mode- see "undocumented pc", p.876
+ mode = (1<<6) // single-cycle
+ +(0<<5) // address increment
+ +(1<<4) // auto-init dma
+ +(2<<2) // read
+ +(DmaChannel & 0x03); // channel #
+ dos_outportb(ModeReg, mode);
+
+ // set page
+ dos_outportb(PageRegs[DmaChannel], RealAddr >> 16);
+
+ if (DmaChannel <= 3)
+ { // address is in bytes
+ dos_outportb(0x0C, 0); // prepare to send 16-bit value
+ dos_outportb(AddrReg, RealAddr & 0xff);
+ dos_outportb(AddrReg, (RealAddr>>8) & 0xff);
+
+ dos_outportb(0x0C, 0); // prepare to send 16-bit value
+ dos_outportb(CountReg, (count-1) & 0xff);
+ dos_outportb(CountReg, (count-1) >> 8);
+ }
+ else
+ { // address is in words
+ dos_outportb(0xD8, 0); // prepare to send 16-bit value
+ dos_outportb(AddrReg, (RealAddr>>1) & 0xff);
+ dos_outportb(AddrReg, (RealAddr>>9) & 0xff);
+
+ dos_outportb(0xD8, 0); // prepare to send 16-bit value
+ dos_outportb(CountReg, ((count>>1)-1) & 0xff);
+ dos_outportb(CountReg, ((count>>1)-1) >> 8);
+ }
+
+ dos_outportb(ClearReg, 0); // clear write mask
+ dos_outportb(DisableReg, DmaChannel & ~4);
+}
+
+//=============================================================================
+// Starts the CODEC playing
+//=============================================================================
+static void GUS_StartCODEC(int count,BYTE FSVal)
+{
+ int i,j;
+
+ // Clear any pending IRQs
+ dos_inportb(CodecStatus);
+ dos_outportb(CodecStatus,0);
+
+ // Set mode to 2
+ dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
+ dos_outportb(CodecData,0xC0);
+
+ // Stop any playback or capture which may be happening
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
+ dos_outportb(CodecData,dos_inportb(CodecData) & 0xFC);
+
+ // Set FS
+ dos_outportb(CodecRegisterSelect,CODEC_FS_FORMAT | 0x40);
+ dos_outportb(CodecData,FSVal | 0x50); // Or in stereo and 16 bit bits
+
+ // Wait a bit
+ for (i=0;i<10;i++)
+ dos_inportb(CodecData);
+
+ // Routine 1 to counter CODEC bug - wait for init bit to clear and then a
+ // bit longer (i=min loop count, j=timeout
+ for (i=0,j=0;i<1000 && j<0x7FFFF;j++)
+ if ((dos_inportb(CodecRegisterSelect) & 0x80)==0)
+ i++;
+
+ // Routine 2 to counter CODEC bug - this is from Forte's code. For me it
+ // does not seem to cure the problem, but is added security
+ // Waits till we can modify index register
+ for (j=0;j<0x7FFFF;j++)
+ {
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
+ if (dos_inportb(CodecRegisterSelect)==(CODEC_INTERFACE_CONFIG | 0x40))
+ break;
+ }
+
+ // Perform ACAL
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
+ dos_outportb(CodecData,0x08);
+
+ // Clear MCE bit - this makes ACAL happen
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
+
+ // Wait for ACAL to finish
+ for (j=0;j<0x7FFFF;j++)
+ {
+ if ((dos_inportb(CodecRegisterSelect) & 0x80) != 0)
+ continue;
+ dos_outportb(CodecRegisterSelect,CODEC_ERROR_STATUS_AND_INIT);
+ if ((dos_inportb(CodecData) & 0x20) == 0)
+ break;
+ }
+
+ // Clear ACAL bit
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
+ dos_outportb(CodecData,0x00);
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
+
+ // Set some other junk
+ dos_outportb(CodecRegisterSelect,CODEC_LOOPBACK_CONTROL);
+ dos_outportb(CodecData,0x00);
+ dos_outportb(CodecRegisterSelect,CODEC_PIN_CONTROL);
+ dos_outportb(CodecData,0x08); // IRQ is disabled in PIN control
+
+ // Set count (it doesn't really matter what value we stuff in here
+ dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_LOWER_BASE_COUNT);
+ dos_outportb(CodecData,count & 0xFF);
+ dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_UPPER_BASE_COUNT);
+ dos_outportb(CodecData,count >> 8);
+
+ // Start playback
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
+ dos_outportb(CodecData,0x01);
+}
+
+//=============================================================================
+// Starts the GF1 playing
+//=============================================================================
+static void GUS_StartGf1(int count,BYTE Voices)
+{
+ DWORD StartAddressL,EndAddressL,StartAddressR,EndAddressR;
+
+ // Set number of voices to give us the sampling rate we want
+ SetGf18(SET_VOICES,0xC0 | (Voices-1));
+
+ // Figure out addresses
+ StartAddressL=ConvertTo16(0);
+ EndAddressL=ConvertTo16(count-2-2);
+ StartAddressR=ConvertTo16(2);
+ EndAddressR=ConvertTo16(count-2);
+
+ // Set left voice addresses
+ dos_outportb(Gf1PageRegister,0);
+ SetGf116(SET_START_LOW,StartAddressL<<9);
+ SetGf116(SET_START_HIGH,StartAddressL>>7);
+ SetGf116(SET_ACC_LOW,StartAddressL<<9);
+ SetGf116(SET_ACC_HIGH,StartAddressL>>7);
+ SetGf116(SET_END_LOW,EndAddressL<<9);
+ SetGf116(SET_END_HIGH,EndAddressL>>7);
+ // Set balance to full left
+ SetGf18(SET_BALANCE,0);
+ // Set volume to full
+ SetGf116(SET_VOLUME,0xFFF0);
+ // Set FC to 2 (so we play every second sample)
+ SetGf116(SET_FREQUENCY,0x0800);
+
+ // Set right voice addresses
+ dos_outportb(Gf1PageRegister,1);
+ SetGf116(SET_START_LOW,StartAddressR<<9);
+ SetGf116(SET_START_HIGH,StartAddressR>>7);
+ SetGf116(SET_ACC_LOW,StartAddressR<<9);
+ SetGf116(SET_ACC_HIGH,StartAddressR>>7);
+ SetGf116(SET_END_LOW,EndAddressR<<9);
+ SetGf116(SET_END_HIGH,EndAddressR>>7);
+ // Set balance to full right
+ SetGf18(SET_BALANCE,15);
+ // Set volume to full
+ SetGf116(SET_VOLUME,0xFFF0);
+ // Set FC to 2 (so we play every second sample)
+ SetGf116(SET_FREQUENCY,0x0800);
+
+ // Start voices
+ dos_outportb(Gf1PageRegister,0);
+ SetGf18(SET_CONTROL,0x0C);
+ dos_outportb(Gf1PageRegister,1);
+ SetGf18(SET_CONTROL,0x0C);
+ Gf1Delay();
+ dos_outportb(Gf1PageRegister,0);
+ SetGf18(SET_CONTROL,0x0C);
+ dos_outportb(Gf1PageRegister,1);
+ SetGf18(SET_CONTROL,0x0C);
+}
+
+
+//=============================================================================
+// Figures out what kind of UltraSound we have, if any, and starts it playing
+//=============================================================================
+qboolean GUS_Init(void)
+{
+ int rc;
+ int RealAddr;
+ BYTE FSVal,Voices;
+ struct CodecRateStruct *CodecRate;
+ struct Gf1RateStruct *Gf1Rate;
+
+ // See what kind of UltraSound we have, if any
+ if (GUS_GetIWData()==false)
+ if (GUS_GetMAXData()==false)
+ if (GUS_GetGUSData()==false)
+ return(false);
+
+ shm = &sn;
+
+ if (HaveCodec)
+ {
+ // do 11khz sampling rate unless command line parameter wants different
+ shm->speed = 11025;
+ FSVal = 0x03;
+ rc = COM_CheckParm("-sspeed");
+ if (rc)
+ {
+ shm->speed = Q_atoi(com_argv[rc+1]);
+
+ // Make sure rate not too high
+ if (shm->speed>48000)
+ shm->speed=48000;
+
+ // Adjust speed to match one of the possible CODEC rates
+ for (CodecRate=CodecRates;CodecRate->Rate!=0;CodecRate++)
+ {
+ if (shm->speed <= CodecRate->Rate)
+ {
+ shm->speed=CodecRate->Rate;
+ FSVal=CodecRate->FSVal;
+ break;
+ }
+ }
+ }
+
+
+ // Always do 16 bit stereo
+ shm->channels = 2;
+ shm->samplebits = 16;
+
+ // allocate buffer twice the size we need so we can get aligned buffer
+ dma_buffer = dos_getmemory(BUFFER_SIZE*2);
+ if (dma_buffer==NULL)
+ {
+ Con_Printf("Couldn't allocate sound dma buffer");
+ return false;
+ }
+
+ RealAddr = ptr2real(dma_buffer);
+ RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
+ dma_buffer = (short *) real2ptr(RealAddr);
+
+ // Zero off DMA buffer
+ memset(dma_buffer, 0, BUFFER_SIZE);
+
+ shm->soundalive = true;
+ shm->splitbuffer = false;
+
+ shm->samplepos = 0;
+ shm->submission_chunk = 1;
+ shm->buffer = (unsigned char *) dma_buffer;
+ shm->samples = BUFFER_SIZE/(shm->samplebits/8);
+
+ GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
+ GUS_StartCODEC(BUFFER_SIZE,FSVal);
+ }
+ else
+ {
+ // do 19khz sampling rate unless command line parameter wants different
+ shm->speed = 19293;
+ Voices=32;
+ rc = COM_CheckParm("-sspeed");
+ if (rc)
+ {
+ shm->speed = Q_atoi(com_argv[rc+1]);
+
+ // Make sure rate not too high
+ if (shm->speed>44100)
+ shm->speed=44100;
+
+ // Adjust speed to match one of the possible GF1 rates
+ for (Gf1Rate=Gf1Rates;Gf1Rate->Rate!=0;Gf1Rate++)
+ {
+ if (shm->speed <= Gf1Rate->Rate)
+ {
+ shm->speed=Gf1Rate->Rate;
+ Voices=Gf1Rate->Voices;
+ break;
+ }
+ }
+ }
+
+ // Always do 16 bit stereo
+ shm->channels = 2;
+ shm->samplebits = 16;
+
+ // allocate buffer twice the size we need so we can get aligned buffer
+ dma_buffer = dos_getmemory(BUFFER_SIZE*2);
+ if (dma_buffer==NULL)
+ {
+ Con_Printf("Couldn't allocate sound dma buffer");
+ return false;
+ }
+
+ RealAddr = ptr2real(dma_buffer);
+ RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
+ dma_buffer = (short *) real2ptr(RealAddr);
+
+ // Zero off DMA buffer
+ memset(dma_buffer, 0, BUFFER_SIZE);
+
+ shm->soundalive = true;
+ shm->splitbuffer = false;
+
+ shm->samplepos = 0;
+ shm->submission_chunk = 1;
+ shm->buffer = (unsigned char *) dma_buffer;
+ shm->samples = BUFFER_SIZE/(shm->samplebits/8);
+
+ GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
+ SetGf116(SET_DMA_ADDRESS,0x0000);
+ if (DmaChannel<=3)
+ SetGf18(DMA_CONTROL,0x41);
+ else
+ SetGf18(DMA_CONTROL,0x45);
+ GUS_StartGf1(BUFFER_SIZE,Voices);
+ }
+ return(true);
+}
+
+//=============================================================================
+// Returns the current playback position
+//=============================================================================
+int GUS_GetDMAPos(void)
+{
+ int count;
+
+ if (HaveCodec)
+ {
+ // clear 16-bit reg flip-flop
+ // load the current dma count register
+ if (DmaChannel < 4)
+ {
+ dos_outportb(0x0C, 0);
+ count = dos_inportb(CountReg);
+ count += dos_inportb(CountReg) << 8;
+ if (shm->samplebits == 16)
+ count /= 2;
+ count = shm->samples - (count+1);
+ }
+ else
+ {
+ dos_outportb(0xD8, 0);
+ count = dos_inportb(CountReg);
+ count += dos_inportb(CountReg) << 8;
+ if (shm->samplebits == 8)
+ count *= 2;
+ count = shm->samples - (count+1);
+ }
+
+ }
+ else
+ {
+ // Read current position from GF1
+ dos_outportb(Gf1PageRegister,0);
+ count=(GetGf116(GET_ACC_HIGH)<<7) & 0xFFFF;
+ // See which half of buffer we are in. Note that since this is 16 bit
+ // data we are playing, position is in 16 bit samples
+ if (GetGf18(DMA_CONTROL) & 0x40)
+ {
+ GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
+ SetGf116(SET_DMA_ADDRESS,0x0000);
+ if (DmaChannel<=3)
+ SetGf18(DMA_CONTROL,0x41);
+ else
+ SetGf18(DMA_CONTROL,0x45);
+ }
+ }
+
+ shm->samplepos = count & (shm->samples-1);
+ return(shm->samplepos);
+}
+
+//=============================================================================
+// Stops the UltraSound playback
+//=============================================================================
+void GUS_Shutdown (void)
+{
+ if (HaveCodec)
+ {
+ // Stop CODEC
+ dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
+ dos_outportb(CodecData,0x01);
+ }
+ else
+ {
+ // Stop Voices
+ dos_outportb(Gf1PageRegister,0);
+ SetGf18(SET_CONTROL,0x03);
+ dos_outportb(Gf1PageRegister,1);
+ SetGf18(SET_CONTROL,0x03);
+ Gf1Delay();
+ dos_outportb(Gf1PageRegister,0);
+ SetGf18(SET_CONTROL,0x03);
+ dos_outportb(Gf1PageRegister,1);
+ SetGf18(SET_CONTROL,0x03);
+
+ // Stop any DMA
+ SetGf18(DMA_CONTROL,0x00);
+ GetGf18(DMA_CONTROL);
+ }
+
+ dos_outportb(DisableReg, DmaChannel | 4); // disable dma channel
+}