+// Macros for SoundBlaster stuff\r
+#define sbOut(n,b) outportb((n) + sbLocation,b)\r
+#define sbIn(n) inportb((n) + sbLocation)\r
+#define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80);\r
+#define sbReadDelay() while (sbIn(sbDataAvail) & 0x80);\r
+\r
+ SoundSourcePresent,\r
+ SoundBlasterPresent,SBProPresent,\r
+\r
+ word ssPort = 2;\r
+\r
+ "nosb",\r
+ "nopro",\r
+ "noss",\r
+ "sst",\r
+ "ss1",\r
+ "ss2",\r
+ "ss3",\r
+\r
+// SoundBlaster variables\r
+static boolean sbNoCheck,sbNoProCheck;\r
+static volatile boolean sbSamplePlaying;\r
+static byte sbOldIntMask = -1;\r
+static volatile byte huge *sbNextSegPtr;\r
+static byte sbDMA = 1,\r
+ sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3,\r
+ sba1Vals[] = {0x87,0x83,0,0x82},\r
+ sba2Vals[] = {0,2,0,6},\r
+ sba3Vals[] = {1,3,0,7};\r
+static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,\r
+ sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};\r
+static volatile dword sbNextSegLen;\r
+static volatile SampledSound huge *sbSamples;\r
+static void interrupt (*sbOldIntHand)(void);\r
+static byte sbpOldFMMix,sbpOldVOCMix;\r
+\r
+// SoundSource variables\r
+ boolean ssNoCheck;\r
+ boolean ssActive;\r
+ word ssControl,ssStatus,ssData;\r
+ byte ssOn,ssOff;\r
+ volatile byte far *ssSample;\r
+ volatile dword ssLengthLeft;\r
+\r
+\r
+\r
+//++#if 0\r
+//\r
+// SoundBlaster code\r
+//\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SBStopSample() - Stops any active sampled sound and causes DMA\r
+// requests from the SoundBlaster to cease\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_SBStopSample(void)\r
+{\r
+ byte is;\r
+\r
+asm pushf\r
+asm cli\r
+\r
+ if (sbSamplePlaying)\r
+ {\r
+ sbSamplePlaying = false;\r
+\r
+ sbWriteDelay();\r
+ sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA\r
+\r
+ is = inportb(0x21); // Restore interrupt mask bit\r
+ if (sbOldIntMask & (1 << sbInterrupt))\r
+ is |= (1 << sbInterrupt);\r
+ else\r
+ is &= ~(1 << sbInterrupt);\r
+ outportb(0x21,is);\r
+ }\r
+\r
+asm popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster\r
+// Insures that the chunk doesn't cross a bank boundary, programs the DMA\r
+// controller, and tells the SB to start doing DMA requests for DAC\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static dword\r
+SDL_SBPlaySeg(volatile byte huge *data,dword length)\r
+{\r
+ unsigned datapage;\r
+ dword dataofs,uselen;\r
+\r
+ uselen = length;\r
+ datapage = FP_SEG(data) >> 12;\r
+ dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);\r
+ if (dataofs >= 0x10000)\r
+ {\r
+ datapage++;\r
+ dataofs -= 0x10000;\r
+ }\r
+\r
+ if (dataofs + uselen > 0x10000)\r
+ uselen = 0x10000 - dataofs;\r
+\r
+ uselen--;\r
+\r
+ // Program the DMA controller\r
+asm pushf\r
+asm cli\r
+ outportb(0x0a,sbDMA | 4); // Mask off DMA on channel sbDMA\r
+ outportb(0x0c,0); // Clear byte ptr flip-flop to lower byte\r
+ outportb(0x0b,0x49); // Set transfer mode for D/A conv\r
+ outportb(sbDMAa2,(byte)dataofs); // Give LSB of address\r
+ outportb(sbDMAa2,(byte)(dataofs >> 8)); // Give MSB of address\r
+ outportb(sbDMAa1,(byte)datapage); // Give page of address\r
+ outportb(sbDMAa3,(byte)uselen); // Give LSB of length\r
+ outportb(sbDMAa3,(byte)(uselen >> 8)); // Give MSB of length\r
+ outportb(0x0a,sbDMA); // Re-enable DMA on channel sbDMA\r
+\r
+ // Start playing the thing\r
+ sbWriteDelay();\r
+ sbOut(sbWriteCmd,0x14);\r
+ sbWriteDelay();\r
+ sbOut(sbWriteData,(byte)uselen);\r
+ sbWriteDelay();\r
+ sbOut(sbWriteData,(byte)(uselen >> 8));\r
+asm popf\r
+\r
+ return(uselen + 1);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SBService() - Services the SoundBlaster DMA interrupt\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+/*static*/ void interrupt\r
+SDL_SBService(void)\r
+{\r
+ dword used;\r
+\r
+ sbIn(sbDataAvail); // Ack interrupt to SB\r
+\r
+ if (sbNextSegPtr)\r
+ {\r
+ used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);\r
+ if (sbNextSegLen <= used)\r
+ sbNextSegPtr = nil;\r
+ else\r
+ {\r
+ sbNextSegPtr += used;\r
+ sbNextSegLen -= used;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ SDL_SBStopSample();\r
+ SDL_DigitizedDone();\r
+ }\r
+\r
+ outportb(0x20,0x20); // Ack interrupt\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up\r
+// DMA to play the sound\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_SBPlaySample(byte huge *data,dword len)\r
+{\r
+ dword used;\r
+\r
+ SDL_SBStopSample();\r
+\r
+asm pushf\r
+asm cli\r
+\r
+ used = SDL_SBPlaySeg(data,len);\r
+ if (len <= used)\r
+ sbNextSegPtr = nil;\r
+ else\r
+ {\r
+ sbNextSegPtr = data + used;\r
+ sbNextSegLen = len - used;\r
+ }\r
+\r
+ // Save old interrupt status and unmask ours\r
+ sbOldIntMask = inportb(0x21);\r
+ outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));\r
+\r
+ sbWriteDelay();\r
+ sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled\r
+\r
+ sbSamplePlaying = true;\r
+\r
+asm popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_PositionSBP() - Sets the attenuation levels for the left and right\r
+// channels by using the mixer chip on the SB Pro. This hits a hole in\r
+// the address map for normal SBs.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_PositionSBP(int leftpos,int rightpos)\r
+{\r
+ byte v;\r
+\r
+ if (!SBProPresent)\r
+ return;\r
+\r
+ leftpos = 15 - leftpos;\r
+ rightpos = 15 - rightpos;\r
+ v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);\r
+\r
+asm pushf\r
+asm cli\r
+\r
+ sbOut(sbpMixerAddr,sbpmVoiceVol);\r
+ sbOut(sbpMixerData,v);\r
+\r
+asm popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_CheckSB() - Checks to see if a SoundBlaster resides at a\r
+// particular I/O location\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+SDL_CheckSB(int port)\r
+{\r
+ int i;\r
+\r
+ sbLocation = port << 4; // Initialize stuff for later use\r
+\r
+ sbOut(sbReset,true); // Reset the SoundBlaster DSP\r
+asm mov dx,0x388 // Wait >4usec\r
+asm in al, dx\r
+asm in al, dx\r
+asm in al, dx\r
+asm in al, dx\r
+asm in al, dx\r
+asm in al, dx\r
+asm in al, dx\r
+asm in al, dx\r
+asm in al, dx\r
+\r
+ sbOut(sbReset,false); // Turn off sb DSP reset\r
+asm mov dx,0x388 // Wait >100usec\r
+asm mov cx,100\r
+#ifdef __WATCOMC__\r
+ __asm {\r
+#endif\r
+usecloop:\r
+asm in al,dx\r
+asm loop usecloop\r
+#ifdef __WATCOMC__\r
+ }\r
+#endif\r
+\r
+ for (i = 0;i < 100;i++)\r
+ {\r
+ if (sbIn(sbDataAvail) & 0x80) // If data is available...\r
+ {\r
+ if (sbIn(sbReadData) == 0xaa) // If it matches correct value\r
+ return(true);\r
+ else\r
+ {\r
+ sbLocation = -1; // Otherwise not a SoundBlaster\r
+ return(false);\r
+ }\r
+ }\r
+ }\r
+ sbLocation = -1; // Retry count exceeded - fail\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// Checks to see if a SoundBlaster is in the system. If the port passed is\r
+// -1, then it scans through all possible I/O locations. If the port\r
+// passed is 0, then it uses the default (2). If the port is >0, then\r
+// it just passes it directly to SDL_CheckSB()\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+SDL_DetectSoundBlaster(int port)\r
+{\r
+ int i;\r
+\r
+ if (port == 0) // If user specifies default, use 2\r
+ port = 2;\r
+ if (port == -1)\r
+ {\r
+ if (SDL_CheckSB(2)) // Check default before scanning\r
+ return(true);\r
+\r
+ if (SDL_CheckSB(4)) // Check other SB Pro location before scan\r
+ return(true);\r
+\r
+ for (i = 1;i <= 6;i++) // Scan through possible SB locations\r
+ {\r
+ if ((i == 2) || (i == 4))\r
+ continue;\r
+\r
+ if (SDL_CheckSB(i)) // If found at this address,\r
+ return(true); // return success\r
+ }\r
+ return(false); // All addresses failed, return failure\r
+ }\r
+ else\r
+ return(SDL_CheckSB(port)); // User specified address or default\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster\r
+// code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()).\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SDL_SBSetDMA(byte channel, global_game_variables_t *gvar)\r
+{\r
+ if (channel > 3)\r
+ Quit(gvar, "SDL_SBSetDMA() - invalid SoundBlaster DMA channel");\r
+\r
+ sbDMA = channel;\r
+ sbDMAa1 = sba1Vals[channel];\r
+ sbDMAa2 = sba2Vals[channel];\r
+ sbDMAa3 = sba3Vals[channel];\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_StartSB() - Turns on the SoundBlaster\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_StartSB(global_game_variables_t *gvar)\r
+{\r
+ byte timevalue,test;\r
+\r
+ sbIntVec = sbIntVectors[sbInterrupt];\r
+ if (sbIntVec < 0)\r
+ Quit(gvar, "SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");\r
+\r
+ sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler\r
+ setvect(sbIntVec,SDL_SBService); // Set mine\r
+\r
+ sbWriteDelay();\r
+ sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker\r
+\r
+ // Set the SoundBlaster DAC time constant for 7KHz\r
+ timevalue = 256 - (1000000 / 7000);\r
+ sbWriteDelay();\r
+ sbOut(sbWriteCmd,0x40);\r
+ sbWriteDelay();\r
+ sbOut(sbWriteData,timevalue);\r
+\r
+ SBProPresent = false;\r
+ if (sbNoProCheck)\r
+ return;\r
+\r
+ // Check to see if this is a SB Pro\r
+ sbOut(sbpMixerAddr,sbpmFMVol);\r
+ sbpOldFMMix = sbIn(sbpMixerData);\r
+ sbOut(sbpMixerData,0xbb);\r
+ test = sbIn(sbpMixerData);\r
+ if (test == 0xbb)\r
+ {\r
+ // Boost FM output levels to be equivilent with digitized output\r
+ sbOut(sbpMixerData,0xff);\r
+ test = sbIn(sbpMixerData);\r
+ if (test == 0xff)\r
+ {\r
+ SBProPresent = true;\r
+\r
+ // Save old Voice output levels (SB Pro)\r
+ sbOut(sbpMixerAddr,sbpmVoiceVol);\r
+ sbpOldVOCMix = sbIn(sbpMixerData);\r
+\r
+ // Turn SB Pro stereo DAC off\r
+ sbOut(sbpMixerAddr,sbpmControl);\r
+ sbOut(sbpMixerData,0); // 0=off,2=on\r
+ }\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_ShutSB() - Turns off the SoundBlaster\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_ShutSB(void)\r
+{\r
+ SDL_SBStopSample();\r
+\r
+ if (SBProPresent)\r
+ {\r
+ // Restore FM output levels (SB Pro)\r
+ sbOut(sbpMixerAddr,sbpmFMVol);\r
+ sbOut(sbpMixerData,sbpOldFMMix);\r
+\r
+ // Restore Voice output levels (SB Pro)\r
+ sbOut(sbpMixerAddr,sbpmVoiceVol);\r
+ sbOut(sbpMixerData,sbpOldVOCMix);\r
+ }\r
+\r
+ setvect(sbIntVec,sbOldIntHand); // Set vector back\r
+}\r
+//++#endif\r
+\r
+\r
+\r
+\r
+\r
+// Sound Source Code\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SSStopSample() - Stops a sample playing on the Sound Source\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_SSStopSample(void)\r
+{\r
+asm pushf\r
+asm cli\r
+\r
+ /*(long)*/ssSample = 0;\r
+\r
+asm popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SSService() - Handles playing the next sample on the Sound Source\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_SSService(void)\r
+{\r
+ //boolean gotit;\r
+ boolean doneflag=false;\r
+ byte v;\r
+\r
+ while (ssSample)\r
+ {\r
+ __asm {\r
+ mov dx,[ssStatus] // Check to see if FIFO is currently empty\r
+ in al,dx\r
+ test al,0x40\r
+ jnz done // Nope - don't push any more data out\r
+ jmp end\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+ done:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov doneflag,1\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+ end:\r
+#ifdef __WATCOMC__\r
+ }\r
+#endif\r
+ if(!doneflag)\r
+ {\r
+ v = *ssSample++;\r
+ if (!(--ssLengthLeft))\r
+ {\r
+ /*(long)*/ssSample = 0;\r
+ SDL_DigitizedDone();\r
+ }\r
+\r
+ __asm {\r
+ mov dx,[ssData] // Pump the value out\r
+ mov al,[v]\r
+ out dx,al\r
+\r
+ mov dx,[ssControl] // Pulse printer select\r
+ mov al,[ssOff]\r
+ out dx,al\r
+ push ax\r
+ pop ax\r
+ mov al,[ssOn]\r
+ out dx,al\r
+\r
+ push ax // Delay a short while\r
+ pop ax\r
+ push ax\r
+ pop ax\r
+done:;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_SSPlaySample() - Plays the specified sample on the Sound Source\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_SSPlaySample(byte huge *data,dword len)\r
+{\r
+asm pushf\r
+asm cli\r
+\r
+ ssLengthLeft = len;\r
+ ssSample = (volatile byte far *)data;\r
+\r
+asm popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_StartSS() - Sets up for and turns on the Sound Source\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_StartSS(void)\r
+{\r
+ if (ssPort == 3)\r
+ ssControl = 0x27a; // If using LPT3\r
+ else if (ssPort == 2)\r
+ ssControl = 0x37a; // If using LPT2\r
+ else\r
+ ssControl = 0x3be; // If using LPT1\r
+ ssStatus = ssControl - 1;\r
+ ssData = ssStatus - 1;\r
+\r
+ ssOn = 0x04;\r
+ if (ssIsTandy)\r
+ ssOff = 0x0e; // Tandy wierdness\r
+ else\r
+ ssOff = 0x0c; // For normal machines\r
+\r
+ outportb(ssControl,ssOn); // Enable SS\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_ShutSS() - Turns off the Sound Source\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_ShutSS(void)\r
+{\r
+ outportb(ssControl,ssOff);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// SDL_CheckSS() - Checks to see if a Sound Source is present at the\r
+// location specified by the sound source variables\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+SDL_CheckSS(void)\r
+{\r
+ boolean present = false, chkdone=0;\r
+ dword lasttime;\r
+\r
+ // Turn the Sound Source on and wait awhile (4 ticks)\r
+ SDL_StartSS();\r
+\r
+ lasttime = TimeCount;\r
+ while (TimeCount < lasttime + 4)\r
+ {}\r
+\r
+ __asm {\r
+ mov dx,[ssStatus] // Check to see if FIFO is currently empty\r
+ in al,dx\r
+ test al,0x40\r
+ jnz checkdone // Nope - Sound Source not here\r
+\r
+ mov cx,32 // Force FIFO overflow (FIFO is 16 bytes)\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+outloop:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov dx,[ssData] // Pump a neutral value out\r
+ mov al,0x80\r
+ out dx,al\r
+\r
+ mov dx,[ssControl] // Pulse printer select\r
+ mov al,[ssOff]\r
+ out dx,al\r
+ push ax\r
+ pop ax\r
+ mov al,[ssOn]\r
+ out dx,al\r
+\r
+ push ax // Delay a short while before we do this again\r
+ pop ax\r
+ push ax\r
+ pop ax\r
+\r
+ loop outloop\r
+\r
+ mov dx,[ssStatus] // Is FIFO overflowed now?\r
+ in al,dx\r
+ test al,0x40\r
+ jz checkdone // Nope, still not - Sound Source not here\r
+ jmp end\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+checkdone:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov chkdone,1\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+ end:\r
+#ifdef __WATCOMC__\r
+ }\r
+#endif\r
+\r
+ if(!chkdone) present = true; // Yes - it's here!\r
+\r
+//checkdone:\r
+ SDL_ShutSS();\r
+ return(present);\r
+}\r
+\r
+static boolean\r
+SDL_DetectSoundSource(void)\r
+{\r
+ for (ssPort = 1;ssPort <= 3;ssPort++)\r
+ if (SDL_CheckSS())\r
+ return(true);\r
+ return(false);\r
+}\r