Annotation of quake1/snd_gus.c, revision 1.1.1.2

1.1       root        1: //=============================================================================
                      2: // Routines for GUS support in QUAKE
                      3: //
                      4: // Author(s): Jayeson Lee-Steere
                      5: //=============================================================================
                      6: 
                      7: #include "quakedef.h"
                      8: #include "dosisms.h"
                      9: 
                     10: //=============================================================================
                     11: // Author(s): Jayeson Lee-Steere
                     12: 
                     13: #define INI_STRING_SIZE 0x100
                     14: 
                     15: FILE *ini_fopen(const char *filename, const char *modes);
                     16: int ini_fclose(FILE *f);
                     17: void ini_fgets(FILE *f, const char *section, const char *field, char *s);
                     18: 
                     19: // Routines for reading from .INI files
                     20: // The read routines are fairly efficient.
                     21: //
                     22: // Author(s): Jayeson Lee-Steere
                     23: 
                     24: #define MAX_SECTION_WIDTH 20
                     25: #define MAX_FIELD_WIDTH 20
                     26: 
                     27: #define NUM_SECTION_BUFFERS 10
                     28: #define NUM_FIELD_BUFFERS 20
                     29: 
                     30: struct section_buffer
                     31: {
                     32:    long offset;
                     33:    char name[MAX_SECTION_WIDTH+1];
                     34: };
                     35: 
                     36: struct field_buffer
                     37: {
                     38:    long offset;
                     39:    int  section;
                     40:    char name[MAX_FIELD_WIDTH+1];
                     41: };
                     42: 
                     43: static FILE *current_file=NULL;
                     44: static int   current_section;
                     45: 
                     46: static int current_section_buffer=0;
                     47: static int current_field_buffer=0;
                     48: 
                     49: static struct section_buffer section_buffers[NUM_SECTION_BUFFERS];
                     50: static struct field_buffer field_buffers[NUM_FIELD_BUFFERS];
                     51: //***************************************************************************
                     52: // Internal routines
                     53: //***************************************************************************
                     54: static char toupper(char c)
                     55: {
                     56:    if (c>='a' && c<='z')
                     57:       c-=('a'-'A');
                     58:    return(c);
                     59: }
                     60: 
                     61: static void reset_buffer(FILE *f)
                     62: {
                     63:    int i;
                     64: 
                     65:    for (i=0;i<NUM_SECTION_BUFFERS;i++)
                     66:       section_buffers[i].name[0]=0;
                     67:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                     68:       field_buffers[i].name[0]=0;
                     69: 
                     70:    current_file=f;
                     71: }
                     72: 
                     73: // Sees if the current string is section "name" (i.e. ["name"]).
                     74: // If "name"=="*", sees if the current string is any section
                     75: // (i.e. [....]). Returns 1 if true else 0 if false.
                     76: static int is_section(char *s,const char *name)
                     77: {
                     78:    int wild=0;
                     79: 
                     80:    // See if wild search
                     81:    if (strcmp("*",name)==0)
                     82:       wild=1;
                     83: 
                     84:    // Skip leading spaces
                     85:    while (s[0]==' ')
                     86:       s++;
                     87:    // Look for leading "["
                     88:    if (s[0]!='[')
                     89:       return(0);
                     90:    s++;
                     91:    // Make sure name matches
                     92:    while (s[0]!=']' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
                     93:    {
                     94:       if (!wild)
                     95:          if (toupper(s[0])!=toupper(name[0]))
                     96:             return(0);
                     97:       s++;
                     98:       if (!wild)
                     99:          name++;
                    100:    }
                    101:    if (!wild)
                    102:       if (name[0]!=0)
                    103:          return(0);
                    104:    // Skip trailing spaces
                    105:    while (s[0]==' ')
                    106:       s++;
                    107:    // Make sure we have trailing "]"
                    108:    if (s[0]!=']')
                    109:       return(0);
                    110:    return(1);
                    111: }
                    112: 
                    113: // Sees if the current string is field "name" (i.e. "name"=...).
                    114: // If "name"=="*", sees if the current string is any field
                    115: // (i.e. ...=...). Returns 1 if true else 0 if false.
                    116: static int is_field(char *s,const char *name)
                    117: {
                    118:    int wild=0;
                    119: 
                    120:    // See if wild search
                    121:    if (strcmp("*",name)==0)
                    122:       wild=1;
                    123: 
                    124:    // Skip leading spaces
                    125:    while (s[0]==' ')
                    126:       s++;
                    127: 
                    128:    // Make sure name matches
                    129:    while (s[0]!='=' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
                    130:    {
                    131:       if (!wild)
                    132:          if (toupper(s[0])!=toupper(name[0]))
                    133:             return(0);
                    134:       s++;
                    135:       if (!wild)
                    136:          name++;
                    137:    }
                    138:    if (!wild)
                    139:       if (name[0]!=0)
                    140:          return(0);
                    141:    // Skip trailing spaces
                    142:    while (s[0]==' ')
                    143:       s++;
                    144:    // Make sure we have an "="
                    145:    if (s[0]!='=')
                    146:       return(0);
                    147: 
                    148:    return(1);
                    149: }
                    150: 
                    151: // Extracts the section name from a section heading
                    152: // e.g. in="[hey man]" gives out="hey man"
                    153: static void get_section_name(char *out, char *in)
                    154: {
                    155:    int i=0;
                    156: 
                    157:    // Skip spaces before '['
                    158:    while (in[0]==' ')
                    159:       in++;
                    160:    // Make sure there is a '['
                    161:    if (in[0]!='[')
                    162:    {
                    163:       out[0]=0;
                    164:       return;
                    165:    }
                    166:    // Skip past '['
                    167:    in++;
                    168:    // Copy string if any to output string.
                    169:    while (in[0]!=']' && in[0]!=13 && in[0]!=10 && in[0]!=0)
                    170:    {
                    171:       if (i<MAX_SECTION_WIDTH)
                    172:       {
                    173:          out[i]=in[0];
                    174:          i++;
                    175:       }
                    176:       in++;
                    177:    }
                    178:    // Make sure string was terminated with ']'
                    179:    if (in[0]!=']')
                    180:    {
                    181:       out[0]=0;
                    182:       return;
                    183:    }
                    184:    // Remove trailing spaces
                    185:    while (i>0 && out[i-1]==' ')
                    186:       i--;
                    187:    // Null terminate the output string.
                    188:    out[i]=0;
                    189: }
                    190: 
                    191: // Extracts the field name from a field line
                    192: // e.g. in="sooty=life be in it" gives out="sooty"
                    193: static void get_field_name(char *out, char *in)
                    194: {
                    195:    int i=0;
                    196: 
                    197:    // Skip leading spaces
                    198:    while (in[0]==' ')
                    199:       in++;
                    200:    // Copy name to output string
                    201:    while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
                    202:    {
                    203:       if (i<MAX_FIELD_WIDTH)
                    204:       {
                    205:          out[i]=in[0];
                    206:          i++;
                    207:       }
                    208:       in++;
                    209:    }
                    210:    // Make sure we stopped on "="
                    211:    if (in[0]!='=')
                    212:    {
                    213:       out[0]=0;
                    214:       return;
                    215:    }
                    216:    // Remove trailing spaces
                    217:    while (i>0 && out[i-1]==' ')
                    218:       i--;
                    219:    // Null terminate the output string.
                    220:    out[i]=0;
                    221: }
                    222: 
                    223: // Returns the field data from string s.
                    224: // e.g. in="wally = golly man" gives out="golly man"
                    225: static void get_field_string(char *out, char *in)
                    226: {
                    227:    int i=0;
                    228: 
                    229:    // Find '=' if it exists
                    230:    while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
                    231:       in++;
                    232:    // If there is an '=', skip past it.
                    233:    if (in[0]=='=')
                    234:       in++;
                    235:    // Skip any spaces between the '=' and string.
                    236:    while (in[0]==' ' || in[0]=='[')
                    237:       in++;
                    238:    // Copy string, if there is one, to the output string.
                    239:    while (in[0]!=13 && in[0]!=10 && in[0]!=0 && i<(INI_STRING_SIZE-1))
                    240:    {
                    241:       out[i]=in[0];
                    242:       in++;
                    243:       i++;
                    244:    }
                    245:    // Null terminate the output string.
                    246:    out[i]=0;
                    247: }
                    248: 
                    249: // Adds a section to the buffer
                    250: static int add_section(char *instring, long offset)
                    251: {
                    252:    int i;
                    253:    char section[MAX_SECTION_WIDTH+1];
                    254: 
                    255:    // Extract section name
                    256:    get_section_name(section,instring);
                    257:    // See if section already exists.
                    258:    for (i=0;i<NUM_SECTION_BUFFERS;i++)
                    259:       if (stricmp(section,section_buffers[i].name)==0)
                    260:          return(i);
                    261:    // Increment current_section_buffer
                    262:    current_section_buffer++;
                    263:    if (current_section_buffer>NUM_SECTION_BUFFERS)
                    264:       current_section_buffer=0;
                    265:    // Delete any field buffers that correspond to this section
                    266:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                    267:       if (field_buffers[i].section==current_section_buffer)
                    268:          field_buffers[i].name[0]=0;
                    269:    // Set buffer information
                    270:    strcpy(section_buffers[current_section_buffer].name,section);
                    271:    section_buffers[current_section_buffer].offset=offset;
                    272:    return(current_section_buffer);
                    273: }
                    274: 
                    275: // Adds a field to the buffer
                    276: static void add_field(char *instring, int section, long offset)
                    277: {
                    278:    int i;
                    279:    char field[MAX_FIELD_WIDTH+1];
                    280: 
                    281:    // Extract field name
                    282:    get_field_name(field,instring);
                    283:    // See if field already exists
                    284:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                    285:       if (field_buffers[i].section==section)
                    286:          if (stricmp(field_buffers[i].name,field)==0)
                    287:             return;
                    288:    // Increment current_field_buffer
                    289:    current_field_buffer++;
                    290:    if (current_field_buffer>NUM_FIELD_BUFFERS)
                    291:       current_field_buffer=0;
                    292:    // Set buffer information
                    293:    strcpy(field_buffers[current_field_buffer].name,field);
                    294:    field_buffers[current_field_buffer].section=section;
                    295:    field_buffers[current_field_buffer].offset=offset;
                    296: }
                    297: 
                    298: // Identical to fgets except the string is trucated at the first ';',
                    299: // carriage return or line feed.
                    300: static char *stripped_fgets(char *s, int n, FILE *f)
                    301: {
                    302:    int i=0;
                    303: 
                    304:    if (fgets(s,n,f)==NULL)
                    305:       return(NULL);
                    306: 
                    307:    while (s[i]!=';' && s[i]!=13 && s[i]!=10 && s[i]!=0)
                    308:       i++;
                    309:    s[i]=0;
                    310: 
                    311:    return(s);
                    312: }
                    313: 
                    314: //***************************************************************************
                    315: // Externally accessable routines
                    316: //***************************************************************************
                    317: // Opens an .INI file. Works like fopen
                    318: FILE *ini_fopen(const char *filename, const char *modes)
                    319: {
                    320:    return(fopen(filename,modes));
                    321: }
                    322: 
                    323: // Closes a .INI file. Works like fclose
                    324: int ini_fclose(FILE *f)
                    325: {
                    326:    if (f==current_file)
                    327:       reset_buffer(NULL);
                    328:    return(fclose(f));
                    329: }
                    330: 
                    331: // Puts "field" from "section" from .ini file "f" into "s".
                    332: // If "section" does not exist or "field" does not exist in
                    333: // section then s="";
                    334: void ini_fgets(FILE *f, const char *section, const char *field, char *s)
                    335: {
                    336:    int i;
                    337:    long start_pos,string_start_pos;
                    338:    char ts[INI_STRING_SIZE*2];
                    339: 
                    340:    if (f!=current_file)
                    341:       reset_buffer(f);
                    342: 
                    343:    // Default to "Not found"
                    344:    s[0]=0;
                    345: 
                    346:    // See if section is in buffer
                    347:    for (i=0;i<NUM_SECTION_BUFFERS;i++)
                    348:       if (strnicmp(section_buffers[i].name,section,MAX_SECTION_WIDTH)==0)
                    349:          break;
                    350: 
                    351:    // If section is in buffer, seek to it if necessary
                    352:    if (i<NUM_SECTION_BUFFERS)
                    353:    {
                    354:       if (i!=current_section)
                    355:       {
                    356:          current_section=i;
                    357:          fseek(f,section_buffers[i].offset,SEEK_SET);
                    358:       }
                    359:    }
                    360:    // else look through .ini file for it.
                    361:    else
                    362:    {
                    363:       // Make sure we are not at eof or this will cause trouble.
                    364:       if (feof(f))
                    365:          rewind(f);
                    366:       start_pos=ftell(f);
                    367:       while (1)
                    368:       {
                    369:          stripped_fgets(ts,INI_STRING_SIZE*2,f);
                    370:          // If it is a section, add it to the section buffer
                    371:          if (is_section(ts,"*"))
                    372:             current_section=add_section(ts,ftell(f));
                    373:          // If it is the section we are looking for, break.
                    374:          if (is_section(ts,section))
                    375:             break;
                    376:          // If we reach the end of the file, rewind to the start.
                    377:          if (feof(f))
                    378:             rewind(f);
                    379:          if (ftell(f)==start_pos)
                    380:             return;
                    381:       }
                    382:    }
                    383: 
                    384:    // See if field is in buffer
                    385:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                    386:       if (field_buffers[i].section==current_section)
                    387:          if (strnicmp(field_buffers[i].name,field,MAX_FIELD_WIDTH)==0)
                    388:             break;
                    389: 
                    390:    // If field is in buffer, seek to it and read it
                    391:    if (i<NUM_FIELD_BUFFERS)
                    392:    {
                    393:       fseek(f,field_buffers[i].offset,SEEK_SET);
                    394:       stripped_fgets(ts,INI_STRING_SIZE*2,f);
                    395:       get_field_string(s,ts);
                    396:    }
                    397:    else
                    398:    // else search through section for field.
                    399:    {
                    400:       // Make sure we do not start at eof or this will cause problems.
                    401:       if (feof(f))
                    402:          fseek(f,section_buffers[current_section].offset,SEEK_SET);
                    403:       start_pos=ftell(f);
                    404:       while (1)
                    405:       {
                    406:          string_start_pos=ftell(f);
                    407:          stripped_fgets(ts,INI_STRING_SIZE*2,f);
                    408:          // If it is a field, add it to the buffer
                    409:          if (is_field(ts,"*"))
                    410:             add_field(ts,current_section,string_start_pos);
                    411:          // If it is the field we are looking for, save it
                    412:          if (is_field(ts,field))
                    413:          {
                    414:             get_field_string(s,ts);
                    415:             break;
                    416:          }
                    417:          // If we reach the end of the section, start over
                    418:          if (feof(f) || is_section(ts,"*"))
                    419:             fseek(f,section_buffers[current_section].offset,SEEK_SET);
                    420:          if (ftell(f)==start_pos)
                    421:             return;
                    422:       }
                    423:    }
                    424: }
                    425: 
                    426: //=============================================================================
                    427: 
                    428: #define BYTE unsigned char
                    429: #define WORD unsigned short
                    430: #define DWORD unsigned long
                    431: 
                    432: #define BUFFER_SIZE 4096
                    433: 
                    434: #define CODEC_ADC_INPUT_CONTROL_LEFT   0x00
                    435: #define CODEC_ADC_INPUT_CONTROL_RIGHT  0x01
                    436: #define CODEC_AUX1_INPUT_CONTROL_LEFT  0x02
                    437: #define CODEC_AUX1_INPUT_CONTROL_RIGHT 0x03
                    438: #define CODEC_AUX2_INPUT_CONTROL_LEFT  0x04
                    439: #define CODEC_AUX2_INPUT_CONTROL_RIGHT 0x05
                    440: #define CODEC_DAC_OUTPUT_CONTROL_LEFT  0x06
                    441: #define CODEC_DAC_OUTPUT_CONTROL_RIGHT 0x07
                    442: #define CODEC_FS_FORMAT                        0x08
                    443: #define CODEC_INTERFACE_CONFIG         0x09
                    444: #define CODEC_PIN_CONTROL              0x0A
                    445: #define CODEC_ERROR_STATUS_AND_INIT    0x0B
                    446: #define CODEC_MODE_AND_ID              0x0C
                    447: #define CODEC_LOOPBACK_CONTROL         0x0D
                    448: #define CODEC_PLAYBACK_UPPER_BASE_COUNT        0x0E
                    449: #define CODEC_PLAYBACK_LOWER_BASE_COUNT        0x0F
                    450: 
1.1.1.2 ! root      451: #define SET_CONTROL                    0x00
        !           452: #define SET_FREQUENCY                  0x01
        !           453: #define SET_START_HIGH                 0x02
        !           454: #define SET_START_LOW                  0x03
        !           455: #define SET_END_HIGH                   0x04
        !           456: #define SET_END_LOW                    0x05
        !           457: #define SET_VOLUME_RATE                        0x06
        !           458: #define SET_VOLUME_START               0x07
        !           459: #define SET_VOLUME_END                 0x08
        !           460: #define SET_CURR_VOLUME                        0x09
        !           461: #define SET_VOLUME                     0x09
        !           462: #define SET_ACC_HIGH                   0x0A
        !           463: #define SET_ACC_LOW                    0x0B
        !           464: #define SET_BALANCE                    0x0C
        !           465: #define SET_VOLUME_CONTROL             0x0D
        !           466: #define SET_VOICES                     0x0E
        !           467: 
        !           468: #define DMA_CONTROL                    0x41
        !           469: #define SET_DMA_ADDRESS                        0x42
        !           470: #define SET_DRAM_LOW                   0x43
        !           471: #define SET_DRAM_HIGH                  0x44
        !           472: #define ADLIB_CONTROL                  0x45
        !           473: #define ADLIB_TIMER1                   0x46
        !           474: #define ADLIB_TIMER2                   0x47
        !           475: #define SET_RECORD_RATE                        0x48
        !           476: #define RECORD_CONTROL                 0x49
        !           477: #define SET_JOYSTICK                   0x4B
        !           478: #define MASTER_RESET                   0x4C
        !           479: 
        !           480: #define GET_CONTROL                    0x80
        !           481: #define GET_FREQUENCY                  0x81
        !           482: #define GET_START_HIGH                 0x82
        !           483: #define GET_START_LOW                  0x83
        !           484: #define GET_END_HIGH                   0x84
        !           485: #define GET_END_LOW                    0x85
        !           486: #define GET_VOLUME_RATE                        0x86
        !           487: #define GET_VOLUME_START               0x87
        !           488: #define GET_VOLUME_END                 0x88
        !           489: #define GET_VOLUME                     0x89
        !           490: #define GET_ACC_HIGH                   0x8A
        !           491: #define GET_ACC_LOW                    0x8B
        !           492: #define GET_BALANCE                    0x8C
        !           493: #define GET_VOLUME_CONTROL             0x8D
        !           494: #define GET_VOICES                     0x8E
        !           495: #define GET_IRQV                        0x8F
        !           496: 
1.1       root      497: struct CodecRateStruct
                    498: {
                    499:    WORD Rate;
                    500:    BYTE FSVal;
                    501: };
                    502: 
1.1.1.2 ! root      503: struct Gf1RateStruct
        !           504: {
        !           505:    WORD Rate;
        !           506:    BYTE Voices;
        !           507: };
        !           508: 
1.1       root      509: //=============================================================================
                    510: // Reference variables in SND_DOS.C
                    511: //=============================================================================
                    512: extern short *dma_buffer;
                    513: 
                    514: //=============================================================================
                    515: // GUS-only variables
                    516: //=============================================================================
1.1.1.2 ! root      517: static BYTE HaveCodec=0;
        !           518: 
1.1       root      519: static WORD CodecRegisterSelect;
                    520: static WORD CodecData;
                    521: static WORD CodecStatus;
1.1.1.2 ! root      522: static WORD Gf1TimerControl;
        !           523: static WORD Gf1PageRegister;
        !           524: static WORD Gf1RegisterSelect;
        !           525: static WORD Gf1DataLow;
        !           526: static WORD Gf1DataHigh;
1.1       root      527: 
                    528: static BYTE DmaChannel;
                    529: 
                    530: static BYTE PageRegs[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
                    531: static BYTE AddrRegs[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc };
                    532: static BYTE CountRegs[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce };
                    533: 
                    534: static WORD AddrReg;
                    535: static WORD CountReg;
                    536: static WORD ModeReg;
                    537: static WORD DisableReg;
                    538: static WORD ClearReg;
                    539: 
                    540: static struct CodecRateStruct CodecRates[]=
                    541: {
                    542:    { 5512,0x01},
                    543:    { 6620,0x0F},
                    544:    { 8000,0x00},
                    545:    { 9600,0x0E},
                    546:    {11025,0x03},
                    547:    {16000,0x02},
                    548:    {18900,0x05},
                    549:    {22050,0x07},
                    550:    {27420,0x04},
                    551:    {32000,0x06},
                    552:    {33075,0x0D},
                    553:    {37800,0x09},
                    554:    {44100,0x0B},
                    555:    {48000,0x0C},
                    556:    {    0,0x00} // End marker
                    557: };
                    558: 
1.1.1.2 ! root      559: static struct Gf1RateStruct Gf1Rates[]=
        !           560: {
        !           561:    {19293,32},
        !           562:    {19916,31},
        !           563:    {20580,30},
        !           564:    {21289,29},
        !           565:    {22050,28},
        !           566:    {22866,27},
        !           567:    {23746,26},
        !           568:    {24696,25},
        !           569:    {25725,24},
        !           570:    {26843,23},
        !           571:    {28063,22},
        !           572:    {29400,21},
        !           573:    {30870,20},
        !           574:    {32494,19},
        !           575:    {34300,18},
        !           576:    {36317,17},
        !           577:    {38587,16},
        !           578:    {41160,15},
        !           579:    {44100,14},
        !           580:    {0,0}
        !           581: };
        !           582: 
        !           583: //=============================================================================
        !           584: // Basic GF1 functions
        !           585: //=============================================================================
        !           586: void SetGf18(BYTE reg,BYTE data)
        !           587: {
        !           588:    dos_outportb(Gf1RegisterSelect,reg);
        !           589:    dos_outportb(Gf1DataHigh,data);
        !           590: }
        !           591: 
        !           592: void SetGf116(BYTE reg,WORD data)
        !           593: {
        !           594:    dos_outportb(Gf1RegisterSelect,reg);
        !           595:    dos_outportw(Gf1DataLow,data);
        !           596: }
        !           597: 
        !           598: BYTE GetGf18(BYTE reg)
        !           599: {
        !           600:    dos_outportb(Gf1RegisterSelect,reg);
        !           601:    return(dos_inportb(Gf1DataHigh));
        !           602: }
        !           603: 
        !           604: WORD GetGf116(BYTE reg)
        !           605: {
        !           606:    dos_outportb(Gf1RegisterSelect,reg);
        !           607:    return(dos_inportw(Gf1DataLow));
        !           608: }
        !           609: 
        !           610: void Gf1Delay(void)
        !           611: {
        !           612:    int i;
        !           613: 
        !           614:    for (i=0;i<27;i++)
        !           615:       dos_inportb(Gf1TimerControl);
        !           616: }
        !           617: 
        !           618: DWORD ConvertTo16(DWORD Address)
        !           619: {
        !           620:    return( ((Address>>1) & 0x0001FFFF) | (Address & 0x000C0000L) );
        !           621: }
        !           622: 
        !           623: void ClearGf1Ints(void)
        !           624: {
        !           625:    int i;
        !           626: 
        !           627:    SetGf18(DMA_CONTROL,0x00);
        !           628:    SetGf18(ADLIB_CONTROL,0x00);
        !           629:    SetGf18(RECORD_CONTROL,0x00);
        !           630:                
        !           631:    GetGf18(DMA_CONTROL);
        !           632:    GetGf18(RECORD_CONTROL);
        !           633:    for (i=0;i<32;i++);
        !           634:       GetGf18(GET_IRQV);
        !           635: }
        !           636: 
        !           637: 
1.1       root      638: //=============================================================================
                    639: // Get Interwave (UltraSound PnP) configuration if any
                    640: //=============================================================================
                    641: static qboolean GUS_GetIWData(void)
                    642: {
                    643:    char *Interwave,s[INI_STRING_SIZE];
                    644:    FILE *IwFile;
                    645:    int  CodecBase,CodecDma,i;
                    646: 
                    647:    Interwave=getenv("INTERWAVE");
                    648:    if (Interwave==NULL)
                    649:       return(false);
                    650: 
                    651:    // Open IW.INI
                    652:    IwFile=ini_fopen(Interwave,"rt");
                    653:    if (IwFile==NULL)
                    654:       return(false);
                    655: 
                    656:    // Read codec base and codec DMA
                    657:    ini_fgets(IwFile,"setup 0","CodecBase",s);
                    658:    sscanf(s,"%X",&CodecBase);
                    659:    ini_fgets(IwFile,"setup 0","DMA2",s);
                    660:    sscanf(s,"%i",&CodecDma);
                    661: 
                    662:    ini_fclose(IwFile);
                    663: 
                    664:    // Make sure numbers OK
                    665:    if (CodecBase==0 || CodecDma==0)
                    666:       return(false);
                    667: 
                    668:    CodecRegisterSelect=CodecBase;
                    669:    CodecData=CodecBase+1;
                    670:    CodecStatus=CodecBase+2;
                    671:    DmaChannel=CodecDma;
                    672: 
                    673:    // Make sure there is a CODEC at the CODEC base
                    674: 
                    675:    // Clear any pending IRQs
                    676:    dos_inportb(CodecStatus);
                    677:    dos_outportb(CodecStatus,0);
                    678: 
                    679:    // Wait for 'INIT' bit to clear
                    680:    for (i=0;i<0xFFFF;i++)
                    681:       if ((dos_inportb(CodecRegisterSelect) & 0x80) == 0)
                    682:          break;
                    683:    if (i==0xFFFF)
                    684:       return(false);
                    685: 
                    686:    // Get chip revision - can not be zero
                    687:    dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
                    688:    if ((dos_inportb(CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID)
                    689:       return(false);
                    690:    if ((dos_inportb(CodecData) & 0x0F) == 0)
                    691:       return(false);
                    692: 
1.1.1.2 ! root      693:    HaveCodec=1;
        !           694:    Con_Printf("Sound Card is UltraSound PnP\n");
1.1       root      695:    return(true);
                    696: }
                    697: 
                    698: //=============================================================================
                    699: // Get UltraSound MAX configuration if any
                    700: //=============================================================================
                    701: static qboolean GUS_GetMAXData(void)
                    702: {
                    703:    char *Ultrasnd,*Ultra16;
                    704:    int  i;
                    705:    int  GusBase,Dma1,Dma2,Irq1,Irq2;
                    706:    int  CodecBase,CodecDma,CodecIrq,CodecType;
                    707:    BYTE MaxVal;
                    708: 
                    709:    Ultrasnd=getenv("ULTRASND");
                    710:    Ultra16=getenv("ULTRA16");
                    711:    if (Ultrasnd==NULL || Ultra16==NULL)
                    712:       return(false);
                    713: 
                    714:    sscanf(Ultrasnd,"%x,%i,%i,%i,%i",&GusBase,&Dma1,&Dma2,&Irq1,&Irq2);
                    715:    sscanf(Ultra16,"%x,%i,%i,%i",&CodecBase,&CodecDma,&CodecIrq,&CodecType);
                    716: 
                    717:    if (CodecType==0 && CodecDma!=0)
                    718:       DmaChannel=CodecDma & 0x07;
                    719:    else
                    720:       DmaChannel=Dma2 & 0x07;
                    721: 
                    722:    // Make sure there is a GUS at GUS base
                    723:    dos_outportb(GusBase+0x08,0x55);
                    724:    if (dos_inportb(GusBase+0x0A)!=0x55)
                    725:       return(false);
                    726:    dos_outportb(GusBase+0x08,0xAA);
                    727:    if (dos_inportb(GusBase+0x0A)!=0xAA)
                    728:       return(false);
                    729: 
                    730:    // Program CODEC control register
                    731:    MaxVal=((CodecBase & 0xF0)>>4) | 0x40;
                    732:    if (Dma1 > 3)
                    733:       MaxVal|=0x10;
                    734:    if (Dma2 > 3)
                    735:       MaxVal|=0x20;
                    736:    dos_outportb(GusBase+0x106,MaxVal);
                    737: 
                    738:    CodecRegisterSelect=CodecBase;
                    739:    CodecData=CodecBase+1;
                    740:    CodecStatus=CodecBase+2;
                    741: 
                    742:    // Make sure there is a CODEC at the CODEC base
                    743: 
                    744:    // Clear any pending IRQs
                    745:    dos_inportb(CodecStatus);
                    746:    dos_outportb(CodecStatus,0);
                    747: 
                    748:    // Wait for 'INIT' bit to clear
                    749:    for (i=0;i<0xFFFF;i++)
                    750:       if ((dos_inportb(CodecRegisterSelect) & 0x80) == 0)
                    751:          break;
                    752:    if (i==0xFFFF)
                    753:       return(false);
                    754: 
                    755:    // Get chip revision - can not be zero
                    756:    dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
                    757:    if ((dos_inportb(CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID)
                    758:       return(false);
                    759:    if ((dos_inportb(CodecData) & 0x0F) == 0)
                    760:       return(false);
                    761: 
1.1.1.2 ! root      762:    HaveCodec=1;
        !           763:    Con_Printf("Sound Card is UltraSound MAX\n");
        !           764:    return(true);
        !           765: }
        !           766: 
        !           767: //=============================================================================
        !           768: // Get regular UltraSound configuration if any
        !           769: //=============================================================================
        !           770: static qboolean GUS_GetGUSData(void)
        !           771: {
        !           772:    char *Ultrasnd;
        !           773:    int  GusBase,Dma1,Dma2,Irq1,Irq2,i;
        !           774: 
        !           775:    Ultrasnd=getenv("ULTRASND");
        !           776:    if (Ultrasnd==NULL)
        !           777:       return(false);
        !           778: 
        !           779:    sscanf(Ultrasnd,"%x,%i,%i,%i,%i",&GusBase,&Dma1,&Dma2,&Irq1,&Irq2);
        !           780: 
        !           781:    DmaChannel=Dma1 & 0x07;
        !           782: 
        !           783:    // Make sure there is a GUS at GUS base
        !           784:    dos_outportb(GusBase+0x08,0x55);
        !           785:    if (dos_inportb(GusBase+0x0A)!=0x55)
        !           786:       return(false);
        !           787:    dos_outportb(GusBase+0x08,0xAA);
        !           788:    if (dos_inportb(GusBase+0x0A)!=0xAA)
        !           789:       return(false);
        !           790: 
        !           791:    Gf1TimerControl   = GusBase+0x008;
        !           792:    Gf1PageRegister   = GusBase+0x102;
        !           793:    Gf1RegisterSelect = GusBase+0x103;
        !           794:    Gf1DataLow        = GusBase+0x104;
        !           795:    Gf1DataHigh       = GusBase+0x105;
        !           796: 
        !           797:    // Reset the GUS
        !           798:    SetGf18(MASTER_RESET,0x00);
        !           799:    Gf1Delay();
        !           800:    Gf1Delay();
        !           801:    SetGf18(MASTER_RESET,0x01);
        !           802:    Gf1Delay();
        !           803:    Gf1Delay();
        !           804: 
        !           805:    // Set to max (32) voices
        !           806:    SetGf18(SET_VOICES,0xDF);
        !           807: 
        !           808:    // Clear any pending IRQ's
        !           809:    ClearGf1Ints();
        !           810: 
        !           811:    // Set all registers to known values
        !           812:    for (i=0;i<32;i++)
        !           813:    {
        !           814:       dos_outportb(Gf1PageRegister,i);
        !           815:       SetGf18(SET_CONTROL,0x03);
        !           816:       SetGf18(SET_VOLUME_CONTROL,0x03);
        !           817:       Gf1Delay();
        !           818:       SetGf18(SET_CONTROL,0x03);
        !           819:       SetGf18(SET_VOLUME_CONTROL,0x03);
        !           820:       SetGf116(SET_START_HIGH,0);
        !           821:       SetGf116(SET_START_LOW,0);
        !           822:       SetGf116(SET_END_HIGH,0);
        !           823:       SetGf116(SET_END_LOW,0);
        !           824:       SetGf116(SET_ACC_HIGH,0);
        !           825:       SetGf116(SET_ACC_LOW,0);
        !           826:       SetGf18(SET_VOLUME_RATE,63);
        !           827:       SetGf18(SET_VOLUME_START,5);
        !           828:       SetGf18(SET_VOLUME_END,251);
        !           829:       SetGf116(SET_VOLUME,5<<8);
        !           830:    }
        !           831: 
        !           832:    // Clear any pending IRQ's
        !           833:    ClearGf1Ints();
        !           834: 
        !           835:    // Enable DAC etc.
        !           836:    SetGf18(MASTER_RESET,0x07);
        !           837: 
        !           838:    // Enable line output so we can hear something
        !           839:    dos_outportb(GusBase,0x08);
        !           840: 
        !           841:    HaveCodec=0;
        !           842:    Con_Printf("Sound Card is UltraSound\n");
1.1       root      843:    return(true);
                    844: }
                    845: 
1.1.1.2 ! root      846: 
1.1       root      847: //=============================================================================
                    848: // Programs the DMA controller to start DMAing in Auto-init mode
                    849: //=============================================================================
                    850: static void GUS_StartDMA(BYTE DmaChannel,short *dma_buffer,int count)
                    851: {
                    852:    int mode;
                    853:    int RealAddr;
                    854: 
                    855:    RealAddr = ptr2real(dma_buffer);
                    856: 
                    857:    if (DmaChannel <= 3)
                    858:    {
                    859:       ModeReg = 0x0B;
                    860:       DisableReg = 0x0A;
                    861:       ClearReg = 0x0E;
                    862:    }
                    863:    else
                    864:    {
                    865:       ModeReg = 0xD6;
                    866:       DisableReg = 0xD4;
                    867:       ClearReg = 0xDC;
                    868:    }
                    869:    CountReg=CountRegs[DmaChannel];
                    870:    AddrReg=AddrRegs[DmaChannel];
                    871: 
                    872:    dos_outportb(DisableReg, DmaChannel | 4);   // disable channel
                    873: 
                    874:    // set mode- see "undocumented pc", p.876
                    875:    mode = (1<<6)               // single-cycle
                    876:           +(0<<5)              // address increment
                    877:          +(1<<4)               // auto-init dma
                    878:          +(2<<2)               // read
                    879:          +(DmaChannel & 0x03); // channel #
                    880:    dos_outportb(ModeReg, mode);
                    881: 
                    882:    // set page
                    883:    dos_outportb(PageRegs[DmaChannel], RealAddr >> 16);
                    884: 
                    885:    if (DmaChannel <= 3)
                    886:    {   // address is in bytes
                    887:       dos_outportb(0x0C, 0);           // prepare to send 16-bit value
                    888:       dos_outportb(AddrReg, RealAddr & 0xff);
                    889:       dos_outportb(AddrReg, (RealAddr>>8) & 0xff);
                    890: 
                    891:       dos_outportb(0x0C, 0);           // prepare to send 16-bit value
                    892:       dos_outportb(CountReg, (count-1) & 0xff);
                    893:       dos_outportb(CountReg, (count-1) >> 8);
                    894:    }
                    895:    else
                    896:    {   // address is in words
                    897:       dos_outportb(0xD8, 0);           // prepare to send 16-bit value
                    898:       dos_outportb(AddrReg, (RealAddr>>1) & 0xff);
                    899:       dos_outportb(AddrReg, (RealAddr>>9) & 0xff);
                    900: 
                    901:       dos_outportb(0xD8, 0);           // prepare to send 16-bit value
                    902:       dos_outportb(CountReg, ((count>>1)-1) & 0xff);
                    903:       dos_outportb(CountReg, ((count>>1)-1) >> 8);
                    904:    }
                    905: 
                    906:    dos_outportb(ClearReg, 0);          // clear write mask
                    907:    dos_outportb(DisableReg, DmaChannel & ~4);
                    908: }
                    909: 
                    910: //=============================================================================
                    911: // Starts the CODEC playing
                    912: //=============================================================================
                    913: static void GUS_StartCODEC(int count,BYTE FSVal)
                    914: {
                    915:    int i,j;
                    916: 
                    917:    // Clear any pending IRQs
                    918:    dos_inportb(CodecStatus);
                    919:    dos_outportb(CodecStatus,0);
                    920: 
                    921:    // Set mode to 2
                    922:    dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
                    923:    dos_outportb(CodecData,0xC0);
                    924: 
                    925:    // Stop any playback or capture which may be happening
                    926:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    927:    dos_outportb(CodecData,dos_inportb(CodecData) & 0xFC);
                    928: 
                    929:    // Set FS
                    930:    dos_outportb(CodecRegisterSelect,CODEC_FS_FORMAT | 0x40);
                    931:    dos_outportb(CodecData,FSVal | 0x50); // Or in stereo and 16 bit bits
                    932: 
                    933:    // Wait a bit
                    934:    for (i=0;i<10;i++)
                    935:       dos_inportb(CodecData);
                    936: 
                    937:    // Routine 1 to counter CODEC bug - wait for init bit to clear and then a
                    938:    // bit longer (i=min loop count, j=timeout
                    939:    for (i=0,j=0;i<1000 && j<0x7FFFF;j++)
                    940:       if ((dos_inportb(CodecRegisterSelect) & 0x80)==0)
                    941:          i++;
                    942: 
                    943:    // Routine 2 to counter CODEC bug - this is from Forte's code. For me it
                    944:    // does not seem to cure the problem, but is added security
                    945:    // Waits till we can modify index register
                    946:    for (j=0;j<0x7FFFF;j++)
                    947:    {
                    948:       dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
                    949:       if (dos_inportb(CodecRegisterSelect)==(CODEC_INTERFACE_CONFIG | 0x40))
                    950:          break;
                    951:    }
                    952: 
                    953:    // Perform ACAL
                    954:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
                    955:    dos_outportb(CodecData,0x08);
                    956: 
                    957:    // Clear MCE bit - this makes ACAL happen
                    958:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    959: 
                    960:    // Wait for ACAL to finish
                    961:    for (j=0;j<0x7FFFF;j++)
                    962:    {
                    963:       if ((dos_inportb(CodecRegisterSelect) & 0x80) != 0)
                    964:          continue;
                    965:       dos_outportb(CodecRegisterSelect,CODEC_ERROR_STATUS_AND_INIT);
                    966:       if ((dos_inportb(CodecData) & 0x20) == 0)
                    967:          break;
                    968:    }
                    969: 
                    970:    // Clear ACAL bit
                    971:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
                    972:    dos_outportb(CodecData,0x00);
                    973:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    974: 
                    975:    // Set some other junk
                    976:    dos_outportb(CodecRegisterSelect,CODEC_LOOPBACK_CONTROL);
                    977:    dos_outportb(CodecData,0x00);
                    978:    dos_outportb(CodecRegisterSelect,CODEC_PIN_CONTROL);
                    979:    dos_outportb(CodecData,0x08); // IRQ is disabled in PIN control
                    980: 
                    981:    // Set count (it doesn't really matter what value we stuff in here
                    982:    dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_LOWER_BASE_COUNT);
                    983:    dos_outportb(CodecData,count & 0xFF);
                    984:    dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_UPPER_BASE_COUNT);
                    985:    dos_outportb(CodecData,count >> 8);
                    986: 
                    987:    // Start playback
                    988:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    989:    dos_outportb(CodecData,0x01);
                    990: }
                    991: 
                    992: //=============================================================================
1.1.1.2 ! root      993: // Starts the GF1 playing
1.1       root      994: //=============================================================================
1.1.1.2 ! root      995: static void GUS_StartGf1(int count,BYTE Voices)
1.1       root      996: {
1.1.1.2 ! root      997:    DWORD StartAddressL,EndAddressL,StartAddressR,EndAddressR;
1.1       root      998: 
1.1.1.2 ! root      999:    // Set number of voices to give us the sampling rate we want
        !          1000:    SetGf18(SET_VOICES,0xC0 | (Voices-1));
1.1       root     1001: 
1.1.1.2 ! root     1002:    // Figure out addresses
        !          1003:    StartAddressL=ConvertTo16(0);
        !          1004:    EndAddressL=ConvertTo16(count-2-2);
        !          1005:    StartAddressR=ConvertTo16(2);
        !          1006:    EndAddressR=ConvertTo16(count-2);
        !          1007: 
        !          1008:    // Set left voice addresses
        !          1009:    dos_outportb(Gf1PageRegister,0);
        !          1010:    SetGf116(SET_START_LOW,StartAddressL<<9);
        !          1011:    SetGf116(SET_START_HIGH,StartAddressL>>7);
        !          1012:    SetGf116(SET_ACC_LOW,StartAddressL<<9);
        !          1013:    SetGf116(SET_ACC_HIGH,StartAddressL>>7);
        !          1014:    SetGf116(SET_END_LOW,EndAddressL<<9);
        !          1015:    SetGf116(SET_END_HIGH,EndAddressL>>7);
        !          1016:    // Set balance to full left
        !          1017:    SetGf18(SET_BALANCE,0);
        !          1018:    // Set volume to full
        !          1019:    SetGf116(SET_VOLUME,0xFFF0);
        !          1020:    // Set FC to 2 (so we play every second sample)
        !          1021:    SetGf116(SET_FREQUENCY,0x0800);
        !          1022: 
        !          1023:    // Set right voice addresses
        !          1024:    dos_outportb(Gf1PageRegister,1);
        !          1025:    SetGf116(SET_START_LOW,StartAddressR<<9);
        !          1026:    SetGf116(SET_START_HIGH,StartAddressR>>7);
        !          1027:    SetGf116(SET_ACC_LOW,StartAddressR<<9);
        !          1028:    SetGf116(SET_ACC_HIGH,StartAddressR>>7);
        !          1029:    SetGf116(SET_END_LOW,EndAddressR<<9);
        !          1030:    SetGf116(SET_END_HIGH,EndAddressR>>7);
        !          1031:    // Set balance to full right
        !          1032:    SetGf18(SET_BALANCE,15);
        !          1033:    // Set volume to full
        !          1034:    SetGf116(SET_VOLUME,0xFFF0);
        !          1035:    // Set FC to 2 (so we play every second sample)
        !          1036:    SetGf116(SET_FREQUENCY,0x0800);
        !          1037: 
        !          1038:    // Start voices
        !          1039:    dos_outportb(Gf1PageRegister,0);
        !          1040:    SetGf18(SET_CONTROL,0x0C);
        !          1041:    dos_outportb(Gf1PageRegister,1);
        !          1042:    SetGf18(SET_CONTROL,0x0C);
        !          1043:    Gf1Delay();
        !          1044:    dos_outportb(Gf1PageRegister,0);
        !          1045:    SetGf18(SET_CONTROL,0x0C);
        !          1046:    dos_outportb(Gf1PageRegister,1);
        !          1047:    SetGf18(SET_CONTROL,0x0C);
        !          1048: }
1.1       root     1049: 
                   1050: 
1.1.1.2 ! root     1051: //=============================================================================
        !          1052: // Figures out what kind of UltraSound we have, if any, and starts it playing
        !          1053: //=============================================================================
        !          1054: qboolean GUS_Init(void)
        !          1055: {
        !          1056:        int rc;
        !          1057:        int RealAddr;
        !          1058:        BYTE FSVal,Voices;
        !          1059:        struct CodecRateStruct *CodecRate;
        !          1060:        struct Gf1RateStruct *Gf1Rate;
        !          1061: 
        !          1062:        // See what kind of UltraSound we have, if any
        !          1063:        if (GUS_GetIWData()==false)
        !          1064:                if (GUS_GetMAXData()==false)
        !          1065:                        if (GUS_GetGUSData()==false)
        !          1066:                                return(false);
        !          1067: 
        !          1068:        shm = &sn;
        !          1069: 
        !          1070:        if (HaveCodec)
        !          1071:        {
        !          1072:                // do 11khz sampling rate unless command line parameter wants different
        !          1073:                shm->speed = 11025;
        !          1074:                FSVal = 0x03;
        !          1075:                rc = COM_CheckParm("-sspeed");
        !          1076:                if (rc)
        !          1077:                {
        !          1078:                        shm->speed = Q_atoi(com_argv[rc+1]);
        !          1079:        
        !          1080:                        // Make sure rate not too high
        !          1081:                        if (shm->speed>48000)
        !          1082:                                shm->speed=48000;
        !          1083:        
        !          1084:                        // Adjust speed to match one of the possible CODEC rates
        !          1085:                        for (CodecRate=CodecRates;CodecRate->Rate!=0;CodecRate++)
        !          1086:                        {
        !          1087:                                if (shm->speed <= CodecRate->Rate)
        !          1088:                                {
        !          1089:                                        shm->speed=CodecRate->Rate;
        !          1090:                                        FSVal=CodecRate->FSVal;
        !          1091:                                        break;
        !          1092:                                }
        !          1093:                        }
        !          1094:                }
        !          1095: 
        !          1096:        
        !          1097:                // Always do 16 bit stereo
        !          1098:                shm->channels = 2;
        !          1099:                shm->samplebits = 16;
        !          1100:        
        !          1101:                // allocate buffer twice the size we need so we can get aligned buffer
        !          1102:                dma_buffer = dos_getmemory(BUFFER_SIZE*2);
        !          1103:                if (dma_buffer==NULL)
        !          1104:                {
        !          1105:                        Con_Printf("Couldn't allocate sound dma buffer");
        !          1106:                        return false;
        !          1107:                }
        !          1108: 
        !          1109:                RealAddr = ptr2real(dma_buffer);
        !          1110:                RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
        !          1111:                dma_buffer = (short *) real2ptr(RealAddr);
        !          1112: 
        !          1113:                // Zero off DMA buffer
        !          1114:                memset(dma_buffer, 0, BUFFER_SIZE);
        !          1115: 
        !          1116:                shm->soundalive = true;
        !          1117:                shm->splitbuffer = false;
        !          1118: 
        !          1119:                shm->samplepos = 0;
        !          1120:                shm->submission_chunk = 1;
        !          1121:                shm->buffer = (unsigned char *) dma_buffer;
        !          1122:                shm->samples = BUFFER_SIZE/(shm->samplebits/8);
        !          1123: 
        !          1124:                GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
        !          1125:                GUS_StartCODEC(BUFFER_SIZE,FSVal);
        !          1126:        }
        !          1127:        else
        !          1128:        {
        !          1129:                // do 19khz sampling rate unless command line parameter wants different
        !          1130:                shm->speed = 19293;
        !          1131:                Voices=32;
        !          1132:                rc = COM_CheckParm("-sspeed");
        !          1133:                if (rc)
        !          1134:                {
        !          1135:                        shm->speed = Q_atoi(com_argv[rc+1]);
        !          1136: 
        !          1137:                        // Make sure rate not too high
        !          1138:                        if (shm->speed>44100)
        !          1139:                                shm->speed=44100;
        !          1140: 
        !          1141:                        // Adjust speed to match one of the possible GF1 rates
        !          1142:                        for (Gf1Rate=Gf1Rates;Gf1Rate->Rate!=0;Gf1Rate++)
        !          1143:                        {
        !          1144:                                if (shm->speed <= Gf1Rate->Rate)
        !          1145:                                {
        !          1146:                                        shm->speed=Gf1Rate->Rate;
        !          1147:                                        Voices=Gf1Rate->Voices;
        !          1148:                                        break;
        !          1149:                                }
        !          1150:                        }
        !          1151:                }
        !          1152: 
        !          1153:                // Always do 16 bit stereo
        !          1154:                shm->channels = 2;
        !          1155:                shm->samplebits = 16;
        !          1156: 
        !          1157:                // allocate buffer twice the size we need so we can get aligned buffer
        !          1158:                dma_buffer = dos_getmemory(BUFFER_SIZE*2);
        !          1159:                if (dma_buffer==NULL)
        !          1160:                {
        !          1161:                        Con_Printf("Couldn't allocate sound dma buffer");
        !          1162:                        return false;
        !          1163:                }
        !          1164: 
        !          1165:                RealAddr = ptr2real(dma_buffer);
        !          1166:                RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
        !          1167:                dma_buffer = (short *) real2ptr(RealAddr);
        !          1168: 
        !          1169:                // Zero off DMA buffer
        !          1170:                memset(dma_buffer, 0, BUFFER_SIZE);
        !          1171: 
        !          1172:                shm->soundalive = true;
        !          1173:                shm->splitbuffer = false;
        !          1174: 
        !          1175:                shm->samplepos = 0;
        !          1176:                shm->submission_chunk = 1;
        !          1177:                shm->buffer = (unsigned char *) dma_buffer;
        !          1178:                shm->samples = BUFFER_SIZE/(shm->samplebits/8);
        !          1179: 
        !          1180:                GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
        !          1181:                SetGf116(SET_DMA_ADDRESS,0x0000);
        !          1182:                if (DmaChannel<=3)
        !          1183:                        SetGf18(DMA_CONTROL,0x41);
        !          1184:                else
        !          1185:                        SetGf18(DMA_CONTROL,0x45);
        !          1186:                GUS_StartGf1(BUFFER_SIZE,Voices);
        !          1187:        }
        !          1188:        return(true);
1.1       root     1189: }
                   1190: 
                   1191: //=============================================================================
                   1192: // Returns the current playback position
                   1193: //=============================================================================
                   1194: int GUS_GetDMAPos(void)
                   1195: {
                   1196:    int count;
                   1197: 
1.1.1.2 ! root     1198:        if (HaveCodec)
        !          1199:        {
        !          1200:           // clear 16-bit reg flip-flop
        !          1201:          // load the current dma count register
        !          1202:          if (DmaChannel < 4)
        !          1203:          {
        !          1204:             dos_outportb(0x0C, 0);
        !          1205:             count = dos_inportb(CountReg);
        !          1206:             count += dos_inportb(CountReg) << 8;
        !          1207:             if (shm->samplebits == 16)
        !          1208:                count /= 2;
        !          1209:             count = shm->samples - (count+1);
        !          1210:          }
        !          1211:          else
        !          1212:          {
        !          1213:             dos_outportb(0xD8, 0);
        !          1214:             count = dos_inportb(CountReg);
        !          1215:             count += dos_inportb(CountReg) << 8;
        !          1216:             if (shm->samplebits == 8)
        !          1217:                count *= 2;
        !          1218:             count = shm->samples - (count+1);
        !          1219:          }
        !          1220: 
        !          1221:        }
        !          1222:        else
        !          1223:        {
        !          1224:                // Read current position from GF1
        !          1225:                dos_outportb(Gf1PageRegister,0);
        !          1226:                count=(GetGf116(GET_ACC_HIGH)<<7) & 0xFFFF;
        !          1227:                // See which half of buffer we are in. Note that since this is 16 bit
        !          1228:                // data we are playing, position is in 16 bit samples
        !          1229:                if (GetGf18(DMA_CONTROL) & 0x40)
        !          1230:                {
        !          1231:                        GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
        !          1232:                        SetGf116(SET_DMA_ADDRESS,0x0000);
        !          1233:                        if (DmaChannel<=3)
        !          1234:                                SetGf18(DMA_CONTROL,0x41);
        !          1235:                        else
        !          1236:                                SetGf18(DMA_CONTROL,0x45);
        !          1237:                }
        !          1238:        }
1.1       root     1239: 
                   1240:    shm->samplepos = count & (shm->samples-1);
                   1241:    return(shm->samplepos);
                   1242: }
                   1243: 
                   1244: //=============================================================================
                   1245: // Stops the UltraSound playback
                   1246: //=============================================================================
                   1247: void GUS_Shutdown (void)
                   1248: {
1.1.1.2 ! root     1249:        if (HaveCodec)
        !          1250:        {
        !          1251:                // Stop CODEC
        !          1252:                dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
        !          1253:                dos_outportb(CodecData,0x01);
        !          1254:        }
        !          1255:        else
        !          1256:        {
        !          1257:                // Stop Voices
        !          1258:                dos_outportb(Gf1PageRegister,0);
        !          1259:                SetGf18(SET_CONTROL,0x03);
        !          1260:                dos_outportb(Gf1PageRegister,1);
        !          1261:                SetGf18(SET_CONTROL,0x03);
        !          1262:                Gf1Delay();
        !          1263:                dos_outportb(Gf1PageRegister,0);
        !          1264:                SetGf18(SET_CONTROL,0x03);
        !          1265:                dos_outportb(Gf1PageRegister,1);
        !          1266:                SetGf18(SET_CONTROL,0x03);
        !          1267: 
        !          1268:                // Stop any DMA
        !          1269:                SetGf18(DMA_CONTROL,0x00);
        !          1270:                GetGf18(DMA_CONTROL);
        !          1271:        }
1.1       root     1272: 
1.1.1.2 ! root     1273:        dos_outportb(DisableReg, DmaChannel | 4); // disable dma channel
1.1       root     1274: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.