wolf3d

The original open source release of Wolfenstein 3D
Log | Files | Refs

ID_SD.C (48057B)


      1 //
      2 //	ID Engine
      3 //	ID_SD.c - Sound Manager for Wolfenstein 3D
      4 //	v1.2
      5 //	By Jason Blochowiak
      6 //
      7 
      8 //
      9 //	This module handles dealing with generating sound on the appropriate
     10 //		hardware
     11 //
     12 //	Depends on: User Mgr (for parm checking)
     13 //
     14 //	Globals:
     15 //		For User Mgr:
     16 //			SoundSourcePresent - Sound Source thingie present?
     17 //			SoundBlasterPresent - SoundBlaster card present?
     18 //			AdLibPresent - AdLib card present?
     19 //			SoundMode - What device is used for sound effects
     20 //				(Use SM_SetSoundMode() to set)
     21 //			MusicMode - What device is used for music
     22 //				(Use SM_SetMusicMode() to set)
     23 //			DigiMode - What device is used for digitized sound effects
     24 //				(Use SM_SetDigiDevice() to set)
     25 //
     26 //		For Cache Mgr:
     27 //			NeedsDigitized - load digitized sounds?
     28 //			NeedsMusic - load music?
     29 //
     30 
     31 #pragma hdrstop		// Wierdo thing with MUSE
     32 
     33 #include <dos.h>
     34 
     35 #ifdef	_MUSE_      // Will be defined in ID_Types.h
     36 #include "ID_SD.h"
     37 #else
     38 #include "ID_HEADS.H"
     39 #endif
     40 #pragma	hdrstop
     41 #pragma	warn	-pia
     42 
     43 #ifdef	nil
     44 #undef	nil
     45 #endif
     46 #define	nil	0
     47 
     48 #define	SDL_SoundFinished()	{SoundNumber = SoundPriority = 0;}
     49 
     50 // Macros for SoundBlaster stuff
     51 #define	sbOut(n,b)	outportb((n) + sbLocation,b)
     52 #define	sbIn(n)		inportb((n) + sbLocation)
     53 #define	sbWriteDelay()	while (sbIn(sbWriteStat) & 0x80);
     54 #define	sbReadDelay()	while (sbIn(sbDataAvail) & 0x80);
     55 
     56 // Macros for AdLib stuff
     57 #define	selreg(n)	outportb(alFMAddr,n)
     58 #define	writereg(n)	outportb(alFMData,n)
     59 #define	readstat()	inportb(alFMStatus)
     60 
     61 //	Imports from ID_SD_A.ASM
     62 extern	void			SDL_SetDS(void),
     63 						SDL_IndicatePC(boolean on);
     64 extern	void interrupt	SDL_t0ExtremeAsmService(void),
     65 						SDL_t0FastAsmService(void),
     66 						SDL_t0SlowAsmService(void);
     67 
     68 //	Global variables
     69 	boolean		SoundSourcePresent,
     70 				AdLibPresent,
     71 				SoundBlasterPresent,SBProPresent,
     72 				NeedsDigitized,NeedsMusic,
     73 				SoundPositioned;
     74 	SDMode		SoundMode;
     75 	SMMode		MusicMode;
     76 	SDSMode		DigiMode;
     77 	longword	TimeCount;
     78 	word		HackCount;
     79 	word		*SoundTable;	// Really * _seg *SoundTable, but that don't work
     80 	boolean		ssIsTandy;
     81 	word		ssPort = 2;
     82 	int			DigiMap[LASTSOUND];
     83 
     84 //	Internal variables
     85 static	boolean			SD_Started;
     86 		boolean			nextsoundpos;
     87 		longword		TimerDivisor,TimerCount;
     88 static	char			*ParmStrings[] =
     89 						{
     90 							"noal",
     91 							"nosb",
     92 							"nopro",
     93 							"noss",
     94 							"sst",
     95 							"ss1",
     96 							"ss2",
     97 							"ss3",
     98 							nil
     99 						};
    100 static	void			(*SoundUserHook)(void);
    101 		soundnames		SoundNumber,DigiNumber;
    102 		word			SoundPriority,DigiPriority;
    103 		int				LeftPosition,RightPosition;
    104 		void interrupt	(*t0OldService)(void);
    105 		long			LocalTime;
    106 		word			TimerRate;
    107 
    108 		word			NumDigi,DigiLeft,DigiPage;
    109 		word			_seg *DigiList;
    110 		word			DigiLastStart,DigiLastEnd;
    111 		boolean			DigiPlaying;
    112 static	boolean			DigiMissed,DigiLastSegment;
    113 static	memptr			DigiNextAddr;
    114 static	word			DigiNextLen;
    115 
    116 //	SoundBlaster variables
    117 static	boolean					sbNoCheck,sbNoProCheck;
    118 static	volatile boolean		sbSamplePlaying;
    119 static	byte					sbOldIntMask = -1;
    120 static	volatile byte			huge *sbNextSegPtr;
    121 static	byte					sbDMA = 1,
    122 								sbDMAa1 = 0x83,sbDMAa2 = 2,sbDMAa3 = 3,
    123 								sba1Vals[] = {0x87,0x83,0,0x82},
    124 								sba2Vals[] = {0,2,0,6},
    125 								sba3Vals[] = {1,3,0,7};
    126 static	int						sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf,
    127 								sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf,-1,-1,-1};
    128 static	volatile longword		sbNextSegLen;
    129 static	volatile SampledSound	huge *sbSamples;
    130 static	void interrupt			(*sbOldIntHand)(void);
    131 static	byte					sbpOldFMMix,sbpOldVOCMix;
    132 
    133 //	SoundSource variables
    134 		boolean				ssNoCheck;
    135 		boolean				ssActive;
    136 		word				ssControl,ssStatus,ssData;
    137 		byte				ssOn,ssOff;
    138 		volatile byte		far *ssSample;
    139 		volatile longword	ssLengthLeft;
    140 
    141 //	PC Sound variables
    142 		volatile byte	pcLastSample,far *pcSound;
    143 		longword		pcLengthLeft;
    144 		word			pcSoundLookup[255];
    145 
    146 //	AdLib variables
    147 		boolean			alNoCheck;
    148 		byte			far *alSound;
    149 		word			alBlock;
    150 		longword		alLengthLeft;
    151 		longword		alTimeCount;
    152 		Instrument		alZeroInst;
    153 
    154 // This table maps channel numbers to carrier and modulator op cells
    155 static	byte			carriers[9] =  { 3, 4, 5,11,12,13,19,20,21},
    156 						modifiers[9] = { 0, 1, 2, 8, 9,10,16,17,18},
    157 // This table maps percussive voice numbers to op cells
    158 						pcarriers[5] = {19,0xff,0xff,0xff,0xff},
    159 						pmodifiers[5] = {16,17,18,20,21};
    160 
    161 //	Sequencer variables
    162 		boolean			sqActive;
    163 static	word			alFXReg;
    164 static	ActiveTrack		*tracks[sqMaxTracks],
    165 						mytracks[sqMaxTracks];
    166 static	word			sqMode,sqFadeStep;
    167 		word			far *sqHack,far *sqHackPtr,sqHackLen,sqHackSeqLen;
    168 		long			sqHackTime;
    169 
    170 //	Internal routines
    171 		void			SDL_DigitizedDone(void);
    172 
    173 ///////////////////////////////////////////////////////////////////////////
    174 //
    175 //	SDL_SetTimer0() - Sets system timer 0 to the specified speed
    176 //
    177 ///////////////////////////////////////////////////////////////////////////
    178 #pragma	argsused
    179 static void
    180 SDL_SetTimer0(word speed)
    181 {
    182 #ifndef TPROF	// If using Borland's profiling, don't screw with the timer
    183 asm	pushf
    184 asm	cli
    185 
    186 	outportb(0x43,0x36);				// Change timer 0
    187 	outportb(0x40,speed);
    188 	outportb(0x40,speed >> 8);
    189 	// Kludge to handle special case for digitized PC sounds
    190 	if (TimerDivisor == (1192030 / (TickBase * 100)))
    191 		TimerDivisor = (1192030 / (TickBase * 10));
    192 	else
    193 		TimerDivisor = speed;
    194 
    195 asm	popf
    196 #else
    197 	TimerDivisor = 0x10000;
    198 #endif
    199 }
    200 
    201 ///////////////////////////////////////////////////////////////////////////
    202 //
    203 //	SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
    204 //		interrupts generated by system timer 0 per second
    205 //
    206 ///////////////////////////////////////////////////////////////////////////
    207 static void
    208 SDL_SetIntsPerSec(word ints)
    209 {
    210 	TimerRate = ints;
    211 	SDL_SetTimer0(1192030 / ints);
    212 }
    213 
    214 static void
    215 SDL_SetTimerSpeed(void)
    216 {
    217 	word	rate;
    218 	void interrupt	(*isr)(void);
    219 
    220 	if ((DigiMode == sds_PC) && DigiPlaying)
    221 	{
    222 		rate = TickBase * 100;
    223 		isr = SDL_t0ExtremeAsmService;
    224 	}
    225 	else if
    226 	(
    227 		(MusicMode == smm_AdLib)
    228 	||	((DigiMode == sds_SoundSource) && DigiPlaying)
    229 	)
    230 	{
    231 		rate = TickBase * 10;
    232 		isr = SDL_t0FastAsmService;
    233 	}
    234 	else
    235 	{
    236 		rate = TickBase * 2;
    237 		isr = SDL_t0SlowAsmService;
    238 	}
    239 
    240 	if (rate != TimerRate)
    241 	{
    242 		setvect(8,isr);
    243 		SDL_SetIntsPerSec(rate);
    244 		TimerRate = rate;
    245 	}
    246 }
    247 
    248 //
    249 //	SoundBlaster code
    250 //
    251 
    252 ///////////////////////////////////////////////////////////////////////////
    253 //
    254 //	SDL_SBStopSample() - Stops any active sampled sound and causes DMA
    255 //		requests from the SoundBlaster to cease
    256 //
    257 ///////////////////////////////////////////////////////////////////////////
    258 #ifdef	_MUSE_
    259 void
    260 #else
    261 static void
    262 #endif
    263 SDL_SBStopSample(void)
    264 {
    265 	byte	is;
    266 
    267 asm	pushf
    268 asm	cli
    269 
    270 	if (sbSamplePlaying)
    271 	{
    272 		sbSamplePlaying = false;
    273 
    274 		sbWriteDelay();
    275 		sbOut(sbWriteCmd,0xd0);	// Turn off DSP DMA
    276 
    277 		is = inportb(0x21);	// Restore interrupt mask bit
    278 		if (sbOldIntMask & (1 << sbInterrupt))
    279 			is |= (1 << sbInterrupt);
    280 		else
    281 			is &= ~(1 << sbInterrupt);
    282 		outportb(0x21,is);
    283 	}
    284 
    285 asm	popf
    286 }
    287 
    288 ///////////////////////////////////////////////////////////////////////////
    289 //
    290 //	SDL_SBPlaySeg() - Plays a chunk of sampled sound on the SoundBlaster
    291 //	Insures that the chunk doesn't cross a bank boundary, programs the DMA
    292 //	 controller, and tells the SB to start doing DMA requests for DAC
    293 //
    294 ///////////////////////////////////////////////////////////////////////////
    295 static longword
    296 SDL_SBPlaySeg(volatile byte huge *data,longword length)
    297 {
    298 	unsigned		datapage;
    299 	longword		dataofs,uselen;
    300 
    301 	uselen = length;
    302 	datapage = FP_SEG(data) >> 12;
    303 	dataofs = ((FP_SEG(data) & 0xfff) << 4) + FP_OFF(data);
    304 	if (dataofs >= 0x10000)
    305 	{
    306 		datapage++;
    307 		dataofs -= 0x10000;
    308 	}
    309 
    310 	if (dataofs + uselen > 0x10000)
    311 		uselen = 0x10000 - dataofs;
    312 
    313 	uselen--;
    314 
    315 	// Program the DMA controller
    316 asm	pushf
    317 asm	cli
    318 	outportb(0x0a,sbDMA | 4);					// Mask off DMA on channel sbDMA
    319 	outportb(0x0c,0);							// Clear byte ptr flip-flop to lower byte
    320 	outportb(0x0b,0x49);						// Set transfer mode for D/A conv
    321 	outportb(sbDMAa2,(byte)dataofs);			// Give LSB of address
    322 	outportb(sbDMAa2,(byte)(dataofs >> 8));		// Give MSB of address
    323 	outportb(sbDMAa1,(byte)datapage);			// Give page of address
    324 	outportb(sbDMAa3,(byte)uselen);				// Give LSB of length
    325 	outportb(sbDMAa3,(byte)(uselen >> 8));		// Give MSB of length
    326 	outportb(0x0a,sbDMA);						// Re-enable DMA on channel sbDMA
    327 
    328 	// Start playing the thing
    329 	sbWriteDelay();
    330 	sbOut(sbWriteCmd,0x14);
    331 	sbWriteDelay();
    332 	sbOut(sbWriteData,(byte)uselen);
    333 	sbWriteDelay();
    334 	sbOut(sbWriteData,(byte)(uselen >> 8));
    335 asm	popf
    336 
    337 	return(uselen + 1);
    338 }
    339 
    340 ///////////////////////////////////////////////////////////////////////////
    341 //
    342 //	SDL_SBService() - Services the SoundBlaster DMA interrupt
    343 //
    344 ///////////////////////////////////////////////////////////////////////////
    345 static void interrupt
    346 SDL_SBService(void)
    347 {
    348 	longword	used;
    349 
    350 	sbIn(sbDataAvail);	// Ack interrupt to SB
    351 
    352 	if (sbNextSegPtr)
    353 	{
    354 		used = SDL_SBPlaySeg(sbNextSegPtr,sbNextSegLen);
    355 		if (sbNextSegLen <= used)
    356 			sbNextSegPtr = nil;
    357 		else
    358 		{
    359 			sbNextSegPtr += used;
    360 			sbNextSegLen -= used;
    361 		}
    362 	}
    363 	else
    364 	{
    365 		SDL_SBStopSample();
    366 		SDL_DigitizedDone();
    367 	}
    368 
    369 	outportb(0x20,0x20);	// Ack interrupt
    370 }
    371 
    372 ///////////////////////////////////////////////////////////////////////////
    373 //
    374 //	SDL_SBPlaySample() - Plays a sampled sound on the SoundBlaster. Sets up
    375 //		DMA to play the sound
    376 //
    377 ///////////////////////////////////////////////////////////////////////////
    378 #ifdef	_MUSE_
    379 void
    380 #else
    381 static void
    382 #endif
    383 SDL_SBPlaySample(byte huge *data,longword len)
    384 {
    385 	longword	used;
    386 
    387 	SDL_SBStopSample();
    388 
    389 asm	pushf
    390 asm	cli
    391 
    392 	used = SDL_SBPlaySeg(data,len);
    393 	if (len <= used)
    394 		sbNextSegPtr = nil;
    395 	else
    396 	{
    397 		sbNextSegPtr = data + used;
    398 		sbNextSegLen = len - used;
    399 	}
    400 
    401 	// Save old interrupt status and unmask ours
    402 	sbOldIntMask = inportb(0x21);
    403 	outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));
    404 
    405 	sbWriteDelay();
    406 	sbOut(sbWriteCmd,0xd4);						// Make sure DSP DMA is enabled
    407 
    408 	sbSamplePlaying = true;
    409 
    410 asm	popf
    411 }
    412 
    413 ///////////////////////////////////////////////////////////////////////////
    414 //
    415 //	SDL_PositionSBP() - Sets the attenuation levels for the left and right
    416 //		channels by using the mixer chip on the SB Pro. This hits a hole in
    417 //		the address map for normal SBs.
    418 //
    419 ///////////////////////////////////////////////////////////////////////////
    420 static void
    421 SDL_PositionSBP(int leftpos,int rightpos)
    422 {
    423 	byte	v;
    424 
    425 	if (!SBProPresent)
    426 		return;
    427 
    428 	leftpos = 15 - leftpos;
    429 	rightpos = 15 - rightpos;
    430 	v = ((leftpos & 0x0f) << 4) | (rightpos & 0x0f);
    431 
    432 asm	pushf
    433 asm	cli
    434 
    435 	sbOut(sbpMixerAddr,sbpmVoiceVol);
    436 	sbOut(sbpMixerData,v);
    437 
    438 asm	popf
    439 }
    440 
    441 ///////////////////////////////////////////////////////////////////////////
    442 //
    443 //	SDL_CheckSB() - Checks to see if a SoundBlaster resides at a
    444 //		particular I/O location
    445 //
    446 ///////////////////////////////////////////////////////////////////////////
    447 static boolean
    448 SDL_CheckSB(int port)
    449 {
    450 	int	i;
    451 
    452 	sbLocation = port << 4;		// Initialize stuff for later use
    453 
    454 	sbOut(sbReset,true);		// Reset the SoundBlaster DSP
    455 asm	mov	dx,0x388				// Wait >4usec
    456 asm	in	al, dx
    457 asm	in	al, dx
    458 asm	in	al, dx
    459 asm	in	al, dx
    460 asm	in	al, dx
    461 asm	in	al, dx
    462 asm	in	al, dx
    463 asm	in	al, dx
    464 asm	in	al, dx
    465 
    466 	sbOut(sbReset,false);		// Turn off sb DSP reset
    467 asm	mov	dx,0x388				// Wait >100usec
    468 asm	mov	cx,100
    469 usecloop:
    470 asm	in	al,dx
    471 asm	loop usecloop
    472 
    473 	for (i = 0;i < 100;i++)
    474 	{
    475 		if (sbIn(sbDataAvail) & 0x80)		// If data is available...
    476 		{
    477 			if (sbIn(sbReadData) == 0xaa)	// If it matches correct value
    478 				return(true);
    479 			else
    480 			{
    481 				sbLocation = -1;			// Otherwise not a SoundBlaster
    482 				return(false);
    483 			}
    484 		}
    485 	}
    486 	sbLocation = -1;						// Retry count exceeded - fail
    487 	return(false);
    488 }
    489 
    490 ///////////////////////////////////////////////////////////////////////////
    491 //
    492 //	Checks to see if a SoundBlaster is in the system. If the port passed is
    493 //		-1, then it scans through all possible I/O locations. If the port
    494 //		passed is 0, then it uses the default (2). If the port is >0, then
    495 //		it just passes it directly to SDL_CheckSB()
    496 //
    497 ///////////////////////////////////////////////////////////////////////////
    498 static boolean
    499 SDL_DetectSoundBlaster(int port)
    500 {
    501 	int	i;
    502 
    503 	if (port == 0)					// If user specifies default, use 2
    504 		port = 2;
    505 	if (port == -1)
    506 	{
    507 		if (SDL_CheckSB(2))			// Check default before scanning
    508 			return(true);
    509 
    510 		if (SDL_CheckSB(4))			// Check other SB Pro location before scan
    511 			return(true);
    512 
    513 		for (i = 1;i <= 6;i++)		// Scan through possible SB locations
    514 		{
    515 			if ((i == 2) || (i == 4))
    516 				continue;
    517 
    518 			if (SDL_CheckSB(i))		// If found at this address,
    519 				return(true);		//	return success
    520 		}
    521 		return(false);				// All addresses failed, return failure
    522 	}
    523 	else
    524 		return(SDL_CheckSB(port));	// User specified address or default
    525 }
    526 
    527 ///////////////////////////////////////////////////////////////////////////
    528 //
    529 //	SDL_SBSetDMA() - Sets the DMA channel to be used by the SoundBlaster
    530 //		code. Sets up sbDMA, and sbDMAa1-sbDMAa3 (used by SDL_SBPlaySeg()).
    531 //
    532 ///////////////////////////////////////////////////////////////////////////
    533 void
    534 SDL_SBSetDMA(byte channel)
    535 {
    536 	if (channel > 3)
    537 		Quit("SDL_SBSetDMA() - invalid SoundBlaster DMA channel");
    538 
    539 	sbDMA = channel;
    540 	sbDMAa1 = sba1Vals[channel];
    541 	sbDMAa2 = sba2Vals[channel];
    542 	sbDMAa3 = sba3Vals[channel];
    543 }
    544 
    545 ///////////////////////////////////////////////////////////////////////////
    546 //
    547 //	SDL_StartSB() - Turns on the SoundBlaster
    548 //
    549 ///////////////////////////////////////////////////////////////////////////
    550 static void
    551 SDL_StartSB(void)
    552 {
    553 	byte	timevalue,test;
    554 
    555 	sbIntVec = sbIntVectors[sbInterrupt];
    556 	if (sbIntVec < 0)
    557 		Quit("SDL_StartSB: Illegal or unsupported interrupt number for SoundBlaster");
    558 
    559 	sbOldIntHand = getvect(sbIntVec);	// Get old interrupt handler
    560 	setvect(sbIntVec,SDL_SBService);	// Set mine
    561 
    562 	sbWriteDelay();
    563 	sbOut(sbWriteCmd,0xd1);				// Turn on DSP speaker
    564 
    565 	// Set the SoundBlaster DAC time constant for 7KHz
    566 	timevalue = 256 - (1000000 / 7000);
    567 	sbWriteDelay();
    568 	sbOut(sbWriteCmd,0x40);
    569 	sbWriteDelay();
    570 	sbOut(sbWriteData,timevalue);
    571 
    572 	SBProPresent = false;
    573 	if (sbNoProCheck)
    574 		return;
    575 
    576 	// Check to see if this is a SB Pro
    577 	sbOut(sbpMixerAddr,sbpmFMVol);
    578 	sbpOldFMMix = sbIn(sbpMixerData);
    579 	sbOut(sbpMixerData,0xbb);
    580 	test = sbIn(sbpMixerData);
    581 	if (test == 0xbb)
    582 	{
    583 		// Boost FM output levels to be equivilent with digitized output
    584 		sbOut(sbpMixerData,0xff);
    585 		test = sbIn(sbpMixerData);
    586 		if (test == 0xff)
    587 		{
    588 			SBProPresent = true;
    589 
    590 			// Save old Voice output levels (SB Pro)
    591 			sbOut(sbpMixerAddr,sbpmVoiceVol);
    592 			sbpOldVOCMix = sbIn(sbpMixerData);
    593 
    594 			// Turn SB Pro stereo DAC off
    595 			sbOut(sbpMixerAddr,sbpmControl);
    596 			sbOut(sbpMixerData,0);				// 0=off,2=on
    597 		}
    598 	}
    599 }
    600 
    601 ///////////////////////////////////////////////////////////////////////////
    602 //
    603 //	SDL_ShutSB() - Turns off the SoundBlaster
    604 //
    605 ///////////////////////////////////////////////////////////////////////////
    606 static void
    607 SDL_ShutSB(void)
    608 {
    609 	SDL_SBStopSample();
    610 
    611 	if (SBProPresent)
    612 	{
    613 		// Restore FM output levels (SB Pro)
    614 		sbOut(sbpMixerAddr,sbpmFMVol);
    615 		sbOut(sbpMixerData,sbpOldFMMix);
    616 
    617 		// Restore Voice output levels (SB Pro)
    618 		sbOut(sbpMixerAddr,sbpmVoiceVol);
    619 		sbOut(sbpMixerData,sbpOldVOCMix);
    620 	}
    621 
    622 	setvect(sbIntVec,sbOldIntHand);		// Set vector back
    623 }
    624 
    625 //	Sound Source Code
    626 
    627 ///////////////////////////////////////////////////////////////////////////
    628 //
    629 //	SDL_SSStopSample() - Stops a sample playing on the Sound Source
    630 //
    631 ///////////////////////////////////////////////////////////////////////////
    632 #ifdef	_MUSE_
    633 void
    634 #else
    635 static void
    636 #endif
    637 SDL_SSStopSample(void)
    638 {
    639 asm	pushf
    640 asm	cli
    641 
    642 	(long)ssSample = 0;
    643 
    644 asm	popf
    645 }
    646 
    647 ///////////////////////////////////////////////////////////////////////////
    648 //
    649 //	SDL_SSService() - Handles playing the next sample on the Sound Source
    650 //
    651 ///////////////////////////////////////////////////////////////////////////
    652 static void
    653 SDL_SSService(void)
    654 {
    655 	boolean	gotit;
    656 	byte	v;
    657 
    658 	while (ssSample)
    659 	{
    660 	asm	mov		dx,[ssStatus]	// Check to see if FIFO is currently empty
    661 	asm	in		al,dx
    662 	asm	test	al,0x40
    663 	asm	jnz		done			// Nope - don't push any more data out
    664 
    665 		v = *ssSample++;
    666 		if (!(--ssLengthLeft))
    667 		{
    668 			(long)ssSample = 0;
    669 			SDL_DigitizedDone();
    670 		}
    671 
    672 	asm	mov		dx,[ssData]		// Pump the value out
    673 	asm	mov		al,[v]
    674 	asm	out		dx,al
    675 
    676 	asm	mov		dx,[ssControl]	// Pulse printer select
    677 	asm	mov		al,[ssOff]
    678 	asm	out		dx,al
    679 	asm	push	ax
    680 	asm	pop		ax
    681 	asm	mov		al,[ssOn]
    682 	asm	out		dx,al
    683 
    684 	asm	push	ax				// Delay a short while
    685 	asm	pop		ax
    686 	asm	push	ax
    687 	asm	pop		ax
    688 	}
    689 done:;
    690 }
    691 
    692 ///////////////////////////////////////////////////////////////////////////
    693 //
    694 //	SDL_SSPlaySample() - Plays the specified sample on the Sound Source
    695 //
    696 ///////////////////////////////////////////////////////////////////////////
    697 #ifdef	_MUSE_
    698 void
    699 #else
    700 static void
    701 #endif
    702 SDL_SSPlaySample(byte huge *data,longword len)
    703 {
    704 asm	pushf
    705 asm	cli
    706 
    707 	ssLengthLeft = len;
    708 	ssSample = (volatile byte far *)data;
    709 
    710 asm	popf
    711 }
    712 
    713 ///////////////////////////////////////////////////////////////////////////
    714 //
    715 //	SDL_StartSS() - Sets up for and turns on the Sound Source
    716 //
    717 ///////////////////////////////////////////////////////////////////////////
    718 static void
    719 SDL_StartSS(void)
    720 {
    721 	if (ssPort == 3)
    722 		ssControl = 0x27a;	// If using LPT3
    723 	else if (ssPort == 2)
    724 		ssControl = 0x37a;	// If using LPT2
    725 	else
    726 		ssControl = 0x3be;	// If using LPT1
    727 	ssStatus = ssControl - 1;
    728 	ssData = ssStatus - 1;
    729 
    730 	ssOn = 0x04;
    731 	if (ssIsTandy)
    732 		ssOff = 0x0e;				// Tandy wierdness
    733 	else
    734 		ssOff = 0x0c;				// For normal machines
    735 
    736 	outportb(ssControl,ssOn);		// Enable SS
    737 }
    738 
    739 ///////////////////////////////////////////////////////////////////////////
    740 //
    741 //	SDL_ShutSS() - Turns off the Sound Source
    742 //
    743 ///////////////////////////////////////////////////////////////////////////
    744 static void
    745 SDL_ShutSS(void)
    746 {
    747 	outportb(ssControl,ssOff);
    748 }
    749 
    750 ///////////////////////////////////////////////////////////////////////////
    751 //
    752 //	SDL_CheckSS() - Checks to see if a Sound Source is present at the
    753 //		location specified by the sound source variables
    754 //
    755 ///////////////////////////////////////////////////////////////////////////
    756 static boolean
    757 SDL_CheckSS(void)
    758 {
    759 	boolean		present = false;
    760 	longword	lasttime;
    761 
    762 	// Turn the Sound Source on and wait awhile (4 ticks)
    763 	SDL_StartSS();
    764 
    765 	lasttime = TimeCount;
    766 	while (TimeCount < lasttime + 4)
    767 		;
    768 
    769 asm	mov		dx,[ssStatus]	// Check to see if FIFO is currently empty
    770 asm	in		al,dx
    771 asm	test	al,0x40
    772 asm	jnz		checkdone		// Nope - Sound Source not here
    773 
    774 asm	mov		cx,32			// Force FIFO overflow (FIFO is 16 bytes)
    775 outloop:
    776 asm	mov		dx,[ssData]		// Pump a neutral value out
    777 asm	mov		al,0x80
    778 asm	out		dx,al
    779 
    780 asm	mov		dx,[ssControl]	// Pulse printer select
    781 asm	mov		al,[ssOff]
    782 asm	out		dx,al
    783 asm	push	ax
    784 asm	pop		ax
    785 asm	mov		al,[ssOn]
    786 asm	out		dx,al
    787 
    788 asm	push	ax				// Delay a short while before we do this again
    789 asm	pop		ax
    790 asm	push	ax
    791 asm	pop		ax
    792 
    793 asm	loop	outloop
    794 
    795 asm	mov		dx,[ssStatus]	// Is FIFO overflowed now?
    796 asm	in		al,dx
    797 asm	test	al,0x40
    798 asm	jz		checkdone		// Nope, still not - Sound Source not here
    799 
    800 	present = true;			// Yes - it's here!
    801 
    802 checkdone:
    803 	SDL_ShutSS();
    804 	return(present);
    805 }
    806 
    807 static boolean
    808 SDL_DetectSoundSource(void)
    809 {
    810 	for (ssPort = 1;ssPort <= 3;ssPort++)
    811 		if (SDL_CheckSS())
    812 			return(true);
    813 	return(false);
    814 }
    815 
    816 //
    817 //	PC Sound code
    818 //
    819 
    820 ///////////////////////////////////////////////////////////////////////////
    821 //
    822 //	SDL_PCPlaySample() - Plays the specified sample on the PC speaker
    823 //
    824 ///////////////////////////////////////////////////////////////////////////
    825 #ifdef	_MUSE_
    826 void
    827 #else
    828 static void
    829 #endif
    830 SDL_PCPlaySample(byte huge *data,longword len)
    831 {
    832 asm	pushf
    833 asm	cli
    834 
    835 	SDL_IndicatePC(true);
    836 
    837 	pcLengthLeft = len;
    838 	pcSound = (volatile byte far *)data;
    839 
    840 asm	popf
    841 }
    842 
    843 ///////////////////////////////////////////////////////////////////////////
    844 //
    845 //	SDL_PCStopSample() - Stops a sample playing on the PC speaker
    846 //
    847 ///////////////////////////////////////////////////////////////////////////
    848 #ifdef	_MUSE_
    849 void
    850 #else
    851 static void
    852 #endif
    853 SDL_PCStopSample(void)
    854 {
    855 asm	pushf
    856 asm	cli
    857 
    858 	(long)pcSound = 0;
    859 
    860 	SDL_IndicatePC(false);
    861 
    862 asm	in	al,0x61		  	// Turn the speaker off
    863 asm	and	al,0xfd			// ~2
    864 asm	out	0x61,al
    865 
    866 asm	popf
    867 }
    868 
    869 ///////////////////////////////////////////////////////////////////////////
    870 //
    871 //	SDL_PCPlaySound() - Plays the specified sound on the PC speaker
    872 //
    873 ///////////////////////////////////////////////////////////////////////////
    874 #ifdef	_MUSE_
    875 void
    876 #else
    877 static void
    878 #endif
    879 SDL_PCPlaySound(PCSound far *sound)
    880 {
    881 asm	pushf
    882 asm	cli
    883 
    884 	pcLastSample = -1;
    885 	pcLengthLeft = sound->common.length;
    886 	pcSound = sound->data;
    887 
    888 asm	popf
    889 }
    890 
    891 ///////////////////////////////////////////////////////////////////////////
    892 //
    893 //	SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
    894 //
    895 ///////////////////////////////////////////////////////////////////////////
    896 #ifdef	_MUSE_
    897 void
    898 #else
    899 static void
    900 #endif
    901 SDL_PCStopSound(void)
    902 {
    903 asm	pushf
    904 asm	cli
    905 
    906 	(long)pcSound = 0;
    907 
    908 asm	in	al,0x61		  	// Turn the speaker off
    909 asm	and	al,0xfd			// ~2
    910 asm	out	0x61,al
    911 
    912 asm	popf
    913 }
    914 
    915 #if 0
    916 ///////////////////////////////////////////////////////////////////////////
    917 //
    918 //	SDL_PCService() - Handles playing the next sample in a PC sound
    919 //
    920 ///////////////////////////////////////////////////////////////////////////
    921 static void
    922 SDL_PCService(void)
    923 {
    924 	byte	s;
    925 	word	t;
    926 
    927 	if (pcSound)
    928 	{
    929 		s = *pcSound++;
    930 		if (s != pcLastSample)
    931 		{
    932 		asm	pushf
    933 		asm	cli
    934 
    935 			pcLastSample = s;
    936 			if (s)					// We have a frequency!
    937 			{
    938 				t = pcSoundLookup[s];
    939 			asm	mov	bx,[t]
    940 
    941 			asm	mov	al,0xb6			// Write to channel 2 (speaker) timer
    942 			asm	out	43h,al
    943 			asm	mov	al,bl
    944 			asm	out	42h,al			// Low byte
    945 			asm	mov	al,bh
    946 			asm	out	42h,al			// High byte
    947 
    948 			asm	in	al,0x61			// Turn the speaker & gate on
    949 			asm	or	al,3
    950 			asm	out	0x61,al
    951 			}
    952 			else					// Time for some silence
    953 			{
    954 			asm	in	al,0x61		  	// Turn the speaker & gate off
    955 			asm	and	al,0xfc			// ~3
    956 			asm	out	0x61,al
    957 			}
    958 
    959 		asm	popf
    960 		}
    961 
    962 		if (!(--pcLengthLeft))
    963 		{
    964 			SDL_PCStopSound();
    965 			SDL_SoundFinished();
    966 		}
    967 	}
    968 }
    969 #endif
    970 
    971 ///////////////////////////////////////////////////////////////////////////
    972 //
    973 //	SDL_ShutPC() - Turns off the pc speaker
    974 //
    975 ///////////////////////////////////////////////////////////////////////////
    976 static void
    977 SDL_ShutPC(void)
    978 {
    979 asm	pushf
    980 asm	cli
    981 
    982 	pcSound = 0;
    983 
    984 asm	in	al,0x61		  	// Turn the speaker & gate off
    985 asm	and	al,0xfc			// ~3
    986 asm	out	0x61,al
    987 
    988 asm	popf
    989 }
    990 
    991 //
    992 //	Stuff for digitized sounds
    993 //
    994 memptr
    995 SDL_LoadDigiSegment(word page)
    996 {
    997 	memptr	addr;
    998 
    999 #if 0	// for debugging
   1000 asm	mov	dx,STATUS_REGISTER_1
   1001 asm	in	al,dx
   1002 asm	mov	dx,ATR_INDEX
   1003 asm	mov	al,ATR_OVERSCAN
   1004 asm	out	dx,al
   1005 asm	mov	al,10	// bright green
   1006 asm	out	dx,al
   1007 #endif
   1008 
   1009 	addr = PM_GetSoundPage(page);
   1010 	PM_SetPageLock(PMSoundStart + page,pml_Locked);
   1011 
   1012 #if 0	// for debugging
   1013 asm	mov	dx,STATUS_REGISTER_1
   1014 asm	in	al,dx
   1015 asm	mov	dx,ATR_INDEX
   1016 asm	mov	al,ATR_OVERSCAN
   1017 asm	out	dx,al
   1018 asm	mov	al,3	// blue
   1019 asm	out	dx,al
   1020 asm	mov	al,0x20	// normal
   1021 asm	out	dx,al
   1022 #endif
   1023 
   1024 	return(addr);
   1025 }
   1026 
   1027 void
   1028 SDL_PlayDigiSegment(memptr addr,word len)
   1029 {
   1030 	switch (DigiMode)
   1031 	{
   1032 	case sds_PC:
   1033     	SDL_PCPlaySample(addr,len);
   1034 		break;
   1035 	case sds_SoundSource:
   1036 		SDL_SSPlaySample(addr,len);
   1037 		break;
   1038 	case sds_SoundBlaster:
   1039 		SDL_SBPlaySample(addr,len);
   1040 		break;
   1041 	}
   1042 }
   1043 
   1044 void
   1045 SD_StopDigitized(void)
   1046 {
   1047 	int	i;
   1048 
   1049 asm	pushf
   1050 asm	cli
   1051 
   1052 	DigiLeft = 0;
   1053 	DigiNextAddr = nil;
   1054 	DigiNextLen = 0;
   1055 	DigiMissed = false;
   1056 	DigiPlaying = false;
   1057 	DigiNumber = DigiPriority = 0;
   1058 	SoundPositioned = false;
   1059 	if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
   1060 		SDL_SoundFinished();
   1061 
   1062 	switch (DigiMode)
   1063 	{
   1064 	case sds_PC:
   1065 		SDL_PCStopSample();
   1066 		break;
   1067 	case sds_SoundSource:
   1068 		SDL_SSStopSample();
   1069 		break;
   1070 	case sds_SoundBlaster:
   1071 		SDL_SBStopSample();
   1072 		break;
   1073 	}
   1074 
   1075 asm	popf
   1076 
   1077 	for (i = DigiLastStart;i < DigiLastEnd;i++)
   1078 		PM_SetPageLock(i + PMSoundStart,pml_Unlocked);
   1079 	DigiLastStart = 1;
   1080 	DigiLastEnd = 0;
   1081 }
   1082 
   1083 void
   1084 SD_Poll(void)
   1085 {
   1086 	if (DigiLeft && !DigiNextAddr)
   1087 	{
   1088 		DigiNextLen = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
   1089 		DigiLeft -= DigiNextLen;
   1090 		if (!DigiLeft)
   1091 			DigiLastSegment = true;
   1092 		DigiNextAddr = SDL_LoadDigiSegment(DigiPage++);
   1093 	}
   1094 	if (DigiMissed && DigiNextAddr)
   1095 	{
   1096 		SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
   1097 		DigiNextAddr = nil;
   1098 		DigiMissed = false;
   1099 		if (DigiLastSegment)
   1100 		{
   1101 			DigiPlaying = false;
   1102 			DigiLastSegment = false;
   1103 		}
   1104 	}
   1105 	SDL_SetTimerSpeed();
   1106 }
   1107 
   1108 void
   1109 SD_SetPosition(int leftpos,int rightpos)
   1110 {
   1111 	if
   1112 	(
   1113 		(leftpos < 0)
   1114 	||	(leftpos > 15)
   1115 	||	(rightpos < 0)
   1116 	||	(rightpos > 15)
   1117 	||	((leftpos == 15) && (rightpos == 15))
   1118 	)
   1119 		Quit("SD_SetPosition: Illegal position");
   1120 
   1121 	switch (DigiMode)
   1122 	{
   1123 	case sds_SoundBlaster:
   1124 		SDL_PositionSBP(leftpos,rightpos);
   1125 		break;
   1126 	}
   1127 }
   1128 
   1129 void
   1130 SD_PlayDigitized(word which,int leftpos,int rightpos)
   1131 {
   1132 	word	len;
   1133 	memptr	addr;
   1134 
   1135 	if (!DigiMode)
   1136 		return;
   1137 
   1138 	SD_StopDigitized();
   1139 	if (which >= NumDigi)
   1140 		Quit("SD_PlayDigitized: bad sound number");
   1141 
   1142 	SD_SetPosition(leftpos,rightpos);
   1143 
   1144 	DigiPage = DigiList[(which * 2) + 0];
   1145 	DigiLeft = DigiList[(which * 2) + 1];
   1146 
   1147 	DigiLastStart = DigiPage;
   1148 	DigiLastEnd = DigiPage + ((DigiLeft + (PMPageSize - 1)) / PMPageSize);
   1149 
   1150 	len = (DigiLeft >= PMPageSize)? PMPageSize : (DigiLeft % PMPageSize);
   1151 	addr = SDL_LoadDigiSegment(DigiPage++);
   1152 
   1153 	DigiPlaying = true;
   1154 	DigiLastSegment = false;
   1155 
   1156 	SDL_PlayDigiSegment(addr,len);
   1157 	DigiLeft -= len;
   1158 	if (!DigiLeft)
   1159 		DigiLastSegment = true;
   1160 
   1161 	SD_Poll();
   1162 }
   1163 
   1164 void
   1165 SDL_DigitizedDone(void)
   1166 {
   1167 	if (DigiNextAddr)
   1168 	{
   1169 		SDL_PlayDigiSegment(DigiNextAddr,DigiNextLen);
   1170 		DigiNextAddr = nil;
   1171 		DigiMissed = false;
   1172 	}
   1173 	else
   1174 	{
   1175 		if (DigiLastSegment)
   1176 		{
   1177 			DigiPlaying = false;
   1178 			DigiLastSegment = false;
   1179 			if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
   1180 			{
   1181 				SDL_SoundFinished();
   1182 			}
   1183 			else
   1184 				DigiNumber = DigiPriority = 0;
   1185 			SoundPositioned = false;
   1186 		}
   1187 		else
   1188 			DigiMissed = true;
   1189 	}
   1190 }
   1191 
   1192 void
   1193 SD_SetDigiDevice(SDSMode mode)
   1194 {
   1195 	boolean	devicenotpresent;
   1196 
   1197 	if (mode == DigiMode)
   1198 		return;
   1199 
   1200 	SD_StopDigitized();
   1201 
   1202 	devicenotpresent = false;
   1203 	switch (mode)
   1204 	{
   1205 	case sds_SoundBlaster:
   1206 		if (!SoundBlasterPresent)
   1207 		{
   1208 			if (SoundSourcePresent)
   1209 				mode = sds_SoundSource;
   1210 			else
   1211 				devicenotpresent = true;
   1212 		}
   1213 		break;
   1214 	case sds_SoundSource:
   1215 		if (!SoundSourcePresent)
   1216 			devicenotpresent = true;
   1217 		break;
   1218 	}
   1219 
   1220 	if (!devicenotpresent)
   1221 	{
   1222 		if (DigiMode == sds_SoundSource)
   1223 			SDL_ShutSS();
   1224 
   1225 		DigiMode = mode;
   1226 
   1227 		if (mode == sds_SoundSource)
   1228 			SDL_StartSS();
   1229 
   1230 		SDL_SetTimerSpeed();
   1231 	}
   1232 }
   1233 
   1234 void
   1235 SDL_SetupDigi(void)
   1236 {
   1237 	memptr	list;
   1238 	word	far *p,
   1239 			pg;
   1240 	int		i;
   1241 
   1242 	PM_UnlockMainMem();
   1243 	MM_GetPtr(&list,PMPageSize);
   1244 	PM_CheckMainMem();
   1245 	p = (word far *)MK_FP(PM_GetPage(ChunksInFile - 1),0);
   1246 	_fmemcpy((void far *)list,(void far *)p,PMPageSize);
   1247 	pg = PMSoundStart;
   1248 	for (i = 0;i < PMPageSize / (sizeof(word) * 2);i++,p += 2)
   1249 	{
   1250 		if (pg >= ChunksInFile - 1)
   1251 			break;
   1252 		pg += (p[1] + (PMPageSize - 1)) / PMPageSize;
   1253 	}
   1254 	PM_UnlockMainMem();
   1255 	MM_GetPtr((memptr *)&DigiList,i * sizeof(word) * 2);
   1256 	_fmemcpy((void far *)DigiList,(void far *)list,i * sizeof(word) * 2);
   1257 	MM_FreePtr(&list);
   1258 	NumDigi = i;
   1259 
   1260 	for (i = 0;i < LASTSOUND;i++)
   1261 		DigiMap[i] = -1;
   1262 }
   1263 
   1264 // 	AdLib Code
   1265 
   1266 ///////////////////////////////////////////////////////////////////////////
   1267 //
   1268 //	alOut(n,b) - Puts b in AdLib card register n
   1269 //
   1270 ///////////////////////////////////////////////////////////////////////////
   1271 void
   1272 alOut(byte n,byte b)
   1273 {
   1274 asm	pushf
   1275 asm	cli
   1276 
   1277 asm	mov	dx,0x388
   1278 asm	mov	al,[n]
   1279 asm	out	dx,al
   1280 asm	in	al,dx
   1281 asm	in	al,dx
   1282 asm	in	al,dx
   1283 asm	in	al,dx
   1284 asm	in	al,dx
   1285 asm	in	al,dx
   1286 asm	inc	dx
   1287 asm	mov	al,[b]
   1288 asm	out	dx,al
   1289 
   1290 asm	popf
   1291 
   1292 asm	dec	dx
   1293 asm	in	al,dx
   1294 asm	in	al,dx
   1295 asm	in	al,dx
   1296 asm	in	al,dx
   1297 asm	in	al,dx
   1298 asm	in	al,dx
   1299 asm	in	al,dx
   1300 asm	in	al,dx
   1301 asm	in	al,dx
   1302 asm	in	al,dx
   1303 
   1304 asm	in	al,dx
   1305 asm	in	al,dx
   1306 asm	in	al,dx
   1307 asm	in	al,dx
   1308 asm	in	al,dx
   1309 asm	in	al,dx
   1310 asm	in	al,dx
   1311 asm	in	al,dx
   1312 asm	in	al,dx
   1313 asm	in	al,dx
   1314 
   1315 asm	in	al,dx
   1316 asm	in	al,dx
   1317 asm	in	al,dx
   1318 asm	in	al,dx
   1319 asm	in	al,dx
   1320 asm	in	al,dx
   1321 asm	in	al,dx
   1322 asm	in	al,dx
   1323 asm	in	al,dx
   1324 asm	in	al,dx
   1325 
   1326 asm	in	al,dx
   1327 asm	in	al,dx
   1328 asm	in	al,dx
   1329 asm	in	al,dx
   1330 asm	in	al,dx
   1331 }
   1332 
   1333 #if 0
   1334 ///////////////////////////////////////////////////////////////////////////
   1335 //
   1336 //	SDL_SetInstrument() - Puts an instrument into a generator
   1337 //
   1338 ///////////////////////////////////////////////////////////////////////////
   1339 static void
   1340 SDL_SetInstrument(int track,int which,Instrument far *inst,boolean percussive)
   1341 {
   1342 	byte		c,m;
   1343 
   1344 	if (percussive)
   1345 	{
   1346 		c = pcarriers[which];
   1347 		m = pmodifiers[which];
   1348 	}
   1349 	else
   1350 	{
   1351 		c = carriers[which];
   1352 		m = modifiers[which];
   1353 	}
   1354 
   1355 	tracks[track - 1]->inst = *inst;
   1356 	tracks[track - 1]->percussive = percussive;
   1357 
   1358 	alOut(m + alChar,inst->mChar);
   1359 	alOut(m + alScale,inst->mScale);
   1360 	alOut(m + alAttack,inst->mAttack);
   1361 	alOut(m + alSus,inst->mSus);
   1362 	alOut(m + alWave,inst->mWave);
   1363 
   1364 	// Most percussive instruments only use one cell
   1365 	if (c != 0xff)
   1366 	{
   1367 		alOut(c + alChar,inst->cChar);
   1368 		alOut(c + alScale,inst->cScale);
   1369 		alOut(c + alAttack,inst->cAttack);
   1370 		alOut(c + alSus,inst->cSus);
   1371 		alOut(c + alWave,inst->cWave);
   1372 	}
   1373 
   1374 	alOut(which + alFeedCon,inst->nConn);	// DEBUG - I think this is right
   1375 }
   1376 #endif
   1377 
   1378 ///////////////////////////////////////////////////////////////////////////
   1379 //
   1380 //	SDL_ALStopSound() - Turns off any sound effects playing through the
   1381 //		AdLib card
   1382 //
   1383 ///////////////////////////////////////////////////////////////////////////
   1384 #ifdef	_MUSE_
   1385 void
   1386 #else
   1387 static void
   1388 #endif
   1389 SDL_ALStopSound(void)
   1390 {
   1391 asm	pushf
   1392 asm	cli
   1393 
   1394 	(long)alSound = 0;
   1395 	alOut(alFreqH + 0,0);
   1396 
   1397 asm	popf
   1398 }
   1399 
   1400 static void
   1401 SDL_AlSetFXInst(Instrument far *inst)
   1402 {
   1403 	byte		c,m;
   1404 
   1405 	m = modifiers[0];
   1406 	c = carriers[0];
   1407 	alOut(m + alChar,inst->mChar);
   1408 	alOut(m + alScale,inst->mScale);
   1409 	alOut(m + alAttack,inst->mAttack);
   1410 	alOut(m + alSus,inst->mSus);
   1411 	alOut(m + alWave,inst->mWave);
   1412 	alOut(c + alChar,inst->cChar);
   1413 	alOut(c + alScale,inst->cScale);
   1414 	alOut(c + alAttack,inst->cAttack);
   1415 	alOut(c + alSus,inst->cSus);
   1416 	alOut(c + alWave,inst->cWave);
   1417 
   1418 	// Note: Switch commenting on these lines for old MUSE compatibility
   1419 //	alOut(alFeedCon,inst->nConn);
   1420 	alOut(alFeedCon,0);
   1421 }
   1422 
   1423 ///////////////////////////////////////////////////////////////////////////
   1424 //
   1425 //	SDL_ALPlaySound() - Plays the specified sound on the AdLib card
   1426 //
   1427 ///////////////////////////////////////////////////////////////////////////
   1428 #ifdef	_MUSE_
   1429 void
   1430 #else
   1431 static void
   1432 #endif
   1433 SDL_ALPlaySound(AdLibSound far *sound)
   1434 {
   1435 	Instrument	far *inst;
   1436 	byte		huge *data;
   1437 
   1438 	SDL_ALStopSound();
   1439 
   1440 asm	pushf
   1441 asm	cli
   1442 
   1443 	alLengthLeft = sound->common.length;
   1444 	data = sound->data;
   1445 	data++;
   1446 	data--;
   1447 	alSound = (byte far *)data;
   1448 	alBlock = ((sound->block & 7) << 2) | 0x20;
   1449 	inst = &sound->inst;
   1450 
   1451 	if (!(inst->mSus | inst->cSus))
   1452 	{
   1453 	asm	popf
   1454 		Quit("SDL_ALPlaySound() - Bad instrument");
   1455 	}
   1456 
   1457 	SDL_AlSetFXInst(&alZeroInst);	// DEBUG
   1458 	SDL_AlSetFXInst(inst);
   1459 
   1460 asm	popf
   1461 }
   1462 
   1463 #if 0
   1464 ///////////////////////////////////////////////////////////////////////////
   1465 //
   1466 // 	SDL_ALSoundService() - Plays the next sample out through the AdLib card
   1467 //
   1468 ///////////////////////////////////////////////////////////////////////////
   1469 //static void
   1470 void
   1471 SDL_ALSoundService(void)
   1472 {
   1473 	byte	s;
   1474 
   1475 	if (alSound)
   1476 	{
   1477 		s = *alSound++;
   1478 		if (!s)
   1479 			alOut(alFreqH + 0,0);
   1480 		else
   1481 		{
   1482 			alOut(alFreqL + 0,s);
   1483 			alOut(alFreqH + 0,alBlock);
   1484 		}
   1485 
   1486 		if (!(--alLengthLeft))
   1487 		{
   1488 			(long)alSound = 0;
   1489 			alOut(alFreqH + 0,0);
   1490 			SDL_SoundFinished();
   1491 		}
   1492 	}
   1493 }
   1494 #endif
   1495 
   1496 #if 0
   1497 void
   1498 SDL_ALService(void)
   1499 {
   1500 	byte	a,v;
   1501 	word	w;
   1502 
   1503 	if (!sqActive)
   1504 		return;
   1505 
   1506 	while (sqHackLen && (sqHackTime <= alTimeCount))
   1507 	{
   1508 		w = *sqHackPtr++;
   1509 		sqHackTime = alTimeCount + *sqHackPtr++;
   1510 	asm	mov	dx,[w]
   1511 	asm	mov	[a],dl
   1512 	asm	mov	[v],dh
   1513 		alOut(a,v);
   1514 		sqHackLen -= 4;
   1515 	}
   1516 	alTimeCount++;
   1517 	if (!sqHackLen)
   1518 	{
   1519 		sqHackPtr = (word far *)sqHack;
   1520 		sqHackLen = sqHackSeqLen;
   1521 		alTimeCount = sqHackTime = 0;
   1522 	}
   1523 }
   1524 #endif
   1525 
   1526 ///////////////////////////////////////////////////////////////////////////
   1527 //
   1528 //	SDL_ShutAL() - Shuts down the AdLib card for sound effects
   1529 //
   1530 ///////////////////////////////////////////////////////////////////////////
   1531 static void
   1532 SDL_ShutAL(void)
   1533 {
   1534 asm	pushf
   1535 asm	cli
   1536 
   1537 	alOut(alEffects,0);
   1538 	alOut(alFreqH + 0,0);
   1539 	SDL_AlSetFXInst(&alZeroInst);
   1540 	alSound = 0;
   1541 
   1542 asm	popf
   1543 }
   1544 
   1545 ///////////////////////////////////////////////////////////////////////////
   1546 //
   1547 //	SDL_CleanAL() - Totally shuts down the AdLib card
   1548 //
   1549 ///////////////////////////////////////////////////////////////////////////
   1550 static void
   1551 SDL_CleanAL(void)
   1552 {
   1553 	int	i;
   1554 
   1555 asm	pushf
   1556 asm	cli
   1557 
   1558 	alOut(alEffects,0);
   1559 	for (i = 1;i < 0xf5;i++)
   1560 		alOut(i,0);
   1561 
   1562 asm	popf
   1563 }
   1564 
   1565 ///////////////////////////////////////////////////////////////////////////
   1566 //
   1567 //	SDL_StartAL() - Starts up the AdLib card for sound effects
   1568 //
   1569 ///////////////////////////////////////////////////////////////////////////
   1570 static void
   1571 SDL_StartAL(void)
   1572 {
   1573 	alFXReg = 0;
   1574 	alOut(alEffects,alFXReg);
   1575 	SDL_AlSetFXInst(&alZeroInst);
   1576 }
   1577 
   1578 ///////////////////////////////////////////////////////////////////////////
   1579 //
   1580 //	SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
   1581 //		emulating an AdLib) present
   1582 //
   1583 ///////////////////////////////////////////////////////////////////////////
   1584 static boolean
   1585 SDL_DetectAdLib(void)
   1586 {
   1587 	byte	status1,status2;
   1588 	int		i;
   1589 
   1590 	alOut(4,0x60);	// Reset T1 & T2
   1591 	alOut(4,0x80);	// Reset IRQ
   1592 	status1 = readstat();
   1593 	alOut(2,0xff);	// Set timer 1
   1594 	alOut(4,0x21);	// Start timer 1
   1595 #if 0
   1596 	SDL_Delay(TimerDelay100);
   1597 #else
   1598 asm	mov	dx,0x388
   1599 asm	mov	cx,100
   1600 usecloop:
   1601 asm	in	al,dx
   1602 asm	loop usecloop
   1603 #endif
   1604 
   1605 	status2 = readstat();
   1606 	alOut(4,0x60);
   1607 	alOut(4,0x80);
   1608 
   1609 	if (((status1 & 0xe0) == 0x00) && ((status2 & 0xe0) == 0xc0))
   1610 	{
   1611 		for (i = 1;i <= 0xf5;i++)	// Zero all the registers
   1612 			alOut(i,0);
   1613 
   1614 		alOut(1,0x20);	// Set WSE=1
   1615 		alOut(8,0);		// Set CSM=0 & SEL=0
   1616 
   1617 		return(true);
   1618 	}
   1619 	else
   1620 		return(false);
   1621 }
   1622 
   1623 #if 0
   1624 ///////////////////////////////////////////////////////////////////////////
   1625 //
   1626 //	SDL_t0Service() - My timer 0 ISR which handles the different timings and
   1627 //		dispatches to whatever other routines are appropriate
   1628 //
   1629 ///////////////////////////////////////////////////////////////////////////
   1630 static void interrupt
   1631 SDL_t0Service(void)
   1632 {
   1633 static	word	count = 1;
   1634 
   1635 #if 1	// for debugging
   1636 asm	mov	dx,STATUS_REGISTER_1
   1637 asm	in	al,dx
   1638 asm	mov	dx,ATR_INDEX
   1639 asm	mov	al,ATR_OVERSCAN
   1640 asm	out	dx,al
   1641 asm	mov	al,4	// red
   1642 asm	out	dx,al
   1643 #endif
   1644 
   1645 	HackCount++;
   1646 
   1647 	if ((MusicMode == smm_AdLib) || (DigiMode == sds_SoundSource))
   1648 	{
   1649 		SDL_ALService();
   1650 		SDL_SSService();
   1651 //		if (!(++count & 7))
   1652 		if (!(++count % 10))
   1653 		{
   1654 			LocalTime++;
   1655 			TimeCount++;
   1656 			if (SoundUserHook)
   1657 				SoundUserHook();
   1658 		}
   1659 //		if (!(count & 3))
   1660 		if (!(count % 5))
   1661 		{
   1662 			switch (SoundMode)
   1663 			{
   1664 			case sdm_PC:
   1665 				SDL_PCService();
   1666 				break;
   1667 			case sdm_AdLib:
   1668 				SDL_ALSoundService();
   1669 				break;
   1670 			}
   1671 		}
   1672 	}
   1673 	else
   1674 	{
   1675 		if (!(++count & 1))
   1676 		{
   1677 			LocalTime++;
   1678 			TimeCount++;
   1679 			if (SoundUserHook)
   1680 				SoundUserHook();
   1681 		}
   1682 		switch (SoundMode)
   1683 		{
   1684 		case sdm_PC:
   1685 			SDL_PCService();
   1686 			break;
   1687 		case sdm_AdLib:
   1688 			SDL_ALSoundService();
   1689 			break;
   1690 		}
   1691 	}
   1692 
   1693 asm	mov	ax,[WORD PTR TimerCount]
   1694 asm	add	ax,[WORD PTR TimerDivisor]
   1695 asm	mov	[WORD PTR TimerCount],ax
   1696 asm	jnc	myack
   1697 	t0OldService();			// If we overflow a word, time to call old int handler
   1698 asm	jmp	olddone
   1699 myack:;
   1700 	outportb(0x20,0x20);	// Ack the interrupt
   1701 olddone:;
   1702 
   1703 #if 1	// for debugging
   1704 asm	mov	dx,STATUS_REGISTER_1
   1705 asm	in	al,dx
   1706 asm	mov	dx,ATR_INDEX
   1707 asm	mov	al,ATR_OVERSCAN
   1708 asm	out	dx,al
   1709 asm	mov	al,3	// blue
   1710 asm	out	dx,al
   1711 asm	mov	al,0x20	// normal
   1712 asm	out	dx,al
   1713 #endif
   1714 }
   1715 #endif
   1716 
   1717 ////////////////////////////////////////////////////////////////////////////
   1718 //
   1719 //	SDL_ShutDevice() - turns off whatever device was being used for sound fx
   1720 //
   1721 ////////////////////////////////////////////////////////////////////////////
   1722 static void
   1723 SDL_ShutDevice(void)
   1724 {
   1725 	switch (SoundMode)
   1726 	{
   1727 	case sdm_PC:
   1728 		SDL_ShutPC();
   1729 		break;
   1730 	case sdm_AdLib:
   1731 		SDL_ShutAL();
   1732 		break;
   1733 	}
   1734 	SoundMode = sdm_Off;
   1735 }
   1736 
   1737 ///////////////////////////////////////////////////////////////////////////
   1738 //
   1739 //	SDL_CleanDevice() - totally shuts down all sound devices
   1740 //
   1741 ///////////////////////////////////////////////////////////////////////////
   1742 static void
   1743 SDL_CleanDevice(void)
   1744 {
   1745 	if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
   1746 		SDL_CleanAL();
   1747 }
   1748 
   1749 ///////////////////////////////////////////////////////////////////////////
   1750 //
   1751 //	SDL_StartDevice() - turns on whatever device is to be used for sound fx
   1752 //
   1753 ///////////////////////////////////////////////////////////////////////////
   1754 static void
   1755 SDL_StartDevice(void)
   1756 {
   1757 	switch (SoundMode)
   1758 	{
   1759 	case sdm_AdLib:
   1760 		SDL_StartAL();
   1761 		break;
   1762 	}
   1763 	SoundNumber = SoundPriority = 0;
   1764 }
   1765 
   1766 //	Public routines
   1767 
   1768 ///////////////////////////////////////////////////////////////////////////
   1769 //
   1770 //	SD_SetSoundMode() - Sets which sound hardware to use for sound effects
   1771 //
   1772 ///////////////////////////////////////////////////////////////////////////
   1773 boolean
   1774 SD_SetSoundMode(SDMode mode)
   1775 {
   1776 	boolean	result = false;
   1777 	word	tableoffset;
   1778 
   1779 	SD_StopSound();
   1780 
   1781 #ifndef	_MUSE_
   1782 	if ((mode == sdm_AdLib) && !AdLibPresent)
   1783 		mode = sdm_PC;
   1784 
   1785 	switch (mode)
   1786 	{
   1787 	case sdm_Off:
   1788 		NeedsDigitized = false;
   1789 		result = true;
   1790 		break;
   1791 	case sdm_PC:
   1792 		tableoffset = STARTPCSOUNDS;
   1793 		NeedsDigitized = false;
   1794 		result = true;
   1795 		break;
   1796 	case sdm_AdLib:
   1797 		if (AdLibPresent)
   1798 		{
   1799 			tableoffset = STARTADLIBSOUNDS;
   1800 			NeedsDigitized = false;
   1801 			result = true;
   1802 		}
   1803 		break;
   1804 	}
   1805 #else
   1806 	result = true;
   1807 #endif
   1808 
   1809 	if (result && (mode != SoundMode))
   1810 	{
   1811 		SDL_ShutDevice();
   1812 		SoundMode = mode;
   1813 #ifndef	_MUSE_
   1814 		SoundTable = (word *)(&audiosegs[tableoffset]);
   1815 #endif
   1816 		SDL_StartDevice();
   1817 	}
   1818 
   1819 	SDL_SetTimerSpeed();
   1820 
   1821 	return(result);
   1822 }
   1823 
   1824 ///////////////////////////////////////////////////////////////////////////
   1825 //
   1826 //	SD_SetMusicMode() - sets the device to use for background music
   1827 //
   1828 ///////////////////////////////////////////////////////////////////////////
   1829 boolean
   1830 SD_SetMusicMode(SMMode mode)
   1831 {
   1832 	boolean	result = false;
   1833 
   1834 	SD_FadeOutMusic();
   1835 	while (SD_MusicPlaying())
   1836 		;
   1837 
   1838 	switch (mode)
   1839 	{
   1840 	case smm_Off:
   1841 		NeedsMusic = false;
   1842 		result = true;
   1843 		break;
   1844 	case smm_AdLib:
   1845 		if (AdLibPresent)
   1846 		{
   1847 			NeedsMusic = true;
   1848 			result = true;
   1849 		}
   1850 		break;
   1851 	}
   1852 
   1853 	if (result)
   1854 		MusicMode = mode;
   1855 
   1856 	SDL_SetTimerSpeed();
   1857 
   1858 	return(result);
   1859 }
   1860 
   1861 ///////////////////////////////////////////////////////////////////////////
   1862 //
   1863 //	SD_Startup() - starts up the Sound Mgr
   1864 //		Detects all additional sound hardware and installs my ISR
   1865 //
   1866 ///////////////////////////////////////////////////////////////////////////
   1867 void
   1868 SD_Startup(void)
   1869 {
   1870 	int	i;
   1871 
   1872 	if (SD_Started)
   1873 		return;
   1874 
   1875 	SDL_SetDS();
   1876 
   1877 	ssIsTandy = false;
   1878 	ssNoCheck = false;
   1879 	alNoCheck = false;
   1880 	sbNoCheck = false;
   1881 	sbNoProCheck = false;
   1882 #ifndef	_MUSE_
   1883 	for (i = 1;i < _argc;i++)
   1884 	{
   1885 		switch (US_CheckParm(_argv[i],ParmStrings))
   1886 		{
   1887 		case 0:						// No AdLib detection
   1888 			alNoCheck = true;
   1889 			break;
   1890 		case 1:						// No SoundBlaster detection
   1891 			sbNoCheck = true;
   1892 			break;
   1893 		case 2:						// No SoundBlaster Pro detection
   1894 			sbNoProCheck = true;
   1895 			break;
   1896 		case 3:
   1897 			ssNoCheck = true;		// No Sound Source detection
   1898 			break;
   1899 		case 4:						// Tandy Sound Source handling
   1900 			ssIsTandy = true;
   1901 			break;
   1902 		case 5:						// Sound Source present at LPT1
   1903 			ssPort = 1;
   1904 			ssNoCheck = SoundSourcePresent = true;
   1905 			break;
   1906 		case 6:                     // Sound Source present at LPT2
   1907 			ssPort = 2;
   1908 			ssNoCheck = SoundSourcePresent = true;
   1909 			break;
   1910 		case 7:                     // Sound Source present at LPT3
   1911 			ssPort = 3;
   1912 			ssNoCheck = SoundSourcePresent = true;
   1913 			break;
   1914 		}
   1915 	}
   1916 #endif
   1917 
   1918 	SoundUserHook = 0;
   1919 
   1920 	t0OldService = getvect(8);	// Get old timer 0 ISR
   1921 
   1922 	LocalTime = TimeCount = alTimeCount = 0;
   1923 
   1924 	SD_SetSoundMode(sdm_Off);
   1925 	SD_SetMusicMode(smm_Off);
   1926 
   1927 	if (!ssNoCheck)
   1928 		SoundSourcePresent = SDL_DetectSoundSource();
   1929 
   1930 	if (!alNoCheck)
   1931 	{
   1932 		AdLibPresent = SDL_DetectAdLib();
   1933 		if (AdLibPresent && !sbNoCheck)
   1934 		{
   1935 			int port = -1;
   1936 			char *env = getenv("BLASTER");
   1937 			if (env)
   1938 			{
   1939 				long temp;
   1940 				while (*env)
   1941 				{
   1942 					while (isspace(*env))
   1943 						env++;
   1944 
   1945 					switch (toupper(*env))
   1946 					{
   1947 					case 'A':
   1948 						temp = strtol(env + 1,&env,16);
   1949 						if
   1950 						(
   1951 							(temp >= 0x210)
   1952 						&&	(temp <= 0x260)
   1953 						&&	(!(temp & 0x00f))
   1954 						)
   1955 							port = (temp - 0x200) >> 4;
   1956 						else
   1957 							Quit("SD_Startup: Unsupported address value in BLASTER");
   1958 						break;
   1959 					case 'I':
   1960 						temp = strtol(env + 1,&env,10);
   1961 						if
   1962 						(
   1963 							(temp >= 0)
   1964 						&&	(temp <= 10)
   1965 						&&	(sbIntVectors[temp] != -1)
   1966 						)
   1967 						{
   1968 							sbInterrupt = temp;
   1969 							sbIntVec = sbIntVectors[sbInterrupt];
   1970 						}
   1971 						else
   1972 							Quit("SD_Startup: Unsupported interrupt value in BLASTER");
   1973 						break;
   1974 					case 'D':
   1975 						temp = strtol(env + 1,&env,10);
   1976 						if ((temp == 0) || (temp == 1) || (temp == 3))
   1977 							SDL_SBSetDMA(temp);
   1978 						else
   1979 							Quit("SD_Startup: Unsupported DMA value in BLASTER");
   1980 						break;
   1981 					default:
   1982 						while (isspace(*env))
   1983 							env++;
   1984 						while (*env && !isspace(*env))
   1985 							env++;
   1986 						break;
   1987 					}
   1988 				}
   1989 			}
   1990 			SoundBlasterPresent = SDL_DetectSoundBlaster(port);
   1991 		}
   1992 	}
   1993 
   1994 	for (i = 0;i < 255;i++)
   1995 		pcSoundLookup[i] = i * 60;
   1996 
   1997 	if (SoundBlasterPresent)
   1998 		SDL_StartSB();
   1999 
   2000 	SDL_SetupDigi();
   2001 
   2002 	SD_Started = true;
   2003 }
   2004 
   2005 ///////////////////////////////////////////////////////////////////////////
   2006 //
   2007 //	SD_Default() - Sets up the default behaviour for the Sound Mgr whether
   2008 //		the config file was present or not.
   2009 //
   2010 ///////////////////////////////////////////////////////////////////////////
   2011 void
   2012 SD_Default(boolean gotit,SDMode sd,SMMode sm)
   2013 {
   2014 	boolean	gotsd,gotsm;
   2015 
   2016 	gotsd = gotsm = gotit;
   2017 
   2018 	if (gotsd)	// Make sure requested sound hardware is available
   2019 	{
   2020 		switch (sd)
   2021 		{
   2022 		case sdm_AdLib:
   2023 			gotsd = AdLibPresent;
   2024 			break;
   2025 		}
   2026 	}
   2027 	if (!gotsd)
   2028 	{
   2029 		if (AdLibPresent)
   2030 			sd = sdm_AdLib;
   2031 		else
   2032 			sd = sdm_PC;
   2033 	}
   2034 	if (sd != SoundMode)
   2035 		SD_SetSoundMode(sd);
   2036 
   2037 
   2038 	if (gotsm)	// Make sure requested music hardware is available
   2039 	{
   2040 		switch (sm)
   2041 		{
   2042 		case sdm_AdLib:
   2043 			gotsm = AdLibPresent;
   2044 			break;
   2045 		}
   2046 	}
   2047 	if (!gotsm)
   2048 	{
   2049 		if (AdLibPresent)
   2050 			sm = smm_AdLib;
   2051 	}
   2052 	if (sm != MusicMode)
   2053 		SD_SetMusicMode(sm);
   2054 }
   2055 
   2056 ///////////////////////////////////////////////////////////////////////////
   2057 //
   2058 //	SD_Shutdown() - shuts down the Sound Mgr
   2059 //		Removes sound ISR and turns off whatever sound hardware was active
   2060 //
   2061 ///////////////////////////////////////////////////////////////////////////
   2062 void
   2063 SD_Shutdown(void)
   2064 {
   2065 	if (!SD_Started)
   2066 		return;
   2067 
   2068 	SD_MusicOff();
   2069 	SD_StopSound();
   2070 	SDL_ShutDevice();
   2071 	SDL_CleanDevice();
   2072 
   2073 	if (SoundBlasterPresent)
   2074 		SDL_ShutSB();
   2075 
   2076 	if (SoundSourcePresent)
   2077 		SDL_ShutSS();
   2078 
   2079 	asm	pushf
   2080 	asm	cli
   2081 
   2082 	SDL_SetTimer0(0);
   2083 
   2084 	setvect(8,t0OldService);
   2085 
   2086 	asm	popf
   2087 
   2088 	SD_Started = false;
   2089 }
   2090 
   2091 ///////////////////////////////////////////////////////////////////////////
   2092 //
   2093 //	SD_SetUserHook() - sets the routine that the Sound Mgr calls every 1/70th
   2094 //		of a second from its timer 0 ISR
   2095 //
   2096 ///////////////////////////////////////////////////////////////////////////
   2097 void
   2098 SD_SetUserHook(void (* hook)(void))
   2099 {
   2100 	SoundUserHook = hook;
   2101 }
   2102 
   2103 ///////////////////////////////////////////////////////////////////////////
   2104 //
   2105 //	SD_PositionSound() - Sets up a stereo imaging location for the next
   2106 //		sound to be played. Each channel ranges from 0 to 15.
   2107 //
   2108 ///////////////////////////////////////////////////////////////////////////
   2109 void
   2110 SD_PositionSound(int leftvol,int rightvol)
   2111 {
   2112 	LeftPosition = leftvol;
   2113 	RightPosition = rightvol;
   2114 	nextsoundpos = true;
   2115 }
   2116 
   2117 ///////////////////////////////////////////////////////////////////////////
   2118 //
   2119 //	SD_PlaySound() - plays the specified sound on the appropriate hardware
   2120 //
   2121 ///////////////////////////////////////////////////////////////////////////
   2122 boolean
   2123 SD_PlaySound(soundnames sound)
   2124 {
   2125 	boolean		ispos;
   2126 	SoundCommon	far *s;
   2127 	int	lp,rp;
   2128 
   2129 	lp = LeftPosition;
   2130 	rp = RightPosition;
   2131 	LeftPosition = 0;
   2132 	RightPosition = 0;
   2133 
   2134 	ispos = nextsoundpos;
   2135 	nextsoundpos = false;
   2136 
   2137 	if (sound == -1)
   2138 		return(false);
   2139 
   2140 	s = MK_FP(SoundTable[sound],0);
   2141 	if ((SoundMode != sdm_Off) && !s)
   2142 		Quit("SD_PlaySound() - Uncached sound");
   2143 
   2144 	if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
   2145 	{
   2146 		if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
   2147 		{
   2148 			if (s->priority < SoundPriority)
   2149 				return(false);
   2150 
   2151 			SDL_PCStopSound();
   2152 
   2153 			SD_PlayDigitized(DigiMap[sound],lp,rp);
   2154 			SoundPositioned = ispos;
   2155 			SoundNumber = sound;
   2156 			SoundPriority = s->priority;
   2157 		}
   2158 		else
   2159 		{
   2160 		asm	pushf
   2161 		asm	cli
   2162 			if (DigiPriority && !DigiNumber)
   2163 			{
   2164 			asm	popf
   2165 				Quit("SD_PlaySound: Priority without a sound");
   2166 			}
   2167 		asm	popf
   2168 
   2169 			if (s->priority < DigiPriority)
   2170 				return(false);
   2171 
   2172 			SD_PlayDigitized(DigiMap[sound],lp,rp);
   2173 			SoundPositioned = ispos;
   2174 			DigiNumber = sound;
   2175 			DigiPriority = s->priority;
   2176 		}
   2177 
   2178 		return(true);
   2179 	}
   2180 
   2181 	if (SoundMode == sdm_Off)
   2182 		return(false);
   2183 	if (!s->length)
   2184 		Quit("SD_PlaySound() - Zero length sound");
   2185 	if (s->priority < SoundPriority)
   2186 		return(false);
   2187 
   2188 	switch (SoundMode)
   2189 	{
   2190 	case sdm_PC:
   2191 		SDL_PCPlaySound((void far *)s);
   2192 		break;
   2193 	case sdm_AdLib:
   2194 		SDL_ALPlaySound((void far *)s);
   2195 		break;
   2196 	}
   2197 
   2198 	SoundNumber = sound;
   2199 	SoundPriority = s->priority;
   2200 
   2201 	return(false);
   2202 }
   2203 
   2204 ///////////////////////////////////////////////////////////////////////////
   2205 //
   2206 //	SD_SoundPlaying() - returns the sound number that's playing, or 0 if
   2207 //		no sound is playing
   2208 //
   2209 ///////////////////////////////////////////////////////////////////////////
   2210 word
   2211 SD_SoundPlaying(void)
   2212 {
   2213 	boolean	result = false;
   2214 
   2215 	switch (SoundMode)
   2216 	{
   2217 	case sdm_PC:
   2218 		result = pcSound? true : false;
   2219 		break;
   2220 	case sdm_AdLib:
   2221 		result = alSound? true : false;
   2222 		break;
   2223 	}
   2224 
   2225 	if (result)
   2226 		return(SoundNumber);
   2227 	else
   2228 		return(false);
   2229 }
   2230 
   2231 ///////////////////////////////////////////////////////////////////////////
   2232 //
   2233 //	SD_StopSound() - if a sound is playing, stops it
   2234 //
   2235 ///////////////////////////////////////////////////////////////////////////
   2236 void
   2237 SD_StopSound(void)
   2238 {
   2239 	if (DigiPlaying)
   2240 		SD_StopDigitized();
   2241 
   2242 	switch (SoundMode)
   2243 	{
   2244 	case sdm_PC:
   2245 		SDL_PCStopSound();
   2246 		break;
   2247 	case sdm_AdLib:
   2248 		SDL_ALStopSound();
   2249 		break;
   2250 	}
   2251 
   2252 	SoundPositioned = false;
   2253 
   2254 	SDL_SoundFinished();
   2255 }
   2256 
   2257 ///////////////////////////////////////////////////////////////////////////
   2258 //
   2259 //	SD_WaitSoundDone() - waits until the current sound is done playing
   2260 //
   2261 ///////////////////////////////////////////////////////////////////////////
   2262 void
   2263 SD_WaitSoundDone(void)
   2264 {
   2265 	while (SD_SoundPlaying())
   2266 		;
   2267 }
   2268 
   2269 ///////////////////////////////////////////////////////////////////////////
   2270 //
   2271 //	SD_MusicOn() - turns on the sequencer
   2272 //
   2273 ///////////////////////////////////////////////////////////////////////////
   2274 void
   2275 SD_MusicOn(void)
   2276 {
   2277 	sqActive = true;
   2278 }
   2279 
   2280 ///////////////////////////////////////////////////////////////////////////
   2281 //
   2282 //	SD_MusicOff() - turns off the sequencer and any playing notes
   2283 //
   2284 ///////////////////////////////////////////////////////////////////////////
   2285 void
   2286 SD_MusicOff(void)
   2287 {
   2288 	word	i;
   2289 
   2290 
   2291 	switch (MusicMode)
   2292 	{
   2293 	case smm_AdLib:
   2294 		alFXReg = 0;
   2295 		alOut(alEffects,0);
   2296 		for (i = 0;i < sqMaxTracks;i++)
   2297 			alOut(alFreqH + i + 1,0);
   2298 		break;
   2299 	}
   2300 	sqActive = false;
   2301 }
   2302 
   2303 ///////////////////////////////////////////////////////////////////////////
   2304 //
   2305 //	SD_StartMusic() - starts playing the music pointed to
   2306 //
   2307 ///////////////////////////////////////////////////////////////////////////
   2308 void
   2309 SD_StartMusic(MusicGroup far *music)
   2310 {
   2311 	SD_MusicOff();
   2312 asm	pushf
   2313 asm	cli
   2314 
   2315 	if (MusicMode == smm_AdLib)
   2316 	{
   2317 		sqHackPtr = sqHack = music->values;
   2318 		sqHackSeqLen = sqHackLen = music->length;
   2319 		sqHackTime = 0;
   2320 		alTimeCount = 0;
   2321 		SD_MusicOn();
   2322 	}
   2323 
   2324 asm	popf
   2325 }
   2326 
   2327 ///////////////////////////////////////////////////////////////////////////
   2328 //
   2329 //	SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
   2330 //		to see if the fadeout is complete
   2331 //
   2332 ///////////////////////////////////////////////////////////////////////////
   2333 void
   2334 SD_FadeOutMusic(void)
   2335 {
   2336 	switch (MusicMode)
   2337 	{
   2338 	case smm_AdLib:
   2339 		// DEBUG - quick hack to turn the music off
   2340 		SD_MusicOff();
   2341 		break;
   2342 	}
   2343 }
   2344 
   2345 ///////////////////////////////////////////////////////////////////////////
   2346 //
   2347 //	SD_MusicPlaying() - returns true if music is currently playing, false if
   2348 //		not
   2349 //
   2350 ///////////////////////////////////////////////////////////////////////////
   2351 boolean
   2352 SD_MusicPlaying(void)
   2353 {
   2354 	boolean	result;
   2355 
   2356 	switch (MusicMode)
   2357 	{
   2358 	case smm_AdLib:
   2359 		result = false;
   2360 		// DEBUG - not written
   2361 		break;
   2362 	default:
   2363 		result = false;
   2364 	}
   2365 
   2366 	return(result);
   2367 }