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