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