]> 4ch.mooo.com Git - 16.git/commitdiff
ok.... damn....
authorsparky4 <sparky4@cock.li>
Wed, 15 Jul 2015 12:36:31 +0000 (07:36 -0500)
committersparky4 <sparky4@cock.li>
Wed, 15 Jul 2015 12:36:31 +0000 (07:36 -0500)
new file:   16/ID_SD.C
new file:   16/ID_SD.EQU
new file:   16/ID_SD.H
new file:   16/ID_SD_A.ASM
new file:   16/ID_SD_A.BAK

16/ID_SD.C [new file with mode: 0644]
16/ID_SD.EQU [new file with mode: 0644]
16/ID_SD.H [new file with mode: 0644]
16/ID_SD_A.ASM [new file with mode: 0644]
16/ID_SD_A.BAK [new file with mode: 0644]

diff --git a/16/ID_SD.C b/16/ID_SD.C
new file mode 100644 (file)
index 0000000..60136b7
--- /dev/null
@@ -0,0 +1,2367 @@
+//\r
+//     ID Engine\r
+//     ID_SD.c - Sound Manager for Wolfenstein 3D\r
+//     v1.2\r
+//     By Jason Blochowiak\r
+//\r
+\r
+//\r
+//     This module handles dealing with generating sound on the appropriate\r
+//             hardware\r
+//\r
+//     Depends on: User Mgr (for parm checking)\r
+//\r
+//     Globals:\r
+//             For User Mgr:\r
+//                     SoundSourcePresent - Sound Source thingie present?\r
+//                     SoundBlasterPresent - SoundBlaster card present?\r
+//                     AdLibPresent - AdLib card present?\r
+//                     SoundMode - What device is used for sound effects\r
+//                             (Use SM_SetSoundMode() to set)\r
+//                     MusicMode - What device is used for music\r
+//                             (Use SM_SetMusicMode() to set)\r
+//                     DigiMode - What device is used for digitized sound effects\r
+//                             (Use SM_SetDigiDevice() to set)\r
+//\r
+//             For Cache Mgr:\r
+//                     NeedsDigitized - load digitized sounds?\r
+//                     NeedsMusic - load music?\r
+//\r
+\r
+#pragma hdrstop                // Wierdo thing with MUSE\r
+\r
+#include <dos.h>\r
+\r
+#ifdef _MUSE_      // Will be defined in ID_Types.h\r
+#include "ID_SD.h"\r
+#else\r
+#include "ID_HEADS.H"\r
+#endif\r
+#pragma        hdrstop\r
+#pragma        warn    -pia\r
+\r
+#ifdef nil\r
+#undef nil\r
+#endif\r
+#define        nil     0\r
+\r
+#define        SDL_SoundFinished()     {SoundNumber = SoundPriority = 0;}\r
+\r
+// 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
+// Macros for AdLib stuff\r
+#define        selreg(n)       outportb(alFMAddr,n)\r
+#define        writereg(n)     outportb(alFMData,n)\r
+#define        readstat()      inportb(alFMStatus)\r
+\r
+//     Imports from ID_SD_A.ASM\r
+extern void                    SDL_SetDS(void),\r
+                                               SDL_IndicatePC(boolean on);\r
+extern void interrupt  SDL_t0ExtremeAsmService(void),\r
+                                               SDL_t0FastAsmService(void),\r
+                                               SDL_t0SlowAsmService(void);\r
+\r
+//     Global variables\r
+       boolean         SoundSourcePresent,\r
+                               AdLibPresent,\r
+                               SoundBlasterPresent,SBProPresent,\r
+                               NeedsDigitized,NeedsMusic,\r
+                               SoundPositioned;\r
+       SDMode          SoundMode;\r
+       SMMode          MusicMode;\r
+       SDSMode         DigiMode;\r
+       longword        TimeCount;\r
+       word            HackCount;\r
+       word            *SoundTable;    // Really * _seg *SoundTable, but that don't work\r
+       boolean         ssIsTandy;\r
+       word            ssPort = 2;\r
+       int                     DigiMap[LASTSOUND];\r
+\r
+//     Internal variables\r
+static boolean                 SD_Started;\r
+               boolean                 nextsoundpos;\r
+               longword                TimerDivisor,TimerCount;\r
+static char                    *ParmStrings[] =\r
+                                               {\r
+                                                       "noal",\r
+                                                       "nosb",\r
+                                                       "nopro",\r
+                                                       "noss",\r
+                                                       "sst",\r
+                                                       "ss1",\r
+                                                       "ss2",\r
+                                                       "ss3",\r
+                                                       nil\r
+                                               };\r
+static void                    (*SoundUserHook)(void);\r
+               soundnames              SoundNumber,DigiNumber;\r
+               word                    SoundPriority,DigiPriority;\r
+               int                             LeftPosition,RightPosition;\r
+               void interrupt  (*t0OldService)(void);\r
+               long                    LocalTime;\r
+               word                    TimerRate;\r
+\r
+               word                    NumDigi,DigiLeft,DigiPage;\r
+               word                    _seg *DigiList;\r
+               word                    DigiLastStart,DigiLastEnd;\r
+               boolean                 DigiPlaying;\r
+static boolean                 DigiMissed,DigiLastSegment;\r
+static memptr                  DigiNextAddr;\r
+static word                    DigiNextLen;\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 longword               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 longword       ssLengthLeft;\r
+\r
+//     PC Sound variables\r
+               volatile byte   pcLastSample,far *pcSound;\r
+               longword                pcLengthLeft;\r
+               word                    pcSoundLookup[255];\r
+\r
+//     AdLib variables\r
+               boolean                 alNoCheck;\r
+               byte                    far *alSound;\r
+               word                    alBlock;\r
+               longword                alLengthLeft;\r
+               longword                alTimeCount;\r
+               Instrument              alZeroInst;\r
+\r
+// This table maps channel numbers to carrier and modulator op cells\r
+static byte                    carriers[9] =  { 3, 4, 5,11,12,13,19,20,21},\r
+                                               modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},\r
+// This table maps percussive voice numbers to op cells\r
+                                               pcarriers[5] = {19,0xff,0xff,0xff,0xff},\r
+                                               pmodifiers[5] = {16,17,18,20,21};\r
+\r
+//     Sequencer variables\r
+               boolean                 sqActive;\r
+static word                    alFXReg;\r
+static ActiveTrack             *tracks[sqMaxTracks],\r
+                                               mytracks[sqMaxTracks];\r
+static word                    sqMode,sqFadeStep;\r
+               word                    far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;\r
+               long                    sqHackTime;\r
+\r
+//     Internal routines\r
+               void                    SDL_DigitizedDone(void);\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_SetTimer0() - Sets system timer 0 to the specified speed\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#pragma        argsused\r
+static void\r
+SDL_SetTimer0(word speed)\r
+{\r
+#ifndef TPROF  // If using Borland's profiling, don't screw with the timer\r
+asm    pushf\r
+asm    cli\r
+\r
+       outportb(0x43,0x36);                            // Change timer 0\r
+       outportb(0x40,speed);\r
+       outportb(0x40,speed >> 8);\r
+       // Kludge to handle special case for digitized PC sounds\r
+       if (TimerDivisor == (1192030 / (TickBase * 100)))\r
+               TimerDivisor = (1192030 / (TickBase * 10));\r
+       else\r
+               TimerDivisor = speed;\r
+\r
+asm    popf\r
+#else\r
+       TimerDivisor = 0x10000;\r
+#endif\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of\r
+//             interrupts generated by system timer 0 per second\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_SetIntsPerSec(word ints)\r
+{\r
+       TimerRate = ints;\r
+       SDL_SetTimer0(1192030 / ints);\r
+}\r
+\r
+static void\r
+SDL_SetTimerSpeed(void)\r
+{\r
+       word    rate;\r
+       void interrupt  (*isr)(void);\r
+\r
+       if ((DigiMode == sds_PC) && DigiPlaying)\r
+       {\r
+               rate = TickBase * 100;\r
+               isr = SDL_t0ExtremeAsmService;\r
+       }\r
+       else if\r
+       (\r
+               (MusicMode == smm_AdLib)\r
+       ||      ((DigiMode == sds_SoundSource) && DigiPlaying)\r
+       )\r
+       {\r
+               rate = TickBase * 10;\r
+               isr = SDL_t0FastAsmService;\r
+       }\r
+       else\r
+       {\r
+               rate = TickBase * 2;\r
+               isr = SDL_t0SlowAsmService;\r
+       }\r
+\r
+       if (rate != TimerRate)\r
+       {\r
+               setvect(8,isr);\r
+               SDL_SetIntsPerSec(rate);\r
+               TimerRate = rate;\r
+       }\r
+}\r
+\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 longword\r
+SDL_SBPlaySeg(volatile byte huge *data,longword length)\r
+{\r
+       unsigned                datapage;\r
+       longword                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
+       longword        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,longword len)\r
+{\r
+       longword        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
+usecloop:\r
+asm    in      al,dx\r
+asm    loop usecloop\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)\r
+{\r
+       if (channel > 3)\r
+               Quit("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(void)\r
+{\r
+       byte    timevalue,test;\r
+\r
+       sbIntVec = sbIntVectors[sbInterrupt];\r
+       if (sbIntVec < 0)\r
+               Quit("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
+\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
+       byte    v;\r
+\r
+       while (ssSample)\r
+       {\r
+       asm     mov             dx,[ssStatus]   // Check to see if FIFO is currently empty\r
+       asm     in              al,dx\r
+       asm     test    al,0x40\r
+       asm     jnz             done                    // Nope - don't push any more data out\r
+\r
+               v = *ssSample++;\r
+               if (!(--ssLengthLeft))\r
+               {\r
+                       (long)ssSample = 0;\r
+                       SDL_DigitizedDone();\r
+               }\r
+\r
+       asm     mov             dx,[ssData]             // Pump the value out\r
+       asm     mov             al,[v]\r
+       asm     out             dx,al\r
+\r
+       asm     mov             dx,[ssControl]  // Pulse printer select\r
+       asm     mov             al,[ssOff]\r
+       asm     out             dx,al\r
+       asm     push    ax\r
+       asm     pop             ax\r
+       asm     mov             al,[ssOn]\r
+       asm     out             dx,al\r
+\r
+       asm     push    ax                              // Delay a short while\r
+       asm     pop             ax\r
+       asm     push    ax\r
+       asm     pop             ax\r
+       }\r
+done:;\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,longword 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;\r
+       longword        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    mov             dx,[ssStatus]   // Check to see if FIFO is currently empty\r
+asm    in              al,dx\r
+asm    test    al,0x40\r
+asm    jnz             checkdone               // Nope - Sound Source not here\r
+\r
+asm    mov             cx,32                   // Force FIFO overflow (FIFO is 16 bytes)\r
+outloop:\r
+asm    mov             dx,[ssData]             // Pump a neutral value out\r
+asm    mov             al,0x80\r
+asm    out             dx,al\r
+\r
+asm    mov             dx,[ssControl]  // Pulse printer select\r
+asm    mov             al,[ssOff]\r
+asm    out             dx,al\r
+asm    push    ax\r
+asm    pop             ax\r
+asm    mov             al,[ssOn]\r
+asm    out             dx,al\r
+\r
+asm    push    ax                              // Delay a short while before we do this again\r
+asm    pop             ax\r
+asm    push    ax\r
+asm    pop             ax\r
+\r
+asm    loop    outloop\r
+\r
+asm    mov             dx,[ssStatus]   // Is FIFO overflowed now?\r
+asm    in              al,dx\r
+asm    test    al,0x40\r
+asm    jz              checkdone               // Nope, still not - Sound Source not here\r
+\r
+       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
+\r
+//\r
+//     PC Sound code\r
+//\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_PCPlaySample() - Plays the specified sample on the PC speaker\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_PCPlaySample(byte huge *data,longword len)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+       SDL_IndicatePC(true);\r
+\r
+       pcLengthLeft = len;\r
+       pcSound = (volatile byte far *)data;\r
+\r
+asm    popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_PCStopSample() - Stops a sample playing on the PC speaker\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_PCStopSample(void)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+       (long)pcSound = 0;\r
+\r
+       SDL_IndicatePC(false);\r
+\r
+asm    in      al,0x61                 // Turn the speaker off\r
+asm    and     al,0xfd                 // ~2\r
+asm    out     0x61,al\r
+\r
+asm    popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_PCPlaySound() - Plays the specified sound on the PC speaker\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_PCPlaySound(PCSound far *sound)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+       pcLastSample = -1;\r
+       pcLengthLeft = sound->common.length;\r
+       pcSound = sound->data;\r
+\r
+asm    popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_PCStopSound() - Stops the current sound playing on the PC Speaker\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_PCStopSound(void)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+       (long)pcSound = 0;\r
+\r
+asm    in      al,0x61                 // Turn the speaker off\r
+asm    and     al,0xfd                 // ~2\r
+asm    out     0x61,al\r
+\r
+asm    popf\r
+}\r
+\r
+#if 0\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_PCService() - Handles playing the next sample in a PC sound\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_PCService(void)\r
+{\r
+       byte    s;\r
+       word    t;\r
+\r
+       if (pcSound)\r
+       {\r
+               s = *pcSound++;\r
+               if (s != pcLastSample)\r
+               {\r
+               asm     pushf\r
+               asm     cli\r
+\r
+                       pcLastSample = s;\r
+                       if (s)                                  // We have a frequency!\r
+                       {\r
+                               t = pcSoundLookup[s];\r
+                       asm     mov     bx,[t]\r
+\r
+                       asm     mov     al,0xb6                 // Write to channel 2 (speaker) timer\r
+                       asm     out     43h,al\r
+                       asm     mov     al,bl\r
+                       asm     out     42h,al                  // Low byte\r
+                       asm     mov     al,bh\r
+                       asm     out     42h,al                  // High byte\r
+\r
+                       asm     in      al,0x61                 // Turn the speaker & gate on\r
+                       asm     or      al,3\r
+                       asm     out     0x61,al\r
+                       }\r
+                       else                                    // Time for some silence\r
+                       {\r
+                       asm     in      al,0x61                 // Turn the speaker & gate off\r
+                       asm     and     al,0xfc                 // ~3\r
+                       asm     out     0x61,al\r
+                       }\r
+\r
+               asm     popf\r
+               }\r
+\r
+               if (!(--pcLengthLeft))\r
+               {\r
+                       SDL_PCStopSound();\r
+                       SDL_SoundFinished();\r
+               }\r
+       }\r
+}\r
+#endif\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_ShutPC() - Turns off the pc speaker\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_ShutPC(void)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+       pcSound = 0;\r
+\r
+asm    in      al,0x61                 // Turn the speaker & gate off\r
+asm    and     al,0xfc                 // ~3\r
+asm    out     0x61,al\r
+\r
+asm    popf\r
+}\r
+\r
+//\r
+//     Stuff for digitized sounds\r
+//\r
+memptr\r
+SDL_LoadDigiSegment(word page)\r
+{\r
+       memptr  addr;\r
+\r
+#if 0  // for debugging\r
+asm    mov     dx,STATUS_REGISTER_1\r
+asm    in      al,dx\r
+asm    mov     dx,ATR_INDEX\r
+asm    mov     al,ATR_OVERSCAN\r
+asm    out     dx,al\r
+asm    mov     al,10   // bright green\r
+asm    out     dx,al\r
+#endif\r
+\r
+       addr = PM_GetSoundPage(page);\r
+       PM_SetPageLock(PMSoundStart + page,pml_Locked);\r
+\r
+#if 0  // for debugging\r
+asm    mov     dx,STATUS_REGISTER_1\r
+asm    in      al,dx\r
+asm    mov     dx,ATR_INDEX\r
+asm    mov     al,ATR_OVERSCAN\r
+asm    out     dx,al\r
+asm    mov     al,3    // blue\r
+asm    out     dx,al\r
+asm    mov     al,0x20 // normal\r
+asm    out     dx,al\r
+#endif\r
+\r
+       return(addr);\r
+}\r
+\r
+void\r
+SDL_PlayDigiSegment(memptr addr,word len)\r
+{\r
+       switch (DigiMode)\r
+       {\r
+       case sds_PC:\r
+       SDL_PCPlaySample(addr,len);\r
+               break;\r
+       case sds_SoundSource:\r
+               SDL_SSPlaySample(addr,len);\r
+               break;\r
+       case sds_SoundBlaster:\r
+               SDL_SBPlaySample(addr,len);\r
+               break;\r
+       }\r
+}\r
+\r
+void\r
+SD_StopDigitized(void)\r
+{\r
+       int     i;\r
+\r
+asm    pushf\r
+asm    cli\r
+\r
+       DigiLeft = 0;\r
+       DigiNextAddr = nil;\r
+       DigiNextLen = 0;\r
+       DigiMissed = false;\r
+       DigiPlaying = false;\r
+       DigiNumber = DigiPriority = 0;\r
+       SoundPositioned = false;\r
+       if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
+               SDL_SoundFinished();\r
+\r
+       switch (DigiMode)\r
+       {\r
+       case sds_PC:\r
+               SDL_PCStopSample();\r
+               break;\r
+       case sds_SoundSource:\r
+               SDL_SSStopSample();\r
+               break;\r
+       case sds_SoundBlaster:\r
+               SDL_SBStopSample();\r
+               break;\r
+       }\r
+\r
+asm    popf\r
+\r
+       for (i = DigiLastStart;i < DigiLastEnd;i++)\r
+               PM_SetPageLock(i + PMSoundStart,pml_Unlocked);\r
+       DigiLastStart = 1;\r
+       DigiLastEnd = 0;\r
+}\r
+\r
+void\r
+SD_Poll(void)\r
+{\r
+       if (DigiLeft && !DigiNextAddr)\r
+       {\r
+               DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);\r
+               DigiLeft -= DigiNextLen;\r
+               if (!DigiLeft)\r
+                       DigiLastSegment = true;\r
+               DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);\r
+       }\r
+       if (DigiMissed && DigiNextAddr)\r
+       {\r
+               SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);\r
+               DigiNextAddr = nil;\r
+               DigiMissed = false;\r
+               if (DigiLastSegment)\r
+               {\r
+                       DigiPlaying = false;\r
+                       DigiLastSegment = false;\r
+               }\r
+       }\r
+       SDL_SetTimerSpeed();\r
+}\r
+\r
+void\r
+SD_SetPosition(int leftpos,int rightpos)\r
+{\r
+       if\r
+       (\r
+               (leftpos < 0)\r
+       ||      (leftpos > 15)\r
+       ||      (rightpos < 0)\r
+       ||      (rightpos > 15)\r
+       ||      ((leftpos == 15) && (rightpos == 15))\r
+       )\r
+               Quit("SD_SetPosition: Illegal position");\r
+\r
+       switch (DigiMode)\r
+       {\r
+       case sds_SoundBlaster:\r
+               SDL_PositionSBP(leftpos,rightpos);\r
+               break;\r
+       }\r
+}\r
+\r
+void\r
+SD_PlayDigitized(word which,int leftpos,int rightpos)\r
+{\r
+       word    len;\r
+       memptr  addr;\r
+\r
+       if (!DigiMode)\r
+               return;\r
+\r
+       SD_StopDigitized();\r
+       if (which >= NumDigi)\r
+               Quit("SD_PlayDigitized: bad sound number");\r
+\r
+       SD_SetPosition(leftpos,rightpos);\r
+\r
+       DigiPage = DigiList[(which * 2) + 0];\r
+       DigiLeft = DigiList[(which * 2) + 1];\r
+\r
+       DigiLastStart = DigiPage;\r
+       DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);\r
+\r
+       len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);\r
+       addr = SDL_LoadDigiSegment(DigiPage++);\r
+\r
+       DigiPlaying = true;\r
+       DigiLastSegment = false;\r
+\r
+       SDL_PlayDigiSegment(addr,len);\r
+       DigiLeft -= len;\r
+       if (!DigiLeft)\r
+               DigiLastSegment = true;\r
+\r
+       SD_Poll();\r
+}\r
+\r
+void\r
+SDL_DigitizedDone(void)\r
+{\r
+       if (DigiNextAddr)\r
+       {\r
+               SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);\r
+               DigiNextAddr = nil;\r
+               DigiMissed = false;\r
+       }\r
+       else\r
+       {\r
+               if (DigiLastSegment)\r
+               {\r
+                       DigiPlaying = false;\r
+                       DigiLastSegment = false;\r
+                       if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
+                       {\r
+                               SDL_SoundFinished();\r
+                       }\r
+                       else\r
+                               DigiNumber = DigiPriority = 0;\r
+                       SoundPositioned = false;\r
+               }\r
+               else\r
+                       DigiMissed = true;\r
+       }\r
+}\r
+\r
+void\r
+SD_SetDigiDevice(SDSMode mode)\r
+{\r
+       boolean devicenotpresent;\r
+\r
+       if (mode == DigiMode)\r
+               return;\r
+\r
+       SD_StopDigitized();\r
+\r
+       devicenotpresent = false;\r
+       switch (mode)\r
+       {\r
+       case sds_SoundBlaster:\r
+               if (!SoundBlasterPresent)\r
+               {\r
+                       if (SoundSourcePresent)\r
+                               mode = sds_SoundSource;\r
+                       else\r
+                               devicenotpresent = true;\r
+               }\r
+               break;\r
+       case sds_SoundSource:\r
+               if (!SoundSourcePresent)\r
+                       devicenotpresent = true;\r
+               break;\r
+       }\r
+\r
+       if (!devicenotpresent)\r
+       {\r
+               if (DigiMode == sds_SoundSource)\r
+                       SDL_ShutSS();\r
+\r
+               DigiMode = mode;\r
+\r
+               if (mode == sds_SoundSource)\r
+                       SDL_StartSS();\r
+\r
+               SDL_SetTimerSpeed();\r
+       }\r
+}\r
+\r
+void\r
+SDL_SetupDigi(void)\r
+{\r
+       memptr  list;\r
+       word    far *p,\r
+                       pg;\r
+       int             i;\r
+\r
+       PM_UnlockMainMem();\r
+       MM_GetPtr(&list,PMPageSize);\r
+       PM_CheckMainMem();\r
+       p = (word far *)MK_FP(PM_GetPage(ChunksInFile - 1),0);\r
+       _fmemcpy((void far *)list,(void far *)p,PMPageSize);\r
+       pg = PMSoundStart;\r
+       for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2)\r
+       {\r
+               if (pg >= ChunksInFile - 1)\r
+                       break;\r
+               pg += (p[1] + (PMPageSize - 1)) / PMPageSize;\r
+       }\r
+       PM_UnlockMainMem();\r
+       MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2);\r
+       _fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(word) * 2);\r
+       MM_FreePtr(&list);\r
+       NumDigi = i;\r
+\r
+       for (i = 0;i < LASTSOUND;i++)\r
+               DigiMap[i] = -1;\r
+}\r
+\r
+//     AdLib Code\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     alOut(n,b) - Puts b in AdLib card register n\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+alOut(byte n,byte b)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+asm    mov     dx,0x388\r
+asm    mov     al,[n]\r
+asm    out     dx,al\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    inc     dx\r
+asm    mov     al,[b]\r
+asm    out     dx,al\r
+\r
+asm    popf\r
+\r
+asm    dec     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
+asm    in      al,dx\r
+asm    in      al,dx\r
+\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
+asm    in      al,dx\r
+\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
+asm    in      al,dx\r
+\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
+\r
+#if 0\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_SetInstrument() - Puts an instrument into a generator\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive)\r
+{\r
+       byte            c,m;\r
+\r
+       if (percussive)\r
+       {\r
+               c = pcarriers[which];\r
+               m = pmodifiers[which];\r
+       }\r
+       else\r
+       {\r
+               c = carriers[which];\r
+               m = modifiers[which];\r
+       }\r
+\r
+       tracks[track - 1]->inst = *inst;\r
+       tracks[track - 1]->percussive = percussive;\r
+\r
+       alOut(m + alChar,inst->mChar);\r
+       alOut(m + alScale,inst->mScale);\r
+       alOut(m + alAttack,inst->mAttack);\r
+       alOut(m + alSus,inst->mSus);\r
+       alOut(m + alWave,inst->mWave);\r
+\r
+       // Most percussive instruments only use one cell\r
+       if (c != 0xff)\r
+       {\r
+               alOut(c + alChar,inst->cChar);\r
+               alOut(c + alScale,inst->cScale);\r
+               alOut(c + alAttack,inst->cAttack);\r
+               alOut(c + alSus,inst->cSus);\r
+               alOut(c + alWave,inst->cWave);\r
+       }\r
+\r
+       alOut(which + alFeedCon,inst->nConn);   // DEBUG - I think this is right\r
+}\r
+#endif\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_ALStopSound() - Turns off any sound effects playing through the\r
+//             AdLib card\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_ALStopSound(void)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+       (long)alSound = 0;\r
+       alOut(alFreqH + 0,0);\r
+\r
+asm    popf\r
+}\r
+\r
+static void\r
+SDL_AlSetFXInst(Instrument far *inst)\r
+{\r
+       byte            c,m;\r
+\r
+       m = modifiers[0];\r
+       c = carriers[0];\r
+       alOut(m + alChar,inst->mChar);\r
+       alOut(m + alScale,inst->mScale);\r
+       alOut(m + alAttack,inst->mAttack);\r
+       alOut(m + alSus,inst->mSus);\r
+       alOut(m + alWave,inst->mWave);\r
+       alOut(c + alChar,inst->cChar);\r
+       alOut(c + alScale,inst->cScale);\r
+       alOut(c + alAttack,inst->cAttack);\r
+       alOut(c + alSus,inst->cSus);\r
+       alOut(c + alWave,inst->cWave);\r
+\r
+       // Note: Switch commenting on these lines for old MUSE compatibility\r
+//     alOut(alFeedCon,inst->nConn);\r
+       alOut(alFeedCon,0);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_ALPlaySound() - Plays the specified sound on the AdLib card\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#ifdef _MUSE_\r
+void\r
+#else\r
+static void\r
+#endif\r
+SDL_ALPlaySound(AdLibSound far *sound)\r
+{\r
+       Instrument      far *inst;\r
+       byte            huge *data;\r
+\r
+       SDL_ALStopSound();\r
+\r
+asm    pushf\r
+asm    cli\r
+\r
+       alLengthLeft = sound->common.length;\r
+       data = sound->data;\r
+       data++;\r
+       data--;\r
+       alSound = (byte far *)data;\r
+       alBlock = ((sound->block & 7) << 2) | 0x20;\r
+       inst = &sound->inst;\r
+\r
+       if (!(inst->mSus | inst->cSus))\r
+       {\r
+       asm     popf\r
+               Quit("SDL_ALPlaySound() - Bad instrument");\r
+       }\r
+\r
+       SDL_AlSetFXInst(&alZeroInst);   // DEBUG\r
+       SDL_AlSetFXInst(inst);\r
+\r
+asm    popf\r
+}\r
+\r
+#if 0\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_ALSoundService() - Plays the next sample out through the AdLib card\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+//static void\r
+void\r
+SDL_ALSoundService(void)\r
+{\r
+       byte    s;\r
+\r
+       if (alSound)\r
+       {\r
+               s = *alSound++;\r
+               if (!s)\r
+                       alOut(alFreqH + 0,0);\r
+               else\r
+               {\r
+                       alOut(alFreqL + 0,s);\r
+                       alOut(alFreqH + 0,alBlock);\r
+               }\r
+\r
+               if (!(--alLengthLeft))\r
+               {\r
+                       (long)alSound = 0;\r
+                       alOut(alFreqH + 0,0);\r
+                       SDL_SoundFinished();\r
+               }\r
+       }\r
+}\r
+#endif\r
+\r
+#if 0\r
+void\r
+SDL_ALService(void)\r
+{\r
+       byte    a,v;\r
+       word    w;\r
+\r
+       if (!sqActive)\r
+               return;\r
+\r
+       while (sqHackLen && (sqHackTime <= alTimeCount))\r
+       {\r
+               w = *sqHackPtr++;\r
+               sqHackTime = alTimeCount + *sqHackPtr++;\r
+       asm     mov     dx,[w]\r
+       asm     mov     [a],dl\r
+       asm     mov     [v],dh\r
+               alOut(a,v);\r
+               sqHackLen -= 4;\r
+       }\r
+       alTimeCount++;\r
+       if (!sqHackLen)\r
+       {\r
+               sqHackPtr = (word far *)sqHack;\r
+               sqHackLen = sqHackSeqLen;\r
+               alTimeCount = sqHackTime = 0;\r
+       }\r
+}\r
+#endif\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_ShutAL() - Shuts down the AdLib card for sound effects\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_ShutAL(void)\r
+{\r
+asm    pushf\r
+asm    cli\r
+\r
+       alOut(alEffects,0);\r
+       alOut(alFreqH + 0,0);\r
+       SDL_AlSetFXInst(&alZeroInst);\r
+       alSound = 0;\r
+\r
+asm    popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_CleanAL() - Totally shuts down the AdLib card\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_CleanAL(void)\r
+{\r
+       int     i;\r
+\r
+asm    pushf\r
+asm    cli\r
+\r
+       alOut(alEffects,0);\r
+       for (i = 1;i < 0xf5;i++)\r
+               alOut(i,0);\r
+\r
+asm    popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_StartAL() - Starts up the AdLib card for sound effects\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_StartAL(void)\r
+{\r
+       alFXReg = 0;\r
+       alOut(alEffects,alFXReg);\r
+       SDL_AlSetFXInst(&alZeroInst);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster\r
+//             emulating an AdLib) present\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+SDL_DetectAdLib(void)\r
+{\r
+       byte    status1,status2;\r
+       int             i;\r
+\r
+       alOut(4,0x60);  // Reset T1 & T2\r
+       alOut(4,0x80);  // Reset IRQ\r
+       status1 = readstat();\r
+       alOut(2,0xff);  // Set timer 1\r
+       alOut(4,0x21);  // Start timer 1\r
+#if 0\r
+       SDL_Delay(TimerDelay100);\r
+#else\r
+asm    mov     dx,0x388\r
+asm    mov     cx,100\r
+usecloop:\r
+asm    in      al,dx\r
+asm    loop usecloop\r
+#endif\r
+\r
+       status2 = readstat();\r
+       alOut(4,0x60);\r
+       alOut(4,0x80);\r
+\r
+       if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))\r
+       {\r
+               for (i = 1;i <= 0xf5;i++)       // Zero all the registers\r
+                       alOut(i,0);\r
+\r
+               alOut(1,0x20);  // Set WSE=1\r
+               alOut(8,0);             // Set CSM=0 & SEL=0\r
+\r
+               return(true);\r
+       }\r
+       else\r
+               return(false);\r
+}\r
+\r
+#if 0\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_t0Service() - My timer 0 ISR which handles the different timings and\r
+//             dispatches to whatever other routines are appropriate\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void interrupt\r
+SDL_t0Service(void)\r
+{\r
+static word    count = 1;\r
+\r
+#if 1  // for debugging\r
+asm    mov     dx,STATUS_REGISTER_1\r
+asm    in      al,dx\r
+asm    mov     dx,ATR_INDEX\r
+asm    mov     al,ATR_OVERSCAN\r
+asm    out     dx,al\r
+asm    mov     al,4    // red\r
+asm    out     dx,al\r
+#endif\r
+\r
+       HackCount++;\r
+\r
+       if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))\r
+       {\r
+               SDL_ALService();\r
+               SDL_SSService();\r
+//             if (!(++count & 7))\r
+               if (!(++count % 10))\r
+               {\r
+                       LocalTime++;\r
+                       TimeCount++;\r
+                       if (SoundUserHook)\r
+                               SoundUserHook();\r
+               }\r
+//             if (!(count & 3))\r
+               if (!(count % 5))\r
+               {\r
+                       switch (SoundMode)\r
+                       {\r
+                       case sdm_PC:\r
+                               SDL_PCService();\r
+                               break;\r
+                       case sdm_AdLib:\r
+                               SDL_ALSoundService();\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (!(++count & 1))\r
+               {\r
+                       LocalTime++;\r
+                       TimeCount++;\r
+                       if (SoundUserHook)\r
+                               SoundUserHook();\r
+               }\r
+               switch (SoundMode)\r
+               {\r
+               case sdm_PC:\r
+                       SDL_PCService();\r
+                       break;\r
+               case sdm_AdLib:\r
+                       SDL_ALSoundService();\r
+                       break;\r
+               }\r
+       }\r
+\r
+asm    mov     ax,[WORD PTR TimerCount]\r
+asm    add     ax,[WORD PTR TimerDivisor]\r
+asm    mov     [WORD PTR TimerCount],ax\r
+asm    jnc     myack\r
+       t0OldService();                 // If we overflow a word, time to call old int handler\r
+asm    jmp     olddone\r
+myack:;\r
+       outportb(0x20,0x20);    // Ack the interrupt\r
+olddone:;\r
+\r
+#if 1  // for debugging\r
+asm    mov     dx,STATUS_REGISTER_1\r
+asm    in      al,dx\r
+asm    mov     dx,ATR_INDEX\r
+asm    mov     al,ATR_OVERSCAN\r
+asm    out     dx,al\r
+asm    mov     al,3    // blue\r
+asm    out     dx,al\r
+asm    mov     al,0x20 // normal\r
+asm    out     dx,al\r
+#endif\r
+}\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_ShutDevice() - turns off whatever device was being used for sound fx\r
+//\r
+////////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_ShutDevice(void)\r
+{\r
+       switch (SoundMode)\r
+       {\r
+       case sdm_PC:\r
+               SDL_ShutPC();\r
+               break;\r
+       case sdm_AdLib:\r
+               SDL_ShutAL();\r
+               break;\r
+       }\r
+       SoundMode = sdm_Off;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_CleanDevice() - totally shuts down all sound devices\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_CleanDevice(void)\r
+{\r
+       if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))\r
+               SDL_CleanAL();\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_StartDevice() - turns on whatever device is to be used for sound fx\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_StartDevice(void)\r
+{\r
+       switch (SoundMode)\r
+       {\r
+       case sdm_AdLib:\r
+               SDL_StartAL();\r
+               break;\r
+       }\r
+       SoundNumber = SoundPriority = 0;\r
+}\r
+\r
+//     Public routines\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_SetSoundMode() - Sets which sound hardware to use for sound effects\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+boolean\r
+SD_SetSoundMode(SDMode mode)\r
+{\r
+       boolean result = false;\r
+       word    tableoffset;\r
+\r
+       SD_StopSound();\r
+\r
+#ifndef        _MUSE_\r
+       if ((mode == sdm_AdLib) && !AdLibPresent)\r
+               mode = sdm_PC;\r
+\r
+       switch (mode)\r
+       {\r
+       case sdm_Off:\r
+               NeedsDigitized = false;\r
+               result = true;\r
+               break;\r
+       case sdm_PC:\r
+               tableoffset = STARTPCSOUNDS;\r
+               NeedsDigitized = false;\r
+               result = true;\r
+               break;\r
+       case sdm_AdLib:\r
+               if (AdLibPresent)\r
+               {\r
+                       tableoffset = STARTADLIBSOUNDS;\r
+                       NeedsDigitized = false;\r
+                       result = true;\r
+               }\r
+               break;\r
+       }\r
+#else\r
+       result = true;\r
+#endif\r
+\r
+       if (result && (mode != SoundMode))\r
+       {\r
+               SDL_ShutDevice();\r
+               SoundMode = mode;\r
+#ifndef        _MUSE_\r
+               SoundTable = (word *)(&audiosegs[tableoffset]);\r
+#endif\r
+               SDL_StartDevice();\r
+       }\r
+\r
+       SDL_SetTimerSpeed();\r
+\r
+       return(result);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_SetMusicMode() - sets the device to use for background music\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+boolean\r
+SD_SetMusicMode(SMMode mode)\r
+{\r
+       boolean result = false;\r
+\r
+       SD_FadeOutMusic();\r
+       while (SD_MusicPlaying())\r
+               ;\r
+\r
+       switch (mode)\r
+       {\r
+       case smm_Off:\r
+               NeedsMusic = false;\r
+               result = true;\r
+               break;\r
+       case smm_AdLib:\r
+               if (AdLibPresent)\r
+               {\r
+                       NeedsMusic = true;\r
+                       result = true;\r
+               }\r
+               break;\r
+       }\r
+\r
+       if (result)\r
+               MusicMode = mode;\r
+\r
+       SDL_SetTimerSpeed();\r
+\r
+       return(result);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_Startup() - starts up the Sound Mgr\r
+//             Detects all additional sound hardware and installs my ISR\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_Startup(void)\r
+{\r
+       int     i;\r
+\r
+       if (SD_Started)\r
+               return;\r
+\r
+       SDL_SetDS();\r
+\r
+       ssIsTandy = false;\r
+       ssNoCheck = false;\r
+       alNoCheck = false;\r
+       sbNoCheck = false;\r
+       sbNoProCheck = false;\r
+#ifndef        _MUSE_\r
+       for (i = 1;i < _argc;i++)\r
+       {\r
+               switch (US_CheckParm(_argv[i],ParmStrings))\r
+               {\r
+               case 0:                                         // No AdLib detection\r
+                       alNoCheck = true;\r
+                       break;\r
+               case 1:                                         // No SoundBlaster detection\r
+                       sbNoCheck = true;\r
+                       break;\r
+               case 2:                                         // No SoundBlaster Pro detection\r
+                       sbNoProCheck = true;\r
+                       break;\r
+               case 3:\r
+                       ssNoCheck = true;               // No Sound Source detection\r
+                       break;\r
+               case 4:                                         // Tandy Sound Source handling\r
+                       ssIsTandy = true;\r
+                       break;\r
+               case 5:                                         // Sound Source present at LPT1\r
+                       ssPort = 1;\r
+                       ssNoCheck = SoundSourcePresent = true;\r
+                       break;\r
+               case 6:                     // Sound Source present at LPT2\r
+                       ssPort = 2;\r
+                       ssNoCheck = SoundSourcePresent = true;\r
+                       break;\r
+               case 7:                     // Sound Source present at LPT3\r
+                       ssPort = 3;\r
+                       ssNoCheck = SoundSourcePresent = true;\r
+                       break;\r
+               }\r
+       }\r
+#endif\r
+\r
+       SoundUserHook = 0;\r
+\r
+       t0OldService = getvect(8);      // Get old timer 0 ISR\r
+\r
+       LocalTime = TimeCount = alTimeCount = 0;\r
+\r
+       SD_SetSoundMode(sdm_Off);\r
+       SD_SetMusicMode(smm_Off);\r
+\r
+       if (!ssNoCheck)\r
+               SoundSourcePresent = SDL_DetectSoundSource();\r
+\r
+       if (!alNoCheck)\r
+       {\r
+               AdLibPresent = SDL_DetectAdLib();\r
+               if (AdLibPresent && !sbNoCheck)\r
+               {\r
+                       int port = -1;\r
+                       char *env = getenv("BLASTER");\r
+                       if (env)\r
+                       {\r
+                               long temp;\r
+                               while (*env)\r
+                               {\r
+                                       while (isspace(*env))\r
+                                               env++;\r
+\r
+                                       switch (toupper(*env))\r
+                                       {\r
+                                       case 'A':\r
+                                               temp = strtol(env + 1,&env,16);\r
+                                               if\r
+                                               (\r
+                                                       (temp >= 0x210)\r
+                                               &&      (temp <= 0x260)\r
+                                               &&      (!(temp & 0x00f))\r
+                                               )\r
+                                                       port = (temp - 0x200) >> 4;\r
+                                               else\r
+                                                       Quit("SD_Startup: Unsupported address value in BLASTER");\r
+                                               break;\r
+                                       case 'I':\r
+                                               temp = strtol(env + 1,&env,10);\r
+                                               if\r
+                                               (\r
+                                                       (temp >= 0)\r
+                                               &&      (temp <= 10)\r
+                                               &&      (sbIntVectors[temp] != -1)\r
+                                               )\r
+                                               {\r
+                                                       sbInterrupt = temp;\r
+                                                       sbIntVec = sbIntVectors[sbInterrupt];\r
+                                               }\r
+                                               else\r
+                                                       Quit("SD_Startup: Unsupported interrupt value in BLASTER");\r
+                                               break;\r
+                                       case 'D':\r
+                                               temp = strtol(env + 1,&env,10);\r
+                                               if ((temp == 0) || (temp == 1) || (temp == 3))\r
+                                                       SDL_SBSetDMA(temp);\r
+                                               else\r
+                                                       Quit("SD_Startup: Unsupported DMA value in BLASTER");\r
+                                               break;\r
+                                       default:\r
+                                               while (isspace(*env))\r
+                                                       env++;\r
+                                               while (*env && !isspace(*env))\r
+                                                       env++;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+                       SoundBlasterPresent = SDL_DetectSoundBlaster(port);\r
+               }\r
+       }\r
+\r
+       for (i = 0;i < 255;i++)\r
+               pcSoundLookup[i] = i * 60;\r
+\r
+       if (SoundBlasterPresent)\r
+               SDL_StartSB();\r
+\r
+       SDL_SetupDigi();\r
+\r
+       SD_Started = true;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_Default() - Sets up the default behaviour for the Sound Mgr whether\r
+//             the config file was present or not.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_Default(boolean gotit,SDMode sd,SMMode sm)\r
+{\r
+       boolean gotsd,gotsm;\r
+\r
+       gotsd = gotsm = gotit;\r
+\r
+       if (gotsd)      // Make sure requested sound hardware is available\r
+       {\r
+               switch (sd)\r
+               {\r
+               case sdm_AdLib:\r
+                       gotsd = AdLibPresent;\r
+                       break;\r
+               }\r
+       }\r
+       if (!gotsd)\r
+       {\r
+               if (AdLibPresent)\r
+                       sd = sdm_AdLib;\r
+               else\r
+                       sd = sdm_PC;\r
+       }\r
+       if (sd != SoundMode)\r
+               SD_SetSoundMode(sd);\r
+\r
+\r
+       if (gotsm)      // Make sure requested music hardware is available\r
+       {\r
+               switch (sm)\r
+               {\r
+               case sdm_AdLib:\r
+                       gotsm = AdLibPresent;\r
+                       break;\r
+               }\r
+       }\r
+       if (!gotsm)\r
+       {\r
+               if (AdLibPresent)\r
+                       sm = smm_AdLib;\r
+       }\r
+       if (sm != MusicMode)\r
+               SD_SetMusicMode(sm);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_Shutdown() - shuts down the Sound Mgr\r
+//             Removes sound ISR and turns off whatever sound hardware was active\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_Shutdown(void)\r
+{\r
+       if (!SD_Started)\r
+               return;\r
+\r
+       SD_MusicOff();\r
+       SD_StopSound();\r
+       SDL_ShutDevice();\r
+       SDL_CleanDevice();\r
+\r
+       if (SoundBlasterPresent)\r
+               SDL_ShutSB();\r
+\r
+       if (SoundSourcePresent)\r
+               SDL_ShutSS();\r
+\r
+       asm     pushf\r
+       asm     cli\r
+\r
+       SDL_SetTimer0(0);\r
+\r
+       setvect(8,t0OldService);\r
+\r
+       asm     popf\r
+\r
+       SD_Started = false;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th\r
+//             of a second from its timer 0 ISR\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_SetUserHook(void (* hook)(void))\r
+{\r
+       SoundUserHook = hook;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_PositionSound() - Sets up a stereo imaging location for the next\r
+//             sound to be played. Each channel ranges from 0 to 15.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_PositionSound(int leftvol,int rightvol)\r
+{\r
+       LeftPosition = leftvol;\r
+       RightPosition = rightvol;\r
+       nextsoundpos = true;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_PlaySound() - plays the specified sound on the appropriate hardware\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+boolean\r
+SD_PlaySound(soundnames sound)\r
+{\r
+       boolean         ispos;\r
+       SoundCommon     far *s;\r
+       int     lp,rp;\r
+\r
+       lp = LeftPosition;\r
+       rp = RightPosition;\r
+       LeftPosition = 0;\r
+       RightPosition = 0;\r
+\r
+       ispos = nextsoundpos;\r
+       nextsoundpos = false;\r
+\r
+       if (sound == -1)\r
+               return(false);\r
+\r
+       s = MK_FP(SoundTable[sound],0);\r
+       if ((SoundMode != sdm_Off) && !s)\r
+               Quit("SD_PlaySound() - Uncached sound");\r
+\r
+       if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))\r
+       {\r
+               if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))\r
+               {\r
+                       if (s->priority < SoundPriority)\r
+                               return(false);\r
+\r
+                       SDL_PCStopSound();\r
+\r
+                       SD_PlayDigitized(DigiMap[sound],lp,rp);\r
+                       SoundPositioned = ispos;\r
+                       SoundNumber = sound;\r
+                       SoundPriority = s->priority;\r
+               }\r
+               else\r
+               {\r
+               asm     pushf\r
+               asm     cli\r
+                       if (DigiPriority && !DigiNumber)\r
+                       {\r
+                       asm     popf\r
+                               Quit("SD_PlaySound: Priority without a sound");\r
+                       }\r
+               asm     popf\r
+\r
+                       if (s->priority < DigiPriority)\r
+                               return(false);\r
+\r
+                       SD_PlayDigitized(DigiMap[sound],lp,rp);\r
+                       SoundPositioned = ispos;\r
+                       DigiNumber = sound;\r
+                       DigiPriority = s->priority;\r
+               }\r
+\r
+               return(true);\r
+       }\r
+\r
+       if (SoundMode == sdm_Off)\r
+               return(false);\r
+       if (!s->length)\r
+               Quit("SD_PlaySound() - Zero length sound");\r
+       if (s->priority < SoundPriority)\r
+               return(false);\r
+\r
+       switch (SoundMode)\r
+       {\r
+       case sdm_PC:\r
+               SDL_PCPlaySound((void far *)s);\r
+               break;\r
+       case sdm_AdLib:\r
+               SDL_ALPlaySound((void far *)s);\r
+               break;\r
+       }\r
+\r
+       SoundNumber = sound;\r
+       SoundPriority = s->priority;\r
+\r
+       return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_SoundPlaying() - returns the sound number that's playing, or 0 if\r
+//             no sound is playing\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+word\r
+SD_SoundPlaying(void)\r
+{\r
+       boolean result = false;\r
+\r
+       switch (SoundMode)\r
+       {\r
+       case sdm_PC:\r
+               result = pcSound? true : false;\r
+               break;\r
+       case sdm_AdLib:\r
+               result = alSound? true : false;\r
+               break;\r
+       }\r
+\r
+       if (result)\r
+               return(SoundNumber);\r
+       else\r
+               return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_StopSound() - if a sound is playing, stops it\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_StopSound(void)\r
+{\r
+       if (DigiPlaying)\r
+               SD_StopDigitized();\r
+\r
+       switch (SoundMode)\r
+       {\r
+       case sdm_PC:\r
+               SDL_PCStopSound();\r
+               break;\r
+       case sdm_AdLib:\r
+               SDL_ALStopSound();\r
+               break;\r
+       }\r
+\r
+       SoundPositioned = false;\r
+\r
+       SDL_SoundFinished();\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_WaitSoundDone() - waits until the current sound is done playing\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_WaitSoundDone(void)\r
+{\r
+       while (SD_SoundPlaying())\r
+               ;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_MusicOn() - turns on the sequencer\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_MusicOn(void)\r
+{\r
+       sqActive = true;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_MusicOff() - turns off the sequencer and any playing notes\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_MusicOff(void)\r
+{\r
+       word    i;\r
+\r
+\r
+       switch (MusicMode)\r
+       {\r
+       case smm_AdLib:\r
+               alFXReg = 0;\r
+               alOut(alEffects,0);\r
+               for (i = 0;i < sqMaxTracks;i++)\r
+                       alOut(alFreqH + i + 1,0);\r
+               break;\r
+       }\r
+       sqActive = false;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_StartMusic() - starts playing the music pointed to\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_StartMusic(MusicGroup far *music)\r
+{\r
+       SD_MusicOff();\r
+asm    pushf\r
+asm    cli\r
+\r
+       if (MusicMode == smm_AdLib)\r
+       {\r
+               sqHackPtr = sqHack = music->values;\r
+               sqHackSeqLen = sqHackLen = music->length;\r
+               sqHackTime = 0;\r
+               alTimeCount = 0;\r
+               SD_MusicOn();\r
+       }\r
+\r
+asm    popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()\r
+//             to see if the fadeout is complete\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_FadeOutMusic(void)\r
+{\r
+       switch (MusicMode)\r
+       {\r
+       case smm_AdLib:\r
+               // DEBUG - quick hack to turn the music off\r
+               SD_MusicOff();\r
+               break;\r
+       }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_MusicPlaying() - returns true if music is currently playing, false if\r
+//             not\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+boolean\r
+SD_MusicPlaying(void)\r
+{\r
+       boolean result;\r
+\r
+       switch (MusicMode)\r
+       {\r
+       case smm_AdLib:\r
+               result = false;\r
+               // DEBUG - not written\r
+               break;\r
+       default:\r
+               result = false;\r
+       }\r
+\r
+       return(result);\r
+}\r
diff --git a/16/ID_SD.EQU b/16/ID_SD.EQU
new file mode 100644 (file)
index 0000000..1b1d4e6
--- /dev/null
@@ -0,0 +1,38 @@
+;\r
+;      ID_SD.EQU\r
+;      Id Sound Manager assembly equates\r
+;\r
+\r
+       INCLUDE 'ID_VL.EQU'     ; For screen color debugging stuff\r
+\r
+;      Modes\r
+sdm_Off                                =       0\r
+sdm_PC                         =       1\r
+sdm_AdLib                      =       2\r
+\r
+smm_Off                                =       0\r
+smm_AdLib                      =       1\r
+\r
+sds_Off                                =       0\r
+sds_SoundSource                =       1\r
+sds_SoundBlaster       =       2\r
+\r
+;      Stuff for the PC speaker\r
+pcTimer                                =       42h\r
+pcTAccess                      =       43h\r
+pcSpeaker                      =       61h\r
+pcSpkBits                      =       3\r
+\r
+;      Stuff for the AdLib\r
+;      Operator registers\r
+alChar                         =       20h\r
+alScale                                =       40h\r
+alAttack                       =       60h\r
+alSus                          =       80h\r
+alWave                         =       0e0h\r
+;      Channel registers\r
+alFreqL                                =       0a0h\r
+alFreqH                                =       0b0h\r
+alFeedCon                      =       0c0h\r
+;      Global registers\r
+alEffects                      =       0bdh\r
diff --git a/16/ID_SD.H b/16/ID_SD.H
new file mode 100644 (file)
index 0000000..1fa4c16
--- /dev/null
@@ -0,0 +1,237 @@
+//\r
+//     ID Engine\r
+//     ID_SD.h - Sound Manager Header\r
+//     Version for Wolfenstein\r
+//     By Jason Blochowiak\r
+//\r
+\r
+#ifndef        __ID_SD__\r
+#define        __ID_SD__\r
+\r
+void   alOut(byte n,byte b);\r
+\r
+#ifdef __DEBUG__\r
+#define        __DEBUG_SoundMgr__\r
+#endif\r
+\r
+#define        TickBase        70              // 70Hz per tick - used as a base for timer 0\r
+\r
+typedef        enum    {\r
+                                       sdm_Off,\r
+                                       sdm_PC,sdm_AdLib,\r
+                               }       SDMode;\r
+typedef        enum    {\r
+                                       smm_Off,smm_AdLib\r
+                               }       SMMode;\r
+typedef        enum    {\r
+                                       sds_Off,sds_PC,sds_SoundSource,sds_SoundBlaster\r
+                               }       SDSMode;\r
+typedef        struct\r
+               {\r
+                       longword        length;\r
+                       word            priority;\r
+               } SoundCommon;\r
+\r
+//     PC Sound stuff\r
+#define        pcTimer         0x42\r
+#define        pcTAccess       0x43\r
+#define        pcSpeaker       0x61\r
+\r
+#define        pcSpkBits       3\r
+\r
+typedef        struct\r
+               {\r
+                       SoundCommon     common;\r
+                       byte            data[1];\r
+               } PCSound;\r
+\r
+//     Registers for the Sound Blaster card - needs to be offset by n0 (0x10,0x20,0x30,0x40,0x50,0x60)\r
+#define        sbReset         0x206   // W\r
+#define        sbFMStatus      0x208   // R\r
+#define        sbFMAddr        0x208   // W\r
+#define        sbFMData        0x209   // W\r
+#define        sbReadData      0x20a   // R\r
+#define        sbWriteCmd      0x20c   // W\r
+#define        sbWriteData     0x20c   // W\r
+#define        sbWriteStat     0x20c   // R\r
+#define        sbDataAvail     0x20e   // R\r
+\r
+//     Registers for the Sound Blaster Pro card - needs to be offset by n0 (0x20 or 0x40)\r
+#define        sbpLFMStatus    0x200   // R\r
+#define        sbpLFMAddr              0x200   // W\r
+#define        sbpLFMData              0x201   // W\r
+#define        sbpRFMStatus    0x202   // R\r
+#define        sbpRFMAddr              0x202   // W\r
+#define        sbpRFMData              0x203   // W\r
+#define        sbpMixerAddr    0x204   // W\r
+#define        sbpMixerData    0x205   // RW\r
+#define        sbpCDData               0x210   // R\r
+#define        sbpCDCommand    0x210   // W\r
+#define        sbpCDStatus             0x211   // R\r
+#define        sbpCDReset              0x212   // W\r
+\r
+//     SBPro Mixer addresses\r
+#define        sbpmReset               0x00\r
+#define        sbpmVoiceVol    0x04\r
+#define        sbpmMicMix              0x0a\r
+#define        sbpmFilterADC   0x0c\r
+#define        sbpmControl             0x0e\r
+#define        sbpmMasterVol   0x22\r
+#define        sbpmFMVol               0x26\r
+#define        sbpmCDVol               0x28\r
+#define        sbpmLineVol             0x2e\r
+\r
+typedef        struct\r
+               {\r
+                       SoundCommon     common;\r
+                       word            hertz;\r
+                       byte            bits,\r
+                                               reference,\r
+                                               data[1];\r
+               } SampledSound;\r
+\r
+//     Registers for the AdLib card\r
+#define        alFMStatus      0x388   // R\r
+#define        alFMAddr        0x388   // W\r
+#define        alFMData        0x389   // W\r
+\r
+//     Register addresses\r
+// Operator stuff\r
+#define        alChar          0x20\r
+#define        alScale         0x40\r
+#define        alAttack        0x60\r
+#define        alSus           0x80\r
+#define        alWave          0xe0\r
+// Channel stuff\r
+#define        alFreqL         0xa0\r
+#define        alFreqH         0xb0\r
+#define        alFeedCon       0xc0\r
+// Global stuff\r
+#define        alEffects       0xbd\r
+\r
+typedef        struct\r
+               {\r
+                       byte    mChar,cChar,\r
+                                       mScale,cScale,\r
+                                       mAttack,cAttack,\r
+                                       mSus,cSus,\r
+                                       mWave,cWave,\r
+                                       nConn,\r
+\r
+                                       // These are only for Muse - these bytes are really unused\r
+                                       voice,\r
+                                       mode,\r
+                                       unused[3];\r
+               } Instrument;\r
+\r
+typedef        struct\r
+               {\r
+                       SoundCommon     common;\r
+                       Instrument      inst;\r
+                       byte            block,\r
+                                               data[1];\r
+               } AdLibSound;\r
+\r
+//\r
+//     Sequencing stuff\r
+//\r
+#define        sqMaxTracks     10\r
+#define        sqMaxMoods      1       // DEBUG\r
+\r
+#define        sev_Null                0       // Does nothing\r
+#define        sev_NoteOff             1       // Turns a note off\r
+#define        sev_NoteOn              2       // Turns a note on\r
+#define        sev_NotePitch   3       // Sets the pitch of a currently playing note\r
+#define        sev_NewInst             4       // Installs a new instrument\r
+#define        sev_NewPerc             5       // Installs a new percussive instrument\r
+#define        sev_PercOn              6       // Turns a percussive note on\r
+#define        sev_PercOff             7       // Turns a percussive note off\r
+#define        sev_SeqEnd              -1      // Terminates a sequence\r
+\r
+//     Flags for MusicGroup.flags\r
+#define        sf_Melodic              0\r
+#define        sf_Percussive   1\r
+\r
+#if 1\r
+typedef        struct\r
+               {\r
+                       word    length,\r
+                                       values[1];\r
+               } MusicGroup;\r
+#else\r
+typedef        struct\r
+               {\r
+                       word    flags,\r
+                                       count,\r
+                                       offsets[1];\r
+               } MusicGroup;\r
+#endif\r
+\r
+typedef        struct\r
+               {\r
+                       /* This part needs to be set up by the user */\r
+                       word        mood,far *moods[sqMaxMoods];\r
+\r
+                       /* The rest is set up by the code */\r
+                       Instrument      inst;\r
+                       boolean         percussive;\r
+                       word            far *seq;\r
+                       longword        nextevent;\r
+               } ActiveTrack;\r
+\r
+#define        sqmode_Normal           0\r
+#define        sqmode_FadeIn           1\r
+#define        sqmode_FadeOut          2\r
+\r
+#define        sqMaxFade               64      // DEBUG\r
+\r
+\r
+// Global variables\r
+extern boolean         AdLibPresent,\r
+                                       SoundSourcePresent,\r
+                                       SoundBlasterPresent,\r
+                                       NeedsMusic,                                     // For Caching Mgr\r
+                                       SoundPositioned;\r
+extern SDMode          SoundMode;\r
+extern SDSMode         DigiMode;\r
+extern SMMode          MusicMode;\r
+extern boolean         DigiPlaying;\r
+extern int                     DigiMap[];\r
+extern longword        TimeCount;                                      // Global time in ticks\r
+\r
+// Function prototypes\r
+extern void    SD_Startup(void),\r
+                               SD_Shutdown(void),\r
+                               SD_Default(boolean gotit,SDMode sd,SMMode sm),\r
+\r
+                               SD_PositionSound(int leftvol,int rightvol);\r
+extern boolean SD_PlaySound(soundnames sound);\r
+extern void    SD_SetPosition(int leftvol,int rightvol),\r
+                               SD_StopSound(void),\r
+                               SD_WaitSoundDone(void),\r
+\r
+                               SD_StartMusic(MusicGroup far *music),\r
+                               SD_MusicOn(void),\r
+                               SD_MusicOff(void),\r
+                               SD_FadeOutMusic(void),\r
+\r
+                               SD_SetUserHook(void (*hook)(void));\r
+extern boolean SD_MusicPlaying(void),\r
+                               SD_SetSoundMode(SDMode mode),\r
+                               SD_SetMusicMode(SMMode mode);\r
+extern word    SD_SoundPlaying(void);\r
+\r
+extern void    SD_SetDigiDevice(SDSMode),\r
+                               SD_PlayDigitized(word which,int leftpos,int rightpos),\r
+                               SD_StopDigitized(void),\r
+                               SD_Poll(void);\r
+\r
+#ifdef _MUSE_  // MUSE Goes directly to the lower level routines\r
+extern void    SDL_PCPlaySound(PCSound far *sound),\r
+                               SDL_PCStopSound(void),\r
+                               SDL_ALPlaySound(AdLibSound far *sound),\r
+                               SDL_ALStopSound(void);\r
+#endif\r
+\r
+#endif\r
+\r
diff --git a/16/ID_SD_A.ASM b/16/ID_SD_A.ASM
new file mode 100644 (file)
index 0000000..2de0ea6
--- /dev/null
@@ -0,0 +1,572 @@
+;\r
+;      ID_SD_A.ASM\r
+;      Id Sound Manager assembly stuff\r
+\r
+       .8086\r
+       IDEAL\r
+       MODEL   MEDIUM,C\r
+       JUMPS\r
+\r
+       INCLUDE 'ID_SD.EQU'\r
+\r
+DEBUG  =       0\r
+\r
+       EXTRN   SDL_DigitizedDone:FAR\r
+       EXTRN   alOut:FAR\r
+\r
+;============================================================================\r
+\r
+DATASEG\r
+\r
+       EXTRN   sqActive:WORD\r
+       EXTRN   ssSample:DWORD\r
+       EXTRN   ssLengthLeft:WORD\r
+       EXTRN   ssControl:WORD\r
+       EXTRN   ssStatus:WORD\r
+       EXTRN   ssData:WORD\r
+       EXTRN   ssOn:BYTE\r
+       EXTRN   ssOff:BYTE\r
+\r
+       EXTRN   pcSound:DWORD\r
+       EXTRN   pcLengthLeft:WORD\r
+       EXTRN   pcLastSample:BYTE\r
+       EXTRN   pcSoundLookup:WORD\r
+\r
+       EXTRN   alSound:DWORD\r
+       EXTRN   alBlock:WORD\r
+       EXTRN   alLengthLeft:WORD\r
+       EXTRN   alTimeCount:DWORD\r
+\r
+       EXTRN   sqHack:DWORD\r
+       EXTRN   sqHackPtr:DWORD\r
+       EXTRN   sqHackLen:WORD\r
+       EXTRN   sqHackSeqLen:WORD\r
+       EXTRN   sqHackTime:DWORD\r
+\r
+       EXTRN   HackCount:WORD\r
+       EXTRN   TimeCount:WORD\r
+       EXTRN   LocalTime:WORD\r
+\r
+       EXTRN   TimerCount:WORD\r
+       EXTRN   TimerDivisor:WORD\r
+       EXTRN   t0OldService:DWORD\r
+\r
+       EXTRN   SoundMode:WORD\r
+       EXTRN   DigiMode:WORD\r
+\r
+       EXTRN   SoundNumber:WORD\r
+       EXTRN   SoundPriority:WORD\r
+\r
+count_time     dw      ?\r
+count_fx       dw      ?\r
+\r
+pcdtab db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+\r
+\r
+;============================================================================\r
+\r
+CODESEG\r
+\r
+MyDS   dw      ?\r
+\r
+pcindicate     dw      ?\r
+extreme                dw      ?\r
+\r
+       PROC    SDL_SetDS\r
+       PUBLIC  SDL_SetDS\r
+\r
+       mov     ax,ds\r
+       mov     [cs:MyDS],ds\r
+       ret\r
+\r
+       ENDP\r
+\r
+;\r
+;      COMMONSTART\r
+;      Macro used for common prefix code\r
+;\r
+       MACRO   COMMONSTART\r
+       IF DEBUG\r
+       push dx\r
+       push ax\r
+       mov     dx,STATUS_REGISTER_1\r
+       in      al,dx\r
+       mov     dx,ATR_INDEX\r
+       mov     al,ATR_OVERSCAN\r
+       out     dx,al\r
+       mov     al,4    ; red\r
+       out     dx,al\r
+       ENDIF\r
+\r
+       push ds\r
+       push ax\r
+\r
+       mov     ds,[cs:MyDS]\r
+       inc     [HackCount]\r
+       ENDM\r
+\r
+;\r
+;      DOFX\r
+;      Macro used to do the sound effects code\r
+;\r
+       MACRO   DOFX\r
+       les     di,[pcSound]                            ; PC sound effects\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@nopc                                          ; nil pointer - no PC sound effect going\r
+\r
+       mov     bl,[es:di]                                      ; Get the byte\r
+       inc     [WORD PTR pcSound]                      ; Increment pointer\r
+       cmp     [pcLastSample],bl                       ; Is this sample the same as last?\r
+       jz      @@pcsame                                        ; Yep - don't do anything\r
+       mov     [pcLastSample],bl                       ; No, save it for next time\r
+\r
+       or      bl,bl\r
+       jz      @@pcoff                                         ; If 0, turn sounds off\r
+       xor     bh,bh\r
+       shl     bx,1\r
+       mov     bx,[pcSoundLookup+bx]           ; Use byte as index into frequency table\r
+\r
+       mov     al,0b6h                                         ; Write to channel 2 (speaker) timer\r
+       out     pcTAccess,al\r
+       mov     al,bl\r
+       out     pcTimer,al                                      ; Low byte\r
+       mov     al,bh\r
+       out     pcTimer,al                                      ; High byte\r
+\r
+       in      al,pcSpeaker                            ; Turn the speaker & gate on\r
+       or      al,3\r
+       out     pcSpeaker,al\r
+\r
+       jmp @@pcsame\r
+\r
+@@pcoff:\r
+       in      al,pcSpeaker                            ; Turn the speaker & gate off\r
+       and     al,0fch                                         ; ~3\r
+       out     pcSpeaker,al\r
+\r
+@@pcsame:\r
+       dec     [pcLengthLeft]                          ; Decrement length\r
+       jnz     @@nopc                                          ; If not 0, we're not done with the sound\r
+\r
+       mov     ax,0\r
+       mov     [WORD PTR pcSound],ax           ; Zero the pointer\r
+       mov     [WORD PTR pcSound + 2],ax\r
+       mov     [SoundNumber],ax                ; Indicate no sound\r
+       mov     [SoundPriority],ax                      ;  with no priority\r
+\r
+       in      al,pcSpeaker                            ; Turn the speaker off\r
+       and     al,0fdh                                         ; ~2\r
+       out     pcSpeaker,al\r
+@@nopc:\r
+\r
+       les     di,[alSound]                            ; AdLib sound effects\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@noal                                          ; nil pointer - no AdLib effect going\r
+\r
+       xor     ah,ah\r
+       mov     al,[es:di]\r
+       or      al,al\r
+       jz      @@aldone\r
+\r
+       CALL alOut C,alFreqL,ax\r
+       mov     ax,[alBlock]\r
+\r
+@@aldone:\r
+       CALL alOut C,alFreqH,ax\r
+       inc     [WORD PTR alSound]\r
+       dec     [alLengthLeft]\r
+       jnz     @@noal\r
+\r
+       mov     ax,0\r
+       mov     [WORD PTR alSound],ax           ; Zero the pointer\r
+       mov     [WORD PTR alSound + 2],ax\r
+       mov     [SoundNumber],ax                ; Indicate no sound\r
+       mov     [SoundPriority],ax                      ;  with no priority\r
+       CALL alOut C,alFreqH,ax                 ; Turn off the sound\r
+@@noal:\r
+\r
+       ENDM\r
+\r
+;\r
+;\r
+;\r
+       MACRO   TIME\r
+       cmp     [count_time],2\r
+       jb      @@notime\r
+       add     [LocalTime],1\r
+       adc     [LocalTime+2],0\r
+       add     [TimeCount],1\r
+       adc     [TimeCount+2],0\r
+       mov     [count_time],0\r
+@@notime:\r
+       ENDM\r
+\r
+;\r
+;      COMMONEND\r
+;      Macro used for common suffix code\r
+;\r
+       MACRO   COMMONEND\r
+@@fullexit:\r
+       pop     es\r
+       ;popa\r
+       pop di\r
+       pop si\r
+       pop bp\r
+       pop [oldsp]\r
+       pop bx\r
+       pop dx\r
+       pop cx\r
+       pop ax\r
+\r
+@@nosave:\r
+       mov     ax,[TimerDivisor]\r
+       add     [TimerCount],ax\r
+       jnc     @@myack\r
+\r
+       pushf\r
+       call [t0OldService]\r
+       jmp     @@out\r
+\r
+@@myack:\r
+       mov     al,20h\r
+       out     20h,al\r
+\r
+@@out:\r
+       pop     ax\r
+       pop     ds\r
+\r
+       IF DEBUG\r
+       mov     dx,STATUS_REGISTER_1\r
+       in      al,dx\r
+       mov     dx,ATR_INDEX\r
+       mov     al,ATR_OVERSCAN\r
+       out     dx,al\r
+       mov     al,3    ; blue\r
+       out     dx,al\r
+       mov     al,20h  ; normal\r
+       out     dx,al\r
+       pop     ax\r
+       pop     dx\r
+       ENDIF\r
+\r
+       iret\r
+       ENDM\r
+\r
+;\r
+;      SDL_IndicatePC\r
+;\r
+       PROC    SDL_IndicatePC on:WORD\r
+       PUBLIC  SDL_IndicatePC\r
+\r
+       mov     ax,[on]\r
+       mov     [cs:pcindicate],ax\r
+       ret\r
+\r
+       ENDP\r
+\r
+;\r
+;      SDL_t0ExtremeAsmService\r
+;      Timer 0 ISR 7000Hz interrupts\r
+;\r
+       PROC    SDL_t0ExtremeAsmService\r
+       PUBLIC  SDL_t0ExtremeAsmService\r
+\r
+       push ax\r
+       mov     al,[BYTE PTR cs:pcindicate]\r
+       or      al,al\r
+       jz      @@done\r
+\r
+       push ds\r
+       push es\r
+       ;pusha\r
+       jmp @@skipme\r
+       oldsp dw ?\r
+@@skipme:\r
+       mov [oldsp], sp\r
+       push ax\r
+       push cx\r
+       push dx\r
+       push bx\r
+       push [oldsp]\r
+       push bp\r
+       push si\r
+       push di\r
+\r
+       mov     ds,[cs:MyDS]\r
+\r
+       les     di,[pcSound]\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@donereg                                       ; nil pointer\r
+\r
+       mov     bl,[es:di]                                      ; Get the byte\r
+       inc     [WORD PTR pcSound]                      ; Increment pointer\r
+\r
+       and     bl,11100000b                            ; Nuke some of the precision (DEBUG - do this in the table)\r
+\r
+       xor     bh,bh\r
+       mov     ah,[pcdtab+bx]                          ; Translate the byte\r
+\r
+       in      al,pcSpeaker\r
+       and     al,11111100b\r
+       or      al,ah\r
+       out     pcSpeaker,al\r
+\r
+       dec     [pcLengthLeft]\r
+       jnz     @@donereg\r
+\r
+       mov     [WORD PTR pcSound],0            ; We're done with this sample\r
+       mov     [WORD PTR pcSound+2],0\r
+\r
+       in      al,pcSpeaker\r
+       and     al,11111100b\r
+       out     pcSpeaker,al\r
+\r
+       call SDL_DigitizedDone\r
+\r
+@@donereg:\r
+       ;popa\r
+       pop di\r
+       pop si\r
+       pop bp\r
+       pop [oldsp]\r
+       pop bx\r
+       pop dx\r
+       pop cx\r
+       pop ax\r
+       pop     es\r
+       pop     ds\r
+\r
+@@done:\r
+       inc     [cs:extreme]\r
+       cmp     [cs:extreme],10\r
+       jae     @@tofast\r
+\r
+       mov     al,20h\r
+       out     20h,al\r
+       pop     ax\r
+       iret\r
+\r
+@@tofast:\r
+       mov     [cs:extreme],0\r
+       pop     ax\r
+\r
+;      jmp     SDL_t0FastAsmService                    ; Drops through to SDL_t0FastAsmService\r
+\r
+       ENDP\r
+\r
+;\r
+;      SDL_t0FastAsmService\r
+;      Timer 0 ISR for 700Hz interrupts\r
+;\r
+       PROC    SDL_t0FastAsmService\r
+       PUBLIC  SDL_t0FastAsmService\r
+\r
+       COMMONSTART\r
+\r
+       inc     [count_fx]                                              ; Time to do PC/AdLib effects & time?\r
+       cmp     [count_fx],5\r
+       jae     @@dofull\r
+\r
+       mov     ax,[sqActive]                                   ; Is the sequencer active?\r
+       or      ax,ax\r
+       jnz     @@dofull\r
+\r
+       mov     ax,[WORD PTR ssSample]                  ; Is there a sample for the Sound Src?\r
+       or      ax,[WORD PTR ssSample+2]\r
+       jz      @@nosave\r
+\r
+@@dofull:\r
+       ;pusha\r
+       mov [oldsp], sp\r
+       push ax\r
+       push cx\r
+       push dx\r
+       push bx\r
+       push [oldsp]\r
+       push bp\r
+       push si\r
+       push di\r
+       push es\r
+\r
+       cmp     [count_fx],5\r
+       jb      @@nofx\r
+       mov     [count_fx],0\r
+       DOFX\r
+\r
+       inc     [count_time]\r
+       TIME\r
+@@nofx:\r
+\r
+       mov     ax,[sqActive]\r
+       or      ax,ax\r
+       jz      @@nosq\r
+\r
+       mov     ax,[sqHackLen]\r
+       or      ax,ax\r
+       jz      @@sqdone\r
+\r
+       les     di,[sqHackPtr]\r
+@@sqloop:\r
+       mov     ax,[WORD PTR sqHackTime+2]\r
+       cmp     ax,[WORD PTR alTimeCount+2]\r
+       ja      @@sqdone\r
+       mov     ax,[WORD PTR sqHackTime]\r
+       cmp     ax,[WORD PTR alTimeCount]\r
+       ja      @@sqdone\r
+\r
+       mov     ax,[es:di+2]                                    ; Get time to next event\r
+       add     ax,[WORD PTR alTimeCount]\r
+       mov     [WORD PTR sqHackTime],ax\r
+       mov     ax,[WORD PTR alTimeCount+2]\r
+       adc     ax,0\r
+       mov     [WORD PTR sqHackTime+2],ax\r
+\r
+       mov     ax,[es:di]                                              ; Get register/value pair\r
+       xor     bh,bh\r
+       mov     bl,ah\r
+       xor     ah,ah\r
+       CALL alOut C,ax,bx\r
+\r
+       add     di,4\r
+       mov     [WORD PTR sqHackPtr],di\r
+\r
+       sub     [sqHackLen],4\r
+       jnz     @@sqloop\r
+\r
+@@sqdone:\r
+       add     [WORD PTR alTimeCount],1\r
+       adc     [WORD PTR alTimeCount+2],0\r
+       mov     ax,[sqHackLen]\r
+       or      ax,ax\r
+       jnz     @@nosq\r
+\r
+       mov     ax,[WORD PTR sqHack]            ; Copy pointer\r
+       mov     [WORD PTR sqHackPtr],ax\r
+       mov     ax,[WORD PTR sqHack+2]\r
+       mov     [WORD PTR sqHackPtr+2],ax\r
+\r
+       mov     ax,[sqHackSeqLen]                       ; Copy length\r
+       mov     [sqHackLen],ax\r
+\r
+       mov     ax,0\r
+       mov     [WORD PTR alTimeCount],ax       ; Reset time counts\r
+       mov     [WORD PTR alTimeCount+2],ax\r
+       mov     [WORD PTR sqHackTime],ax\r
+       mov     [WORD PTR sqHackTime+2],ax\r
+@@nosq:\r
+\r
+       les     di,[ssSample]                   ; Get pointer to Sound Source sample\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@ssdone                                ; If nil, skip this\r
+\r
+@@ssloop:\r
+       mov     dx,[ssStatus]                   ; Check to see if FIFO has any empty slots\r
+       in      al,dx\r
+       test al,40h\r
+       jnz     @@ssdone                                ; Nope - don't push any more data out\r
+\r
+       mov     dx,[ssData]\r
+       mov     al,[es:di]                              ; al = *ssSample\r
+       out     dx,al                                   ; Pump the value out\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
+\r
+       inc     di\r
+       mov     [WORD PTR ssSample],di  ; ssSample++\r
+\r
+       dec     [ssLengthLeft]\r
+       jnz @@ssloop\r
+\r
+       mov     [WORD PTR ssSample],0   ; We're done with this sample\r
+       mov     [WORD PTR ssSample+2],0\r
+\r
+       call SDL_DigitizedDone\r
+@@ssdone:\r
+\r
+       COMMONEND\r
+\r
+       ENDP\r
+\r
+;\r
+;      SDL_t0SlowAsmService\r
+;      Timer 0 ISR for 140Hz interrupts\r
+;\r
+       PROC    SDL_t0SlowAsmService\r
+       PUBLIC  SDL_t0SlowAsmService\r
+\r
+       IF DEBUG\r
+       push dx\r
+       push ax\r
+       mov     dx,STATUS_REGISTER_1\r
+       in      al,dx\r
+       mov     dx,ATR_INDEX\r
+       mov     al,ATR_OVERSCAN\r
+       out     dx,al\r
+       mov     al,4    ; red\r
+       out     dx,al\r
+       ENDIF\r
+\r
+       push ds\r
+       push ax\r
+\r
+       mov     ds,[cs:MyDS]\r
+\r
+       inc     [count_time]\r
+       TIME\r
+\r
+       mov     ax,[WORD PTR pcSound]           ; Is there a PC sound effect going?\r
+       or      ax,[WORD PTR pcSound+2]\r
+       jnz     @@dofull\r
+\r
+       mov     ax,[WORD PTR alSound]           ; Is there an AdLib sound effect going?\r
+       or      ax,[WORD PTR alSound+2]\r
+       jz      @@nosave\r
+\r
+@@dofull:\r
+       ;pusha\r
+       mov [oldsp], sp\r
+       push ax\r
+       push cx\r
+       push dx\r
+       push bx\r
+       push [oldsp]\r
+       push bp\r
+       push si\r
+       push di\r
+       push es\r
+\r
+       DOFX\r
+\r
+       COMMONEND\r
+\r
+       ENDP\r
+\r
+       END\r
diff --git a/16/ID_SD_A.BAK b/16/ID_SD_A.BAK
new file mode 100644 (file)
index 0000000..34e1ac6
--- /dev/null
@@ -0,0 +1,572 @@
+;\r
+;      ID_SD_A.ASM\r
+;      Id Sound Manager assembly stuff\r
+\r
+       .8086\r
+       IDEAL\r
+       MODEL   MEDIUM,C\r
+       JUMPS\r
+\r
+       INCLUDE 'ID_SD.EQU'\r
+\r
+DEBUG  =       0\r
+\r
+       EXTRN   SDL_DigitizedDone:FAR\r
+       EXTRN   alOut:FAR\r
+\r
+;============================================================================\r
+\r
+DATASEG\r
+\r
+       EXTRN   sqActive:WORD\r
+       EXTRN   ssSample:DWORD\r
+       EXTRN   ssLengthLeft:WORD\r
+       EXTRN   ssControl:WORD\r
+       EXTRN   ssStatus:WORD\r
+       EXTRN   ssData:WORD\r
+       EXTRN   ssOn:BYTE\r
+       EXTRN   ssOff:BYTE\r
+\r
+       EXTRN   pcSound:DWORD\r
+       EXTRN   pcLengthLeft:WORD\r
+       EXTRN   pcLastSample:BYTE\r
+       EXTRN   pcSoundLookup:WORD\r
+\r
+       EXTRN   alSound:DWORD\r
+       EXTRN   alBlock:WORD\r
+       EXTRN   alLengthLeft:WORD\r
+       EXTRN   alTimeCount:DWORD\r
+\r
+       EXTRN   sqHack:DWORD\r
+       EXTRN   sqHackPtr:DWORD\r
+       EXTRN   sqHackLen:WORD\r
+       EXTRN   sqHackSeqLen:WORD\r
+       EXTRN   sqHackTime:DWORD\r
+\r
+       EXTRN   HackCount:WORD\r
+       EXTRN   TimeCount:WORD\r
+       EXTRN   LocalTime:WORD\r
+\r
+       EXTRN   TimerCount:WORD\r
+       EXTRN   TimerDivisor:WORD\r
+       EXTRN   t0OldService:DWORD\r
+\r
+       EXTRN   SoundMode:WORD\r
+       EXTRN   DigiMode:WORD\r
+\r
+       EXTRN   SoundNumber:WORD\r
+       EXTRN   SoundPriority:WORD\r
+\r
+count_time     dw      ?\r
+count_fx       dw      ?\r
+\r
+pcdtab db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b,00b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+               db      10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b,10b\r
+\r
+\r
+;============================================================================\r
+\r
+CODESEG\r
+\r
+MyDS   dw      ?\r
+\r
+pcindicate     dw      ?\r
+extreme                dw      ?\r
+\r
+       PROC    SDL_SetDS\r
+       PUBLIC  SDL_SetDS\r
+\r
+       mov     ax,ds\r
+       mov     [cs:MyDS],ds\r
+       ret\r
+\r
+       ENDP\r
+\r
+;\r
+;      COMMONSTART\r
+;      Macro used for common prefix code\r
+;\r
+       MACRO   COMMONSTART\r
+       IF DEBUG\r
+       push dx\r
+       push ax\r
+       mov     dx,STATUS_REGISTER_1\r
+       in      al,dx\r
+       mov     dx,ATR_INDEX\r
+       mov     al,ATR_OVERSCAN\r
+       out     dx,al\r
+       mov     al,4    ; red\r
+       out     dx,al\r
+       ENDIF\r
+\r
+       push ds\r
+       push ax\r
+\r
+       mov     ds,[cs:MyDS]\r
+       inc     [HackCount]\r
+       ENDM\r
+\r
+;\r
+;      DOFX\r
+;      Macro used to do the sound effects code\r
+;\r
+       MACRO   DOFX\r
+       les     di,[pcSound]                            ; PC sound effects\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@nopc                                          ; nil pointer - no PC sound effect going\r
+\r
+       mov     bl,[es:di]                                      ; Get the byte\r
+       inc     [WORD PTR pcSound]                      ; Increment pointer\r
+       cmp     [pcLastSample],bl                       ; Is this sample the same as last?\r
+       jz      @@pcsame                                        ; Yep - don't do anything\r
+       mov     [pcLastSample],bl                       ; No, save it for next time\r
+\r
+       or      bl,bl\r
+       jz      @@pcoff                                         ; If 0, turn sounds off\r
+       xor     bh,bh\r
+       shl     bx,1\r
+       mov     bx,[pcSoundLookup+bx]           ; Use byte as index into frequency table\r
+\r
+       mov     al,0b6h                                         ; Write to channel 2 (speaker) timer\r
+       out     pcTAccess,al\r
+       mov     al,bl\r
+       out     pcTimer,al                                      ; Low byte\r
+       mov     al,bh\r
+       out     pcTimer,al                                      ; High byte\r
+\r
+       in      al,pcSpeaker                            ; Turn the speaker & gate on\r
+       or      al,3\r
+       out     pcSpeaker,al\r
+\r
+       jmp @@pcsame\r
+\r
+@@pcoff:\r
+       in      al,pcSpeaker                            ; Turn the speaker & gate off\r
+       and     al,0fch                                         ; ~3\r
+       out     pcSpeaker,al\r
+\r
+@@pcsame:\r
+       dec     [pcLengthLeft]                          ; Decrement length\r
+       jnz     @@nopc                                          ; If not 0, we're not done with the sound\r
+\r
+       mov     ax,0\r
+       mov     [WORD PTR pcSound],ax           ; Zero the pointer\r
+       mov     [WORD PTR pcSound + 2],ax\r
+       mov     [SoundNumber],ax                ; Indicate no sound\r
+       mov     [SoundPriority],ax                      ;  with no priority\r
+\r
+       in      al,pcSpeaker                            ; Turn the speaker off\r
+       and     al,0fdh                                         ; ~2\r
+       out     pcSpeaker,al\r
+@@nopc:\r
+\r
+       les     di,[alSound]                            ; AdLib sound effects\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@noal                                          ; nil pointer - no AdLib effect going\r
+\r
+       xor     ah,ah\r
+       mov     al,[es:di]\r
+       or      al,al\r
+       jz      @@aldone\r
+\r
+       CALL alOut C,alFreqL,ax\r
+       mov     ax,[alBlock]\r
+\r
+@@aldone:\r
+       CALL alOut C,alFreqH,ax\r
+       inc     [WORD PTR alSound]\r
+       dec     [alLengthLeft]\r
+       jnz     @@noal\r
+\r
+       mov     ax,0\r
+       mov     [WORD PTR alSound],ax           ; Zero the pointer\r
+       mov     [WORD PTR alSound + 2],ax\r
+       mov     [SoundNumber],ax                ; Indicate no sound\r
+       mov     [SoundPriority],ax                      ;  with no priority\r
+       CALL alOut C,alFreqH,ax                 ; Turn off the sound\r
+@@noal:\r
+\r
+       ENDM\r
+\r
+;\r
+;\r
+;\r
+       MACRO   TIME\r
+       cmp     [count_time],2\r
+       jb      @@notime\r
+       add     [LocalTime],1\r
+       adc     [LocalTime+2],0\r
+       add     [TimeCount],1\r
+       adc     [TimeCount+2],0\r
+       mov     [count_time],0\r
+@@notime:\r
+       ENDM\r
+\r
+;\r
+;      COMMONEND\r
+;      Macro used for common suffix code\r
+;\r
+       MACRO   COMMONEND\r
+@@fullexit:\r
+       pop     es\r
+       ;popa\r
+       pop di\r
+       pop si\r
+       pop bp\r
+       pop [regsp]\r
+       pop bx\r
+       pop dx\r
+       pop cx\r
+       pop ax\r
+\r
+@@nosave:\r
+       mov     ax,[TimerDivisor]\r
+       add     [TimerCount],ax\r
+       jnc     @@myack\r
+\r
+       pushf\r
+       call [t0OldService]\r
+       jmp     @@out\r
+\r
+@@myack:\r
+       mov     al,20h\r
+       out     20h,al\r
+\r
+@@out:\r
+       pop     ax\r
+       pop     ds\r
+\r
+       IF DEBUG\r
+       mov     dx,STATUS_REGISTER_1\r
+       in      al,dx\r
+       mov     dx,ATR_INDEX\r
+       mov     al,ATR_OVERSCAN\r
+       out     dx,al\r
+       mov     al,3    ; blue\r
+       out     dx,al\r
+       mov     al,20h  ; normal\r
+       out     dx,al\r
+       pop     ax\r
+       pop     dx\r
+       ENDIF\r
+\r
+       iret\r
+       ENDM\r
+\r
+;\r
+;      SDL_IndicatePC\r
+;\r
+       PROC    SDL_IndicatePC on:WORD\r
+       PUBLIC  SDL_IndicatePC\r
+\r
+       mov     ax,[on]\r
+       mov     [cs:pcindicate],ax\r
+       ret\r
+\r
+       ENDP\r
+\r
+;\r
+;      SDL_t0ExtremeAsmService\r
+;      Timer 0 ISR 7000Hz interrupts\r
+;\r
+       PROC    SDL_t0ExtremeAsmService\r
+       PUBLIC  SDL_t0ExtremeAsmService\r
+\r
+       push ax\r
+       mov     al,[BYTE PTR cs:pcindicate]\r
+       or      al,al\r
+       jz      @@done\r
+\r
+       push ds\r
+       push es\r
+       ;pusha\r
+       jmp @@skipme\r
+       oldsp dw ?\r
+@@skipme:\r
+       mov [oldsp], sp\r
+       push ax\r
+       push cx\r
+       push dx\r
+       push bx\r
+       push [oldsp]\r
+       push bp\r
+       push si\r
+       push di\r
+\r
+       mov     ds,[cs:MyDS]\r
+\r
+       les     di,[pcSound]\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@donereg                                       ; nil pointer\r
+\r
+       mov     bl,[es:di]                                      ; Get the byte\r
+       inc     [WORD PTR pcSound]                      ; Increment pointer\r
+\r
+       and     bl,11100000b                            ; Nuke some of the precision (DEBUG - do this in the table)\r
+\r
+       xor     bh,bh\r
+       mov     ah,[pcdtab+bx]                          ; Translate the byte\r
+\r
+       in      al,pcSpeaker\r
+       and     al,11111100b\r
+       or      al,ah\r
+       out     pcSpeaker,al\r
+\r
+       dec     [pcLengthLeft]\r
+       jnz     @@donereg\r
+\r
+       mov     [WORD PTR pcSound],0            ; We're done with this sample\r
+       mov     [WORD PTR pcSound+2],0\r
+\r
+       in      al,pcSpeaker\r
+       and     al,11111100b\r
+       out     pcSpeaker,al\r
+\r
+       call SDL_DigitizedDone\r
+\r
+@@donereg:\r
+       ;popa\r
+       pop di\r
+       pop si\r
+       pop bp\r
+       pop [oldsp]\r
+       pop bx\r
+       pop dx\r
+       pop cx\r
+       pop ax\r
+       pop     es\r
+       pop     ds\r
+\r
+@@done:\r
+       inc     [cs:extreme]\r
+       cmp     [cs:extreme],10\r
+       jae     @@tofast\r
+\r
+       mov     al,20h\r
+       out     20h,al\r
+       pop     ax\r
+       iret\r
+\r
+@@tofast:\r
+       mov     [cs:extreme],0\r
+       pop     ax\r
+\r
+;      jmp     SDL_t0FastAsmService                    ; Drops through to SDL_t0FastAsmService\r
+\r
+       ENDP\r
+\r
+;\r
+;      SDL_t0FastAsmService\r
+;      Timer 0 ISR for 700Hz interrupts\r
+;\r
+       PROC    SDL_t0FastAsmService\r
+       PUBLIC  SDL_t0FastAsmService\r
+\r
+       COMMONSTART\r
+\r
+       inc     [count_fx]                                              ; Time to do PC/AdLib effects & time?\r
+       cmp     [count_fx],5\r
+       jae     @@dofull\r
+\r
+       mov     ax,[sqActive]                                   ; Is the sequencer active?\r
+       or      ax,ax\r
+       jnz     @@dofull\r
+\r
+       mov     ax,[WORD PTR ssSample]                  ; Is there a sample for the Sound Src?\r
+       or      ax,[WORD PTR ssSample+2]\r
+       jz      @@nosave\r
+\r
+@@dofull:\r
+       ;pusha\r
+       mov [oldsp], sp\r
+       push ax\r
+       push cx\r
+       push dx\r
+       push bx\r
+       push [oldsp]\r
+       push bp\r
+       push si\r
+       push di\r
+       push es\r
+\r
+       cmp     [count_fx],5\r
+       jb      @@nofx\r
+       mov     [count_fx],0\r
+       DOFX\r
+\r
+       inc     [count_time]\r
+       TIME\r
+@@nofx:\r
+\r
+       mov     ax,[sqActive]\r
+       or      ax,ax\r
+       jz      @@nosq\r
+\r
+       mov     ax,[sqHackLen]\r
+       or      ax,ax\r
+       jz      @@sqdone\r
+\r
+       les     di,[sqHackPtr]\r
+@@sqloop:\r
+       mov     ax,[WORD PTR sqHackTime+2]\r
+       cmp     ax,[WORD PTR alTimeCount+2]\r
+       ja      @@sqdone\r
+       mov     ax,[WORD PTR sqHackTime]\r
+       cmp     ax,[WORD PTR alTimeCount]\r
+       ja      @@sqdone\r
+\r
+       mov     ax,[es:di+2]                                    ; Get time to next event\r
+       add     ax,[WORD PTR alTimeCount]\r
+       mov     [WORD PTR sqHackTime],ax\r
+       mov     ax,[WORD PTR alTimeCount+2]\r
+       adc     ax,0\r
+       mov     [WORD PTR sqHackTime+2],ax\r
+\r
+       mov     ax,[es:di]                                              ; Get register/value pair\r
+       xor     bh,bh\r
+       mov     bl,ah\r
+       xor     ah,ah\r
+       CALL alOut C,ax,bx\r
+\r
+       add     di,4\r
+       mov     [WORD PTR sqHackPtr],di\r
+\r
+       sub     [sqHackLen],4\r
+       jnz     @@sqloop\r
+\r
+@@sqdone:\r
+       add     [WORD PTR alTimeCount],1\r
+       adc     [WORD PTR alTimeCount+2],0\r
+       mov     ax,[sqHackLen]\r
+       or      ax,ax\r
+       jnz     @@nosq\r
+\r
+       mov     ax,[WORD PTR sqHack]            ; Copy pointer\r
+       mov     [WORD PTR sqHackPtr],ax\r
+       mov     ax,[WORD PTR sqHack+2]\r
+       mov     [WORD PTR sqHackPtr+2],ax\r
+\r
+       mov     ax,[sqHackSeqLen]                       ; Copy length\r
+       mov     [sqHackLen],ax\r
+\r
+       mov     ax,0\r
+       mov     [WORD PTR alTimeCount],ax       ; Reset time counts\r
+       mov     [WORD PTR alTimeCount+2],ax\r
+       mov     [WORD PTR sqHackTime],ax\r
+       mov     [WORD PTR sqHackTime+2],ax\r
+@@nosq:\r
+\r
+       les     di,[ssSample]                   ; Get pointer to Sound Source sample\r
+       mov     ax,es\r
+       or      ax,di\r
+       jz      @@ssdone                                ; If nil, skip this\r
+\r
+@@ssloop:\r
+       mov     dx,[ssStatus]                   ; Check to see if FIFO has any empty slots\r
+       in      al,dx\r
+       test al,40h\r
+       jnz     @@ssdone                                ; Nope - don't push any more data out\r
+\r
+       mov     dx,[ssData]\r
+       mov     al,[es:di]                              ; al = *ssSample\r
+       out     dx,al                                   ; Pump the value out\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
+\r
+       inc     di\r
+       mov     [WORD PTR ssSample],di  ; ssSample++\r
+\r
+       dec     [ssLengthLeft]\r
+       jnz @@ssloop\r
+\r
+       mov     [WORD PTR ssSample],0   ; We're done with this sample\r
+       mov     [WORD PTR ssSample+2],0\r
+\r
+       call SDL_DigitizedDone\r
+@@ssdone:\r
+\r
+       COMMONEND\r
+\r
+       ENDP\r
+\r
+;\r
+;      SDL_t0SlowAsmService\r
+;      Timer 0 ISR for 140Hz interrupts\r
+;\r
+       PROC    SDL_t0SlowAsmService\r
+       PUBLIC  SDL_t0SlowAsmService\r
+\r
+       IF DEBUG\r
+       push dx\r
+       push ax\r
+       mov     dx,STATUS_REGISTER_1\r
+       in      al,dx\r
+       mov     dx,ATR_INDEX\r
+       mov     al,ATR_OVERSCAN\r
+       out     dx,al\r
+       mov     al,4    ; red\r
+       out     dx,al\r
+       ENDIF\r
+\r
+       push ds\r
+       push ax\r
+\r
+       mov     ds,[cs:MyDS]\r
+\r
+       inc     [count_time]\r
+       TIME\r
+\r
+       mov     ax,[WORD PTR pcSound]           ; Is there a PC sound effect going?\r
+       or      ax,[WORD PTR pcSound+2]\r
+       jnz     @@dofull\r
+\r
+       mov     ax,[WORD PTR alSound]           ; Is there an AdLib sound effect going?\r
+       or      ax,[WORD PTR alSound+2]\r
+       jz      @@nosave\r
+\r
+@@dofull:\r
+       ;pusha\r
+       mov [oldsp], sp\r
+       push ax\r
+       push cx\r
+       push dx\r
+       push bx\r
+       push [oldsp]\r
+       push bp\r
+       push si\r
+       push di\r
+       push es\r
+\r
+       DOFX\r
+\r
+       COMMONEND\r
+\r
+       ENDP\r
+\r
+       END\r