home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / snd_gus.c < prev    next >
C/C++ Source or Header  |  2000-06-17  |  35KB  |  1,294 lines

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