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