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 //                      SoundBlasterPresent - SoundBlaster card present?
17 //                      AdLibPresent - AdLib card present?
18 //                      SoundMode - What device is used for sound effects
19 //                              (Use SM_SetSoundMode() to set)
20 //                      MusicMode - What device is used for music
21 //                              (Use SM_SetMusicMode() to set)
22 //                      DigiMode - What device is used for digitized sound effects
23 //                              (Use SM_SetDigiDevice() to set)
24 //
25 //              For Cache Mgr:
26 //                      NeedsDigitized - load digitized sounds?
27 //                      NeedsMusic - load music?
28 //
29 #include "wl_def.h"
30 #include <SDL_mixer.h>
31 #include "w_wad.h"
32 #include "zstring.h"
33 #include "sndinfo.h"
34 #include "sndseq.h"
35 #ifdef USE_GPL
36 #include "dosbox/dbopl.h"
37 #else
38 #include "mame/fmopl.h"
39 #endif
40 #include "wl_main.h"
41 #include "id_sd.h"
42 
43 // For AdLib sounds & music:
44 #define MUSIC_RATE 700	// Must be a multiple of SOUND_RATE
45 #define SOUND_RATE 140	// Also affects PC Speaker sounds
46 #define SOUND_TICKS (MUSIC_RATE/SOUND_RATE)
47 
48 // Linear falloff
49 //#define TO_SDL_POSITION(pos) (((15 - (pos)) << 4) + 15)
50 // Volume is based on the square of the distance to the source. (More like vanilla)
51 #define TO_SDL_POSITION(pos) (((64 - ((pos) * (pos))) * 3) + 63)
52 
53 #define MIN_TICKS_BETWEEN_DIGI_REPEATS 10
54 
55 // Mutex for thread-safe audio:
56 SDL_mutex *audioMutex;
57 
58 globalsoundpos channelSoundPos[MIX_CHANNELS];
59 
60 //      Global variables
61 bool	AdLibPresent,
62 		SoundBlasterPresent,SBProPresent,
63 		SoundPositioned;
64 SDMode	SoundMode;
65 SMMode	MusicMode;
66 SDSMode	DigiMode;
67 int		AdlibVolume=MAX_VOLUME;
68 int		MusicVolume=MAX_VOLUME;
69 int		SoundVolume=MAX_VOLUME;
70 
71 //      Internal variables
72 static  bool					SD_Started;
73 static  bool					nextsoundpos;
74 FString                 SoundPlaying;
75 static  word                    SoundPriority;
76 static  word                    DigiPriority;
77 static  int                     LeftPosition;
78 static  int                     RightPosition;
79 
80 static  bool					DigiPlaying;
81 
82 //      PC Sound variables
83 static  volatile byte           pcLastSample;
84 static  byte * volatile         pcSound;
85 static  longword                pcLengthLeft;
86 
87 //      AdLib variables
88 static  byte * volatile         alSound;
89 static  byte                    alBlock;
90 static  longword                alLengthLeft;
91 static  longword                alTimeCount;
92 static  Instrument              alZeroInst;
93 
94 //      Sequencer variables
95 static  volatile bool			sqActive;
96 static  word                   *sqHack;
97 static	word					*sqHackFreeable=NULL;
98 static  word                   *sqHackPtr;
99 static  int                     sqHackLen;
100 static  int                     sqHackSeqLen;
101 static  longword                sqHackTime;
102 
103 static int musicchunk=-1;
104 Mix_Music *music=NULL;
105 byte* chunkmem = NULL;
106 
musicFinished(void)107 void musicFinished(void)
108 {
109 	if (music != NULL)
110 	{
111 		Mix_HaltMusic();
112 		Mix_FreeMusic(music);
113 		music = NULL;
114 
115 		delete [] chunkmem;
116 		chunkmem = NULL;
117 
118 		musicchunk = -1;
119 	}
120 }
121 
SD_UpdateMusicVolume(int which)122 bool SD_UpdateMusicVolume(int which)
123 {
124 	Mix_VolumeMusic(static_cast<int> (ceil(128.0*MULTIPLY_VOLUME(MusicVolume))));
125 	return 0;
126 }
127 
128 #ifdef USE_GPL
129 
130 DBOPL::Chip oplChip;
131 
YM3812Init(int numChips,int clock,int rate)132 static inline bool YM3812Init(int numChips, int clock, int rate)
133 {
134 	oplChip.Setup(rate);
135 	return false;
136 }
137 
YM3812Write(DBOPL::Chip & which,Bit32u reg,Bit8u val,const int & volume)138 static inline void YM3812Write(DBOPL::Chip &which, Bit32u reg, Bit8u val, const int &volume)
139 {
140 	which.SetVolume(volume);
141 	which.WriteReg(reg, val);
142 }
143 
YM3812UpdateOne(DBOPL::Chip & which,int16_t * stream,int length)144 static inline void YM3812UpdateOne(DBOPL::Chip &which, int16_t *stream, int length)
145 {
146 	Bit32s buffer[512 * 2];
147 	int i;
148 
149 	// length is at maximum samplesPerMusicTick = param_samplerate / 700
150 	// so 512 is sufficient for a sample rate of 358.4 kHz (default 44.1 kHz)
151 	if(length > 512)
152 		length = 512;
153 
154 	if(which.opl3Active)
155 	{
156 		which.GenerateBlock3(length, buffer);
157 
158 		// GenerateBlock3 generates a number of "length" 32-bit stereo samples
159 		// so we only need to convert them to 16-bit samples
160 		for(i = 0; i < length * 2; i++)  // * 2 for left/right channel
161 		{
162 			// Multiply by 4 to match loudness of MAME emulator.
163 			Bit32s sample = buffer[i] << 2;
164 			if(sample > 32767) sample = 32767;
165 			else if(sample < -32768) sample = -32768;
166 			stream[i] = LittleShort(sample);
167 		}
168 	}
169 	else
170 	{
171 		which.GenerateBlock2(length, buffer);
172 
173 		// GenerateBlock3 generates a number of "length" 32-bit mono samples
174 		// so we need to convert them to 32-bit stereo samples
175 		for(i = 0; i < length; i++)
176 		{
177 			// Multiply by 4 to match loudness of MAME emulator.
178 			// Then upconvert to stereo.
179 			Bit32s sample = buffer[i] << 2;
180 			if(sample > 32767) sample = 32767;
181 			else if(sample < -32768) sample = -32768;
182 			stream[i * 2] = stream[i * 2 + 1] = (int16_t) LittleShort(sample);
183 		}
184 	}
185 }
186 
187 #else
188 
189 static const int oplChip = 0;
190 
191 #endif
192 
193 #ifndef ECWOLF_MIXER
Mix_SetMusicPCMPosition(Uint64 position)194 static int Mix_SetMusicPCMPosition(Uint64 position) { return 0; }
Mix_GetMusicPCMPosition()195 static Uint64 Mix_GetMusicPCMPosition() { return 0; }
196 #endif
197 
SDL_SoundFinished(void)198 static void SDL_SoundFinished(void)
199 {
200 	SoundPlaying = FString();
201 	SoundPriority = 0;
202 }
203 
204 /*
205 =============================================================================
206 
207                      PC SPEAKER EMULATOR -- by K1n9_Duk3
208 
209 -----------------------------------------------------------------------------
210 
211 This emulator was designed to be FAST! The sampled audio data created by this
212 code might not be 100% true to the output of a real PC Speaker, but it is
213 close enough.
214 
215 The emulator generates a square wave:
216      _____       _____       _____       _____       _____       _____
217   __|     |     |     |     |     |     |     |     |     |     |     |___
218           |_____|     |_____|     |_____|     |_____|     |_____|
219 
220 =============================================================================
221 */
222 
223 static short	pcVolume = 5000;	// for 16-bit mixing (8-bit should use 20)
224 static longword	pcPhaseTick = 0;
225 static longword	pcPhaseLength;
226 static bool		pcActive = false;
227 static longword	pcSamplesPerTick;
228 static longword	pcNumReadySamples = 0;
229 
230 #define PC_BASE_TIMER 1193181
231 
232 // Function prototype is for menu listener
SD_UpdatePCSpeakerVolume(int)233 bool SD_UpdatePCSpeakerVolume(int)
234 {
235 	SDL_LockMutex(audioMutex);
236 
237 	if(pcVolume > 0)
238 		pcVolume = AdlibVolume*250;
239 	else
240 		pcVolume = -AdlibVolume*250;
241 
242 	SDL_UnlockMutex(audioMutex);
243 
244 	return true;
245 }
246 
247 // Note: The inline functions do not lock or unlock 'audioMutex'. Make sure
248 // that the code calling these functions locks/unlocks the mutex before/after
249 // calling these functions!
250 
_SDL_turnOnPCSpeaker(byte pcSample)251 inline void _SDL_turnOnPCSpeaker(byte pcSample)
252 {
253 	// Note: You could use a lookup table to make this even faster. Only
254 	// 256 table entries are required since the PC samples are just byte
255 	// values.
256 	pcPhaseLength = (pcSample*60*param_samplerate)/(2*PC_BASE_TIMER);
257 #ifdef PC_VIBRATO
258 	//if(pcVolume<0) pcVolume = -pcVolume;
259 	pcPhaseTick = 0;
260 #endif
261 	pcActive = true;
262 }
263 
_SDL_turnOffPCSpeaker()264 inline void _SDL_turnOffPCSpeaker()
265 {
266 	pcActive = false;
267 	pcPhaseTick = 0;	// Only required in case PC_VIBRATO is not defined
268 }
269 
_SDL_PCService()270 inline void _SDL_PCService()
271 {
272 	if(pcSound)
273 	{
274 		if(*pcSound!=pcLastSample)
275 		{
276 			pcLastSample=*pcSound;
277 			if(pcLastSample)
278 				_SDL_turnOnPCSpeaker(pcLastSample);	// don't multiply by 60, just pass the byte value
279 			else
280 				_SDL_turnOffPCSpeaker();
281 		}
282 		pcSound++;
283 		pcLengthLeft--;
284 		if(!pcLengthLeft)
285 		{
286 			pcSound=0;
287 			SoundPriority=0;
288 			_SDL_turnOffPCSpeaker();
289 		}
290 	}
291 }
292 
293 ///////////////////////////////////////////////////////////////////////////
294 //
295 //      SDL_PCPlaySound() - Plays the specified sound on the PC speaker
296 //
297 ///////////////////////////////////////////////////////////////////////////
298 static void
_SDL_PCPlaySound(PCSound * sound)299 _SDL_PCPlaySound(PCSound *sound)
300 {
301 	// We must stop the digitized sound because we're just faking the digitized PC Speaker playback
302 	if(DigiMode == sds_PC)
303 		SD_StopDigitized();
304 
305 	SDL_LockMutex(audioMutex);
306 
307 	pcPhaseTick = 0;
308 	pcLastSample = 0;	// Must be a value that cannot be played, so the PC Speaker is forced to reset (-1 wraps to 255 so it cannot be used here)
309     pcLengthLeft = LittleLong(sound->common.length);
310     pcSound = sound->data;
311 
312 	SDL_UnlockMutex(audioMutex);
313 }
314 
315 ///////////////////////////////////////////////////////////////////////////
316 //
317 //      SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
318 //
319 ///////////////////////////////////////////////////////////////////////////
320 static void
_SDL_PCStopSound(void)321 _SDL_PCStopSound(void)
322 {
323 	SDL_LockMutex(audioMutex);
324 
325     pcSound = 0;
326 	_SDL_turnOffPCSpeaker();
327 
328 	SDL_UnlockMutex(audioMutex);
329 }
330 
331 ///////////////////////////////////////////////////////////////////////////
332 //
333 //      SDL_ShutPC() - Turns off the pc speaker
334 //
335 ///////////////////////////////////////////////////////////////////////////
336 static void
_SDL_ShutPC(void)337 _SDL_ShutPC(void)
338 {
339     _SDL_PCStopSound();
340 }
341 
342 
343 ///////////////////////////////////////////////////////////////////////////
344 //
345 //      SDL_EmulateAndMixPC() - Emulates the pc speaker
346 //                              and mixes the output into buffer
347 //
348 ///////////////////////////////////////////////////////////////////////////
_SDL_EmulateAndMixPC(Sint16 * buffer,int length)349 void _SDL_EmulateAndMixPC(Sint16 *buffer, int length)
350 {
351 	// This should be called in SDL_IMFMusicPlayer() directly after calling
352 	// YM3812UpdateOne() so that the PC sounds can be mixed into the output
353 	// of the OPL emulator. This way, all sound hardware is emulated in the
354 	// same routine. The audio gets mixed into the Music channel, so we do
355 	// not need an additional channel for the PC Speaker sounds.
356 
357 	// Note: This code assumes that 'buffer' is a signed 16-bit stereo sound!
358 
359 	Sint32 mix;	// Needs more bits than the buffer
360 
361 	if(!pcActive) return; // PC Speaker is turned off
362 
363 	SDL_LockMutex(audioMutex);
364 
365 	while(length--)
366 	{
367 		mix = *buffer;
368 
369 		// Mix it by simply adding the volume:
370 		mix += pcVolume;
371 		if (mix < -32768) mix = -32768;
372 		else if (mix >  32767) mix =  32767;
373 		// This generates pretty much the same output as SDL_MixAudio(), but
374 		// it does not require a second buffer for the PC Speaker sample data.
375 		//
376 		// Note: If you use another mixing method, you cannot simply return
377 		// from this function if pcActive is false. You will have to mix a
378 		// PC Volume of 0 into the entire buffer!
379 
380 		// We assume that the left and right channel in the buffer contain
381 		// the same value, so we only need to calculate the mix once.
382 		*buffer++ = mix;	//left channel
383 		*buffer++ = mix;	//right channel
384 
385 		// Update the PC speaker state:
386 		if(pcPhaseTick++ >= pcPhaseLength)
387 		{
388 			pcVolume = -pcVolume;
389 			pcPhaseTick = 0;
390 		}
391 	}
392 
393 	SDL_UnlockMutex(audioMutex);
394 }
395 
396 ///////////////////////////////////////////////////////////////////////////
397 //
398 //      SDL_PCSpeakerEmulator() - Emulates the pc speaker
399 //      (replaces SDL_IMFMusicPlayer if no AdLib emulator is present)
400 //
401 ///////////////////////////////////////////////////////////////////////////
_SDL_PCSpeakerEmulator(void * udata,Uint8 * stream,int len)402 void _SDL_PCSpeakerEmulator(void *udata, Uint8 *stream, int len)
403 {
404     int stereolen = len>>1;
405     int sampleslen = stereolen>>1;
406     Sint16 *stream16 = (Sint16 *) (void *) stream;    // expect correct alignment
407 
408 	SDL_LockMutex(audioMutex);
409 
410 	while(1)
411     {
412         if(pcNumReadySamples)
413         {
414 			if(pcActive)
415 				while(pcNumReadySamples && sampleslen)
416 				{
417 					pcNumReadySamples--;
418 					sampleslen--;
419 
420 					*stream16++ = pcVolume;
421 					*stream16++ = pcVolume;
422 
423 					if(pcPhaseTick++ >= pcPhaseLength)
424 					{
425 						pcVolume = -pcVolume;
426 						pcPhaseTick = 0;
427 					}
428 				}
429 			else
430 				while(pcNumReadySamples && sampleslen)
431 				{
432 					pcNumReadySamples--;
433 					sampleslen--;
434 
435 					stream16 += 2;	// No need to set it to 0. SDL should have done that already.
436 				}
437 
438 			if(!sampleslen)
439 				break;	// We need to unlock the mutex, so we cannot just return!
440         }
441 
442 		_SDL_PCService();
443 
444         pcNumReadySamples = pcSamplesPerTick;
445 
446     }
447 
448 	SDL_UnlockMutex(audioMutex);
449 }
450 /*
451 =============================================================================
452 ======================== End of PC Speaker emulator ========================
453 =============================================================================
454 */
455 #define SDL_PCPlaySound(pcsound)				_SDL_PCPlaySound(pcsound)
456 #define SDL_PCStopSound()						_SDL_PCStopSound()
457 #define SDL_ShutPC()							_SDL_ShutPC()
458 #define SDL_PCService()							_SDL_PCService()
459 #define SDL_PCEmulateAndMix(buffer, length)		if(SoundMode == sdm_PC) _SDL_EmulateAndMixPC(buffer, length)
460 
SD_StopDigitized(void)461 void SD_StopDigitized(void)
462 {
463 	DigiPlaying = false;
464 	DigiPriority = 0;
465 	SoundPositioned = false;
466 	if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
467 		SDL_SoundFinished();
468 
469 	Mix_HaltChannel(-1);
470 }
471 
SD_SetPosition(int channel,int leftpos,int rightpos)472 void SD_SetPosition(int channel, int leftpos, int rightpos)
473 {
474 	if((leftpos < 0) || (leftpos > 15) || (rightpos < 0) || (rightpos > 15)
475 			|| ((leftpos == 15) && (rightpos == 15)))
476 		Quit("SD_SetPosition: Illegal position");
477 
478 	switch (DigiMode)
479 	{
480 		default:
481 			break;
482 		case sds_SoundBlaster:
483 //            SDL_PositionSBP(leftpos,rightpos);
484 			Mix_SetPanning(channel, TO_SDL_POSITION(leftpos), TO_SDL_POSITION(rightpos));
485 			break;
486 	}
487 }
488 
SD_PrepareSound(int which)489 byte* SD_PrepareSound(int which)
490 {
491 	int size = Wads.LumpLength(which);
492 	if(size == 0)
493 		return NULL;
494 
495 	FMemLump soundLump = Wads.ReadLump(which);
496 
497 	byte* out = reinterpret_cast<byte*> (Mix_LoadWAV_RW(SDL_RWFromMem(soundLump.GetMem(), size), 1));
498 	if(!out)
499 		return NULL;
500 
501 	// TEMPORARY WORK AROUND FOR MEMORY ERROR
502 	byte* nout = new byte[sizeof(Mix_Chunk)];
503 	memcpy(nout, out, sizeof(Mix_Chunk));
504 	return nout;
505 }
506 
SD_PlayDigitized(const SoundData & which,int leftpos,int rightpos,SoundChannel chan)507 int SD_PlayDigitized(const SoundData &which,int leftpos,int rightpos,SoundChannel chan)
508 {
509 	if (!DigiMode)
510 		return 0;
511 
512 	// If this sound has been played too recently, don't play it again.
513 	// (Fix for extremely loud sounds when one plays over itself too much.)
514 	uint32_t currentTick = SDL_GetTicks();
515 	if (currentTick - SoundInfo.GetLastPlayTick(which) < MIN_TICKS_BETWEEN_DIGI_REPEATS)
516 		return 0;
517 
518 	SoundInfo.SetLastPlayTick(which, currentTick);
519 
520 	int channel = chan;
521 	if(chan == SD_GENERIC)
522 	{
523 		channel = Mix_GroupAvailable(1);
524 		if(channel == -1) channel = Mix_GroupOldest(1);
525 		if(channel == -1)           // All sounds stopped in the meantime?
526 			channel = Mix_GroupAvailable(1);
527 	}
528 	SD_SetPosition(channel, leftpos,rightpos);
529 
530 	DigiPlaying = true;
531 
532 	Mix_Chunk *sample = reinterpret_cast<Mix_Chunk*> (which.GetData(SoundData::DIGITAL));
533 	if(sample == NULL)
534 		return 0;
535 
536 	Mix_Volume(channel, static_cast<int> (ceil(128.0*MULTIPLY_VOLUME(SoundVolume))));
537 	if(Mix_PlayChannel(channel, sample, 0) == -1)
538 	{
539 		printf("Unable to play sound: %s\n", Mix_GetError());
540 		return 0;
541 	}
542 
543 	// Return channel + 1 because zero is a valid channel.
544 	return channel + 1;
545 }
546 
SD_ChannelFinished(int channel)547 void SD_ChannelFinished(int channel)
548 {
549 	SoundPlaying = FString();
550 	channelSoundPos[channel].valid = 0;
551 }
552 
553 void
SD_SetDigiDevice(SDSMode mode)554 SD_SetDigiDevice(SDSMode mode)
555 {
556 	bool devicenotpresent;
557 
558 	if (mode == DigiMode)
559 		return;
560 
561 	SD_StopDigitized();
562 
563 	devicenotpresent = false;
564 	switch (mode)
565 	{
566 		default:
567 			break;
568 		case sds_SoundBlaster:
569 			if (!SoundBlasterPresent)
570 				devicenotpresent = true;
571 			break;
572 	}
573 
574 	if (!devicenotpresent)
575 	{
576 		DigiMode = mode;
577 
578 #ifdef NOTYET
579 		SDL_SetTimerSpeed();
580 #endif
581 	}
582 }
583 
584 //      AdLib Code
585 
586 ///////////////////////////////////////////////////////////////////////////
587 //
588 //      SDL_ALStopSound() - Turns off any sound effects playing through the
589 //              AdLib card
590 //
591 ///////////////////////////////////////////////////////////////////////////
592 static void
SDL_ALStopSound(void)593 SDL_ALStopSound(void)
594 {
595 	SDL_LockMutex(audioMutex);
596 
597 	alSound = 0;
598 	alOut(alFreqH + 0, 0);
599 
600 	SDL_UnlockMutex(audioMutex);
601 }
602 
SDL_AlSetChanInst(const Instrument * inst,unsigned int chan)603 static void SDL_AlSetChanInst(const Instrument *inst, unsigned int chan)
604 {
605 	static const byte chanOps[OPL_CHANNELS] = {
606 		0, 1, 2, 8, 9, 0xA, 0x10, 0x11, 0x12
607 	};
608 	byte c,m;
609 
610 	m = chanOps[chan]; // modulator cell for channel
611 	c = m + 3; // carrier cell for channel
612 	alOut(m + alChar,inst->mChar);
613 	alOut(m + alScale,inst->mScale);
614 	alOut(m + alAttack,inst->mAttack);
615 	alOut(m + alSus,inst->mSus);
616 	alOut(m + alWave,inst->mWave);
617 	alOut(c + alChar,inst->cChar);
618 	alOut(c + alScale,inst->cScale);
619 	alOut(c + alAttack,inst->cAttack);
620 	alOut(c + alSus,inst->cSus);
621 	alOut(c + alWave,inst->cWave);
622 
623 	// Note: Switch commenting on these lines for old MUSE compatibility
624 //    alOutInIRQ(alFeedCon,inst->nConn);
625 
626 	alOut(chan + alFreqL,0);
627 	alOut(chan + alFreqH,0);
628 	alOut(chan + alFeedCon,0);
629 }
SDL_AlSetFXInst(const Instrument * inst)630 static void SDL_AlSetFXInst(const Instrument *inst)
631 {
632 	SDL_AlSetChanInst(inst, 0);
633 }
634 
635 ///////////////////////////////////////////////////////////////////////////
636 //
637 //      SDL_ALPlaySound() - Plays the specified sound on the AdLib card
638 //
639 ///////////////////////////////////////////////////////////////////////////
640 static void
SDL_ALPlaySound(AdLibSound * sound)641 SDL_ALPlaySound(AdLibSound *sound)
642 {
643 	Instrument      *inst;
644 	byte            *data;
645 
646 	SDL_ALStopSound();
647 
648 	SDL_LockMutex(audioMutex);
649 
650 	alLengthLeft = LittleLong(sound->common.length);
651 	data = sound->data;
652 	alBlock = ((sound->block & 7) << 2) | 0x20;
653 	inst = &sound->inst;
654 
655 	if (!(inst->mSus | inst->cSus))
656 	{
657 		Quit("SDL_ALPlaySound() - Bad instrument");
658 	}
659 
660 	SDL_AlSetFXInst(inst);
661 	alSound = (byte *)data;
662 
663 	SDL_UnlockMutex(audioMutex);
664 }
665 
666 ///////////////////////////////////////////////////////////////////////////
667 //
668 //      SDL_ShutAL() - Shuts down the AdLib card for sound effects
669 //
670 ///////////////////////////////////////////////////////////////////////////
671 static void
SDL_ShutAL(void)672 SDL_ShutAL(void)
673 {
674 	SDL_LockMutex(audioMutex);
675 
676 	alSound = 0;
677 	//alOut(alEffects,0);	// Sound effects should not mess with the music's rhythm settings!
678 	alOut(alFreqH + 0,0);
679 	SDL_AlSetFXInst(&alZeroInst);
680 
681 	SDL_UnlockMutex(audioMutex);
682 }
683 
684 ///////////////////////////////////////////////////////////////////////////
685 //
686 //      SDL_StartAL() - Starts up the AdLib card for sound effects
687 //
688 ///////////////////////////////////////////////////////////////////////////
689 static void
SDL_StartAL(void)690 SDL_StartAL(void)
691 {
692 	//alOut(alEffects, 0);	// Sound effects should not mess with the music's rhythm settings!
693 	SDL_AlSetFXInst(&alZeroInst);
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////
697 //
698 //      SDL_ShutDevice() - turns off whatever device was being used for sound fx
699 //
700 ////////////////////////////////////////////////////////////////////////////
701 static void
SDL_ShutDevice(void)702 SDL_ShutDevice(void)
703 {
704 	switch (SoundMode)
705 	{
706 		default:
707 			break;
708 		case sdm_PC:
709 			SDL_ShutPC();
710 			break;
711 		case sdm_AdLib:
712 			SDL_ShutAL();
713 			break;
714 	}
715 	SoundMode = sdm_Off;
716 }
717 
718 ///////////////////////////////////////////////////////////////////////////
719 //
720 //      SDL_StartDevice() - turns on whatever device is to be used for sound fx
721 //
722 ///////////////////////////////////////////////////////////////////////////
723 static void
SDL_StartDevice(void)724 SDL_StartDevice(void)
725 {
726 	switch (SoundMode)
727 	{
728 		default:
729 			break;
730 		case sdm_AdLib:
731 			SDL_StartAL();
732 			break;
733 	}
734 	SoundPlaying = FString();
735 	SoundPriority = 0;
736 }
737 
738 //      Public routines
739 
740 ///////////////////////////////////////////////////////////////////////////
741 //
742 //      SD_SetSoundMode() - Sets which sound hardware to use for sound effects
743 //
744 ///////////////////////////////////////////////////////////////////////////
SD_SetSoundMode(SDMode mode)745 bool SD_SetSoundMode(SDMode mode)
746 {
747 	bool result = false;
748 
749 	SD_StopSound();
750 
751 	if ((mode == sdm_AdLib) && !AdLibPresent)
752 		mode = sdm_PC;
753 
754 	switch (mode)
755 	{
756 		case sdm_Off:
757 		case sdm_PC:
758 			result = true;
759 			break;
760 		case sdm_AdLib:
761 			if (AdLibPresent)
762 				result = true;
763 			break;
764 		default:
765 			Quit("SD_SetSoundMode: Invalid sound mode %i", mode);
766 			return false;
767 	}
768 
769 	if (result && (mode != SoundMode))
770 	{
771 		SDL_ShutDevice();
772 		SoundMode = mode;
773 		SDL_StartDevice();
774 	}
775 
776 	return(result);
777 }
778 
779 ///////////////////////////////////////////////////////////////////////////
780 //
781 //      SD_SetMusicMode() - sets the device to use for background music
782 //
783 ///////////////////////////////////////////////////////////////////////////
SD_SetMusicMode(SMMode mode)784 bool SD_SetMusicMode(SMMode mode)
785 {
786 	bool result = false;
787 
788 	SD_FadeOutMusic();
789 	while (SD_MusicPlaying())
790 		SDL_Delay(5);
791 
792 	switch (mode)
793 	{
794 		case smm_Off:
795 			result = true;
796 			break;
797 		case smm_AdLib:
798 			if (AdLibPresent)
799 				result = true;
800 			break;
801 	}
802 
803 	if (result)
804 		MusicMode = mode;
805 
806 //    SDL_SetTimerSpeed();
807 
808 	return(result);
809 }
810 
811 int numreadysamples = 0;
812 int soundTimeCounter = SOUND_TICKS;
813 int samplesPerMusicTick;
814 /*-----------------------------------------------------------------------------
815 The variables below are not required unless you WANT to change the behavior of
816 AdLib sound effects compared to the original Wolfenstein 3-D code.
817 
818 What would happen is this: SDL_AlPlaySound() resets the AdLib instrument and
819 the alSound pointer to play the given AdLib sound from the beginning. The check
820 that was implemented in SDL_IMFMusicPlayer() would not reset the curAlSoundPtr
821 if the alSound pointer pointed to the data that was already being played. This
822 resulted in situations where the instrument data was reset, but not the data
823 pointer. This caused some sounds to be played at the wrong pitch.
824 
825 If you really WANT to set the behavior so that an AdLib sound will not be re-
826 started when it is interrupted by itself, you should change the code in the
827 SDL_AlPlaySound() function instead, making sure not to reset the instrument.
828 
829 Any thread-safety issues should be solved now. The mutex 'audioMutex' protects
830 gloabal variables that need to be accessed in SDL_IMFMusicPlayer().
831 
832 -- K1n9_Duk3
833 -----------------------------------------------------------------------------*/
834 //byte *curAlSound = 0;
835 //byte *curAlSoundPtr = 0;
836 //longword curAlLengthLeft = 0;
837 
SDL_IMFMusicPlayer(void * udata,Uint8 * stream,int len)838 void SDL_IMFMusicPlayer(void *udata, Uint8 *stream, int len)
839 {
840 	int stereolen = len>>1;
841 	int sampleslen = stereolen>>1;
842 	Sint16 *stream16 = (Sint16 *) (void *) stream;    // expect correct alignment
843 
844 	while(1)
845 	{
846 		if(numreadysamples)
847 		{
848 			if(numreadysamples<sampleslen)
849 			{
850 				if(MusicMode == smm_AdLib || SoundMode == sdm_AdLib)
851 					YM3812UpdateOne(oplChip, stream16, numreadysamples);
852 
853 				// Mix the emulated PC sounds into the AdLib buffer:
854 				SDL_PCEmulateAndMix(stream16, numreadysamples);
855 
856 				stream16 += numreadysamples*2;
857 				sampleslen -= numreadysamples;
858 			}
859 			else
860 			{
861 				if(MusicMode == smm_AdLib || SoundMode == sdm_AdLib)
862 					YM3812UpdateOne(oplChip, stream16, sampleslen);
863 
864 				// Mix the emulated PC sounds into the AdLib buffer:
865 				SDL_PCEmulateAndMix(stream16, sampleslen);
866 
867 				numreadysamples -= sampleslen;
868 				return;
869 			}
870 		}
871 
872 		SDL_LockMutex(audioMutex);
873 
874 		soundTimeCounter--;
875 		if(!soundTimeCounter)
876 		{
877 			// Sound effects are played at 140 Hz (every 5 cycles of the 700 Hz music service)
878 			soundTimeCounter = SOUND_TICKS;
879 
880 			SDL_PCService();
881 
882 			// THIS is the way the original Wolfenstein 3-D code handled it!
883 			if(alSound)
884 			{
885 				if(*alSound)
886 				{
887 					alOut(alFreqL, *alSound);
888 					alOut(alFreqH, alBlock);
889 				} else alOut(alFreqH, 0);
890 				alSound++;
891 				if (!(--alLengthLeft))
892 				{
893 					alSound = 0;
894 					SoundPriority=0;
895 					alOut(alFreqH, 0);
896 				}
897 			}
898 		}
899 		if(sqActive)
900 		{
901 			do
902 			{
903 				if(sqHackTime > alTimeCount) break;
904 				sqHackTime = alTimeCount + LittleShort(*(sqHackPtr+1));
905 				alOutMusic(*(byte *) sqHackPtr, *(((byte *) sqHackPtr)+1));
906 				sqHackPtr += 2;
907 				sqHackLen -= 4;
908 			}
909 			while(sqHackLen>0);
910 			alTimeCount++;
911 			if(!sqHackLen)
912 			{
913 				sqHackPtr = sqHack;
914 				sqHackLen = sqHackSeqLen;
915 				sqHackTime = 0;
916 				alTimeCount = 0;
917 			}
918 		}
919 		numreadysamples = samplesPerMusicTick;
920 
921 		SDL_UnlockMutex(audioMutex);
922 	}
923 }
924 
925 ///////////////////////////////////////////////////////////////////////////
926 //
927 //      SD_Startup() - starts up the Sound Mgr
928 //              Detects all additional sound hardware and installs my ISR
929 //
930 ///////////////////////////////////////////////////////////////////////////
931 void
SD_Startup(void)932 SD_Startup(void)
933 {
934 	int     i;
935 
936 	if (SD_Started)
937 		return;
938 
939 	if(SDL_InitSubSystem(SDL_INIT_AUDIO) != 0)
940 	{
941 		Printf("Unable to initialize audio.\n");
942 		return;
943 	}
944 
945 	if((audioMutex = SDL_CreateMutex()) == NULL)
946 	{
947 		printf("Unable to create audio mutex\n");
948 		return;
949 	}
950 
951 #if defined(__ANDROID__)
952 	// Working directory will be in the form: Beloko/Wolf3d/FULL
953 	Mix_SetSoundFonts("../../FluidR3_GM.sf2");
954 #elif defined(__unix__)
955 	Mix_SetSoundFonts("/usr/share/sounds/sf2/FluidR3_GM.sf2");
956 #endif
957 
958 	if(Mix_OpenAudio(param_samplerate, AUDIO_S16, 2, param_audiobuffer))
959 	{
960 		printf("Unable to open audio: %s\n", Mix_GetError());
961 		return;
962 	}
963 
964 	Mix_ReserveChannels(2);  // reserve player and boss weapon channels
965 	Mix_GroupChannels(2, MIX_CHANNELS-1, 1); // group remaining channels
966 
967 	// Init music
968 	if(YM3812Init(1,3579545,param_samplerate))
969 	{
970 		printf("Unable to create virtual OPL!!\n");
971 	}
972 
973 	for(i=1;i<0xf6;i++)
974 		YM3812Write(oplChip,i,0,MAX_VOLUME);
975 
976 	YM3812Write(oplChip,1,0x20,MAX_VOLUME); // Set WSE=1
977 //    YM3812Write(0,8,0); // Set CSM=0 & SEL=0		 // already set in for statement
978 
979 	samplesPerMusicTick = param_samplerate / MUSIC_RATE;    // SDL_t0FastAsmService played at 700Hz
980 	Mix_HookMusic(SDL_IMFMusicPlayer, 0);
981 	Mix_ChannelFinished(SD_ChannelFinished);
982 
983 	Mix_VolumeMusic(static_cast<int> (ceil(128.0*MULTIPLY_VOLUME(MusicVolume))));
984 
985 	// Make sure that the musicFinished() function is called when the music stops playing
986 	Mix_HookMusicFinished(musicFinished);
987 
988 	AdLibPresent = true;
989 	SoundBlasterPresent = true;
990 
991 	alTimeCount = 0;
992 
993 	SD_SetSoundMode(sdm_Off);
994 	SD_SetMusicMode(smm_Off);
995 
996 	SD_Started = true;
997 
998 	SoundInfo.Init();
999 	SoundSeq.Init();
1000 }
1001 
1002 ///////////////////////////////////////////////////////////////////////////
1003 //
1004 //      SD_Shutdown() - shuts down the Sound Mgr
1005 //              Removes sound ISR and turns off whatever sound hardware was active
1006 //
1007 ///////////////////////////////////////////////////////////////////////////
1008 void
SD_Shutdown(void)1009 SD_Shutdown(void)
1010 {
1011 	if (!SD_Started)
1012 		return;
1013 
1014 	SD_MusicOff();
1015 	SD_StopSound();
1016 
1017 	if(audioMutex != NULL)
1018 	{
1019 		SDL_DestroyMutex(audioMutex);
1020 		audioMutex = NULL;
1021 	}
1022 
1023 	SDL_QuitSubSystem(SDL_INIT_AUDIO);
1024 
1025 	SD_Started = false;
1026 }
1027 
1028 ///////////////////////////////////////////////////////////////////////////
1029 //
1030 //      SD_PositionSound() - Sets up a stereo imaging location for the next
1031 //              sound to be played. Each channel ranges from 0 to 15.
1032 //
1033 ///////////////////////////////////////////////////////////////////////////
1034 void
SD_PositionSound(int leftvol,int rightvol)1035 SD_PositionSound(int leftvol,int rightvol)
1036 {
1037 	LeftPosition = leftvol;
1038 	RightPosition = rightvol;
1039 	nextsoundpos = true;
1040 }
1041 
1042 ///////////////////////////////////////////////////////////////////////////
1043 //
1044 //      SD_PlaySound() - plays the specified sound on the appropriate hardware
1045 //              Returns the channel of the sound if it played, else 0.
1046 //
1047 ///////////////////////////////////////////////////////////////////////////
SD_PlaySound(const char * sound,SoundChannel chan)1048 int SD_PlaySound(const char* sound, SoundChannel chan)
1049 {
1050 	bool            ispos;
1051 	int             lp,rp;
1052 
1053 	lp = LeftPosition;
1054 	rp = RightPosition;
1055 	LeftPosition = 0;
1056 	RightPosition = 0;
1057 
1058 	ispos = nextsoundpos;
1059 	nextsoundpos = false;
1060 
1061 	const SoundData &sindex = SoundInfo[sound];
1062 
1063 	if ((SoundMode != sdm_Off) && sindex.IsNull())
1064 		return 0;
1065 
1066 	if ((DigiMode != sds_Off) && sindex.HasType(SoundData::DIGITAL))
1067 	{
1068 		if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
1069 		{
1070 #ifdef NOTYET
1071 			if (s->priority < SoundPriority)
1072 				return 0;
1073 
1074 			SDL_PCStopSound();
1075 
1076 			SD_PlayDigitized(sindex,lp,rp);
1077 			SoundPositioned = ispos;
1078 			SoundPriority = s->priority;
1079 #else
1080 			return 0;
1081 #endif
1082 		}
1083 		else
1084 		{
1085 #ifdef NOTYET
1086 			if (s->priority < DigiPriority)
1087 				return(false);
1088 #endif
1089 
1090 			int channel = SD_PlayDigitized(sindex, lp, rp, chan);
1091 			SoundPositioned = ispos;
1092 			DigiPriority = sindex.GetPriority();
1093 			SoundPlaying = sound;
1094 			return channel;
1095 		}
1096 
1097 		return(true);
1098 	}
1099 
1100 	if (SoundMode == sdm_Off)
1101 		return 0;
1102 
1103 //    if (!s->length)
1104 //        Quit("SD_PlaySound() - Zero length sound");
1105 	if (sindex.GetPriority() < SoundPriority)
1106 		return 0;
1107 
1108 #ifndef ECWOLF_MIXER
1109 	// With stock SDL_mixer we can't play music and emulated sounds.
1110 	if (music != NULL)
1111 		return 0;
1112 #endif
1113 
1114 	bool didPlaySound = false;
1115 
1116 	switch (SoundMode)
1117 	{
1118 		default:
1119 			didPlaySound = true;
1120 			break;
1121 		case sdm_PC:
1122 			if(sindex.HasType(SoundData::PCSPEAKER))
1123 			{
1124 				SDL_PCPlaySound((PCSound *)sindex.GetData(SoundData::PCSPEAKER));
1125 				didPlaySound = true;
1126 			}
1127 			break;
1128 		case sdm_AdLib:
1129 			if(sindex.HasType(SoundData::ADLIB))
1130 			{
1131 				SDL_ALPlaySound((AdLibSound *)sindex.GetData(SoundData::ADLIB));
1132 				didPlaySound = true;
1133 			}
1134 			break;
1135 	}
1136 
1137 	if (didPlaySound)
1138 	{
1139 		SoundPriority = sindex.GetPriority();
1140 		SoundPlaying = sound;
1141 	}
1142 
1143 	return 0;
1144 }
1145 
1146 ///////////////////////////////////////////////////////////////////////////
1147 //
1148 //      SD_SoundPlaying() - returns the sound number that's playing, or 0 if
1149 //              no sound is playing
1150 //
1151 ///////////////////////////////////////////////////////////////////////////
SD_SoundPlaying(void)1152 bool SD_SoundPlaying(void)
1153 {
1154 	bool result = false;
1155 
1156 	switch (SoundMode)
1157 	{
1158 		default:
1159 			break;
1160 		case sdm_PC:
1161 			result = pcSound? true : false;	// not really thread-safe, but a mutex would be overkill
1162 			break;
1163 		case sdm_AdLib:
1164 			result = alSound? true : false;	// not really thread-safe, but a mutex would be overkill
1165 			break;
1166 	}
1167 
1168 	if (result)
1169 		return SoundPlaying.IsNotEmpty();
1170 	else
1171 		return false;
1172 }
1173 
1174 ///////////////////////////////////////////////////////////////////////////
1175 //
1176 //      SD_StopSound() - if a sound is playing, stops it
1177 //
1178 ///////////////////////////////////////////////////////////////////////////
1179 void
SD_StopSound(void)1180 SD_StopSound(void)
1181 {
1182 	if (DigiPlaying)
1183 		SD_StopDigitized();
1184 
1185 	switch (SoundMode)
1186 	{
1187 		default:
1188 			break;
1189 		case sdm_PC:
1190 			SDL_PCStopSound();
1191 			break;
1192 		case sdm_AdLib:
1193 			SDL_ALStopSound();
1194 			break;
1195 	}
1196 
1197 	SoundPositioned = false;
1198 
1199 	SDL_SoundFinished();
1200 }
1201 
1202 ///////////////////////////////////////////////////////////////////////////
1203 //
1204 //      SD_WaitSoundDone() - waits until the current sound is done playing
1205 //
1206 ///////////////////////////////////////////////////////////////////////////
1207 void
SD_WaitSoundDone(void)1208 SD_WaitSoundDone(void)
1209 {
1210 	while (SD_SoundPlaying())
1211 		SDL_Delay(5);
1212 }
1213 
1214 ///////////////////////////////////////////////////////////////////////////
1215 //
1216 //      SD_MusicOn() - turns on the sequencer
1217 //
1218 ///////////////////////////////////////////////////////////////////////////
1219 void
SD_MusicOn(void)1220 SD_MusicOn(void)
1221 {
1222 	sqActive = true;	// not really thread-safe, but a mutex would be overkill
1223 }
1224 
1225 ///////////////////////////////////////////////////////////////////////////
1226 //
1227 //      SD_MusicOff() - turns off the sequencer and any playing notes
1228 //      returns the last music offset for music continue
1229 //
1230 ///////////////////////////////////////////////////////////////////////////
1231 int
SD_MusicOff(void)1232 SD_MusicOff(void)
1233 {
1234 	word    i;
1235 	int musoffs;
1236 
1237 	SDL_LockMutex(audioMutex);
1238 
1239 	sqActive = false;
1240 	musoffs = (int) (sqHackPtr-sqHack);
1241 
1242 	SDL_UnlockMutex(audioMutex);
1243 
1244 	switch (MusicMode)
1245 	{
1246 		default:
1247 			break;
1248 		case smm_AdLib:
1249 			if (music == NULL)
1250 			{
1251 				alOut(alEffects, 0);
1252 				for (i = 0;i < sqMaxTracks;i++)
1253 					alOut(alFreqH + i + 1, 0);
1254 			}
1255 			else
1256 			{
1257 				Mix_PauseMusic();
1258 				return 0;
1259 			}
1260 			break;
1261 	}
1262 
1263 	return musoffs;
1264 }
1265 
1266 ///////////////////////////////////////////////////////////////////////////
1267 //
1268 //      SD_StartMusic() - starts playing the music pointed to
1269 //
1270 ///////////////////////////////////////////////////////////////////////////
1271 void
SD_StartMusic(const char * chunk)1272 SD_StartMusic(const char* chunk)
1273 {
1274 	static const Instrument ChannelRelease = {
1275 		0, 0,
1276 		0x3F, 0x3F,
1277 		0xFF, 0xFF,
1278 		0xF, 0xF,
1279 		0, 0,
1280 		0,
1281 
1282 		0, 0, {0, 0, 0}
1283 	};
1284 
1285 	SD_MusicOff();
1286 
1287 	if (MusicMode == smm_AdLib)
1288 	{
1289 		int lumpNum = Wads.CheckNumForName(chunk, ns_music);
1290 		if(lumpNum == -1)
1291 			return;
1292 
1293 		// Load our music file from chunk
1294 		chunkmem = new byte[Wads.LumpLength(lumpNum)];
1295 		FWadLump lump = Wads.OpenLumpNum(lumpNum);
1296 		lump.Read(chunkmem, Wads.LumpLength(lumpNum));
1297 		SDL_RWops *mus_cunk = SDL_RWFromMem(chunkmem, Wads.LumpLength(lumpNum));
1298 		music = Mix_LoadMUS_RW(mus_cunk);
1299 
1300 		// We assume that when music equals to NULL, we've an IMF file to play
1301 		if (music == NULL)
1302 		{
1303 			Mix_HookMusic(SDL_IMFMusicPlayer, 0);
1304 
1305 			SDL_LockMutex(audioMutex);
1306 
1307 			for (int i = 0;i < OPL_CHANNELS;++i)
1308 				SDL_AlSetChanInst(&ChannelRelease, i);
1309 
1310 			delete[] sqHackFreeable;
1311 			sqHack = reinterpret_cast<word*>(chunkmem);
1312 			sqHackFreeable = sqHack;
1313 			chunkmem = NULL;
1314 			if(*sqHack == 0) sqHackLen = sqHackSeqLen = Wads.LumpLength(lumpNum);
1315 			else sqHackLen = sqHackSeqLen = LittleShort(*sqHack++);
1316 			sqHackPtr = sqHack;
1317 			sqHackTime = 0;
1318 			alTimeCount = 0;
1319 
1320 			SDL_UnlockMutex(audioMutex);
1321 
1322 			SD_MusicOn();
1323 		}
1324 		else
1325 		{
1326 			Mix_HookMusic(0, 0);
1327 
1328 			SDL_LockMutex(audioMutex);
1329 
1330 			// Play the music
1331 			musicchunk = lumpNum;
1332 			if (Mix_PlayMusic(music, -1) == -1)
1333 			{
1334 				printf("Unable to play music file: %s\n", Mix_GetError());
1335 			}
1336 
1337 			SDL_UnlockMutex(audioMutex);
1338 		}
1339 	}
1340 }
1341 
1342 int
SD_PauseMusic(void)1343 SD_PauseMusic(void)
1344 {
1345 	if (music != NULL && Mix_PlayingMusic() == 1)
1346 	{
1347 		Mix_PauseMusic();
1348 		return (int)Mix_GetMusicPCMPosition();
1349 	}
1350 	return 0;
1351 }
1352 
1353 void
SD_ContinueMusic(const char * chunk,int startoffs)1354 SD_ContinueMusic(const char* chunk, int startoffs)
1355 {
1356 	SD_MusicOff();
1357 
1358 	if (MusicMode == smm_AdLib)
1359 	{
1360 		int lumpNum = Wads.CheckNumForName(chunk, ns_music);
1361 		if(lumpNum == -1)
1362 			return;
1363 
1364 		if (music == NULL || musicchunk != lumpNum)
1365 		{ // We need this scope to "delete" the lump before modifying the sqHack pointers.
1366 			SDL_LockMutex(audioMutex);
1367 			FWadLump lump = Wads.OpenLumpNum(lumpNum);
1368 			delete[] sqHackFreeable;
1369 			sqHackFreeable = NULL;
1370 
1371 			// Load our music file from chunk
1372 			chunkmem = new byte[Wads.LumpLength(lumpNum)];
1373 			lump.Read(chunkmem, Wads.LumpLength(lumpNum));
1374 			SDL_RWops *mus_cunk = SDL_RWFromMem(chunkmem, Wads.LumpLength(lumpNum));
1375 			music = Mix_LoadMUS_RW(mus_cunk);
1376 
1377 			if (music == NULL)
1378 			{
1379 				sqHack = reinterpret_cast<word*>(chunkmem);
1380 				sqHackFreeable = sqHack;
1381 				chunkmem = NULL;
1382 				if(*sqHack == 0) sqHackLen = sqHackSeqLen = Wads.LumpLength(lumpNum);
1383 				else sqHackLen = sqHackSeqLen = LittleShort(*sqHack++);
1384 				sqHackPtr = sqHack;
1385 			}
1386 		}
1387 
1388 		if (music == NULL)
1389 		{
1390 			if(startoffs >= sqHackLen)
1391 			{
1392 				SDL_UnlockMutex(audioMutex);
1393 				Quit("SD_StartMusic: Illegal startoffs provided!");
1394 			}
1395 
1396 			// fast forward to correct position
1397 			// (needed to reconstruct the instruments)
1398 
1399 			for(int i = 0; i < startoffs; i += 2)
1400 			{
1401 				byte reg = *(byte *)sqHackPtr;
1402 				byte val = *(((byte *)sqHackPtr) + 1);
1403 				if(reg >= 0xb1 && reg <= 0xb8) val &= 0xdf;           // disable play note flag
1404 				else if(reg == 0xbd) val &= 0xe0;                     // disable drum flags
1405 
1406 				alOut(reg,val);
1407 				sqHackPtr += 2;
1408 				sqHackLen -= 4;
1409 			}
1410 			sqHackTime = 0;
1411 			alTimeCount = 0;
1412 
1413 			SDL_UnlockMutex(audioMutex);
1414 
1415 			Mix_HookMusic(SDL_IMFMusicPlayer, 0);
1416 
1417 			SD_MusicOn();
1418 		}
1419 		else
1420 		{
1421 			SDL_UnlockMutex(audioMutex);
1422 
1423 			Mix_HookMusic(0, 0);
1424 
1425 			if (Mix_PausedMusic() == 1 && musicchunk == lumpNum)
1426 			{
1427 				Mix_ResumeMusic();
1428 				return;
1429 			}
1430 
1431 			// Play the music
1432 			musicchunk = lumpNum;
1433 			if (Mix_PlayMusic(music, -1) == -1)
1434 			{
1435 				printf("Unable to play music file: %s\n", Mix_GetError());
1436 			}
1437 
1438 			Mix_SetMusicPCMPosition(startoffs);
1439 		}
1440 	}
1441 }
1442 
1443 ///////////////////////////////////////////////////////////////////////////
1444 //
1445 //      SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
1446 //              to see if the fadeout is complete
1447 //
1448 ///////////////////////////////////////////////////////////////////////////
1449 void
SD_FadeOutMusic(void)1450 SD_FadeOutMusic(void)
1451 {
1452 	switch (MusicMode)
1453 	{
1454 		default:
1455 			break;
1456 		case smm_AdLib:
1457 			// DEBUG - quick hack to turn the music off
1458 			SD_MusicOff();
1459 			break;
1460 	}
1461 }
1462 
1463 ///////////////////////////////////////////////////////////////////////////
1464 //
1465 //      SD_MusicPlaying() - returns true if music is currently playing, false if
1466 //              not
1467 //
1468 ///////////////////////////////////////////////////////////////////////////
SD_MusicPlaying(void)1469 bool SD_MusicPlaying(void)
1470 {
1471 	bool result;
1472 
1473 	switch (MusicMode)
1474 	{
1475 		case smm_AdLib:
1476 			if (music == NULL)
1477 				result = sqActive;	// not really thread-safe, but a mutex would be overkill
1478 			else
1479 				result = Mix_PlayingMusic() && !Mix_PausedMusic();
1480 			break;
1481 		default:
1482 			result = false;
1483 			break;
1484 	}
1485 
1486 	return(result);
1487 }
1488