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..a956131 --- /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 | LLAudioEngine_OpenAL::LLAudioEngine_OpenAL() | ||
40 | : | ||
41 | mWindGen(NULL), | ||
42 | mWindBuf(NULL), | ||
43 | mWindBufFreq(0), | ||
44 | mWindBufSamples(0), | ||
45 | mWindBufBytes(0), | ||
46 | mWindSource(AL_NONE), | ||
47 | mNumEmptyWindALBuffers(MAX_NUM_WIND_BUFFERS) | ||
48 | { | ||
49 | } | ||
50 | |||
51 | // virtual | ||
52 | LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() | ||
53 | { | ||
54 | } | ||
55 | |||
56 | // virtual | ||
57 | bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) | ||
58 | { | ||
59 | mWindGen = NULL; | ||
60 | LLAudioEngine::init(num_channels, userdata); | ||
61 | |||
62 | if(!alutInit(NULL, NULL)) | ||
63 | { | ||
64 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; | ||
65 | return false; | ||
66 | } | ||
67 | |||
68 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << LL_ENDL; | ||
69 | |||
70 | LL_INFOS("OpenAL") << "OpenAL version: " | ||
71 | << ll_safe_string(alGetString(AL_VERSION)) << LL_ENDL; | ||
72 | LL_INFOS("OpenAL") << "OpenAL vendor: " | ||
73 | << ll_safe_string(alGetString(AL_VENDOR)) << LL_ENDL; | ||
74 | LL_INFOS("OpenAL") << "OpenAL renderer: " | ||
75 | << ll_safe_string(alGetString(AL_RENDERER)) << LL_ENDL; | ||
76 | |||
77 | ALint major = alutGetMajorVersion (); | ||
78 | ALint minor = alutGetMinorVersion (); | ||
79 | LL_INFOS("OpenAL") << "ALUT version: " << major << "." << minor << LL_ENDL; | ||
80 | |||
81 | ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); | ||
82 | |||
83 | alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major); | ||
84 | alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor); | ||
85 | LL_INFOS("OpenAL") << "ALC version: " << major << "." << minor << LL_ENDL; | ||
86 | |||
87 | LL_INFOS("OpenAL") << "ALC default device: " | ||
88 | << ll_safe_string(alcGetString(device, | ||
89 | ALC_DEFAULT_DEVICE_SPECIFIER)) | ||
90 | << LL_ENDL; | ||
91 | |||
92 | return true; | ||
93 | } | ||
94 | |||
95 | // virtual | ||
96 | std::string LLAudioEngine_OpenAL::getDriverName(bool verbose) | ||
97 | { | ||
98 | ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); | ||
99 | std::ostringstream version; | ||
100 | |||
101 | version << | ||
102 | "OpenAL"; | ||
103 | |||
104 | if (verbose) | ||
105 | { | ||
106 | version << | ||
107 | ", version " << | ||
108 | ll_safe_string(alGetString(AL_VERSION)) << | ||
109 | " / " << | ||
110 | ll_safe_string(alGetString(AL_VENDOR)) << | ||
111 | " / " << | ||
112 | ll_safe_string(alGetString(AL_RENDERER)); | ||
113 | |||
114 | if (device) | ||
115 | version << | ||
116 | ": " << | ||
117 | ll_safe_string(alcGetString(device, | ||
118 | ALC_DEFAULT_DEVICE_SPECIFIER)); | ||
119 | } | ||
120 | |||
121 | return version.str(); | ||
122 | } | ||
123 | |||
124 | // virtual | ||
125 | void LLAudioEngine_OpenAL::allocateListener() | ||
126 | { | ||
127 | mListenerp = (LLListener *) new LLListener_OpenAL(); | ||
128 | if(!mListenerp) | ||
129 | { | ||
130 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << LL_ENDL; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | // virtual | ||
135 | void LLAudioEngine_OpenAL::shutdown() | ||
136 | { | ||
137 | LL_INFOS("OpenAL") << "About to LLAudioEngine::shutdown()" << LL_ENDL; | ||
138 | LLAudioEngine::shutdown(); | ||
139 | |||
140 | LL_INFOS("OpenAL") << "About to alutExit()" << LL_ENDL; | ||
141 | if(!alutExit()) | ||
142 | { | ||
143 | LL_WARNS("OpenAL") << "Nuts." << LL_ENDL; | ||
144 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; | ||
145 | } | ||
146 | |||
147 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << LL_ENDL; | ||
148 | |||
149 | delete mListenerp; | ||
150 | mListenerp = NULL; | ||
151 | } | ||
152 | |||
153 | LLAudioBuffer *LLAudioEngine_OpenAL::createBuffer() | ||
154 | { | ||
155 | return new LLAudioBufferOpenAL(); | ||
156 | } | ||
157 | |||
158 | LLAudioChannel *LLAudioEngine_OpenAL::createChannel() | ||
159 | { | ||
160 | return new LLAudioChannelOpenAL(); | ||
161 | } | ||
162 | |||
163 | void LLAudioEngine_OpenAL::setInternalGain(F32 gain) | ||
164 | { | ||
165 | //LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << LL_ENDL; | ||
166 | alListenerf(AL_GAIN, gain); | ||
167 | } | ||
168 | |||
169 | LLAudioChannelOpenAL::LLAudioChannelOpenAL() | ||
170 | : | ||
171 | mALSource(AL_NONE), | ||
172 | mLastSamplePos(0) | ||
173 | { | ||
174 | alGenSources(1, &mALSource); | ||
175 | } | ||
176 | |||
177 | LLAudioChannelOpenAL::~LLAudioChannelOpenAL() | ||
178 | { | ||
179 | cleanup(); | ||
180 | alDeleteSources(1, &mALSource); | ||
181 | } | ||
182 | |||
183 | void LLAudioChannelOpenAL::cleanup() | ||
184 | { | ||
185 | alSourceStop(mALSource); | ||
186 | mCurrentBufferp = NULL; | ||
187 | } | ||
188 | |||
189 | void LLAudioChannelOpenAL::play() | ||
190 | { | ||
191 | if (mALSource == AL_NONE) | ||
192 | { | ||
193 | LL_WARNS("OpenAL") << "Playing without a mALSource, aborting" << LL_ENDL; | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | if(!isPlaying()) | ||
198 | { | ||
199 | alSourcePlay(mALSource); | ||
200 | getSource()->setPlayedOnce(true); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp) | ||
205 | { | ||
206 | if (channelp) | ||
207 | { | ||
208 | LLAudioChannelOpenAL *masterchannelp = | ||
209 | (LLAudioChannelOpenAL*)channelp; | ||
210 | if (mALSource != AL_NONE && | ||
211 | masterchannelp->mALSource != AL_NONE) | ||
212 | { | ||
213 | // we have channels allocated to master and slave | ||
214 | ALfloat master_offset; | ||
215 | alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET, | ||
216 | &master_offset); | ||
217 | |||
218 | LL_INFOS("OpenAL") << "Syncing with master at " << master_offset | ||
219 | << "sec" << LL_ENDL; | ||
220 | // *TODO: detect when this fails, maybe use AL_SAMPLE_ | ||
221 | alSourcef(mALSource, AL_SEC_OFFSET, master_offset); | ||
222 | } | ||
223 | } | ||
224 | play(); | ||
225 | } | ||
226 | |||
227 | bool LLAudioChannelOpenAL::isPlaying() | ||
228 | { | ||
229 | if (mALSource != AL_NONE) | ||
230 | { | ||
231 | ALint state; | ||
232 | alGetSourcei(mALSource, AL_SOURCE_STATE, &state); | ||
233 | if(state == AL_PLAYING) | ||
234 | { | ||
235 | return true; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | return false; | ||
240 | } | ||
241 | |||
242 | bool LLAudioChannelOpenAL::updateBuffer() | ||
243 | { | ||
244 | if (LLAudioChannel::updateBuffer()) | ||
245 | { | ||
246 | // Base class update returned true, which means that we need to actually | ||
247 | // set up the source for a different buffer. | ||
248 | LLAudioBufferOpenAL *bufferp = (LLAudioBufferOpenAL *)mCurrentSourcep->getCurrentBuffer(); | ||
249 | ALuint buffer = bufferp->getBuffer(); | ||
250 | alSourcei(mALSource, AL_BUFFER, buffer); | ||
251 | mLastSamplePos = 0; | ||
252 | } | ||
253 | |||
254 | if (mCurrentSourcep) | ||
255 | { | ||
256 | alSourcef(mALSource, AL_GAIN, | ||
257 | mCurrentSourcep->getGain() * getSecondaryGain()); | ||
258 | alSourcei(mALSource, AL_LOOPING, | ||
259 | mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE); | ||
260 | alSourcef(mALSource, AL_ROLLOFF_FACTOR, | ||
261 | gAudiop->mListenerp->getRolloffFactor()); | ||
262 | alSourcef(mALSource, AL_REFERENCE_DISTANCE, | ||
263 | gAudiop->mListenerp->getDistanceFactor()); | ||
264 | } | ||
265 | |||
266 | return true; | ||
267 | } | ||
268 | |||
269 | |||
270 | void LLAudioChannelOpenAL::updateLoop() | ||
271 | { | ||
272 | if (mALSource == AL_NONE) | ||
273 | { | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | // Hack: We keep track of whether we looped or not by seeing when the | ||
278 | // sample position looks like it's going backwards. Not reliable; may | ||
279 | // yield false negatives. | ||
280 | // | ||
281 | ALint cur_pos; | ||
282 | alGetSourcei(mALSource, AL_SAMPLE_OFFSET, &cur_pos); | ||
283 | if (cur_pos < mLastSamplePos) | ||
284 | { | ||
285 | mLoopedThisFrame = true; | ||
286 | } | ||
287 | mLastSamplePos = cur_pos; | ||
288 | } | ||
289 | |||
290 | |||
291 | void LLAudioChannelOpenAL::update3DPosition() | ||
292 | { | ||
293 | if(!mCurrentSourcep) | ||
294 | { | ||
295 | return; | ||
296 | } | ||
297 | if (mCurrentSourcep->isAmbient()) | ||
298 | { | ||
299 | alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0); | ||
300 | alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0); | ||
301 | //alSource3f(mALSource, AL_DIRECTION, 0.0, 0.0, 0.0); | ||
302 | alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_TRUE); | ||
303 | } else { | ||
304 | LLVector3 float_pos; | ||
305 | float_pos.setVec(mCurrentSourcep->getPositionGlobal()); | ||
306 | alSourcefv(mALSource, AL_POSITION, float_pos.mV); | ||
307 | alSourcefv(mALSource, AL_VELOCITY, mCurrentSourcep->getVelocity().mV); | ||
308 | //alSource3f(mALSource, AL_DIRECTION, 0.0, 0.0, 0.0); | ||
309 | alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_FALSE); | ||
310 | } | ||
311 | |||
312 | alSourcef(mALSource, AL_GAIN, mCurrentSourcep->getGain() * getSecondaryGain()); | ||
313 | } | ||
314 | |||
315 | LLAudioBufferOpenAL::LLAudioBufferOpenAL() | ||
316 | { | ||
317 | mALBuffer = AL_NONE; | ||
318 | } | ||
319 | |||
320 | LLAudioBufferOpenAL::~LLAudioBufferOpenAL() | ||
321 | { | ||
322 | cleanup(); | ||
323 | } | ||
324 | |||
325 | void LLAudioBufferOpenAL::cleanup() | ||
326 | { | ||
327 | if(mALBuffer != AL_NONE) | ||
328 | { | ||
329 | alDeleteBuffers(1, &mALBuffer); | ||
330 | mALBuffer = AL_NONE; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | bool LLAudioBufferOpenAL::loadWAV(const std::string& filename) | ||
335 | { | ||
336 | cleanup(); | ||
337 | mALBuffer = alutCreateBufferFromFile(filename.c_str()); | ||
338 | if(mALBuffer == AL_NONE) | ||
339 | { | ||
340 | ALenum error = alutGetError(); | ||
341 | if (gDirUtilp->fileExists(filename)) | ||
342 | { | ||
343 | LL_WARNS("OpenAL") << | ||
344 | "LLAudioBufferOpenAL::loadWAV() Error loading " | ||
345 | << filename | ||
346 | << " " << alutGetErrorString(error) << LL_ENDL; | ||
347 | } | ||
348 | else | ||
349 | { | ||
350 | // It's common for the file to not actually exist. | ||
351 | LL_DEBUGS("OpenAL") << | ||
352 | "LLAudioBufferOpenAL::loadWAV() Error loading " | ||
353 | << filename | ||
354 | << " " << alutGetErrorString(error) << LL_ENDL; | ||
355 | } | ||
356 | return false; | ||
357 | } | ||
358 | |||
359 | return true; | ||
360 | } | ||
361 | |||
362 | U32 LLAudioBufferOpenAL::getLength() | ||
363 | { | ||
364 | if(mALBuffer == AL_NONE) | ||
365 | { | ||
366 | return 0; | ||
367 | } | ||
368 | ALint length; | ||
369 | alGetBufferi(mALBuffer, AL_SIZE, &length); | ||
370 | return length >> 2; | ||
371 | } | ||
372 | |||
373 | // ------------ | ||
374 | |||
375 | void LLAudioEngine_OpenAL::initWind() | ||
376 | { | ||
377 | ALenum error; | ||
378 | LL_INFOS("OpenAL") << "LLAudioEngine_OpenAL::initWind() start" << LL_ENDL; | ||
379 | |||
380 | mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS; | ||
381 | |||
382 | alGetError(); /* clear error */ | ||
383 | |||
384 | alGenSources(1,&mWindSource); | ||
385 | |||
386 | if((error=alGetError()) != AL_NO_ERROR) | ||
387 | { | ||
388 | LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<<error<<LL_ENDL; | ||
389 | } | ||
390 | |||
391 | mWindGen = new LLWindGen<WIND_SAMPLE_T>; | ||
392 | const float WIND_BUFFER_SIZE_SEC = 0.05f; // 1/20th sec | ||
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 | } | ||