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