1 
2 #include "../config-opentomb.h"
3 
4 extern "C" {
5 #include <al.h>
6 #include <alc.h>
7 #ifdef HAVE_ALEXT_H
8 #include <alext.h>
9 #endif
10 #ifdef HAVE_EFX_H
11 #include <efx.h>
12 #endif
13 #ifdef HAVE_EFX_PRESETS_H
14 #include <efx-presets.h>
15 #endif
16 }
17 
18 #include <string.h>
19 
20 #include "audio.h"
21 #include "audio_fx.h"
22 
23 // FX manager structure.
24 // It contains all necessary info to process sample FX (reverb and echo).
25 typedef struct audio_fxmanager_s
26 {
27     ALuint      al_filter;
28     ALuint      al_effect[TR_AUDIO_FX_LASTINDEX];
29     ALuint      al_slot[TR_AUDIO_MAX_SLOTS];
30     ALuint      current_slot;
31     ALuint      current_room_type;
32     ALuint      last_room_type;
33     bool        water_state;    // If listener is underwater, all samples will damp.
34 }audio_fxmanager_t, *audio_fxmanager_p;
35 
36 
37 
38 struct audio_fxmanager_s    fxManager = {0};
39 
40 #ifdef HAVE_ALEXT_H
41 int Audio_LoadReverbToFX(const int effect_index, const EFXEAXREVERBPROPERTIES *reverb);
42 #endif
43 
44 
Audio_InitFX()45 void Audio_InitFX()
46 {
47 #ifdef HAVE_ALEXT_H
48     memset(&fxManager, 0, sizeof(audio_fxmanager_s));
49 
50     // Set up effect slots, effects and filters.
51 
52     alGenAuxiliaryEffectSlots(TR_AUDIO_MAX_SLOTS, fxManager.al_slot);
53     alGenEffects(TR_AUDIO_FX_LASTINDEX, fxManager.al_effect);
54     alGenFilters(1, &fxManager.al_filter);
55 
56     alFilteri(fxManager.al_filter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
57     alFilterf(fxManager.al_filter, AL_LOWPASS_GAIN, 0.7f);      // Low frequencies gain.
58     alFilterf(fxManager.al_filter, AL_LOWPASS_GAINHF, 0.0f);    // High frequencies gain.
59 
60     // Fill up effects with reverb presets.
61 
62     EFXEAXREVERBPROPERTIES reverb1 = EFX_REVERB_PRESET_CITY;
63     Audio_LoadReverbToFX(TR_AUDIO_FX_OUTSIDE, &reverb1);
64 
65     EFXEAXREVERBPROPERTIES reverb2 = EFX_REVERB_PRESET_LIVINGROOM;
66     Audio_LoadReverbToFX(TR_AUDIO_FX_SMALLROOM, &reverb2);
67 
68     EFXEAXREVERBPROPERTIES reverb3 = EFX_REVERB_PRESET_WOODEN_LONGPASSAGE;
69     Audio_LoadReverbToFX(TR_AUDIO_FX_MEDIUMROOM, &reverb3);
70 
71     EFXEAXREVERBPROPERTIES reverb4 = EFX_REVERB_PRESET_DOME_TOMB;
72     Audio_LoadReverbToFX(TR_AUDIO_FX_LARGEROOM, &reverb4);
73 
74     EFXEAXREVERBPROPERTIES reverb5 = EFX_REVERB_PRESET_PIPE_LARGE;
75     Audio_LoadReverbToFX(TR_AUDIO_FX_PIPE, &reverb5);
76 
77     EFXEAXREVERBPROPERTIES reverb6 = EFX_REVERB_PRESET_UNDERWATER;
78     Audio_LoadReverbToFX(TR_AUDIO_FX_WATER, &reverb6);
79 #endif
80     fxManager.last_room_type = TR_AUDIO_FX_LASTINDEX;
81 }
82 
83 
Audio_DeinitFX()84 void Audio_DeinitFX()
85 {
86 #ifdef HAVE_ALEXT_H
87     for(int i = 0; i < TR_AUDIO_MAX_SLOTS; i++)
88     {
89         if(alIsAuxiliaryEffectSlot(fxManager.al_slot[i]))
90         {
91             alAuxiliaryEffectSloti(fxManager.al_slot[i], AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
92             alDeleteAuxiliaryEffectSlots(1, &fxManager.al_slot[i]);
93         }
94     }
95 
96     if(alIsFilter(fxManager.al_filter))
97     {
98         alDeleteFilters(1, &fxManager.al_filter);
99         alDeleteEffects(TR_AUDIO_FX_LASTINDEX, fxManager.al_effect);
100     }
101 #endif
102 }
103 
104 #ifdef HAVE_ALEXT_H
Audio_LoadReverbToFX(const int effect_index,const EFXEAXREVERBPROPERTIES * reverb)105 int Audio_LoadReverbToFX(const int effect_index, const EFXEAXREVERBPROPERTIES *reverb)
106 {
107     ALuint effect = fxManager.al_effect[effect_index];
108 
109     if(alIsEffect(effect))
110     {
111         alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
112 
113         alEffectf(effect, AL_REVERB_DENSITY, reverb->flDensity);
114         alEffectf(effect, AL_REVERB_DIFFUSION, reverb->flDiffusion);
115         alEffectf(effect, AL_REVERB_GAIN, reverb->flGain);
116         alEffectf(effect, AL_REVERB_GAINHF, reverb->flGainHF);
117         alEffectf(effect, AL_REVERB_DECAY_TIME, reverb->flDecayTime);
118         alEffectf(effect, AL_REVERB_DECAY_HFRATIO, reverb->flDecayHFRatio);
119         alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, reverb->flReflectionsGain);
120         alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, reverb->flReflectionsDelay);
121         alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, reverb->flLateReverbGain);
122         alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, reverb->flLateReverbDelay);
123         alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, reverb->flAirAbsorptionGainHF);
124         alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, reverb->flRoomRolloffFactor);
125         alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, reverb->iDecayHFLimit);
126     }
127     else
128     {
129         //Sys_DebugLog(SYS_LOG_FILENAME, "OpenAL error: no effect %d", effect);
130         return 0;
131     }
132 
133     return 1;
134 }
135 #endif
136 
137 
Audio_SetFX(uint32_t source)138 void Audio_SetFX(uint32_t source)
139 {
140 #ifdef HAVE_ALEXT_H
141     ALuint effect;
142     ALuint slot;
143 
144     // Reverb FX is applied globally through audio send. Since player can
145     // jump between adjacent rooms with different reverb info, we assign
146     // several (2 by default) interchangeable audio sends, which are switched
147     // every time current room reverb is changed.
148 
149     if(fxManager.current_room_type != fxManager.last_room_type)  // Switch audio send.
150     {
151         fxManager.last_room_type = fxManager.current_room_type;
152         fxManager.current_slot   = (++fxManager.current_slot > (TR_AUDIO_MAX_SLOTS - 1)) ? (0) : (fxManager.current_slot);
153 
154         effect = fxManager.al_effect[fxManager.current_room_type];
155         slot   = fxManager.al_slot[fxManager.current_slot];
156 
157         if(alIsAuxiliaryEffectSlot(slot) && alIsEffect(effect))
158         {
159             alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, effect);
160         }
161     }
162     else    // Do not switch audio send.
163     {
164         slot = fxManager.al_slot[fxManager.current_slot];
165     }
166 
167     // Assign global reverb FX to channel.
168     alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, 0, AL_FILTER_NULL);
169 #endif
170 }
171 
172 
Audio_UnsetFX(uint32_t source)173 void Audio_UnsetFX(uint32_t source)
174 {
175 #ifdef HAVE_ALEXT_H
176     // Remove any audio sends and direct filters from channel.
177     alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
178     alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
179 #endif
180 }
181 
182 
Audio_SetFXWaterStateForSource(uint32_t source)183 void Audio_SetFXWaterStateForSource(uint32_t source)
184 {
185 #ifdef HAVE_ALEXT_H
186     // Water low-pass filter is applied when source's is_water flag is set.
187     // Note that it is applied directly to channel, i. e. all sources that
188     // are underwater will damp, despite of global reverb setting.
189     if(fxManager.water_state)
190     {
191         alSourcei(source, AL_DIRECT_FILTER, fxManager.al_filter);
192     }
193     else
194     {
195         alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
196     }
197 #endif
198 }
199 
200 
Audio_SetFXRoomType(int value)201 void Audio_SetFXRoomType(int value)
202 {
203     fxManager.current_room_type = value;
204 }
205 
206 
Audio_SetFXWaterState(bool state)207 void Audio_SetFXWaterState(bool state)
208 {
209     fxManager.water_state = state;
210 }
211 
212 
Audio_GetFXWaterState()213 bool Audio_GetFXWaterState()
214 {
215     return fxManager.water_state;
216 }
217