diff options
Diffstat (limited to 'linden/indra/llaudio/audioengine_openal.cpp')
-rw-r--r-- | linden/indra/llaudio/audioengine_openal.cpp | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/linden/indra/llaudio/audioengine_openal.cpp b/linden/indra/llaudio/audioengine_openal.cpp new file mode 100644 index 0000000..f13a5fa --- /dev/null +++ b/linden/indra/llaudio/audioengine_openal.cpp | |||
@@ -0,0 +1,544 @@ | |||
1 | /** | ||
2 | * @file audioengine_openal.cpp | ||
3 | * @brief implementation of audio engine using OpenAL | ||
4 | * support as a OpenAL 3D implementation | ||
5 | * | ||
6 | * $LicenseInfo:firstyear=2002&license=viewergpl$ | ||
7 | * | ||
8 | * Copyright (c) 2002-2008, Linden Research, Inc. | ||
9 | * | ||
10 | * Second Life Viewer Source Code | ||
11 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
12 | * to you under the terms of the GNU General Public License, version 2.0 | ||
13 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
14 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
15 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
16 | * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 | ||
17 | * | ||
18 | * There are special exceptions to the terms and conditions of the GPL as | ||
19 | * it is applied to this Source Code. View the full text of the exception | ||
20 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
21 | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception | ||
22 | * | ||
23 | * By copying, modifying or distributing this software, you acknowledge | ||
24 | * that you have read and understood your obligations described above, | ||
25 | * and agree to abide by those obligations. | ||
26 | * | ||
27 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
28 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
29 | * COMPLETENESS OR PERFORMANCE. | ||
30 | * $/LicenseInfo$ | ||
31 | */ | ||
32 | |||
33 | #include "linden_common.h" | ||
34 | #include "lldir.h" | ||
35 | |||
36 | #include "audioengine_openal.h" | ||
37 | #include "listener_openal.h" | ||
38 | |||
39 | |||
40 | LLAudioEngine_OpenAL::LLAudioEngine_OpenAL() | ||
41 | : | ||
42 | mWindGen(NULL), | ||
43 | mWindBuf(NULL), | ||
44 | mWindBufFreq(0), | ||
45 | mWindBufSamples(0), | ||
46 | mWindBufBytes(0), | ||
47 | mWindSource(AL_NONE), | ||
48 | mNumEmptyWindALBuffers(MAX_NUM_WIND_BUFFERS) | ||
49 | { | ||
50 | } | ||
51 | |||
52 | // virtual | ||
53 | LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() | ||
54 | { | ||
55 | } | ||
56 | |||
57 | // virtual | ||
58 | bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) | ||
59 | { | ||
60 | mWindGen = NULL; | ||
61 | LLAudioEngine::init(num_channels, userdata); | ||
62 | |||
63 | if(!alutInit(NULL, NULL)) | ||
64 | { | ||
65 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; | ||
66 | return false; | ||
67 | } | ||
68 | |||
69 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << LL_ENDL; | ||
70 | |||
71 | LL_INFOS("OpenAL") << "OpenAL version: " | ||
72 | << ll_safe_string(alGetString(AL_VERSION)) << LL_ENDL; | ||
73 | LL_INFOS("OpenAL") << "OpenAL vendor: " | ||
74 | << ll_safe_string(alGetString(AL_VENDOR)) << LL_ENDL; | ||
75 | LL_INFOS("OpenAL") << "OpenAL renderer: " | ||
76 | << ll_safe_string(alGetString(AL_RENDERER)) << LL_ENDL; | ||
77 | |||
78 | ALint major = alutGetMajorVersion (); | ||
79 | ALint minor = alutGetMinorVersion (); | ||
80 | LL_INFOS("OpenAL") << "ALUT version: " << major << "." << minor << LL_ENDL; | ||
81 | |||
82 | ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); | ||
83 | |||
84 | alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major); | ||
85 | alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor); | ||
86 | LL_INFOS("OpenAL") << "ALC version: " << major << "." << minor << LL_ENDL; | ||
87 | |||
88 | LL_INFOS("OpenAL") << "ALC default device: " | ||
89 | << ll_safe_string(alcGetString(device, | ||
90 | ALC_DEFAULT_DEVICE_SPECIFIER)) | ||
91 | << LL_ENDL; | ||
92 | |||
93 | return true; | ||
94 | } | ||
95 | |||
96 | // virtual | ||
97 | std::string LLAudioEngine_OpenAL::getDriverName(bool verbose) | ||
98 | { | ||
99 | ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); | ||
100 | std::ostringstream version; | ||
101 | |||
102 | version << | ||
103 | "OpenAL"; | ||
104 | |||
105 | if (verbose) | ||
106 | { | ||
107 | version << | ||
108 | ", version " << | ||
109 | ll_safe_string(alGetString(AL_VERSION)) << | ||
110 | " / " << | ||
111 | ll_safe_string(alGetString(AL_VENDOR)) << | ||
112 | " / " << | ||
113 | ll_safe_string(alGetString(AL_RENDERER)); | ||
114 | |||
115 | if (device) | ||
116 | version << | ||
117 | ": " << | ||
118 | ll_safe_string(alcGetString(device, | ||
119 | ALC_DEFAULT_DEVICE_SPECIFIER)); | ||
120 | } | ||
121 | |||
122 | return version.str(); | ||
123 | } | ||
124 | |||
125 | // virtual | ||
126 | void LLAudioEngine_OpenAL::allocateListener() | ||
127 | { | ||
128 | mListenerp = (LLListener *) new LLListener_OpenAL(); | ||
129 | if(!mListenerp) | ||
130 | { | ||
131 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << LL_ENDL; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | // virtual | ||
136 | void LLAudioEngine_OpenAL::shutdown() | ||
137 | { | ||
138 | LL_INFOS("OpenAL") << "About to LLAudioEngine::shutdown()" << LL_ENDL; | ||
139 | LLAudioEngine::shutdown(); | ||
140 | |||
141 | LL_INFOS("OpenAL") << "About to alutExit()" << LL_ENDL; | ||
142 | if(!alutExit()) | ||
143 | { | ||
144 | LL_WARNS("OpenAL") << "Nuts." << LL_ENDL; | ||
145 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; | ||
146 | } | ||
147 | |||
148 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << LL_ENDL; | ||
149 | |||
150 | delete mListenerp; | ||
151 | mListenerp = NULL; | ||
152 | } | ||
153 | |||
154 | LLAudioBuffer *LLAudioEngine_OpenAL::createBuffer() | ||
155 | { | ||
156 | return new LLAudioBufferOpenAL(); | ||
157 | } | ||
158 | |||
159 | LLAudioChannel *LLAudioEngine_OpenAL::createChannel() | ||
160 | { | ||
161 | return new LLAudioChannelOpenAL(); | ||
162 | } | ||
163 | |||
164 | void LLAudioEngine_OpenAL::setInternalGain(F32 gain) | ||
165 | { | ||
166 | //LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << LL_ENDL; | ||
167 | alListenerf(AL_GAIN, gain); | ||
168 | } | ||
169 | |||
170 | LLAudioChannelOpenAL::LLAudioChannelOpenAL() | ||
171 | : | ||
172 | mALSource(AL_NONE), | ||
173 | mLastSamplePos(0) | ||
174 | { | ||
175 | alGenSources(1, &mALSource); | ||
176 | } | ||
177 | |||
178 | LLAudioChannelOpenAL::~LLAudioChannelOpenAL() | ||
179 | { | ||
180 | cleanup(); | ||
181 | alDeleteSources(1, &mALSource); | ||
182 | } | ||
183 | |||
184 | void LLAudioChannelOpenAL::cleanup() | ||
185 | { | ||
186 | alSourceStop(mALSource); | ||
187 | mCurrentBufferp = NULL; | ||
188 | } | ||
189 | |||
190 | void LLAudioChannelOpenAL::play() | ||
191 | { | ||
192 | if (mALSource == AL_NONE) | ||
193 | { | ||
194 | LL_WARNS("OpenAL") << "Playing without a mALSource, aborting" << LL_ENDL; | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | if(!isPlaying()) | ||
199 | { | ||
200 | alSourcePlay(mALSource); | ||
201 | getSource()->setPlayedOnce(true); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp) | ||
206 | { | ||
207 | if (channelp) | ||
208 | { | ||
209 | LLAudioChannelOpenAL *masterchannelp = | ||
210 | (LLAudioChannelOpenAL*)channelp; | ||
211 | if (mALSource != AL_NONE && | ||
212 | masterchannelp->mALSource != AL_NONE) | ||
213 | { | ||
214 | // we have channels allocated to master and slave | ||
215 | ALfloat master_offset; | ||
216 | alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET, | ||
217 | &master_offset); | ||
218 | |||
219 | LL_INFOS("OpenAL") << "Syncing with master at " << master_offset | ||
220 | << "sec" << LL_ENDL; | ||
221 | // *TODO: detect when this fails, maybe use AL_SAMPLE_ | ||
222 | alSourcef(mALSource, AL_SEC_OFFSET, master_offset); | ||
223 | } | ||
224 | } | ||
225 | play(); | ||
226 | } | ||
227 | |||
228 | bool LLAudioChannelOpenAL::isPlaying() | ||
229 | { | ||
230 | if (mALSource != AL_NONE) | ||
231 | { | ||
232 | ALint state; | ||
233 | alGetSourcei(mALSource, AL_SOURCE_STATE, &state); | ||
234 | if(state == AL_PLAYING) | ||
235 | { | ||
236 | return true; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | return false; | ||
241 | } | ||
242 | |||
243 | bool LLAudioChannelOpenAL::updateBuffer() | ||
244 | { | ||
245 | if (LLAudioChannel::updateBuffer()) | ||
246 | { | ||
247 | // Base class update returned true, which means that we need to actually | ||
248 | // set up the source for a different buffer. | ||
249 | LLAudioBufferOpenAL *bufferp = (LLAudioBufferOpenAL *)mCurrentSourcep->getCurrentBuffer(); | ||
250 | ALuint buffer = bufferp->getBuffer(); | ||
251 | alSourcei(mALSource, AL_BUFFER, buffer); | ||
252 | mLastSamplePos = 0; | ||
253 | } | ||
254 | |||
255 | if (mCurrentSourcep) | ||
256 | { | ||
257 | alSourcef(mALSource, AL_GAIN, | ||
258 | mCurrentSourcep->getGain() * getSecondaryGain()); | ||
259 | alSourcei(mALSource, AL_LOOPING, | ||
260 | mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE); | ||
261 | alSourcef(mALSource, AL_ROLLOFF_FACTOR, | ||
262 | gAudiop->mListenerp->getRolloffFactor()); | ||
263 | alSourcef(mALSource, AL_REFERENCE_DISTANCE, | ||
264 | gAudiop->mListenerp->getDistanceFactor()); | ||
265 | } | ||
266 | |||
267 | return true; | ||
268 | } | ||
269 | |||
270 | |||
271 | void LLAudioChannelOpenAL::updateLoop() | ||
272 | { | ||
273 | if (mALSource == AL_NONE) | ||
274 | { | ||
275 | return; | ||
276 | } | ||
277 | |||
278 | // Hack: We keep track of whether we looped or not by seeing when the | ||
279 | // sample position looks like it's going backwards. Not reliable; may | ||
280 | // yield false negatives. | ||
281 | // | ||
282 | ALint cur_pos; | ||
283 | alGetSourcei(mALSource, AL_SAMPLE_OFFSET, &cur_pos); | ||
284 | if (cur_pos < mLastSamplePos) | ||
285 | { | ||
286 | mLoopedThisFrame = true; | ||
287 | } | ||
288 | mLastSamplePos = cur_pos; | ||
289 | } | ||
290 | |||
291 | |||
292 | void LLAudioChannelOpenAL::update3DPosition() | ||
293 | { | ||
294 | if(!mCurrentSourcep) | ||
295 | { | ||
296 | return; | ||
297 | } | ||
298 | if (mCurrentSourcep->isAmbient()) | ||
299 | { | ||
300 | alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0); | ||
301 | alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0); | ||
302 | //alSource3f(mALSource, AL_DIRECTION, 0.0, 0.0, 0.0); | ||
303 | alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_TRUE); | ||
304 | } else { | ||
305 | LLVector3 float_pos; | ||
306 | float_pos.setVec(mCurrentSourcep->getPositionGlobal()); | ||
307 | alSourcefv(mALSource, AL_POSITION, float_pos.mV); | ||
308 | alSourcefv(mALSource, AL_VELOCITY, mCurrentSourcep->getVelocity().mV); | ||
309 | //alSource3f(mALSource, AL_DIRECTION, 0.0, 0.0, 0.0); | ||
310 | alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_FALSE); | ||
311 | } | ||
312 | |||
313 | alSourcef(mALSource, AL_GAIN, mCurrentSourcep->getGain() * getSecondaryGain()); | ||
314 | } | ||
315 | |||
316 | LLAudioBufferOpenAL::LLAudioBufferOpenAL() | ||
317 | { | ||
318 | mALBuffer = AL_NONE; | ||
319 | } | ||
320 | |||
321 | LLAudioBufferOpenAL::~LLAudioBufferOpenAL() | ||
322 | { | ||
323 | cleanup(); | ||
324 | } | ||
325 | |||
326 | void LLAudioBufferOpenAL::cleanup() | ||
327 | { | ||
328 | if(mALBuffer != AL_NONE) | ||
329 | { | ||
330 | alDeleteBuffers(1, &mALBuffer); | ||
331 | mALBuffer = AL_NONE; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | bool LLAudioBufferOpenAL::loadWAV(const std::string& filename) | ||
336 | { | ||
337 | cleanup(); | ||
338 | mALBuffer = alutCreateBufferFromFile(filename.c_str()); | ||
339 | if(mALBuffer == AL_NONE) | ||
340 | { | ||
341 | ALenum error = alutGetError(); | ||
342 | if (gDirUtilp->fileExists(filename)) | ||
343 | { | ||
344 | LL_WARNS("OpenAL") << | ||
345 | "LLAudioBufferOpenAL::loadWAV() Error loading " | ||
346 | << filename | ||
347 | << " " << alutGetErrorString(error) << LL_ENDL; | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | // It's common for the file to not actually exist. | ||
352 | LL_DEBUGS("OpenAL") << | ||
353 | "LLAudioBufferOpenAL::loadWAV() Error loading " | ||
354 | << filename | ||
355 | << " " << alutGetErrorString(error) << LL_ENDL; | ||
356 | } | ||
357 | return false; | ||
358 | } | ||
359 | |||
360 | return true; | ||
361 | } | ||
362 | |||
363 | U32 LLAudioBufferOpenAL::getLength() | ||
364 | { | ||
365 | if(mALBuffer == AL_NONE) | ||
366 | { | ||
367 | return 0; | ||
368 | } | ||
369 | ALint length; | ||
370 | alGetBufferi(mALBuffer, AL_SIZE, &length); | ||
371 | return length >> 2; | ||
372 | } | ||
373 | |||
374 | // ------------ | ||
375 | |||
376 | void LLAudioEngine_OpenAL::initWind() | ||
377 | { | ||
378 | ALenum error; | ||
379 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::initWind() start" << LL_ENDL; | ||
380 | |||
381 | mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS; | ||
382 | |||
383 | alGetError(); /* clear error */ | ||
384 | |||
385 | alGenSources(1,&mWindSource); | ||
386 | |||
387 | if((error=alGetError()) != AL_NO_ERROR) | ||
388 | { | ||
389 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<<error<<LL_ENDL; | ||
390 | } | ||
391 | |||
392 | mWindGen = new LLWindGen<WIND_SAMPLE_T>; | ||
393 | |||
394 | mWindBufFreq = mWindGen->getInputSamplingRate(); | ||
395 | mWindBufSamples = llceil(mWindBufFreq * WIND_BUFFER_SIZE_SEC); | ||
396 | mWindBufBytes = mWindBufSamples * 2 /*stereo*/ * sizeof(WIND_SAMPLE_T); | ||
397 | |||
398 | mWindBuf = new WIND_SAMPLE_T [mWindBufSamples * 2 /*stereo*/]; | ||
399 | |||
400 | if(mWindBuf==NULL) | ||
401 | { | ||
402 | LL_ERRS("OpenAL") << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << LL_ENDL; | ||
403 | mEnableWind=false; | ||
404 | } | ||
405 | |||
406 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::initWind() done" << LL_ENDL; | ||
407 | } | ||
408 | |||
409 | void LLAudioEngine_OpenAL::cleanupWind() | ||
410 | { | ||
411 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::cleanupWind()" << LL_ENDL; | ||
412 | |||
413 | if (mWindSource != AL_NONE) | ||
414 | { | ||
415 | // detach and delete all outstanding buffers on the wind source | ||
416 | alSourceStop(mWindSource); | ||
417 | int processed; | ||
418 | alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); | ||
419 | while (processed--) | ||
420 | { | ||
421 | ALuint buffer = AL_NONE; | ||
422 | alSourceUnqueueBuffers(mWindSource, 1, &buffer); | ||
423 | alDeleteBuffers(1, &buffer); | ||
424 | } | ||
425 | |||
426 | // delete the wind source itself | ||
427 | alDeleteSources(1, &mWindSource); | ||
428 | |||
429 | mWindSource = AL_NONE; | ||
430 | } | ||
431 | |||
432 | delete[] mWindBuf; | ||
433 | mWindBuf = NULL; | ||
434 | |||
435 | delete mWindGen; | ||
436 | mWindGen = NULL; | ||
437 | } | ||
438 | |||
439 | void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) | ||
440 | { | ||
441 | LLVector3 wind_pos; | ||
442 | F64 pitch; | ||
443 | F64 center_freq; | ||
444 | ALenum error; | ||
445 | |||
446 | if (!mEnableWind) | ||
447 | return; | ||
448 | |||
449 | if(!mWindBuf) | ||
450 | return; | ||
451 | |||
452 | if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) | ||
453 | { | ||
454 | |||
455 | // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) | ||
456 | // need to convert this to the conventional orientation DS3D and OpenAL use | ||
457 | // where +X = right, +Y = up, +Z = backwards | ||
458 | |||
459 | wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); | ||
460 | |||
461 | pitch = 1.0 + mapWindVecToPitch(wind_vec); | ||
462 | center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); | ||
463 | |||
464 | mWindGen->mTargetFreq = (F32)center_freq; | ||
465 | mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; | ||
466 | mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); | ||
467 | |||
468 | alSourcei(mWindSource, AL_LOOPING, AL_FALSE); | ||
469 | alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0); | ||
470 | alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0); | ||
471 | alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0); | ||
472 | alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE); | ||
473 | } | ||
474 | |||
475 | // ok lets make a wind buffer now | ||
476 | |||
477 | int processed, queued, unprocessed; | ||
478 | alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); | ||
479 | alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued); | ||
480 | unprocessed = queued - processed; | ||
481 | |||
482 | // ensure that there are always at least 3x as many filled buffers | ||
483 | // queued as we managed to empty since last time. | ||
484 | mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed); | ||
485 | mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0); | ||
486 | |||
487 | //LL_INFOS("OpenAL") << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << LL_ENDL; | ||
488 | |||
489 | while(processed--) // unqueue old buffers | ||
490 | { | ||
491 | ALuint buffer; | ||
492 | int error; | ||
493 | alGetError(); /* clear error */ | ||
494 | alSourceUnqueueBuffers(mWindSource, 1, &buffer); | ||
495 | error = alGetError(); | ||
496 | if(error != AL_NO_ERROR) | ||
497 | { | ||
498 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL; | ||
499 | } | ||
500 | else | ||
501 | { | ||
502 | alDeleteBuffers(1, &buffer); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | unprocessed += mNumEmptyWindALBuffers; | ||
507 | while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers | ||
508 | { | ||
509 | ALuint buffer; | ||
510 | alGetError(); /* clear error */ | ||
511 | alGenBuffers(1,&buffer); | ||
512 | if((error=alGetError()) != AL_NO_ERROR) | ||
513 | { | ||
514 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::initWind() Error creating wind buffer: " << error << LL_ENDL; | ||
515 | break; | ||
516 | } | ||
517 | |||
518 | alBufferData(buffer, | ||
519 | AL_FORMAT_STEREO16, | ||
520 | mWindGen->windGenerate(mWindBuf, | ||
521 | mWindBufSamples, 2), | ||
522 | mWindBufBytes, | ||
523 | mWindBufFreq); | ||
524 | error = alGetError(); | ||
525 | if(error != AL_NO_ERROR) | ||
526 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL; | ||
527 | |||
528 | alSourceQueueBuffers(mWindSource, 1, &buffer); | ||
529 | error = alGetError(); | ||
530 | if(error != AL_NO_ERROR) | ||
531 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL; | ||
532 | |||
533 | --mNumEmptyWindALBuffers; | ||
534 | } | ||
535 | |||
536 | int playing; | ||
537 | alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing); | ||
538 | if(playing != AL_PLAYING) | ||
539 | { | ||
540 | alSourcePlay(mWindSource); | ||
541 | |||
542 | LL_INFOS("OpenAL") << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL; | ||
543 | } | ||
544 | } | ||