1 /*
2  * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3  *
4  * This file is part of Arx Libertatis.
5  *
6  * Arx Libertatis is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Arx Libertatis is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Arx Libertatis.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23 
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25 
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28 
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31 
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code.  If not, see
33 <http://www.gnu.org/licenses/>.
34 
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38 
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved
44 
45 #include "scene/GameSound.h"
46 
47 #include <map>
48 #include <vector>
49 #include <sstream>
50 #include <cstdio>
51 
52 #include <boost/algorithm/string/case_conv.hpp>
53 
54 #include "animation/Animation.h"
55 
56 #include "audio/Audio.h"
57 
58 #include "core/Config.h"
59 
60 #include "game/EntityManager.h"
61 #include "game/Inventory.h"
62 #include "game/NPC.h"
63 #include "game/Player.h"
64 
65 #include "graphics/Math.h"
66 #include "graphics/particle/ParticleEffects.h"
67 
68 #include "io/resource/ResourcePath.h"
69 #include "io/resource/PakReader.h"
70 #include "io/IniReader.h"
71 #include "io/log/Logger.h"
72 
73 #include "platform/Platform.h"
74 #include "platform/Thread.h"
75 
76 #include "scene/Interactive.h"
77 
78 #include "util/String.h"
79 
80 using std::map;
81 using std::string;
82 using std::istringstream;
83 using std::ostringstream;
84 using std::vector;
85 using std::sprintf;
86 
87 using audio::AmbianceId;
88 using audio::SampleId;
89 using audio::SourceId;
90 using audio::EnvId;
91 using audio::INVALID_ID;
92 using audio::FLAG_VOLUME;
93 using audio::FLAG_POSITION;
94 using audio::FLAG_REVERBERATION;
95 using audio::FLAG_FALLOFF;
96 using audio::FLAG_PITCH;
97 using audio::FLAG_RELATIVE;
98 using audio::FLAG_AUTOFREE;
99 
100 extern long EXTERNALVIEW;
101 extern Entity * CAMERACONTROLLER;
102 
103 
104 enum PlayingAmbianceType {
105 	PLAYING_AMBIANCE_MENU,
106 	PLAYING_AMBIANCE_SCRIPT,
107 	PLAYING_AMBIANCE_ZONE
108 };
109 
110 // TODO used for saving
111 struct PlayingAmbiance {
112 	char name[256];
113 	f32 volume;
114 	s32 loop;
115 	s32 type;
116 };
117 
118 static const unsigned long ARX_SOUND_UPDATE_INTERVAL(100);
119 static const unsigned long ARX_SOUND_STREAMING_LIMIT(176400);
120 static const unsigned long MAX_MATERIALS(17);
121 static const unsigned long MAX_VARIANTS(5);
122 static const unsigned long AMBIANCE_FADE_TIME(2000);
123 static const float ARX_SOUND_UNIT_FACTOR(0.01F);
124 static const float ARX_SOUND_ROLLOFF_FACTOR(1.3F);
125 static const float ARX_SOUND_DEFAULT_FALLSTART(200.0F);
126 
127 static const float ARX_SOUND_DEFAULT_FALLEND(2200.0F);
128 static const float ARX_SOUND_REFUSE_DISTANCE(2500.0F);
129 
130 static const res::path ARX_SOUND_PATH_INI = "localisation";
131 static const char ARX_SOUND_PATH_SAMPLE[] = "sfx";
132 static const char ARX_SOUND_PATH_AMBIANCE[] = "sfx/ambiance";
133 static const char ARX_SOUND_PATH_ENVIRONMENT[] = "sfx/environment";
134 static const res::path ARX_SOUND_PRESENCE_NAME = "presence";
135 static const string ARX_SOUND_FILE_EXTENSION_WAV = ".wav";
136 static const string ARX_SOUND_FILE_EXTENSION_INI = ".ini";
137 
138 static const unsigned long ARX_SOUND_COLLISION_MAP_COUNT = 3;
139 static const res::path ARX_SOUND_COLLISION_MAP_NAMES[] = {
140 	"snd_armor",
141 	"snd_step",
142 	"snd_weapon"
143 };
144 
145 static bool bIsActive(false);
146 
147 
148 static AmbianceId ambiance_zone(INVALID_ID);
149 static AmbianceId ambiance_menu = INVALID_ID;
150 
151 static long Inter_Materials[MAX_MATERIALS][MAX_MATERIALS][MAX_VARIANTS];
152 
153 namespace {
154 
155 struct SoundMaterial {
156 
157 	vector<SampleId> variants;
158 
SoundMaterial__anoncd60bbff0111::SoundMaterial159 	SoundMaterial() : current(0) { }
160 
~SoundMaterial__anoncd60bbff0111::SoundMaterial161 	~SoundMaterial() {
162 		for(vector<SampleId>::const_iterator i = variants.begin(); i !=  variants.end(); ++i) {
163 			audio::deleteSample(*i);
164 		}
165 	}
166 
next__anoncd60bbff0111::SoundMaterial167 	SampleId next() {
168 		arx_assert(current < variants.size());
169 		SampleId sample = variants[current];
170 		current = (current + 1) % variants.size();
171 		return sample;
172 	}
173 
174 private:
175 
176 	size_t current;
177 
178 };
179 
180 typedef map<string, SoundMaterial> CollisionMap;
181 typedef map<string, CollisionMap> CollisionMaps;
182 static CollisionMaps collisionMaps;
183 
184 namespace Section {
185 static const string presence = "presence";
186 }
187 
188 typedef map<res::path, float> PresenceFactors;
189 static PresenceFactors presence;
190 
191 }
192 
193 
194 
195 SampleId ARX_SOUND_MixerGame(INVALID_ID);
196 SampleId ARX_SOUND_MixerGameSample(INVALID_ID);
197 SampleId ARX_SOUND_MixerGameSpeech(INVALID_ID);
198 SampleId ARX_SOUND_MixerGameAmbiance(INVALID_ID);
199 SampleId ARX_SOUND_MixerMenu(INVALID_ID);
200 SampleId ARX_SOUND_MixerMenuSample(INVALID_ID);
201 SampleId ARX_SOUND_MixerMenuSpeech(INVALID_ID);
202 SampleId ARX_SOUND_MixerMenuAmbiance(INVALID_ID);
203 
204 // Menu samples
205 SampleId SND_MENU_CLICK(INVALID_ID);
206 SampleId SND_MENU_RELEASE(INVALID_ID);
207 
208 // Interface samples
209 SampleId SND_BACKPACK(INVALID_ID);
210 SampleId SND_BOOK_OPEN(INVALID_ID);
211 SampleId SND_BOOK_CLOSE(INVALID_ID);
212 SampleId SND_BOOK_PAGE_TURN(INVALID_ID);
213 SampleId SND_GOLD(INVALID_ID);
214 SampleId SND_INVSTD(INVALID_ID);
215 SampleId SND_SCROLL_OPEN(INVALID_ID);
216 SampleId SND_SCROLL_CLOSE(INVALID_ID);
217 SampleId SND_TORCH_START(INVALID_ID);
218 SampleId SND_TORCH_LOOP(INVALID_ID);
219 SampleId SND_TORCH_END(INVALID_ID);
220 
221 // Other SFX samples
222 SampleId SND_FIREPLACE(INVALID_ID);
223 SampleId SND_PLOUF(INVALID_ID);
224 SampleId SND_QUAKE(INVALID_ID);
225 SampleId SND_WHOOSH(INVALID_ID);
226 
227 // Player samples
228 SampleId SND_PLAYER_DEATH_BY_FIRE(INVALID_ID);
229 
230 SampleId SND_PLAYER_FILLLIFEMANA(INVALID_ID);
231 SampleId SND_PLAYER_HEART_BEAT(INVALID_ID);
232 SampleId SND_PLAYER_LEVEL_UP(INVALID_ID);
233 SampleId SND_PLAYER_POISONED(INVALID_ID);
234 
235 // Magic drawing samples
236 SampleId SND_MAGIC_AMBIENT(INVALID_ID);
237 SampleId SND_MAGIC_DRAW(INVALID_ID);
238 SampleId SND_MAGIC_FIZZLE(INVALID_ID);
239 
240 // Magic symbols samples
241 SampleId SND_SYMB_AAM(INVALID_ID);
242 SampleId SND_SYMB_CETRIUS(INVALID_ID);
243 SampleId SND_SYMB_COSUM(INVALID_ID);
244 SampleId SND_SYMB_COMUNICATUM(INVALID_ID);
245 SampleId SND_SYMB_FOLGORA(INVALID_ID);
246 SampleId SND_SYMB_FRIDD(INVALID_ID);
247 SampleId SND_SYMB_KAOM(INVALID_ID);
248 SampleId SND_SYMB_MEGA(INVALID_ID);
249 SampleId SND_SYMB_MORTE(INVALID_ID);
250 SampleId SND_SYMB_MOVIS(INVALID_ID);
251 SampleId SND_SYMB_NHI(INVALID_ID);
252 SampleId SND_SYMB_RHAA(INVALID_ID);
253 SampleId SND_SYMB_SPACIUM(INVALID_ID);
254 SampleId SND_SYMB_STREGUM(INVALID_ID);
255 SampleId SND_SYMB_TAAR(INVALID_ID);
256 SampleId SND_SYMB_TEMPUS(INVALID_ID);
257 SampleId SND_SYMB_TERA(INVALID_ID);
258 SampleId SND_SYMB_VISTA(INVALID_ID);
259 SampleId SND_SYMB_VITAE(INVALID_ID);
260 SampleId SND_SYMB_YOK(INVALID_ID);
261 
262 // Spells samples
263 SampleId SND_SPELL_ACTIVATE_PORTAL(INVALID_ID);
264 SampleId SND_SPELL_ARMOR_START(INVALID_ID);
265 SampleId SND_SPELL_ARMOR_END(INVALID_ID);
266 SampleId SND_SPELL_ARMOR_LOOP(INVALID_ID);
267 SampleId SND_SPELL_LOWER_ARMOR(INVALID_ID);
268 SampleId SND_SPELL_BLESS(INVALID_ID);
269 SampleId SND_SPELL_COLD_PROTECTION_START(INVALID_ID);
270 SampleId SND_SPELL_COLD_PROTECTION_LOOP(INVALID_ID);
271 SampleId SND_SPELL_COLD_PROTECTION_END(INVALID_ID);
272 SampleId SND_SPELL_CONFUSE(INVALID_ID);
273 SampleId SND_SPELL_CONTROL_TARGET(INVALID_ID);
274 SampleId SND_SPELL_CREATE_FIELD(INVALID_ID);
275 SampleId SND_SPELL_CREATE_FOOD(INVALID_ID);
276 SampleId SND_SPELL_CURE_POISON(INVALID_ID);
277 SampleId SND_SPELL_CURSE(INVALID_ID);
278 SampleId SND_SPELL_DETECT_TRAP(INVALID_ID);
279 SampleId SND_SPELL_DETECT_TRAP_LOOP(INVALID_ID);
280 SampleId SND_SPELL_DISARM_TRAP(INVALID_ID);
281 SampleId SND_SPELL_DISPELL_FIELD(INVALID_ID);
282 SampleId SND_SPELL_DISPELL_ILLUSION(INVALID_ID);
283 SampleId SND_SPELL_DOUSE(INVALID_ID);
284 SampleId SND_SPELL_ELECTRIC(INVALID_ID);
285 SampleId SND_SPELL_ENCHANT_WEAPON(INVALID_ID);
286 SampleId SND_SPELL_EXPLOSION(INVALID_ID);
287 SampleId SND_SPELL_EYEBALL_IN(INVALID_ID);
288 SampleId SND_SPELL_EYEBALL_OUT(INVALID_ID);
289 SampleId SND_SPELL_FIRE_FIELD(INVALID_ID);
290 SampleId SND_SPELL_FIRE_HIT(INVALID_ID);
291 SampleId SND_SPELL_FIRE_LAUNCH(INVALID_ID);
292 SampleId SND_SPELL_FIRE_PROTECTION(INVALID_ID);
293 SampleId SND_SPELL_FIRE_PROTECTION_LOOP(INVALID_ID);
294 SampleId SND_SPELL_FIRE_PROTECTION_END(INVALID_ID);
295 SampleId SND_SPELL_FIRE_WIND(INVALID_ID);
296 SampleId SND_SPELL_FREEZETIME(INVALID_ID);
297 SampleId SND_SPELL_HARM(INVALID_ID);
298 SampleId SND_SPELL_HEALING(INVALID_ID);
299 SampleId SND_SPELL_ICE_FIELD(INVALID_ID);
300 SampleId SND_SPELL_ICE_FIELD_LOOP(INVALID_ID);
301 SampleId SND_SPELL_ICE_FIELD_END(INVALID_ID);
302 SampleId SND_SPELL_ICE_PROJECTILE_LAUNCH(INVALID_ID);
303 SampleId SND_SPELL_INCINERATE(INVALID_ID);
304 SampleId SND_SPELL_INCINERATE_LOOP(INVALID_ID);
305 SampleId SND_SPELL_INCINERATE_END(INVALID_ID);
306 SampleId SND_SPELL_IGNITE(INVALID_ID);
307 SampleId SND_SPELL_INVISIBILITY_START(INVALID_ID);
308 SampleId SND_SPELL_INVISIBILITY_END(INVALID_ID);
309 SampleId SND_SPELL_LEVITATE_START(INVALID_ID);
310 SampleId SND_SPELL_LIGHTNING_START(INVALID_ID);
311 SampleId SND_SPELL_LIGHTNING_LOOP(INVALID_ID);
312 SampleId SND_SPELL_LIGHTNING_END(INVALID_ID);
313 SampleId SND_SPELL_MAGICAL_HIT(INVALID_ID);
314 
315 //SampleId SND_SPELL_MASS_LIGHTNING_END(INVALID_ID);
316 SampleId SND_SPELL_FIRE_FIELD_START(INVALID_ID);
317 SampleId SND_SPELL_FIRE_FIELD_LOOP(INVALID_ID);
318 SampleId SND_SPELL_FIRE_FIELD_END(INVALID_ID);
319 
320 
321 SampleId SND_SPELL_MAGICAL_SHIELD(INVALID_ID);
322 SampleId SND_SPELL_MASS_INCINERATE(INVALID_ID);
323 SampleId SND_SPELL_MASS_PARALYSE(INVALID_ID);
324 SampleId SND_SPELL_MM_CREATE(INVALID_ID);
325 SampleId SND_SPELL_MM_HIT(INVALID_ID);
326 SampleId SND_SPELL_MM_LAUNCH(INVALID_ID);
327 SampleId SND_SPELL_MM_LOOP(INVALID_ID);
328 SampleId SND_SPELL_NEGATE_MAGIC(INVALID_ID);
329 SampleId SND_SPELL_NO_EFFECT(INVALID_ID);
330 SampleId SND_SPELL_PARALYSE(INVALID_ID);
331 SampleId SND_SPELL_PARALYSE_END(INVALID_ID);
332 SampleId SND_SPELL_POISON_PROJECTILE_LAUNCH(INVALID_ID);
333 SampleId SND_SPELL_RAISE_DEAD(INVALID_ID);
334 SampleId SND_SPELL_REPEL_UNDEAD(INVALID_ID);
335 SampleId SND_SPELL_REPEL_UNDEAD_LOOP(INVALID_ID);
336 SampleId SND_SPELL_RUNE_OF_GUARDING(INVALID_ID);
337 SampleId SND_SPELL_RUNE_OF_GUARDING_END(INVALID_ID);
338 SampleId SND_SPELL_SLOW_DOWN(INVALID_ID);
339 SampleId SND_SPELL_SPARK(INVALID_ID);
340 SampleId SND_SPELL_SPEED_START(INVALID_ID);
341 SampleId SND_SPELL_SPEED_LOOP(INVALID_ID);
342 SampleId SND_SPELL_SPEED_END(INVALID_ID);
343 SampleId SND_SPELL_SUMMON_CREATURE(INVALID_ID);
344 SampleId SND_SPELL_TELEKINESIS_START(INVALID_ID);
345 SampleId SND_SPELL_TELEKINESIS_END(INVALID_ID);
346 SampleId SND_SPELL_TELEPORT(INVALID_ID);
347 SampleId SND_SPELL_TELEPORTED(INVALID_ID);
348 SampleId SND_SPELL_VISION_START(INVALID_ID);
349 SampleId SND_SPELL_VISION_LOOP(INVALID_ID);
350 
351 static void ARX_SOUND_EnvironmentSet(const res::path & name);
352 static void ARX_SOUND_CreateEnvironments();
353 static void ARX_SOUND_CreateStaticSamples();
354 static void ARX_SOUND_ReleaseStaticSamples();
355 static void ARX_SOUND_LoadCollision(const long & mat1, const long & mat2, const char * name);
356 static void ARX_SOUND_CreateCollisionMaps();
357 static void ARX_SOUND_CreateMaterials();
358 static void ARX_SOUND_CreatePresenceMap();
359 static float GetSamplePresenceFactor(const res::path & name);
360 static void ARX_SOUND_LaunchUpdateThread();
361 static void ARX_SOUND_KillUpdateThread();
362 
ARX_SOUND_Init()363 bool ARX_SOUND_Init() {
364 
365 	if (bIsActive) ARX_SOUND_Release();
366 
367 	if(audio::init(config.audio.backend,  config.audio.eax)) {
368 		audio::clean();
369 		return false;
370 	}
371 
372 	if(audio::setSamplePath(ARX_SOUND_PATH_SAMPLE)
373 	   || audio::setAmbiancePath(ARX_SOUND_PATH_AMBIANCE)
374 	   || audio::setEnvironmentPath(ARX_SOUND_PATH_ENVIRONMENT)) {
375 		audio::clean();
376 		return false;
377 	}
378 
379 	// Create game mixers
380 	ARX_SOUND_MixerGame = audio::createMixer();
381 	ARX_SOUND_MixerGameSample = audio::createMixer();
382 	audio::setMixerParent(ARX_SOUND_MixerGameSample, ARX_SOUND_MixerGame);
383 	ARX_SOUND_MixerGameSpeech = audio::createMixer();
384 	audio::setMixerParent(ARX_SOUND_MixerGameSpeech, ARX_SOUND_MixerGame);
385 	ARX_SOUND_MixerGameAmbiance = audio::createMixer();
386 	audio::setMixerParent(ARX_SOUND_MixerGameAmbiance, ARX_SOUND_MixerGame);
387 
388 	// Create menu mixers
389 	ARX_SOUND_MixerMenu = audio::createMixer();
390 	ARX_SOUND_MixerMenuSample = audio::createMixer();
391 	audio::setMixerParent(ARX_SOUND_MixerMenuSample, ARX_SOUND_MixerMenu);
392 	ARX_SOUND_MixerMenuSpeech = audio::createMixer();
393 	audio::setMixerParent(ARX_SOUND_MixerMenuSpeech, ARX_SOUND_MixerMenu);
394 	ARX_SOUND_MixerMenuAmbiance = audio::createMixer();
395 	audio::setMixerParent(ARX_SOUND_MixerMenuAmbiance, ARX_SOUND_MixerMenu);
396 
397 	if(ARX_SOUND_MixerGame == INVALID_ID
398 	   || ARX_SOUND_MixerGameSample == INVALID_ID
399 	   || ARX_SOUND_MixerGameSpeech == INVALID_ID
400 	   || ARX_SOUND_MixerGameAmbiance == INVALID_ID
401 	   || ARX_SOUND_MixerMenu == INVALID_ID
402 	   || ARX_SOUND_MixerMenuSample == INVALID_ID
403 	   || ARX_SOUND_MixerMenuSpeech == INVALID_ID
404 	   || ARX_SOUND_MixerMenuAmbiance == INVALID_ID) {
405 		audio::clean();
406 		return false;
407 	}
408 
409 	audio::setStreamLimit(ARX_SOUND_STREAMING_LIMIT);
410 
411 	audio::setUnitFactor(ARX_SOUND_UNIT_FACTOR);
412 	audio::setRolloffFactor(ARX_SOUND_ROLLOFF_FACTOR);
413 
414 	ARX_SOUND_LaunchUpdateThread();
415 
416 	bIsActive = true;
417 
418 	return true;
419 }
420 
ARX_SOUND_LoadData()421 void ARX_SOUND_LoadData() {
422 
423 	if(!bIsActive) {
424 		return;
425 	}
426 
427 	// Load samples
428 	ARX_SOUND_CreateStaticSamples();
429 	ARX_SOUND_CreateMaterials();
430 	ARX_SOUND_CreateCollisionMaps();
431 	ARX_SOUND_CreatePresenceMap();
432 
433 	// Load environments, enable environment system and set default one if required
434 	ARX_SOUND_CreateEnvironments();
435 
436 	if(config.audio.eax) {
437 		audio::setReverbEnabled(true);
438 		ARX_SOUND_EnvironmentSet("alley.aef");
439 	}
440 }
441 
ARX_SOUND_Release()442 void ARX_SOUND_Release() {
443 
444 	if(!bIsActive) {
445 		return;
446 	}
447 
448 	ARX_SOUND_ReleaseStaticSamples();
449 	collisionMaps.clear();
450 	presence.clear();
451 	ARX_SOUND_KillUpdateThread();
452 	audio::clean();
453 	bIsActive = false;
454 }
455 
ARX_SOUND_IsEnabled()456 long ARX_SOUND_IsEnabled()
457 {
458 	return bIsActive ? 1 : 0;
459 }
460 
ARX_SOUND_MixerSetVolume(audio::MixerId mixer_id,float volume)461 void ARX_SOUND_MixerSetVolume(audio::MixerId mixer_id, float volume) {
462 	if(bIsActive) {
463 		audio::setMixerVolume(mixer_id, volume);
464 	}
465 }
466 
ARX_SOUND_MixerStop(audio::MixerId mixer_id)467 void ARX_SOUND_MixerStop(audio::MixerId mixer_id) {
468 	if(bIsActive) {
469 		audio::mixerStop(mixer_id);
470 	}
471 }
472 
ARX_SOUND_MixerPause(audio::MixerId mixer_id)473 void ARX_SOUND_MixerPause(audio::MixerId mixer_id) {
474 	if(bIsActive) {
475 		audio::mixerPause(mixer_id);
476 	}
477 }
478 
ARX_SOUND_MixerResume(audio::MixerId mixer_id)479 void ARX_SOUND_MixerResume(audio::MixerId mixer_id) {
480 	if(bIsActive) {
481 		audio::mixerResume(mixer_id);
482 	}
483 }
484 
ARX_SOUND_MixerSwitch(audio::MixerId from,audio::MixerId to)485 void ARX_SOUND_MixerSwitch(audio::MixerId from, audio::MixerId to) {
486 	ARX_SOUND_MixerPause(from);
487 	ARX_SOUND_MixerResume(to);
488 }
489 
490 // Sets the position of the listener
ARX_SOUND_SetListener(const Vec3f * position,const Vec3f * front,const Vec3f * up)491 void ARX_SOUND_SetListener(const Vec3f * position, const Vec3f * front, const Vec3f * up) {
492 	if(bIsActive) {
493 		audio::setListenerPosition(*position);
494 		audio::setListenerDirection(*front, *up);
495 	}
496 }
497 
ARX_SOUND_EnvironmentSet(const res::path & name)498 void ARX_SOUND_EnvironmentSet(const res::path & name) {
499 
500 	if(bIsActive) {
501 		EnvId e_id = audio::getEnvironment(name);
502 		if(e_id != INVALID_ID) {
503 			audio::setListenerEnvironment(e_id);
504 			audio::setRoomRolloffFactor(ARX_SOUND_ROLLOFF_FACTOR);
505 		}
506 	}
507 }
508 
ARX_SOUND_PlaySFX(SourceId & sample_id,const Vec3f * position,float pitch,SoundLoopMode loop)509 long ARX_SOUND_PlaySFX(SourceId & sample_id, const Vec3f * position, float pitch, SoundLoopMode loop) {
510 
511 	if(!bIsActive || sample_id == INVALID_ID) {
512 		return INVALID_ID;
513 	}
514 
515 	audio::Channel channel;
516 	float presence;
517 
518 	channel.mixer = ARX_SOUND_MixerGameSample;
519 	channel.flags = FLAG_VOLUME | FLAG_POSITION | FLAG_REVERBERATION | FLAG_FALLOFF;
520 	channel.volume = 1.0F;
521 
522 	if(position) {
523 		if(ACTIVECAM && distSqr(ACTIVECAM->pos, *position) > square(ARX_SOUND_REFUSE_DISTANCE)) {
524 			return -1;
525 		}
526 	}
527 
528 	res::path sample_name;
529 	audio::getSampleName(sample_id, sample_name);
530 	presence = GetSamplePresenceFactor(sample_name);
531 	channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
532 	channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
533 
534 	if(pitch != 1.0F) {
535 		channel.flags |= FLAG_PITCH;
536 		channel.pitch = pitch;
537 	}
538 
539 	if(position) {
540 		channel.position = *position;
541 	} else {
542 		channel.flags |= FLAG_RELATIVE;
543 		channel.position = Vec3f::Z_AXIS;
544 	}
545 
546 	audio::samplePlay(sample_id, channel, loop);
547 
548 	return sample_id;
549 }
550 
551 
ARX_SOUND_PlayInterface(SourceId & sample_id,float pitch,SoundLoopMode loop)552 long ARX_SOUND_PlayInterface(SourceId & sample_id, float pitch, SoundLoopMode loop) {
553 
554 	if (!bIsActive || sample_id == INVALID_ID) return INVALID_ID;
555 
556 	audio::Channel channel;
557 
558 	channel.mixer = ARX_SOUND_MixerGameSample;
559 	channel.flags = FLAG_VOLUME;
560 	channel.volume = 1.0F;
561 
562 	if (pitch != 1.0F) channel.flags |= FLAG_PITCH, channel.pitch = pitch;
563 
564 	audio::samplePlay(sample_id, channel, loop);
565 
566 	return sample_id;
567 }
568 
ARX_SOUND_PlayMenu(SourceId & sample_id,float pitch,SoundLoopMode loop)569 long ARX_SOUND_PlayMenu(SourceId & sample_id, float pitch, SoundLoopMode loop) {
570 
571 	if (!bIsActive || sample_id == INVALID_ID) return INVALID_ID;
572 
573 	audio::Channel channel;
574 
575 	channel.mixer = ARX_SOUND_MixerMenuSample;
576 	channel.flags = FLAG_VOLUME;
577 	channel.volume = 1.0F;
578 
579 	if (pitch != 1.0F) channel.flags |= FLAG_PITCH, channel.pitch = pitch;
580 
581 	audio::samplePlay(sample_id, channel, loop);
582 
583 	return sample_id;
584 }
585 
586 
ARX_SOUND_IOFrontPos(const Entity * io,Vec3f & pos)587 void ARX_SOUND_IOFrontPos(const Entity * io, Vec3f & pos) {
588 	if(io) {
589 		pos.x = io->pos.x - EEsin(radians(MAKEANGLE(io->angle.b))) * 100.0F;
590 		pos.y = io->pos.y - 100.0F;
591 		pos.z = io->pos.z + EEcos(radians(MAKEANGLE(io->angle.b))) * 100.0F;
592 	} else if(ACTIVECAM) {
593 		pos.x = ACTIVECAM->pos.x - EEsin(radians(MAKEANGLE(ACTIVECAM->angle.b))) * 100.0F;
594 		pos.y = ACTIVECAM->pos.y - 100.0F;
595 		pos.z = ACTIVECAM->pos.z + EEcos(radians(MAKEANGLE(ACTIVECAM->angle.b))) * 100.0F;
596 	} else {
597 		pos = Vec3f::ZERO;
598 	}
599 }
600 
speechFileName(const res::path & name)601 static res::path speechFileName(const res::path & name) {
602 	return res::path("speech") / config.language / name;
603 }
604 
ARX_SOUND_PlaySpeech(const res::path & name,const Entity * io)605 long ARX_SOUND_PlaySpeech(const res::path & name, const Entity * io)
606 {
607 	if (!bIsActive) return INVALID_ID;
608 
609 	audio::Channel channel;
610 	SampleId sample_id;
611 
612 	res::path file = speechFileName(name);
613 	file.set_ext(ARX_SOUND_FILE_EXTENSION_WAV);
614 
615 	sample_id = audio::createSample(file);
616 
617 	channel.mixer = ARX_SOUND_MixerGameSpeech;
618 	channel.flags = FLAG_VOLUME | FLAG_POSITION | FLAG_REVERBERATION | FLAG_AUTOFREE | FLAG_FALLOFF;
619 	channel.volume = 1.f;
620 	channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART;
621 	channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND;
622 
623 	if (io)
624 	{
625 		if (((io == entities.player()) && !EXTERNALVIEW) ||
626 		        (io->ioflags & IO_CAMERA && io == CAMERACONTROLLER))
627 			ARX_SOUND_IOFrontPos(io, channel.position);
628 		else
629 		{
630 			channel.position = io->pos;
631 		}
632 
633 		if(ACTIVECAM && distSqr(ACTIVECAM->pos, io->pos) > square(ARX_SOUND_REFUSE_DISTANCE)) {
634 			return ARX_SOUND_TOO_FAR; // TODO sample is never freed!
635 		}
636 
637 		if (io->ioflags & IO_NPC && io->_npcdata->speakpitch != 1.f)
638 		{
639 			channel.flags |= FLAG_PITCH;
640 			channel.pitch = io->_npcdata->speakpitch;
641 		}
642 
643 	}
644 	else
645 	{
646 		channel.flags |= FLAG_RELATIVE;
647 		channel.position = Vec3f::Z_AXIS * 100.f;
648 	}
649 
650 	audio::samplePlay(sample_id, channel);
651 
652 	return sample_id;
653 }
654 
ARX_SOUND_PlayCollision(long mat1,long mat2,float volume,float power,Vec3f * position,Entity * source)655 long ARX_SOUND_PlayCollision(long mat1, long mat2, float volume, float power, Vec3f * position, Entity * source)
656 {
657 	if (!bIsActive) return 0;
658 
659 	if (mat1 == MATERIAL_NONE || mat2 == MATERIAL_NONE) return 0;
660 
661 	if (mat1 == MATERIAL_WATER || mat2 == MATERIAL_WATER)
662 		ARX_PARTICLES_SpawnWaterSplash(position);
663 
664 	SampleId sample_id;
665 
666 	sample_id = Inter_Materials[mat1][mat2][0];
667 
668 	if (sample_id == INVALID_ID) return 0;
669 
670 	audio::Channel channel;
671 	float presence;
672 
673 	channel.mixer = ARX_SOUND_MixerGameSample;
674 
675 	channel.flags = FLAG_VOLUME | FLAG_PITCH | FLAG_POSITION | FLAG_REVERBERATION | FLAG_FALLOFF;
676 
677 	res::path sample_name;
678 	audio::getSampleName(sample_id, sample_name);
679 	presence = GetSamplePresenceFactor(sample_name);
680 	channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
681 	channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
682 
683 	if (position)
684 	{
685 		if (ACTIVECAM && distSqr(ACTIVECAM->pos, *position) > square(ARX_SOUND_REFUSE_DISTANCE))
686 			return -1;
687 	}
688 
689 	//Launch 'ON HEAR' script event
690 	ARX_NPC_SpawnAudibleSound(position, source, power, presence);
691 
692 	if(position) {
693 		channel.position = *position;
694 	} else {
695 		ARX_PLAYER_FrontPos(&channel.position);
696 	}
697 
698 	channel.pitch = 0.9F + 0.2F * rnd();
699 	channel.volume = volume;
700 	audio::samplePlay(sample_id, channel);
701 
702 	size_t length;
703 	audio::getSampleLength(sample_id, length);
704 
705 	return (long)(channel.pitch * length);
706 }
707 
ARX_SOUND_PlayCollision(const string & name1,const string & name2,float volume,float power,Vec3f * position,Entity * source)708 long ARX_SOUND_PlayCollision(const string & name1, const string & name2, float volume, float power, Vec3f * position, Entity * source) {
709 
710 	if(!bIsActive) {
711 		return 0;
712 	}
713 
714 	if(name1.empty() || name2.empty()) {
715 		return 0;
716 	}
717 
718 	if(name2 == "water") {
719 		ARX_PARTICLES_SpawnWaterSplash(position);
720 	}
721 
722 	CollisionMaps::iterator mi = collisionMaps.find(name1);
723 	if(mi == collisionMaps.end()) {
724 		return 0;
725 	}
726 	CollisionMap & map = mi->second;
727 
728 	CollisionMap::iterator ci = map.find(name2);
729 	if(ci == map.end()) {
730 		return 0;
731 	}
732 	SoundMaterial & mat = ci->second;
733 
734 	SampleId sample_id = mat.next();
735 	arx_assert(sample_id != INVALID_ID);
736 
737 	audio::Channel channel;
738 	channel.mixer = ARX_SOUND_MixerGameSample;
739 	channel.flags = FLAG_VOLUME | FLAG_PITCH | FLAG_POSITION | FLAG_REVERBERATION | FLAG_FALLOFF;
740 
741 	res::path sample_name;
742 	audio::getSampleName(sample_id, sample_name);
743 	float presence = GetSamplePresenceFactor(sample_name);
744 	channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
745 	channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
746 
747 	// Launch 'ON HEAR' script event
748 	ARX_NPC_SpawnAudibleSound(position, source, power, presence);
749 
750 	if(position) {
751 		channel.position = *position;
752 		if(ACTIVECAM && fartherThan(ACTIVECAM->pos, *position, ARX_SOUND_REFUSE_DISTANCE)) {
753 			return -1;
754 		}
755 	} else {
756 		ARX_PLAYER_FrontPos(&channel.position);
757 	}
758 
759 	channel.pitch = 0.975f + 0.5f * rnd();
760 	channel.volume = volume;
761 	audio::samplePlay(sample_id, channel);
762 
763 	size_t length;
764 	audio::getSampleLength(sample_id, length);
765 
766 	return (long)(channel.pitch * length);
767 }
768 
ARX_SOUND_PlayScript(const res::path & name,const Entity * io,float pitch,SoundLoopMode loop)769 long ARX_SOUND_PlayScript(const res::path & name, const Entity * io, float pitch, SoundLoopMode loop)
770 {
771 	if (!bIsActive) {
772 		return INVALID_ID;
773 	}
774 
775 	audio::Channel channel;
776 	SampleId sample_id;
777 
778 	sample_id = audio::createSample(name);
779 
780 	if (sample_id == INVALID_ID) {
781 		return INVALID_ID;
782 	}
783 
784 	channel.mixer = ARX_SOUND_MixerGameSample;
785 	channel.flags = FLAG_VOLUME | FLAG_AUTOFREE | FLAG_POSITION | FLAG_REVERBERATION | FLAG_FALLOFF;
786 	channel.volume = 1.0F;
787 	channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * GetSamplePresenceFactor(name);
788 	channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND;
789 
790 	if(io) {
791 		GetItemWorldPositionSound(io, &channel.position);
792 		if(loop != ARX_SOUND_PLAY_LOOPED) {
793 			if (ACTIVECAM && distSqr(ACTIVECAM->pos, channel.position) > square(ARX_SOUND_REFUSE_DISTANCE)) {
794 				// TODO the sample will never be freed!
795 				return ARX_SOUND_TOO_FAR;
796 			}
797 		}
798 	} else {
799 		channel.flags |= FLAG_RELATIVE;
800 		channel.position = Vec3f::Z_AXIS * 100.f;
801 	}
802 
803 	if(pitch != 1.0F) {
804 		channel.flags |= FLAG_PITCH;
805 		channel.pitch = pitch;
806 	}
807 
808 	audio::samplePlay(sample_id, channel, loop);
809 
810 	return sample_id;
811 }
812 
ARX_SOUND_PlayAnim(SourceId & sample_id,const Vec3f * position)813 long ARX_SOUND_PlayAnim(SourceId & sample_id, const Vec3f * position)
814 {
815 	if (!bIsActive || sample_id == INVALID_ID) return INVALID_ID;
816 
817 	audio::Channel channel;
818 
819 	channel.mixer = ARX_SOUND_MixerGameSample;
820 	channel.flags = FLAG_VOLUME;
821 	channel.volume = 1.0F;
822 
823 	if(position) {
824 		if(ACTIVECAM && fartherThan(ACTIVECAM->pos, *position, ARX_SOUND_REFUSE_DISTANCE)) {
825 			return -1;
826 		}
827 		channel.flags |= FLAG_POSITION | FLAG_REVERBERATION | FLAG_FALLOFF;
828 		res::path sample_name;
829 		audio::getSampleName(sample_id, sample_name);
830 		float presence = GetSamplePresenceFactor(sample_name);
831 		channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART * presence;
832 		channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND * presence;
833 		channel.position = *position;
834 	}
835 
836 	audio::samplePlay(sample_id, channel);
837 
838 	return sample_id;
839 }
840 
ARX_SOUND_PlayCinematic(const res::path & name,bool isSpeech)841 long ARX_SOUND_PlayCinematic(const res::path & name, bool isSpeech) {
842 
843 	res::path file = (isSpeech) ? speechFileName(name) : name;
844 	file.set_ext(ARX_SOUND_FILE_EXTENSION_WAV);
845 
846 	s32 sample_id = audio::createSample(file);
847 	if(sample_id == INVALID_ID) {
848 		LogError << "Cannot load sound for cinematic: " << file;
849 		return INVALID_ID;
850 	}
851 
852 	audio::Channel channel;
853 	channel.mixer = ARX_SOUND_MixerGameSpeech;
854 	channel.flags = FLAG_VOLUME | FLAG_AUTOFREE | FLAG_POSITION | FLAG_FALLOFF
855 	                | FLAG_REVERBERATION | FLAG_POSITION;
856 	channel.volume = 1.0f;
857 	channel.falloff.start = ARX_SOUND_DEFAULT_FALLSTART;
858 	channel.falloff.end = ARX_SOUND_DEFAULT_FALLEND;
859 
860 	if (ACTIVECAM) {
861 		Vec3f front, up;
862 		float t;
863 		t = radians(MAKEANGLE(ACTIVECAM->angle.b));
864 		front.x = -EEsin(t);
865 		front.y = 0.f;
866 		front.z = EEcos(t);
867 		front.normalize();
868 		up.x = 0.f;
869 		up.y = 1.f;
870 		up.z = 0.f;
871 		ARX_SOUND_SetListener(&ACTIVECAM->pos, &front, &up);
872 	}
873 
874 	ARX_SOUND_IOFrontPos(NULL, channel.position);
875 
876 	audio::samplePlay(sample_id, channel);
877 
878 	return sample_id;
879 }
880 
ARX_SOUND_IsPlaying(SourceId & sample_id)881 long ARX_SOUND_IsPlaying(SourceId & sample_id) {
882 	return bIsActive ? audio::isSamplePlaying(sample_id) : 0;
883 }
884 
885 
ARX_SOUND_GetDuration(SampleId & sample_id)886 float ARX_SOUND_GetDuration(SampleId & sample_id) {
887 
888 	if(bIsActive && sample_id != INVALID_ID) {
889 		size_t length;
890 		audio::getSampleLength(sample_id, length);
891 		return static_cast<float>(length);
892 	}
893 
894 	return 0.f;
895 }
896 
ARX_SOUND_RefreshVolume(SourceId & sample_id,float volume)897 void ARX_SOUND_RefreshVolume(SourceId & sample_id, float volume) {
898 	if(bIsActive && sample_id != INVALID_ID) {
899 		audio::setSampleVolume(sample_id, volume);
900 	}
901 }
902 
ARX_SOUND_RefreshPitch(SourceId & sample_id,float pitch)903 void ARX_SOUND_RefreshPitch(SourceId & sample_id, float pitch) {
904 	if(bIsActive && sample_id != INVALID_ID) {
905 		audio::setSamplePitch(sample_id, pitch);
906 	}
907 }
908 
ARX_SOUND_RefreshPosition(SourceId & sample_id,const Vec3f * position)909 void ARX_SOUND_RefreshPosition(SourceId & sample_id, const Vec3f * position) {
910 
911 	if(bIsActive && sample_id != INVALID_ID) {
912 		if(position) {
913 			audio::setSamplePosition(sample_id, *position);
914 		} else {
915 			Vec3f pos;
916 			ARX_PLAYER_FrontPos(&pos);
917 			audio::setSamplePosition(sample_id, pos);
918 		}
919 	}
920 }
921 
ARX_SOUND_RefreshSpeechPosition(SourceId & sample_id,const Entity * io)922 void ARX_SOUND_RefreshSpeechPosition(SourceId & sample_id, const Entity * io) {
923 
924 	if(!bIsActive || !io || sample_id == INVALID_ID) {
925 		return;
926 	}
927 
928 	Vec3f position;
929 	if(io) {
930 		if((io == entities.player() && !EXTERNALVIEW)
931 		   || ((io->ioflags & IO_CAMERA) && io == CAMERACONTROLLER)) {
932 			ARX_SOUND_IOFrontPos(io, position);
933 		} else {
934 			position = io->pos;
935 		}
936 	}
937 
938 	audio::setSamplePosition(sample_id, position);
939 }
940 
ARX_SOUND_Load(const res::path & name)941 SampleId ARX_SOUND_Load(const res::path & name) {
942 
943 	if(!bIsActive) {
944 		return INVALID_ID;
945 	}
946 
947 	res::path sample_name = name;
948 
949 	return audio::createSample(sample_name.set_ext(ARX_SOUND_FILE_EXTENSION_WAV));
950 }
951 
ARX_SOUND_Free(const SampleId & sample)952 void ARX_SOUND_Free(const SampleId & sample) {
953 	if(bIsActive && sample != INVALID_ID) {
954 		audio::deleteSample(sample);
955 	}
956 }
957 
ARX_SOUND_Stop(SourceId & sample_id)958 void ARX_SOUND_Stop(SourceId & sample_id) {
959 	if(bIsActive && sample_id != INVALID_ID) {
960 		audio::sampleStop(sample_id);
961 	}
962 }
963 
ARX_SOUND_PlayScriptAmbiance(const res::path & name,SoundLoopMode loop,float volume)964 bool ARX_SOUND_PlayScriptAmbiance(const res::path & name, SoundLoopMode loop, float volume) {
965 
966 	if (!bIsActive) return INVALID_ID;
967 
968 	res::path temp = res::path(name).set_ext("amb");
969 
970 	AmbianceId ambiance_id = audio::getAmbiance(temp);
971 
972 	if (ambiance_id == INVALID_ID)
973 	{
974 		if (volume == 0.f) return true;
975 
976 		ambiance_id = audio::createAmbiance(temp);
977 		if(ambiance_id == INVALID_ID) {
978 			return false;
979 		}
980 
981 		audio::setAmbianceUserData(ambiance_id, reinterpret_cast<void *>(PLAYING_AMBIANCE_SCRIPT));
982 
983 		audio::Channel channel;
984 
985 		channel.mixer = ARX_SOUND_MixerGameAmbiance;
986 		channel.flags = FLAG_VOLUME | FLAG_AUTOFREE;
987 		channel.volume = volume;
988 
989 		audio::ambiancePlay(ambiance_id, channel, loop == ARX_SOUND_PLAY_LOOPED);
990 	}
991 	else
992 	{
993 		if (volume <= 0.0F)
994 		{
995 			audio::deleteAmbiance(ambiance_id);
996 			return true;
997 		}
998 
999 		audio::setAmbianceVolume(ambiance_id, volume);
1000 	}
1001 
1002 	return true;
1003 }
1004 
ARX_SOUND_PlayZoneAmbiance(const res::path & name,SoundLoopMode loop,float volume)1005 bool ARX_SOUND_PlayZoneAmbiance(const res::path & name, SoundLoopMode loop, float volume) {
1006 
1007 	if (!bIsActive) return true;
1008 
1009 	if(name == "none") {
1010 		audio::ambianceStop(ambiance_zone, AMBIANCE_FADE_TIME);
1011 		ambiance_zone = INVALID_ID;
1012 		return true;
1013 	}
1014 
1015 	res::path temp = res::path(name).set_ext("amb");
1016 
1017 	AmbianceId ambiance_id = audio::getAmbiance(temp);
1018 
1019 	if (ambiance_id == INVALID_ID)
1020 	{
1021 		ambiance_id = audio::createAmbiance(temp);
1022 		if(ambiance_id == INVALID_ID) {
1023 			return false;
1024 		}
1025 		audio::setAmbianceUserData(ambiance_id, reinterpret_cast<void *>(PLAYING_AMBIANCE_ZONE));
1026 	}
1027 	else if (ambiance_id == ambiance_zone)
1028 		return true;
1029 
1030 	audio::Channel channel;
1031 
1032 	channel.mixer = ARX_SOUND_MixerGameAmbiance;
1033 	channel.flags = FLAG_VOLUME | FLAG_AUTOFREE;
1034 	channel.volume = volume;
1035 
1036 	audio::ambianceStop(ambiance_zone, AMBIANCE_FADE_TIME);
1037 	ambiance_zone = ambiance_id;
1038 	audio::ambiancePlay(ambiance_zone, channel, loop == ARX_SOUND_PLAY_LOOPED, AMBIANCE_FADE_TIME);
1039 
1040 	return true;
1041 }
1042 
ARX_SOUND_SetAmbianceTrackStatus(const string & ambiance_name,const string & track_name,unsigned long status)1043 AmbianceId ARX_SOUND_SetAmbianceTrackStatus(const string & ambiance_name, const string & track_name, unsigned long status) {
1044 
1045 	if(!bIsActive) {
1046 		return INVALID_ID;
1047 	}
1048 
1049 	AmbianceId ambiance_id = audio::getAmbiance(res::path(ambiance_name).set_ext("amb"));
1050 	if(ambiance_id == INVALID_ID) {
1051 		return INVALID_ID;
1052 	}
1053 
1054 	audio::muteAmbianceTrack(ambiance_id, track_name, status != 0);
1055 
1056 	return ambiance_id;
1057 }
1058 
ARX_SOUND_KillAmbiances()1059 void ARX_SOUND_KillAmbiances() {
1060 
1061 	if(!bIsActive) {
1062 		return;
1063 	}
1064 
1065 	AmbianceId ambiance_id = audio::getNextAmbiance();
1066 
1067 	while(ambiance_id != INVALID_ID) {
1068 		audio::deleteAmbiance(ambiance_id);
1069 		ambiance_id = audio::getNextAmbiance(ambiance_id);
1070 	}
1071 
1072 	ambiance_zone = INVALID_ID;
1073 }
1074 
ARX_SOUND_PlayMenuAmbiance(const res::path & ambiance_name)1075 AmbianceId ARX_SOUND_PlayMenuAmbiance(const res::path & ambiance_name) {
1076 
1077 	if(!bIsActive) {
1078 		return INVALID_ID;
1079 	}
1080 
1081 	audio::deleteAmbiance(ambiance_menu);
1082 	ambiance_menu = audio::createAmbiance(ambiance_name);
1083 
1084 	audio::setAmbianceUserData(ambiance_menu, reinterpret_cast<void *>(PLAYING_AMBIANCE_MENU));
1085 
1086 	audio::Channel channel;
1087 
1088 	channel.mixer = ARX_SOUND_MixerMenuAmbiance;
1089 	channel.flags = FLAG_VOLUME;
1090 	channel.volume = 1.0F;
1091 
1092 	audio::ambiancePlay(ambiance_menu, channel, true);
1093 
1094 	return ambiance_menu;
1095 }
1096 
1097 static long nbelems = 0;
1098 static char ** elems = NULL;
1099 static long * numbers = NULL;
1100 
ARX_SOUND_FreeAnimSamples()1101 void ARX_SOUND_FreeAnimSamples() {
1102 
1103 	if(elems) {
1104 		for(long i = 0; i < nbelems; i++) {
1105 			free(elems[i]), elems[i] = NULL;
1106 		}
1107 		free(elems), elems = NULL;
1108 	}
1109 	nbelems = 0;
1110 
1111 	free(numbers), numbers = NULL;
1112 }
1113 
1114 extern ANIM_HANDLE animations[];
ARX_SOUND_PushAnimSamples()1115 void ARX_SOUND_PushAnimSamples()
1116 {
1117 	ARX_SOUND_FreeAnimSamples();
1118 
1119 	long number = 0;
1120 
1121 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
1122 
1123 		if (!animations[i].path.empty())
1124 		{
1125 			for (long j = 0; j < animations[i].alt_nb; j++)
1126 			{
1127 				EERIE_ANIM * anim = animations[i].anims[j];
1128 
1129 				for (long k = 0; k < anim->nb_key_frames; k++)
1130 				{
1131 					number++;
1132 
1133 					if (anim->frames[k].sample != -1)
1134 					{
1135 						res::path dest;
1136 						audio::getSampleName(anim->frames[k].sample, dest);
1137 						if(!dest.empty()) {
1138 							elems = (char **)realloc(elems, sizeof(char *) * (nbelems + 1));
1139 							elems[nbelems] = strdup(dest.string().c_str());
1140 							numbers = (long *)realloc(numbers, sizeof(long) * (nbelems + 1));
1141 							numbers[nbelems] = number;
1142 							nbelems++;
1143 						}
1144 					}
1145 				}
1146 			}
1147 		}
1148 	}
1149 }
1150 
ARX_SOUND_PopAnimSamples()1151 void ARX_SOUND_PopAnimSamples()
1152 {
1153 	if ((!elems) ||
1154 	        (!bIsActive))
1155 	{
1156 		return;
1157 	}
1158 
1159 	long curelem = 0;
1160 	long number = 0;
1161 
1162 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
1163 
1164 		if (!animations[i].path.empty())
1165 		{
1166 			for (long j = 0; j < animations[i].alt_nb; j++)
1167 			{
1168 				EERIE_ANIM * anim = animations[i].anims[j];
1169 
1170 				for (long k = 0; k < anim->nb_key_frames; k++)
1171 				{
1172 					number++;
1173 
1174 					if (number == numbers[curelem])
1175 					{
1176 						arx_assert(elems[curelem] != NULL);
1177 						anim->frames[k].sample = audio::createSample(elems[curelem++]);
1178 					}
1179 				}
1180 			}
1181 		}
1182 	}
1183 
1184 
1185 	ARX_SOUND_FreeAnimSamples();
1186 }
1187 
ARX_SOUND_AmbianceSavePlayList(size_t & size)1188 char * ARX_SOUND_AmbianceSavePlayList(size_t & size) {
1189 
1190 	unsigned long count(0);
1191 	PlayingAmbiance * play_list = NULL;
1192 	long ambiance_id(INVALID_ID);
1193 
1194 	ambiance_id = audio::getNextAmbiance();
1195 
1196 	while (ambiance_id != INVALID_ID)
1197 	{
1198 		void * storedType;
1199 		audio::getAmbianceUserData(ambiance_id, &storedType);
1200 		long type = reinterpret_cast<long>(storedType);
1201 
1202 		if (type == PLAYING_AMBIANCE_SCRIPT || type == PLAYING_AMBIANCE_ZONE)
1203 		{
1204 			void * ptr;
1205 			PlayingAmbiance * playing;
1206 
1207 			ptr = realloc(play_list, (count + 1) * sizeof(PlayingAmbiance));
1208 
1209 			if (!ptr) break;
1210 
1211 			play_list = (PlayingAmbiance *)ptr;
1212 			playing = &play_list[count];
1213 
1214 			memset(playing->name, 0, sizeof(playing->name));
1215 
1216 			res::path name;
1217 			audio::getAmbianceName(ambiance_id, name);
1218 			arx_assert(name.string().length() + 1 < ARRAY_SIZE(playing->name));
1219 			strcpy(playing->name, name.string().c_str());
1220 			audio::getAmbianceVolume(ambiance_id, playing->volume);
1221 			playing->loop = audio::isAmbianceLooped(ambiance_id) ? ARX_SOUND_PLAY_LOOPED : ARX_SOUND_PLAY_ONCE;
1222 			playing->type = type;
1223 
1224 			count++;
1225 		}
1226 
1227 		ambiance_id = audio::getNextAmbiance(ambiance_id);
1228 	}
1229 
1230 	size = count * sizeof(PlayingAmbiance);
1231 	return reinterpret_cast<char *>(play_list);
1232 }
1233 
ARX_SOUND_AmbianceRestorePlayList(const char * _play_list,size_t size)1234 void ARX_SOUND_AmbianceRestorePlayList(const char * _play_list, size_t size) {
1235 
1236 	size_t count = size / sizeof(PlayingAmbiance);
1237 	const PlayingAmbiance * play_list = reinterpret_cast<const PlayingAmbiance *>(_play_list);
1238 
1239 	for(size_t i = 0; i < count; i++) {
1240 
1241 		const PlayingAmbiance * playing = &play_list[i];
1242 
1243 		res::path name = res::path::load(util::loadString(playing->name));
1244 
1245 		// TODO save/load enum
1246 		switch (playing->type) {
1247 
1248 			case PLAYING_AMBIANCE_SCRIPT :
1249 				ARX_SOUND_PlayScriptAmbiance(name, (SoundLoopMode)playing->loop, playing->volume);
1250 				break;
1251 
1252 			case PLAYING_AMBIANCE_ZONE :
1253 				ARX_SOUND_PlayZoneAmbiance(name, (SoundLoopMode)playing->loop, playing->volume);
1254 				break;
1255 		}
1256 	}
1257 }
1258 
ARX_SOUND_CreateEnvironments()1259 static void ARX_SOUND_CreateEnvironments() {
1260 
1261 	PakDirectory * dir = resources->getDirectory(ARX_SOUND_PATH_ENVIRONMENT);
1262 	if(!dir) {
1263 		return;
1264 	}
1265 
1266 	for(PakDirectory::files_iterator i = dir->files_begin(); i != dir->files_end(); i++) {
1267 		audio::createEnvironment(i->first);
1268 	}
1269 }
1270 
ARX_SOUND_CreateStaticSamples()1271 static void ARX_SOUND_CreateStaticSamples() {
1272 
1273 	// Interface
1274 	SND_BACKPACK                       = audio::createSample("interface_backpack.wav");
1275 	SND_BOOK_OPEN                      = audio::createSample("book_open.wav");
1276 	SND_BOOK_CLOSE                     = audio::createSample("book_close.wav");
1277 	SND_BOOK_PAGE_TURN                 = audio::createSample("book_page_turn.wav");
1278 	SND_SCROLL_OPEN                    = audio::createSample("scroll_open.wav");
1279 	SND_SCROLL_CLOSE                   = audio::createSample("scroll_close.wav");
1280 	SND_TORCH_START                    = audio::createSample("torch_start.wav");
1281 	SND_TORCH_LOOP                     = audio::createSample("sfx_torch_11khz.wav");
1282 	SND_TORCH_END                      = audio::createSample("torch_end.wav");
1283 	SND_INVSTD                         = audio::createSample("interface_invstd.wav");
1284 	SND_GOLD                           = audio::createSample("drop_coin.wav");
1285 
1286 	//Menu
1287 	SND_MENU_CLICK                     = audio::createSample("menu_click.wav");
1288 	SND_MENU_RELEASE                   = audio::createSample("menu_release.wav");
1289 
1290 	//Other SFX samples
1291 	SND_FIREPLACE                      = audio::createSample("fire_place.wav");
1292 	SND_PLOUF                          = audio::createSample("fishing_plouf.wav");
1293 	SND_QUAKE                          = audio::createSample("sfx_quake.wav");
1294 	SND_WHOOSH                         = audio::createSample("whoosh07.wav");
1295 
1296 	// Player
1297 	SND_PLAYER_FILLLIFEMANA            = audio::createSample("player_filllifemana.wav");
1298 	SND_PLAYER_HEART_BEAT              = audio::createSample("player_heartb.wav");
1299 	SND_PLAYER_LEVEL_UP                = audio::createSample("player_level_up.wav");
1300 	SND_PLAYER_POISONED                = audio::createSample("player_poisoned.wav");
1301 	SND_PLAYER_DEATH_BY_FIRE           = audio::createSample("lava_death.wav");
1302 
1303 	// Magic draw
1304 	SND_MAGIC_AMBIENT                  = audio::createSample("magic_ambient.wav");
1305 	SND_MAGIC_DRAW                     = audio::createSample("magic_draw.wav");
1306 	SND_MAGIC_FIZZLE                   = audio::createSample("magic_fizzle.wav");
1307 
1308 	// Magic symbols
1309 	SND_SYMB_AAM                       = audio::createSample("magic_aam.wav");
1310 	SND_SYMB_CETRIUS                   = audio::createSample("magic_citrius.wav");
1311 	SND_SYMB_COSUM                     = audio::createSample("magic_cosum.wav");
1312 	SND_SYMB_COMUNICATUM               = audio::createSample("magic_comunicatum.wav");
1313 	SND_SYMB_FOLGORA                   = audio::createSample("magic_folgora.wav");
1314 	SND_SYMB_FRIDD                     = audio::createSample("magic_fridd.wav");
1315 	SND_SYMB_KAOM                      = audio::createSample("magic_kaom.wav");
1316 	SND_SYMB_MEGA                      = audio::createSample("magic_mega.wav");
1317 	SND_SYMB_MORTE                     = audio::createSample("magic_morte.wav");
1318 	SND_SYMB_MOVIS                     = audio::createSample("magic_movis.wav");
1319 	SND_SYMB_NHI                       = audio::createSample("magic_nhi.wav");
1320 	SND_SYMB_RHAA                      = audio::createSample("magic_rhaa.wav");
1321 	SND_SYMB_SPACIUM                   = audio::createSample("magic_spacium.wav");
1322 	SND_SYMB_STREGUM                   = audio::createSample("magic_stregum.wav");
1323 	SND_SYMB_TAAR                      = audio::createSample("magic_taar.wav");
1324 	SND_SYMB_TEMPUS                    = audio::createSample("magic_tempus.wav");
1325 	SND_SYMB_TERA                      = audio::createSample("magic_tera.wav");
1326 	SND_SYMB_VISTA                     = audio::createSample("magic_vista.wav");
1327 	SND_SYMB_VITAE                     = audio::createSample("magic_vitae.wav");
1328 	SND_SYMB_YOK                       = audio::createSample("magic_yok.wav");
1329 
1330 	// Spells
1331 	SND_SPELL_ACTIVATE_PORTAL          = audio::createSample("magic_spell_activate_portal.wav");
1332 	SND_SPELL_ARMOR_START              = audio::createSample("magic_spell_armor_start.wav");
1333 	SND_SPELL_ARMOR_END                = audio::createSample("magic_spell_armor_end.wav");
1334 	SND_SPELL_ARMOR_LOOP               = audio::createSample("magic_spell_armor_loop.wav");
1335 	SND_SPELL_LOWER_ARMOR              = audio::createSample("magic_spell_decrease_armor.wav");
1336 	SND_SPELL_BLESS                    = audio::createSample("magic_spell_bless.wav");
1337 	SND_SPELL_COLD_PROTECTION_START    = audio::createSample("magic_spell_cold_protection.wav");
1338 	SND_SPELL_COLD_PROTECTION_LOOP     = audio::createSample("magic_spell_cold_protection_loop.wav");
1339 	SND_SPELL_COLD_PROTECTION_END      = audio::createSample("magic_spell_cold_protection_end.wav");
1340 	SND_SPELL_CONFUSE                  = audio::createSample("magic_spell_confuse.wav");
1341 	SND_SPELL_CONTROL_TARGET           = audio::createSample("magic_spell_control_target.wav");
1342 	SND_SPELL_CREATE_FIELD             = audio::createSample("magic_spell_create_field.wav");
1343 	SND_SPELL_CREATE_FOOD              = audio::createSample("magic_spell_create_food.wav");
1344 	SND_SPELL_CURE_POISON              = audio::createSample("magic_spell_cure_poison.wav");
1345 	SND_SPELL_CURSE                    = audio::createSample("magic_spell_curse.wav");
1346 	SND_SPELL_DETECT_TRAP              = audio::createSample("magic_spell_detect_trap.wav");
1347 	SND_SPELL_DETECT_TRAP_LOOP         = audio::createSample("magic_spell_detect_trap_loop.wav");
1348 	SND_SPELL_DISARM_TRAP              = audio::createSample("magic_spell_disarm_trap.wav");
1349 	SND_SPELL_DISPELL_FIELD            = audio::createSample("magic_spell_dispell_field.wav");
1350 	SND_SPELL_DISPELL_ILLUSION         = audio::createSample("magic_spell_dispell_illusion.wav");
1351 	SND_SPELL_DOUSE                    = audio::createSample("magic_spell_douse.wav");
1352 	SND_SPELL_ELECTRIC                 = audio::createSample("sfx_electric.wav");
1353 	SND_SPELL_ENCHANT_WEAPON           = audio::createSample("magic_spell_enchant_weapon.wav");
1354 	SND_SPELL_EXPLOSION                = audio::createSample("magic_spell_explosion.wav");
1355 	SND_SPELL_EYEBALL_IN               = audio::createSample("magic_spell_eyeball_in.wav");
1356 	SND_SPELL_EYEBALL_OUT              = audio::createSample("magic_spell_eyeball_out.wav");
1357 	SND_SPELL_FIRE_HIT                 = audio::createSample("magic_spell_firehit.wav");
1358 	SND_SPELL_FIRE_LAUNCH              = audio::createSample("magic_spell_firelaunch.wav");
1359 	SND_SPELL_FIRE_PROTECTION          = audio::createSample("magic_spell_fire_protection.wav");
1360 	SND_SPELL_FIRE_PROTECTION_LOOP     = audio::createSample("magic_spell_fire_protection_loop.wav");
1361 	SND_SPELL_FIRE_PROTECTION_END      = audio::createSample("magic_spell_fire_protection_end.wav");
1362 	SND_SPELL_FIRE_WIND                = audio::createSample("magic_spell_firewind.wav");
1363 	SND_SPELL_FREEZETIME               = audio::createSample("magic_spell_freezetime.wav");
1364 	SND_SPELL_HARM                     = audio::createSample("magic_spell_harm.wav");
1365 	SND_SPELL_HEALING                  = audio::createSample("magic_spell_healing.wav");
1366 	SND_SPELL_ICE_FIELD                = audio::createSample("magic_spell_ice_field.wav");
1367 	SND_SPELL_ICE_FIELD_LOOP           = audio::createSample("magic_spell_ice_fieldloop.wav");
1368 	SND_SPELL_ICE_FIELD_END            = audio::createSample("magic_spell_ice_field_end.wav");
1369 	SND_SPELL_ICE_PROJECTILE_LAUNCH    = audio::createSample("magic_spell_ice_projectile_launch.wav");
1370 	SND_SPELL_INCINERATE               = audio::createSample("magic_spell_incinerate.wav");
1371 	SND_SPELL_INCINERATE_LOOP          = audio::createSample("magic_spell_incinerate_loop.wav");
1372 	SND_SPELL_INCINERATE_END           = audio::createSample("magic_spell_incinerate_end.wav");
1373 	SND_SPELL_IGNITE                   = audio::createSample("magic_spell_ignite.wav");
1374 	SND_SPELL_INVISIBILITY_START       = audio::createSample("magic_spell_invisibilityon.wav");
1375 	SND_SPELL_INVISIBILITY_END         = audio::createSample("magic_spell_invisibilityoff.wav");
1376 	SND_SPELL_LEVITATE_START           = audio::createSample("magic_spell_levitate_start.wav");
1377 	SND_SPELL_LIGHTNING_START          = audio::createSample("magic_spell_lightning_start.wav");
1378 	SND_SPELL_LIGHTNING_LOOP           = audio::createSample("magic_spell_lightning_loop.wav");
1379 	SND_SPELL_LIGHTNING_END            = audio::createSample("magic_spell_lightning_end.wav");
1380 	SND_SPELL_MAGICAL_HIT              = audio::createSample("magic_spell_magicalhit.wav");
1381 
1382 	SND_SPELL_FIRE_FIELD_START         = audio::createSample("magic_spell_fire_field.wav");
1383 	SND_SPELL_FIRE_FIELD_LOOP          = audio::createSample("magic_spell_fire_field_loop.wav");
1384 	SND_SPELL_FIRE_FIELD_END           = audio::createSample("magic_spell_fire_field_end.wav");
1385 
1386 	SND_SPELL_MAGICAL_SHIELD           = audio::createSample("magic_spell_magicalshield.wav");
1387 	SND_SPELL_MASS_INCINERATE          = audio::createSample("magic_spell_mass_incinerate.wav");
1388 	SND_SPELL_MASS_PARALYSE            = audio::createSample("magic_spell_mass_paralyse.wav");
1389 	SND_SPELL_MM_CREATE                = audio::createSample("magic_spell_missilecreate.wav");
1390 	SND_SPELL_MM_HIT                   = audio::createSample("magic_spell_missilehit.wav");
1391 	SND_SPELL_MM_LAUNCH                = audio::createSample("magic_spell_missilelaunch.wav");
1392 	SND_SPELL_MM_LOOP                  = audio::createSample("magic_spell_missileloop.wav");
1393 	SND_SPELL_NEGATE_MAGIC             = audio::createSample("magic_spell_negate_magic.wav");
1394 	SND_SPELL_NO_EFFECT                = audio::createSample("magic_spell_noeffect.wav");
1395 	SND_SPELL_PARALYSE                 = audio::createSample("magic_spell_paralyse.wav");
1396 	SND_SPELL_PARALYSE_END             = audio::createSample("magic_spell_paralyse_end.wav");
1397 	SND_SPELL_POISON_PROJECTILE_LAUNCH = audio::createSample("magic_spell_poison_projectile_launch.wav");
1398 	SND_SPELL_RAISE_DEAD               = audio::createSample("magic_spell_raise_dead.wav");
1399 	SND_SPELL_REPEL_UNDEAD             = audio::createSample("magic_spell_repel_undead.wav");
1400 	SND_SPELL_REPEL_UNDEAD_LOOP        = audio::createSample("magic_spell_repell_loop.wav");
1401 	SND_SPELL_RUNE_OF_GUARDING         = audio::createSample("magic_spell_rune_of_guarding.wav");
1402 	SND_SPELL_RUNE_OF_GUARDING_END     = audio::createSample("magic_spell_rune_of_guarding_explode.wav");
1403 	SND_SPELL_SLOW_DOWN                = audio::createSample("magic_spell_slow_down.wav");
1404 	SND_SPELL_SPARK                    = audio::createSample("sfx_spark.wav");
1405 	SND_SPELL_SPEED_START              = audio::createSample("magic_spell_speedstart.wav");
1406 	SND_SPELL_SPEED_LOOP               = audio::createSample("magic_spell_speed.wav");
1407 	SND_SPELL_SPEED_END                = audio::createSample("magic_spell_speedend.wav");
1408 	SND_SPELL_SUMMON_CREATURE          = audio::createSample("magic_spell_summon_creature.wav");
1409 	SND_SPELL_TELEKINESIS_START        = audio::createSample("magic_spell_telekinesison.wav");
1410 	SND_SPELL_TELEKINESIS_END          = audio::createSample("magic_spell_telekinesisoff.wav");
1411 	SND_SPELL_TELEPORT                 = audio::createSample("magic_spell_teleport.wav");
1412 	SND_SPELL_TELEPORTED               = audio::createSample("magic_spell_teleported.wav");
1413 	SND_SPELL_VISION_START             = audio::createSample("magic_spell_vision2.wav");
1414 	SND_SPELL_VISION_LOOP              = audio::createSample("magic_spell_vision.wav");
1415 }
1416 
1417 // Reset each static sample to INVALID_ID
1418 // Those samples are freed from memory when by audio::clean() is deleted
ARX_SOUND_ReleaseStaticSamples()1419 static void ARX_SOUND_ReleaseStaticSamples() {
1420 
1421 	// Interface samples
1422 	SND_BACKPACK = INVALID_ID;
1423 	SND_BOOK_OPEN = INVALID_ID;
1424 	SND_BOOK_CLOSE = INVALID_ID;
1425 	SND_BOOK_PAGE_TURN = INVALID_ID;
1426 	SND_GOLD = INVALID_ID;
1427 	SND_INVSTD = INVALID_ID;
1428 	SND_SCROLL_OPEN = INVALID_ID;
1429 	SND_SCROLL_CLOSE = INVALID_ID;
1430 	SND_TORCH_START = INVALID_ID;
1431 	SND_TORCH_LOOP = INVALID_ID;
1432 	SND_TORCH_END = INVALID_ID;
1433 
1434 	// Other SFX samples
1435 	SND_FIREPLACE = INVALID_ID;
1436 	SND_PLOUF = INVALID_ID;
1437 	SND_QUAKE = INVALID_ID;
1438 
1439 	// Menu samples
1440 	SND_MENU_CLICK = INVALID_ID;
1441 	SND_MENU_RELEASE = INVALID_ID;
1442 
1443 	// Player samples
1444 	SND_PLAYER_DEATH_BY_FIRE = INVALID_ID;
1445 	SND_PLAYER_FILLLIFEMANA = INVALID_ID;
1446 	SND_PLAYER_HEART_BEAT = INVALID_ID;
1447 	SND_PLAYER_LEVEL_UP = INVALID_ID;
1448 	SND_PLAYER_POISONED = INVALID_ID;
1449 
1450 	// Magic drawing samples
1451 	SND_MAGIC_AMBIENT = INVALID_ID;
1452 	SND_MAGIC_DRAW = INVALID_ID;
1453 	SND_MAGIC_FIZZLE = INVALID_ID;
1454 
1455 	// Magic symbols samples
1456 	SND_SYMB_AAM = INVALID_ID;
1457 	SND_SYMB_CETRIUS = INVALID_ID;
1458 	SND_SYMB_COSUM = INVALID_ID;
1459 	SND_SYMB_COMUNICATUM = INVALID_ID;
1460 	SND_SYMB_FOLGORA = INVALID_ID;
1461 	SND_SYMB_FRIDD = INVALID_ID;
1462 	SND_SYMB_KAOM = INVALID_ID;
1463 	SND_SYMB_MEGA = INVALID_ID;
1464 	SND_SYMB_MORTE = INVALID_ID;
1465 	SND_SYMB_MOVIS = INVALID_ID;
1466 	SND_SYMB_NHI = INVALID_ID;
1467 	SND_SYMB_RHAA = INVALID_ID;
1468 	SND_SYMB_SPACIUM = INVALID_ID;
1469 	SND_SYMB_STREGUM = INVALID_ID;
1470 	SND_SYMB_TAAR = INVALID_ID;
1471 	SND_SYMB_TEMPUS = INVALID_ID;
1472 	SND_SYMB_TERA = INVALID_ID;
1473 	SND_SYMB_VISTA = INVALID_ID;
1474 	SND_SYMB_VITAE = INVALID_ID;
1475 	SND_SYMB_YOK = INVALID_ID;
1476 
1477 	// Spells samples
1478 	SND_SPELL_ACTIVATE_PORTAL = INVALID_ID;
1479 	SND_SPELL_ARMOR_START	= INVALID_ID;
1480 	SND_SPELL_ARMOR_END		= INVALID_ID;
1481 	SND_SPELL_ARMOR_LOOP	= INVALID_ID;
1482 	SND_SPELL_LOWER_ARMOR = INVALID_ID;
1483 	SND_SPELL_BLESS = INVALID_ID;
1484 	SND_SPELL_COLD_PROTECTION_START = INVALID_ID;
1485 	SND_SPELL_COLD_PROTECTION_LOOP = INVALID_ID;
1486 	SND_SPELL_COLD_PROTECTION_END = INVALID_ID;
1487 	SND_SPELL_CONFUSE = INVALID_ID;
1488 	SND_SPELL_CONTROL_TARGET = INVALID_ID;
1489 	SND_SPELL_CREATE_FIELD = INVALID_ID;
1490 	SND_SPELL_CREATE_FOOD = INVALID_ID;
1491 	SND_SPELL_CURE_POISON = INVALID_ID;
1492 	SND_SPELL_CURSE = INVALID_ID;
1493 	SND_SPELL_DETECT_TRAP = INVALID_ID;
1494 	SND_SPELL_DETECT_TRAP_LOOP = INVALID_ID;
1495 	SND_SPELL_DISARM_TRAP = INVALID_ID;
1496 	SND_SPELL_DISPELL_FIELD = INVALID_ID;
1497 	SND_SPELL_DISPELL_ILLUSION = INVALID_ID;
1498 	SND_SPELL_DOUSE = INVALID_ID;
1499 	SND_SPELL_ELECTRIC = INVALID_ID;
1500 	SND_SPELL_ENCHANT_WEAPON = INVALID_ID;
1501 	SND_SPELL_EXPLOSION = INVALID_ID;
1502 	SND_SPELL_EYEBALL_IN = INVALID_ID;
1503 	SND_SPELL_EYEBALL_OUT = INVALID_ID;
1504 	SND_SPELL_FIRE_FIELD = INVALID_ID;
1505 	SND_SPELL_FIRE_HIT = INVALID_ID;
1506 	SND_SPELL_FIRE_LAUNCH = INVALID_ID;
1507 	SND_SPELL_FIRE_PROTECTION = INVALID_ID;
1508 	SND_SPELL_FIRE_PROTECTION_LOOP = INVALID_ID;
1509 	SND_SPELL_FIRE_PROTECTION_END = INVALID_ID;
1510 	SND_SPELL_FIRE_WIND = INVALID_ID;
1511 	SND_SPELL_FREEZETIME = INVALID_ID;
1512 	SND_SPELL_HARM = INVALID_ID;
1513 	SND_SPELL_HEALING = INVALID_ID;
1514 	SND_SPELL_ICE_FIELD = INVALID_ID;
1515 	SND_SPELL_ICE_FIELD_LOOP = INVALID_ID;
1516 	SND_SPELL_ICE_FIELD_END = INVALID_ID;
1517 	SND_SPELL_ICE_PROJECTILE_LAUNCH = INVALID_ID;
1518 	SND_SPELL_INCINERATE = INVALID_ID;
1519 	SND_SPELL_INCINERATE_LOOP = INVALID_ID;
1520 	SND_SPELL_INCINERATE_END = INVALID_ID;
1521 	SND_SPELL_IGNITE = INVALID_ID;
1522 	SND_SPELL_INVISIBILITY_START = INVALID_ID;
1523 	SND_SPELL_INVISIBILITY_END = INVALID_ID;
1524 	SND_SPELL_LEVITATE_START = INVALID_ID;
1525 	SND_SPELL_LIGHTNING_START = INVALID_ID;
1526 	SND_SPELL_LIGHTNING_LOOP = INVALID_ID;
1527 	SND_SPELL_LIGHTNING_END = INVALID_ID;
1528 	SND_SPELL_MAGICAL_HIT = INVALID_ID;
1529 
1530 	//SND_SPELL_MASS_LIGHTNING_END = INVALID_ID;
1531 	SND_SPELL_FIRE_FIELD_START = INVALID_ID;
1532 	SND_SPELL_FIRE_FIELD_LOOP = INVALID_ID;
1533 	SND_SPELL_FIRE_FIELD_END = INVALID_ID;
1534 
1535 	SND_SPELL_MAGICAL_SHIELD = INVALID_ID;
1536 	SND_SPELL_MASS_INCINERATE = INVALID_ID;
1537 	SND_SPELL_MASS_PARALYSE = INVALID_ID;
1538 	SND_SPELL_MM_CREATE = INVALID_ID;
1539 	SND_SPELL_MM_HIT = INVALID_ID;
1540 	SND_SPELL_MM_LAUNCH = INVALID_ID;
1541 	SND_SPELL_MM_LOOP = INVALID_ID;
1542 	SND_SPELL_NEGATE_MAGIC = INVALID_ID;
1543 	SND_SPELL_PARALYSE = INVALID_ID;
1544 	SND_SPELL_PARALYSE_END = INVALID_ID;
1545 	SND_SPELL_POISON_PROJECTILE_LAUNCH = INVALID_ID;
1546 	SND_SPELL_RAISE_DEAD = INVALID_ID;
1547 	SND_SPELL_REPEL_UNDEAD = INVALID_ID;
1548 	SND_SPELL_REPEL_UNDEAD_LOOP = INVALID_ID;
1549 	SND_SPELL_RUNE_OF_GUARDING = INVALID_ID;
1550 	SND_SPELL_RUNE_OF_GUARDING_END = INVALID_ID;
1551 	SND_SPELL_SLOW_DOWN = INVALID_ID;
1552 	SND_SPELL_SPARK = INVALID_ID;
1553 	SND_SPELL_SPEED_START = INVALID_ID;
1554 	SND_SPELL_SPEED_LOOP = INVALID_ID;
1555 	SND_SPELL_SPEED_END = INVALID_ID;
1556 	SND_SPELL_SUMMON_CREATURE = INVALID_ID;
1557 	SND_SPELL_TELEKINESIS_START = INVALID_ID;
1558 	SND_SPELL_TELEKINESIS_END = INVALID_ID;
1559 	SND_SPELL_TELEPORT = INVALID_ID;
1560 	SND_SPELL_TELEPORTED = INVALID_ID;
1561 	SND_SPELL_VISION_START = INVALID_ID;
1562 	SND_SPELL_VISION_LOOP = INVALID_ID;
1563 }
1564 
ARX_MATERIAL_GetNameById(long id,char * name)1565 bool ARX_MATERIAL_GetNameById(long id, char * name)
1566 {
1567 	switch (id)
1568 	{
1569 		case MATERIAL_WEAPON:
1570 			strcpy(name, "weapon");
1571 			return true;
1572 			break;
1573 		case MATERIAL_FLESH:
1574 			strcpy(name, "flesh");
1575 			return true;
1576 			break;
1577 		case MATERIAL_METAL:
1578 			strcpy(name, "metal");
1579 			return true;
1580 			break;
1581 		case MATERIAL_GLASS:
1582 			strcpy(name, "glass");
1583 			return true;
1584 			break;
1585 		case MATERIAL_CLOTH:
1586 			strcpy(name, "cloth");
1587 			return true;
1588 			break;
1589 		case MATERIAL_WOOD:
1590 			strcpy(name, "wood");
1591 			return true;
1592 			break;
1593 		case MATERIAL_EARTH:
1594 			strcpy(name, "earth");
1595 			return true;
1596 			break;
1597 		case MATERIAL_WATER:
1598 			strcpy(name, "water");
1599 			return true;
1600 			break;
1601 		case MATERIAL_ICE:
1602 			strcpy(name, "ice");
1603 			return true;
1604 			break;
1605 		case MATERIAL_GRAVEL:
1606 			strcpy(name, "gravel");
1607 			return true;
1608 			break;
1609 		case MATERIAL_STONE:
1610 			strcpy(name, "stone");
1611 			return true;
1612 			break;
1613 		case MATERIAL_FOOT_LARGE:
1614 			strcpy(name, "foot_large");
1615 			return true;
1616 			break;
1617 		case MATERIAL_FOOT_BARE:
1618 			strcpy(name, "foot_bare");
1619 			return true;
1620 			break;
1621 		case MATERIAL_FOOT_SHOE:
1622 			strcpy(name, "foot_shoe");
1623 			return true;
1624 			break;
1625 		case MATERIAL_FOOT_METAL:
1626 			strcpy(name, "foot_metal");
1627 			return true;
1628 			break;
1629 		case MATERIAL_FOOT_STEALTH:
1630 			strcpy(name, "foot_stealth");
1631 			return true;
1632 			break;
1633 	}
1634 
1635 	strcpy(name, "none");
1636 	return false;
1637 }
ARX_SOUND_LoadCollision(const long & mat1,const long & mat2,const char * name)1638 static void ARX_SOUND_LoadCollision(const long & mat1, const long & mat2, const char * name)
1639 {
1640 	char path[256];
1641 
1642 	for (size_t i = 0; i < MAX_VARIANTS; i++)
1643 	{
1644 		sprintf(path, "%s_%lu.wav", name, (unsigned long)(i + 1));
1645 		Inter_Materials[mat1][mat2][i] = audio::createSample(path);
1646 
1647 		if (mat1 != mat2)
1648 			Inter_Materials[mat2][mat1][i] = Inter_Materials[mat1][mat2][i];
1649 	}
1650 }
1651 
ARX_SOUND_CreateCollisionMaps()1652 static void ARX_SOUND_CreateCollisionMaps() {
1653 
1654 	collisionMaps.clear();
1655 
1656 	for(size_t i = 0; i < ARX_SOUND_COLLISION_MAP_COUNT; i++) {
1657 
1658 		res::path file = ARX_SOUND_PATH_INI / ARX_SOUND_COLLISION_MAP_NAMES[i];
1659 		file.set_ext(ARX_SOUND_FILE_EXTENSION_INI);
1660 
1661 		size_t fileSize;
1662 		char * data = resources->readAlloc(file, fileSize);
1663 		if(!data) {
1664 			LogWarning << "Could not find collision map " << file;
1665 			return;
1666 		}
1667 
1668 		istringstream iss(string(data, fileSize));
1669 		free(data);
1670 
1671 		IniReader reader;
1672 		if(!reader.read(iss)) {
1673 			LogWarning << "Errors while parsing collision map " << file;
1674 		}
1675 
1676 		for(IniReader::iterator si = reader.begin(); si != reader.end(); ++si) {
1677 			const IniSection & section = si->second;
1678 			CollisionMap & map = collisionMaps[si->first];
1679 
1680 			for(IniSection::iterator ki = section.begin(); ki != section.end(); ++ki) {
1681 				const IniKey & key = *ki;
1682 				SoundMaterial & mat = map[key.getName()];
1683 
1684 				for(size_t mi = 0; mi < MAX_VARIANTS; mi++) {
1685 
1686 					ostringstream oss;
1687 					oss << boost::to_lower_copy(key.getValue());
1688 					if(mi) {
1689 						oss << mi;
1690 					}
1691 					oss << ARX_SOUND_FILE_EXTENSION_WAV;
1692 					SampleId sample = audio::createSample(oss.str());
1693 
1694 					if(sample == INVALID_ID) {
1695 						ostringstream oss2;
1696 						oss2 << boost::to_lower_copy(key.getValue()) << '_' << mi << ARX_SOUND_FILE_EXTENSION_WAV;
1697 						sample = audio::createSample(oss2.str());
1698 					}
1699 
1700 					if(sample != INVALID_ID) {
1701 						mat.variants.push_back(sample);
1702 					}
1703 				}
1704 
1705 				if(mat.variants.empty()) {
1706 					map.erase(key.getName());
1707 				}
1708 
1709 			}
1710 
1711 			if(map.empty()) {
1712 				collisionMaps.erase(si->first);
1713 			}
1714 
1715 		}
1716 
1717 	}
1718 
1719 }
1720 
ARX_SOUND_CreateMaterials()1721 static void ARX_SOUND_CreateMaterials()
1722 {
1723 	memset(Inter_Materials, -1, sizeof(long) * MAX_MATERIALS * MAX_MATERIALS * MAX_VARIANTS);
1724 
1725 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_WEAPON,       "weapon_on_weapon");
1726 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_FLESH,        "weapon_on_flesh");
1727 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_METAL,        "weapon_on_metal");
1728 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_GLASS,        "weapon_on_glass");
1729 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_CLOTH,        "weapon_on_cloth");
1730 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_WOOD,         "weapon_on_wood");
1731 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_EARTH,        "weapon_on_earth");
1732 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_WATER,        "weapon_on_water");
1733 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_ICE,          "weapon_on_ice");
1734 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_GRAVEL,       "weapon_on_gravel");
1735 	ARX_SOUND_LoadCollision(MATERIAL_WEAPON, MATERIAL_STONE,        "weapon_on_stone");
1736 
1737 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_FLESH,        "flesh_on_flesh");
1738 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_METAL,        "flesh_on_metal");
1739 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_GLASS,        "flesh_on_glass");
1740 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_CLOTH,        "flesh_on_cloth");
1741 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_WOOD,         "flesh_on_wood");
1742 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_EARTH,        "flesh_on_earth");
1743 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_WATER,        "flesh_on_water");
1744 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_ICE,          "flesh_on_ice");
1745 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_GRAVEL,       "flesh_on_gravel");
1746 	ARX_SOUND_LoadCollision(MATERIAL_FLESH,  MATERIAL_STONE,        "flesh_on_stone");
1747 
1748 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_METAL,        "metal_on_metal");
1749 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_GLASS,        "metal_on_glass");
1750 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_CLOTH,        "metal_on_cloth");
1751 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_WOOD,         "metal_on_wood");
1752 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_EARTH,        "metal_on_earth");
1753 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_WATER,        "metal_on_water");
1754 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_ICE,          "metal_on_ice");
1755 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_GRAVEL,       "metal_on_gravel");
1756 	ARX_SOUND_LoadCollision(MATERIAL_METAL,  MATERIAL_STONE,        "metal_on_stone");
1757 
1758 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_GLASS,        "glass_on_glass");
1759 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_CLOTH,        "glass_on_cloth");
1760 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_WOOD,         "glass_on_wood");
1761 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_EARTH,        "glass_on_earth");
1762 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_WATER,        "glass_on_water");
1763 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_ICE,          "glass_on_ice");
1764 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_GRAVEL,       "glass_on_gravel");
1765 	ARX_SOUND_LoadCollision(MATERIAL_GLASS,  MATERIAL_STONE,        "glass_on_stone");
1766 
1767 	ARX_SOUND_LoadCollision(MATERIAL_CLOTH,  MATERIAL_CLOTH,        "cloth_on_cloth");
1768 	ARX_SOUND_LoadCollision(MATERIAL_CLOTH,  MATERIAL_WOOD,         "cloth_on_wood");
1769 	ARX_SOUND_LoadCollision(MATERIAL_CLOTH,  MATERIAL_EARTH,        "cloth_on_earth");
1770 	ARX_SOUND_LoadCollision(MATERIAL_CLOTH,  MATERIAL_WATER,        "cloth_on_water");
1771 	ARX_SOUND_LoadCollision(MATERIAL_CLOTH,  MATERIAL_ICE,          "cloth_on_ice");
1772 	ARX_SOUND_LoadCollision(MATERIAL_CLOTH,  MATERIAL_GRAVEL,       "cloth_on_gravel");
1773 	ARX_SOUND_LoadCollision(MATERIAL_CLOTH,  MATERIAL_STONE,        "cloth_on_stone");
1774 
1775 	ARX_SOUND_LoadCollision(MATERIAL_WOOD,   MATERIAL_WOOD,         "wood_on_wood");
1776 	ARX_SOUND_LoadCollision(MATERIAL_WOOD,   MATERIAL_EARTH,        "wood_on_earth");
1777 	ARX_SOUND_LoadCollision(MATERIAL_WOOD,   MATERIAL_WATER,        "wood_on_water");
1778 	ARX_SOUND_LoadCollision(MATERIAL_WOOD,   MATERIAL_ICE,          "wood_on_ice");
1779 	ARX_SOUND_LoadCollision(MATERIAL_WOOD,   MATERIAL_GRAVEL,       "wood_on_gravel");
1780 	ARX_SOUND_LoadCollision(MATERIAL_WOOD,   MATERIAL_STONE,        "wood_on_stone");
1781 
1782 	ARX_SOUND_LoadCollision(MATERIAL_EARTH,  MATERIAL_EARTH,        "earth_on_earth");
1783 	ARX_SOUND_LoadCollision(MATERIAL_EARTH,  MATERIAL_WATER,        "earth_on_water");
1784 	ARX_SOUND_LoadCollision(MATERIAL_EARTH,  MATERIAL_ICE,          "earth_on_ice");
1785 	ARX_SOUND_LoadCollision(MATERIAL_EARTH,  MATERIAL_GRAVEL,       "earth_on_gravel");
1786 	ARX_SOUND_LoadCollision(MATERIAL_EARTH,  MATERIAL_STONE,        "earth_on_stone");
1787 
1788 	ARX_SOUND_LoadCollision(MATERIAL_WATER,  MATERIAL_WATER,        "water_on_water");
1789 	ARX_SOUND_LoadCollision(MATERIAL_WATER,  MATERIAL_ICE,          "water_on_ice");
1790 	ARX_SOUND_LoadCollision(MATERIAL_WATER,  MATERIAL_GRAVEL,       "water_on_gravel");
1791 	ARX_SOUND_LoadCollision(MATERIAL_WATER,  MATERIAL_STONE,        "water_on_stone");
1792 
1793 	ARX_SOUND_LoadCollision(MATERIAL_ICE,    MATERIAL_ICE,          "ice_on_ice");
1794 	ARX_SOUND_LoadCollision(MATERIAL_ICE,    MATERIAL_GRAVEL,       "ice_on_gravel");
1795 	ARX_SOUND_LoadCollision(MATERIAL_ICE,    MATERIAL_STONE,        "ice_on_stone");
1796 
1797 	ARX_SOUND_LoadCollision(MATERIAL_GRAVEL, MATERIAL_GRAVEL,       "gravel_on_gravel");
1798 	ARX_SOUND_LoadCollision(MATERIAL_GRAVEL, MATERIAL_STONE,        "gravel_on_stone");
1799 
1800 	ARX_SOUND_LoadCollision(MATERIAL_STONE,  MATERIAL_STONE,        "stone_on_stone");
1801 }
1802 
1803 
ARX_SOUND_CreatePresenceMap()1804 static void ARX_SOUND_CreatePresenceMap() {
1805 
1806 	presence.clear();
1807 
1808 	res::path file = (ARX_SOUND_PATH_INI / ARX_SOUND_PRESENCE_NAME).set_ext(ARX_SOUND_FILE_EXTENSION_INI);
1809 
1810 	size_t fileSize;
1811 	char * data = resources->readAlloc(file, fileSize);
1812 	if(!data) {
1813 		LogWarning << "Could not find presence map " << file;
1814 		return;
1815 	}
1816 
1817 	istringstream iss(string(data, fileSize));
1818 	free(data);
1819 
1820 	IniReader reader;
1821 	if(!reader.read(iss)) {
1822 		LogWarning << "Errors while parsing presence map " << file;
1823 	}
1824 
1825 	const IniSection * section = reader.getSection(Section::presence);
1826 	if(!section) {
1827 		LogWarning << "No [" << Section::presence << "] section in presence map " << file;
1828 		return;
1829 	}
1830 
1831 	for(IniSection::iterator i = section->begin(); i != section->end(); ++i) {
1832 		float factor = i->getValue(100.f) / 100.f;
1833 		presence[res::path::load(i->getName()).set_ext(ARX_SOUND_FILE_EXTENSION_WAV)] = factor;
1834 	}
1835 
1836 }
1837 
GetSamplePresenceFactor(const res::path & name)1838 static float GetSamplePresenceFactor(const res::path & name) {
1839 
1840 	arx_assert_msg(name.string().find_first_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ") == string::npos,
1841 	               "bad sample name: \"%s\"", name.string().c_str());
1842 
1843 	PresenceFactors::const_iterator it = presence.find(name);
1844 	if(it != presence.end()) {
1845 		return it->second;
1846 	}
1847 
1848 	return 1.f;
1849 }
1850 
1851 class SoundUpdateThread : public StoppableThread {
1852 
run()1853 	void run() {
1854 
1855 		while(!isStopRequested()) {
1856 
1857 			sleep(ARX_SOUND_UPDATE_INTERVAL);
1858 
1859 			audio::update();
1860 		}
1861 
1862 	}
1863 
1864 };
1865 
1866 static SoundUpdateThread * updateThread = NULL;
1867 
ARX_SOUND_LaunchUpdateThread()1868 static void ARX_SOUND_LaunchUpdateThread() {
1869 
1870 	arx_assert(!updateThread);
1871 
1872 	updateThread = new SoundUpdateThread();
1873 	updateThread->setThreadName("Sound Update");
1874 	updateThread->start();
1875 }
1876 
ARX_SOUND_KillUpdateThread()1877 static void ARX_SOUND_KillUpdateThread() {
1878 
1879 	if(!updateThread) {
1880 		return;
1881 	}
1882 
1883 	updateThread->stop();
1884 	delete updateThread, updateThread = NULL;
1885 }
1886