1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2004 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program 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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "Interface.h"
28 #include "OpenALAudio.h"
29 #include "AmbientMgrAL.h"
33 // TODO: remove last dependencies on OpenAL, and then rename and move it?
35 // legal nop if already reset
36 void AmbientMgrAL::reset()
41 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
44 ambientSources
.clear();
49 SDL_WaitThread(player
, NULL
);
54 void AmbientMgrAL::setAmbients(const std::vector
<Ambient
*> &a
)
56 AmbientMgr::setAmbients(a
);
57 assert(NULL
== player
);
59 ambientSources
.reserve(a
.size());
60 for (std::vector
<Ambient
*>::const_iterator it
= a
.begin(); it
!= a
.end(); ++it
) {
61 ambientSources
.push_back(new AmbientSource(*it
));
63 core
->GetAudioDrv()->UpdateVolume( GEM_SND_VOL_AMBIENTS
);
65 player
= SDL_CreateThread(&play
, (void *) this);
68 void AmbientMgrAL::activate(const std::string
&name
)
72 AmbientMgr::activate(name
);
79 void AmbientMgrAL::activate()
83 AmbientMgr::activate();
90 void AmbientMgrAL::deactivate(const std::string
&name
)
94 AmbientMgr::deactivate(name
);
101 void AmbientMgrAL::deactivate()
105 AmbientMgr::deactivate();
111 void AmbientMgrAL::hardStop()
113 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
118 int AmbientMgrAL::play(void *am
)
120 AmbientMgrAL
* ambim
= (AmbientMgrAL
*) am
;
121 SDL_mutexP(ambim
->mutex
);
122 while (0 != ambim
->ambientSources
.size()) {
123 if (NULL
== core
->GetGame()) { // we don't have any game, and we need one
126 unsigned int delay
= ambim
->tick(SDL_GetTicks());
128 SDL_CondWaitTimeout(ambim
->cond
, ambim
->mutex
, delay
);
130 SDL_mutexV(ambim
->mutex
);
134 unsigned int AmbientMgrAL::tick(unsigned int ticks
)
136 unsigned int delay
= 60000; // wait one minute if all sources are off
142 core
->GetAudioDrv()->GetListenerPos(xpos
, ypos
);
144 listener
.x
= (short) xpos
;
145 listener
.y
= (short) ypos
;
147 ieDword timeslice
= 1<<(((core
->GetGame()->GameTime
/ 60 + 30) / 60 - 1) % 24);
149 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
150 unsigned int newdelay
= (*it
)->tick(ticks
, listener
, timeslice
);
151 if (newdelay
< delay
)
157 AmbientMgrAL::AmbientSource::AmbientSource(const Ambient
*a
)
158 : stream(-1), ambient(a
), lastticks(0), enqueued(0), loaded(false)
160 // TODO: wait random amount of time before beginning?
163 void AmbientMgrAL::AmbientSource::ensureLoaded()
165 // TODO: implement this after caching in ACMImp is done
168 unsigned int i
=ambient
->sounds
.size();
169 soundrefs
.reserve(i
);
171 // TODO: cache this sound
172 // (and skip it if it turns out to be invalid)
173 soundrefs
.push_back(ambient
->sounds
[i
]);
179 AmbientMgrAL::AmbientSource::~AmbientSource()
182 core
->GetAudioDrv()->ReleaseStream(stream
, true);
187 unsigned int AmbientMgrAL::AmbientSource::tick(unsigned int ticks
, Point listener
, ieDword timeslice
)
189 /* if we are out of sounds do nothing */
190 if(!ambient
->sounds
.size()) {
193 if (loaded
&& soundrefs
.empty()) return UINT_MAX
;
195 if ((! (ambient
->getFlags() & IE_AMBI_ENABLED
)) || (! ambient
->getAppearance()×lice
)) {
199 // release the stream without immediately stopping it
200 core
->GetAudioDrv()->ReleaseStream(stream
, false);
205 int delay
= ambient
->getInterval() * 1000;
206 int left
= lastticks
- ticks
+ delay
;
207 if (0 < left
) // we are still waiting
209 if (enqueued
> 0) // we have already played that much
215 if (0 == delay
) // it's a non-stop ambient, so in any case wait only a sec
218 if (! (ambient
->getFlags() & IE_AMBI_MAIN
) && !isHeard( listener
)) { // we are out of range
220 // release stream if we're inactive for a while
221 core
->GetAudioDrv()->ReleaseStream(stream
);
227 if (soundrefs
.empty()) return UINT_MAX
;
230 // we need to allocate a stream
231 stream
= core
->GetAudioDrv()->SetupNewStream(ambient
->getOrigin().x
, ambient
->getOrigin().y
, ambient
->getHeight(), ambient
->getGain(), (ambient
->getFlags() & IE_AMBI_POINT
), true);
234 // no streams available...
241 /* it seems that the following (commented out) is not the purpose of the perset field, as
242 it leads to ambients playing non-stop and queues overfilled */
243 /* int leftNum = ambient -> getPerset(); */
246 if (0 == ambient
->getInterval()) {
248 leftMS
= 1000 - enqueued
; // let's have at least 1 second worth queue
252 while (0 < leftNum
|| 0 < leftMS
) {
263 /* enqueues a random sound and returns its length */
264 int AmbientMgrAL::AmbientSource::enqueue()
266 if (soundrefs
.empty()) return -1;
267 if (stream
< 0) return -1;
268 int index
= rand() % soundrefs
.size();
269 //printf("Playing ambient %p, %s, %d/%ld on stream %d\n", (void*)this, soundrefs[index], index, soundrefs.size(), stream);
270 return core
->GetAudioDrv()->QueueAmbient(stream
, soundrefs
[index
]);
273 bool AmbientMgrAL::AmbientSource::isHeard(const Point
&listener
) const
275 int xdist
=listener
.x
- ambient
->getOrigin().x
;
276 int ydist
=listener
.y
- ambient
->getOrigin().y
;
277 int dist
= (int) sqrt( (double) (xdist
* xdist
+ ydist
* ydist
) );
278 return dist
< ambient
->getRadius();
281 void AmbientMgrAL::AmbientSource::hardStop()
284 core
->GetAudioDrv()->ReleaseStream(stream
, true);
289 void AmbientMgrAL::UpdateVolume(unsigned short volume
)
292 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
293 (*it
) -> SetVolume( volume
);
298 /* sets the overall volume (in percent)
299 * the final volume is affected by the specific ambient gain
301 void AmbientMgrAL::AmbientSource::SetVolume(unsigned short volume
)
305 v
*= ambient
->getGain();
307 core
->GetAudioDrv()->SetAmbientStreamVolume(stream
, v
);