1 /* Copyright (C) 2015 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "CSoundBase.h"
21 
22 #if CONFIG2_AUDIO
23 
24 #include "lib/timer.h"
25 #include "soundmanager/SoundManager.h"
26 #include "soundmanager/data/SoundData.h"
27 #include "ps/CLogger.h"
28 
CSoundBase()29 CSoundBase::CSoundBase()
30 {
31 	ResetVars();
32 }
33 
~CSoundBase()34 CSoundBase::~CSoundBase()
35 {
36 	Stop();
37 	ReleaseOpenAL();
38 }
39 
ReleaseOpenAL()40 void CSoundBase::ReleaseOpenAL()
41 {
42 	if (m_ALSource != 0)
43 	{
44 		AL_CHECK;
45 		alSourcei(m_ALSource, AL_BUFFER, 0L);
46 		AL_CHECK;
47 		((CSoundManager*)g_SoundManager)->ReleaseALSource(m_ALSource);
48 		AL_CHECK;
49 		m_ALSource = 0;
50 	}
51 	if (m_SoundData != 0)
52 	{
53 		AL_CHECK;
54 		CSoundData::ReleaseSoundData(m_SoundData);
55 		AL_CHECK;
56 		m_SoundData = 0;
57 	}
58 }
59 
Attach(CSoundData * itemData)60 void CSoundBase::Attach(CSoundData* itemData)
61 {
62 	UNUSED2(itemData);
63 }
64 
ResetVars()65 void CSoundBase::ResetVars()
66 {
67 	m_ALSource = 0;
68 	m_SoundData = 0;
69 	m_LastPlay = false;
70 	m_Looping = false;
71 	m_StartFadeTime = 0;
72 	m_EndFadeTime = 0;
73 	m_StartVolume = 0;
74 	m_EndVolume = 0;
75 	m_ShouldBePlaying = false;
76 	m_IsPaused = false;
77 	ResetFade();
78 }
79 
ResetFade()80 void CSoundBase::ResetFade()
81 {
82 	m_StartFadeTime = 0;
83 	m_EndFadeTime = 0;
84 	m_StartVolume = 0;
85 	m_EndVolume = 0;
86 	m_PauseAfterFade = false;
87 }
88 
Finished()89 bool CSoundBase::Finished()
90 {
91   return !m_ShouldBePlaying && !IsPlaying();
92 }
93 
InitOpenAL()94 bool CSoundBase::InitOpenAL()
95 {
96 	alGetError(); /* clear error */
97 	m_ALSource = ((CSoundManager*)g_SoundManager)->GetALSource( this );
98 
99 	AL_CHECK;
100 
101 	if ( m_ALSource )
102 	{
103 		alSourcef(m_ALSource,AL_PITCH,1.0f);
104 		AL_CHECK;
105 		alSourcef(m_ALSource,AL_GAIN,1.0f);
106 		AL_CHECK;
107 		alSourcei(m_ALSource,AL_LOOPING,AL_FALSE);
108 		AL_CHECK;
109 		return true;
110 	}
111 	else
112 	{
113 //		LOGERROR("Source not allocated by SoundManager\n", 0);
114 	}
115 	return false;
116 }
117 
SetGain(ALfloat gain)118 void CSoundBase::SetGain(ALfloat gain)
119 {
120 	AL_CHECK;
121 
122 	if ( m_ALSource )
123 	{
124 		CScopeLock lock(m_ItemMutex);
125 		alSourcef(m_ALSource, AL_GAIN, gain);
126 		AL_CHECK;
127 	}
128 }
129 
SetRollOff(ALfloat rolls)130 void CSoundBase::SetRollOff(ALfloat rolls)
131 {
132 	if ( m_ALSource )
133 	{
134 		CScopeLock lock(m_ItemMutex);
135 		alSourcef(m_ALSource, AL_REFERENCE_DISTANCE, 70.0f);
136 		AL_CHECK;
137 		alSourcef(m_ALSource, AL_MAX_DISTANCE, 200.0);
138 		AL_CHECK;
139 		alSourcef(m_ALSource, AL_ROLLOFF_FACTOR, rolls);
140 		AL_CHECK;
141 	}
142 }
143 
EnsurePlay()144 void CSoundBase::EnsurePlay()
145 {
146 	if (m_ShouldBePlaying && !m_IsPaused && !IsPlaying())
147 		Play();
148 }
149 
SetCone(ALfloat innerCone,ALfloat outerCone,ALfloat coneGain)150 void CSoundBase::SetCone(ALfloat innerCone, ALfloat outerCone, ALfloat coneGain)
151 {
152 	if ( m_ALSource )
153 	{
154 		CScopeLock lock(m_ItemMutex);
155 		AL_CHECK;
156 		alSourcef(m_ALSource, AL_CONE_INNER_ANGLE, innerCone);
157 		AL_CHECK;
158 		alSourcef(m_ALSource, AL_CONE_OUTER_ANGLE, outerCone);
159 		AL_CHECK;
160 		alSourcef(m_ALSource, AL_CONE_OUTER_GAIN, coneGain);
161 		AL_CHECK;
162 	}
163 }
164 
SetPitch(ALfloat pitch)165 void CSoundBase::SetPitch(ALfloat pitch)
166 {
167 	if ( m_ALSource )
168 	{
169 		CScopeLock lock(m_ItemMutex);
170 		alSourcef(m_ALSource, AL_PITCH, pitch);
171 		AL_CHECK;
172 	}
173 }
174 
SetDirection(const CVector3D & direction)175 void CSoundBase::SetDirection(const CVector3D& direction)
176 {
177 	if ( m_ALSource )
178 	{
179 		CScopeLock lock(m_ItemMutex);
180 		alSourcefv(m_ALSource, AL_DIRECTION, direction.GetFloatArray());
181 		AL_CHECK;
182 	}
183 }
184 
185 
IsPlaying()186 bool CSoundBase::IsPlaying()
187 {
188 	if ( m_ALSource )
189 	{
190 		CScopeLock lock(m_ItemMutex);
191 		int proc_state;
192 		alGetSourcei(m_ALSource, AL_SOURCE_STATE, &proc_state);
193 		AL_CHECK;
194 
195 		return (proc_state == AL_PLAYING);
196 	}
197 	return false;
198 }
199 
SetLastPlay(bool last)200 void CSoundBase::SetLastPlay(bool last)
201 {
202 	m_LastPlay = last;
203 }
204 
IdleTask()205 bool CSoundBase::IdleTask()
206 {
207 	return true;
208 }
209 
SetLocation(const CVector3D & position)210 void CSoundBase::SetLocation (const CVector3D& position)
211 {
212 	if ( m_ALSource != 0 )
213 	{
214 		CScopeLock lock(m_ItemMutex);
215 		alSourcefv(m_ALSource,AL_POSITION, position.GetFloatArray());
216 		AL_CHECK;
217 	}
218 }
219 
HandleFade()220 bool CSoundBase::HandleFade()
221 {
222 	AL_CHECK;
223 	if (m_ALSource == 0)
224 		return true;
225 
226 	if (m_StartFadeTime != 0)
227 	{
228 		double currTime = timer_Time();
229 		double pctDone = std::min(1.0, (currTime - m_StartFadeTime) / (m_EndFadeTime - m_StartFadeTime));
230 		pctDone = std::max(0.0, pctDone);
231 		ALfloat curGain = ((m_EndVolume - m_StartVolume) * pctDone) + m_StartVolume;
232 
233 		if  (curGain == 0)
234 		{
235 			if ( m_PauseAfterFade )
236 				Pause();
237 			else
238 				Stop();
239 		}
240 		else if (curGain == m_EndVolume)
241 		{
242 			if (m_ALSource != 0)
243 				alSourcef(m_ALSource, AL_GAIN, curGain);
244 			ResetFade();
245 		}
246 		else if (m_ALSource != 0)
247 			alSourcef(m_ALSource, AL_GAIN, curGain);
248 
249 		AL_CHECK;
250 	}
251 	return true;
252 }
253 
IsFading()254 bool CSoundBase::IsFading()
255 {
256 	return ((m_ALSource != 0) && (m_StartFadeTime != 0));
257 }
258 
259 
GetLooping()260 bool CSoundBase::GetLooping()
261 {
262 	return m_Looping;
263 }
264 
SetLooping(bool loops)265 void CSoundBase::SetLooping(bool loops)
266 {
267 	m_Looping = loops;
268 	if (m_ALSource != 0)
269 	{
270 		alSourcei(m_ALSource, AL_LOOPING, loops ? AL_TRUE : AL_FALSE);
271 		AL_CHECK;
272 	}
273 }
274 
Play()275 void CSoundBase::Play()
276 {
277 	CScopeLock lock(m_ItemMutex);
278 
279 	m_ShouldBePlaying = true;
280 	m_IsPaused = false;
281 	AL_CHECK;
282 	if (m_ALSource != 0)
283 	{
284 		alSourcePlay(m_ALSource);
285 		ALenum err = alGetError();
286 		if (err != AL_NO_ERROR)
287 		{
288 			if (err == AL_INVALID)
289 				((CSoundManager*)g_SoundManager)->SetDistressThroughError();
290 			else
291 				((CSoundManager*)g_SoundManager)->al_ReportError(err, __func__, __LINE__);
292 		}
293 	}
294 }
295 
PlayAndDelete()296 void CSoundBase::PlayAndDelete()
297 {
298 	SetLastPlay(true);
299 	Play();
300 }
301 
FadeAndPause(double fadeTime)302 void CSoundBase::FadeAndPause(double fadeTime)
303 {
304 	m_PauseAfterFade = true;
305 	FadeToIn(0, fadeTime);
306 }
307 
FadeAndDelete(double fadeTime)308 void CSoundBase::FadeAndDelete(double fadeTime)
309 {
310 	SetLastPlay(true);
311 	FadeToIn(0, fadeTime);
312 }
313 
StopAndDelete()314 void CSoundBase::StopAndDelete()
315 {
316 	SetLastPlay(true);
317 	Stop();
318 }
319 
PlayLoop()320 void CSoundBase::PlayLoop()
321 {
322 	if (m_ALSource != 0)
323 	{
324 		SetLooping(true);
325 		Play();
326 		AL_CHECK;
327 	}
328 }
329 
FadeToIn(ALfloat newVolume,double fadeDuration)330 void CSoundBase::FadeToIn(ALfloat newVolume, double fadeDuration)
331 {
332 	if (m_ALSource != 0)
333 	{
334 		ALenum proc_state;
335 		alGetSourcei(m_ALSource, AL_SOURCE_STATE, &proc_state);
336 		if (proc_state == AL_PLAYING)
337 		{
338 			m_StartFadeTime = timer_Time();
339 			m_EndFadeTime = m_StartFadeTime + fadeDuration;
340 			alGetSourcef(m_ALSource, AL_GAIN, &m_StartVolume);
341 			m_EndVolume = newVolume;
342 		}
343 		AL_CHECK;
344 	}
345 }
346 
Stop()347 void CSoundBase::Stop()
348 {
349 	m_ShouldBePlaying = false;
350 	if (m_ALSource != 0)
351 	{
352 		CScopeLock lock(m_ItemMutex);
353 
354 		AL_CHECK;
355 		alSourcei(m_ALSource, AL_LOOPING, AL_FALSE);
356 		AL_CHECK;
357 		alSourceStop(m_ALSource);
358 		AL_CHECK;
359 	}
360 }
361 
GetName()362 const Path CSoundBase::GetName()
363 {
364 	if (m_SoundData)
365 		return m_SoundData->GetFileName();
366 
367 	return Path();
368 }
369 
Pause()370 void CSoundBase::Pause()
371 {
372 	if (m_ALSource != 0)
373 	{
374 		m_IsPaused = true;
375 		alSourcePause(m_ALSource);
376 		AL_CHECK;
377 	}
378 }
379 
Resume()380 void CSoundBase::Resume()
381 {
382 	if (m_ALSource != 0)
383 	{
384 		alSourcePlay(m_ALSource);
385 		AL_CHECK;
386 	}
387 }
388 
389 #endif // CONFIG2_AUDIO
390 
391