1 #include "pch.h"
2 #include "../ogre/common/Def_Str.h"
3 #include "../vdrift/pathmanager.h"
4 #include "SoundBase.h"
5 #include "SoundBaseMgr.h"
6 #include <AL/alc.h>
7 #include <AL/alext.h>
8 #include <AL/efx.h>
9 #include "SoundReverbSets.h"
10 using namespace Ogre;
11 
12 
13 const float SoundBaseMgr::MAX_DISTANCE	 = 500.f;  // 500
14 const float SoundBaseMgr::REF_DISTANCE   = 1.0f;   // 1
15 const float SoundBaseMgr::ROLLOFF_FACTOR = 0.05f;  // 0.05 0.1
16 
17 
18 //  Init
19 //---------------------------------------------------------------------------------------------
SoundBaseMgr()20 SoundBaseMgr::SoundBaseMgr()
21 	:buffers_use(0), buffers_used_max(0), sources_use(0)
22 	,hw_sources_use(0), hw_sources_num(0)
23 	,context(NULL), device(NULL)
24 	,slot(0), effect(0), master_volume(1.f)
25 {
26 	hw_sources_map.resize(HW_SRC,0);
27 	hw_sources.resize(HW_SRC,0);
28 	sources.resize(MAX_BUFFERS,0);
29 	buffers.resize(MAX_BUFFERS,0);
30 	buffer_file.resize(MAX_BUFFERS);
31 }
32 
logList(const char * list)33 void logList(const char *list)
34 {
35 	if (!list || *list == '\0')
36 		LogO("@@@  None!");
37 	else
38 	do
39 	{	LogO(String("@  ") + list);
40 		list += strlen(list) + 1;
41 	}
42 	while (*list != '\0');
43 }
44 
Init(std::string snd_device,bool reverb1)45 bool SoundBaseMgr::Init(std::string snd_device, bool reverb1)
46 {
47 	reverb = reverb1;
48 
49     //  list devices
50     LogO("@  ---- Sound devices ----");
51     if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
52         logList(alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER));
53     else
54         logList(alcGetString(NULL, ALC_DEVICE_SPECIFIER));
55 
56 
57 	//  open device
58 	if (snd_device == "")
59 		device = alcOpenDevice(NULL);
60 	else
61 		device = alcOpenDevice(snd_device.c_str());
62 
63 	if (!device)
64 	{
65 		LogO("@@@  Sound Init - Could not open device");
66 		hasALErrors();
67 		return false;
68 	}
69 
70 	//  efx
71 	ALCboolean efx = alcIsExtensionPresent(device, ALC_EXT_EFX_NAME);
72 	if (efx == ALC_FALSE)		LogO("@  EFX extention not found !");
73 	else if (efx == ALC_TRUE)	LogO("@  EFX extension found.");
74 
75 	ALint attr[4] = { 0 };
76 	attr[0] = ALC_MAX_AUXILIARY_SENDS;
77 	attr[1] = 4;
78 
79 
80 	//  context
81 	context = alcCreateContext(device, reverb ? attr : NULL);
82 	if (context == NULL ||
83 		alcMakeContextCurrent(context) == ALC_FALSE)
84 	{
85 		LogO("@@@  Sound Init - Could not create context");
86 		if (context != NULL)
87 			alcDestroyContext(context);
88 		alcCloseDevice(device);
89 		device = NULL;
90 		hasALErrors();
91 		return false;
92 	}
93 
94 
95 	//  log info  ----
96 	String s,t;
97 	LogO("@ @  ---- SoundManager Info ----");
98 	s = alGetString(AL_VENDOR);		LogO("@  vendor: " + s);
99 	s = alGetString(AL_VERSION);	LogO("@  version: " + s);
100 	s = alGetString(AL_RENDERER);	LogO("@  renderer: " + s);
101 	//t = alcGetString(device, ALC_DEVICE_SPECIFIER);	LogO("@  renderer: " + s + "  alc device: " + t);
102 	s = alGetString(AL_EXTENSIONS);	LogO("@  extensions: " + s);
103 	//t = alcGetString(device, ALC_EXTENSIONS);	LogO("@  alc extensions: " + s);
104 
105 
106 	//  sends
107 	ALint iSends = 0;
108 	alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &iSends);
109 	LogO("@  Aux Sends per Source: " + toStr(iSends));
110 
111 
112 	//  get function pointers
113 	alGenEffects    = (LPALGENEFFECTS)alGetProcAddress("alGenEffects");
114 	alDeleteEffects = (LPALDELETEEFFECTS)alGetProcAddress("alDeleteEffects");
115 	alIsEffect = (LPALISEFFECT)alGetProcAddress("alIsEffect");
116 	alEffecti  = (LPALEFFECTI)alGetProcAddress("alEffecti");
117 	alEffectf  = (LPALEFFECTF)alGetProcAddress("alEffectf");
118 	alEffectfv = (LPALEFFECTFV)alGetProcAddress("alEffectfv");
119 	alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)alGetProcAddress("alGenAuxiliaryEffectSlots");
120 	alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)alGetProcAddress("alAuxiliaryEffectSloti");
121 	alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)alGetProcAddress("alDeleteAuxiliaryEffectSlots");
122 
123 
124 	//  doppler
125 	alDopplerFactor(0.f);  // 1.f  todo: vel..
126 	//alDopplerVelocity(343.f);
127 
128 	alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);  //+
129 
130 	//  reverb
131 	if (!reverb)
132 	{
133 		LogO("@  Not using reverb.");
134 		return true;
135 	}
136 
137 	//  slot is what plays an effect on sources that connect to it
138 	alGenAuxiliaryEffectSlots(1, &slot);
139 	InitReverMap();
140 
141 	//SetReverb("MOUNTAINS");
142 	return true;
143 }
144 
145 
146 //  Reverb
147 //-----------------------------------------------------------------------------------
SetReverb(std::string name)148 void SoundBaseMgr::SetReverb(std::string name)
149 {
150 	if (!device || !reverb)  return;
151 	sReverb = name;
152 	int r = mapReverbs[name] -1;
153 	if (r < 0 || r >= RVB_PRESETS_ALL)
154 	{
155 		r = RVB_GENERIC;  // use generic
156 		LogO("@  Reverb preset not found! "+name);
157 		sReverb = "GENERIC, not found";
158 	}
159 	const REVERB_PRESET* reverb = &ReverbPresets[r];
160 
161 	effect = LoadEffect(reverb);
162 	if (!effect)
163 		LogO("@  Can't load effect !!");
164 
165 	//  Tell the effect slot to use the loaded effect object.
166 	//  Note that the this copies the effect properties.
167 	alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, effect);
168 	if (alGetError() != AL_NO_ERROR)
169 		LogO("@  Failed to set effect slot!");
170 	alDeleteEffects(1, &effect);
171 }
172 
173 
174 //  Create  --
CreateSources()175 void SoundBaseMgr::CreateSources()
176 {
177 	if (!device)  return;
178 	LogO("@ @  Creating hw sources.");
179 	int i;
180 	for (i = 0; i < HW_SRC; ++i)
181 	{
182 		alGetError();
183 		alGenSources(1, &hw_sources[i]);
184 		//alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, 0, AL_FILTER_NULL);
185 
186 		if (alGetError() != AL_NO_ERROR)  break;
187 		alSourcef(hw_sources[i], AL_REFERENCE_DISTANCE, REF_DISTANCE);
188 		alSourcef(hw_sources[i], AL_ROLLOFF_FACTOR, ROLLOFF_FACTOR);
189 		alSourcef(hw_sources[i], AL_MAX_DISTANCE, MAX_DISTANCE);
190 		//LogO(toStr(i)+" +SRC: "+toStr(hw_sources[i]));
191 		++hw_sources_num;
192 	}
193 
194 	for (i = 0; i < HW_SRC; ++i)
195 		hw_sources_map[i] = -1;
196 
197 	buffers_used_max = buffers_use;  // save for info
198 	buffers_use = 0;  //)+ zero after all loaded
199 }
200 
201 //  Destroy  --
DestroySources(bool all)202 void SoundBaseMgr::DestroySources(bool all)
203 {
204 	if (!device)  return;
205 
206 	LogO("@ @  Destroying hw sources.");
207 	int i;
208 	for (int i = 0; i < HW_SRC; ++i)
209 	{
210 		//LogO(toStr(i)+" -SRC: "+toStr(hw_sources[i]));
211 		alSourceStop(hw_sources[i]);
212 		alSourcei(hw_sources[i], AL_BUFFER, 0);
213 		alDeleteSources(1, &hw_sources[i]);
214 		--hw_sources_num;
215 	}
216 
217 	//buffers_use = 0;  //)+ needed when loading, zero after CreateSources
218 	hw_sources_use = 0;
219 }
220 
221 //  Destroy
~SoundBaseMgr()222 SoundBaseMgr::~SoundBaseMgr()
223 {
224 	if (device)
225 	{
226 		if (reverb)
227 			alDeleteAuxiliaryEffectSlots(1, &slot);
228 
229 		//  sources and buffers
230 		DestroySources(true);
231 		alDeleteBuffers(MAX_BUFFERS, &buffers[0]);
232 	}
233 
234 	//  context and device
235 	ALCcontext* context = alcGetCurrentContext();
236 	if (context == NULL)
237 	{	LogO("@ @  SoundManager was disabled.");
238 		return;
239 	}
240 	ALCdevice* device = alcGetContextsDevice(context);
241 	alcMakeContextCurrent(NULL);
242 	alcDestroyContext(context);
243 	if (device)
244 		alcCloseDevice(device);
245 
246 	LogO("@ @  SoundManager destroyed.");
247 }
248 
249 
250 //  Update
251 //-----------------------------------------------------------------------------------
setCamera(Vector3 pos,Vector3 dir,Vector3 up,Vector3 vel)252 void SoundBaseMgr::setCamera(Vector3 pos, Vector3 dir, Vector3 up, Vector3 vel)
253 {
254 	if (!device)  return;
255 	camera_position = pos;
256 	recomputeAllSources();
257 
258 	float o[6];
259 	o[0] = dir.x;  o[1] = dir.y;  o[2] = dir.z;
260 	o[3] = up.x;  o[4] = up.y;  o[5] = up.z;
261 
262 	alListener3f(AL_POSITION, pos.x, pos.y, pos.z);
263 	alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z);
264 	alListenerfv(AL_ORIENTATION, o);
265 }
266 
compareByAudibility(std::pair<int,float> a,std::pair<int,float> b)267 bool compareByAudibility(std::pair<int, float> a, std::pair<int, float> b)
268 {
269 	return a.second > b.second;
270 }
271 
272 //  called when camera moves
recomputeAllSources()273 void SoundBaseMgr::recomputeAllSources()
274 {
275 	if (!device)  return;
276 
277 	int i;
278 	for (i=0; i < sources_use; i++)
279 	{
280 		sources[i]->computeAudibility(camera_position);
281 		src_audible[i].first = i;
282 		src_audible[i].second = sources[i]->audibility;
283 	}
284 
285 	//  sort first 'num_hardware_sources' sources by audibility
286 	//  see: https://en.wikipedia.org/wiki/Selection_algorithm
287 	if (sources_use - 1 > hw_sources_num)
288 		std::nth_element(src_audible, src_audible+hw_sources_num, src_audible+sources_use-1, compareByAudibility);
289 
290 	// retire out of range sources first
291 	for (i=0; i < sources_use; i++)
292 		if (sources[src_audible[i].first]->hw_id != -1 && (i >= hw_sources_num || src_audible[i].second == 0))
293 			retire(src_audible[i].first);
294 
295 	// assign new sources
296 	for (i=0; i < std::min(sources_use, hw_sources_num); i++)
297 	if (sources[src_audible[i].first]->hw_id == -1 && src_audible[i].second > 0)
298 		for (int j=0; j < hw_sources_num; j++)
299 		if (hw_sources_map[j] == -1)
300 		{
301 			assign(src_audible[i].first, j);
302 			break;
303 		}
304 }
305 
306 
307 //  recompute Source
308 //---------------------------------------------------------------------------------------------------------------------------
recomputeSource(int id,int reason,float fl,Vector3 * vec)309 void SoundBaseMgr::recomputeSource(int id, int reason, float fl, Vector3* vec)
310 {
311 	if (!device)  return;
312 	sources[id]->computeAudibility(camera_position);
313 
314 	if (sources[id]->audibility == 0.0f)
315 	{
316 		if (sources[id]->hw_id != -1)
317 			//  retire the source if it is currently assigned
318 			retire(id);
319 	}else
320 	{
321 		//  this is a potentially audible sources[id]
322 		if (sources[id]->hw_id != -1)
323 		{
324 			//  sources[id] already playing
325 			//  update the AL settings
326 			switch (reason)
327 			{
328 			case REASON_GAIN:  alSourcef(hw_sources[sources[id]->hw_id], AL_GAIN, fl * master_volume); break;
329 			case REASON_PTCH:  alSourcef(hw_sources[sources[id]->hw_id], AL_PITCH, fl); break;
330 			case REASON_POS:  if (!sources[id]->is2D)
331 							  alSource3f(hw_sources[sources[id]->hw_id], AL_POSITION, vec->x, vec->y, vec->z); break;
332 			case REASON_VEL:  alSource3f(hw_sources[sources[id]->hw_id], AL_VELOCITY, vec->x, vec->y, vec->z); break;
333 
334 			case REASON_PLAY:  alSourcePlay(hw_sources[sources[id]->hw_id]); break;
335 			case REASON_STOP:  alSourceStop(hw_sources[sources[id]->hw_id]); break;
336 			case REASON_LOOP:  alSourcei(hw_sources[sources[id]->hw_id], AL_LOOPING, fl > 0.5f ? AL_TRUE : AL_FALSE); break;
337 			case REASON_SEEK:  alSourcei(hw_sources[sources[id]->hw_id], AL_SAMPLE_OFFSET, fl); break;
338 			default: break;
339 			}
340 		}else
341 		{
342 			//  try to make it play by the hardware
343 			//  check if there is one free sources[id] in the pool
344 			if (hw_sources_use < hw_sources_num)
345 			{
346 				for (int i=0; i < hw_sources_num; i++)
347 				{
348 					if (hw_sources_map[i] == -1)
349 					{
350 						assign(id, i);
351 						break;
352 					}
353 				}
354 			}else
355 			{
356 				//  now, compute who is the faintest
357 				//  note: we know the table m_hardware_sources_map is full!
358 				float fv = 1.0f;
359 				int al_faintest = 0;
360 				for (int i=0; i < hw_sources_num; i++)
361 				{
362 					if (hw_sources_map[i] >= 0 && sources[hw_sources_map[i]]->audibility < fv)
363 					{
364 						fv = sources[hw_sources_map[i]]->audibility;
365 						al_faintest = i;
366 					}
367 				}
368 				//  check to ensure that the sound is louder than the faintest sound currently playing
369 				if (fv < sources[id]->audibility)
370 				{
371 					// this new sources[id] is louder than the faintest!
372 					retire(hw_sources_map[al_faintest]);
373 					assign(id, al_faintest);
374 				}
375 				//  else this sources[id] is too faint, we don't play it!
376 			}
377 		}
378 	}
379 }
380 
381 
382 //  assign
383 //-----------------------------------------------------------------------------------
384 
assign(int id,int hw_id)385 void SoundBaseMgr::assign(int id, int hw_id)
386 {
387 	if (!device)  return;
388 	sources[id]->hw_id = hw_id;
389 	hw_sources_map[hw_id] = id;
390 
391 	//  the hardware source is supposed to be stopped!
392 	ALuint source = hw_sources[hw_id];
393 	alSourcei(source, AL_BUFFER, sources[id]->buffer);
394 
395 	//  use reverb +
396 	if (reverb)
397 		alSource3i(source, AL_AUXILIARY_SEND_FILTER,
398 			!sources[id]->is2D ? slot : AL_EFFECTSLOT_NULL,  0, AL_FILTER_NULL);
399 
400 	alSourcef(source, AL_GAIN, sources[id]->gain * master_volume);
401 	alSourcei(source, AL_LOOPING, sources[id]->loop ? AL_TRUE : AL_FALSE);
402 	alSourcef(source, AL_PITCH, sources[id]->pitch);
403 
404 	alSource3f(source, AL_POSITION, sources[id]->pos.x, sources[id]->pos.y, sources[id]->pos.z);
405 	alSource3f(source, AL_VELOCITY, sources[id]->vel.x, sources[id]->vel.y, sources[id]->vel.z);
406 
407 	//  hud, 2d
408 	if (sources[id]->is2D)
409 	{
410 		alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
411 		alSource3f(source, AL_POSITION, 0.f,0.f,0.f);
412 		//alSourcef(source, AL_ROLLOFF_FACTOR, 0.f);
413 	}
414 
415 	if (sources[id]->should_play)
416 		alSourcePlay(hw_sources[hw_id]);
417 
418 	++hw_sources_use;
419 }
420 
421 
retire(int id)422 void SoundBaseMgr::retire(int id)
423 {
424 	if (!device)  return;
425 	//if (sources[id]->is2D)  return;
426 	if (sources[id]->hw_id == -1)  return;
427 
428 	alSourceStop(hw_sources[sources[id]->hw_id]);
429 	hw_sources_map[sources[id]->hw_id] = -1;
430 	sources[id]->hw_id = -1;
431 	--hw_sources_use;
432 }
433 
434 
435 //  utility
pauseAll(bool mute)436 void SoundBaseMgr::pauseAll(bool mute)
437 {
438 	if (!device)  return;
439 	alListenerf(AL_GAIN, mute ? 0.0f : master_volume);
440 }
441 
setMasterVolume(float vol)442 void SoundBaseMgr::setMasterVolume(float vol)
443 {
444 	if (!device)  return;
445 	master_volume = vol;
446 	alListenerf(AL_GAIN, master_volume);
447 }
448