1 /*
2 SOUND.C
3 
4 	Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 	and the "Aleph One" developers.
6 
7 	This program is free software; you can redistribute it and/or modify
8 	it under the terms of the GNU General Public License as published by
9 	the Free Software Foundation; either version 3 of the License, or
10 	(at your option) any later version.
11 
12 	This program is distributed in the hope that it will be useful,
13 	but WITHOUT ANY WARRANTY; without even the implied warranty of
14 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 	GNU General Public License for more details.
16 
17 	This license is contained in the file "COPYING",
18 	which is included with this source code; it is available online at
19 	http://www.gnu.org/licenses/gpl.html
20 
21 */
22 
23 #include <iostream>
24 
25 #include "SoundManager.h"
26 #include "ReplacementSounds.h"
27 #include "sound_definitions.h"
28 #include "Mixer.h"
29 #include "images.h"
30 #include "InfoTree.h"
31 
32 #define SLOT_IS_USED(o) ((o)->flags&(uint16)0x8000)
33 #define SLOT_IS_FREE(o) (!SLOT_IS_USED(o))
34 #define MARK_SLOT_AS_FREE(o) ((o)->flags&=(uint16)~0x8000)
35 #define MARK_SLOT_AS_USED(o) ((o)->flags|=(uint16)0x8000)
36 
37 class SoundMemoryManager {
38 public:
SoundMemoryManager(std::size_t max_size)39 	SoundMemoryManager(std::size_t max_size) : m_size(0), m_max_size(max_size) { }
40 
SetMaxSize(std::size_t max_size)41 	void SetMaxSize(std::size_t max_size) { m_max_size = max_size; }
42 
43 	void Add(boost::shared_ptr<SoundData> data, short index, short slot);
Get(short index,short slot)44 	boost::shared_ptr<SoundData> Get(short index, short slot) { return m_entries[index].data[slot]; }
45 	void Update(short index);
46 	boost::function<void (short)> SoundReleased;
47 
IsLoaded(short index)48 	bool IsLoaded(short index) {
49 		return m_entries.count(index);
50 	}
51 
Clear()52 	void Clear() { m_entries.clear(); m_size = 0; }
53 
54 private:
55 	struct Entry {
EntrySoundMemoryManager::Entry56 		Entry() : data(5), last_played(0) { }
57 		std::vector<boost::shared_ptr<SoundData> > data;
58 		uint32 last_played;
59 
sizeSoundMemoryManager::Entry60 		std::size_t size() {
61 			std::size_t n = 0;
62 			for (std::vector<boost::shared_ptr<SoundData> >::iterator it = data.begin(); it != data.end(); ++it)
63 			{
64 				if (it->get())
65 				{
66 					n += (*it)->size();
67 				}
68 			}
69 
70 			return n;
71 		}
72 	};
73 
74 	void ReleaseOldestSound();
75 	void Release(short index);
76 	std::map<short, Entry> m_entries;
77 	std::size_t m_size;
78 	std::size_t m_max_size;
79 };
80 
Add(boost::shared_ptr<SoundData> data,short index,short slot)81 void SoundMemoryManager::Add(boost::shared_ptr<SoundData> data, short index, short slot)
82 {
83 	m_entries[index].data[slot] = data;
84 	m_entries[index].last_played = machine_tick_count();
85 
86 	m_size += data->size();
87 
88 	while (m_size > m_max_size)
89 	{
90 		std::cerr << "Size is too big (" << m_size << ">" << m_max_size << ")" << std::endl;
91 		ReleaseOldestSound();
92 	}
93 }
94 
Release(short index)95 void SoundMemoryManager::Release(short index)
96 {
97 	if (SoundReleased)
98 	{
99 		SoundReleased(index);
100 	}
101 	m_size -= m_entries[index].size();
102 	m_entries.erase(index);
103 }
104 
ReleaseOldestSound()105 void SoundMemoryManager::ReleaseOldestSound()
106 {
107 	if (!m_entries.size())
108 	{
109 		return;
110 	}
111 
112 	std::map<short, Entry>::iterator oldest_sound = m_entries.begin();
113 	std::map<short, Entry>::iterator it = oldest_sound;
114 	++it;
115 	for (; it != m_entries.end(); ++it)
116 	{
117 		if (it->second.last_played < oldest_sound->second.last_played)
118 		{
119 			oldest_sound = it;
120 		}
121 	}
122 
123 	std::cerr << "Dropping sound " << oldest_sound->first << std::endl;
124 	Release(oldest_sound->first);
125 }
126 
Update(short index)127 void SoundMemoryManager::Update(short index)
128 {
129 	m_entries[index].last_played = machine_tick_count();
130 }
131 
132 
Shutdown()133 static void Shutdown()
134 {
135 	SoundManager::instance()->Shutdown();
136 }
137 
138 // From FileSpecifier_SDL.cpp
139 extern void get_default_sounds_spec(FileSpecifier &file);
140 
Initialize(const Parameters & new_parameters)141 void SoundManager::Initialize(const Parameters& new_parameters)
142 {
143 	total_channel_count = 0;
144 
145 	FileSpecifier InitialSoundFile;
146 	get_default_sounds_spec(InitialSoundFile);
147 	if (OpenSoundFile(InitialSoundFile))
148 	{
149 		atexit(::Shutdown);
150 
151 		parameters.flags = 0;
152 		initialized = true;
153 		active = false;
154 		SetParameters(new_parameters);
155 		SetStatus(true);
156 	}
157 }
158 
SetParameters(const Parameters & parameters)159 void SoundManager::SetParameters(const Parameters& parameters)
160 {
161 	if (initialized)
162 	{
163 		bool initial_state = active;
164 
165 		// If it was initially on, turn off the sound manager
166 		if (initial_state)
167 			SetStatus(false);
168 
169 		// We need to get rid of the sounds we have in memory
170 		UnloadAllSounds();
171 
172 		// Stuff in our new parameters
173 		this->parameters = parameters;
174 		this->parameters.Verify();
175 
176 		// If it was initially on, turn the sound manager back on
177 		if (initial_state && parameters.volume)
178 			SetStatus(true);
179 	}
180 
181 }
182 
Shutdown()183 void SoundManager::Shutdown()
184 {
185 	instance()->SetStatus(false);
186 	instance()->CloseSoundFile();
187 }
188 
OpenSoundFile(FileSpecifier & File)189 bool SoundManager::OpenSoundFile(FileSpecifier& File)
190 {
191 	StopAllSounds();
192 	sound_file.reset(new M2SoundFile);
193 	if (!sound_file->Open(File))
194 	{
195 		// try M1 sounds
196 		sound_file.reset(new M1SoundFile);
197 		if (!sound_file->Open(File))
198 		{
199 			return false;
200 		}
201 		set_sounds_images_file(File);
202 	}
203 
204 	sound_source = (parameters.flags & _16bit_sound_flag) ? _16bit_22k_source : _8bit_22k_source;
205 	if (sound_file->SourceCount() == 1)
206 		sound_source = _8bit_22k_source;
207 
208 	return true;
209 }
210 
CloseSoundFile()211 void SoundManager::CloseSoundFile()
212 {
213 	StopAllSounds();
214 	sound_file->Close();
215 }
216 
AdjustVolumeUp(short sound_index)217 bool SoundManager::AdjustVolumeUp(short sound_index)
218 {
219 	if (active && parameters.volume < NUMBER_OF_SOUND_VOLUME_LEVELS)
220 	{
221 		parameters.volume++;
222 		Mixer::instance()->SetVolume(parameters.volume * SOUND_VOLUME_DELTA);
223 		PlaySound(sound_index, 0, NONE);
224 		return true;
225 	}
226 	return false;
227 }
228 
AdjustVolumeDown(short sound_index)229 bool SoundManager::AdjustVolumeDown(short sound_index)
230 {
231 	if (active && parameters.volume > 0)
232 	{
233 		parameters.volume--;
234 		Mixer::instance()->SetVolume(parameters.volume * SOUND_VOLUME_DELTA);
235 		PlaySound(sound_index, 0, NONE);
236 		return true;
237 	}
238 	return false;
239 }
240 
TestVolume(short volume,short sound_index)241 void SoundManager::TestVolume(short volume, short sound_index)
242 {
243 	if (active)
244 	{
245 		if ((volume = PIN(volume, 0, NUMBER_OF_SOUND_VOLUME_LEVELS)) != 0)
246 		{
247 			PlaySound(sound_index, 0, NONE);
248 			Mixer::instance()->SetVolume(volume * SOUND_VOLUME_DELTA);
249 			while (SoundIsPlaying(sound_index))
250 				SDL_Delay(10);
251 			Mixer::instance()->SetVolume(parameters.volume * SOUND_VOLUME_DELTA);
252 		}
253 	}
254 }
255 
LoadSound(short sound_index)256 bool SoundManager::LoadSound(short sound_index)
257 {
258 	if (active)
259 	{
260 		SoundDefinition *definition = GetSoundDefinition(sound_index);
261 		if (!definition) return false;
262 
263 		// Load all the external-file sounds for each index;
264 		// fill the slots appropriately.
265 		int NumSlots= (parameters.flags & _more_sounds_flag) ? definition->permutations : 1;
266 
267 		if (definition->sound_code == NONE)
268 		{
269 			return false;
270 		}
271 
272 		if (!(parameters.flags & _ambient_sound_flag) && (definition->flags & _sound_is_ambient))
273 		{
274 			return false;
275 		}
276 
277 		if (sounds->IsLoaded(sound_index))
278 		{
279 			sounds->Update(sound_index);
280 		}
281 		else
282 		{
283 			for (int i = 0; i < NumSlots; ++i)
284 			{
285 				boost::shared_ptr<SoundData> p = sound_file->GetSoundData(definition, i);
286 
287 				SoundOptions *SndOpts = SoundReplacements::instance()->GetSoundOptions(sound_index, i);
288 				if (SndOpts)
289 				{
290 					boost::shared_ptr<SoundData> x = SndOpts->Sound.LoadExternal(SndOpts->File);
291 					if (x.get())
292 					{
293 						p = x;
294 					}
295 				}
296 
297 				if (p.get())
298 				{
299 					sounds->Add(p, sound_index, i);
300 				}
301 			}
302 		}
303 
304 		return sounds->IsLoaded(sound_index);
305 	}
306 
307 	return false;
308 }
309 
LoadSounds(short * sounds,short count)310 void SoundManager::LoadSounds(short *sounds, short count)
311 {
312 	for (short i = 0; i < count; i++)
313 	{
314 		LoadSound(sounds[i]);
315 	}
316 }
317 
OrphanSound(short identifier)318 void SoundManager::OrphanSound(short identifier)
319 {
320 	if (active && total_channel_count > 0)
321 	{
322 		for (short i = 0; i < parameters.channel_count; i++)
323 		{
324 			Channel *channel = &channels[i];
325 			if (channel->identifier == identifier || identifier == NONE)
326 			{
327 				channel->dynamic_source = 0;
328 				channel->identifier = NONE;
329 			}
330 		}
331 	}
332 }
333 
UnloadAllSounds()334 void SoundManager::UnloadAllSounds()
335 {
336 	if (active)
337 	{
338 		StopSound(NONE, NONE);
339 		sounds->Clear();
340 	}
341 }
342 
PlaySound(short sound_index,world_location3d * source,short identifier,_fixed pitch)343 void SoundManager::PlaySound(short sound_index,
344 			     world_location3d *source,
345 			     short identifier, // NONE is no identifer and the sound is immediately orphaned
346 			     _fixed pitch) // on top of all existing pitch modifiers
347 {
348 	/* don�t do anything if we�re not initialized or active, or our sound_code is NONE,
349 		or our volume is zero, our we have no sound channels */
350 	if (sound_index!=NONE && active && parameters.volume > 0 && total_channel_count > 0)
351 	{
352 		Channel::Variables variables;
353 
354 		CalculateInitialSoundVariables(sound_index, source, variables, pitch);
355 
356 		/* make sure the sound data is in memory */
357 		if (LoadSound(sound_index))
358 		{
359 			Channel *channel = BestChannel(sound_index, variables);;
360 			/* get the channel, and free it for our new sound */
361 			if (channel)
362 			{
363 				/* set the volume and pitch in this channel */
364 				InstantiateSoundVariables(variables, *channel, true);
365 
366 				/* initialize the channel */
367 				channel->flags= 0;
368 				channel->callback_count= 0; // #MD
369 				channel->start_tick= machine_tick_count();
370 				channel->sound_index= sound_index;
371 				channel->identifier= identifier;
372 				channel->dynamic_source= (identifier==NONE) ? (world_location3d *) NULL : source;
373 				MARK_SLOT_AS_USED(channel);
374 
375 				/* start the sound playing */
376 				BufferSound(*channel, sound_index, pitch);
377 
378 				/* if we have a valid source, copy it, otherwise remember that we don�t */
379 				if (source)
380 				{
381 					channel->source= *source;
382 				}
383 				else
384 				{
385 					channel->flags|= _sound_is_local;
386 				}
387 			}
388 		}
389 	}
390 }
391 
DirectPlaySound(short sound_index,angle direction,short volume,_fixed pitch)392 void SoundManager::DirectPlaySound(short sound_index, angle direction, short volume, _fixed pitch)
393 {
394 	/* don�t do anything if we�re not initialized or active, or our sound_code is NONE,
395 	   or our volume is zero, our we have no sound channels */
396 
397 	if (sound_index != NONE && active && parameters.volume > 0 && total_channel_count > 0)
398 	{
399 		if (LoadSound(sound_index))
400 		{
401 			Channel::Variables variables;
402 			Channel *channel = BestChannel(sound_index, variables);
403 			if (channel)
404 			{
405 				world_location3d *listener = _sound_listener_proc();
406 
407 				variables.priority = 0;
408 				variables.volume = volume;
409 
410 				if (direction == NONE || !listener)
411 				{
412 					variables.left_volume = variables.right_volume = volume;
413 				}
414 				else
415 				{
416 					AngleAndVolumeToStereoVolume(direction - listener->yaw, volume, &variables.right_volume, &variables.left_volume);
417 				}
418 
419 				InstantiateSoundVariables(variables, *channel, true);
420 				/* initialize the channel */
421 				channel->flags = _sound_is_local; // but possibly being played in stereo
422 				channel->callback_count = 0;
423 				channel->start_tick = machine_tick_count();
424 				channel->sound_index = sound_index;
425 				channel->dynamic_source = 0;
426 				MARK_SLOT_AS_USED(channel);
427 
428 				/* start the sound playing */
429 				BufferSound(*channel, sound_index, pitch);
430 			}
431 		}
432 	}
433 }
434 
SoundIsPlaying(short sound_index)435 bool SoundManager::SoundIsPlaying(short sound_index)
436 {
437 	bool sound_playing = false;
438 
439 	if (active && total_channel_count > 0)
440 	{
441 		for (short i = 0; i < total_channel_count; i++)
442 		{
443 			if (SLOT_IS_USED(&channels[i]) && channels[i].sound_index == sound_index)
444 			{
445 				sound_playing = true;
446 			}
447 		}
448 
449 		UnlockLockedSounds();
450 	}
451 
452 	return sound_playing;
453 }
454 
StopSound(short identifier,short sound_index)455 void SoundManager::StopSound(short identifier, short sound_index)
456 {
457 	if (active && total_channel_count > 0)
458 	{
459 		// if we're stopping everything...
460 		if (identifier == NONE && sound_index == NONE)
461 		{
462 			// can't fade to silence here
463 
464 			// stop the ambient sound channels, too
465 			if (parameters.flags & _ambient_sound_flag)
466 			{
467 				for (short i = 0; i < MAXIMUM_AMBIENT_SOUND_CHANNELS; i++)
468 				{
469 					FreeChannel(channels[total_channel_count - i - 1]);
470 				}
471 			}
472 		}
473 
474 		for (short i = 0; i < total_channel_count; i++)
475 		{
476 			if (SLOT_IS_USED(&channels[i]) && (channels[i].identifier == identifier || identifier == NONE) && (channels[i].sound_index == sound_index || sound_index == NONE))
477 			{
478 				FreeChannel(channels[i]);
479 			}
480 		}
481 	}
482 
483 	return;
484 }
485 
Idle()486 void SoundManager::Idle()
487 {
488 	if (active && total_channel_count > 0)
489 	{
490 		UnlockLockedSounds();
491 		TrackStereoSounds();
492 		CauseAmbientSoundSourceUpdate();
493 	}
494 }
495 
CauseAmbientSoundSourceUpdate()496 void SoundManager::CauseAmbientSoundSourceUpdate()
497 {
498 	if (active && parameters.volume > 0 && total_channel_count > 0)
499 	{
500 		if (parameters.flags & _ambient_sound_flag)
501 		{
502 			UpdateAmbientSoundSources();
503 		}
504 	}
505 }
506 
507 struct ambient_sound_data
508 {
509 	uint16 flags;
510 	short sound_index;
511 
512 	SoundManager::Channel::Variables variables;
513 
514 	struct channel_data *channel;
515 };
516 
get_sound_behavior_definition(const short sound_behavior_index)517 static sound_behavior_definition *get_sound_behavior_definition(
518 	const short sound_behavior_index)
519 {
520 	return GetMemberWithBounds(sound_behavior_definitions,sound_behavior_index,NUMBER_OF_SOUND_BEHAVIOR_DEFINITIONS);
521 }
522 
distance_to_volume(SoundDefinition * definition,world_distance distance,uint16 flags)523 static short distance_to_volume(
524 	SoundDefinition *definition,
525 	world_distance distance,
526 	uint16 flags)
527 {
528 	struct sound_behavior_definition *behavior= get_sound_behavior_definition(definition->behavior_index);
529 	// LP change: idiot-proofing
530 	if (!behavior) return 0; // Silence
531 
532 	struct depth_curve_definition *depth_curve;
533 	short volume;
534 
535 	if (((flags&_sound_was_obstructed) && !(definition->flags&_sound_cannot_be_obstructed)) ||
536 		((flags&_sound_was_media_obstructed) && !(definition->flags&_sound_cannot_be_media_obstructed)))
537 	{
538 		depth_curve= &behavior->obstructed_curve;
539 	}
540 	else
541 	{
542 		depth_curve= &behavior->unobstructed_curve;
543 	}
544 
545 	if (distance<=depth_curve->maximum_volume_distance)
546 	{
547 		volume= depth_curve->maximum_volume;
548 	}
549 	else
550 	{
551 		if (distance>depth_curve->minimum_volume_distance)
552 		{
553 			volume= depth_curve->minimum_volume;
554 		}
555 		else
556 		{
557 			volume= depth_curve->minimum_volume - ((depth_curve->minimum_volume-depth_curve->maximum_volume)*(depth_curve->minimum_volume_distance-distance)) /
558 				(depth_curve->minimum_volume_distance-depth_curve->maximum_volume_distance);
559 		}
560 	}
561 
562 	if ((flags&_sound_was_media_muffled) && !(definition->flags&_sound_cannot_be_media_obstructed))
563 	{
564 		volume>>= 1;
565 	}
566 
567 	return volume;
568 }
569 
get_ambient_sound_definition(const short ambient_sound_index)570 static ambient_sound_definition *get_ambient_sound_definition(
571 	const short ambient_sound_index)
572 {
573 	return GetMemberWithBounds(ambient_sound_definitions,ambient_sound_index,NUMBER_OF_AMBIENT_SOUND_DEFINITIONS);
574 }
575 
AddOneAmbientSoundSource(ambient_sound_data * ambient_sounds,world_location3d * source,world_location3d * listener,short ambient_sound_index,short absolute_volume)576 void SoundManager::AddOneAmbientSoundSource(ambient_sound_data *ambient_sounds, world_location3d *source, world_location3d *listener, short ambient_sound_index, short absolute_volume)
577 {
578 	if (ambient_sound_index!=NONE)
579 	{
580 		// LP change; make NONE in case this sound definition is invalid
581 		struct ambient_sound_definition *SoundDef = get_ambient_sound_definition(ambient_sound_index);
582 		short sound_index = (SoundDef) ? SoundDef->sound_index : NONE;
583 
584 		if (sound_index!=NONE)
585 		{
586 			SoundDefinition *definition = SoundManager::instance()->GetSoundDefinition(sound_index);
587 
588 			// LP change: idiot-proofing
589 			if (definition)
590 			{
591 				if (definition->sound_code!=NONE)
592 				{
593 					struct sound_behavior_definition *behavior= get_sound_behavior_definition(definition->behavior_index);
594 					// LP change: idiot-proofing
595 					if (!behavior) return; // Silence
596 
597 					struct ambient_sound_data *ambient;
598 					short distance = 0;
599 					short i;
600 
601 					if (source)
602 					{
603 						distance= distance3d(&listener->point, &source->point);
604 					}
605 
606 					for (i= 0, ambient= ambient_sounds;
607 					     i<MAXIMUM_PROCESSED_AMBIENT_SOUNDS;
608 					     ++i, ++ambient)
609 					{
610 						if (SLOT_IS_USED(ambient))
611 						{
612 							if (ambient->sound_index==sound_index) break;
613 						}
614 						else
615 						{
616 							MARK_SLOT_AS_USED(ambient);
617 
618 							ambient->sound_index= sound_index;
619 
620 							ambient->variables.priority= definition->behavior_index;
621 							ambient->variables.volume= ambient->variables.left_volume= ambient->variables.right_volume= 0;
622 
623 							break;
624 						}
625 					}
626 
627 					if (i!=MAXIMUM_PROCESSED_AMBIENT_SOUNDS)
628 					{
629 						if (!source || distance<behavior->unobstructed_curve.minimum_volume_distance)
630 						{
631 							short volume, left_volume, right_volume;
632 
633 							if (source)
634 							{
635 								// LP change: made this long-distance friendly
636 								int32 dx= int32(listener->point.x) - int32(source->point.x);
637 								int32 dy= int32(listener->point.y) - int32(source->point.y);
638 
639 								volume= distance_to_volume(definition, distance, _sound_obstructed_proc(source));
640 								volume= (absolute_volume*volume)>>MAXIMUM_SOUND_VOLUME_BITS;
641 
642 								if (dx || dy)
643 								{
644 									AngleAndVolumeToStereoVolume(arctangent(dx, dy) - listener->yaw, volume, &right_volume, &left_volume);
645 								}
646 								else
647 								{
648 									left_volume= right_volume= volume;
649 								}
650 							}
651 							else
652 							{
653 								volume= left_volume= right_volume= absolute_volume;
654 							}
655 
656 							{
657 								short maximum_volume= MAX(MAXIMUM_AMBIENT_SOUND_VOLUME, volume);
658 								short maximum_left_volume= MAX(MAXIMUM_AMBIENT_SOUND_VOLUME, left_volume);
659 								short maximum_right_volume= MAX(MAXIMUM_AMBIENT_SOUND_VOLUME, right_volume);
660 
661 								ambient->variables.volume= CEILING(ambient->variables.volume+volume, maximum_volume);
662 								ambient->variables.left_volume= CEILING(ambient->variables.left_volume+left_volume, maximum_left_volume);
663 								ambient->variables.right_volume= CEILING(ambient->variables.right_volume+right_volume, maximum_right_volume);
664 							}
665 						}
666 					}
667 					else
668 					{
669 //					dprintf("warning: ambient sound buffer full;g;");
670 					}
671 				}
672 			}
673 		}
674 	}
675 }
676 
get_random_sound_definition(const short random_sound_index)677 struct random_sound_definition *get_random_sound_definition(
678 	const short random_sound_index)
679 {
680 	return GetMemberWithBounds(random_sound_definitions,random_sound_index,NUMBER_OF_RANDOM_SOUND_DEFINITIONS);
681 }
682 
RandomSoundIndexToSoundIndex(short random_sound_index)683 short SoundManager::RandomSoundIndexToSoundIndex(short random_sound_index)
684 {
685 	random_sound_definition *definition = get_random_sound_definition(random_sound_index);
686 
687 	if (definition)
688 		return definition->sound_index;
689 	else
690 		return NONE;
691 }
692 
Parameters()693 SoundManager::Parameters::Parameters() :
694 	channel_count(MAXIMUM_SOUND_CHANNELS),
695 	volume(DEFAULT_SOUND_LEVEL),
696 	flags(_more_sounds_flag | _stereo_flag | _dynamic_tracking_flag | _ambient_sound_flag | _16bit_sound_flag),
697 	rate(DEFAULT_RATE),
698 	samples(DEFAULT_SAMPLES),
699 	music(DEFAULT_MUSIC_LEVEL),
700 	volume_while_speaking(DEFAULT_VOLUME_WHILE_SPEAKING),
701 	mute_while_transmitting(true)
702 {
703 }
704 
Verify()705 bool SoundManager::Parameters::Verify()
706 {
707 	channel_count = PIN(channel_count, 0, MAXIMUM_SOUND_CHANNELS);
708 	volume = PIN(volume, 0, NUMBER_OF_SOUND_VOLUME_LEVELS);
709 
710 	return true;
711 }
712 
SoundManager()713 SoundManager::SoundManager() : active(false), initialized(false), sounds(new SoundMemoryManager(10 << 20))
714 {
715 	channels.resize(MAXIMUM_SOUND_CHANNELS + MAXIMUM_AMBIENT_SOUND_CHANNELS);
716 }
717 
SetStatus(bool active)718 void SoundManager::SetStatus(bool active)
719 {
720 	if (initialized)
721 	{
722 		if (active != this->active)
723 		{
724 			if (active)
725 			{
726 				uint32 total_buffer_size;
727 
728 				total_channel_count = parameters.channel_count;
729 				if (parameters.flags & _ambient_sound_flag)
730 					total_channel_count += MAXIMUM_AMBIENT_SOUND_CHANNELS;
731 				int32 samples = parameters.samples;
732 				if (parameters.flags & _more_sounds_flag)
733 					total_buffer_size = MORE_SOUND_BUFFER_SIZE;
734 				else
735 					total_buffer_size = MINIMUM_SOUND_BUFFER_SIZE;
736 				if (parameters.flags & _ambient_sound_flag)
737 					total_buffer_size += AMBIENT_SOUND_BUFFER_SIZE;
738 				if (parameters.flags & _16bit_sound_flag)
739 				{
740 					total_buffer_size *= 2;
741 					samples *= 2;
742 				}
743 
744 				total_buffer_size *= 2;
745 				if (parameters.channel_count > 4)
746 				{
747 					total_buffer_size = total_buffer_size * parameters.channel_count / 4;
748 				}
749 
750 				sounds->SetMaxSize(total_buffer_size);
751 
752 				if (parameters.flags & _stereo_flag)
753 					samples *= 2;
754 				sound_source = (parameters.flags & _16bit_sound_flag) ? _16bit_22k_source : _8bit_22k_source;
755 				for (int i = 0; i < channels.size(); i++)
756 				{
757 					channels[i].mixer_channel = i;
758 				}
759 
760 				samples = samples * parameters.rate / Parameters::DEFAULT_RATE;
761 
762 				Mixer::instance()->Start(parameters.rate, parameters.flags & _16bit_sound_flag, parameters.flags & _stereo_flag, MAXIMUM_SOUND_CHANNELS + MAXIMUM_AMBIENT_SOUND_CHANNELS, parameters.volume * SOUND_VOLUME_DELTA, samples);
763 
764 				if (Mixer::instance()->SoundChannelCount() == 0)
765 				{
766 					total_channel_count = 0;
767 					active = this->active = initialized = false;
768 				}
769 				else
770 				{
771 					total_channel_count = Mixer::instance()->SoundChannelCount();
772 				}
773 			}
774 			else
775 			{
776 				StopAllSounds();
777 				Mixer::instance()->Stop();
778 				total_channel_count = 0;
779 			}
780 			this->active = active;
781 		}
782 	}
783 }
784 
GetSoundDefinition(short sound_index)785 SoundDefinition* SoundManager::GetSoundDefinition(short sound_index)
786 {
787 	SoundDefinition* sound_definition = sound_file->GetSoundDefinition(sound_source, sound_index);
788 	if (sound_source == _16bit_22k_source && sound_definition && sound_definition->permutations == 0)
789 	{
790 		sound_definition = sound_file->GetSoundDefinition(_8bit_22k_source, sound_index);
791 	}
792 
793 	return sound_definition;
794 }
795 
BufferSound(Channel & channel,short sound_index,_fixed pitch,bool ext_play_immed)796 void SoundManager::BufferSound(Channel &channel, short sound_index, _fixed pitch, bool ext_play_immed)
797 {
798 	SoundDefinition *definition = GetSoundDefinition(sound_index);
799 	if (!definition || !definition->permutations)
800 		return;
801 
802 	int permutation = GetRandomSoundPermutation(sound_index);
803 
804 	assert(permutation >= 0 && permutation < definition->permutations);
805 
806 	SoundInfo header;
807 
808 	SoundOptions *SndOpts = SoundReplacements::instance()->GetSoundOptions(sound_index, permutation);
809 	if (SndOpts && SndOpts->Sound.length)
810 	{
811 		header = SndOpts->Sound;
812 	}
813 	else
814 	{
815 		header = sound_file->GetSoundHeader(definition, permutation);
816 	}
817 
818 	boost::shared_ptr<SoundData> sound = sounds->Get(sound_index, permutation);
819 	if (sound.get())
820 	{
821 		Mixer::instance()->BufferSound(channel.mixer_channel, header, sound, CalculatePitchModifier(sound_index, pitch));
822 	}
823 }
824 
BestChannel(short sound_index,Channel::Variables & variables)825 SoundManager::Channel *SoundManager::BestChannel(short sound_index, Channel::Variables &variables)
826 {
827 	Channel *best_channel;
828 
829 	SoundDefinition *definition = GetSoundDefinition(sound_index);
830 	if (!definition) return 0;
831 
832 	best_channel = 0;
833 	if (!definition->chance || (local_random() > definition->chance))
834 	{
835 		for (short i = 0; i < parameters.channel_count; i++)
836 		{
837 			Channel *channel = &channels[i];
838 			if (SLOT_IS_USED(channel) && Mixer::instance()->ChannelBusy(channel->mixer_channel))
839 			{
840 				/* if this channel is at a lower volume than the sound we are trying to play and is at the same
841 				   priority, or the channel is at a lower priority, then we can abort it */
842 				if ((channel->variables.volume <= variables.volume + ABORT_AMPLITUDE_THRESHHOLD && channel->variables.priority == variables.priority) ||
843 				    channel->variables.priority < variables.priority)
844 				{
845 					// if this channel is already playing our sound,
846 					// this is our channel (for better or for worse)
847 					if (channel->sound_index == sound_index)
848 					{
849 						if (definition->flags & _sound_cannot_be_restarted)
850 						{
851 							best_channel = 0;
852 							break;
853 						}
854 
855 						if (!(definition->flags & _sound_does_not_self_abort))
856 						{
857 							if ((parameters.flags & _zero_restart_delay) || channel->variables.volume == 0 || channel->start_tick + MINIMUM_RESTART_TICKS < machine_tick_count())
858 								best_channel = channel;
859 							else
860 								best_channel = 0;
861 							break;
862 						}
863 					}
864 
865 					/* if we haven�t found an alternative channel or this channel is at a lower
866 					   volume than our previously best channel (which isn�t an unused channel),
867 					   then we�ve found a new best channel */
868 					if (!best_channel ||
869 					    (SLOT_IS_USED(best_channel) && best_channel->variables.volume > channel->variables.volume) ||
870 					    (SLOT_IS_USED(best_channel) && best_channel->variables.priority < channel->variables.priority))
871 					{
872 						best_channel = channel;
873 					}
874 				}
875 				else
876 				{
877 					if (channel->sound_index == sound_index && !(definition->flags & _sound_does_not_self_abort))
878 					{
879 						/* if we�re already playing this sound at a higher volume, don�t abort it */
880 						best_channel = 0;
881 						break;
882 					}
883 				}
884 
885 			}
886 			else
887 			{
888 				/* unused channel (we won�t get much better than this!) */
889 				if (SLOT_IS_USED(channel))
890 					FreeChannel(*channel);
891 				best_channel = channel;
892 			}
893 		}
894 	}
895 
896 	if (best_channel)
897 	{
898 
899 		/* stop whatever sound is playing and unlock the old handle if necessary */
900 		FreeChannel(*best_channel);
901 	}
902 
903 	return best_channel;
904 }
905 
FreeChannel(Channel & channel)906 void SoundManager::FreeChannel(Channel &channel)
907 {
908 	if (SLOT_IS_USED(&channel))
909 	{
910 		short sound_index = channel.sound_index;
911 		Mixer::instance()->QuietChannel(channel.mixer_channel);
912 
913 		assert(sound_index != NONE);
914 		channel.sound_index = NONE;
915 		MARK_SLOT_AS_FREE(&channel);
916 	}
917 }
918 
UnlockLockedSounds()919 void SoundManager::UnlockLockedSounds()
920 {
921 	if (active && total_channel_count > 0)
922 	{
923 		for (short i = 0; i < parameters.channel_count; i++)
924 		{
925 			Channel *channel = &channels[i];
926 			if (SLOT_IS_USED(channel) && !Mixer::instance()->ChannelBusy(channel->mixer_channel))
927 			{
928 				FreeChannel(*channel);
929 			}
930 		}
931 	}
932 }
933 
CalculateSoundVariables(short sound_index,world_location3d * source,Channel::Variables & variables)934 void SoundManager::CalculateSoundVariables(short sound_index, world_location3d *source, Channel::Variables& variables)
935 {
936 	SoundDefinition *definition = GetSoundDefinition(sound_index);
937 	if (!definition) return;
938 
939 	world_location3d *listener = _sound_listener_proc();
940 
941 	if (source && listener)
942 	{
943 		world_distance distance = distance3d(&source->point, &listener->point);
944 
945 		// LP change: made this long-distance friendly
946 		int32 dx = int32(listener->point.x) - int32(source->point.x);
947 		int32 dy = int32(listener->point.y) - int32(source->point.y);
948 
949 		// for now, a sound's priority is its behavior index
950 		variables.priority = definition->behavior_index;
951 
952 		// calculate the relative volume due to the given depth curve
953 		variables.volume = distance_to_volume(definition, distance, _sound_obstructed_proc(source));
954 
955 		if (dx || dy)
956 		{
957 
958 			// set volume, left_volume, right_volume
959 			AngleAndVolumeToStereoVolume(arctangent(dx, dy) - listener->yaw, variables.volume, &variables.right_volume, &variables.left_volume);
960 		}
961 		else
962 		{
963 			variables.left_volume = variables.right_volume = variables.volume;
964 		}
965 	}
966 
967 }
968 
CalculateInitialSoundVariables(short sound_index,world_location3d * source,Channel::Variables & variables,_fixed)969 void SoundManager::CalculateInitialSoundVariables(short sound_index, world_location3d *source, Channel::Variables& variables, _fixed)
970 {
971 	SoundDefinition *definition = GetSoundDefinition(sound_index);
972 	if (!definition) return;
973 
974 	if (!source)
975 	{
976 		variables.volume = variables.left_volume = variables.right_volume = MAXIMUM_SOUND_VOLUME;
977 		// ghs: is this what the priority should be if there's no source?
978 		variables.priority = definition->behavior_index;
979 	}
980 
981 	// and finally, do all the stuff we regularly do ...
982 	CalculateSoundVariables(sound_index, source, variables);
983 }
984 
InstantiateSoundVariables(Channel::Variables & variables,Channel & channel,bool first_time)985 void SoundManager::InstantiateSoundVariables(Channel::Variables& variables, Channel& channel, bool first_time)
986 {
987 	if (first_time || variables.right_volume != channel.variables.right_volume || variables.left_volume != channel.variables.left_volume)
988 	{
989 		Mixer::instance()->SetChannelVolumes(channel.mixer_channel, variables.left_volume, variables.right_volume);
990 	}
991 	channel.variables = variables;
992 }
993 
CalculatePitchModifier(short sound_index,_fixed pitch_modifier)994 _fixed SoundManager::CalculatePitchModifier(short sound_index, _fixed pitch_modifier)
995 {
996 	SoundDefinition *definition = GetSoundDefinition(sound_index);
997 	if (!definition) return FIXED_ONE;
998 
999 	if (!(definition->flags & _sound_cannot_change_pitch))
1000 	{
1001 		if (!(definition->flags & _sound_resists_pitch_changes))
1002 		{
1003 			pitch_modifier += ((FIXED_ONE-pitch_modifier)>>1);
1004 		}
1005 	}
1006 	else
1007 	{
1008 		pitch_modifier= FIXED_ONE;
1009 	}
1010 
1011 	return pitch_modifier;
1012 }
1013 
AngleAndVolumeToStereoVolume(angle delta,short volume,short * right_volume,short * left_volume)1014 void SoundManager::AngleAndVolumeToStereoVolume(angle delta, short volume, short *right_volume, short *left_volume)
1015 {
1016 	if (parameters.flags & _stereo_flag)
1017 	{
1018 		short fraction = delta & ((1<<(ANGULAR_BITS-2))-1);
1019 		short maximum_volume = volume + (volume >> 1);
1020 		short minimum_volume = volume >> 2;
1021 		short middle_volume = volume - minimum_volume;
1022 
1023 		switch (NORMALIZE_ANGLE(delta)>>(ANGULAR_BITS-2))
1024 		{
1025 		case 0: // rear right quarter [v,vmax] [v,vmin]
1026 			*left_volume= middle_volume + ((fraction*(maximum_volume-middle_volume))>>(ANGULAR_BITS-2));
1027 			*right_volume= middle_volume + ((fraction*(minimum_volume-middle_volume))>>(ANGULAR_BITS-2));
1028 			break;
1029 
1030 		case 1: // front right quarter [vmax,vmid] [vmin,vmid]
1031 			*left_volume= maximum_volume + ((fraction*(volume-maximum_volume))>>(ANGULAR_BITS-2));
1032 			*right_volume= minimum_volume + ((fraction*(volume-minimum_volume))>>(ANGULAR_BITS-2));
1033 			break;
1034 
1035 		case 2: // front left quarter [vmid,vmin] [vmid,vmax]
1036 			*left_volume= volume + ((fraction*(minimum_volume-volume))>>(ANGULAR_BITS-2));
1037 			*right_volume= volume + ((fraction*(maximum_volume-volume))>>(ANGULAR_BITS-2));
1038 			break;
1039 
1040 		case 3: // rear left quarter [vmin,v] [vmax,v]
1041 			*left_volume= minimum_volume + ((fraction*(middle_volume-minimum_volume))>>(ANGULAR_BITS-2));
1042 			*right_volume= maximum_volume + ((fraction*(middle_volume-maximum_volume))>>(ANGULAR_BITS-2));
1043 			break;
1044 
1045 		default:
1046 			assert(false);
1047 			break;
1048 
1049 		}
1050 	}
1051 	else
1052 	{
1053 		*left_volume = *right_volume = volume;
1054 	}
1055 }
1056 
GetRandomSoundPermutation(short sound_index)1057 short SoundManager::GetRandomSoundPermutation(short sound_index)
1058 {
1059 	SoundDefinition *definition = GetSoundDefinition(sound_index);
1060 	if (!definition) return 0;
1061 
1062 	short permutation;
1063 
1064 	if (!(definition->permutations > 0)) return 0;
1065 
1066 	if (parameters.flags & _more_sounds_flag)
1067 	{
1068 		if ((definition->permutations_played & ((1<<definition->permutations)-1))==((1<<definition->permutations)-1))
1069 			definition->permutations_played = 0;
1070 		permutation = local_random() % definition->permutations;
1071 		while (definition->permutations_played & (1 << permutation))
1072 			if ((permutation += 1) >= definition->permutations)
1073 				permutation = 0;
1074 		definition->permutations_played |= 1 << permutation;
1075 	}
1076 	else
1077 	{
1078 		permutation = 0;
1079 	}
1080 
1081 	definition->last_played = machine_tick_count();
1082 
1083 	return permutation;
1084 }
1085 
TrackStereoSounds()1086 void SoundManager::TrackStereoSounds()
1087 {
1088 	if (active && total_channel_count > 0 && (parameters.flags & _dynamic_tracking_flag))
1089 	{
1090 		for (int i = 0; i < parameters.channel_count; i++)
1091 		{
1092 			Channel *channel = &channels[i];
1093 			if (SLOT_IS_USED(channel) && !Mixer::instance()->ChannelBusy(channel->mixer_channel) && !(channel->flags & _sound_is_local))
1094 			{
1095 				Channel::Variables variables = channel->variables;
1096 				if (channel->dynamic_source)
1097 					channel->source = *channel->dynamic_source;
1098 				CalculateSoundVariables(channel->sound_index, &channel->source, variables);
1099 				InstantiateSoundVariables(variables, *channel, false);
1100 			}
1101 		}
1102 	}
1103 }
1104 
add_one_ambient_sound_source(struct ambient_sound_data * ambient_sounds,world_location3d * source,world_location3d * listener,short sound_index,short absolute_volume)1105 static void add_one_ambient_sound_source(struct ambient_sound_data *ambient_sounds,
1106 					 world_location3d *source, world_location3d *listener, short sound_index,
1107 					 short absolute_volume)
1108 {
1109 	SoundManager::instance()->AddOneAmbientSoundSource(ambient_sounds, source, listener, sound_index, absolute_volume);
1110 }
1111 
UpdateAmbientSoundSources()1112 void SoundManager::UpdateAmbientSoundSources()
1113 {
1114 	ambient_sound_data ambient_sounds[MAXIMUM_PROCESSED_AMBIENT_SOUNDS];
1115 
1116 	bool channel_used[MAXIMUM_AMBIENT_SOUND_CHANNELS];
1117 	bool sound_handled[MAXIMUM_PROCESSED_AMBIENT_SOUNDS];
1118 
1119 	// reset all local copies
1120 	for (short i = 0; i < MAXIMUM_PROCESSED_AMBIENT_SOUNDS; i++)
1121 	{
1122 		ambient_sounds[i].flags = 0;
1123 		ambient_sounds[i].sound_index = NONE;
1124 
1125 		sound_handled[i] = false;
1126 	}
1127 
1128 	for (short i = 0; i < MAXIMUM_AMBIENT_SOUND_CHANNELS; i++)
1129 	{
1130 		channel_used[i] = false;
1131 	}
1132 
1133 	// accumulate up to MAXIMUM_PROCESSED_AMBIENT_SOUNDS worth of sounds
1134 	_sound_add_ambient_sources_proc(&ambient_sounds, add_one_ambient_sound_source);
1135 
1136 	// remove all zero volume sounds
1137 	for (short i = 0; i < MAXIMUM_PROCESSED_AMBIENT_SOUNDS; i++)
1138 	{
1139 		ambient_sound_data *ambient = &ambient_sounds[i];
1140 		if (SLOT_IS_USED(ambient) && !ambient->variables.volume)
1141 			MARK_SLOT_AS_FREE(ambient);
1142 	}
1143 
1144 	{
1145 		ambient_sound_data *lowest_priority;
1146 		short count;
1147 
1148 		do
1149 		{
1150 			lowest_priority = 0;
1151 			count = 0;
1152 
1153 			for (short i = 0; i < MAXIMUM_PROCESSED_AMBIENT_SOUNDS; i++)
1154 			{
1155 				ambient_sound_data *ambient = &ambient_sounds[i];
1156 				if (SLOT_IS_USED(ambient))
1157 				{
1158 					if (!lowest_priority || lowest_priority->variables.volume > ambient->variables.volume + ABORT_AMPLITUDE_THRESHHOLD)
1159 					{
1160 						lowest_priority = ambient;
1161 					}
1162 
1163 					count++;
1164 				}
1165 			}
1166 
1167 			if (count >  MAXIMUM_AMBIENT_SOUND_CHANNELS)
1168 			{
1169 				assert(lowest_priority);
1170 				MARK_SLOT_AS_FREE(lowest_priority);
1171 				count--;
1172 			}
1173 		}
1174 		while (count > MAXIMUM_AMBIENT_SOUND_CHANNELS);
1175 
1176 	}
1177 
1178 	// update .variables of those sounds which we are already playing
1179 	for (short i = 0; i < MAXIMUM_PROCESSED_AMBIENT_SOUNDS; i++)
1180 	{
1181 		ambient_sound_data *ambient = &ambient_sounds[i];
1182 		if (SLOT_IS_USED(ambient))
1183 		{
1184 			for (short j = 0; j < MAXIMUM_AMBIENT_SOUND_CHANNELS; j++)
1185 			{
1186 				Channel *channel = &channels[parameters.channel_count + j];
1187 				if (SLOT_IS_USED(channel) && channel->sound_index == ambient->sound_index)
1188 				{
1189 					InstantiateSoundVariables(ambient->variables, *channel, false);
1190 					sound_handled[i] = channel_used[j] = true;
1191 					break;
1192 				}
1193 			}
1194 		}
1195 	}
1196 
1197 	// allocate a channel for a sound we just started playing
1198 	for (short i = 0; i < MAXIMUM_PROCESSED_AMBIENT_SOUNDS; i++)
1199 	{
1200 		ambient_sound_data *ambient = &ambient_sounds[i];
1201 
1202 		if (SLOT_IS_USED(ambient) && !sound_handled[i])
1203 		{
1204 			for (short j = 0; j < MAXIMUM_AMBIENT_SOUND_CHANNELS; j++)
1205 			{
1206 				Channel *channel = &channels[j + parameters.channel_count];
1207 				if (!channel_used[j])
1208 				{
1209 					if (SLOT_IS_USED(channel)) FreeChannel(*channel);
1210 					channel->flags = 0;
1211 					channel->callback_count = 2; // #MD as if two sounds had just stopped playing
1212 					channel->sound_index = ambient->sound_index;
1213 					MARK_SLOT_AS_USED(channel);
1214 
1215 					channel_used[j] = true;
1216 
1217 					InstantiateSoundVariables(ambient->variables, *channel, true);
1218 					break;
1219 				}
1220 			}
1221 		}
1222 	}
1223 
1224 	// remove those sounds which are no longer being played
1225 	for (short i = 0; i < MAXIMUM_AMBIENT_SOUND_CHANNELS; i++)
1226 	{
1227 		Channel *channel = &channels[i + parameters.channel_count];
1228 		if (SLOT_IS_USED(channel) && !channel_used[i])
1229 		{
1230 			FreeChannel(*channel);
1231 		}
1232 	}
1233 
1234 	// unlock those handles which need to be unlocked and buffer new sounds if necessary
1235 	for (short i = 0; i < MAXIMUM_AMBIENT_SOUND_CHANNELS; i++)
1236 	{
1237 		Channel *channel = &channels[i + parameters.channel_count];
1238 		if (SLOT_IS_USED(channel))
1239 		{
1240 			if (LoadSound(channel->sound_index))
1241 			{
1242 				while (channel->callback_count)
1243 				{
1244 					BufferSound(*channel, channel->sound_index, FIXED_ONE, false);
1245 					channel->callback_count--;
1246 				}
1247 			}
1248 		}
1249 	}
1250 }
1251 
1252 // List of sounds
1253 
1254 // Extra formerly-hardcoded sounds and their accessors; this is done for M1 compatibility:
1255 // Added Ian-Rickard-style interface commands for button actions (map resizing, resolution changes, ...)
1256 
1257 static short _Sound_TerminalLogon = _snd_computer_interface_logon;
1258 static short _Sound_TerminalLogoff = _snd_computer_interface_logout;
1259 static short _Sound_TerminalPage = _snd_computer_interface_page;
1260 
1261 static short _Sound_TeleportIn = _snd_teleport_in;
1262 static short _Sound_TeleportOut = _snd_teleport_out;
1263 
1264 static short _Sound_GotPowerup = _snd_got_powerup;
1265 static short _Sound_GotItem = _snd_got_item;
1266 
1267 static short _Sound_Crunched = _snd_body_being_crunched;
1268 static short _Sound_Exploding = _snd_juggernaut_exploding;
1269 
1270 static short _Sound_Breathing = _snd_breathing;
1271 static short _Sound_OxygenWarning = _snd_oxygen_warning;
1272 
1273 static short _Sound_AdjustVolume = _snd_adjust_volume;
1274 
1275 static short _Sound_ButtonSuccess = _snd_computer_interface_page;
1276 static short _Sound_ButtonFailure = _snd_absorbed;
1277 static short _Sound_ButtonInoperative = _snd_cant_toggle_switch;
1278 static short _Sound_OGL_Reset = _snd_juggernaut_exploding;
1279 static short _Sound_Center_Button = _snd_owl;
1280 
1281 
Sound_TerminalLogon()1282 short Sound_TerminalLogon() {return _Sound_TerminalLogon;}
Sound_TerminalLogoff()1283 short Sound_TerminalLogoff() {return _Sound_TerminalLogoff;}
Sound_TerminalPage()1284 short Sound_TerminalPage() {return _Sound_TerminalPage;}
1285 
Sound_TeleportIn()1286 short Sound_TeleportIn() {return _Sound_TeleportIn;}
Sound_TeleportOut()1287 short Sound_TeleportOut() {return _Sound_TeleportOut;}
1288 
Sound_GotPowerup()1289 short Sound_GotPowerup() {return _Sound_GotPowerup;}
Sound_GotItem()1290 short Sound_GotItem() {return _Sound_GotItem;}
1291 
Sound_Crunched()1292 short Sound_Crunched() {return _Sound_Crunched;}
Sound_Exploding()1293 short Sound_Exploding() {return _Sound_Exploding;}
1294 
Sound_Breathing()1295 short Sound_Breathing() {return _Sound_Breathing;}
Sound_OxygenWarning()1296 short Sound_OxygenWarning() {return _Sound_OxygenWarning;}
1297 
Sound_AdjustVolume()1298 short Sound_AdjustVolume() {return _Sound_AdjustVolume;}
1299 
Sound_ButtonSuccess()1300 short Sound_ButtonSuccess() {return _Sound_ButtonSuccess;}
Sound_ButtonFailure()1301 short Sound_ButtonFailure() {return _Sound_ButtonFailure;}
Sound_ButtonInoperative()1302 short Sound_ButtonInoperative() {return _Sound_ButtonInoperative;}
Sound_OGL_Reset()1303 short Sound_OGL_Reset() {return _Sound_OGL_Reset;}
Sound_Center_Button()1304 short Sound_Center_Button() {return _Sound_Center_Button;}
1305 
1306 // XML elements for parsing sound specifications
1307 struct ambient_sound_definition *original_ambient_sound_definitions = NULL;
1308 struct random_sound_definition *original_random_sound_definitions = NULL;
1309 
1310 extern int16 dialog_sound_definitions[];
1311 extern int16* original_dialog_sound_definitions;
1312 extern int number_of_dialog_sounds();
1313 
reset_mml_sounds()1314 void reset_mml_sounds()
1315 {
1316 	if (original_ambient_sound_definitions) {
1317 		for (int i = 0; i < NUMBER_OF_AMBIENT_SOUND_DEFINITIONS; i++)
1318 			ambient_sound_definitions[i] = original_ambient_sound_definitions[i];
1319 		free(original_ambient_sound_definitions);
1320 		original_ambient_sound_definitions = NULL;
1321 	}
1322 	if (original_random_sound_definitions) {
1323 		for (int i = 0; i < NUMBER_OF_RANDOM_SOUND_DEFINITIONS; i++)
1324 			random_sound_definitions[i] = original_random_sound_definitions[i];
1325 		free(original_random_sound_definitions);
1326 		original_random_sound_definitions = NULL;
1327 	}
1328 	if (original_dialog_sound_definitions)
1329 	{
1330 		for (int i = 0; i < number_of_dialog_sounds(); ++i)
1331 		{
1332 			dialog_sound_definitions[i] = original_dialog_sound_definitions[i];
1333 		}
1334 		free(original_dialog_sound_definitions);
1335 		original_dialog_sound_definitions = 0;
1336 	}
1337 	SoundReplacements::instance()->Reset();
1338 }
1339 
parse_mml_sounds(const InfoTree & root)1340 void parse_mml_sounds(const InfoTree& root)
1341 {
1342 	// back up old values first
1343 	if (!original_ambient_sound_definitions) {
1344 		original_ambient_sound_definitions = (struct ambient_sound_definition *) malloc(sizeof(struct ambient_sound_definition) * NUMBER_OF_AMBIENT_SOUND_DEFINITIONS);
1345 		assert(original_ambient_sound_definitions);
1346 		for (int i = 0; i < NUMBER_OF_AMBIENT_SOUND_DEFINITIONS; i++)
1347 			original_ambient_sound_definitions[i] = ambient_sound_definitions[i];
1348 	}
1349 	if (!original_random_sound_definitions) {
1350 		original_random_sound_definitions = (struct random_sound_definition *) malloc(sizeof(struct random_sound_definition) * NUMBER_OF_RANDOM_SOUND_DEFINITIONS);
1351 		assert(original_random_sound_definitions);
1352 		for (int i = 0; i < NUMBER_OF_RANDOM_SOUND_DEFINITIONS; i++)
1353 			original_random_sound_definitions[i] = random_sound_definitions[i];
1354 	}
1355 	if (!original_dialog_sound_definitions)
1356 	{
1357 		original_dialog_sound_definitions = (int16*) malloc(sizeof(int16) * number_of_dialog_sounds());
1358 		for (int i = 0; i < number_of_dialog_sounds(); ++i)
1359 		{
1360 			original_dialog_sound_definitions[i] = dialog_sound_definitions[i];
1361 		}
1362 	}
1363 
1364 	root.read_attr("terminal_logon", _Sound_TerminalLogon);
1365 	root.read_attr("terminal_logoff", _Sound_TerminalLogoff);
1366 	root.read_attr("terminal_page", _Sound_TerminalPage);
1367 	root.read_attr("teleport_in", _Sound_TeleportIn);
1368 	root.read_attr("teleport_out", _Sound_TeleportOut);
1369 	root.read_attr("got_powerup", _Sound_GotPowerup);
1370 	root.read_attr("got_item", _Sound_GotItem);
1371 	root.read_attr("crunched", _Sound_Crunched);
1372 	root.read_attr("exploding", _Sound_Exploding);
1373 	root.read_attr("breathing", _Sound_Breathing);
1374 	root.read_attr("oxygen_warning", _Sound_OxygenWarning);
1375 	root.read_attr("adjust_volume", _Sound_AdjustVolume);
1376 	root.read_attr("button_success", _Sound_ButtonSuccess);
1377 	root.read_attr("button_failure", _Sound_ButtonFailure);
1378 	root.read_attr("button_inoperative", _Sound_ButtonInoperative);
1379 	root.read_attr("ogl_reset", _Sound_OGL_Reset);
1380 	root.read_attr("center_button", _Sound_Center_Button);
1381 
1382 	BOOST_FOREACH(InfoTree ambient, root.children_named("ambient"))
1383 	{
1384 		int16 index;
1385 		if (!ambient.read_indexed("index", index, NUMBER_OF_AMBIENT_SOUND_DEFINITIONS))
1386 			continue;
1387 		ambient.read_indexed("sound", ambient_sound_definitions[index].sound_index, SHRT_MAX+1, true);
1388 	}
1389 	BOOST_FOREACH(InfoTree random, root.children_named("random"))
1390 	{
1391 		int16 index;
1392 		if (!random.read_indexed("index", index, NUMBER_OF_RANDOM_SOUND_DEFINITIONS))
1393 			continue;
1394 		random.read_indexed("sound", random_sound_definitions[index].sound_index, SHRT_MAX+1, true);
1395 	}
1396 	BOOST_FOREACH(InfoTree dialog, root.children_named("dialog"))
1397 	{
1398 		int16 index;
1399 		if (!dialog.read_indexed("index", index, number_of_dialog_sounds()))
1400 			continue;
1401 		dialog.read_indexed("sound", dialog_sound_definitions[index], SHRT_MAX+1, true);
1402 	}
1403 
1404 	// external sounds: set or clear in order
1405 	BOOST_FOREACH(const InfoTree::value_type &v, root)
1406 	{
1407 		std::string name = v.first;
1408 		if (name == "sound_clear")
1409 		{
1410 			SoundReplacements::instance()->Reset();
1411 		}
1412 		else if (name == "sound")
1413 		{
1414 			InfoTree external = v.second;
1415 			int16 index;
1416 			if (!external.read_attr("index", index))
1417 				continue;
1418 
1419 			int16 slot = 0;
1420 			external.read_indexed("slot", slot, MAXIMUM_PERMUTATIONS_PER_SOUND);
1421 
1422 			SoundOptions data;
1423 			data.File = FileSpecifier();
1424 			std::string filename;
1425 			if (external.read_attr("file", filename))
1426 				data.File.SetNameWithPath(filename.c_str());
1427 
1428 			SoundReplacements::instance()->Add(data, index, slot);
1429 		}
1430 	}
1431 }
1432