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.
21 #include "AmbientMgrAL.h"
23 #include "OpenALAudio.h"
27 #include "Interface.h"
36 // TODO: remove last dependencies on OpenAL, and then rename and move it?
38 // legal nop if already reset
39 void AmbientMgrAL::reset()
44 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
47 ambientSources
.clear();
52 SDL_WaitThread(player
, NULL
);
57 void AmbientMgrAL::setAmbients(const std::vector
<Ambient
*> &a
)
59 AmbientMgr::setAmbients(a
);
60 assert(NULL
== player
);
62 ambientSources
.reserve(a
.size());
63 for (std::vector
<Ambient
*>::const_iterator it
= a
.begin(); it
!= a
.end(); ++it
) {
64 ambientSources
.push_back(new AmbientSource(*it
));
66 core
->GetAudioDrv()->UpdateVolume( GEM_SND_VOL_AMBIENTS
);
68 player
= SDL_CreateThread(&play
, (void *) this);
71 void AmbientMgrAL::activate(const std::string
&name
)
75 AmbientMgr::activate(name
);
82 void AmbientMgrAL::activate()
86 AmbientMgr::activate();
93 void AmbientMgrAL::deactivate(const std::string
&name
)
97 AmbientMgr::deactivate(name
);
104 void AmbientMgrAL::deactivate()
108 AmbientMgr::deactivate();
114 void AmbientMgrAL::hardStop()
116 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
121 int AmbientMgrAL::play(void *am
)
123 AmbientMgrAL
* ambim
= (AmbientMgrAL
*) am
;
124 SDL_mutexP(ambim
->mutex
);
125 while (0 != ambim
->ambientSources
.size()) {
126 if (NULL
== core
->GetGame()) { // we don't have any game, and we need one
129 unsigned int delay
= ambim
->tick(SDL_GetTicks());
131 SDL_CondWaitTimeout(ambim
->cond
, ambim
->mutex
, delay
);
133 SDL_mutexV(ambim
->mutex
);
137 unsigned int AmbientMgrAL::tick(unsigned int ticks
)
139 unsigned int delay
= 60000; // wait one minute if all sources are off
145 core
->GetAudioDrv()->GetListenerPos(xpos
, ypos
);
147 listener
.x
= (short) xpos
;
148 listener
.y
= (short) ypos
;
150 ieDword timeslice
= 1<<(((core
->GetGame()->GameTime
/ 60 + 30) / 60 - 1) % 24);
152 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
153 unsigned int newdelay
= (*it
)->tick(ticks
, listener
, timeslice
);
154 if (newdelay
< delay
)
160 AmbientMgrAL::AmbientSource::AmbientSource(const Ambient
*a
)
161 : stream(-1), ambient(a
), lastticks(0), enqueued(0), loaded(false)
163 // TODO: wait random amount of time before beginning?
166 void AmbientMgrAL::AmbientSource::ensureLoaded()
168 // TODO: implement this after caching in ACMImp is done
171 unsigned int i
=ambient
->sounds
.size();
172 soundrefs
.reserve(i
);
174 // TODO: cache this sound
175 // (and skip it if it turns out to be invalid)
176 soundrefs
.push_back(ambient
->sounds
[i
]);
182 AmbientMgrAL::AmbientSource::~AmbientSource()
185 core
->GetAudioDrv()->ReleaseStream(stream
, true);
190 unsigned int AmbientMgrAL::AmbientSource::tick(unsigned int ticks
, Point listener
, ieDword timeslice
)
192 /* if we are out of sounds do nothing */
193 if(!ambient
->sounds
.size()) {
196 if (loaded
&& soundrefs
.empty()) return UINT_MAX
;
198 if ((! (ambient
->getFlags() & IE_AMBI_ENABLED
)) || (! ambient
->getAppearance()×lice
)) {
202 // release the stream without immediately stopping it
203 core
->GetAudioDrv()->ReleaseStream(stream
, false);
208 int delay
= ambient
->getInterval() * 1000;
209 int left
= lastticks
- ticks
+ delay
;
210 if (0 < left
) // we are still waiting
212 if (enqueued
> 0) // we have already played that much
218 if (0 == delay
) // it's a non-stop ambient, so in any case wait only a sec
221 if (! (ambient
->getFlags() & IE_AMBI_MAIN
) && !isHeard( listener
)) { // we are out of range
223 // release stream if we're inactive for a while
224 core
->GetAudioDrv()->ReleaseStream(stream
);
230 if (soundrefs
.empty()) return UINT_MAX
;
233 // we need to allocate a stream
234 stream
= core
->GetAudioDrv()->SetupNewStream(ambient
->getOrigin().x
, ambient
->getOrigin().y
, ambient
->getHeight(), ambient
->getGain(), (ambient
->getFlags() & IE_AMBI_POINT
), true);
237 // no streams available...
244 /* it seems that the following (commented out) is not the purpose of the perset field, as
245 it leads to ambients playing non-stop and queues overfilled */
246 /* int leftNum = ambient -> getPerset(); */
249 if (0 == ambient
->getInterval()) {
251 leftMS
= 1000 - enqueued
; // let's have at least 1 second worth queue
255 while (0 < leftNum
|| 0 < leftMS
) {
266 /* enqueues a random sound and returns its length */
267 int AmbientMgrAL::AmbientSource::enqueue()
269 if (soundrefs
.empty()) return -1;
270 if (stream
< 0) return -1;
271 int index
= rand() % soundrefs
.size();
272 //printf("Playing ambient %p, %s, %d/%ld on stream %d\n", (void*)this, soundrefs[index], index, soundrefs.size(), stream);
273 return core
->GetAudioDrv()->QueueAmbient(stream
, soundrefs
[index
]);
276 bool AmbientMgrAL::AmbientSource::isHeard(const Point
&listener
) const
278 int xdist
=listener
.x
- ambient
->getOrigin().x
;
279 int ydist
=listener
.y
- ambient
->getOrigin().y
;
280 int dist
= (int) sqrt( (double) (xdist
* xdist
+ ydist
* ydist
) );
281 return dist
< ambient
->getRadius();
284 void AmbientMgrAL::AmbientSource::hardStop()
287 core
->GetAudioDrv()->ReleaseStream(stream
, true);
292 void AmbientMgrAL::UpdateVolume(unsigned short volume
)
295 for (std::vector
<AmbientSource
*>::iterator it
= ambientSources
.begin(); it
!= ambientSources
.end(); ++it
) {
296 (*it
) -> SetVolume( volume
);
301 /* sets the overall volume (in percent)
302 * the final volume is affected by the specific ambient gain
304 void AmbientMgrAL::AmbientSource::SetVolume(unsigned short volume
)
308 v
*= ambient
->getGain();
310 core
->GetAudioDrv()->SetAmbientStreamVolume(stream
, v
);