Switch to using -I to find includes, rather than relative paths.
[gemrb.git] / gemrb / plugins / OpenALAudio / AmbientMgrAL.cpp
blob53f6deca2956b5203f4595ab6378b7039a89a981
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 <limits.h>
22 #include <cmath>
23 #include <cassert>
24 #include <cstdio>
25 #include "Ambient.h"
26 #include "Interface.h"
27 #include "Game.h"
28 #include "OpenALAudio.h"
29 #include "AmbientMgrAL.h"
31 #include "SDL.h"
33 // TODO: remove last dependencies on OpenAL, and then rename and move it?
35 // legal nop if already reset
36 void AmbientMgrAL::reset()
38 if (NULL != player){
39 SDL_mutexP(mutex);
41 for (std::vector<AmbientSource *>::iterator it = ambientSources.begin(); it != ambientSources.end(); ++it) {
42 delete (*it);
44 ambientSources.clear();
45 AmbientMgr::reset();
46 if (NULL != player) {
47 SDL_CondSignal(cond);
48 SDL_mutexV(mutex);
49 SDL_WaitThread(player, NULL);
50 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)
70 if (NULL != player)
71 SDL_mutexP(mutex);
72 AmbientMgr::activate(name);
73 if (NULL != player) {
74 SDL_CondSignal(cond);
75 SDL_mutexV(mutex);
79 void AmbientMgrAL::activate()
81 if (NULL != player)
82 SDL_mutexP(mutex);
83 AmbientMgr::activate();
84 if (NULL != player) {
85 SDL_CondSignal(cond);
86 SDL_mutexV(mutex);
90 void AmbientMgrAL::deactivate(const std::string &name)
92 if (NULL != player)
93 SDL_mutexP(mutex);
94 AmbientMgr::deactivate(name);
95 if (NULL != player) {
96 SDL_CondSignal(cond);
97 SDL_mutexV(mutex);
101 void AmbientMgrAL::deactivate()
103 if (NULL != player)
104 SDL_mutexP(mutex);
105 AmbientMgr::deactivate();
106 hardStop();
107 if (NULL != player)
108 SDL_mutexV(mutex);
111 void AmbientMgrAL::hardStop()
113 for (std::vector<AmbientSource *>::iterator it = ambientSources.begin(); it != ambientSources.end(); ++it) {
114 (*it)->hardStop();
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
124 break;
126 unsigned int delay = ambim->tick(SDL_GetTicks());
127 assert(delay > 0);
128 SDL_CondWaitTimeout(ambim->cond, ambim->mutex, delay);
130 SDL_mutexV(ambim->mutex);
131 return 0;
134 unsigned int AmbientMgrAL::tick(unsigned int ticks)
136 unsigned int delay = 60000; // wait one minute if all sources are off
138 if (!active)
139 return delay;
141 int xpos, ypos;
142 core->GetAudioDrv()->GetListenerPos(xpos, ypos);
143 Point listener;
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)
152 delay = newdelay;
154 return 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
166 if (loaded) return;
168 unsigned int i=ambient->sounds.size();
169 soundrefs.reserve(i);
170 while(i--) {
171 // TODO: cache this sound
172 // (and skip it if it turns out to be invalid)
173 soundrefs.push_back(ambient->sounds[i]);
176 loaded = true;
179 AmbientMgrAL::AmbientSource::~AmbientSource()
181 if (stream >= 0) {
182 core->GetAudioDrv()->ReleaseStream(stream, true);
183 stream = -1;
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()) {
191 return UINT_MAX;
193 if (loaded && soundrefs.empty()) return UINT_MAX;
195 if ((! (ambient->getFlags() & IE_AMBI_ENABLED)) || (! ambient->getAppearance()&timeslice)) {
196 // disabled
198 if (stream >= 0) {
199 // release the stream without immediately stopping it
200 core->GetAudioDrv()->ReleaseStream(stream, false);
202 return UINT_MAX;
205 int delay = ambient->getInterval() * 1000;
206 int left = lastticks - ticks + delay;
207 if (0 < left) // we are still waiting
208 return left;
209 if (enqueued > 0) // we have already played that much
210 enqueued += left;
211 if (enqueued < 0)
212 enqueued = 0;
214 lastticks = ticks;
215 if (0 == delay) // it's a non-stop ambient, so in any case wait only a sec
216 delay = 1000;
218 if (! (ambient->getFlags() & IE_AMBI_MAIN) && !isHeard( listener )) { // we are out of range
219 if (delay > 500) {
220 // release stream if we're inactive for a while
221 core->GetAudioDrv()->ReleaseStream(stream);
223 return delay;
226 ensureLoaded();
227 if (soundrefs.empty()) return UINT_MAX;
229 if (stream < 0) {
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);
233 if (stream == -1) {
234 // no streams available...
235 // Try again later
236 return delay;
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(); */
244 int leftNum = 1;
245 int leftMS = 0;
246 if (0 == ambient->getInterval()) {
247 leftNum = 0;
248 leftMS = 1000 - enqueued; // let's have at least 1 second worth queue
252 while (0 < leftNum || 0 < leftMS) {
253 int len = enqueue();
254 if (len < 0) break;
255 --leftNum;
256 leftMS -= len;
257 enqueued += len;
260 return delay;
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()
283 if (stream >= 0) {
284 core->GetAudioDrv()->ReleaseStream(stream, true);
285 stream = -1;
289 void AmbientMgrAL::UpdateVolume(unsigned short volume)
291 SDL_mutexP( mutex );
292 for (std::vector<AmbientSource *>::iterator it = ambientSources.begin(); it != ambientSources.end(); ++it) {
293 (*it) -> SetVolume( volume );
295 SDL_mutexV( mutex );
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)
303 if (stream >= 0) {
304 int v = volume;
305 v *= ambient->getGain();
306 v /= 100;
307 core->GetAudioDrv()->SetAmbientStreamVolume(stream, v);