1
2 #include <SDL2/SDL.h>
3 #include <SDL2/SDL_audio.h>
4
5 #include <math.h>
6
7 #include "../config-opentomb.h"
8
9 extern "C" {
10 #include <al.h>
11 #include <alc.h>
12 #ifdef HAVE_ALEXT_H
13 #include <alext.h>
14 #endif
15 }
16
17 #include "../core/system.h"
18 #include "../core/vmath.h"
19 #include "../core/gl_text.h"
20 #include "../core/console.h"
21 #include "../script/script.h"
22 #include "../render/camera.h"
23 #include "../vt/vt_level.h"
24 #include "../entity.h"
25 #include "../room.h"
26 #include "../world.h"
27 #include "../engine.h"
28 #include "../game.h"
29
30 #include "audio.h"
31 #include "audio_stream.h"
32 #include "audio_fx.h"
33
34 #define STB_VORBIS_HEADER_ONLY
35 #include "stb_vorbis.c"
36
37 static ALCdevice *al_device = NULL;
38 static ALCcontext *al_context = NULL;
39
40 // Effect structure.
41 // Contains all global effect parameters.
42 typedef struct audio_effect_s
43 {
44 // General sound source parameters (similar to TR sound info).
45
46 ALfloat pitch; // [PIT in TR] Global pitch shift.
47 ALfloat gain; // [VOL in TR] Global gain (volume).
48 ALfloat range; // [RAD in TR] Range (radius).
49 ALuint chance; // [CH in TR] Chance to play.
50 ALuint loop; // 0 = none, 1 = W, 2 = R, 3 = L.
51 ALboolean rand_pitch; // Similar to flag 0x200000 (P) in native TRs.
52 ALboolean rand_gain; // Similar to flag 0x400000 (V) in native TRs.
53
54 // Additional sound source parameters.
55 // These are not natively in TR engines, but can be later assigned by
56 // external script.
57
58 ALboolean rand_freq; // Slightly randomize frequency.
59 ALuint rand_pitch_var; // Pitch randomizer bounds.
60 ALuint rand_gain_var; // Gain randomizer bounds.
61 ALuint rand_freq_var; // Frequency randomizer bounds.
62
63 // Sample reference parameters.
64
65 ALuint sample_index; // First (or only) sample (buffer) index.
66 ALuint sample_count; // Sample amount to randomly select from.
67 }audio_effect_t, *audio_effect_p;
68
69 // Audio emitter (aka SoundSource) structure.
70
71 typedef struct audio_emitter_s
72 {
73 ALuint emitter_index; // Unique emitter index.
74 ALuint sound_index; // Sound index.
75 float position[3]; // Vector coordinate.
76 uint16_t flags; // Flags - MEANING UNKNOWN!!!
77 }audio_emitter_t, *audio_emitter_p;
78
79 // Main audio source class.
80
81 // Sound source is a complex class, each member of which is linked with
82 // certain in-game entity or sound source, but also a kind of entity by itself.
83 // Number of simultaneously existing sound sources is fixed, and can't be more than
84 // MAX_CHANNELS global constant.
85
86 class AudioSource
87 {
88 public:
89 AudioSource(); // Audio source constructor.
90 ~AudioSource(); // Audio source destructor.
91
92 void Play(); // Make source active and play it.
93 void Pause(); // Pause source (leaving it active).
94 void Stop(); // Stop and destroy source.
95 void Update(); // Update source parameters.
96
97 void SetBuffer(ALint buffer); // Assign buffer to source.
98 void SetLooping(ALboolean is_looping); // Set looping flag.
99 void SetPitch(ALfloat pitch_value); // Set pitch shift.
100 void SetGain(ALfloat gain_value); // Set gain (volume).
101 void SetRange(ALfloat range_value); // Set max. audible distance.
102
103 bool IsActive(); // Check if source is active.
104
105 int32_t emitter_ID; // Entity of origin. -1 means no entity (hence - empty source).
106 uint32_t emitter_type; // 0 - ordinary entity, 1 - sound source, 2 - global sound.
107 uint32_t effect_index; // Effect index. Used to associate effect with entity for R/W flags.
108 uint32_t sample_index; // OpenAL sample (buffer) index. May be the same for different sources.
109 uint32_t sample_count; // How many buffers to use, beginning with sample_index.
110
111 friend int Audio_IsEffectPlaying(int effect_ID, int entity_type, int entity_ID);
112
113 private:
114 bool active; // Source gets autostopped and destroyed on next frame, if it's not set.
115 bool is_water; // Marker to define if sample is in underwater state or not.
116 ALuint source_index; // Source index. Should be unique for each source.
117
118 void LinkEmitter(); // Link source to parent emitter.
119 void SetPosition(const ALfloat pos_vector[]); // Set source position.
120 void SetVelocity(const ALfloat vel_vector[]); // Set source velocity (speed).
121 };
122
123
124 class StreamTrackBuffer
125 {
126 public:
127 StreamTrackBuffer();
128 ~StreamTrackBuffer();
129
130 bool Load(int track_index);
131
132 private:
133 bool Load_Ogg(const char *path); // Ogg file loading routine.
134 bool Load_Wad(const char *path, uint32_t track); // Wad file loading routine.
135 bool Load_Wav(const char *path); // Wav file loading routine.
136 bool Load_WavRW(SDL_RWops *file); // Wav file loading routine.
137
138 public:
139 int track_index;
140 uint32_t buffer_size;
141 uint32_t buffer_part;
142 uint8_t *buffer;
143 int stream_type; // Either BACKGROUND, ONESHOT or CHAT.
144 int channels;
145 int sample_bitsize;
146 int rate;
147 };
148
149
150 // ======== PRIVATE PROTOTYPES =============
151 int Audio_LogALError(int error_marker = 0); // AL-specific error handler.
152 void Audio_LogOGGError(int code); // Ogg-specific error handler.
153
154 bool Audio_FillALBuffer(ALuint buf_number, Uint8* buffer_data, Uint32 buffer_size, int sample_bitsize, int channels, int frequency);
155 int Audio_LoadALbufferFromWAV_Mem(ALuint buf_number, uint8_t *sample_pointer, uint32_t sample_size, uint32_t uncomp_sample_size = 0);
156 int Audio_LoadALbufferFromWAV_File(ALuint buf_number, const char *fname);
157 void Audio_LoadOverridedSamples();
158
159 int Audio_GetFreeSource();
160 int Audio_GetFreeStream(); // Get free (stopped) stream.
161 int Audio_TrackAlreadyPlayed(uint32_t track_index, int8_t mask = 0); // Check if track played with given activation mask.
162 void Audio_UpdateStreams(float time); // Update all streams.
163 int Audio_IsInRange(int entity_type, int entity_ID, float range, float gain);
164
165 void Audio_PauseAllSources(); // Used to pause all effects currently playing.
166 void Audio_StopAllSources(); // Used in audio deinit.
167 void Audio_ResumeAllSources(); // Used to resume all effects currently paused.
168 void Audio_UpdateSources(); // Main sound loop.
169 void Audio_UpdateListenerByCamera(struct camera_s *cam, float time);
170 void Audio_UpdateListenerByEntity(struct entity_s *ent);
171 int Audio_IsTrackPlaying(uint32_t track_index);
172
173 // ==== STREAMTRACK BUFFER CLASS IMPLEMENTATION =====
StreamTrackBuffer()174 StreamTrackBuffer::StreamTrackBuffer() :
175 track_index(-1),
176 buffer_size(0),
177 buffer(NULL),
178 stream_type(TR_AUDIO_STREAM_TYPE_ONESHOT),
179 channels(0),
180 sample_bitsize(0),
181 rate(0)
182 {
183 }
184
185
~StreamTrackBuffer()186 StreamTrackBuffer::~StreamTrackBuffer()
187 {
188 if(buffer)
189 {
190 buffer_size = 0;
191 free(buffer);
192 buffer = NULL;
193 }
194 }
195
196
Load(int track_index)197 bool StreamTrackBuffer::Load(int track_index)
198 {
199 if(this->track_index < 0)
200 {
201 this->track_index = track_index;
202 char file_path[1024];
203 int load_method = 0;
204
205 if(!Script_GetSoundtrack(engine_lua, track_index, file_path, sizeof(file_path), &load_method, &stream_type))
206 {
207 return false;
208 }
209
210 switch(load_method)
211 {
212 case TR_AUDIO_STREAM_METHOD_OGG:
213 return Load_Ogg(file_path);
214
215 case TR_AUDIO_STREAM_METHOD_WAD:
216 return Load_Wad(file_path, track_index);
217
218 case TR_AUDIO_STREAM_METHOD_WAV:
219 return Load_Wav(file_path);
220
221 default:
222 return false;
223 }
224 }
225
226 return (this->buffer != NULL);
227 }
228
229 ///@TODO: fix vorbis streaming! ov_bitrate may differ in differ section
Load_Ogg(const char * path)230 bool StreamTrackBuffer::Load_Ogg(const char *path)
231 {
232 int err = 0;
233 stb_vorbis_alloc alloc;
234 alloc.alloc_buffer_length_in_bytes = 256 * 1024;
235 alloc.alloc_buffer = (char*)Sys_GetTempMem(alloc.alloc_buffer_length_in_bytes);
236 stb_vorbis *ov = stb_vorbis_open_filename(path, &err, &alloc);
237
238 if(!ov)
239 {
240 Sys_DebugLog(SYS_LOG_FILENAME, "OGG: Couldn't open file: %s.", path);
241 Sys_ReturnTempMem(alloc.alloc_buffer_length_in_bytes);
242 return false;
243 }
244
245 stb_vorbis_info info = stb_vorbis_get_info(ov);
246 channels = info.channels;
247 sample_bitsize = 16;
248 buffer_part = 96 * info.max_frame_size;
249 rate = info.sample_rate;
250
251 {
252 const size_t temp_buf_size = 64 * 1024 * 1024;
253 size_t buffer_left = temp_buf_size / 2;
254 short *temp_buff = (short*)malloc(temp_buf_size);
255 size_t readed = 0;
256 buffer_size = 0;
257 while(0 != (readed = stb_vorbis_get_frame_short_interleaved(ov, channels, temp_buff + buffer_size, buffer_left)))
258 {
259 buffer_size += readed * channels;
260 buffer_left -= readed * channels;
261 }
262 buffer_size *= 2;
263 stb_vorbis_close(ov);
264 Sys_ReturnTempMem(alloc.alloc_buffer_length_in_bytes);
265
266 if(buffer_size > 0)
267 {
268 buffer = (uint8_t*)malloc(buffer_size);
269 memcpy(buffer, temp_buff, buffer_size);
270 Con_Notify("file \"%s\" loaded with rate=%d, bitrate=%.1f", path, rate, ((float)info.sample_rate / 1000.0f));
271 }
272 free(temp_buff);
273 }
274
275 return buffer_size > 0;
276 }
277
278
Load_Wad(const char * path,uint32_t track)279 bool StreamTrackBuffer::Load_Wad(const char *path, uint32_t track)
280 {
281 const int TR_AUDIO_STREAM_WAD_STRIDE = 268;
282 const int TR_AUDIO_STREAM_WAD_NAMELENGTH = 260;
283 const int TR_AUDIO_STREAM_WAD_COUNT = 130;
284 char track_name[TR_AUDIO_STREAM_WAD_NAMELENGTH];
285 SDL_RWops *file = NULL;
286 uint32_t offset = 0;
287 uint32_t length = 0;
288
289 if(track > TR_AUDIO_STREAM_WAD_COUNT)
290 {
291 return false;
292 }
293
294 file = SDL_RWFromFile(path, "rb");
295 if(file == NULL)
296 {
297 return false;
298 }
299
300 if(SDL_RWseek(file, (track * TR_AUDIO_STREAM_WAD_STRIDE), RW_SEEK_SET) < 0)
301 {
302 SDL_RWclose(file);
303 return false;
304 }
305
306 if(TR_AUDIO_STREAM_WAD_NAMELENGTH != SDL_RWread(file, track_name, 1, TR_AUDIO_STREAM_WAD_NAMELENGTH))
307 {
308 SDL_RWclose(file);
309 return false;
310 }
311
312 if(1 != SDL_RWread(file, &length, sizeof(uint32_t), 1))
313 {
314 SDL_RWclose(file);
315 return false;
316 }
317
318 if(1 != SDL_RWread(file, &offset, sizeof(uint32_t), 1))
319 {
320 SDL_RWclose(file);
321 return false;
322 }
323
324 if(SDL_RWseek(file, offset, RW_SEEK_SET) < 0)
325 {
326 SDL_RWclose(file);
327 return false;
328 }
329
330 return Load_WavRW(file);
331 }
332
333
Load_Wav(const char * path)334 bool StreamTrackBuffer::Load_Wav(const char *path)
335 {
336 return Load_WavRW(SDL_RWFromFile(path, "rb"));
337 }
338
339
Load_WavRW(SDL_RWops * file)340 bool StreamTrackBuffer::Load_WavRW(SDL_RWops *file)
341 {
342 SDL_AudioSpec wav_spec;
343 uint8_t *wav_buffer;
344 uint32_t wav_length;
345 if(SDL_LoadWAV_RW(file, 1, &wav_spec, &wav_buffer, &wav_length) == NULL)
346 {
347 Sys_DebugLog(SYS_LOG_FILENAME, "Error: can't load track");
348 return false;
349 }
350
351 // Extract bitsize from SDL audio spec for further usage.
352 sample_bitsize = (uint8_t)(wav_spec.format & SDL_AUDIO_MASK_BITSIZE);
353 channels = wav_spec.channels;
354
355 if(wav_spec.channels > 2) // We can't use non-mono and barely can use stereo samples.
356 {
357 Sys_DebugLog(SYS_LOG_FILENAME, "Error: track has more than 2 channels!");
358 return false;
359 }
360
361 // Check if bitsize is supported.
362 // We rarely encounter samples with exotic bitsizes, but just in case...
363 if((sample_bitsize != 32) && (sample_bitsize != 16) && (sample_bitsize != 8))
364 {
365 Sys_DebugLog(SYS_LOG_FILENAME, "Can't load sample - wrong bitsize (%d)", sample_bitsize);
366 return false;
367 }
368
369 if(false)//use_SDL_resampler
370 {
371 int FrameSize = channels * 4; // sizeof(float);
372 SDL_AudioCVT cvt;
373 SDL_BuildAudioCVT(&cvt, wav_spec.format, wav_spec.channels, wav_spec.freq, AUDIO_F32, wav_spec.channels, 44100);
374
375 cvt.len = wav_length;
376 buffer_size = wav_length * cvt.len_mult;
377 if(buffer_size % FrameSize)
378 {
379 buffer_size += FrameSize - (buffer_size % FrameSize); // make align
380 }
381
382 buffer = (uint8_t*)calloc(buffer_size, 1);
383 cvt.buf = buffer;
384 memcpy(cvt.buf, wav_buffer, cvt.len);
385
386 if(cvt.needed)
387 {
388 SDL_ConvertAudio(&cvt);
389 }
390
391 rate = 44100;
392 }
393 else // Standard OpenAL sample loading process.
394 {
395 buffer_size = wav_length;
396 buffer = (uint8_t*)malloc(buffer_size);
397 buffer_part = 128 * 1024;
398 rate = wav_spec.freq;
399 memcpy(buffer, wav_buffer, buffer_size);
400 }
401
402 SDL_FreeWAV(wav_buffer);
403 return true;
404 }
405
406 // ========== GLOBALS ==============
407 ALfloat listener_position[3];
408 struct audio_settings_s audio_settings = {0};
409
410
411 struct audio_world_data_s
412 {
413 uint32_t audio_emitters_count; // Amount of audio emitters in level.
414 struct audio_emitter_s *audio_emitters; // Audio emitters.
415
416 uint32_t audio_map_count; // Amount of overall effects in engine.
417 int16_t *audio_map; // Effect indexes.
418 uint32_t audio_effects_count; // Amount of available effects in level.
419 struct audio_effect_s *audio_effects; // Effects and their parameters.
420
421 uint32_t audio_buffers_count; // Amount of samples.
422 ALuint *audio_buffers; // Samples.
423 uint32_t audio_sources_count; // Amount of runtime channels.
424 AudioSource *audio_sources; // Channels.
425
426 bool damp_active; // Global flag for damping BGM tracks.
427 uint32_t stream_tracks_count; // Amount of stream track channels.
428 struct stream_track_s *stream_tracks; // Stream tracks.
429
430 uint32_t stream_buffers_count; // Amount of stream track source buffers.
431 StreamTrackBuffer **stream_buffers;
432
433 uint32_t stream_track_map_count; // Stream track flag map count.
434 uint8_t *stream_track_map; // Stream track flag map.
435
436 struct stream_track_s external_stream;
437 } audio_world_data;
438
439
440 // ======== AUDIOSOURCE CLASS IMPLEMENTATION ========
AudioSource()441 AudioSource::AudioSource()
442 {
443 active = false;
444 emitter_ID = -1;
445 emitter_type = TR_AUDIO_EMITTER_ENTITY;
446 effect_index = 0;
447 sample_index = 0;
448 sample_count = 0;
449 is_water = false;
450 alGenSources(1, &source_index);
451
452 if(alIsSource(source_index))
453 {
454 alSourcef(source_index, AL_MIN_GAIN, 0.0);
455 alSourcef(source_index, AL_MAX_GAIN, 1.0);
456
457 #ifdef HAVE_ALEXT_H
458 if(audio_settings.use_effects)
459 {
460 alSourcef(source_index, AL_ROOM_ROLLOFF_FACTOR, 1.0);
461 alSourcei(source_index, AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, AL_TRUE);
462 alSourcei(source_index, AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, AL_TRUE);
463 alSourcef(source_index, AL_AIR_ABSORPTION_FACTOR, 0.1);
464 }
465 else
466 {
467 alSourcef(source_index, AL_AIR_ABSORPTION_FACTOR, 0.0);
468 }
469 #endif
470 }
471 }
472
473
~AudioSource()474 AudioSource::~AudioSource()
475 {
476 if(alIsSource(source_index))
477 {
478 alSourceStop(source_index);
479 alDeleteSources(1, &source_index);
480 }
481 }
482
483
IsActive()484 bool AudioSource::IsActive()
485 {
486 return active;
487 }
488
489
Play()490 void AudioSource::Play()
491 {
492 if(alIsSource(source_index))
493 {
494 if(emitter_type == TR_AUDIO_EMITTER_GLOBAL)
495 {
496 alSourcei(source_index, AL_SOURCE_RELATIVE, AL_TRUE);
497 alSource3f(source_index, AL_POSITION, 0.0f, 0.0f, 0.0f);
498 alSource3f(source_index, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
499
500 if(audio_settings.use_effects)
501 {
502 Audio_UnsetFX(source_index);
503 }
504 }
505 else
506 {
507 alSourcei(source_index, AL_SOURCE_RELATIVE, AL_FALSE);
508 LinkEmitter();
509
510 if(audio_settings.use_effects)
511 {
512 Audio_SetFX(source_index);
513 Audio_SetFXWaterStateForSource(source_index);
514 }
515 }
516
517 alSourcePlay(source_index);
518 active = true;
519 }
520 }
521
522
Pause()523 void AudioSource::Pause()
524 {
525 if(alIsSource(source_index))
526 {
527 alSourcePause(source_index);
528 }
529 }
530
531
Stop()532 void AudioSource::Stop()
533 {
534 if(alIsSource(source_index))
535 {
536 alSourceStop(source_index);
537 active = false;
538 }
539 }
540
541
Update()542 void AudioSource::Update()
543 {
544 ALint state;
545 ALfloat range, gain;
546
547 alGetSourcei(source_index, AL_SOURCE_STATE, &state);
548
549 // Disable and bypass source, if it is stopped.
550 if(state == AL_STOPPED)
551 {
552 active = false;
553 return;
554 }
555
556 // Stop source, if it is disabled, but still playing.
557 if(!active && (state == AL_PLAYING))
558 {
559 Stop();
560 return;
561 }
562
563 // Bypass source, if it is paused or global.
564 if( (state == AL_PAUSED) || (emitter_type == TR_AUDIO_EMITTER_GLOBAL) )
565 {
566 return;
567 }
568
569 alGetSourcef(source_index, AL_GAIN, &gain);
570 alGetSourcef(source_index, AL_MAX_DISTANCE, &range);
571
572 // Check if source is in listener's range, and if so, update position,
573 // else stop and disable it.
574 if(Audio_IsInRange(emitter_type, emitter_ID, range, gain))
575 {
576 LinkEmitter();
577
578 if((audio_settings.use_effects) && (is_water != Audio_GetFXWaterState()))
579 {
580 Audio_SetFXWaterStateForSource(source_index);
581 is_water = !is_water;
582 }
583 }
584 else
585 {
586 Stop();
587 }
588 }
589
590
SetBuffer(ALint buffer)591 void AudioSource::SetBuffer(ALint buffer)
592 {
593 ALint buffer_index = audio_world_data.audio_buffers[buffer];
594
595 if(alIsSource(source_index) && alIsBuffer(buffer_index))
596 {
597 alSourcei(source_index, AL_BUFFER, buffer_index);
598
599 // For some reason, OpenAL sometimes produces "Invalid Operation" error here,
600 // so there's extra debug info - maybe it'll help some day.
601
602 /*
603 if(Audio_LogALError(1))
604 {
605 int channels, bits, freq;
606
607 alGetBufferi(buffer_index, AL_CHANNELS, &channels);
608 alGetBufferi(buffer_index, AL_BITS, &bits);
609 alGetBufferi(buffer_index, AL_FREQUENCY, &freq);
610
611 Sys_DebugLog(SYS_LOG_FILENAME, "Erroneous buffer %d info: CH%d, B%d, F%d", buffer_index, channels, bits, freq);
612 }
613 */
614 }
615 }
616
617
SetLooping(ALboolean is_looping)618 void AudioSource::SetLooping(ALboolean is_looping)
619 {
620 alSourcei(source_index, AL_LOOPING, is_looping);
621 }
622
623
SetGain(ALfloat gain_value)624 void AudioSource::SetGain(ALfloat gain_value)
625 {
626 // Clamp gain value.
627 gain_value = (gain_value > 1.0) ? (1.0) : (gain_value);
628 gain_value = (gain_value < 0.0) ? (0.0) : (gain_value);
629
630 alSourcef(source_index, AL_GAIN, gain_value * audio_settings.sound_volume);
631 }
632
633
SetPitch(ALfloat pitch_value)634 void AudioSource::SetPitch(ALfloat pitch_value)
635 {
636 // Clamp pitch value, as OpenAL tends to hang with incorrect ones.
637 pitch_value = (pitch_value < 0.1) ? (0.1) : (pitch_value);
638 pitch_value = (pitch_value > 2.0) ? (2.0) : (pitch_value);
639
640 alSourcef(source_index, AL_PITCH, pitch_value);
641 }
642
643
SetRange(ALfloat range_value)644 void AudioSource::SetRange(ALfloat range_value)
645 {
646 // Source will become fully audible on 1/6 of overall position.
647 alSourcef(source_index, AL_REFERENCE_DISTANCE, range_value / 6.0);
648 alSourcef(source_index, AL_MAX_DISTANCE, range_value);
649 }
650
651
SetPosition(const ALfloat pos_vector[])652 void AudioSource::SetPosition(const ALfloat pos_vector[])
653 {
654 alSourcefv(source_index, AL_POSITION, pos_vector);
655 }
656
657
SetVelocity(const ALfloat vel_vector[])658 void AudioSource::SetVelocity(const ALfloat vel_vector[])
659 {
660 alSourcefv(source_index, AL_VELOCITY, vel_vector);
661 }
662
663
LinkEmitter()664 void AudioSource::LinkEmitter()
665 {
666 entity_p ent;
667
668 switch(emitter_type)
669 {
670 case TR_AUDIO_EMITTER_ENTITY:
671 ent = World_GetEntityByID(emitter_ID);
672 if(ent)
673 {
674 ALfloat vec[3];
675 vec3_copy(vec, ent->transform.M4x4 + 12);
676 SetPosition(vec);
677 vec3_copy(vec, ent->speed);
678 SetVelocity(vec);
679 }
680 return;
681
682 case TR_AUDIO_EMITTER_SOUNDSOURCE:
683 SetPosition(audio_world_data.audio_emitters[emitter_ID].position);
684 return;
685 }
686 }
687
688
Audio_CoreInit()689 void Audio_CoreInit()
690 {
691 ALCint paramList[] = {
692 ALC_STEREO_SOURCES, TR_AUDIO_STREAM_NUMSOURCES,
693 ALC_MONO_SOURCES, (TR_AUDIO_MAX_CHANNELS - TR_AUDIO_STREAM_NUMSOURCES),
694 ALC_FREQUENCY, 44100, 0};
695
696 al_device = alcOpenDevice(NULL);
697 if (!al_device)
698 {
699 Sys_DebugLog(SYS_LOG_FILENAME, "InitAL: No AL audio devices!");
700 return;
701 }
702
703 al_context = alcCreateContext(al_device, paramList);
704 if(!alcMakeContextCurrent(al_context))
705 {
706 Sys_DebugLog(SYS_LOG_FILENAME, "InitAL: AL context is not current!");
707 return;
708 }
709
710 alSpeedOfSound(330.0 * 512.0);
711 alDopplerVelocity(330.0 * 510.0);
712 alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
713
714 StreamTrack_Init(&audio_world_data.external_stream);
715 }
716
717
Audio_CoreDeinit()718 void Audio_CoreDeinit()
719 {
720 StreamTrack_Clear(&audio_world_data.external_stream);
721
722 if(al_context) // T4Larson <t4larson@gmail.com>: fixed
723 {
724 alcMakeContextCurrent(NULL);
725 alcDestroyContext(al_context);
726 al_context = NULL;
727 }
728
729 if(al_device)
730 {
731 alcCloseDevice(al_device);
732 al_device = NULL;
733 }
734 }
735
736
Audio_StreamPlay(uint32_t track_index,const uint8_t mask)737 int Audio_StreamPlay(uint32_t track_index, const uint8_t mask)
738 {
739 int target_stream = -1;
740
741 // Don't even try to do anything with track, if its index is greater than overall amount of
742 // soundtracks specified in a stream track map count (which is derived from script).
743 if((track_index >= audio_world_data.stream_track_map_count) ||
744 (track_index >= audio_world_data.stream_buffers_count))
745 {
746 Con_AddLine("StreamPlay: CANCEL, track index is out of bounds.", FONTSTYLE_CONSOLE_WARNING);
747 return TR_AUDIO_STREAMPLAY_WRONGTRACK;
748 }
749
750 // Don't play track, if it is already playing.
751 // This should become useless option, once proper one-shot trigger functionality is implemented.
752 if(Audio_IsTrackPlaying(track_index))
753 {
754 return TR_AUDIO_STREAMPLAY_IGNORED;
755 }
756
757 // lua_GetSoundtrack returns stream type, file path and load method in last three
758 // provided arguments. That is, after calling this function we receive stream type
759 // in "stream_type" argument, file path into "file_path" argument and load method into
760 // "load_method" argument. Function itself returns false, if script wasn't found or
761 // request was broken; in this case, we quit.
762 if(!audio_world_data.stream_buffers[track_index])
763 {
764 Audio_CacheTrack(track_index);
765 }
766 StreamTrackBuffer *stb = audio_world_data.stream_buffers[track_index];
767 if(!stb)
768 {
769 Con_AddLine("StreamPlay: CANCEL, wrong track index or broken script.", FONTSTYLE_CONSOLE_WARNING);
770 return TR_AUDIO_STREAMPLAY_LOADERROR;
771 }
772
773 // Don't try to play track, if it was already played by specified bit mask.
774 // Additionally, TrackAlreadyPlayed function applies specified bit mask to track map.
775 // Also, bit mask is valid only for non-looped tracks, since looped tracks are played
776 // in any way.
777 if((stb->stream_type != TR_AUDIO_STREAM_TYPE_BACKGROUND) &&
778 Audio_TrackAlreadyPlayed(track_index, mask))
779 {
780 return TR_AUDIO_STREAMPLAY_IGNORED;
781 }
782
783 if(stb->stream_type != TR_AUDIO_STREAM_TYPE_ONESHOT)
784 {
785 Audio_StopStreams(stb->stream_type);
786 }
787
788 // Entry found, now process to actual track loading.
789 target_stream = Audio_GetFreeStream(); // At first, we need to get free stream.
790 if(target_stream == -1)
791 {
792 Con_AddLine("StreamPlay: CANCEL, no free stream.", FONTSTYLE_CONSOLE_WARNING);
793 return TR_AUDIO_STREAMPLAY_NOFREESTREAM; // No success, exit and don't play anything.
794 }
795
796 stream_track_p s = audio_world_data.stream_tracks + target_stream;
797 s->track = stb->track_index;
798 s->type = stb->stream_type;
799 s->state = TR_AUDIO_STREAM_PLAYING;
800 s->current_volume = (s->type == TR_AUDIO_STREAM_TYPE_BACKGROUND) ? (0.0f) : (audio_settings.sound_volume);
801 while(StreamTrack_IsNeedUpdateBuffer(s) && (s->buffer_offset < stb->buffer_size))
802 {
803 size_t bytes = stb->buffer_part;
804 if(bytes > stb->buffer_size - s->buffer_offset)
805 {
806 bytes = stb->buffer_size - s->buffer_offset;
807 }
808 if(StreamTrack_UpdateBuffer(s, stb->buffer + s->buffer_offset, bytes, stb->sample_bitsize, stb->channels, stb->rate) <= 0)
809 {
810 break;
811 }
812 }
813
814 if(audio_settings.use_effects)
815 {
816 StreamTrack_SetEffects(s, s->type == TR_AUDIO_STREAM_TYPE_CHAT);
817 }
818
819 if(StreamTrack_Play(s) <= 0)
820 {
821 Con_AddLine("StreamPlay: CANCEL, stream play error.", FONTSTYLE_CONSOLE_WARNING);
822 return TR_AUDIO_STREAMPLAY_PLAYERROR;
823 }
824
825 return TR_AUDIO_STREAMPLAY_PROCESSED; // Everything is OK!
826 }
827
828
829 // Update routine for all streams. Should be placed into main loop.
Audio_UpdateStreams(float time)830 void Audio_UpdateStreams(float time)
831 {
832 stream_track_p s = audio_world_data.stream_tracks;
833 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i, ++s)
834 {
835 if(StreamTrack_UpdateState(s, time, audio_settings.sound_volume))
836 {
837 StreamTrackBuffer *stb = ((s->track >= 0) && (s->track < audio_world_data.stream_buffers_count)) ?
838 (audio_world_data.stream_buffers[s->track]) : (NULL);
839
840 while(stb && StreamTrack_IsNeedUpdateBuffer(s) && (s->buffer_offset < stb->buffer_size))
841 {
842 size_t bytes = stb->buffer_part;
843 if(bytes + s->buffer_offset > stb->buffer_size)
844 {
845 bytes = stb->buffer_size - s->buffer_offset;
846 }
847 if(StreamTrack_UpdateBuffer(s, stb->buffer + s->buffer_offset, bytes, stb->sample_bitsize, stb->channels, stb->rate) <= 0)
848 {
849 break;
850 }
851 }
852
853 if((s->buffer_offset >= stb->buffer_size) && (s->type == TR_AUDIO_STREAM_TYPE_BACKGROUND))
854 {
855 s->buffer_offset = 0;
856 }
857 }
858 }
859 }
860
861
Audio_IsTrackPlaying(uint32_t track_index)862 int Audio_IsTrackPlaying(uint32_t track_index)
863 {
864 stream_track_p s = audio_world_data.stream_tracks;
865 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i, ++s)
866 {
867 if(s->track == track_index)
868 {
869 return s->state != TR_AUDIO_STREAM_STOPPED;
870 }
871 }
872
873 return 0;
874 }
875
876
Audio_TrackAlreadyPlayed(uint32_t track_index,int8_t mask)877 int Audio_TrackAlreadyPlayed(uint32_t track_index, int8_t mask)
878 {
879 if(!mask)
880 {
881 return 0; // No mask, play in any case.
882 }
883
884 if(track_index >= audio_world_data.stream_track_map_count)
885 {
886 return 1; // No such track, hence "already" played.
887 }
888 else
889 {
890 mask &= 0x3F; // Clamp mask just in case.
891
892 if(audio_world_data.stream_track_map[track_index] == mask)
893 {
894 return true; // Immediately return true, if flags are directly equal.
895 }
896 else
897 {
898 int8_t played = audio_world_data.stream_track_map[track_index] & mask;
899 if(played == mask)
900 {
901 return 1; // Bits were set, hence already played.
902 }
903 else
904 {
905 audio_world_data.stream_track_map[track_index] |= mask;
906 return 0; // Not yet played, set bits and return false.
907 }
908 }
909 }
910 }
911
912
Audio_GetFreeStream()913 int Audio_GetFreeStream()
914 {
915 int ret = TR_AUDIO_STREAMPLAY_NOFREESTREAM;
916 stream_track_p s = audio_world_data.stream_tracks;
917 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i, ++s)
918 {
919 if(s->state == TR_AUDIO_STREAM_STOPPED)
920 {
921 return i;
922 }
923 else if(s->state == TR_AUDIO_STREAM_PAUSED)
924 {
925 StreamTrack_Stop(s);
926 return i;
927 }
928 }
929
930 return ret;
931 }
932
933
Audio_StopStreams(int stream_type)934 int Audio_StopStreams(int stream_type)
935 {
936 int ret = 0;
937 stream_track_p s = audio_world_data.stream_tracks;
938 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i, ++s)
939 {
940 if((stream_type == -1) || (s->type == stream_type))
941 {
942 ret += (StreamTrack_Stop(s) > 0);
943 }
944 }
945
946 return ret;
947 }
948
949
Audio_EndStreams(int stream_type)950 int Audio_EndStreams(int stream_type)
951 {
952 int ret = 0;
953 stream_track_p s = audio_world_data.stream_tracks;
954 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i, ++s)
955 {
956 if((stream_type == -1) || (s->type == stream_type))
957 {
958 if(s->state == TR_AUDIO_STREAM_PLAYING)
959 {
960 s->state = TR_AUDIO_STREAM_STOPPING;
961 ret++;
962 }
963 }
964 }
965
966 return ret;
967 }
968
969
Audio_PauseStreams(int stream_type)970 int Audio_PauseStreams(int stream_type)
971 {
972 int ret = 0;
973
974 stream_track_p s = audio_world_data.stream_tracks;
975 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i, ++s)
976 {
977 if((stream_type == -1) || (s->type == stream_type))
978 {
979 ret += (StreamTrack_Pause(s) > 0);
980 }
981 }
982
983 return ret;
984 }
985
986
Audio_ResumeStreams(int stream_type)987 int Audio_ResumeStreams(int stream_type)
988 {
989 int ret = 0;
990
991 stream_track_p s = audio_world_data.stream_tracks;
992 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i, ++s)
993 {
994 if(((stream_type == -1) || (s->type == stream_type)) && (s->state == TR_AUDIO_STREAM_PAUSED))
995 {
996 ret += (StreamTrack_Play(s) > 0);
997 }
998 }
999
1000 return ret;
1001 }
1002
1003
1004 // ======== Audio source global methods ========
Audio_IsInRange(int entity_type,int entity_ID,float range,float gain)1005 int Audio_IsInRange(int entity_type, int entity_ID, float range, float gain)
1006 {
1007 ALfloat vec[3] = {0.0, 0.0, 0.0}, dist;
1008 entity_p ent;
1009
1010 switch(entity_type)
1011 {
1012 case TR_AUDIO_EMITTER_ENTITY:
1013 ent = World_GetEntityByID(entity_ID);
1014 if(!ent)
1015 {
1016 return 0;
1017 }
1018 vec3_copy(vec, ent->transform.M4x4 + 12);
1019 break;
1020
1021 case TR_AUDIO_EMITTER_SOUNDSOURCE:
1022 if((uint32_t)entity_ID + 1 > audio_world_data.audio_emitters_count)
1023 {
1024 return 0;
1025 }
1026 vec3_copy(vec, audio_world_data.audio_emitters[entity_ID].position);
1027 break;
1028
1029 case TR_AUDIO_EMITTER_GLOBAL:
1030 return 1;
1031
1032 default:
1033 return 0;
1034 }
1035
1036 dist = vec3_dist_sq(listener_position, vec);
1037
1038 // We add 1/4 of overall distance to fix up some issues with
1039 // pseudo-looped sounds that are called at certain frames in animations.
1040
1041 dist /= (gain + 1.25);
1042
1043 return dist < range * range;
1044 }
1045
1046
Audio_UpdateSources()1047 void Audio_UpdateSources()
1048 {
1049 if(audio_world_data.audio_sources_count < 1)
1050 {
1051 return;
1052 }
1053
1054 alGetListenerfv(AL_POSITION, listener_position);
1055
1056 for(uint32_t i = 0; i < audio_world_data.audio_emitters_count; i++)
1057 {
1058 Audio_Send(audio_world_data.audio_emitters[i].sound_index, TR_AUDIO_EMITTER_SOUNDSOURCE, i);
1059 }
1060
1061 for(uint32_t i = 0; i < audio_world_data.audio_sources_count; i++)
1062 {
1063 audio_world_data.audio_sources[i].Update();
1064 }
1065 }
1066
1067
Audio_PauseAllSources()1068 void Audio_PauseAllSources()
1069 {
1070 for(uint32_t i = 0; i < audio_world_data.audio_sources_count; i++)
1071 {
1072 if(audio_world_data.audio_sources[i].IsActive())
1073 {
1074 audio_world_data.audio_sources[i].Pause();
1075 }
1076 }
1077 }
1078
1079
Audio_StopAllSources()1080 void Audio_StopAllSources()
1081 {
1082 for(uint32_t i = 0; i < audio_world_data.audio_sources_count; i++)
1083 {
1084 audio_world_data.audio_sources[i].Stop();
1085 }
1086 }
1087
1088
Audio_ResumeAllSources()1089 void Audio_ResumeAllSources()
1090 {
1091 for(uint32_t i = 0; i < audio_world_data.audio_sources_count; i++)
1092 {
1093 if(audio_world_data.audio_sources[i].IsActive())
1094 {
1095 audio_world_data.audio_sources[i].Play();
1096 }
1097 }
1098 }
1099
1100
Audio_GetFreeSource()1101 int Audio_GetFreeSource() ///@FIXME: add condition (compare max_dist with new source dist)
1102 {
1103 for(uint32_t i = 0; i < audio_world_data.audio_sources_count; i++)
1104 {
1105 if(audio_world_data.audio_sources[i].IsActive() == false)
1106 {
1107 return i;
1108 }
1109 }
1110
1111 return -1;
1112 }
1113
1114
Audio_IsEffectPlaying(int effect_ID,int entity_type,int entity_ID)1115 int Audio_IsEffectPlaying(int effect_ID, int entity_type, int entity_ID)
1116 {
1117 for(uint32_t i = 0; i < audio_world_data.audio_sources_count; i++)
1118 {
1119 if( (audio_world_data.audio_sources[i].emitter_type == (uint32_t)entity_type) &&
1120 (audio_world_data.audio_sources[i].emitter_ID == ( int32_t)entity_ID ) &&
1121 (audio_world_data.audio_sources[i].effect_index == (uint32_t)effect_ID ) &&
1122 audio_world_data.audio_sources[i].IsActive())
1123 {
1124 ALint state;
1125 alGetSourcei(audio_world_data.audio_sources[i].source_index, AL_SOURCE_STATE, &state);
1126 if(state == AL_PLAYING)
1127 {
1128 return i;
1129 }
1130 }
1131 }
1132
1133 return -1;
1134 }
1135
1136
Audio_Send(int effect_ID,int entity_type,int entity_ID)1137 int Audio_Send(int effect_ID, int entity_type, int entity_ID)
1138 {
1139 int32_t source_number;
1140 uint16_t random_value;
1141 ALfloat random_float;
1142 audio_effect_p effect = NULL;
1143 AudioSource *source = NULL;
1144
1145 // If there are no audio buffers or effect index is wrong, don't process.
1146 if((audio_world_data.audio_buffers_count < 1) || (effect_ID < 0))
1147 {
1148 return TR_AUDIO_SEND_IGNORED;
1149 }
1150
1151 // Remap global engine effect ID to local effect ID.
1152 if((uint32_t)effect_ID >= audio_world_data.audio_map_count)
1153 {
1154 return TR_AUDIO_SEND_NOSAMPLE; // Sound is out of bounds; stop.
1155 }
1156
1157 int real_ID = (int)audio_world_data.audio_map[effect_ID];
1158
1159 // Pre-step 1: if there is no effect associated with this ID, bypass audio send.
1160
1161 if(real_ID == -1)
1162 {
1163 return TR_AUDIO_SEND_NOSAMPLE;
1164 }
1165 else
1166 {
1167 effect = audio_world_data.audio_effects + real_ID;
1168 }
1169
1170 // Pre-step 2: check if sound non-looped and chance to play isn't zero,
1171 // then randomly select if it should be played or not.
1172
1173 if((effect->loop != TR_AUDIO_LOOP_LOOPED) && (effect->chance > 0))
1174 {
1175 random_value = rand() % 0x7FFF;
1176 if(effect->chance < random_value)
1177 {
1178 // Bypass audio send, if chance test is not passed.
1179 return TR_AUDIO_SEND_IGNORED;
1180 }
1181 }
1182
1183 // Pre-step 3: Calculate if effect's hearing sphere intersect listener's hearing sphere.
1184 // If it's not, bypass audio send (cause we don't want it to occupy channel, if it's not
1185 // heard).
1186
1187 if(Audio_IsInRange(entity_type, entity_ID, effect->range, effect->gain ) == false)
1188 {
1189 return TR_AUDIO_SEND_IGNORED;
1190 }
1191
1192 // Pre-step 4: check if R (Rewind) flag is set for this effect, if so,
1193 // find any effect with similar ID playing for this entity, and stop it.
1194 // Otherwise, if W (Wait) or L (Looped) flag is set, and same effect is
1195 // playing for current entity, don't send it and exit function.
1196
1197 source_number = Audio_IsEffectPlaying(effect_ID, entity_type, entity_ID);
1198
1199 if(source_number != -1)
1200 {
1201 if(effect->loop == TR_AUDIO_LOOP_REWIND)
1202 {
1203 audio_world_data.audio_sources[source_number].Stop();
1204 }
1205 else if(effect->loop) // Any other looping case (Wait / Loop).
1206 {
1207 return TR_AUDIO_SEND_IGNORED;
1208 }
1209 }
1210 else
1211 {
1212 source_number = Audio_GetFreeSource(); // Get free source.
1213 }
1214
1215 if(source_number != -1) // Everything is OK, we're sending audio to channel.
1216 {
1217 int buffer_index;
1218
1219 // Step 1. Assign buffer to source.
1220
1221 if(effect->sample_count > 1)
1222 {
1223 // Select random buffer, if effect info contains more than 1 assigned samples.
1224 random_value = rand() % (effect->sample_count);
1225 buffer_index = random_value + effect->sample_index;
1226 }
1227 else
1228 {
1229 // Just assign buffer to source, if there is only one assigned sample.
1230 buffer_index = effect->sample_index;
1231 }
1232
1233 source = &audio_world_data.audio_sources[source_number];
1234
1235 source->SetBuffer(buffer_index);
1236
1237 // Step 2. Check looped flag, and if so, set source type to looped.
1238
1239 if(effect->loop == TR_AUDIO_LOOP_LOOPED)
1240 {
1241 source->SetLooping(AL_TRUE);
1242 }
1243 else
1244 {
1245 source->SetLooping(AL_FALSE);
1246 }
1247
1248 // Step 3. Apply internal sound parameters.
1249
1250 source->emitter_ID = entity_ID;
1251 source->emitter_type = entity_type;
1252 source->effect_index = effect_ID;
1253
1254 // Step 4. Apply sound effect properties.
1255
1256 if(effect->rand_pitch) // Vary pitch, if flag is set.
1257 {
1258 random_float = rand() % effect->rand_pitch_var;
1259 random_float = effect->pitch + ((random_float - 25.0) / 200.0);
1260 source->SetPitch(random_float);
1261 }
1262 else
1263 {
1264 source->SetPitch(effect->pitch);
1265 }
1266
1267 if(effect->rand_gain) // Vary gain, if flag is set.
1268 {
1269 random_float = rand() % effect->rand_gain_var;
1270 random_float = effect->gain + (random_float - 25.0) / 200.0;
1271 source->SetGain(random_float);
1272 }
1273 else
1274 {
1275 source->SetGain(effect->gain);
1276 }
1277
1278 source->SetRange(effect->range); // Set audible range.
1279
1280 source->Play(); // Everything is OK, play sound now!
1281
1282 return TR_AUDIO_SEND_PROCESSED;
1283 }
1284 else
1285 {
1286 return TR_AUDIO_SEND_NOCHANNEL;
1287 }
1288 }
1289
1290
Audio_Kill(int effect_ID,int entity_type,int entity_ID)1291 int Audio_Kill(int effect_ID, int entity_type, int entity_ID)
1292 {
1293 int playing_sound = Audio_IsEffectPlaying(effect_ID, entity_type, entity_ID);
1294
1295 if(playing_sound != -1)
1296 {
1297 audio_world_data.audio_sources[playing_sound].Stop();
1298 return TR_AUDIO_SEND_PROCESSED;
1299 }
1300
1301 return TR_AUDIO_SEND_IGNORED;
1302 }
1303
1304
Audio_LoadOverridedSamples()1305 void Audio_LoadOverridedSamples()
1306 {
1307 int num_samples, num_sounds;
1308 int sample_index, sample_count;
1309 char sample_name_mask[256];
1310 char sample_name[256];
1311
1312 if(Script_GetOverridedSamplesInfo(engine_lua, &num_samples, &num_sounds, sample_name_mask))
1313 {
1314 int buffer_counter = 0;
1315
1316 for(uint32_t i = 0; i < audio_world_data.audio_map_count; i++)
1317 {
1318 if(audio_world_data.audio_map[i] != -1)
1319 {
1320 if(Script_GetOverridedSample(engine_lua, i, &sample_index, &sample_count))
1321 {
1322 for(int j = 0; j < sample_count; j++, buffer_counter++)
1323 {
1324 snprintf(sample_name, sizeof(sample_name), sample_name_mask, (sample_index + j));
1325 if(Sys_FileFound(sample_name, 0))
1326 {
1327 Audio_LoadALbufferFromWAV_File(audio_world_data.audio_buffers[buffer_counter], sample_name);
1328 }
1329 }
1330 }
1331 else
1332 {
1333 buffer_counter += audio_world_data.audio_effects[(audio_world_data.audio_map[i])].sample_count;
1334 }
1335 }
1336 }
1337 }
1338 }
1339
1340
Audio_InitGlobals()1341 void Audio_InitGlobals()
1342 {
1343 audio_settings.music_volume = 0.7;
1344 audio_settings.sound_volume = 0.8;
1345 audio_settings.use_effects = true;
1346 audio_settings.listener_is_player = false;
1347
1348 audio_world_data.audio_sources = NULL;
1349 audio_world_data.audio_sources_count = 0;
1350 audio_world_data.audio_buffers = NULL;
1351 audio_world_data.audio_buffers_count = 0;
1352 audio_world_data.audio_effects = NULL;
1353 audio_world_data.audio_effects_count = 0;
1354
1355 audio_world_data.stream_tracks = NULL;
1356 audio_world_data.stream_tracks_count = 0;
1357 audio_world_data.stream_track_map = NULL;
1358 audio_world_data.stream_track_map_count = 0;
1359 }
1360
1361
Audio_Init(uint32_t num_Sources)1362 void Audio_Init(uint32_t num_Sources)
1363 {
1364 // FX should be inited first, as source constructor checks for FX slot to be created.
1365 if(audio_settings.use_effects)
1366 {
1367 Audio_InitFX();
1368 }
1369
1370 // Generate new source array.
1371 num_Sources -= TR_AUDIO_STREAM_NUMSOURCES; // Subtract sources reserved for music.
1372 audio_world_data.audio_sources_count = num_Sources;
1373 audio_world_data.audio_sources = new AudioSource[num_Sources];
1374
1375 // Generate stream tracks array.
1376 audio_world_data.stream_tracks_count = TR_AUDIO_STREAM_NUMSOURCES - 1;
1377 audio_world_data.stream_tracks = (stream_track_p)malloc(audio_world_data.stream_tracks_count * sizeof(stream_track_t));
1378 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i)
1379 {
1380 StreamTrack_Init(audio_world_data.stream_tracks + i);
1381 }
1382 }
1383
1384
Audio_CacheTrack(int id)1385 void Audio_CacheTrack(int id)
1386 {
1387 if((id >= 0) && (id < audio_world_data.stream_buffers_count) && !audio_world_data.stream_buffers[id])
1388 {
1389 StreamTrackBuffer *stb = new StreamTrackBuffer();
1390 if(stb->Load(id))
1391 {
1392 audio_world_data.stream_buffers[id] = stb;
1393 }
1394 else
1395 {
1396 delete stb;
1397 }
1398 }
1399 }
1400
1401
Audio_GenSamples(class VT_Level * tr)1402 void Audio_GenSamples(class VT_Level *tr)
1403 {
1404 uint8_t *pointer = tr->samples_data;
1405 int8_t flag;
1406 uint32_t ind1, ind2;
1407 uint32_t comp_size, uncomp_size;
1408 uint32_t i;
1409
1410 // Generate stream tracks buffers
1411 audio_world_data.stream_buffers = NULL;
1412 audio_world_data.stream_buffers_count = Script_GetNumTracks(engine_lua);
1413 if(audio_world_data.stream_buffers_count > 0)
1414 {
1415 audio_world_data.stream_buffers = (StreamTrackBuffer**)calloc(audio_world_data.stream_buffers_count, sizeof(StreamTrackBuffer*));
1416 Audio_CacheTrack(Script_GetSecretTrackNumber(engine_lua));
1417 }
1418
1419 // Generate new buffer array.
1420 audio_world_data.audio_buffers_count = tr->samples_count;
1421 audio_world_data.audio_buffers = (ALuint*)malloc(audio_world_data.audio_buffers_count * sizeof(ALuint));
1422 memset(audio_world_data.audio_buffers, 0, sizeof(ALuint) * audio_world_data.audio_buffers_count);
1423 alGenBuffers(audio_world_data.audio_buffers_count, audio_world_data.audio_buffers);
1424
1425 // Generate stream track map array.
1426 // We use scripted amount of tracks to define map bounds.
1427 // If script had no such parameter, we define map bounds by default.
1428 audio_world_data.stream_track_map_count = Script_GetNumTracks(engine_lua);
1429 if(audio_world_data.stream_track_map_count == 0) audio_world_data.stream_track_map_count = TR_AUDIO_STREAM_MAP_SIZE;
1430 audio_world_data.stream_track_map = (uint8_t*)malloc(audio_world_data.stream_track_map_count * sizeof(uint8_t));
1431 memset(audio_world_data.stream_track_map, 0, sizeof(uint8_t) * audio_world_data.stream_track_map_count);
1432
1433 // Generate new audio effects array.
1434 audio_world_data.audio_effects_count = tr->sound_details_count;
1435 audio_world_data.audio_effects = (audio_effect_t*)malloc(tr->sound_details_count * sizeof(audio_effect_t));
1436 memset(audio_world_data.audio_effects, 0xFF, sizeof(audio_effect_t) * tr->sound_details_count);
1437
1438 // Generate new audio emitters array.
1439 audio_world_data.audio_emitters_count = tr->sound_sources_count;
1440 audio_world_data.audio_emitters = (audio_emitter_t*)malloc(tr->sound_sources_count * sizeof(audio_emitter_t));
1441 memset(audio_world_data.audio_emitters, 0, sizeof(audio_emitter_t) * tr->sound_sources_count);
1442
1443 // Copy sound map.
1444 audio_world_data.audio_map = tr->soundmap;
1445 tr->soundmap = NULL; /// without it VT destructor free(tr->soundmap)
1446
1447 // Cycle through raw samples block and parse them to OpenAL buffers.
1448
1449 // Different TR versions have different ways of storing samples.
1450 // TR1: sample block size, sample block, num samples, sample offsets.
1451 // TR2/TR3: num samples, sample offsets. (Sample block is in MAIN.SFX.)
1452 // TR4/TR5: num samples, (uncomp_size-comp_size-sample_data) chain.
1453 //
1454 // Hence, we specify certain parse method for each game version.
1455
1456 if(pointer)
1457 {
1458 switch(tr->game_version)
1459 {
1460 case TR_I:
1461 case TR_I_DEMO:
1462 case TR_I_UB:
1463 audio_world_data.audio_map_count = TR_AUDIO_MAP_SIZE_TR1;
1464
1465 for(i = 0; i < audio_world_data.audio_buffers_count-1; i++)
1466 {
1467 pointer = tr->samples_data + tr->sample_indices[i];
1468 uint32_t size = tr->sample_indices[i + 1] - tr->sample_indices[i];
1469 Audio_LoadALbufferFromWAV_Mem(audio_world_data.audio_buffers[i], pointer, size);
1470 }
1471 i = audio_world_data.audio_buffers_count-1;
1472 Audio_LoadALbufferFromWAV_Mem(audio_world_data.audio_buffers[i], pointer, (tr->samples_count - tr->sample_indices[i]));
1473 break;
1474
1475 case TR_II:
1476 case TR_II_DEMO:
1477 case TR_III:
1478 audio_world_data.audio_map_count = (tr->game_version == TR_III) ? (TR_AUDIO_MAP_SIZE_TR3) : (TR_AUDIO_MAP_SIZE_TR2);
1479 ind1 = 0;
1480 ind2 = 0;
1481 flag = 0;
1482 i = 0;
1483 while(pointer < tr->samples_data + tr->samples_data_size - 4)
1484 {
1485 pointer = tr->samples_data + ind2;
1486 if(!memcmp(pointer, "RIFF", 4))
1487 {
1488 if(flag == 0x00)
1489 {
1490 ind1 = ind2;
1491 flag = 0x01;
1492 }
1493 else
1494 {
1495 uncomp_size = ind2 - ind1;
1496 Audio_LoadALbufferFromWAV_Mem(audio_world_data.audio_buffers[i], tr->samples_data + ind1, uncomp_size);
1497 i++;
1498 if(i > audio_world_data.audio_buffers_count - 1)
1499 {
1500 break;
1501 }
1502 ind1 = ind2;
1503 }
1504 }
1505 ind2++;
1506 }
1507 uncomp_size = tr->samples_data_size - ind1;
1508 pointer = tr->samples_data + ind1;
1509 if(i < audio_world_data.audio_buffers_count)
1510 {
1511 Audio_LoadALbufferFromWAV_Mem(audio_world_data.audio_buffers[i], pointer, uncomp_size);
1512 }
1513 break;
1514
1515 case TR_IV:
1516 case TR_IV_DEMO:
1517 case TR_V:
1518 audio_world_data.audio_map_count = (tr->game_version == TR_V) ? (TR_AUDIO_MAP_SIZE_TR5) : (TR_AUDIO_MAP_SIZE_TR4);
1519
1520 for(i = 0; i < tr->samples_count; i++)
1521 {
1522 // Parse sample sizes.
1523 // Always use comp_size as block length, as uncomp_size is used to cut raw sample data.
1524 uncomp_size = *((uint32_t*)pointer);
1525 pointer += 4;
1526 comp_size = *((uint32_t*)pointer);
1527 pointer += 4;
1528
1529 // Load WAV sample into OpenAL buffer.
1530 Audio_LoadALbufferFromWAV_Mem(audio_world_data.audio_buffers[i], pointer, comp_size, uncomp_size);
1531
1532 // Now we can safely move pointer through current sample data.
1533 pointer += comp_size;
1534 }
1535 break;
1536
1537 default:
1538 audio_world_data.audio_map_count = TR_AUDIO_MAP_SIZE_NONE;
1539 free(tr->samples_data);
1540 tr->samples_data = NULL;
1541 tr->samples_data_size = 0;
1542 return;
1543 }
1544
1545 free(tr->samples_data);
1546 tr->samples_data = NULL;
1547 tr->samples_data_size = 0;
1548 }
1549
1550 // Cycle through SoundDetails and parse them into native OpenTomb
1551 // audio effects structure.
1552 for(i = 0; i < audio_world_data.audio_effects_count; i++)
1553 {
1554 if(tr->game_version < TR_III)
1555 {
1556 audio_world_data.audio_effects[i].gain = (float)(tr->sound_details[i].volume) / 32767.0; // Max. volume in TR1/TR2 is 32767.
1557 audio_world_data.audio_effects[i].chance = tr->sound_details[i].chance;
1558 }
1559 else if(tr->game_version > TR_III)
1560 {
1561 audio_world_data.audio_effects[i].gain = (float)(tr->sound_details[i].volume) / 255.0; // Max. volume in TR3 is 255.
1562 audio_world_data.audio_effects[i].chance = tr->sound_details[i].chance * 255;
1563 }
1564 else
1565 {
1566 audio_world_data.audio_effects[i].gain = (float)(tr->sound_details[i].volume) / 255.0; // Max. volume in TR3 is 255.
1567 audio_world_data.audio_effects[i].chance = tr->sound_details[i].chance * 127;
1568 }
1569
1570 audio_world_data.audio_effects[i].rand_gain_var = 50;
1571 audio_world_data.audio_effects[i].rand_pitch_var = 50;
1572
1573 audio_world_data.audio_effects[i].pitch = (float)(tr->sound_details[i].pitch) / 127.0 + 1.0;
1574 audio_world_data.audio_effects[i].range = (float)(tr->sound_details[i].sound_range) * 1024.0;
1575
1576 audio_world_data.audio_effects[i].rand_pitch = (tr->sound_details[i].flags_2 & TR_AUDIO_FLAG_RAND_PITCH);
1577 audio_world_data.audio_effects[i].rand_gain = (tr->sound_details[i].flags_2 & TR_AUDIO_FLAG_RAND_VOLUME);
1578
1579 switch(tr->game_version)
1580 {
1581 case TR_I:
1582 case TR_I_DEMO:
1583 case TR_I_UB:
1584 switch(tr->sound_details[i].num_samples_and_flags_1 & 0x03)
1585 {
1586 case 0x02:
1587 audio_world_data.audio_effects[i].loop = TR_AUDIO_LOOP_LOOPED;
1588 break;
1589 case 0x01:
1590 audio_world_data.audio_effects[i].loop = TR_AUDIO_LOOP_REWIND;
1591 break;
1592 default:
1593 audio_world_data.audio_effects[i].loop = TR_AUDIO_LOOP_NONE;
1594 }
1595 break;
1596
1597 case TR_II:
1598 case TR_II_DEMO:
1599 switch(tr->sound_details[i].num_samples_and_flags_1 & 0x03)
1600 {
1601 /*case 0x02:
1602 audio_world_data.audio_effects[i].loop = TR_AUDIO_LOOP_REWIND;
1603 break;*/
1604 case 0x01:
1605 audio_world_data.audio_effects[i].loop = TR_AUDIO_LOOP_REWIND;
1606 break;
1607 case 0x03:
1608 audio_world_data.audio_effects[i].loop = TR_AUDIO_LOOP_LOOPED;
1609 break;
1610 default:
1611 audio_world_data.audio_effects[i].loop = TR_AUDIO_LOOP_NONE;
1612 }
1613 break;
1614
1615 default:
1616 audio_world_data.audio_effects[i].loop = (tr->sound_details[i].num_samples_and_flags_1 & TR_AUDIO_LOOP_LOOPED);
1617 break;
1618 }
1619
1620 audio_world_data.audio_effects[i].sample_index = tr->sound_details[i].sample;
1621 audio_world_data.audio_effects[i].sample_count = (tr->sound_details[i].num_samples_and_flags_1 >> 2) & TR_AUDIO_SAMPLE_NUMBER_MASK;
1622 }
1623
1624 // Try to override samples via script.
1625 // If there is no script entry exist, we just leave default samples.
1626 // NB! We need to override samples AFTER audio effects array is inited, as override
1627 // routine refers to existence of certain audio effect in level.
1628
1629 Audio_LoadOverridedSamples();
1630
1631 // Hardcoded version-specific fixes!
1632
1633 switch(tr->game_version)
1634 {
1635 case TR_I:
1636 case TR_I_DEMO:
1637 case TR_I_UB:
1638 // Fix for underwater looped sound.
1639 if ((audio_world_data.audio_map[TR_AUDIO_SOUND_UNDERWATER]) >= 0)
1640 {
1641 audio_world_data.audio_effects[(audio_world_data.audio_map[TR_AUDIO_SOUND_UNDERWATER])].loop = TR_AUDIO_LOOP_LOOPED;
1642 }
1643 break;
1644 case TR_II:
1645 // Fix for helicopter sound range.
1646 if ((audio_world_data.audio_map[297]) >= 0)
1647 {
1648 audio_world_data.audio_effects[(audio_world_data.audio_map[297])].range *= 10.0;
1649 }
1650 break;
1651 }
1652
1653 // Cycle through sound emitters and
1654 // parse them to native OpenTomb sound emitters structure.
1655
1656 for(i = 0; i < audio_world_data.audio_emitters_count; i++)
1657 {
1658 audio_world_data.audio_emitters[i].emitter_index = i;
1659 audio_world_data.audio_emitters[i].sound_index = tr->sound_sources[i].sound_id;
1660 audio_world_data.audio_emitters[i].position[0] = tr->sound_sources[i].x;
1661 audio_world_data.audio_emitters[i].position[1] = tr->sound_sources[i].z;
1662 audio_world_data.audio_emitters[i].position[2] = -tr->sound_sources[i].y;
1663 audio_world_data.audio_emitters[i].flags = tr->sound_sources[i].flags;
1664 }
1665 }
1666
1667
Audio_DeInit()1668 int Audio_DeInit()
1669 {
1670 Audio_StopAllSources();
1671 Audio_StopStreams();
1672
1673 if(audio_world_data.audio_sources)
1674 {
1675 audio_world_data.audio_sources_count = 0;
1676 delete[] audio_world_data.audio_sources;
1677 audio_world_data.audio_sources = NULL;
1678 }
1679
1680 if(audio_world_data.audio_emitters)
1681 {
1682 audio_world_data.audio_emitters_count = 0;
1683 free(audio_world_data.audio_emitters);
1684 audio_world_data.audio_emitters = NULL;
1685 }
1686
1687 if(audio_world_data.stream_tracks)
1688 {
1689 for(uint32_t i = 0; i < audio_world_data.stream_tracks_count; ++i)
1690 {
1691 StreamTrack_Clear(audio_world_data.stream_tracks + i);
1692 }
1693 free(audio_world_data.stream_tracks);
1694 audio_world_data.stream_tracks = NULL;
1695 }
1696 audio_world_data.stream_tracks_count = 0;
1697
1698 if(audio_world_data.stream_track_map)
1699 {
1700 audio_world_data.stream_track_map_count = 0;
1701 free(audio_world_data.stream_track_map);
1702 audio_world_data.stream_track_map = NULL;
1703 }
1704
1705 ///@CRITICAL: You must to delete all sources before buffers deleting!!!
1706
1707 if(audio_world_data.audio_buffers)
1708 {
1709 alDeleteBuffers(audio_world_data.audio_buffers_count, audio_world_data.audio_buffers);
1710 audio_world_data.audio_buffers_count = 0;
1711 free(audio_world_data.audio_buffers);
1712 audio_world_data.audio_buffers = NULL;
1713 }
1714
1715 if(audio_world_data.audio_effects)
1716 {
1717 audio_world_data.audio_effects_count = 0;
1718 free(audio_world_data.audio_effects);
1719 audio_world_data.audio_effects = NULL;
1720 }
1721
1722 if(audio_world_data.audio_map)
1723 {
1724 audio_world_data.audio_map_count = 0;
1725 free(audio_world_data.audio_map);
1726 audio_world_data.audio_map = NULL;
1727 }
1728
1729 Audio_DeinitFX();
1730
1731 if(audio_world_data.stream_buffers)
1732 {
1733 for(uint32_t i = 0; i < audio_world_data.stream_buffers_count; i++)
1734 {
1735 if(audio_world_data.stream_buffers[i])
1736 {
1737 delete audio_world_data.stream_buffers[i];
1738 }
1739 audio_world_data.stream_buffers[i] = NULL;
1740 }
1741 audio_world_data.stream_buffers_count = 0;
1742 free(audio_world_data.stream_buffers);
1743 audio_world_data.stream_buffers = NULL;
1744 }
1745
1746 return 1;
1747 }
1748
1749
Audio_LogALError(int error_marker)1750 int Audio_LogALError(int error_marker)
1751 {
1752 ALenum err = alGetError();
1753 if(err != AL_NO_ERROR)
1754 {
1755 Sys_DebugLog(SYS_LOG_FILENAME, "OpenAL error: %s / %d", alGetString(err), error_marker);
1756 }
1757 return err;
1758 }
1759
1760
1761 /*void Audio_LogOGGError(int code)
1762 {
1763 switch(code)
1764 {
1765 case OV_EREAD:
1766 Sys_DebugLog(SYS_LOG_FILENAME, "OGG error: Read from media.");
1767 break;
1768 case OV_ENOTVORBIS:
1769 Sys_DebugLog(SYS_LOG_FILENAME, "OGG error: Not Vorbis data.");
1770 break;
1771 case OV_EVERSION:
1772 Sys_DebugLog(SYS_LOG_FILENAME, "OGG error: Vorbis version mismatch.");
1773 break;
1774 case OV_EBADHEADER:
1775 Sys_DebugLog(SYS_LOG_FILENAME, "OGG error: Invalid Vorbis header.");
1776 break;
1777 case OV_EFAULT:
1778 Sys_DebugLog(SYS_LOG_FILENAME, "OGG error: Internal logic fault (bug or heap/stack corruption.");
1779 break;
1780 default:
1781 Sys_DebugLog(SYS_LOG_FILENAME, "OGG error: Unknown Ogg error.");
1782 break;
1783 }
1784 }*/
1785
1786
Audio_LoadALbufferFromWAV_Mem(ALuint buf_number,uint8_t * sample_pointer,uint32_t sample_size,uint32_t uncomp_sample_size)1787 int Audio_LoadALbufferFromWAV_Mem(ALuint buf_number, uint8_t *sample_pointer, uint32_t sample_size, uint32_t uncomp_sample_size)
1788 {
1789 SDL_AudioSpec wav_spec;
1790 Uint8 *wav_buffer;
1791 Uint32 wav_length;
1792
1793 SDL_RWops *src = SDL_RWFromMem(sample_pointer, sample_size);
1794
1795 // Decode WAV structure with SDL methods.
1796 // SDL automatically defines file format (PCM/ADPCM), so we shouldn't bother
1797 // about if it is TR4 compressed samples or TRLE uncompressed samples.
1798
1799 if(SDL_LoadWAV_RW(src, 1, &wav_spec, &wav_buffer, &wav_length) == NULL)
1800 {
1801 Sys_DebugLog(SYS_LOG_FILENAME, "Error: can't load sample #%03d from sample block!", buf_number);
1802 return -1;
1803 }
1804
1805 // Uncomp_sample_size explicitly specifies amount of raw sample data
1806 // to load into buffer. It is only used in TR4/5 with ADPCM samples,
1807 // because full-sized ADPCM sample contains a bit of silence at the end,
1808 // which should be removed. That's where uncomp_sample_size comes into
1809 // business.
1810 // Note that we also need to compare if uncomp_sample_size is smaller
1811 // than native wav length, because for some reason many TR5 uncomp sizes
1812 // are messed up and actually more than actual sample size.
1813
1814 if((uncomp_sample_size == 0) || (wav_length < uncomp_sample_size))
1815 {
1816 uncomp_sample_size = wav_length;
1817 }
1818
1819 // Find out sample format and load it correspondingly.
1820 // Note that with OpenAL, we can have samples of different formats in same level.
1821
1822 bool result = Audio_FillALBuffer(buf_number, wav_buffer, uncomp_sample_size, wav_spec.format & SDL_AUDIO_MASK_BITSIZE, wav_spec.channels, wav_spec.freq);
1823
1824 SDL_FreeWAV(wav_buffer);
1825
1826 return (result) ? (0) : (-3); // Zero means success.
1827 }
1828
1829
Audio_LoadALbufferFromWAV_File(ALuint buf_number,const char * fname)1830 int Audio_LoadALbufferFromWAV_File(ALuint buf_number, const char *fname)
1831 {
1832 SDL_RWops *file;
1833 SDL_AudioSpec wav_spec;
1834 Uint8 *wav_buffer;
1835 Uint32 wav_length;
1836
1837 file = SDL_RWFromFile(fname, "rb");
1838
1839 if(!file)
1840 {
1841 Con_Warning("file \"%s\" not exists", fname);
1842 return -1;
1843 }
1844
1845 if(SDL_LoadWAV_RW(file, 1, &wav_spec, &wav_buffer, &wav_length) == NULL)
1846 {
1847 SDL_RWclose(file);
1848 Con_Warning("file \"%s\" has wrog format", fname);
1849 return -2;
1850 }
1851 SDL_RWclose(file);
1852
1853 bool result = Audio_FillALBuffer(buf_number, wav_buffer, wav_length, wav_spec.format & SDL_AUDIO_MASK_BITSIZE, wav_spec.channels, wav_spec.freq);
1854
1855 SDL_FreeWAV(wav_buffer);
1856
1857 return (result) ? (0) : (-3); // Zero means success.
1858 }
1859
1860
Audio_FillALBuffer(ALuint buf_number,Uint8 * buffer_data,Uint32 buffer_size,int sample_bitsize,int channels,int frequency)1861 bool Audio_FillALBuffer(ALuint buf_number, Uint8* buffer_data, Uint32 buffer_size, int sample_bitsize, int channels, int frequency)
1862 {
1863 if(channels > 2) // We can't use non-mono and barely can use stereo samples.
1864 {
1865 Sys_DebugLog(SYS_LOG_FILENAME, "Error: sample %03d has more than 2 channels!", buf_number);
1866 return false;
1867 }
1868
1869 // Check if bitsize is supported.
1870 // We rarely encounter samples with exotic bitsizes, but just in case...
1871 if((sample_bitsize != 32) && (sample_bitsize != 16) && (sample_bitsize != 8))
1872 {
1873 Sys_DebugLog(SYS_LOG_FILENAME, "Can't load sample - wrong bitsize (%d)", sample_bitsize);
1874 return false;
1875 }
1876
1877 // Standard OpenAL sample loading process.
1878 ALenum sample_format = 0x00;
1879
1880 if(channels == 1)
1881 {
1882 switch(sample_bitsize)
1883 {
1884 case 8:
1885 sample_format = AL_FORMAT_MONO8;
1886 break;
1887 case 16:
1888 sample_format = AL_FORMAT_MONO16;
1889 break;
1890 #ifdef HAVE_ALEXT_H
1891 case 32:
1892 sample_format = AL_FORMAT_MONO_FLOAT32;
1893 break;
1894 #endif
1895 }
1896 }
1897 else
1898 {
1899 switch(sample_bitsize)
1900 {
1901 case 8:
1902 sample_format = AL_FORMAT_STEREO8;
1903 break;
1904 case 16:
1905 sample_format = AL_FORMAT_STEREO16;
1906 break;
1907 #ifdef HAVE_ALEXT_H
1908 case 32:
1909 sample_format = AL_FORMAT_STEREO_FLOAT32;
1910 break;
1911 #endif
1912 }
1913 }
1914
1915 alBufferData(buf_number, sample_format, buffer_data, buffer_size, frequency);
1916
1917 return true;
1918 }
1919
1920
1921 /**
1922 * Updates listener parameters by camera structure. For correct speed calculation
1923 * that function have to be called every game frame.
1924 * @param cam - pointer to the camera structure.
1925 */
Audio_UpdateListenerByCamera(struct camera_s * cam,float time)1926 void Audio_UpdateListenerByCamera(struct camera_s *cam, float time)
1927 {
1928 ALfloat v[6]; // vec3 - forvard, vec3 - up
1929
1930 vec3_copy(v + 0, cam->transform.M4x4 + 8); // cam_OZ
1931 vec3_copy(v + 3, cam->transform.M4x4 + 4); // cam_OY
1932 alListenerfv(AL_ORIENTATION, v);
1933
1934 vec3_copy(v, cam->transform.M4x4 + 12);
1935 alListenerfv(AL_POSITION, v);
1936
1937 vec3_sub(v, cam->transform.M4x4 + 12, cam->prev_pos);
1938 v[3] = 1.0 / time;
1939 vec3_mul_scalar(v, v, v[3]);
1940 alListenerfv(AL_VELOCITY, v);
1941 vec3_copy(cam->prev_pos, cam->transform.M4x4 + 12);
1942
1943 if(cam->current_room)
1944 {
1945 bool old_state = Audio_GetFXWaterState();
1946 bool water_state = cam->current_room->content->room_flags & TR_ROOM_FLAG_WATER;
1947 Audio_SetFXWaterState(water_state);
1948 if(water_state)
1949 {
1950 Audio_SetFXRoomType(TR_AUDIO_FX_WATER);
1951 }
1952 else
1953 {
1954 Audio_SetFXRoomType(cam->current_room->content->reverb_info);
1955 }
1956
1957 if(water_state != old_state)
1958 {
1959 if(water_state)
1960 {
1961 Audio_Send(TR_AUDIO_SOUND_UNDERWATER);
1962 }
1963 else
1964 {
1965 Audio_Kill(TR_AUDIO_SOUND_UNDERWATER);
1966 }
1967 }
1968 }
1969 }
1970
1971
Audio_UpdateListenerByEntity(struct entity_s * ent)1972 void Audio_UpdateListenerByEntity(struct entity_s *ent)
1973 {
1974 ///@FIXME: Add entity listener updater here.
1975 }
1976
1977
Audio_Update(float time)1978 void Audio_Update(float time)
1979 {
1980 Audio_UpdateSources();
1981 Audio_UpdateStreams(time);
1982 Audio_UpdateListenerByCamera(&engine_camera, time);
1983 }
1984
1985
Audio_GetStreamExternal()1986 struct stream_track_s *Audio_GetStreamExternal()
1987 {
1988 return &audio_world_data.external_stream;
1989 }
1990