]> 4ch.mooo.com Git - 16.git/blobdiff - 16/keen456/KEEN4-6/ID_SD.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / ID_SD.C
diff --git a/16/keen456/KEEN4-6/ID_SD.C b/16/keen456/KEEN4-6/ID_SD.C
new file mode 100755 (executable)
index 0000000..91f1ba7
--- /dev/null
@@ -0,0 +1,1336 @@
+/* Reconstructed Commander Keen 4-6 Source Code\r
+ * Copyright (C) 2021 K1n9_Duk3\r
+ *\r
+ * This file is primarily based on:\r
+ * Catacomb 3-D Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+//\r
+//     ID Engine\r
+//     ID_SD.c - Sound Manager\r
+//     v1.1d1\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
+//             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
+#define        SDL_SoundFinished()     {SoundNumber = SoundPriority = 0;}\r
+\r
+// Macros for AdLib stuff\r
+#define        selreg(n)       outportb(0x388,n)\r
+#define        writereg(n)     outportb(0x389,n)\r
+#define        readstat()      inportb(0x388)\r
+\r
+//     Global variables\r
+       boolean         SoundSourcePresent,SoundBlasterPresent,AdLibPresent,QuietFX,\r
+                               NeedsDigitized,NeedsMusic;\r
+       SDMode          SoundMode;\r
+       SMMode          MusicMode;\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
+\r
+//     Internal variables\r
+static boolean                 SD_Started;\r
+static boolean                 TimerDone;\r
+static word                    TimerVal,TimerDelay10,TimerDelay25,TimerDelay100;\r
+static longword                TimerDivisor,TimerCount;\r
+static char                    *ParmStrings[] =\r
+                                               {\r
+                                                       "noal",\r
+                                                       "adlib",\r
+                                                       nil\r
+                                               };\r
+static void                    (*SoundUserHook)(void);\r
+static word                    SoundNumber,SoundPriority;\r
+static void interrupt  (*t0OldService)(void);\r
+//static       word                    t0CountTable[] = {8,8,8,8,40,40};\r
+static long                    LocalTime;\r
+\r
+//     PC Sound variables\r
+static byte                    pcLastSample,far *pcSound;\r
+static longword                pcLengthLeft;\r
+static word                    pcSoundLookup[255];\r
+\r
+//     AdLib variables\r
+static boolean                 alNoCheck;\r
+static byte                    far *alSound;\r
+static word                    alBlock;\r
+static longword                alLengthLeft;\r
+static longword                alTimeCount;\r
+static 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
+static boolean                 sqActive;\r
+static word                    alFXReg;\r
+static ActiveTrack             *tracks[sqMaxTracks],\r
+                                               mytracks[sqMaxTracks];\r
+static word                    sqMode,sqFadeStep;\r
+static word                    far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;\r
+static long                    sqHackTime;\r
+\r
+//     Internal routines\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
+       outportb(0x43,0x36);                            // Change timer 0\r
+       outportb(0x40,speed);\r
+       outportb(0x40,speed >> 8);\r
+       TimerDivisor = speed;\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
+       SDL_SetTimer0(1192030 / ints);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_TimingService() - Used by SDL_InitDelay() to determine a timing\r
+//             value for the current system that we're running on\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void interrupt\r
+SDL_TimingService(void)\r
+{\r
+       TimerVal = _CX;\r
+       TimerDone++;\r
+\r
+       outportb(0x20,0x20);                            // Ack interrupt\r
+}\r
+\r
+#if 0\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_InitDelay() - Sets up TimerDelay's for SDL_Delay()\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_InitDelay(void)\r
+{\r
+       int             i;\r
+       word    timer;\r
+\r
+       setvect(8,SDL_TimingService);           // Set to my timer 0 ISR\r
+\r
+       SDL_SetIntsPerSec(1000);                        // Time 1ms\r
+\r
+       for (i = 0,timer = 0;i < 10;i++)        // Do timing test 10 times\r
+       {\r
+       asm     xor             dx,dx                                   // Zero DX\r
+       asm     mov             cx,0xffff                               // Put starting value in CX\r
+       asm     mov             [TimerDone],cx                  // TimerDone = false - 1\r
+startloop:\r
+       asm     or              [TimerDone],0\r
+       asm     jnz             startloop                               // Make sure we're at the start\r
+loop:\r
+       asm     test    [TimerDone],1                   // See if TimerDone flag got hit\r
+       asm     jnz             done                                    // Yep - drop out of the loop\r
+       asm     loop    loop\r
+done:\r
+\r
+               if (0xffff - TimerVal > timer)\r
+                       timer = 0xffff - TimerVal;\r
+       }\r
+       timer += timer / 2;                                     // Use some slop\r
+       TimerDelay10 =  timer / (1000 / 10);\r
+       TimerDelay25 =  timer / (1000 / 25);\r
+       TimerDelay100 = timer / (1000 / 100);\r
+\r
+       SDL_SetTimer0(0);                                       // Reset timer 0\r
+\r
+       setvect(8,t0OldService);                        // Set back to old ISR\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_Delay() - Delays the specified amount of time\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_Delay(word delay)\r
+{\r
+       if (!delay)\r
+               return;\r
+\r
+asm    mov             cx,[delay]\r
+loop:\r
+asm    test    [TimerDone],0   // Useless code - just for timing equivilency\r
+asm    jnz             done\r
+asm    loop    loop\r
+done:;\r
+}\r
+#endif\r
+\r
+//\r
+//     PC Sound code\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
+///////////////////////////////////////////////////////////////////////////\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
+\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
+//     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
+#if 0\r
+       SDL_Delay(TimerDelay10);\r
+#else\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
+#endif\r
+\r
+asm    mov             dx,0x389\r
+asm    mov             al,[b]\r
+asm    out             dx,al\r
+\r
+asm    popf\r
+\r
+#if 0\r
+       SDL_Delay(TimerDelay25);\r
+#else\r
+asm    mov     dx,0x388\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
+#endif\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
+       byte            scale;  // added for "quiet AdLib" mode\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
+#if 1\r
+       // quiet AdLib code:\r
+       scale = inst->cScale;\r
+       if (QuietFX)\r
+       {\r
+               scale = 0x3F-scale;\r
+               scale = (scale>>1) + (scale>>2);        // basically 'scale *= 0.75;'\r
+               scale = 0x3F-scale;\r
+       }\r
+       alOut(c + alScale,scale);\r
+#else\r
+       // old code:\r
+       alOut(c + alScale,inst->cScale);\r
+#endif\r
+       alOut(c + alAttack,inst->cAttack);\r
+       alOut(c + alSus,inst->cSus);\r
+       alOut(c + alWave,inst->cWave);\r
+       // DEBUG!!! - I just put this in\r
+//     alOut(alFeedCon,inst->nConn);\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
+\r
+       SDL_ALStopSound();\r
+\r
+asm    pushf\r
+asm    cli\r
+\r
+       alLengthLeft = sound->common.length;\r
+       alSound = sound->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(inst);\r
+\r
+asm    popf\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_ALSoundService() - Plays the next sample out through the AdLib card\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static 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
+\r
+#if 0\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SDL_SelectMeasure() - sets up sequencing variables for a given track\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+SDL_SelectMeasure(ActiveTrack *track)\r
+{\r
+       track->seq = track->moods[track->mood];\r
+       track->nextevent = 0;\r
+}\r
+#endif\r
+\r
+static 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
+\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(boolean force)\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
+waitloop:\r
+       asm     in      al, dx;\r
+       asm     jmp     here;\r
+here:\r
+       asm     loop    waitloop;\r
+#endif\r
+\r
+       status2 = readstat();\r
+       alOut(4,0x60);\r
+       alOut(4,0x80);\r
+\r
+       if (force || (((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
+///////////////////////////////////////////////////////////////////////////\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 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,4    // red\r
+asm    out     dx,al\r
+#endif\r
+\r
+       HackCount++;\r
+\r
+       if (MusicMode == smm_AdLib)\r
+       {\r
+               SDL_ALService();\r
+               if (!(++count & 7))\r
+               {\r
+                       LocalTime++;\r
+                       TimeCount++;\r
+                       if (SoundUserHook)\r
+                               SoundUserHook();\r
+               }\r
+               if (!(count & 3))\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 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
+\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
+static void\r
+SDL_SetTimerSpeed(void)\r
+{\r
+       word    rate;\r
+\r
+       if (MusicMode == smm_AdLib)\r
+               rate = TickBase * 8;\r
+       else\r
+               rate = TickBase * 2;\r
+       SDL_SetIntsPerSec(rate);\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;\r
+       word    tableoffset;\r
+\r
+       SD_StopSound();\r
+\r
+#ifndef        _MUSE_\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
+       default:\r
+               result = false;\r
+               break;\r
+       }\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;\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
+       default:\r
+               result = false;\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
+       boolean alForce;\r
+\r
+       alForce = false;\r
+\r
+       if (SD_Started)\r
+               return;\r
+\r
+       ssIsTandy = false;\r
+       alNoCheck = 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
+\r
+               case 1:\r
+                       alForce = true;\r
+                       break;\r
+               }\r
+       }\r
+#endif\r
+\r
+       SoundUserHook = 0;\r
+\r
+       t0OldService = getvect(8);      // Get old timer 0 ISR\r
+\r
+       //SDL_InitDelay();                      // SDL_InitDelay() uses t0OldService\r
+\r
+       setvect(8,SDL_t0Service);       // Set to my timer 0 ISR\r
+       LocalTime = TimeCount = alTimeCount = 0;\r
+\r
+       SD_SetSoundMode(sdm_Off);\r
+       SD_SetMusicMode(smm_Off);\r
+\r
+       if (!alNoCheck)\r
+               AdLibPresent = SDL_DetectAdLib(alForce);\r
+\r
+       for (i = 0;i < 255;i++)\r
+               pcSoundLookup[i] = i * 60;\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:         // BUG: this should use smm_AdLib!\r
+                       gotsm = AdLibPresent;\r
+                       break;\r
+               }\r
+       }\r
+       if (!gotsm)\r
+       {\r
+               if (AdLibPresent)\r
+                       sm = smm_AdLib;\r
+               else\r
+                       sm = smm_Off;\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
+       SDL_ShutDevice();\r
+       SDL_CleanDevice();\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
+       // BUG: interrupts should be disabled while setting SoundUserHook!\r
+       SoundUserHook = hook;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     SD_PlaySound() - plays the specified sound on the appropriate hardware\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+SD_PlaySound(soundnames sound)\r
+{\r
+       SoundCommon     far *s;\r
+\r
+       if ((SoundMode == sdm_Off) /*|| (sound == -1)*/)\r
+               return;\r
+\r
+       s = MK_FP(SoundTable[sound],0);\r
+       if (!s)\r
+               Quit("SD_PlaySound() - Uncached sound");\r
+       if (!s->length)\r
+               Quit("SD_PlaySound() - Zero length sound");\r
+       if (s->priority < SoundPriority)\r
+               return;\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
+\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
+       switch (SoundMode)\r
+       {\r
+       case sdm_PC:\r
+               SDL_PCStopSound();\r
+               break;\r
+       case sdm_AdLib:\r
+               SDL_ALStopSound();\r
+               break;\r
+       }\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