diff options
| author | Travis Bradshaw <travis.bradshaw@idsoftware.com> | 2012-01-31 14:32:09 -0600 |
|---|---|---|
| committer | Travis Bradshaw <travis.bradshaw@idsoftware.com> | 2012-01-31 14:32:09 -0600 |
| commit | 0023db327bc1db00068284b70e1db45857aeee35 (patch) | |
| tree | 01dd8366d20bd674741cfe8ceb069d82a2e33973 /WinQuake/snd_dos.c | |
| download | quake-pum-0023db327bc1db00068284b70e1db45857aeee35.tar.gz | |
The Quake sources as originally release under the GPL license on December 21, 1999
Diffstat (limited to 'WinQuake/snd_dos.c')
| -rw-r--r-- | WinQuake/snd_dos.c | 653 |
1 files changed, 653 insertions, 0 deletions
diff --git a/WinQuake/snd_dos.c b/WinQuake/snd_dos.c new file mode 100644 index 0000000..bcb93b2 --- /dev/null +++ b/WinQuake/snd_dos.c @@ -0,0 +1,653 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" +#include "dosisms.h" + +int BLASTER_GetDMAPos(void); + +/* +=============================================================================== +GUS SUPPORT + +=============================================================================== +*/ + +qboolean GUS_Init (void); +int GUS_GetDMAPos (void); +void GUS_Shutdown (void); + + +/* +=============================================================================== + +BLASTER SUPPORT + +=============================================================================== +*/ + +short *dma_buffer=0; +static int dma_size; +static int dma; + +static int dsp_port; +static int irq; +static int low_dma; +static int high_dma; +static int mixer_port; +static int mpu401_port; + +int dsp_version; +int dsp_minor_version; + +int timeconstant=-1; + + +void PrintBits (byte b) +{ + int i; + char str[9]; + + for (i=0 ; i<8 ; i++) + str[i] = '0' + ((b & (1<<(7-i))) > 0); + + str[8] = 0; + Con_Printf ("%s (%i)", str, b); +} + +void SB_Info_f(void) +{ + Con_Printf ("BLASTER=%s\n", getenv("BLASTER")); + Con_Printf("dsp version=%d.%d\n", dsp_version, dsp_minor_version); + Con_Printf("dma=%d\n", dma); + if (timeconstant != -1) + Con_Printf("timeconstant=%d\n", timeconstant); + Con_Printf("dma position:%i\n", BLASTER_GetDMAPos ()); +} + +// ======================================================================= +// Interprets BLASTER variable +// ======================================================================= + +int GetBLASTER(void) +{ + char *BLASTER; + char *param; + + BLASTER = getenv("BLASTER"); + if (!BLASTER) + return 0; + + param = strchr(BLASTER, 'A'); + if (!param) + param = strchr(BLASTER, 'a'); + if (!param) + return 0; + sscanf(param+1, "%x", &dsp_port); + + param = strchr(BLASTER, 'I'); + if (!param) + param = strchr(BLASTER, 'i'); + if (!param) + return 0; + sscanf(param+1, "%d", &irq); + + param = strchr(BLASTER, 'D'); + if (!param) + param = strchr(BLASTER, 'd'); + if (!param) + return 0; + sscanf(param+1, "%d", &low_dma); + + param = strchr(BLASTER, 'H'); + if (!param) + param = strchr(BLASTER, 'h'); + if (param) + sscanf(param+1, "%d", &high_dma); + + param = strchr(BLASTER, 'M'); + if (!param) + param = strchr(BLASTER, 'm'); + if (param) + sscanf(param+1, "%x", &mixer_port); + else + mixer_port = dsp_port; + + param = strchr(BLASTER, 'P'); + if (!param) + param = strchr(BLASTER, 'p'); + if (param) + sscanf(param+1, "%x", &mpu401_port); + + return 1; + +} + +// ================================================================== +// Resets DSP. Returns 0 on success. +// ================================================================== + +int ResetDSP(void) +{ + volatile int i; + + dos_outportb(dsp_port + 6, 1); + for (i=65536 ; i ; i--) ; + dos_outportb(dsp_port + 6, 0); + for (i=65536 ; i ; i--) + { + if (!(dos_inportb(dsp_port + 0xe) & 0x80)) continue; + if (dos_inportb(dsp_port + 0xa) == 0xaa) break; + } + if (i) return 0; + else return 1; + +} + +int ReadDSP(void) +{ + while (!(dos_inportb(dsp_port+0xe)&0x80)) ; + return dos_inportb(dsp_port+0xa); +} + +void WriteDSP(int val) +{ + while ((dos_inportb(dsp_port+0xc)&0x80)) ; + dos_outportb(dsp_port+0xc, val); +} + +int ReadMixer(int addr) +{ + dos_outportb(mixer_port+4, addr); + return dos_inportb(mixer_port+5); +} + +void WriteMixer(int addr, int val) +{ + dos_outportb(mixer_port+4, addr); + dos_outportb(mixer_port+5, val); +} + +int oldmixervalue; + +/* +================ +StartSB + +================ +*/ +void StartSB(void) +{ + int i; + +// version 4.xx startup code + if (dsp_version >= 4) + { + Con_Printf("Version 4 SB startup\n"); + WriteDSP(0xd1); // turn on speaker + + WriteDSP(0x41); + + WriteDSP(shm->speed>>8); + WriteDSP(shm->speed&0xff); + + WriteDSP(0xb6); // 16-bit output + WriteDSP(0x30); // stereo + WriteDSP((shm->samples-1) & 0xff); // # of samples - 1 + WriteDSP((shm->samples-1) >> 8); + } +// version 3.xx startup code + else if (dsp_version == 3) + { + Con_Printf("Version 3 SB startup\n"); + WriteDSP(0xd1); // turn on speaker + + oldmixervalue = ReadMixer (0xe); + WriteMixer (0xe, oldmixervalue | 0x2);// turn on stereo + + WriteDSP(0x14); // send one byte + WriteDSP(0x0); + WriteDSP(0x0); + + for (i=0 ; i<0x10000 ; i++) + dos_inportb(dsp_port+0xe); // ack the dsp + + timeconstant = 65536-(256000000/(shm->channels*shm->speed)); + WriteDSP(0x40); + WriteDSP(timeconstant>>8); + + WriteMixer (0xe, ReadMixer(0xe) | 0x20);// turn off filter + + WriteDSP(0x48); + WriteDSP((shm->samples-1) & 0xff); // # of samples - 1 + WriteDSP((shm->samples-1) >> 8); + + WriteDSP(0x90); // high speed 8 bit stereo + } +// normal speed mono + else + { + Con_Printf("Version 2 SB startup\n"); + WriteDSP(0xd1); // turn on speaker + + timeconstant = 65536-(256000000/(shm->channels*shm->speed)); + WriteDSP(0x40); + WriteDSP(timeconstant>>8); + + WriteDSP(0x48); + WriteDSP((shm->samples-1) & 0xff); // # of samples - 1 + WriteDSP((shm->samples-1) >> 8); + + WriteDSP(0x1c); // normal speed 8 bit mono + } +} + +static int page_reg[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; +static int addr_reg[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc }; +static int count_reg[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce }; + +static int mode_reg; +static int flipflop_reg; +static int disable_reg; +static int clear_reg; + +/* +================ +StartDMA + +================ +*/ +void StartDMA(void) +{ + int mode; + int realaddr; + + realaddr = ptr2real(dma_buffer); + +// use a high dma channel if specified + if (high_dma && dsp_version >= 4) // 8 bit snd can never use 16 bit dma + dma = high_dma; + else + dma = low_dma; + + Con_Printf ("Using DMA channel %i\n", dma); + + if (dma > 3) + { + mode_reg = 0xd6; + flipflop_reg = 0xd8; + disable_reg = 0xd4; + clear_reg = 0xdc; + } + else + { + mode_reg = 0xb; + flipflop_reg = 0xc; + disable_reg = 0xa; + clear_reg = 0xe; + } + + dos_outportb(disable_reg, dma|4); // disable channel + // set mode- see "undocumented pc", p.876 + mode = (1<<6) // single-cycle + +(0<<5) // address increment + +(1<<4) // auto-init dma + +(2<<2) // read + +(dma&3); // channel # + dos_outportb(mode_reg, mode); + +// set address + // set page + dos_outportb(page_reg[dma], realaddr >> 16); + + if (dma > 3) + { // address is in words + dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value + dos_outportb(addr_reg[dma], (realaddr>>1) & 0xff); + dos_outportb(addr_reg[dma], (realaddr>>9) & 0xff); + + dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value + dos_outportb(count_reg[dma], ((dma_size>>1)-1) & 0xff); + dos_outportb(count_reg[dma], ((dma_size>>1)-1) >> 8); + } + else + { // address is in bytes + dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value + dos_outportb(addr_reg[dma], realaddr & 0xff); + dos_outportb(addr_reg[dma], (realaddr>>8) & 0xff); + + dos_outportb(flipflop_reg, 0); // prepare to send 16-bit value + dos_outportb(count_reg[dma], (dma_size-1) & 0xff); + dos_outportb(count_reg[dma], (dma_size-1) >> 8); + } + + dos_outportb(clear_reg, 0); // clear write mask + dos_outportb(disable_reg, dma&~4); +} + + +/* +================== +BLASTER_Init + +Returns false if nothing is found. +================== +*/ +qboolean BLASTER_Init(void) +{ + int size; + int realaddr; + int rc; + int p; + + shm = 0; + rc = 0; + +// +// must have a blaster variable set +// + if (!GetBLASTER()) + { + Con_NotifyBox ( + "The BLASTER environment variable\n" + "is not set, sound effects are\n" + "disabled. See README.TXT for help.\n" + ); + return 0; + } + + if (ResetDSP()) + { + Con_Printf("Could not reset SB"); + return 0; + } + +// +// get dsp version +// + WriteDSP(0xe1); + dsp_version = ReadDSP(); + dsp_minor_version = ReadDSP(); + +// we need at least v2 for auto-init dma + if (dsp_version < 2) + { + Con_Printf ("Sound blaster must be at least v2.0\n"); + return 0; + } + +// allow command line parm to set quality down + p = COM_CheckParm ("-dsp"); + if (p && p < com_argc - 1) + { + p = Q_atoi (com_argv[p+1]); + if (p < 2 || p > 4) + Con_Printf ("-dsp parameter can only be 2, 3, or 4\n"); + else if (p > dsp_version) + Con_Printf ("Can't -dsp %i on v%i hardware\n", p, dsp_version); + else + dsp_version = p; + } + + +// everyone does 11khz sampling rate unless told otherwise + shm = &sn; + shm->speed = 11025; + rc = COM_CheckParm("-sspeed"); + if (rc) + shm->speed = Q_atoi(com_argv[rc+1]); + +// version 4 cards (sb 16) do 16 bit stereo + if (dsp_version >= 4) + { + shm->channels = 2; + shm->samplebits = 16; + } +// version 3 cards (sb pro) do 8 bit stereo + else if (dsp_version == 3) + { + shm->channels = 2; + shm->samplebits = 8; + } +// v2 cards do 8 bit mono + else + { + shm->channels = 1; + shm->samplebits = 8; + } + + + Cmd_AddCommand("sbinfo", SB_Info_f); + size = 4096; + +// allocate 8k and get a 4k-aligned buffer from it + dma_buffer = dos_getmemory(size*2); + if (!dma_buffer) + { + Con_Printf("Couldn't allocate sound dma buffer"); + return false; + } + + realaddr = ptr2real(dma_buffer); + realaddr = (realaddr + size) & ~(size-1); + dma_buffer = (short *) real2ptr(realaddr); + dma_size = size; + + memset(dma_buffer, 0, dma_size); + + shm->soundalive = true; + shm->splitbuffer = false; + + shm->samples = size/(shm->samplebits/8); + shm->samplepos = 0; + shm->submission_chunk = 1; + shm->buffer = (unsigned char *) dma_buffer; + shm->samples = size/(shm->samplebits/8); + + StartDMA(); + StartSB(); + + return true; +} + + +/* +============== +BLASTER_GetDMAPos + +return the current sample position (in mono samples read) +inside the recirculating dma buffer, so the mixing code will know +how many sample are required to fill it up. +=============== +*/ +int BLASTER_GetDMAPos(void) +{ + int count; + +// this function is called often. acknowledge the transfer completions +// all the time so that it loops + if (dsp_version >= 4) + dos_inportb(dsp_port+0xf); // 16 bit audio + else + dos_inportb(dsp_port+0xe); // 8 bit audio + +// clear 16-bit reg flip-flop +// load the current dma count register + if (dma < 4) + { + dos_outportb(0xc, 0); + count = dos_inportb(dma*2+1); + count += dos_inportb(dma*2+1) << 8; + if (shm->samplebits == 16) + count /= 2; + count = shm->samples - (count+1); + } + else + { + dos_outportb(0xd8, 0); + count = dos_inportb(0xc0+(dma-4)*4+2); + count += dos_inportb(0xc0+(dma-4)*4+2) << 8; + if (shm->samplebits == 8) + count *= 2; + count = shm->samples - (count+1); + } + +// Con_Printf("DMA pos = 0x%x\n", count); + + shm->samplepos = count & (shm->samples-1); + return shm->samplepos; + +} + +/* +============== +BLASTER_Shutdown + +Reset the sound device for exiting +=============== +*/ +void BLASTER_Shutdown(void) +{ + if (dsp_version >= 4) + { + } + else if (dsp_version == 3) + { + ResetDSP (); // stop high speed mode + WriteMixer (0xe, oldmixervalue); // turn stereo off and filter on + } + else + { + + } + + WriteDSP(0xd3); // turn off speaker + ResetDSP (); + + dos_outportb(disable_reg, dma|4); // disable dma channel +} + + + +/* +=============================================================================== + +INTERFACE + +=============================================================================== +*/ + +typedef enum +{ + dma_none, + dma_blaster, + dma_gus +} dmacard_t; + +dmacard_t dmacard; + +/* +================== +SNDDM_Init + +Try to find a sound device to mix for. +Returns false if nothing is found. +Returns true and fills in the "shm" structure with information for the mixer. +================== +*/ +qboolean SNDDMA_Init(void) +{ + if (GUS_Init ()) + { + dmacard = dma_gus; + return true; + } + if (BLASTER_Init ()) + { + dmacard = dma_blaster; + return true; + } + + dmacard = dma_none; + + return false; +} + + +/* +============== +SNDDMA_GetDMAPos + +return the current sample position (in mono samples, not stereo) +inside the recirculating dma buffer, so the mixing code will know +how many sample are required to fill it up. +=============== +*/ +int SNDDMA_GetDMAPos(void) +{ + switch (dmacard) + { + case dma_blaster: + return BLASTER_GetDMAPos (); + case dma_gus: + return GUS_GetDMAPos (); + case dma_none: + break; + } + + return 0; +} + +/* +============== +SNDDMA_Shutdown + +Reset the sound device for exiting +=============== +*/ +void SNDDMA_Shutdown(void) +{ + switch (dmacard) + { + case dma_blaster: + BLASTER_Shutdown (); + break; + case dma_gus: + GUS_Shutdown (); + break; + case dma_none: + break; + } + + dmacard = dma_none; + return; +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +=============== +*/ +void SNDDMA_Submit(void) +{ +} + |
