]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/oal_efx.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / sound / oal_efx.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 #include "pstypes.h"
10 #include "oal.h"
11 #include "sound.h"
12 #include "oal_efx.h"
13
14 #ifndef __EMSCRIPTEN__
15
16 #include "alext.h"
17 #include "efx-presets.h"
18
19
20 // effects
21 LPALGENEFFECTS alGenEffects;
22 LPALDELETEEFFECTS alDeleteEffects;
23 LPALEFFECTI alEffecti;
24 LPALEFFECTF alEffectf;
25 LPALEFFECTFV alEffectfv;
26 LPALGETEFFECTF alGetEffectf;
27
28 // aux effect slots
29 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
30 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
31 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
32 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
33 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
34 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
35 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
36
37 static uint EFX_active_environment = SND_ENV_GENERIC;
38 static EFXEAXREVERBPROPERTIES EFX_env_properties = EFX_REVERB_PRESET_GENERIC;
39 static int EFX_enabled = 0;
40
41 static ALuint AL_EFX_aux_id = 0;
42 static ALuint AL_EFX_effect_id = 0;
43
44 static int OAL_efx_inited = 0;
45
46 static const EFXEAXREVERBPROPERTIES EFX_ENV_Generic = EFX_REVERB_PRESET_GENERIC;
47 static const EFXEAXREVERBPROPERTIES EFX_ENV_PaddedCell = EFX_REVERB_PRESET_PADDEDCELL;
48 static const EFXEAXREVERBPROPERTIES EFX_ENV_Room = EFX_REVERB_PRESET_ROOM;
49 static const EFXEAXREVERBPROPERTIES EFX_ENV_BathRoom = EFX_REVERB_PRESET_BATHROOM;
50 static const EFXEAXREVERBPROPERTIES EFX_ENV_LivingRoom = EFX_REVERB_PRESET_LIVINGROOM;
51 static const EFXEAXREVERBPROPERTIES EFX_ENV_StoneRoom = EFX_REVERB_PRESET_STONEROOM;
52 static const EFXEAXREVERBPROPERTIES EFX_ENV_Auditorium = EFX_REVERB_PRESET_AUDITORIUM;
53 static const EFXEAXREVERBPROPERTIES EFX_ENV_ConcertHall = EFX_REVERB_PRESET_CONCERTHALL;
54 static const EFXEAXREVERBPROPERTIES EFX_ENV_Cave = EFX_REVERB_PRESET_CAVE;
55 static const EFXEAXREVERBPROPERTIES EFX_ENV_Arena = EFX_REVERB_PRESET_ARENA;
56 static const EFXEAXREVERBPROPERTIES EFX_ENV_Hangar = EFX_REVERB_PRESET_HANGAR;
57 static const EFXEAXREVERBPROPERTIES EFX_ENV_CarpetedHallway = EFX_REVERB_PRESET_CARPETEDHALLWAY;
58 static const EFXEAXREVERBPROPERTIES EFX_ENV_Hallway = EFX_REVERB_PRESET_HALLWAY;
59 static const EFXEAXREVERBPROPERTIES EFX_ENV_StoneCorridor = EFX_REVERB_PRESET_STONECORRIDOR;
60 static const EFXEAXREVERBPROPERTIES EFX_ENV_Alley = EFX_REVERB_PRESET_ALLEY;
61 static const EFXEAXREVERBPROPERTIES EFX_ENV_Forest = EFX_REVERB_PRESET_FOREST;
62 static const EFXEAXREVERBPROPERTIES EFX_ENV_City = EFX_REVERB_PRESET_CITY;
63 static const EFXEAXREVERBPROPERTIES EFX_ENV_Mountains = EFX_REVERB_PRESET_MOUNTAINS;
64 static const EFXEAXREVERBPROPERTIES EFX_ENV_Quarry = EFX_REVERB_PRESET_QUARRY;
65 static const EFXEAXREVERBPROPERTIES EFX_ENV_Plain = EFX_REVERB_PRESET_PLAIN;
66 static const EFXEAXREVERBPROPERTIES EFX_ENV_ParkingLot = EFX_REVERB_PRESET_PARKINGLOT;
67 static const EFXEAXREVERBPROPERTIES EFX_ENV_SewerPipe = EFX_REVERB_PRESET_SEWERPIPE;
68 static const EFXEAXREVERBPROPERTIES EFX_ENV_Underwater = EFX_REVERB_PRESET_UNDERWATER;
69 static const EFXEAXREVERBPROPERTIES EFX_ENV_Drugged = EFX_REVERB_PRESET_DRUGGED;
70 static const EFXEAXREVERBPROPERTIES EFX_ENV_Dizzy = EFX_REVERB_PRESET_DIZZY;
71 static const EFXEAXREVERBPROPERTIES EFX_ENV_Psychotic = EFX_REVERB_PRESET_PSYCHOTIC;
72
73
74 static void oal_efx_set_env_properties()
75 {
76     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DENSITY, EFX_env_properties.flDensity);
77     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DIFFUSION, EFX_env_properties.flDiffusion);
78     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAIN, EFX_env_properties.flGain);
79     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAINHF, EFX_env_properties.flGainHF);
80     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAINLF, EFX_env_properties.flGainLF);
81     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_TIME, EFX_env_properties.flDecayTime);
82     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFRATIO, EFX_env_properties.flDecayHFRatio);
83     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_LFRATIO, EFX_env_properties.flDecayLFRatio);
84     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_REFLECTIONS_GAIN, EFX_env_properties.flReflectionsGain);
85     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_REFLECTIONS_DELAY, EFX_env_properties.flReflectionsDelay);
86     alEffectfv(AL_EFX_effect_id, AL_EAXREVERB_REFLECTIONS_PAN, EFX_env_properties.flReflectionsPan);
87     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_LATE_REVERB_GAIN, EFX_env_properties.flLateReverbGain);
88     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_LATE_REVERB_DELAY, EFX_env_properties.flLateReverbDelay);
89     alEffectfv(AL_EFX_effect_id, AL_EAXREVERB_LATE_REVERB_PAN, EFX_env_properties.flLateReverbPan);
90     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_ECHO_TIME, EFX_env_properties.flEchoTime);
91     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_ECHO_DEPTH, EFX_env_properties.flEchoDepth);
92     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_MODULATION_TIME, EFX_env_properties.flModulationTime);
93     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_MODULATION_DEPTH, EFX_env_properties.flModulationDepth);
94     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, EFX_env_properties.flAirAbsorptionGainHF);
95     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_HFREFERENCE, EFX_env_properties.flHFReference);
96     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_LFREFERENCE, EFX_env_properties.flLFReference);
97     alEffectf(AL_EFX_effect_id, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, EFX_env_properties.flRoomRolloffFactor);
98     alEffecti(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFLIMIT, EFX_env_properties.iDecayHFLimit);
99 }
100
101 static void oal_efx_update_env_properties()
102 {
103         alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAIN, EFX_env_properties.flGain);
104         alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_TIME, EFX_env_properties.flDecayTime);
105         alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFRATIO, EFX_env_properties.flDecayHFRatio);
106 }
107
108 static void oal_efx_set_environment(uint id)
109 {
110         uint n_id = id;
111
112         switch (n_id) {
113                 case SND_ENV_GENERIC:
114                         EFX_env_properties = EFX_ENV_Generic;
115                         break;
116
117                 case SND_ENV_PADDEDCELL:
118                         EFX_env_properties = EFX_ENV_PaddedCell;
119                         break;
120
121                 case SND_ENV_ROOM:
122                         EFX_env_properties = EFX_ENV_Room;
123                         break;
124
125                 case SND_ENV_BATHROOM:
126                         EFX_env_properties = EFX_ENV_BathRoom;
127                         break;
128
129                 case SND_ENV_LIVINGROOM:
130                         EFX_env_properties = EFX_ENV_LivingRoom;
131                         break;
132
133                 case SND_ENV_STONEROOM:
134                         EFX_env_properties = EFX_ENV_StoneRoom;
135                         break;
136
137                 case SND_ENV_AUDITORIUM:
138                         EFX_env_properties = EFX_ENV_Auditorium;
139                         break;
140
141                 case SND_ENV_CONCERTHALL:
142                         EFX_env_properties = EFX_ENV_ConcertHall;
143                         break;
144
145                 case SND_ENV_CAVE:
146                         EFX_env_properties = EFX_ENV_Cave;
147                         break;
148
149                 case SND_ENV_ARENA:
150                         EFX_env_properties = EFX_ENV_Arena;
151                         break;
152
153                 case SND_ENV_HANGAR:
154                         EFX_env_properties = EFX_ENV_Hangar;
155                         break;
156
157                 case SND_ENV_CARPETEDHALLWAY:
158                         EFX_env_properties = EFX_ENV_CarpetedHallway;
159                         break;
160
161                 case SND_ENV_HALLWAY:
162                         EFX_env_properties = EFX_ENV_Hallway;
163                         break;
164
165                 case SND_ENV_STONECORRIDOR:
166                         EFX_env_properties = EFX_ENV_StoneCorridor;
167                         break;
168
169                 case SND_ENV_ALLEY:
170                         EFX_env_properties = EFX_ENV_Alley;
171                         break;
172
173                 case SND_ENV_FOREST:
174                         EFX_env_properties = EFX_ENV_Forest;
175                         break;
176
177                 case SND_ENV_CITY:
178                         EFX_env_properties = EFX_ENV_City;
179                         break;
180
181                 case SND_ENV_MOUNTAINS:
182                         EFX_env_properties = EFX_ENV_Mountains;
183                         break;
184
185                 case SND_ENV_QUARRY:
186                         EFX_env_properties = EFX_ENV_Quarry;
187                         break;
188
189                 case SND_ENV_PLAIN:
190                         EFX_env_properties = EFX_ENV_Plain;
191                         break;
192
193                 case SND_ENV_PARKINGLOT:
194                         EFX_env_properties = EFX_ENV_ParkingLot;
195                         break;
196
197                 case SND_ENV_SEWERPIPE:
198                         EFX_env_properties = EFX_ENV_SewerPipe;
199                         break;
200
201                 case SND_ENV_UNDERWATER:
202                         EFX_env_properties = EFX_ENV_Underwater;
203                         break;
204
205                 case SND_ENV_DRUGGED:
206                         EFX_env_properties = EFX_ENV_Drugged;
207                         break;
208
209                 case SND_ENV_DIZZY:
210                         EFX_env_properties = EFX_ENV_Dizzy;
211                         break;
212
213                 case SND_ENV_PSYCHOTIC:
214                         EFX_env_properties = EFX_ENV_Psychotic;
215                         break;
216
217                 default:
218                         n_id = SND_ENV_GENERIC;
219                         EFX_env_properties = EFX_ENV_Generic;
220                         break;
221         }
222
223         EFX_active_environment = n_id;
224 }
225 #endif
226
227 int oal_efx_init()
228 {
229 #ifndef __EMSCRIPTEN__
230         if (OAL_efx_inited) {
231                 return 0;
232         }
233
234         // make sure we support EFX and the EAXREVERB effect
235         if ( !alcIsExtensionPresent(alcGetContextsDevice(alcGetCurrentContext()), "ALC_EXT_EFX") ) {
236                 return -1;
237         }
238
239         if ( !alGetEnumValue("AL_EFFECT_EAXREVERB") ) {
240                 return -1;
241         }
242
243         // effects
244         alGenEffects = (LPALGENEFFECTS) alGetProcAddress("alGenEffects");
245         alDeleteEffects = (LPALDELETEEFFECTS) alGetProcAddress("alDeleteEffects");
246         alEffecti = (LPALEFFECTI) alGetProcAddress("alEffecti");
247         alEffectf = (LPALEFFECTF) alGetProcAddress("alEffectf");
248         alEffectfv = (LPALEFFECTFV) alGetProcAddress("alEffectfv");
249         alGetEffectf = (LPALGETEFFECTF) alGetProcAddress("alGetEffectf");
250
251         SDL_assert_release( alGenEffects != NULL );
252         SDL_assert_release( alDeleteEffects != NULL );
253         SDL_assert_release( alEffecti != NULL );
254         SDL_assert_release( alEffectf != NULL );
255         SDL_assert_release( alEffectfv != NULL );
256         SDL_assert_release( alGetEffectf != NULL );
257
258         // aux effect slots
259         alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS) alGetProcAddress("alGenAuxiliaryEffectSlots");
260         alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS) alGetProcAddress("alDeleteAuxiliaryEffectSlots");
261         alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT) alGetProcAddress("alIsAuxiliaryEffectSlot");
262         alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI) alGetProcAddress("alAuxiliaryEffectSloti");
263         alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV) alGetProcAddress("alAuxiliaryEffectSlotiv");
264         alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF) alGetProcAddress("alAuxiliaryEffectSlotf");
265         alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV) alGetProcAddress("alAuxiliaryEffectSlotfv");
266
267         SDL_assert_release( alGenAuxiliaryEffectSlots != NULL );
268         SDL_assert_release( alDeleteAuxiliaryEffectSlots != NULL );
269         SDL_assert_release( alIsAuxiliaryEffectSlot != NULL );
270         SDL_assert_release( alAuxiliaryEffectSloti != NULL );
271         SDL_assert_release( alAuxiliaryEffectSlotiv != NULL );
272         SDL_assert_release( alAuxiliaryEffectSlotf != NULL );
273         SDL_assert_release( alAuxiliaryEffectSlotfv != NULL );
274
275
276         EFX_active_environment = SND_ENV_GENERIC;
277         EFX_env_properties = EFX_ENV_Generic;
278
279
280         alGenAuxiliaryEffectSlots(1, &AL_EFX_aux_id);
281
282         if (alGetError() != AL_NO_ERROR) {
283                 nprintf(("Sound", "SOUND ==>  EFX:  Unable to create Aux effect!\n"));
284                 return -1;
285         }
286
287         alGenEffects(1, &AL_EFX_effect_id);
288
289         if (alGetError() != AL_NO_ERROR) {
290                 nprintf(("Sound", "SOUND ==>  EFX:  Unable to create effect!\n"));
291                 return -1;
292         }
293
294         alEffecti(AL_EFX_effect_id, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
295
296         if (alGetError() != AL_NO_ERROR) {
297                 nprintf(("Sound", "SOUND ==>  EFX:  EAXReverb not supported!\n"));
298                 return -1;
299         }
300
301         alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFX_effect_id);
302
303         if (alGetError() != AL_NO_ERROR) {
304                 nprintf(("Sound", "SOUND ==>  EFX:  Couldn't load effect!\n"));
305                 return -1;
306         }
307
308         OAL_efx_inited = 1;
309
310         oal_efx_set_env_properties();
311
312         return 0;
313 #else
314         return -1;
315 #endif
316 }
317
318 int oal_efx_is_inited()
319 {
320 #ifndef __EMSCRIPTEN__
321         return OAL_efx_inited;
322 #else
323         return 0;
324 #endif
325 }
326
327 void oal_efx_close()
328 {
329 #ifndef __EMSCRIPTEN__
330         if ( !OAL_efx_inited ) {
331                 return;
332         }
333
334         alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
335
336         alDeleteEffects(1, &AL_EFX_effect_id);
337         AL_EFX_effect_id = 0;
338
339         alDeleteAuxiliaryEffectSlots(1, &AL_EFX_aux_id);
340         AL_EFX_aux_id = 0;
341
342         EFX_enabled = 0;
343
344         OAL_efx_inited = 0;
345 #endif
346 }
347
348 void oal_efx_attach(ALuint source_id)
349 {
350 #ifndef __EMSCRIPTEN__
351         if ( !OAL_efx_inited ) {
352                 return;
353         }
354
355         // by default it's disabled
356         ALint plist[3] = { 0, 0, AL_FILTER_NULL };
357
358         if (EFX_enabled) {
359                 plist[0] = AL_EFX_aux_id;
360         }
361
362         oal_check_for_errors("oal_efx_attach() begin");
363
364         alSourceiv(source_id, AL_AUXILIARY_SEND_FILTER, plist);
365
366         oal_check_for_errors("oal_efx_attach() end");
367 #endif
368 }
369
370 // Get up the parameters for the current environment
371 //
372 // er: (output) hold environment parameters
373 // id: if set will get specified preset env, otherwise current env
374 //
375 // returns: 0 if successful, otherwise return -1
376 //
377 int oal_efx_get_all(EAX_REVERBPROPERTIES *er, int id)
378 {
379 #ifndef __EMSCRIPTEN__
380         if (er == NULL) {
381                 return -1;
382         }
383
384         uint active_env_save = EFX_active_environment;
385         EFXEAXREVERBPROPERTIES env_save = EFX_env_properties;
386         bool saved = false;
387
388         if ( (id >= 0) && (id != (int)EFX_active_environment) ) {
389                 saved = true;
390
391                 oal_efx_set_environment(id);
392         }
393
394         er->environment = EFX_active_environment;
395         er->fVolume = EFX_env_properties.flGain;
396         er->fDecayTime_sec = EFX_env_properties.flDecayTime;
397         er->fDamping = EFX_env_properties.flDecayHFRatio;
398
399         if (saved) {
400                 EFX_active_environment = active_env_save;
401                 EFX_env_properties = env_save;
402         }
403
404         return 0;
405 #else
406         return -1;
407 #endif
408 }
409
410 // Set up all the parameters for an environment
411 //
412 // id: value from the SND_ENV_* enumeration
413 // volume: volume for the environment
414 // damping: damp value for the environment
415 // decay: decay time in seconds
416 //
417 // returns: 0 if successful, otherwise return -1
418 //
419 int oal_efx_set_all(uint id, float vol, float damping, float decay)
420 {
421 #ifndef __EMSCRIPTEN__
422         if ( !OAL_efx_inited ) {
423                 return -1;
424         }
425
426         oal_check_for_errors("oal_efx_set_all() begin");
427
428         // special disabled case (NOTE: does not take immediate affect!)
429         if ( (id == SND_ENV_GENERIC) && (vol == 0.0f) && (damping == 0.0f) && (decay == 0.0f) ) {
430                 EFX_enabled = 0;
431                 return 0;
432         }
433
434         if (id != EFX_active_environment) {
435                 oal_efx_set_environment(id);
436                 oal_efx_set_env_properties();
437         }
438
439         CAP(vol, AL_EAXREVERB_MIN_GAIN, AL_EAXREVERB_MAX_GAIN);
440         CAP(decay, AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME);
441         CAP(damping, AL_EAXREVERB_MIN_DECAY_HFRATIO, AL_EAXREVERB_MAX_DECAY_HFRATIO);
442
443         EFX_env_properties.flGain = vol;
444         EFX_env_properties.flDecayTime = decay;
445         EFX_env_properties.flDecayHFRatio = damping;
446
447         oal_efx_update_env_properties();
448
449         alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFX_effect_id);
450
451         EFX_enabled = 1;
452
453         if ( oal_check_for_errors("oal_efx_set_all() end") ) {
454                 return -1;
455         }
456
457         return 0;
458 #else
459         return -1;
460 #endif
461 }