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