1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: snd_data.cpp 4327 2010-07-24 19:30:53Z firebrand_kh $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 #include "gamedefs.h"
29 #include "snd_local.h"
30 
31 // MACROS ------------------------------------------------------------------
32 
33 // TYPES -------------------------------------------------------------------
34 
35 #ifdef CLIENT
36 class VRawSampleLoader : public VSampleLoader
37 {
38 public:
39 	void Load(sfxinfo_t&, VStream&);
40 };
41 #endif
42 
43 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
44 
45 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
46 
47 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
48 
49 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
50 
51 // PUBLIC DATA DEFINITIONS -------------------------------------------------
52 
53 VSampleLoader*		VSampleLoader::List;
54 
55 VSoundManager*		GSoundManager;
56 
57 // PRIVATE DATA DEFINITIONS ------------------------------------------------
58 
59 #ifdef CLIENT
60 static VRawSampleLoader		RawSampleLoader;
61 #endif
62 
63 // CODE --------------------------------------------------------------------
64 
65 //==========================================================================
66 //
67 //	VSoundManager::VSoundManager
68 //
69 //==========================================================================
70 
VSoundManager()71 VSoundManager::VSoundManager()
72 : NumPlayerReserves(0)
73 , CurrentChangePitch(7.0 / 255.0)
74 {
75 	memset(AmbientSounds, 0, sizeof(AmbientSounds));
76 }
77 
78 //==========================================================================
79 //
80 //	VSoundManager::~VSoundManager
81 //
82 //==========================================================================
83 
~VSoundManager()84 VSoundManager::~VSoundManager()
85 {
86 	guard(VSoundManager::~VSoundManager);
87 	for (int i = 0; i < S_sfx.Num(); i++)
88 	{
89 		if (S_sfx[i].Data)
90 		{
91 			Z_Free(S_sfx[i].Data);
92 		}
93 		if (S_sfx[i].Sounds)
94 		{
95 			delete[] S_sfx[i].Sounds;
96 			S_sfx[i].Sounds = NULL;
97 		}
98 	}
99 
100 	for (int i = 0; i < NUM_AMBIENT_SOUNDS; i++)
101 	{
102 		if (AmbientSounds[i])
103 		{
104 			delete AmbientSounds[i];
105 			AmbientSounds[i] = NULL;
106 		}
107 	}
108 
109 	for (int i = 0; i < SeqInfo.Num(); i++)
110 	{
111 		if (SeqInfo[i].Data)
112 		{
113 			delete[] SeqInfo[i].Data;
114 			SeqInfo[i].Data = NULL;
115 		}
116 	}
117 
118 	for (VReverbInfo* R = Environments; R;)
119 	{
120 		VReverbInfo* Next = R->Next;
121 		if (!R->Builtin)
122 		{
123 			delete[] const_cast<char*>(R->Name);
124 			R->Name = NULL;
125 			delete R;
126 			R = NULL;
127 		}
128 		R = Next;
129 	}
130 	unguard;
131 }
132 
133 //==========================================================================
134 //
135 //	VSoundManager::Init
136 //
137 //	Loads sound script lump or file, if param -devsnd was specified
138 //
139 //==========================================================================
140 
Init()141 void VSoundManager::Init()
142 {
143 	guard(VSoundManager::Init);
144 	int Lump;
145 
146 	//	Sound 0 is empty sound.
147 	AddSoundLump(NAME_None, -1);
148 
149 	//	Add Strife voices.
150 	for (Lump = W_IterateNS(-1, WADNS_Voices); Lump >= 0;
151 		Lump = W_IterateNS(Lump, WADNS_Voices))
152 	{
153 		char SndName[16];
154 		sprintf(SndName, "svox/%s", *W_LumpName(Lump));
155 
156 		int id = AddSoundLump(SndName, Lump);
157 		S_sfx[id].ChangePitch = 0;
158 	}
159 
160 	//	Load script SNDINFO
161 	for (Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
162 		Lump = W_IterateNS(Lump, WADNS_Global))
163 	{
164 		if (W_LumpName(Lump) == NAME_sndinfo)
165 		{
166 			ParseSndinfo(new VScriptParser(*W_LumpName(Lump),
167 				W_CreateLumpReaderNum(Lump)));
168 		}
169 	}
170 
171 	S_sfx.Condense();
172 
173 	//	Load script SNDSEQ
174 	memset(SeqTrans, -1, sizeof(SeqTrans));
175 	for (int Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
176 		Lump = W_IterateNS(Lump, WADNS_Global))
177 	{
178 		if (W_LumpName(Lump) == NAME_sndseq)
179 		{
180 			ParseSequenceScript(new VScriptParser(*W_LumpName(Lump),
181 				W_CreateLumpReaderNum(Lump)));
182 		}
183 	}
184 
185 	//	Load script REVERBS
186 	Environments = NULL;
187 	for (Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
188 		Lump = W_IterateNS(Lump, WADNS_Global))
189 	{
190 		if (W_LumpName(Lump) == NAME_reverbs)
191 		{
192 			ParseReverbs(new VScriptParser(*W_LumpName(Lump),
193 				W_CreateLumpReaderNum(Lump)));
194 		}
195 	}
196 	unguard;
197 }
198 
199 //==========================================================================
200 //
201 //	VSoundManager::ParseSndinfo
202 //
203 //==========================================================================
204 
ParseSndinfo(VScriptParser * sc)205 void VSoundManager::ParseSndinfo(VScriptParser* sc)
206 {
207 	guard(VSoundManager::ParseSndinfo);
208 	TArray<int>		list;
209 
210 	while (!sc->AtEnd())
211 	{
212 		if (sc->Check("$archivepath"))
213 		{
214 			// $archivepath <directory>
215 			//	Ignored.
216 			sc->ExpectString();
217 		}
218 		else if (sc->Check("$map"))
219 		{
220 			// $map <map number> <song name>
221 			sc->ExpectNumber();
222 			sc->ExpectName();
223 			if (sc->Number)
224 			{
225 				P_PutMapSongLump(sc->Number, sc->Name);
226 			}
227 		}
228 		else if (sc->Check("$registered"))
229 		{
230 			// $registered
231 			//	Unused.
232 		}
233 		else if (sc->Check("$limit"))
234 		{
235 			// $limit <logical name> <max channels>
236 			sc->ExpectString();
237 			int sfx = FindOrAddSound(*sc->String);
238 			sc->ExpectNumber();
239 			S_sfx[sfx].NumChannels = MID(0, sc->Number, 255);
240 		}
241 		else if (sc->Check("$pitchshift"))
242 		{
243 			// $pitchshift <logical name> <pitch shift amount>
244 			sc->ExpectString();
245 			int sfx = FindOrAddSound(*sc->String);
246 			sc->ExpectNumber();
247 			S_sfx[sfx].ChangePitch = ((1 << MID(0, sc->Number, 7)) - 1) / 255.0;
248 		}
249 		else if (sc->Check("$pitchshiftrange"))
250 		{
251 			// $pitchshiftrange <pitch shift amount>
252 			sc->ExpectNumber();
253 			CurrentChangePitch = ((1 << MID(0, sc->Number, 7)) - 1) / 255.0;
254 		}
255 		else if (sc->Check("$alias"))
256 		{
257 			// $alias <name of alias> <name of real sound>
258 			sc->ExpectString();
259 			int sfxfrom = AddSound(*sc->String, -1);
260 			sc->ExpectString();
261 			//if (S_sfx[sfxfrom].bPlayerCompat)
262 			//{
263 			//	sfxfrom = S_sfx[sfxfrom].link;
264 			//}
265 			S_sfx[sfxfrom].Link = FindOrAddSound(*sc->String);
266 		}
267 		else if (sc->Check("$random"))
268 		{
269 			// $random <logical name> { <logical name> ... }
270 			list.Clear();
271 			sc->ExpectString();
272 			int id = AddSound(*sc->String, -1);
273 			sc->Expect("{");
274 			while (!sc->Check("}"))
275 			{
276 				sc->ExpectString();
277 				int sfxto = FindOrAddSound(*sc->String);
278 				list.Append(sfxto);
279 			}
280 			if (list.Num() == 1)
281 			{
282 				// Only one sound: treat as $alias
283 				S_sfx[id].Link = list[0];
284 			}
285 			else if (list.Num() > 1)
286 			{
287 				// Only add non-empty random lists
288 				S_sfx[id].Link = list.Num();
289 				S_sfx[id].Sounds = new int[list.Num()];
290 				memcpy(S_sfx[id].Sounds, &list[0], sizeof(int) * list.Num());
291 				S_sfx[id].bRandomHeader = true;
292 			}
293 		}
294 		else if (sc->Check("$playersound"))
295 		{
296 			// $playersound <player class> <gender> <logical name> <lump name>
297 			int PClass, Gender, RefId;
298 			char FakeName[NAME_SIZE];
299 			size_t len;
300 			int id;
301 
302 			ParsePlayerSoundCommon(sc, PClass, Gender, RefId);
303 			len = VStr::Length(*PlayerClasses[PClass]);
304 			memcpy(FakeName, *PlayerClasses[PClass], len);
305 			FakeName[len] = '|';
306 			FakeName[len + 1] = Gender + '0';
307 			VStr::Cpy(&FakeName[len + 2], *S_sfx[RefId].TagName);
308 
309 			id = AddSoundLump(FakeName, W_CheckNumForName(
310 				VName(*sc->String, VName::AddLower), WADNS_Sounds));
311 			FPlayerSound& PlrSnd = PlayerSounds.Alloc();
312 			PlrSnd.ClassId = PClass;
313 			PlrSnd.GenderId = Gender;
314 			PlrSnd.RefId = RefId;
315 			PlrSnd.SoundId = id;
316 		}
317 		else if (sc->Check("$playersounddup"))
318 		{
319 			// $playersounddup <player class> <gender> <logical name> <target sound name>
320 			int PClass, Gender, RefId, TargId;
321 
322 			ParsePlayerSoundCommon(sc, PClass, Gender, RefId);
323 			TargId = FindSound(*sc->String);
324 			if (!TargId)
325 			{
326 				TargId = AddSound(*sc->String, -1);
327 				S_sfx[TargId].Link = NumPlayerReserves++;
328 				S_sfx[TargId].bPlayerReserve = true;
329 			}
330 			else if (!S_sfx[TargId].bPlayerReserve)
331 			{
332 				sc->Error(va("%s is not a player sound", *sc->String));
333 			}
334 			int AliasTo = FindPlayerSound(PClass, Gender, TargId);
335 			FPlayerSound& PlrSnd = PlayerSounds.Alloc();
336 			PlrSnd.ClassId = PClass;
337 			PlrSnd.GenderId = Gender;
338 			PlrSnd.RefId = RefId;
339 			PlrSnd.SoundId = AliasTo;
340 		}
341 		else if (sc->Check("$playeralias"))
342 		{
343 			// $playeralias <player class> <gender> <logical name> <logical name of existing sound>
344 			int PClass, Gender, RefId;
345 
346 			ParsePlayerSoundCommon(sc, PClass, Gender, RefId);
347 			int AliasTo = FindOrAddSound(*sc->String);
348 			FPlayerSound& PlrSnd = PlayerSounds.Alloc();
349 			PlrSnd.ClassId = PClass;
350 			PlrSnd.GenderId = Gender;
351 			PlrSnd.RefId = RefId;
352 			PlrSnd.SoundId = AliasTo;
353 		}
354 		else if (sc->Check("$singular"))
355 		{
356 			// $singular <logical name>
357 			sc->ExpectString();
358 			int sfx = FindOrAddSound(*sc->String);
359 			S_sfx[sfx].bSingular = true;
360 		}
361 		else if (sc->Check("$ambient"))
362 		{
363 			// $ambient <num> <logical name> [point [atten] | surround | [world]]
364 			//			<continuous | random <minsecs> <maxsecs> | periodic <secs>>
365 			//			<volume>
366 			FAmbientSound* ambient, dummy;
367 
368 			sc->ExpectNumber();
369 			if (sc->Number < 0 || sc->Number >= NUM_AMBIENT_SOUNDS)
370 			{
371 				GCon->Logf("Bad ambient index (%d)", sc->Number);
372 				ambient = &dummy;
373 			}
374 			else if (AmbientSounds[sc->Number])
375 			{
376 				ambient = AmbientSounds[sc->Number];
377 			}
378 			else
379 			{
380 				ambient = new FAmbientSound;
381 				AmbientSounds[sc->Number] = ambient;
382 			}
383 			memset(ambient, 0, sizeof(FAmbientSound));
384 
385 			sc->ExpectString();
386 			ambient->Sound = *sc->String;
387 			ambient->Attenuation = 0;
388 
389 			if (sc->Check("point"))
390 			{
391 				ambient->Type = SNDTYPE_Point;
392 				if (sc->CheckFloat())
393 				{
394 					if (sc->Float > 0)
395 					{
396 						ambient->Attenuation = sc->Float;
397 					}
398 					else
399 					{
400 						ambient->Attenuation = 1;
401 					}
402 				}
403 				else
404 				{
405 					ambient->Attenuation = 1;
406 				}
407 			}
408 			else if (sc->Check("surround"))
409 			{
410 				ambient->Type = SNDTYPE_Surround;
411 				ambient->Attenuation = -1;
412 			}
413 			else if (sc->Check("world"))
414 			{
415 				// World is an optional keyword
416 			}
417 
418 			if (sc->Check("continuous"))
419 			{
420 				ambient->Type |= SNDTYPE_Continuous;
421 			}
422 			else if (sc->Check("random"))
423 			{
424 				ambient->Type |= SNDTYPE_Random;
425 				sc->ExpectFloat();
426 				ambient->PeriodMin = sc->Float;
427 				sc->ExpectFloat();
428 				ambient->PeriodMax = sc->Float;
429 			}
430 			else if (sc->Check("periodic"))
431 			{
432 				ambient->Type |= SNDTYPE_Periodic;
433 				sc->ExpectFloat();
434 				ambient->PeriodMin = sc->Float;
435 			}
436 			else
437 			{
438 				sc->ExpectString();
439 				GCon->Logf("Unknown ambient type (%s)", *sc->String);
440 			}
441 
442 			sc->ExpectFloat();
443 			ambient->Volume = sc->Float;
444 			if (ambient->Volume > 1)
445 				ambient->Volume = 1;
446 			else if (ambient->Volume < 0)
447 				ambient->Volume = 0;
448 		}
449 		else if (sc->Check("$musicvolume"))
450 		{
451 			sc->ExpectName();
452 			VName SongName = sc->Name;
453 			sc->ExpectFloat();
454 			int i;
455 			for (i = 0; i < MusicVolumes.Num(); i++)
456 			{
457 				if (MusicVolumes[i].SongName == SongName)
458 				{
459 					MusicVolumes[i].Volume = sc->Float;
460 					break;
461 				}
462 			}
463 			if (i == MusicVolumes.Num())
464 			{
465 				VMusicVolume& V = MusicVolumes.Alloc();
466 				V.SongName = SongName;
467 				V.Volume = sc->Float;
468 			}
469 		}
470 		else if (sc->Check("$ifdoom") || sc->Check("$ifheretic") ||
471 			sc->Check("$ifhexen") || sc->Check("$ifstrife") ||
472 			sc->Check("$endif"))
473 		{
474 			GCon->Log("Conditional SNDINFO commands are not supported");
475 		}
476 		else if (sc->Check("$volume"))
477 		{
478 			GCon->Log("$volume is not supported yet.");
479 		}
480 		else
481 		{
482 			sc->ExpectString();
483 			if (**sc->String == '$')
484 			{
485 				sc->Error("Unknown command");
486 			}
487 			VName TagName = *sc->String;
488 			sc->ExpectName();
489 			AddSound(TagName, W_CheckNumForName(sc->Name, WADNS_Sounds));
490 		}
491 	}
492 	delete sc;
493 	sc = NULL;
494 	unguard;
495 }
496 
497 //==========================================================================
498 //
499 //	VSoundManager::AddSoundLump
500 //
501 //==========================================================================
502 
AddSoundLump(VName TagName,int Lump)503 int VSoundManager::AddSoundLump(VName TagName, int Lump)
504 {
505 	guard(VSoundManager::AddSoundLump);
506 	sfxinfo_t S;
507 	memset(&S, 0, sizeof(S));
508 	S.TagName = TagName;
509 	S.Data = NULL;
510 	S.Priority = 127;
511 	S.NumChannels = 2;
512 	S.ChangePitch = CurrentChangePitch;
513 	S.LumpNum = Lump;
514 	S.Link = -1;
515 	return S_sfx.Append(S);
516 	unguard;
517 }
518 
519 //==========================================================================
520 //
521 //	VSoundManager::AddSound
522 //
523 //==========================================================================
524 
AddSound(VName TagName,int Lump)525 int VSoundManager::AddSound(VName TagName, int Lump)
526 {
527 	guard(VSoundManager::AddSound);
528 	int id = FindSound(TagName);
529 
530 	if (id > 0)
531 	{
532 		// If the sound has already been defined, change the old definition
533 		sfxinfo_t* sfx = &S_sfx[id];
534 
535 		//if (sfx->bPlayerReserve)
536 		//{
537 		//	SC_ScriptError("Sounds that are reserved for players cannot be reassigned");
538 		//}
539 		// Redefining a player compatibility sound will redefine the target instead.
540 		//if (sfx->bPlayerCompat)
541 		//{
542 		//	sfx = &S_sfx[sfx->link];
543 		//}
544 		if (sfx->bRandomHeader)
545 		{
546 			delete[] sfx->Sounds;
547 			sfx->Sounds = NULL;
548 		}
549 		sfx->LumpNum = Lump;
550 		sfx->bRandomHeader = false;
551 		sfx->Link = -1;
552 	}
553 	else
554 	{
555 		// Otherwise, create a new definition.
556 		id = AddSoundLump(TagName, Lump);
557 	}
558 
559 	return id;
560 	unguard;
561 }
562 
563 //==========================================================================
564 //
565 //	VSoundManager::FindSound
566 //
567 //==========================================================================
568 
FindSound(VName TagName)569 int VSoundManager::FindSound(VName TagName)
570 {
571 	guard(VSoundManager::FindSound);
572 	for (int i = 0; i < S_sfx.Num(); i++)
573 	{
574 		if (!VStr::ICmp(*S_sfx[i].TagName, *TagName))
575 		{
576 			return i;
577 		}
578 	}
579 	return 0;
580 	unguard;
581 }
582 
583 //==========================================================================
584 //
585 //	VSoundManager::FindOrAddSound
586 //
587 //==========================================================================
588 
FindOrAddSound(VName TagName)589 int VSoundManager::FindOrAddSound(VName TagName)
590 {
591 	guard(VSoundManager::FindOrAddSound);
592 	int id = FindSound(TagName);
593 	return id ? id : AddSoundLump(TagName, -1);
594 	unguard;
595 }
596 
597 //==========================================================================
598 //
599 //	VSoundManager::ParsePlayerSoundCommon
600 //
601 //	Parses the common part of playersound commands in SNDINFO
602 // (player class, gender, and ref id)
603 //
604 //==========================================================================
605 
ParsePlayerSoundCommon(VScriptParser * sc,int & PClass,int & Gender,int & RefId)606 void VSoundManager::ParsePlayerSoundCommon(VScriptParser* sc, int& PClass,
607 	int& Gender, int& RefId)
608 {
609 	guard(VSoundManager::ParsePlayerSoundCommon);
610 	sc->ExpectString();
611 	PClass = AddPlayerClass(*sc->String);
612 	sc->ExpectString();
613 	Gender = AddPlayerGender(*sc->String);
614 	sc->ExpectString();
615 	RefId = FindSound(*sc->String);
616 	if (!RefId)
617 	{
618 		RefId = AddSound(*sc->String, -1);
619 		S_sfx[RefId].Link = NumPlayerReserves++;
620 		S_sfx[RefId].bPlayerReserve = true;
621 	}
622 	else if (!S_sfx[RefId].bPlayerReserve)
623 	{
624 		sc->Error(va("%s has not been reserved for a player sound",
625 			*sc->String));
626 	}
627 	sc->ExpectString();
628 	unguard;
629 }
630 
631 //==========================================================================
632 //
633 //	VSoundManager::AddPlayerClass
634 //
635 //==========================================================================
636 
AddPlayerClass(VName CName)637 int VSoundManager::AddPlayerClass(VName CName)
638 {
639 	guard(VSoundManager::AddPlayerClass);
640 	int idx = FindPlayerClass(CName);
641 	return idx == -1 ? PlayerClasses.Append(CName) : idx;
642 	unguard;
643 }
644 
645 //==========================================================================
646 //
647 //	VSoundManager::FindPlayerClass
648 //
649 //==========================================================================
650 
FindPlayerClass(VName CName)651 int VSoundManager::FindPlayerClass(VName CName)
652 {
653 	guard(VSoundManager::FindPlayerClass);
654 	for (int i = 0; i < PlayerClasses.Num(); i++)
655 		if (PlayerClasses[i] == CName)
656 			return i;
657 	return -1;
658 	unguard;
659 }
660 
661 //==========================================================================
662 //
663 //	VSoundManager::AddPlayerGender
664 //
665 //==========================================================================
666 
AddPlayerGender(VName GName)667 int VSoundManager::AddPlayerGender(VName GName)
668 {
669 	guard(VSoundManager::AddPlayerGender);
670 	int idx = FindPlayerGender(GName);
671 	return idx == -1 ? PlayerGenders.Append(GName) : idx;
672 	unguard;
673 }
674 
675 //==========================================================================
676 //
677 //	VSoundManager::FindPlayerGender
678 //
679 //==========================================================================
680 
FindPlayerGender(VName GName)681 int VSoundManager::FindPlayerGender(VName GName)
682 {
683 	guard(VSoundManager::FindPlayerGender);
684 	for (int i = 0; i < PlayerGenders.Num(); i++)
685 		if (PlayerGenders[i] == GName)
686 			return i;
687 	return -1;
688 	unguard;
689 }
690 
691 //==========================================================================
692 //
693 //	VSoundManager::FindPlayerSound
694 //
695 //==========================================================================
696 
FindPlayerSound(int PClass,int Gender,int RefId)697 int VSoundManager::FindPlayerSound(int PClass, int Gender, int RefId)
698 {
699 	guard(VSoundManager::FindPlayerSound);
700 	for (int i = 0; i < PlayerSounds.Num(); i++)
701 	{
702 		if (PlayerSounds[i].ClassId == PClass &&
703 			PlayerSounds[i].GenderId == Gender &&
704 			PlayerSounds[i].RefId == RefId)
705 		{
706 			return PlayerSounds[i].SoundId;
707 		}
708 	}
709 	return 0;
710 	unguard;
711 }
712 
713 //==========================================================================
714 //
715 //	VSoundManager::LookupPlayerSound
716 //
717 //==========================================================================
718 
LookupPlayerSound(int ClassId,int GenderId,int RefId)719 int VSoundManager::LookupPlayerSound(int ClassId, int GenderId, int RefId)
720 {
721 	guard(VSoundManager::LookupPlayerSound);
722 	int Id = FindPlayerSound(ClassId, GenderId, RefId);
723 	if (Id == 0 || (S_sfx[Id].LumpNum == -1 && S_sfx[Id].Link == -1))
724 	{
725 		// This sound is unavailable.
726 		if (GenderId)
727 		{
728 			// Try "male"
729 			return LookupPlayerSound(ClassId, 0, RefId);
730 		}
731 		if (ClassId)
732 		{
733 			// Try the default class.
734 			return LookupPlayerSound(0, GenderId, RefId);
735 		}
736 	}
737 	return Id;
738 	unguard;
739 }
740 
741 //==========================================================================
742 //
743 //	VSoundManager::GetSoundID
744 //
745 //==========================================================================
746 
GetSoundID(VName Name)747 int VSoundManager::GetSoundID(VName Name)
748 {
749 	guard(VSoundManager::GetSoundID);
750 	for (int i = 0; i < S_sfx.Num(); i++)
751 	{
752 		if (!VStr::ICmp(*S_sfx[i].TagName, *Name))
753 		{
754 			return i;
755 		}
756 	}
757 	GCon->Logf("WARNING! Can't find sound %s", *Name);
758 	return 0;
759 	unguard;
760 }
761 
762 //==========================================================================
763 //
764 //	VSoundManager::GetSoundID
765 //
766 //==========================================================================
767 
GetSoundID(const char * name)768 int VSoundManager::GetSoundID(const char *name)
769 {
770 	guard(VSoundManager::GetSoundID);
771 	for (int i = 0; i < S_sfx.Num(); i++)
772 	{
773 		if (!VStr::ICmp(*S_sfx[i].TagName, name))
774 		{
775 			return i;
776 		}
777 	}
778 	GCon->Logf("WARNING! Can't find sound named %s", name);
779 	return 0;
780 	unguard;
781 }
782 
783 //==========================================================================
784 //
785 //	VSoundManager::ResolveSound
786 //
787 //==========================================================================
788 
ResolveSound(int InSoundId)789 int VSoundManager::ResolveSound(int InSoundId)
790 {
791 	guard(VSoundManager::ResolveSound);
792 	return ResolveSound(0, 0, InSoundId);
793 	unguard;
794 }
795 
796 //==========================================================================
797 //
798 //	VSoundManager::ResolveEntitySound
799 //
800 //==========================================================================
801 
ResolveEntitySound(VName ClassName,VName GenderName,VName SoundName)802 int VSoundManager::ResolveEntitySound(VName ClassName, VName GenderName,
803 	VName SoundName)
804 {
805 	guard(VSoundManager::ResolveEntitySound);
806 	int ClassId = FindPlayerClass(ClassName);
807 	if (ClassId == -1)
808 		ClassId = 0;
809 	int GenderId = FindPlayerGender(GenderName);
810 	if (GenderId == -1)
811 		GenderId = 0;
812 	int SoundId = GetSoundID(SoundName);
813 	return ResolveSound(ClassId, GenderId, SoundId);
814 	unguard;
815 }
816 
817 //==========================================================================
818 //
819 //	VSoundManager::ResolveSound
820 //
821 //==========================================================================
822 
ResolveSound(int ClassID,int GenderID,int InSoundId)823 int VSoundManager::ResolveSound(int ClassID, int GenderID, int InSoundId)
824 {
825 	guard(VSoundManager::ResolveSound);
826 	int sound_id = InSoundId;
827 	while (S_sfx[sound_id].Link != -1)
828 	{
829 		if (S_sfx[sound_id].bPlayerReserve)
830 		{
831 			sound_id = LookupPlayerSound(ClassID, GenderID, sound_id);
832 		}
833 		else if (S_sfx[sound_id].bRandomHeader)
834 		{
835 			sound_id = S_sfx[sound_id].Sounds[rand() % S_sfx[sound_id].Link];
836 		}
837 		else
838 		{
839 			sound_id = S_sfx[sound_id].Link;
840 		}
841 	}
842 	return sound_id;
843 	unguard;
844 }
845 
846 //==========================================================================
847 //
848 //	VSoundManager::IsSoundPresent
849 //
850 //==========================================================================
851 
IsSoundPresent(VName ClassName,VName GenderName,VName SoundName)852 bool VSoundManager::IsSoundPresent(VName ClassName, VName GenderName,
853 	VName SoundName)
854 {
855 	guard(VSoundManager::IsSoundPresent);
856 	int SoundId = FindSound(SoundName);
857 	if (!SoundId)
858 	{
859 		return false;
860 	}
861 	int ClassId = FindPlayerClass(ClassName);
862 	if (ClassId == -1)
863 	{
864 		ClassId = 0;
865 	}
866 	int GenderId = FindPlayerGender(GenderName);
867 	if (GenderId == -1)
868 	{
869 		GenderId = 0;
870 	}
871 	return ResolveSound(ClassId, GenderId, SoundId) > 0;
872 	unguard;
873 }
874 
875 //==========================================================================
876 //
877 //	VSoundManager::LoadSound
878 //
879 //==========================================================================
880 
LoadSound(int sound_id)881 bool VSoundManager::LoadSound(int sound_id)
882 {
883 	guard(VSoundManager::LoadSound);
884 	static const char* Exts[] = { "flac", "wav", "raw", NULL };
885 
886 	if (!S_sfx[sound_id].Data)
887 	{
888 		int Lump = S_sfx[sound_id].LumpNum;
889 		if (S_sfx[sound_id].LumpNum < 0)
890 		{
891 			GCon->Logf(NAME_Dev, "Sound %s lump not found",
892 				*S_sfx[sound_id].TagName);
893 			return false;
894 		}
895 		int FileLump = W_FindLumpByFileNameWithExts(va("sound/%s",
896 			*W_LumpName(Lump)), Exts);
897 		if (Lump < FileLump)
898 		{
899 			Lump = FileLump;
900 		}
901 		VStream* Strm = W_CreateLumpReaderNum(Lump);
902 
903 		for (VSampleLoader* Ldr = VSampleLoader::List;
904 			Ldr && !S_sfx[sound_id].Data; Ldr = Ldr->Next)
905 		{
906 			Ldr->Load(S_sfx[sound_id], *Strm);
907 		}
908 		delete Strm;
909 		Strm = NULL;
910 		if (!S_sfx[sound_id].Data)
911 		{
912 			GCon->Logf(NAME_Dev, "Failed to load sound %s",
913 				*S_sfx[sound_id].TagName);
914 			return false;
915 		}
916 	}
917 	S_sfx[sound_id].UseCount++;
918 	return true;
919 	unguard;
920 }
921 
922 //==========================================================================
923 //
924 //	VSoundManager::DoneWithLump
925 //
926 //==========================================================================
927 
DoneWithLump(int sound_id)928 void VSoundManager::DoneWithLump(int sound_id)
929 {
930 	guard(VSoundManager::DoneWithLump);
931 	sfxinfo_t &sfx = S_sfx[sound_id];
932 	if (!sfx.Data || !sfx.UseCount)
933 	{
934 		Sys_Error("Empty lump");
935 	}
936 
937 	sfx.UseCount--;
938 	if (sfx.UseCount)
939 	{
940 		//	still used
941 		return;
942 	}
943 	Z_Free(sfx.Data);
944 	sfx.Data = NULL;
945 	unguard;
946 }
947 
948 //==========================================================================
949 //
950 //	VSoundManager::GetMusicVolume
951 //
952 //==========================================================================
953 
GetMusicVolume(VName SongName)954 float VSoundManager::GetMusicVolume(VName SongName)
955 {
956 	guard(VSoundManager::GetMusicVolume);
957 	for (int i = 0; i < MusicVolumes.Num(); i++)
958 	{
959 		if (MusicVolumes[i].SongName == SongName)
960 		{
961 			return MusicVolumes[i].Volume;
962 		}
963 	}
964 	return 1.0;
965 	unguard;
966 }
967 
968 //==========================================================================
969 //
970 //	VSoundManager::GetAmbientSound
971 //
972 //==========================================================================
973 
GetAmbientSound(int Idx)974 FAmbientSound* VSoundManager::GetAmbientSound(int Idx)
975 {
976 	guardSlow(VSoundManager::GetAmbientSound);
977 	if (Idx < 0 || Idx >= NUM_AMBIENT_SOUNDS)
978 	{
979 		return NULL;
980 	}
981 	return AmbientSounds[Idx];
982 	unguardSlow;
983 }
984 
985 //==========================================================================
986 //
987 //	VSoundManager::ParseSequenceScript
988 //
989 //==========================================================================
990 
ParseSequenceScript(VScriptParser * sc)991 void VSoundManager::ParseSequenceScript(VScriptParser* sc)
992 {
993 	guard(VSoundManager::ParseSequenceScript);
994 	TArray<vint32>	TempData;
995 	bool			inSequence = false;
996 	int				SeqId = 0;
997 	int				DelayOnceIndex = 0;
998 	char			SeqType = ':';
999 
1000 	while (!sc->AtEnd())
1001 	{
1002 		sc->ExpectString();
1003 		if (**sc->String == ':' || **sc->String == '[')
1004 		{
1005 			if (inSequence)
1006 			{
1007 				sc->Error("SN_InitSequenceScript:  Nested Script Error");
1008 			}
1009 			for (SeqId = 0; SeqId < SeqInfo.Num(); SeqId++)
1010 			{
1011 				if (SeqInfo[SeqId].Name == *sc->String + 1)
1012 				{
1013 					Z_Free(SeqInfo[SeqId].Data);
1014 					break;
1015 				}
1016 			}
1017 			if (SeqId == SeqInfo.Num())
1018 			{
1019 				SeqInfo.Alloc();
1020 			}
1021 			TempData.Clear();
1022 			inSequence = true;
1023 			DelayOnceIndex = 0;
1024 			SeqType = sc->String[0];
1025 			SeqInfo[SeqId].Name = *sc->String + 1;
1026 			SeqInfo[SeqId].Slot = NAME_None;
1027 			SeqInfo[SeqId].Data = NULL;
1028 			SeqInfo[SeqId].StopSound = 0;
1029 			if (SeqType == '[')
1030 			{
1031 				TempData.Append(SSCMD_Select);
1032 				TempData.Append(0);
1033 				sc->SetCMode(true);
1034 			}
1035 			continue; // parse the next command
1036 		}
1037 		if (!inSequence)
1038 		{
1039 			sc->Error("String outside sequence");
1040 			continue;
1041 		}
1042 		sc->UnGet();
1043 
1044 		if (sc->Check("door"))
1045 		{
1046 			//	door <number>...
1047 			AssignSeqTranslations(sc, SeqId, SEQ_Door);
1048 			continue;
1049 		}
1050 		if (sc->Check("platform"))
1051 		{
1052 			//	platform <number>...
1053 			AssignSeqTranslations(sc, SeqId, SEQ_Platform);
1054 			continue;
1055 		}
1056 		if (sc->Check("environment"))
1057 		{
1058 			//	environment <number>...
1059 			AssignSeqTranslations(sc, SeqId, SEQ_Environment);
1060 			continue;
1061 		}
1062 
1063 		if (SeqType == '[')
1064 		{
1065 			//	Selection sequence
1066 			if (sc->Check("]"))
1067 			{
1068 				TempData[1] = (TempData.Num() - 2) / 2;
1069 				TempData.Append(SSCMD_End);
1070 				SeqInfo[SeqId].Data = new vint32[TempData.Num()];
1071 				memcpy(SeqInfo[SeqId].Data, TempData.Ptr(), TempData.Num() *
1072 					sizeof(vint32));
1073 				inSequence = false;
1074 				sc->SetCMode(false);
1075 			}
1076 			else
1077 			{
1078 				sc->ExpectNumber();
1079 				TempData.Append(sc->Number);
1080 				sc->ExpectString();
1081 				TempData.Append(VName(*sc->String).GetIndex());
1082 			}
1083 			continue;
1084 		}
1085 
1086 		if (sc->Check("play"))
1087 		{
1088 			//	play <sound>
1089 			sc->ExpectString();
1090 			TempData.Append(SSCMD_Play);
1091 			TempData.Append(GetSoundID(*sc->String));
1092 		}
1093 		else if (sc->Check("playuntildone"))
1094 		{
1095 			//	playuntildone <sound>
1096 			sc->ExpectString();
1097 			TempData.Append(SSCMD_Play);
1098 			TempData.Append(GetSoundID(*sc->String));
1099 			TempData.Append(SSCMD_WaitUntilDone);
1100 		}
1101 		else if (sc->Check("playtime"))
1102 		{
1103 			//	playtime <string> <tics>
1104 			sc->ExpectString();
1105 			TempData.Append(SSCMD_Play);
1106 			TempData.Append(GetSoundID(*sc->String));
1107 			sc->ExpectNumber();
1108 			TempData.Append(SSCMD_Delay);
1109 			TempData.Append(sc->Number);
1110 		}
1111 		else if (sc->Check("playrepeat"))
1112 		{
1113 			//	playrepeat <sound>
1114 			sc->ExpectString();
1115 			TempData.Append(SSCMD_PlayRepeat);
1116 			TempData.Append(GetSoundID(*sc->String));
1117 		}
1118 		else if (sc->Check("playloop"))
1119 		{
1120 			//	playloop <sound> <count>
1121 			sc->ExpectString();
1122 			TempData.Append(SSCMD_PlayLoop);
1123 			TempData.Append(GetSoundID(*sc->String));
1124 			sc->ExpectNumber();
1125 			TempData.Append(sc->Number);
1126 		}
1127 		else if (sc->Check("delay"))
1128 		{
1129 			//	delay <tics>
1130 			TempData.Append(SSCMD_Delay);
1131 			sc->ExpectNumber();
1132 			TempData.Append(sc->Number);
1133 		}
1134 		else if (sc->Check("delayonce"))
1135 		{
1136 			//	delayonce <tics>
1137 			TempData.Append(SSCMD_DelayOnce);
1138 			sc->ExpectNumber();
1139 			TempData.Append(sc->Number);
1140 			TempData.Append(DelayOnceIndex++);
1141 		}
1142 		else if (sc->Check("delayrand"))
1143 		{
1144 			//	delayrand <tics_from> <tics_to>
1145 			TempData.Append(SSCMD_DelayRand);
1146 			sc->ExpectNumber();
1147 			TempData.Append(sc->Number);
1148 			sc->ExpectNumber();
1149 			TempData.Append(sc->Number);
1150 		}
1151 		else if (sc->Check("volume"))
1152 		{
1153 			//	volume <volume>
1154 			TempData.Append(SSCMD_Volume);
1155 			sc->ExpectFloat();
1156 			TempData.Append((vint32)(sc->Float * 100.0));
1157 		}
1158 		else if (sc->Check("volumerel"))
1159 		{
1160 			//	volumerel <volume_delta>
1161 			TempData.Append(SSCMD_VolumeRel);
1162 			sc->ExpectFloat();
1163 			TempData.Append((vint32)(sc->Float * 100.0));
1164 		}
1165 		else if (sc->Check("volumerand"))
1166 		{
1167 			//	volumerand <volume_from> <volume_to>
1168 			TempData.Append(SSCMD_VolumeRand);
1169 			sc->ExpectFloat();
1170 			TempData.Append((vint32)(sc->Float * 100.0));
1171 			sc->ExpectFloat();
1172 			TempData.Append((vint32)(sc->Float * 100.0));
1173 		}
1174 		else if (sc->Check("attenuation"))
1175 		{
1176 			//	attenuation none|normal|idle|static|surround
1177 			TempData.Append(SSCMD_Attenuation);
1178 			vint32 Atten = 0;
1179 			if (sc->Check("none"))
1180 				Atten = 0;
1181 			else if (sc->Check("normal"))
1182 				Atten = 1;
1183 			else if (sc->Check("idle"))
1184 				Atten = 2;
1185 			else if (sc->Check("static"))
1186 				Atten = 3;
1187 			else if (sc->Check("surround"))
1188 				Atten = -1;
1189 			else
1190 				sc->Error("Bad attenuation");
1191 			TempData.Append(Atten);
1192 		}
1193 		else if (sc->Check("randomsequence"))
1194 		{
1195 			//	randomsequence
1196 			TempData.Append(SSCMD_RandomSequence);
1197 		}
1198 		else if (sc->Check("restart"))
1199 		{
1200 			//	restart
1201 			TempData.Append(SSCMD_Branch);
1202 			TempData.Append(TempData.Num() - 1);
1203 		}
1204 		else if (sc->Check("stopsound"))
1205 		{
1206 			//	stopsound <sound>
1207 			sc->ExpectString();
1208 			SeqInfo[SeqId].StopSound = GetSoundID(*sc->String);
1209 			TempData.Append(SSCMD_StopSound);
1210 		}
1211 		else if (sc->Check("nostopcutoff"))
1212 		{
1213 			//	nostopcutoff
1214 			SeqInfo[SeqId].StopSound = -1;
1215 			TempData.Append(SSCMD_StopSound);
1216 		}
1217 		else if (sc->Check("slot"))
1218 		{
1219 			//	slot <name>...
1220 			sc->ExpectString();
1221 			SeqInfo[SeqId].Slot = *sc->String;
1222 		}
1223 		else if (sc->Check("end"))
1224 		{
1225 			//	end
1226 			TempData.Append(SSCMD_End);
1227 			SeqInfo[SeqId].Data = new vint32[TempData.Num()];
1228 			memcpy(SeqInfo[SeqId].Data, TempData.Ptr(), TempData.Num() *
1229 				sizeof(vint32));
1230 			inSequence = false;
1231 		}
1232 		else
1233 		{
1234 			sc->Error("Unknown commmand.");
1235 		}
1236 	}
1237 	delete sc;
1238 	sc = NULL;
1239 	unguard;
1240 }
1241 
1242 //==========================================================================
1243 //
1244 //	VSoundManager::AssignSeqTranslations
1245 //
1246 //==========================================================================
1247 
AssignSeqTranslations(VScriptParser * sc,int SeqId,seqtype_t SeqType)1248 void VSoundManager::AssignSeqTranslations(VScriptParser* sc, int SeqId,
1249 	seqtype_t SeqType)
1250 {
1251 	guard(VSoundManager::AssignSeqTranslations);
1252 	sc->Crossed = false;
1253 
1254 	while (sc->GetString() && !sc->Crossed)
1255 	{
1256 		char* Stopper;
1257 		int Num = strtol(*sc->String, &Stopper, 0);
1258 		if (*Stopper == 0)
1259 		{
1260 			SeqTrans[(Num & 63) + SeqType * 64] = SeqId;
1261 		}
1262 	}
1263 
1264 	sc->UnGet();
1265 	unguard;
1266 }
1267 
1268 //==========================================================================
1269 //
1270 //  VSoundManager::SetSeqTrans
1271 //
1272 //==========================================================================
1273 
SetSeqTrans(VName Name,int Num,int SeqType)1274 void VSoundManager::SetSeqTrans(VName Name, int Num, int SeqType)
1275 {
1276 	guard(VSoundManager::SetSeqTrans);
1277 	int Idx = FindSequence(Name);
1278 	if (Idx != -1)
1279 	{
1280 		SeqTrans[(Num & 63) + SeqType * 64] = Idx;
1281 	}
1282 	unguard;
1283 }
1284 
1285 //==========================================================================
1286 //
1287 //  VSoundManager::GetSeqTrans
1288 //
1289 //==========================================================================
1290 
GetSeqTrans(int Num,int SeqType)1291 VName VSoundManager::GetSeqTrans(int Num, int SeqType)
1292 {
1293 	guard(VSoundManager::GetSeqTrans);
1294 	if (Num < 0)
1295 	{
1296 		//	If not assigned, use 0 as default.
1297 		Num = 0;
1298 	}
1299 	if (SeqTrans[(Num & 63) + SeqType * 64] < 0)
1300 	{
1301 		return NAME_None;
1302 	}
1303 	return SeqInfo[SeqTrans[(Num & 63) + SeqType * 64]].Name;
1304 	unguard;
1305 }
1306 
1307 //==========================================================================
1308 //
1309 //  VSoundManager::GetSeqSlot
1310 //
1311 //==========================================================================
1312 
GetSeqSlot(VName Name)1313 VName VSoundManager::GetSeqSlot(VName Name)
1314 {
1315 	guard(VSoundManager::GetSeqSlot);
1316 	int Idx = FindSequence(Name);
1317 	if (Idx != -1)
1318 	{
1319 		return SeqInfo[Idx].Slot;
1320 	}
1321 	return NAME_None;
1322 	unguard;
1323 }
1324 
1325 //==========================================================================
1326 //
1327 //  VSoundManager::FindSequence
1328 //
1329 //==========================================================================
1330 
FindSequence(VName Name)1331 int VSoundManager::FindSequence(VName Name)
1332 {
1333 	guard(VSoundManager::FindSequence);
1334 	for (int i = 0; i < SeqInfo.Num(); i++)
1335 	{
1336 		if (SeqInfo[i].Name == Name)
1337 		{
1338 			return i;
1339 		}
1340 	}
1341 	return -1;
1342 	unguard;
1343 }
1344 
1345 //==========================================================================
1346 //
1347 //	VSoundManager::GetSoundLumpNames
1348 //
1349 //==========================================================================
1350 
GetSoundLumpNames(TArray<FReplacedString> & List)1351 void VSoundManager::GetSoundLumpNames(TArray<FReplacedString>& List)
1352 {
1353 	guard(VSoundManager::GetSoundLumpNames);
1354 	for (int i = 1; i < S_sfx.Num(); i++)
1355 	{
1356 		if (S_sfx[i].LumpNum < 0)
1357 		{
1358 			continue;
1359 		}
1360 		const char* LName = *W_LumpName(S_sfx[i].LumpNum);
1361 		if (LName[0] == 'd' && LName[1] == 's')
1362 		{
1363 			FReplacedString& R = List.Alloc();
1364 			R.Index = i;
1365 			R.Replaced = false;
1366 			R.Old = LName + 2;
1367 		}
1368 	}
1369 	unguard;
1370 }
1371 
1372 //==========================================================================
1373 //
1374 //	VSoundManager::ReplaceSoundLumpNames
1375 //
1376 //==========================================================================
1377 
ReplaceSoundLumpNames(TArray<FReplacedString> & List)1378 void VSoundManager::ReplaceSoundLumpNames(TArray<FReplacedString>& List)
1379 {
1380 	guard(VSoundManager::ReplaceSoundLumpNames);
1381 	for (int i = 0; i < List.Num(); i++)
1382 	{
1383 		if (!List[i].Replaced)
1384 		{
1385 			continue;
1386 		}
1387 		S_sfx[List[i].Index].LumpNum = W_CheckNumForName(VName(
1388 			*(VStr("ds") + List[i].New), VName::AddLower));
1389 	}
1390 	unguard;
1391 }
1392 
1393 #ifdef CLIENT
1394 
1395 //==========================================================================
1396 //
1397 //	VRawSampleLoader::Load
1398 //
1399 //==========================================================================
1400 
Load(sfxinfo_t & Sfx,VStream & Strm)1401 void VRawSampleLoader::Load(sfxinfo_t& Sfx, VStream& Strm)
1402 {
1403 	guard(VRawSampleLoader::Load);
1404 	//	Read header and see if it's a valid raw sample.
1405 	vuint16		Unknown;
1406 	vuint16		SampleRate;
1407 	vuint32		DataSize;
1408 
1409 	Strm.Seek(0);
1410 	Strm << Unknown
1411 		<< SampleRate
1412 		<< DataSize;
1413 	if (Unknown != 3 || (vint32)DataSize != Strm.TotalSize() - 8)
1414 	{
1415 		return;
1416 	}
1417 
1418 	Sfx.SampleBits = 8;
1419 	Sfx.SampleRate = SampleRate;
1420 	Sfx.DataSize = DataSize;
1421 	Sfx.Data = Z_Malloc(Sfx.DataSize);
1422 	Strm.Serialise(Sfx.Data, Sfx.DataSize);
1423 	unguard;
1424 }
1425 
1426 #endif
1427