--- /dev/null
+/* 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