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 the
6 * source.
7 *
8 */
9
10
11
12 #include "cfile/cfile.h"
13 #include "cmdline/cmdline.h"
14 #include "globalincs/pstypes.h"
15 #include "osapi/osapi.h"
16 #include "sound/audiostr.h"
17 #include "sound/channel.h"
18 #include "sound/ds.h"
19 #include "sound/ds3d.h"
20 #include "sound/dscap.h"
21 #include "sound/openal.h"
22 #include "sound/sound.h" // jg18 - for enhanced sound
23
24
25 typedef struct sound_buffer
26 {
27 ALuint buf_id; // OpenAL buffer id
28 int channel_id; // Channel[] index this buffer is currently bound to
29
30 int frequency;
31 int bits_per_sample;
32 int nchannels;
33 int nseconds;
34 int nbytes;
35
sound_buffersound_buffer36 sound_buffer():
37 buf_id(0), channel_id(-1), frequency(0), bits_per_sample(0),
38 nchannels(0), nseconds(0), nbytes(0)
39 {
40 }
41 } sound_buffer;
42
43
44 static int MAX_CHANNELS; // initialized properly in ds_init_channels()
45 channel *Channels = NULL;
46 static int channel_next_sig = 1;
47
48 const int BUFFER_BUMP = 50;
49 SCP_vector<sound_buffer> sound_buffers;
50
51 static int Ds_use_eax = 0;
52
53 static int Ds_eax_inited = 0;
54
55 static int AL_play_position = 0;
56
57 // NOTE: these can't be static
58 int Ds_sound_quality = DS_SQ_MEDIUM;
59 int Ds_float_supported = 0;
60
61
62 // this is so stupid - required to get VC6 to use the following array initializer
EFXREVERBPROPERTIES(const EFXREVERBPROPERTIES_list & list)63 EFXREVERBPROPERTIES::EFXREVERBPROPERTIES(const EFXREVERBPROPERTIES_list &list)
64 {
65 name = list.name;
66 flDensity = list.flDensity;
67 flDiffusion = list.flDiffusion;
68 flGain = list.flGain;
69 flGainHF = list.flGainHF;
70 flGainLF = list.flGainLF;
71 flDecayTime = list.flDecayTime;
72 flDecayHFRatio = list.flDecayHFRatio;
73 flDecayLFRatio = list.flDecayLFRatio;
74 flReflectionsGain = list.flReflectionsGain;
75 flReflectionsDelay = list.flReflectionsDelay;
76 flReflectionsPan[0] = list.flReflectionsPan[0];
77 flReflectionsPan[1] = list.flReflectionsPan[1];
78 flReflectionsPan[2] = list.flReflectionsPan[2];
79 flLateReverbGain = list.flLateReverbGain;
80 flLateReverbDelay = list.flLateReverbDelay;
81 flLateReverbPan[0] = list.flLateReverbPan[0];
82 flLateReverbPan[1] = list.flLateReverbPan[1];
83 flLateReverbPan[2] = list.flLateReverbPan[2];
84 flEchoTime = list.flEchoTime;
85 flEchoDepth = list.flEchoDepth;
86 flModulationTime = list.flModulationTime;
87 flModulationDepth = list.flModulationDepth;
88 flAirAbsorptionGainHF = list.flAirAbsorptionGainHF;
89 flHFReference = list.flHFReference;
90 flLFReference = list.flLFReference;
91 flRoomRolloffFactor = list.flRoomRolloffFactor;
92 iDecayHFLimit = list.iDecayHFLimit;
93 }
94
95 static const EFXREVERBPROPERTIES_list EFX_Reverb_Defaults[EAX_ENVIRONMENT_COUNT] =
96 {
97 { "Generic", 1.0f, 1.0f, 0.316228f, 0.891251f, 1.0f, 1.49f, 0.83f, 1.0f, 0.050003f, 0.007f, {0.0f, 0.0f, 0.0f}, 1.258925f, 0.011f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
98 { "Padded cell", 0.171500f, 1.0f, 0.316228f, 0.001f, 1.0f, 0.17f, 0.10f, 1.0f, 0.250035f, 0.001f, {0.0f, 0.0f, 0.0f}, 1.269112f, 0.002f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
99 { "Room", 0.428687f, 1.0f, 0.316228f, 0.592925f, 1.0f, 0.40f, 0.83f, 1.0f, 0.150314f, 0.002f, {0.0f, 0.0f, 0.0f}, 1.062919f, 0.003f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
100 { "Bathroom", 0.171500f, 1.0f, 0.316228f, 0.251189f, 1.0f, 1.49f, 0.54f, 1.0f, 0.653131f, 0.007f, {0.0f, 0.0f, 0.0f}, 3.273407f, 0.011f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
101 { "Living room", 0.976563f, 1.0f, 0.316228f, 0.001f, 1.0f, 0.50f, 0.10f, 1.0f, 0.205116f, 0.003f, {0.0f, 0.0f, 0.0f}, 0.280543f, 0.004f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
102 { "Stone room", 1.0f, 1.0f, 0.316228f, 0.707946f, 1.0f, 2.31f, 0.64f, 1.0f, 0.441062f, 0.012f, {0.0f, 0.0f, 0.0f}, 1.100272f, 0.017f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
103 { "Auditorium", 1.0f, 1.0f, 0.316228f, 0.578096f, 1.0f, 4.32f, 0.59f, 1.0f, 0.403181f, 0.02f, {0.0f, 0.0f, 0.0f}, 0.716968f, 0.03f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
104 { "Concert hall", 1.0f, 1.0f, 0.316228f, 0.562341f, 1.0f, 3.92f, 0.70f, 1.0f, 0.242661f, 0.02f, {0.0f, 0.0f, 0.0f}, 0.997700f, 0.029f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
105 { "Cave", 1.0f, 1.0f, 0.316228f, 1.0f, 1.0f, 2.91f, 1.30f, 1.0f, 0.500035f, 0.015f, {0.0f, 0.0f, 0.0f}, 0.706318f, 0.022f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 0 },
106 { "Arena", 1.0f, 1.0f, 0.316228f, 0.447713f, 1.0f, 7.24f, 0.33f, 1.0f, 0.261216f, 0.02f, {0.0f, 0.0f, 0.0f}, 1.018591f, 0.03f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
107 { "Hangar", 1.0f, 1.0f, 0.316228f, 0.316228f, 1.0f, 10.05f, 0.23f, 1.0f, 0.500035f, 0.02f, {0.0f, 0.0f, 0.0f}, 1.256030f, 0.03f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
108 { "Carpeted hallway", 0.428687f, 1.0f, 0.316228f, 0.01f, 1.0f, 0.30f, 0.10f, 1.0f, 0.121479f, 0.002f, {0.0f, 0.0f, 0.0f}, 0.153109f, 0.03f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
109 { "Hallway", 0.364500f, 1.0f, 0.316228f, 0.707946f, 1.0f, 1.49f, 0.59f, 1.0f, 0.245754f, 0.007f, {0.0f, 0.0f, 0.0f}, 1.661499f, 0.011f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
110 { "Stone corridor", 1.0f, 1.0f, 0.316228f, 0.761202f, 1.0f, 2.70f, 0.79f, 1.0f, 0.247172f, 0.013f, {0.0f, 0.0f, 0.0f}, 1.575796f, 0.02f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
111 { "Alley", 1.0f, 0.30f, 0.316228f, 0.732825f, 1.0f, 1.49f, 0.86f, 1.0f, 0.250035f, 0.007f, {0.0f, 0.0f, 0.0f}, 0.995405f, 0.011f, {0.0f, 0.0f, 0.0f}, 0.125f, 0.95f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
112 { "Forest", 1.0f, 0.30f, 0.316228f, 0.022387f, 1.0f, 1.49f, 0.54f, 1.0f, 0.052481f, 0.162f, {0.0f, 0.0f, 0.0f}, 0.768245f, 0.088f, {0.0f, 0.0f, 0.0f}, 0.125f, 1.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
113 { "City", 1.0f, 0.50f, 0.316228f, 0.398107f, 1.0f, 1.49f, 0.67f, 1.0f, 0.073030f, 0.007f, {0.0f, 0.0f, 0.0f}, 0.142725f, 0.011f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
114 { "Mountains", 1.0f, 0.27f, 0.316228f, 0.056234f, 1.0f, 1.49f, 0.21f, 1.0f, 0.040738f, 0.30f, {0.0f, 0.0f, 0.0f}, 0.191867f, 0.10f, {0.0f, 0.0f, 0.0f}, 0.25f, 1.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 0 },
115 { "Quarry", 1.0f, 1.0f, 0.316228f, 0.316228f, 1.0f, 1.49f, 0.83f, 1.0f, 0.0f, 0.061f, {0.0f, 0.0f, 0.0f}, 1.778279f, 0.025f, {0.0f, 0.0f, 0.0f}, 0.125f, 0.70f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
116 { "Plain", 1.0f, 0.21f, 0.316228f, 0.10f, 1.0f, 1.49f, 0.50f, 1.0f, 0.058479f, 0.179f, {0.0f, 0.0f, 0.0f}, 0.108893f, 0.10f, {0.0f, 0.0f, 0.0f}, 0.25f, 1.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
117 { "Parking lot", 1.0f, 1.0f, 0.316228f, 1.0f, 1.0f, 1.65f, 1.50f, 1.0f, 0.208209f, 0.008f, {0.0f, 0.0f, 0.0f}, 0.265155f, 0.012f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 0 },
118 { "Sewer pipe", 0.307063f, 0.80f, 0.316228f, 0.316228f, 1.0f, 2.81f, 0.14f, 1.0f, 1.638702f, 0.014f, {0.0f, 0.0f, 0.0f}, 3.247133f, 0.021f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 0.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
119 { "Underwater", 0.364500f, 1.0f, 0.316228f, 0.01f, 1.0f, 1.49f, 0.10f, 1.0f, 0.596348f, 0.007f, {0.0f, 0.0f, 0.0f}, 7.079458f, 0.011f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 1.18f, 0.348f, 0.994260f, 5000.0f, 250.0f, 0.0f, 1 },
120 { "Drugged", 0.428687f, 0.50f, 0.316228f, 1.0f, 1.0f, 8.39f, 1.39f, 1.0f, 0.875992f, 0.002f, {0.0f, 0.0f, 0.0f}, 3.108136f, 0.03f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 0.25f, 1.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 0 },
121 { "Dizzy", 0.364500f, 0.60f, 0.316228f, 0.630957f, 1.0f, 17.23f, 0.56f, 1.0f, 0.139155f, 0.02f, {0.0f, 0.0f, 0.0f}, 0.493742f, 0.03f, {0.0f, 0.0f, 0.0f}, 0.25f, 1.0f, 0.81f, 0.31f, 0.994260f, 5000.0f, 250.0f, 0.0f, 0 },
122 { "Psychotic", 0.062500f, 0.50f, 0.316228f, 0.840427f, 1.0f, 7.56f, 0.91f, 1.0f, 0.486407f, 0.02f, {0.0f, 0.0f, 0.0f}, 2.437811f, 0.03f, {0.0f, 0.0f, 0.0f}, 0.25f, 0.0f, 4.00f, 1.0f, 0.994260f, 5000.0f, 250.0f, 0.0f, 0 }
123 };
124
125 SCP_vector<EFXREVERBPROPERTIES> EFX_presets;
126
127
128 typedef ALvoid (AL_APIENTRY * ALGENFILTERS) (ALsizei, ALuint*);
129 typedef ALvoid (AL_APIENTRY * ALDELETEFILTERS) (ALsizei, ALuint*);
130 typedef ALvoid (AL_APIENTRY * ALFILTERI) (ALuint, ALenum, ALint);
131 typedef ALvoid (AL_APIENTRY * ALGENEFFECTS) (ALsizei, ALuint*);
132 typedef ALvoid (AL_APIENTRY * ALDELETEEFFECTS) (ALsizei, ALuint*);
133 typedef ALvoid (AL_APIENTRY * ALEFFECTI) (ALuint, ALenum, ALint);
134 typedef ALvoid (AL_APIENTRY * ALEFFECTF) (ALuint, ALenum, ALfloat);
135 typedef ALvoid (AL_APIENTRY * ALEFFECTFV) (ALuint, ALenum, ALfloat*);
136 typedef ALvoid (AL_APIENTRY * ALGETEFFECTF) (ALuint, ALenum, ALfloat*);
137 typedef ALvoid (AL_APIENTRY * ALGENAUXILIARYEFFECTSLOTS) (ALsizei, ALuint*);
138 typedef ALvoid (AL_APIENTRY * ALDELETEAUXILIARYEFFECTSLOTS) (ALsizei, ALuint*);
139 typedef ALboolean (AL_APIENTRY * ALISAUXILIARYEFFECTSLOT) (ALuint);
140 typedef ALvoid (AL_APIENTRY * ALAUXILIARYEFFECTSLOTI) (ALuint, ALenum, ALint);
141 typedef ALvoid (AL_APIENTRY * ALAUXILIARYEFFECTSLOTIV) (ALuint, ALenum, ALint*);
142 typedef ALvoid (AL_APIENTRY * ALAUXILIARYEFFECTSLOTF) (ALuint, ALenum, ALfloat);
143 typedef ALvoid (AL_APIENTRY * ALAUXILIARYEFFECTSLOTFV) (ALuint, ALenum, ALfloat*);
144
145
146 ALGENFILTERS v_alGenFilters = NULL;
147 ALDELETEFILTERS v_alDeleteFilters = NULL;
148
149 ALFILTERI v_alFilteri = NULL;
150
151 ALGENEFFECTS v_alGenEffecs = NULL;
152 ALDELETEEFFECTS v_alDeleteEffects = NULL;
153
154 ALEFFECTI v_alEffecti = NULL;
155 ALEFFECTF v_alEffectf = NULL;
156 ALEFFECTFV v_alEffectfv = NULL;
157 ALGETEFFECTF v_alGetEffectf = NULL;
158
159 ALGENAUXILIARYEFFECTSLOTS v_alGenAuxiliaryEffectSlots = NULL;
160 ALDELETEAUXILIARYEFFECTSLOTS v_alDeleteAuxiliaryEffectSlots = NULL;
161
162 ALISAUXILIARYEFFECTSLOT v_alIsAuxiliaryEffectSlot = NULL;
163 ALAUXILIARYEFFECTSLOTI v_alAuxiliaryEffectSloti = NULL;
164 ALAUXILIARYEFFECTSLOTIV v_alAuxiliaryEffectSlotiv = NULL;
165 ALAUXILIARYEFFECTSLOTF v_alAuxiliaryEffectSlotf = NULL;
166 ALAUXILIARYEFFECTSLOTFV v_alAuxiliaryEffectSlotfv = NULL;
167
168 ALCdevice *ds_sound_device = NULL;
169 ALCcontext *ds_sound_context = NULL;
170
171 ALuint AL_EFX_aux_id = 0;
172
173 static ALuint AL_EFX_effect_id = 0;
174 static bool Ds_active_env = false;
175 static size_t Ds_active_env_idx = 0;
176
177
al_load_function(const char * func_name)178 static void *al_load_function(const char *func_name)
179 {
180 void *func = alGetProcAddress(func_name);
181 if ( !func ) {
182 throw std::runtime_error(func_name);
183 }
184 return func;
185 }
186
al_efx_load_preset(size_t presetid)187 static void al_efx_load_preset(size_t presetid)
188 {
189 if ( !Ds_eax_inited ) {
190 return;
191 }
192
193 if (presetid >= EFX_presets.size()) {
194 return;
195 }
196
197 EFXREVERBPROPERTIES *prop = &EFX_presets[presetid];
198
199 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DENSITY, prop->flDensity) );
200 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DIFFUSION, prop->flDiffusion) );
201 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAIN, prop->flGain) );
202 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAINHF, prop->flGainHF) );
203 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAINLF, prop->flGainLF) );
204 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_TIME, prop->flDecayTime) );
205 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFRATIO, prop->flDecayHFRatio) );
206 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_LFRATIO, prop->flDecayLFRatio) );
207 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_REFLECTIONS_GAIN, prop->flReflectionsGain) );
208 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_REFLECTIONS_DELAY, prop->flReflectionsDelay) );
209 OpenAL_ErrorPrint( v_alEffectfv(AL_EFX_effect_id, AL_EAXREVERB_REFLECTIONS_PAN, prop->flReflectionsPan) );
210 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_LATE_REVERB_GAIN, prop->flLateReverbGain) );
211 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_LATE_REVERB_DELAY, prop->flLateReverbDelay) );
212 OpenAL_ErrorPrint( v_alEffectfv(AL_EFX_effect_id, AL_EAXREVERB_LATE_REVERB_PAN, prop->flLateReverbPan) );
213 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_ECHO_TIME, prop->flEchoTime) );
214 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_ECHO_DEPTH, prop->flEchoDepth) );
215 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_MODULATION_TIME, prop->flModulationTime) );
216 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_MODULATION_DEPTH, prop->flModulationDepth) );
217 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, prop->flAirAbsorptionGainHF) );
218 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_HFREFERENCE, prop->flHFReference) );
219 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_LFREFERENCE, prop->flLFReference) );
220 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, prop->flRoomRolloffFactor) );
221 OpenAL_ErrorPrint( v_alEffecti(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFLIMIT, prop->iDecayHFLimit) );
222
223 Ds_active_env_idx = presetid;
224 Ds_active_env = true;
225 }
226
227
228 int ds_initialized = FALSE;
229
230 /**
231 *
232 */
ds_get_sid()233 int ds_get_sid()
234 {
235 sound_buffer new_buffer;
236 uint i;
237
238 for (i = 0; i < sound_buffers.size(); i++) {
239 if (sound_buffers[i].buf_id == 0) {
240 return (int)i;
241 }
242 }
243
244 sound_buffers.push_back( new_buffer );
245
246 return (int)(sound_buffers.size() - 1);
247 }
248
ds_load_buffer(int * sid,int,sound::IAudioFile * file)249 int ds_load_buffer(int *sid, int /*flags*/, sound::IAudioFile* file)
250 {
251 Assert(sid != NULL);
252 Assert(file != NULL);
253
254 // All sounds are required to have a software buffer
255 *sid = ds_get_sid();
256 if (*sid == -1) {
257 nprintf(("Sound", "SOUND ==> No more sound buffers available\n"));
258 return -1;
259 }
260
261 ALuint pi;
262 OpenAL_ErrorCheck(alGenBuffers(1, &pi), return -1);
263
264 const auto fileProps = file->getFileProperties();
265
266 ALenum format;
267 ALsizei size = fileProps.total_samples * fileProps.bytes_per_sample * fileProps.num_channels;
268 ALint n_channels = fileProps.num_channels;
269 ALsizei frequency;
270
271 // format is now in pcm
272 frequency = fileProps.sample_rate;
273 format = openal_get_format(fileProps.bytes_per_sample * 8, fileProps.num_channels);
274
275 if (format == AL_INVALID_VALUE) {
276 return -1;
277 }
278
279 SCP_vector<uint8_t> audio_buffer;
280 audio_buffer.reserve(size);
281
282 SCP_vector<uint8_t> buffer(fileProps.sample_rate * fileProps.bytes_per_sample * fileProps.num_channels);
283 int read;
284 while((read = file->Read(&buffer[0], buffer.size())) >= 0) {
285 if (read == 0) {
286 // buffer not large enough
287 buffer.resize(buffer.size() * 2);
288 } else {
289 audio_buffer.insert(audio_buffer.end(), buffer.begin(), std::next(buffer.begin(), read));
290 }
291 }
292
293 Snd_sram += audio_buffer.size();
294
295 OpenAL_ErrorCheck(alBufferData(pi, format, audio_buffer.data(), (ALsizei)audio_buffer.size(), frequency), return -1; );
296
297 sound_buffers[*sid].buf_id = pi;
298 sound_buffers[*sid].channel_id = -1;
299 sound_buffers[*sid].frequency = frequency;
300 sound_buffers[*sid].bits_per_sample = fileProps.bytes_per_sample * 8;
301 sound_buffers[*sid].nchannels = n_channels;
302 sound_buffers[*sid].nseconds = fl2i(fileProps.duration);
303 sound_buffers[*sid].nbytes = (int)audio_buffer.size();
304
305 return 0;
306 }
307
308 /**
309 * Initialise the ::Channels[] array
310 */
ds_init_channels()311 void ds_init_channels()
312 {
313 MAX_CHANNELS = Cmdline_no_enhanced_sound ? 32 : 128;
314
315 try {
316 Channels = new channel[MAX_CHANNELS];
317 } catch (const std::bad_alloc&) {
318 Error(LOCATION, "Unable to allocate " SIZE_T_ARG " bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
319 }
320 }
321
322 /**
323 * Initialise the both the software and hardware buffers
324 */
ds_init_buffers()325 void ds_init_buffers()
326 {
327 sound_buffers.clear();
328
329 // pre-allocate for at least BUFFER_BUMP buffers
330 sound_buffers.reserve( BUFFER_BUMP );
331 }
332
333 /**
334 * Check if the player is using OpenAL Soft,
335 * which is required to use enhanced sound.
336 * Returns true on success, false otherwise.
337 */
ds_check_for_openal_soft()338 bool ds_check_for_openal_soft()
339 {
340 const ALchar * renderer = alGetString(AL_RENDERER);
341 if (renderer == NULL)
342 {
343 mprintf(("ds_check_for_openal_soft: renderer is null!\n"));
344 return false;
345 }
346 else if (!stricmp((const char *)renderer, "OpenAL Soft"))
347 {
348 return true;
349 }
350 else
351 {
352 return false;
353 }
354 }
355
356 /**
357 * Sound initialisation
358 * @return -1 if init failed, 0 if init success
359 */
ds_init()360 int ds_init()
361 {
362 ALfloat list_orien[] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f };
363 ALCint attrList[] = { ALC_FREQUENCY, 22050, 0 };
364 unsigned int sample_rate = 22050;
365
366 mprintf(("Initializing OpenAL...\n"));
367
368 Ds_sound_quality = os_config_read_uint("Sound", "Quality", DS_SQ_MEDIUM);
369 CLAMP(Ds_sound_quality, DS_SQ_LOW, DS_SQ_HIGH);
370
371 switch (Ds_sound_quality) {
372 case DS_SQ_HIGH:
373 sample_rate = 48000;
374 break;
375
376 case DS_SQ_MEDIUM:
377 sample_rate = 44100;
378 break;
379
380 default:
381 sample_rate = 22050;
382 break;
383 }
384
385 sample_rate = os_config_read_uint("Sound", "SampleRate", sample_rate);
386 attrList[1] = sample_rate;
387 SCP_string playback_device;
388 SCP_string capture_device;
389
390 if ( openal_init_device(&playback_device, &capture_device) == false ) {
391 mprintf(("\n ERROR: Unable to find suitable playback device!\n\n"));
392 goto AL_InitError;
393 }
394
395 ds_sound_device = alcOpenDevice( (const ALCchar*) playback_device.c_str() );
396
397 if (ds_sound_device == NULL) {
398 mprintf((" Failed to open playback_device (%s) returning error (%s)\n", playback_device.c_str(), openal_error_string(1)));
399 goto AL_InitError;
400 }
401
402 ds_sound_context = alcCreateContext(ds_sound_device, attrList);
403
404 if (ds_sound_context == NULL) {
405 mprintf((" Failed to create context for playback_device (%s) with attrList = { 0x%x, %d, %d } returning error (%s)\n",
406 playback_device.c_str(), attrList[0], attrList[1], attrList[2], openal_error_string(1)));
407 goto AL_InitError;
408 }
409
410 alcMakeContextCurrent(ds_sound_context);
411
412 alcGetError(ds_sound_device);
413
414 mprintf((" OpenAL Vendor : %s\n", alGetString(AL_VENDOR)));
415 mprintf((" OpenAL Renderer : %s\n", alGetString(AL_RENDERER)));
416 mprintf((" OpenAL Version : %s\n", alGetString(AL_VERSION)));
417 mprintf(("\n"));
418
419 // we need to clear out all errors before moving on
420 alcGetError(NULL);
421 alGetError();
422
423 // set distance model to basically match what the D3D code does
424 alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
425
426 // make sure we can actually use AL_BYTE_LOKI (Mac/Win OpenAL doesn't have it)
427 if ( alIsExtensionPresent( (const ALchar*)"AL_LOKI_play_position" ) == AL_TRUE ) {
428 mprintf((" Found extension \"AL_LOKI_play_position\".\n"));
429 AL_play_position = 1;
430 }
431
432 if ( alIsExtensionPresent( (const ALchar*)"AL_EXT_float32" ) == AL_TRUE ) {
433 mprintf((" Found extension \"AL_EXT_float32\".\n"));
434 Ds_float_supported = 1;
435 }
436
437 Ds_use_eax = 0;
438
439 if ( alcIsExtensionPresent(ds_sound_device, (const ALchar*)"ALC_EXT_EFX") == AL_TRUE ) {
440 mprintf((" Found extension \"ALC_EXT_EFX\".\n"));
441 Ds_use_eax = os_config_read_uint("Sound", "EnableEFX", Fred_running);
442 }
443
444 if (Ds_use_eax == 1) {
445 if (ds_eax_init() != 0) {
446 Ds_use_eax = 0;
447 }
448 }
449
450 // the presets always need to be available to FRED
451 if ( !Ds_use_eax && Fred_running ) {
452 EFX_presets.reserve(EAX_ENVIRONMENT_COUNT);
453
454 for (size_t i = 0; i < EAX_ENVIRONMENT_COUNT; i++) {
455 EFX_presets.push_back( EFX_Reverb_Defaults[i] );
456 }
457 }
458
459 if (!Cmdline_no_enhanced_sound)
460 {
461 if (!ds_check_for_openal_soft())
462 {
463 mprintf(("You are not using OpenAL Soft. Disabling enhanced sound.\n"));
464 Cmdline_no_enhanced_sound = 1;
465 }
466 else
467 {
468 mprintf(("Enhanced sound is enabled.\n"));
469 }
470 }
471 else
472 {
473 mprintf(("Enhanced sound is manually disabled.\n"));
474 }
475
476 // setup default listener position/orientation
477 // this is needed for 2D pan
478 OpenAL_ErrorPrint( alListener3f(AL_POSITION, 0.0, 0.0, 0.0) );
479 OpenAL_ErrorPrint( alListenerfv(AL_ORIENTATION, list_orien) );
480
481 // disable doppler (FIXME)
482 OpenAL_ErrorPrint( alDopplerFactor(0.0f) );
483
484 ds_init_channels();
485 ds_init_buffers();
486
487 mprintf(("\n"));
488
489 {
490 ALCint freq = 0;
491 OpenAL_ErrorPrint( alcGetIntegerv(ds_sound_device, ALC_FREQUENCY, sizeof(ALCint), &freq) );
492
493 mprintf((" Sample rate: %d (%d)\n", freq, sample_rate));
494 }
495
496 if (Ds_use_eax) {
497 ALCint major = 0, minor = 0, max_sends = 0;
498
499 alcGetIntegerv(ds_sound_device, ALC_EFX_MAJOR_VERSION, 1, &major);
500 alcGetIntegerv(ds_sound_device, ALC_EFX_MINOR_VERSION, 1, &minor);
501 alcGetIntegerv(ds_sound_device, ALC_MAX_AUXILIARY_SENDS, 1, &max_sends);
502
503 mprintf((" EFX version: %d.%d\n", (int)major, (int)minor));
504 mprintf((" Max auxiliary sends: %d\n", max_sends));
505 } else {
506 mprintf((" EFX enabled: NO\n"));
507 }
508
509 mprintf((" Playback device: %s\n", playback_device.c_str()));
510 mprintf((" Capture device: %s\n", (capture_device.empty()) ? "<not available>" : capture_device.c_str()));
511
512 mprintf(("... OpenAL successfully initialized!\n"));
513
514 // we need to clear out any errors before moving on
515 alcGetError(NULL);
516 alGetError();
517
518 return 0;
519
520 AL_InitError:
521 alcMakeContextCurrent(NULL);
522
523 if (ds_sound_context != NULL) {
524 alcDestroyContext(ds_sound_context);
525 ds_sound_context = NULL;
526 }
527
528 if (ds_sound_device != NULL) {
529 alcCloseDevice(ds_sound_device);
530 ds_sound_device = NULL;
531 }
532
533 mprintf(("... OpenAL failed to initialize!\n"));
534
535 return -1;
536 }
537
538 /**
539 * Free a single channel
540 */
ds_close_channel(int i)541 void ds_close_channel(int i)
542 {
543 if ( (i < 0) || (i >= MAX_CHANNELS) ) {
544 return;
545 }
546
547 if ( (Channels[i].source_id != 0) && alIsSource(Channels[i].source_id) ) {
548 OpenAL_ErrorPrint( alSourceStop(Channels[i].source_id) );
549 OpenAL_ErrorPrint( alSourcei(Channels[i].source_id, AL_BUFFER, 0) );
550
551 if (Ds_eax_inited) {
552 OpenAL_ErrorPrint( alSource3i(Channels[i].source_id, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL) );
553 }
554
555 OpenAL_ErrorPrint( alDeleteSources(1, &Channels[i].source_id) );
556
557 if (Channels[i].sid >= 0) {
558 sound_buffers[Channels[i].sid].channel_id = -1;
559 }
560
561 Channels[i].source_id = 0;
562 Channels[i].sid = -1;
563 Channels[i].sig = ds_sound_handle::invalid();
564 Channels[i].snd_id = -1;
565 }
566 }
567
ds_close_channel_fast(int i)568 void ds_close_channel_fast(int i)
569 {
570 if ( (i < 0) || (i >= MAX_CHANNELS) ) {
571 return;
572 }
573
574 if ( (Channels[i].source_id != 0) && alIsSource(Channels[i].source_id) ) {
575 OpenAL_ErrorPrint( alSourceStop(Channels[i].source_id) );
576 OpenAL_ErrorPrint( alSourcei(Channels[i].source_id, AL_BUFFER, 0) );
577
578 if (Ds_eax_inited) {
579 OpenAL_ErrorPrint( alSource3i(Channels[i].source_id, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL) );
580 }
581
582 if (Channels[i].sid >= 0) {
583 sound_buffers[Channels[i].sid].channel_id = -1;
584 }
585
586 Channels[i].sid = -1;
587 Channels[i].sig = ds_sound_handle::invalid();
588 Channels[i].snd_id = -1;
589 }
590 }
591
592 /**
593 * Free all the channel buffers
594 */
ds_close_all_channels()595 void ds_close_all_channels()
596 {
597 int i;
598
599 for (i = 0; i < MAX_CHANNELS; i++) {
600 ds_close_channel(i);
601 }
602 }
603
604 /**
605 * Unload a buffer
606 */
ds_unload_buffer(int sid)607 void ds_unload_buffer(int sid)
608 {
609 if ( (sid < 0) || ((size_t)sid >= sound_buffers.size()) ) {
610 return;
611 }
612
613 if (sound_buffers[sid].channel_id >= 0) {
614 ds_close_channel_fast(sound_buffers[sid].channel_id);
615 sound_buffers[sid].channel_id = -1;
616 }
617
618 ALuint buf_id = sound_buffers[sid].buf_id;
619
620 if ( (buf_id != 0) && alIsBuffer(buf_id) ) {
621 OpenAL_ErrorCheck( alDeleteBuffers(1, &buf_id), return );
622 }
623
624 sound_buffers[sid].buf_id = 0;
625 }
626
627 /**
628 * Unload all the channel buffers
629 */
ds_close_buffers()630 void ds_close_buffers()
631 {
632 size_t i;
633
634 for (i = 0; i < sound_buffers.size(); i++) {
635 ds_unload_buffer((int)i);
636 }
637
638 sound_buffers.clear();
639 }
640
641 /**
642 * Close the sound system
643 */
ds_close()644 void ds_close()
645 {
646 ds_close_all_channels();
647 ds_close_buffers();
648 ds_eax_close();
649
650 // free the Channels[] array, since it was dynamically allocated
651 delete [] Channels;
652 Channels = NULL;
653
654 alcMakeContextCurrent(NULL); // hangs on me for some reason
655
656 if (ds_sound_context != NULL) {
657 alcDestroyContext(ds_sound_context);
658 ds_sound_context = NULL;
659 }
660
661 if (ds_sound_device != NULL) {
662 alcCloseDevice(ds_sound_device);
663 ds_sound_device = NULL;
664 }
665 }
666
667
668 /**
669 * Find a free channel to play a sound on. If no free channels exists, free up one based on volume levels.
670 * This is the original retail version of ds_get_free_channel().
671 *
672 * @param new_volume Volume for sound to play at
673 * @param snd_id Which kind of sound to play
674 * @param priority ::DS_MUST_PLAY, ::DS_LIMIT_ONE, ::DS_LIMIT_TWO, ::DS_LIMIT_THREE
675 *
676 * @returns Channel number to play sound on, or -1 if no channel could be found
677 *
678 * NOTE: snd_id is needed since we limit the number of concurrent samples
679 */
ds_get_free_channel_retail(float new_volume,int snd_id,int priority)680 int ds_get_free_channel_retail(float new_volume, int snd_id, int priority)
681 {
682 int i, first_free_channel, limit = 100;
683 int instance_count; // number of instances of sound already playing
684 int lowest_vol_index = -1, lowest_instance_vol_index = -1;
685 float lowest_vol = 1.0f, lowest_instance_vol = 1.0f;
686 channel *chp;
687 int status;
688
689 instance_count = 0;
690 first_free_channel = -1;
691
692 // determine the limit of concurrent instances of this sound
693 switch (priority) {
694 case DS_MUST_PLAY:
695 limit = 100;
696 break;
697
698 case DS_LIMIT_ONE:
699 limit = 1;
700 break;
701
702 case DS_LIMIT_TWO:
703 limit = 2;
704 break;
705
706 case DS_LIMIT_THREE:
707 limit = 3;
708 break;
709
710 default:
711 Int3(); // get Alan
712 limit = 100;
713 break;
714 }
715
716 // Look for a channel to use to play this sample
717 for ( i = 0; i < MAX_CHANNELS; i++ ) {
718 chp = &Channels[i];
719
720 // source not created yet
721 if (chp->source_id == 0) {
722 if (first_free_channel == -1) {
723 first_free_channel = i;
724 }
725 continue;
726 }
727
728 // source not bound to a buffer
729 if (chp->sid == -1) {
730 if (first_free_channel == -1) {
731 first_free_channel = i;
732 }
733 continue;
734 }
735
736 OpenAL_ErrorCheck( alGetSourcei(chp->source_id, AL_SOURCE_STATE, &status), continue );
737
738 if ( (status == AL_INITIAL) || (status == AL_STOPPED) ) {
739 ds_close_channel_fast(i);
740
741 if (first_free_channel == -1) {
742 first_free_channel = i;
743 }
744 continue;
745 } else {
746 if ( chp->snd_id == snd_id ) {
747 instance_count++;
748 if ( (chp->vol < lowest_instance_vol) && (chp->looping == FALSE) ) {
749 lowest_instance_vol = chp->vol;
750 lowest_instance_vol_index = i;
751 }
752 } else if ( chp->is_voice_msg ) {
753 // a playing voice message is not allowed to be preempted.
754 } else if ( (chp->vol < lowest_vol) && (chp->looping == FALSE) ) {
755 lowest_vol_index = i;
756 lowest_vol = chp->vol;
757 }
758 }
759 }
760
761 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
762 if ( (instance_count >= limit) && (lowest_instance_vol_index >= 0) ) {
763 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
764 if (lowest_instance_vol <= new_volume) {
765 ds_close_channel_fast(lowest_instance_vol_index);
766 first_free_channel = lowest_instance_vol_index;
767 } else {
768 // NOTE: yes we are preventing the sound from playing even if
769 // there is an available channel because we are over the limit
770 // requested by the rest of the engine, which means if we do
771 // not honour its request to limit the count then the engine
772 // will trip itself up by using all channels without having
773 // the intention of actually doing so. This means we get
774 // very loud sounds, missing more important sounds, etc.
775 // Effectivly the problem is the rest of the engine assumes
776 // it is still stuck in the 90s with a sound card that only has
777 // <=16 channels so we need to give it a sound card that
778 // has 16 channels (though we are actually allowing 32 channels
779 // just because we can).
780 first_free_channel = -1;
781 }
782 } else if (first_free_channel == -1) {
783 // there is no limit barrier to play the sound, but we have run out of channels
784 // stop the lowest volume instance to play our sound if priority demands it
785 if ( (lowest_vol_index != -1) && (priority == DS_MUST_PLAY) ) {
786 // Check if the lowest volume playing is less than the volume of the requested sound.
787 // If so, then we are going to trash the lowest volume sound.
788 if ( Channels[lowest_vol_index].vol <= new_volume ) {
789 ds_close_channel_fast(lowest_vol_index);
790 first_free_channel = lowest_vol_index;
791 }
792 }
793 }
794
795 if ( (first_free_channel >= 0) && (Channels[first_free_channel].source_id == 0) ) {
796 OpenAL_ErrorCheck( alGenSources(1, &Channels[first_free_channel].source_id), return -1 );
797 }
798 return first_free_channel;
799 }
800
801 /**
802 * Find a free channel to play a sound on. If no free channels exists, free up one based on priority and volume levels.
803 * Special version for enhanced mode.
804 *
805 * @param new_volume Volume for sound to play at
806 * @param snd_id Which kind of sound to play
807 * @param enhanced_priority Priority level, see EnhancedSoundPriority enum in gamesnd.h
808 * @param enhanced_limit Per-sound concurrency limit
809 *
810 * @returns Channel number to play sound on, or -1 if no channel could be found
811 *
812 * NOTE: snd_id is needed since we limit the number of concurrent samples
813 */
ds_get_free_channel_enhanced(float new_volume,int snd_id,int enhanced_priority,unsigned int enhanced_limit)814 int ds_get_free_channel_enhanced(float new_volume, int snd_id, int enhanced_priority, unsigned int enhanced_limit)
815 {
816 int i, first_free_channel;
817 int instance_count; // number of instances of sound already playing
818 // least important means lowest volume among lowest priority
819 // note that higher priority value means lower priority
820 int least_important_index = -1, least_important_instance_index = -1;
821 float least_important_vol = 1.1f, least_important_instance_vol = 1.1f;
822 int least_important_priority = -1, least_important_instance_priority = -1;
823 channel *chp;
824 int status;
825
826 instance_count = 0;
827 first_free_channel = -1;
828
829 // Look for a channel to use to play this sample
830 for ( i = 0; i < MAX_CHANNELS; i++ ) {
831 chp = &Channels[i];
832
833 // source not created yet
834 if (chp->source_id == 0) {
835 if (first_free_channel == -1) {
836 first_free_channel = i;
837 }
838 continue;
839 }
840
841 // source not bound to a buffer
842 if (chp->sid == -1) {
843 if (first_free_channel == -1) {
844 first_free_channel = i;
845 }
846 continue;
847 }
848
849 OpenAL_ErrorCheck( alGetSourcei(chp->source_id, AL_SOURCE_STATE, &status), continue );
850
851 if ( (status == AL_INITIAL) || (status == AL_STOPPED) ) {
852 ds_close_channel_fast(i);
853
854 if (first_free_channel == -1) {
855 first_free_channel = i;
856 }
857 continue;
858 } else {
859 if ( chp->snd_id == snd_id ) {
860 instance_count++;
861
862 // looping or ambient soudns can't be preempted
863 if ((chp->looping == FALSE) && !chp->is_ambient)
864 {
865 if (chp->priority > least_important_instance_priority) {
866 least_important_instance_vol = chp->vol;
867 least_important_instance_priority = chp->priority;
868 least_important_instance_index = i;
869 } else if ((chp->priority == least_important_instance_priority)
870 && (chp->vol < least_important_instance_vol)) {
871 least_important_instance_vol = chp->vol;
872 least_important_instance_priority = chp->priority;
873 least_important_instance_index = i;
874 }
875 }
876 } else if ( chp->is_voice_msg || (chp->looping == TRUE) || chp->is_ambient ) {
877 // a playing voice message, looping sound, or ambient sound is not allowed to be preempted.
878 } else if ( (chp->priority > least_important_priority) ) {
879 least_important_index = i;
880 least_important_vol = chp->vol;
881 least_important_priority = chp->priority;
882 } else if ( (chp->priority == least_important_priority) && (chp->vol < least_important_vol) ) {
883 least_important_index = i;
884 least_important_vol = chp->vol;
885 least_important_priority = chp->priority;
886 }
887 }
888 }
889
890 // If we've exceeded the limit, then stop the least important duplicate if it is lower or equal volume
891 // otherwise, don't play the sound
892 if ( ((unsigned int)instance_count >= enhanced_limit) && (least_important_instance_index >= 0) ) {
893 if (least_important_instance_vol <= new_volume) {
894 ds_close_channel_fast(least_important_instance_index);
895 first_free_channel =least_important_instance_index;
896 } else {
897 // don't exceed per-sound concurrency limits, even if there are spare channels
898 first_free_channel = -1;
899 }
900 } else if (first_free_channel == -1) {
901 // we haven't reached the limit, but we have run out of channels
902 // attempt to stop the least important sound to play our sound if priority demands it
903 if ( (least_important_index != -1)) {
904 // Check if the priority difference is great enough (must play or at least 2 levels away)
905 // and if the least important sound's volume playing is less than or equal to the volume of the requested sound.
906 // If so, then we are going to trash the least important sound.
907 if ( (enhanced_priority == SND_ENHANCED_PRIORITY_MUST_PLAY) || (Channels[least_important_index].priority - enhanced_priority >= 2)) {
908 if ( Channels[least_important_index].vol <= new_volume ) {
909 ds_close_channel_fast(least_important_index);
910 first_free_channel = least_important_index;
911 }
912 }
913 }
914 }
915
916 if ( (first_free_channel >= 0) && (Channels[first_free_channel].source_id == 0) ) {
917 OpenAL_ErrorCheck( alGenSources(1, &Channels[first_free_channel].source_id), return -1 );
918 }
919 return first_free_channel;
920 }
921
922 /**
923 * Generic function for getting a free channel
924 * If enhanced soudn is used, set priority to the computed priority.
925 * Returns -1 if no free channel could be found.
926 */
927
928 /**
929 * Find a free channel to play a sound on. If no free channels exists, free up one based on volume levels.
930 * This is the new generic version of ds_get_free_channel().
931 *
932 * @param new_volume Volume for sound to play at
933 * @param snd_id Which kind of sound to play
934 * @param priority From retail :DS_MUST_PLAY, ::DS_LIMIT_ONE, ::DS_LIMIT_TWO, ::DS_LIMIT_THREE
935 * @param enhanced_priority Output param that's updated with correct priority if enhanced sound is enabled
936 *
937 * @returns Channel number to play sound on, or -1 if no channel could be found
938 *
939 * NOTE: snd_id is needed since we limit the number of concurrent samples
940 */
ds_get_free_channel(float volume,int snd_id,int priority,int & enhanced_priority,const EnhancedSoundData & enhanced_sound_data)941 int ds_get_free_channel(float volume, int snd_id, int priority, int & enhanced_priority, const EnhancedSoundData & enhanced_sound_data)
942 {
943 int first_free_channel = -1;
944 unsigned int enhanced_limit = 0;
945
946 if (!Cmdline_no_enhanced_sound) {
947 enhanced_priority = enhanced_sound_data.priority;
948 enhanced_limit = enhanced_sound_data.limit;
949
950 // exception: if retail priority is must play, we assume it's for a good reason
951 // and thus follow suit with enhanced sound
952 if (priority == DS_MUST_PLAY) {
953 enhanced_priority = SND_ENHANCED_PRIORITY_MUST_PLAY;
954 }
955
956 first_free_channel = ds_get_free_channel_enhanced(volume, snd_id, enhanced_priority, enhanced_limit);
957 } else { // enhanced sound is off
958 first_free_channel = ds_get_free_channel_retail(volume, snd_id, priority);
959 }
960
961 return first_free_channel;
962 }
963
964 /**
965 * Create a sound buffer in software, without locking any data in
966 */
ds_create_buffer(int frequency,int bits_per_sample,int nchannels,int nseconds)967 int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
968 {
969 ALuint i;
970 int sid;
971
972 if (!ds_initialized) {
973 return -1;
974 }
975
976 sid = ds_get_sid();
977 if ( sid == -1 ) {
978 nprintf(("Sound","SOUND ==> No more OpenAL buffers available\n"));
979 return -1;
980 }
981
982 OpenAL_ErrorCheck( alGenBuffers(1, &i), return -1 );
983
984 sound_buffers[sid].buf_id = i;
985 sound_buffers[sid].channel_id = -1;
986 sound_buffers[sid].frequency = frequency;
987 sound_buffers[sid].bits_per_sample = bits_per_sample;
988 sound_buffers[sid].nchannels = nchannels;
989 sound_buffers[sid].nseconds = nseconds;
990 sound_buffers[sid].nbytes = nseconds * (bits_per_sample / 8) * nchannels * frequency;
991
992 return sid;
993 }
994
995 /**
996 * Lock data into an existing buffer
997 */
ds_lock_data(int sid,unsigned char * data,int size)998 int ds_lock_data(int sid, unsigned char *data, int size)
999 {
1000 if ( (sid < 0) || ((size_t)sid >= sound_buffers.size()) ) {
1001 return -1;
1002 }
1003
1004 ALenum format = openal_get_format(sound_buffers[sid].bits_per_sample, sound_buffers[sid].nchannels);
1005
1006 if (format == AL_INVALID_VALUE) {
1007 return -1;
1008 }
1009
1010 sound_buffers[sid].nbytes = size;
1011
1012 OpenAL_ErrorCheck( alBufferData(sound_buffers[sid].buf_id, format, data, size, sound_buffers[sid].frequency), return -1 );
1013
1014 return 0;
1015 }
1016
1017 /**
1018 * Stop a buffer from playing directly
1019 */
ds_stop_easy(int sid)1020 void ds_stop_easy(int sid)
1021 {
1022 Assert(sid >= 0);
1023
1024 int cid = sound_buffers[sid].channel_id;
1025
1026 if (cid != -1) {
1027 ALuint source_id = Channels[cid].source_id;
1028 OpenAL_ErrorPrint( alSourceStop(source_id) );
1029 }
1030 }
1031
1032 /**
1033 * Play a sound secondary buffer.
1034 *
1035 * @param sid Software id of sound
1036 * @param snd_id What kind of sound this is
1037 * @param priority ::DS_MUST_PLAY, ::DS_LIMIT_ONE, ::DS_LIMIT_TWO, ::DS_LIMIT_THREE
1038 * @param volume Volume of sound effect in DirectSound units
1039 * @param pan Pan of sound in sound units
1040 * @param looping Whether the sound effect is looping or not
1041 * @param is_voice_msg If a voice message
1042 *
1043 * @return 1 if sound effect could not be started, >=0 sig for sound effect successfully started
1044 */
ds_play(int sid,int snd_id,int priority,const EnhancedSoundData * enhanced_sound_data,float volume,float pan,int looping,bool is_voice_msg)1045 ds_sound_handle ds_play(int sid, int snd_id, int priority, const EnhancedSoundData* enhanced_sound_data, float volume,
1046 float pan, int looping, bool is_voice_msg)
1047 {
1048 int ch_idx;
1049 int enhanced_priority = SND_ENHANCED_PRIORITY_INVALID;
1050
1051 if (!ds_initialized) {
1052 return ds_sound_handle::invalid();
1053 }
1054
1055 ch_idx = ds_get_free_channel(volume, snd_id, priority, enhanced_priority, *enhanced_sound_data);
1056
1057 if (ch_idx < 0) {
1058 return ds_sound_handle::invalid();
1059 }
1060
1061 if (Channels[ch_idx].source_id == 0) {
1062 return ds_sound_handle::invalid();
1063 }
1064
1065 if (pan) {
1066 OpenAL_ErrorPrint( alSource3f(Channels[ch_idx].source_id, AL_POSITION, pan, 0.0f, -1.0f) );
1067 } else {
1068 OpenAL_ErrorPrint( alSource3f(Channels[ch_idx].source_id, AL_POSITION, 0.0f, 0.0f, 0.0f) );
1069 }
1070
1071 OpenAL_ErrorPrint( alSource3f(Channels[ch_idx].source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f) );
1072
1073 OpenAL_ErrorPrint( alDopplerFactor(0.0f) );
1074 OpenAL_ErrorPrint( alSourcef(Channels[ch_idx].source_id, AL_PITCH, 1.0f) );
1075 OpenAL_ErrorPrint( alSourcef(Channels[ch_idx].source_id, AL_GAIN, volume) );
1076
1077
1078 ALint status;
1079 OpenAL_ErrorCheck(alGetSourcei(Channels[ch_idx].source_id, AL_SOURCE_STATE, &status),
1080 return ds_sound_handle::invalid());
1081
1082 if (status == AL_PLAYING) {
1083 OpenAL_ErrorPrint( alSourceStop(Channels[ch_idx].source_id) );
1084 }
1085
1086 OpenAL_ErrorCheck(alSourcei(Channels[ch_idx].source_id, AL_BUFFER, sound_buffers[sid].buf_id),
1087 return ds_sound_handle::invalid());
1088
1089 OpenAL_ErrorPrint( alSourcei(Channels[ch_idx].source_id, AL_SOURCE_RELATIVE, AL_TRUE) );
1090
1091 OpenAL_ErrorPrint( alSourcei(Channels[ch_idx].source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE) );
1092
1093 if (Ds_eax_inited) {
1094 OpenAL_ErrorPrint( alSource3i(Channels[ch_idx].source_id, AL_AUXILIARY_SEND_FILTER, AL_EFX_aux_id, 0, AL_FILTER_NULL) );
1095 }
1096
1097 OpenAL_ErrorPrint( alSourcePlay(Channels[ch_idx].source_id) );
1098
1099 sound_buffers[sid].channel_id = ch_idx;
1100
1101 Channels[ch_idx].sid = sid;
1102 Channels[ch_idx].snd_id = snd_id;
1103 Channels[ch_idx].sig = ds_sound_handle(channel_next_sig++);
1104 Channels[ch_idx].last_position = 0;
1105 Channels[ch_idx].is_voice_msg = is_voice_msg;
1106 Channels[ch_idx].vol = volume;
1107 Channels[ch_idx].looping = looping;
1108 Channels[ch_idx].priority = enhanced_priority;
1109 Channels[ch_idx].is_ambient = false; // no support for 2D ambient sounds
1110
1111 if (channel_next_sig < 0) {
1112 channel_next_sig = 1;
1113 }
1114
1115 return Channels[ch_idx].sig;
1116 }
1117
1118
1119 /**
1120 * Return the channel number that is playing the sound identified by sig.
1121 * @return Channel number, if not playing, return -1.
1122 */
ds_get_channel(ds_sound_handle sig)1123 int ds_get_channel(ds_sound_handle sig)
1124 {
1125 int i;
1126
1127 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1128 if ( Channels[i].source_id && (Channels[i].sig == sig) ) {
1129 if ( ds_is_channel_playing(i) == TRUE ) {
1130 return i;
1131 }
1132 }
1133 }
1134
1135 return -1;
1136 }
1137
1138 /**
1139 * @todo Documentation
1140 */
ds_is_channel_playing(int channel_id)1141 int ds_is_channel_playing(int channel_id)
1142 {
1143 if ( Channels[channel_id].source_id != 0 ) {
1144 ALint status;
1145
1146 OpenAL_ErrorPrint( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status) );
1147
1148 return (status == AL_PLAYING);
1149 }
1150
1151 return 0;
1152 }
1153
1154 /**
1155 * @todo Documentation
1156 */
ds_stop_channel(int channel_id)1157 void ds_stop_channel(int channel_id)
1158 {
1159 if ( Channels[channel_id].source_id != 0 ) {
1160 OpenAL_ErrorPrint( alSourceStop(Channels[channel_id].source_id) );
1161 }
1162 }
1163
1164 /**
1165 * @todo Documentation
1166 */
ds_stop_channel_all()1167 void ds_stop_channel_all()
1168 {
1169 int i;
1170
1171 for ( i=0; i<MAX_CHANNELS; i++ ) {
1172 if ( Channels[i].source_id != 0 ) {
1173 OpenAL_ErrorPrint( alSourceStop(Channels[i].source_id) );
1174 }
1175 }
1176 }
1177
1178 /**
1179 * @brief Set the volume for a channel. The volume is expected to be in linear scale
1180 * @details If the sound is a 3D sound buffer, this is like re-establishing the maximum volume.
1181 */
ds_set_volume(int channel_id,float vol)1182 void ds_set_volume( int channel_id, float vol )
1183 {
1184 if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
1185 return;
1186 }
1187
1188 ALuint source_id = Channels[channel_id].source_id;
1189
1190 if (source_id != 0) {
1191 CAP(vol, 0.0f, 1.0f);
1192 OpenAL_ErrorPrint( alSourcef(source_id, AL_GAIN, vol) );
1193 }
1194 }
1195
1196 /**
1197 * Set the pan for a channel. The pan is expected to be in DirectSound units
1198 */
ds_set_pan(int channel_id,float pan)1199 void ds_set_pan( int channel_id, float pan )
1200 {
1201 if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
1202 return;
1203 }
1204
1205 ALint state;
1206
1207 OpenAL_ErrorCheck( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &state), return );
1208
1209 if (state == AL_PLAYING) {
1210 //OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_SOURCE_RELATIVE, AL_TRUE) );
1211 OpenAL_ErrorPrint( alSource3f(Channels[channel_id].source_id, AL_POSITION, pan, 0.0f, -1.0f) );
1212 }
1213 }
1214
ds_get_pitch(int channel_id)1215 float ds_get_pitch(int channel_id)
1216 {
1217 ALint status;
1218 ALfloat alpitch = 1.0;
1219
1220 if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
1221 return -1;
1222 }
1223
1224 OpenAL_ErrorCheck( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status), return -1 );
1225
1226 if (status == AL_PLAYING) {
1227 OpenAL_ErrorPrint( alGetSourcef(Channels[channel_id].source_id, AL_PITCH, &alpitch) );
1228 }
1229
1230 return alpitch;
1231 }
1232
ds_set_pitch(int channel_id,float pitch)1233 void ds_set_pitch(int channel_id, float pitch)
1234 {
1235 Assertion(pitch > 0.0f, "Pitch may not be less than zero!");
1236
1237 ALint status;
1238
1239 if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
1240 return;
1241 }
1242
1243 OpenAL_ErrorCheck( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status), return );
1244
1245 if (status == AL_PLAYING) {
1246 OpenAL_ErrorPrint( alSourcef(Channels[channel_id].source_id, AL_PITCH, pitch) );
1247 }
1248 }
1249
1250 /**
1251 * Starts a ds3d sound playing
1252 *
1253 * @param sid Software id for sound to play
1254 * @param snd_id Identifies what type of sound is playing
1255 * @param pos World pos of sound
1256 * @param vel Velocity of object emitting sound
1257 * @param min Distance at which sound doesn't get any louder
1258 * @param max Distance at which sound becomes inaudible
1259 * @param looping Whether to loop the sound or not
1260 * @param max_volume Volume (0 to 1) for 3d sound at maximum
1261 * @param estimated_vol Manual estimated volume
1262 * @param priority ::DS_MUST_PLAY, ::DS_LIMIT_ONE, ::DS_LIMIT_TWO, ::DS_LIMIT_THREE
1263 *
1264 * @return 0 if sound started successfully, -1 if sound could not be played
1265 */
ds3d_play(int sid,int snd_id,vec3d * pos,vec3d * vel,float min,float max,int looping,float max_volume,float estimated_vol,const EnhancedSoundData * enhanced_sound_data,int priority,bool is_ambient)1266 ds_sound_handle ds3d_play(int sid, int snd_id, vec3d* pos, vec3d* vel, float min, float max, int looping,
1267 float max_volume, float estimated_vol, const EnhancedSoundData* enhanced_sound_data,
1268 int priority, bool is_ambient)
1269 {
1270 int channel_id;
1271 int enhanced_priority = SND_ENHANCED_PRIORITY_INVALID;
1272
1273
1274 if (!ds_initialized) {
1275 return ds_sound_handle::invalid();
1276 }
1277
1278 channel_id = ds_get_free_channel(estimated_vol, snd_id, priority, enhanced_priority, *enhanced_sound_data);
1279
1280 if (channel_id < 0) {
1281 return ds_sound_handle::invalid();
1282 }
1283
1284 if ( Channels[channel_id].source_id == 0 ) {
1285 return ds_sound_handle::invalid();
1286 }
1287
1288 // set up 3D sound data here
1289 ds3d_update_buffer(channel_id, min, max, pos, vel);
1290
1291
1292 OpenAL_ErrorPrint( alSourcef(Channels[channel_id].source_id, AL_PITCH, 1.0f) );
1293
1294 OpenAL_ErrorPrint( alSourcef(Channels[channel_id].source_id, AL_GAIN, max_volume) );
1295
1296 ALint status;
1297 OpenAL_ErrorCheck(alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status),
1298 return ds_sound_handle::invalid());
1299
1300 if (status == AL_PLAYING) {
1301 OpenAL_ErrorPrint( alSourceStop(Channels[channel_id].source_id) );
1302 }
1303
1304 OpenAL_ErrorCheck(alSourcei(Channels[channel_id].source_id, AL_BUFFER, sound_buffers[sid].buf_id),
1305 return ds_sound_handle::invalid());
1306
1307 if (Ds_eax_inited) {
1308 OpenAL_ErrorPrint( alSource3i(Channels[channel_id].source_id, AL_AUXILIARY_SEND_FILTER, AL_EFX_aux_id, 0, AL_FILTER_NULL) );
1309 }
1310
1311 OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_SOURCE_RELATIVE, AL_FALSE) );
1312
1313 OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE) );
1314
1315 OpenAL_ErrorPrint( alSourcePlay(Channels[channel_id].source_id) );
1316
1317
1318 sound_buffers[sid].channel_id = channel_id;
1319
1320 Channels[channel_id].sid = sid;
1321 Channels[channel_id].snd_id = snd_id;
1322 Channels[channel_id].sig = ds_sound_handle(channel_next_sig++);
1323 Channels[channel_id].last_position = 0;
1324 Channels[channel_id].is_voice_msg = false;
1325 Channels[channel_id].vol = max_volume;
1326 Channels[channel_id].looping = looping;
1327 Channels[channel_id].priority = enhanced_priority;
1328 Channels[channel_id].is_ambient = is_ambient;
1329
1330 if (channel_next_sig < 0 ) {
1331 channel_next_sig = 1;
1332 }
1333
1334 return Channels[channel_id].sig;
1335 }
1336
1337 /**
1338 * @todo Documentation
1339 */
ds_set_position(int channel_id,unsigned int offset)1340 void ds_set_position(int channel_id, unsigned int offset)
1341 {
1342 if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
1343 return;
1344 }
1345
1346 OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_BYTE_OFFSET, offset) );
1347 }
1348
1349 /**
1350 * @todo Documentation
1351 */
ds_get_play_position(int channel_id)1352 unsigned int ds_get_play_position(int channel_id)
1353 {
1354 if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
1355 return 0;
1356 }
1357
1358 ALint pos = -1;
1359 int sid = Channels[channel_id].sid;
1360
1361 if ( (sid < 0) || ((size_t)sid >= sound_buffers.size()) ) {
1362 return 0;
1363 }
1364
1365 if (AL_play_position) {
1366 OpenAL_ErrorPrint( alGetSourcei(Channels[channel_id].source_id, AL_BYTE_LOKI, &pos) );
1367
1368 if ( pos < 0 ) {
1369 pos = 0;
1370 } else if ( pos > 0 ) {
1371 // AL_BYTE_LOKI returns position in canon format which may differ
1372 // from our sample, so we may have to scale it
1373 ALuint buf_id = sound_buffers[sid].buf_id;
1374 ALint size;
1375
1376 OpenAL_ErrorCheck( alGetBufferi(buf_id, AL_SIZE, &size), return 0 );
1377
1378 pos = (ALint)(pos * ((float)sound_buffers[sid].nbytes / size));
1379 }
1380 } else {
1381 OpenAL_ErrorPrint( alGetSourcei(Channels[channel_id].source_id, AL_BYTE_OFFSET, &pos) );
1382
1383 if (pos < 0) {
1384 pos = 0;
1385 }
1386 }
1387
1388 return (unsigned int) pos;
1389 }
1390
1391 /**
1392 * @todo Documentation
1393 */
ds_get_channel_size(int channel_id)1394 int ds_get_channel_size(int channel_id)
1395 {
1396 if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
1397 return 0;
1398 }
1399
1400 int sid = Channels[channel_id].sid;
1401
1402 if ( (sid < 0) || ((size_t)sid >= sound_buffers.size()) ) {
1403 return 0;
1404 }
1405
1406 ALuint buf_id = sound_buffers[sid].buf_id;
1407 ALint data_size = 0;
1408
1409 if ( (buf_id != 0) && alIsBuffer(buf_id)) {
1410 OpenAL_ErrorPrint( alGetBufferi(buf_id, AL_SIZE, &data_size) );
1411 }
1412
1413 return (int) data_size;
1414 }
1415
1416 /**
1417 * Returns the number of channels that are actually playing
1418 */
ds_get_number_channels()1419 int ds_get_number_channels()
1420 {
1421 int i,n;
1422
1423 if (!ds_initialized) {
1424 return 0;
1425 }
1426
1427 n = 0;
1428 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1429 if ( Channels[i].source_id ) {
1430 if ( ds_is_channel_playing(i) == TRUE ) {
1431 n++;
1432 }
1433 }
1434 }
1435
1436 return n;
1437 }
1438
1439 /**
1440 * Retreive raw data from a sound buffer
1441 */
ds_get_data(int,char *)1442 int ds_get_data(int /*sid*/, char * /*data*/)
1443 {
1444 return -1;
1445 }
1446
1447 /**
1448 * Return the size of the raw sound data
1449 */
ds_get_size(int sid,int * size)1450 int ds_get_size(int sid, int *size)
1451 {
1452 Assert(sid >= 0);
1453
1454 if ( (sid < 0) || ((size_t)sid >= sound_buffers.size()) ) {
1455 return 0;
1456 }
1457
1458 ALuint buf_id = sound_buffers[sid].buf_id;
1459 ALint data_size = 0;
1460
1461 if ( (buf_id != 0) && alIsBuffer(buf_id)) {
1462 OpenAL_ErrorPrint( alGetBufferi(buf_id, AL_SIZE, &data_size) );
1463
1464 if (size) {
1465 *size = (int) data_size;
1466 }
1467 return 0;
1468
1469 }
1470 return -1;
1471 }
1472
1473 // --------------------
1474 //
1475 // EAX Functions below
1476 //
1477 // --------------------
1478
1479 /**
1480 * Set the master volume for the reverb added to all sound sources.
1481 *
1482 * @param volume Volume, range from 0 to 1.0
1483 * @returns 0 if the volume is set successfully, otherwise return -1
1484 */
ds_eax_set_volume(float volume)1485 int ds_eax_set_volume(float volume)
1486 {
1487 if ( !Ds_eax_inited ) {
1488 return -1;
1489 }
1490
1491 CAP(volume, 0.0f, 1.0f);
1492
1493 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAIN, volume) );
1494
1495 OpenAL_ErrorCheck( v_alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFX_effect_id), return -1 );
1496
1497 return 0;
1498 }
1499
1500 /**
1501 * Set the decay time for the EAX environment (ie all sound sources)
1502 *
1503 * @param seconds Decay time in seconds
1504 * @return 0 if decay time is successfully set, otherwise return -1
1505 */
ds_eax_set_decay_time(float seconds)1506 int ds_eax_set_decay_time(float seconds)
1507 {
1508 if ( !Ds_eax_inited ) {
1509 return -1;
1510 }
1511
1512 CAP(seconds, 0.1f, 20.0f);
1513
1514 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_TIME, seconds) );
1515
1516 OpenAL_ErrorCheck( v_alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFX_effect_id), return -1 );
1517
1518 return 0;
1519 }
1520
1521 /**
1522 * Set the damping value for the EAX environment (ie all sound sources)
1523 *
1524 * @param damp Damp value from 0 to 2.0
1525 * @return 0 if the damp value is successfully set, otherwise return -1
1526 */
ds_eax_set_damping(float damp)1527 int ds_eax_set_damping(float damp)
1528 {
1529 if ( !Ds_eax_inited ) {
1530 return -1;
1531 }
1532
1533 CAP(damp, 0.1f, 2.0f);
1534
1535 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFRATIO, damp) );
1536
1537 OpenAL_ErrorCheck( v_alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFX_effect_id), return -1 );
1538
1539 return 0;
1540 }
1541
1542 /**
1543 * Set up all the parameters for an environment
1544 *
1545 * @param id Value from the EAX_ENVIRONMENT_* enumeration
1546 * @param vol Volume for the environment (0 to 1.0)
1547 * @param damping Damp value for the environment (0 to 2.0)
1548 * @param decay Decay time in seconds (0.1 to 20.0)
1549 * @return 0 if successful, otherwise return -1
1550 */
ds_eax_set_all(unsigned long id,float vol,float damping,float decay)1551 int ds_eax_set_all(unsigned long id, float vol, float damping, float decay)
1552 {
1553 if ( !Ds_eax_inited ) {
1554 return -1;
1555 }
1556
1557 // special disabled case
1558 if ( (id == EAX_ENVIRONMENT_GENERIC) && (vol == 0.0f) && (damping == 0.0f) && (decay == 0.0f) ) {
1559 v_alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
1560 Ds_active_env_idx = 0;
1561 Ds_active_env = false;
1562 return 0;
1563 }
1564
1565 al_efx_load_preset(id);
1566
1567 CAP(vol, 0.0f, 1.0f);
1568 CAP(decay, 0.1f, 20.0f);
1569 CAP(damping, 0.1f, 2.0f);
1570
1571 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAIN, vol) );
1572 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_TIME, decay) );
1573 OpenAL_ErrorPrint( v_alEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFRATIO, damping) );
1574
1575 OpenAL_ErrorCheck( v_alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFX_effect_id), return -1 );
1576
1577 return 0;
1578 }
1579
ds_eax_get_preset_id(const char * name)1580 int ds_eax_get_preset_id(const char *name)
1581 {
1582 if ( !name || !strlen(name) ) {
1583 return -1;
1584 }
1585
1586 size_t count = EFX_presets.size();
1587
1588 for (size_t i = 0; i < count; i++) {
1589 if ( !stricmp(name, EFX_presets[i].name.c_str()) ) {
1590 return (int)i;
1591 }
1592 }
1593
1594 return -1;
1595 }
1596
ds_eax_get_prop(EFXREVERBPROPERTIES ** props,const char * name,const char * template_name)1597 int ds_eax_get_prop(EFXREVERBPROPERTIES **props, const char *name, const char *template_name)
1598 {
1599 Assert( props != NULL );
1600 Assert( name != NULL );
1601 Assert( strlen(name) > 0 ); //-V805
1602
1603 int template_id = -1;
1604
1605 int id = ds_eax_get_preset_id(name);
1606
1607 if (id >= 0) {
1608 *props = &EFX_presets[id];
1609 } else {
1610 id = (int)EFX_presets.size();
1611
1612 EFXREVERBPROPERTIES n_prop;
1613
1614 if ( (template_name != NULL) && (template_name[0] != '\0') ) {
1615 template_id = ds_eax_get_preset_id(template_name);
1616 }
1617
1618 if (template_id >= 0) {
1619 n_prop = EFX_presets[template_id];
1620 n_prop.name = name;
1621 } else {
1622 n_prop.name = name;
1623 n_prop.flDensity = 1.0f;
1624 n_prop.flDiffusion = 1.0f;
1625 n_prop.flGain = 0.32f;
1626 n_prop.flGainHF = 0.89f;
1627 n_prop.flGainLF = 0.0f;
1628 n_prop.flDecayTime = 1.49f;
1629 n_prop.flDecayHFRatio = 0.83f;
1630 n_prop.flDecayLFRatio = 1.0f;
1631 n_prop.flReflectionsGain = 0.05f;
1632 n_prop.flReflectionsDelay = 0.007f;
1633 n_prop.flReflectionsPan[0] = 0.0f;
1634 n_prop.flReflectionsPan[1] = 0.0f;
1635 n_prop.flReflectionsPan[2] = 0.0f;
1636 n_prop.flLateReverbGain = 1.26f;
1637 n_prop.flLateReverbDelay = 0.011f;
1638 n_prop.flLateReverbPan[0] = 0.0f;
1639 n_prop.flLateReverbPan[1] = 0.0f;
1640 n_prop.flLateReverbPan[2] = 0.0f;
1641 n_prop.flEchoTime = 0.25f;
1642 n_prop.flEchoDepth = 0.0f;
1643 n_prop.flModulationTime = 0.25f;
1644 n_prop.flModulationDepth = 0.0f;
1645 n_prop.flAirAbsorptionGainHF = 0.994f;
1646 n_prop.flHFReference = 5000.0f;
1647 n_prop.flLFReference = 250.0f;
1648 n_prop.flRoomRolloffFactor = 0.0f;
1649 n_prop.iDecayHFLimit = AL_TRUE;
1650 }
1651
1652 EFX_presets.push_back( n_prop );
1653
1654 *props = &EFX_presets[id];
1655 }
1656
1657 if ( !stricmp(name, "default") ) {
1658 extern unsigned int SND_ENV_DEFAULT;
1659 SND_ENV_DEFAULT = id;
1660 }
1661
1662 return 0;
1663 }
1664
1665 /**
1666 * Get up the parameters for the current environment
1667 *
1668 * @param er (output) Hold environment parameters
1669 * @param id If set will get specified preset env, otherwise current env
1670 * @return 0 if successful, otherwise return -1
1671 */
ds_eax_get_all(EAX_REVERBPROPERTIES * er,int id)1672 int ds_eax_get_all(EAX_REVERBPROPERTIES *er, int id)
1673 {
1674 if ( !er ) {
1675 return -1;
1676 }
1677
1678 if (id < 0) {
1679 if (!Ds_active_env) {
1680 return -1;
1681 }
1682
1683 er->environment = Ds_active_env_idx;
1684
1685 OpenAL_ErrorPrint( v_alGetEffectf(AL_EFX_effect_id, AL_EAXREVERB_GAIN, &er->fVolume) );
1686 OpenAL_ErrorPrint( v_alGetEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_TIME, &er->fDecayTime_sec) );
1687 OpenAL_ErrorPrint( v_alGetEffectf(AL_EFX_effect_id, AL_EAXREVERB_DECAY_HFRATIO, &er->fDamping) );
1688 } else if (id < (int)EFX_presets.size()) {
1689 er->environment = (size_t)id;
1690
1691 er->fVolume = EFX_presets[id].flGain;
1692 er->fDecayTime_sec = EFX_presets[id].flDecayTime;
1693 er->fDamping = EFX_presets[id].flDecayHFRatio;
1694 } else {
1695 return -1;
1696 }
1697
1698 return 0;
1699 }
1700
1701 /**
1702 * Close down EAX, freeing any allocated resources
1703 */
ds_eax_close()1704 void ds_eax_close()
1705 {
1706 if (Ds_eax_inited == 0) {
1707 return;
1708 }
1709
1710 v_alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
1711
1712 v_alDeleteEffects(1, &AL_EFX_effect_id);
1713 AL_EFX_effect_id = 0;
1714
1715 v_alDeleteAuxiliaryEffectSlots(1, &AL_EFX_aux_id);
1716 AL_EFX_aux_id = 0;
1717
1718 Ds_eax_inited = 0;
1719 }
1720
1721 /**
1722 * Initialize EAX
1723 * @return 0 if initialization is successful, otherwise return -1
1724 */
ds_eax_init()1725 int ds_eax_init()
1726 {
1727 if (Ds_eax_inited) {
1728 return 0;
1729 }
1730
1731 try {
1732 v_alGenFilters = (ALGENFILTERS) al_load_function("alGenFilters");
1733 v_alDeleteFilters = (ALDELETEFILTERS) al_load_function("alDeleteFilters");
1734 v_alFilteri = (ALFILTERI) al_load_function("alFilteri");
1735 v_alGenEffecs = (ALGENEFFECTS) al_load_function("alGenEffects");
1736 v_alDeleteEffects = (ALDELETEEFFECTS) al_load_function("alDeleteEffects");
1737 v_alEffecti = (ALEFFECTI) al_load_function("alEffecti");
1738 v_alEffectf = (ALEFFECTF) al_load_function("alEffectf");
1739 v_alEffectfv = (ALEFFECTFV) al_load_function("alEffectfv");
1740 v_alGetEffectf = (ALGETEFFECTF) al_load_function("alGetEffectf");
1741
1742 v_alGenAuxiliaryEffectSlots = (ALGENAUXILIARYEFFECTSLOTS) al_load_function("alGenAuxiliaryEffectSlots");
1743 v_alDeleteAuxiliaryEffectSlots = (ALDELETEAUXILIARYEFFECTSLOTS) al_load_function("alDeleteAuxiliaryEffectSlots");
1744 v_alIsAuxiliaryEffectSlot = (ALISAUXILIARYEFFECTSLOT) al_load_function("alIsAuxiliaryEffectSlot");
1745 v_alAuxiliaryEffectSloti = (ALAUXILIARYEFFECTSLOTI) al_load_function("alAuxiliaryEffectSloti");
1746 v_alAuxiliaryEffectSlotiv = (ALAUXILIARYEFFECTSLOTIV) al_load_function("alAuxiliaryEffectSlotiv");
1747 v_alAuxiliaryEffectSlotf = (ALAUXILIARYEFFECTSLOTF) al_load_function("alAuxiliaryEffectSlotf");
1748 v_alAuxiliaryEffectSlotfv = (ALAUXILIARYEFFECTSLOTFV) al_load_function("alAuxiliaryEffectSlotfv");
1749 } catch (const std::exception& err) {
1750 mprintf(("\n EFX: Unable to load function: %s()\n", err.what()));
1751
1752 Ds_eax_inited = 0;
1753 return -1;
1754 }
1755
1756 v_alGenAuxiliaryEffectSlots(1, &AL_EFX_aux_id);
1757
1758 if (alGetError() != AL_NO_ERROR) {
1759 mprintf(("\n EFX: Unable to create Aux effect!\n"));
1760 return -1;
1761 }
1762
1763 v_alGenEffecs(1, &AL_EFX_effect_id);
1764
1765 if (alGetError() != AL_NO_ERROR) {
1766 mprintf(("\n EFX: Unable to create effect!\n"));
1767 return -1;
1768 }
1769
1770 v_alEffecti(AL_EFX_effect_id, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
1771
1772 if (alGetError() != AL_NO_ERROR) {
1773 mprintf(("\n EFX: EAXReverb not supported!\n"));
1774 return -1;
1775 }
1776
1777 v_alAuxiliaryEffectSloti(AL_EFX_aux_id, AL_EFFECTSLOT_EFFECT, AL_EFX_effect_id);
1778
1779 if (alGetError() != AL_NO_ERROR) {
1780 mprintf(("\n EFX: Couldn't load effect!\n"));
1781 return -1;
1782 }
1783
1784 // add default presets
1785 EFX_presets.reserve(EAX_ENVIRONMENT_COUNT);
1786
1787 for (int i = 0; i < EAX_ENVIRONMENT_COUNT; i++) {
1788 EFX_presets.push_back( EFX_Reverb_Defaults[i] );
1789 }
1790
1791 Ds_eax_inited = 1;
1792
1793 // disabled by default
1794 ds_eax_set_all(EAX_ENVIRONMENT_GENERIC, 0.0f, 0.0f, 0.0f);
1795
1796 return 0;
1797 }
1798
1799 /**
1800 * @todo Documentation
1801 */
ds_eax_is_inited()1802 int ds_eax_is_inited()
1803 {
1804 return Ds_eax_inited;
1805 }
1806
1807 /**
1808 * Called once per game frame to make sure voice messages aren't looping
1809 */
ds_do_frame()1810 void ds_do_frame()
1811 {
1812 if (!ds_initialized) {
1813 return;
1814 }
1815
1816 int i;
1817 channel *cp = NULL;
1818
1819 for (i = 0; i < MAX_CHANNELS; i++) {
1820 cp = &Channels[i];
1821 Assert( cp != NULL );
1822
1823 if (cp->is_voice_msg) {
1824 if( cp->source_id == 0 ) {
1825 continue;
1826 }
1827
1828 unsigned int current_position = ds_get_play_position(i);
1829 if (current_position != 0) {
1830 if (current_position < cp->last_position) {
1831 ds_close_channel(i);
1832 } else {
1833 cp->last_position = current_position;
1834 }
1835 }
1836 }
1837 }
1838 }
1839
1840 /**
1841 * Given a valid channel return the sound id
1842 */
ds_get_sound_id(int channel_id)1843 int ds_get_sound_id(int channel_id)
1844 {
1845 Assert( channel_id >= 0 );
1846
1847 return Channels[channel_id].snd_id;
1848 }
1849
1850 /**
1851 * @brief Given a valid channel, returns the sound signature (typically the sound index)
1852 * @param channel_id
1853 * @return
1854 */
ds_get_sound_index(int channel_id)1855 int ds_get_sound_index(int channel_id) {
1856 Assert( channel_id >= 0 );
1857
1858 return Channels[channel_id].sid;
1859 }
1860