aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llaudio/llaudioengine_fmod.cpp
diff options
context:
space:
mode:
authorArmin Weatherwax2010-06-14 12:04:49 +0200
committerArmin Weatherwax2010-09-23 15:38:25 +0200
commit35df5441d3e2789663532c948731aff3a1e04728 (patch)
treeac7674289784a5f96106ea507637055a8dada78a /linden/indra/llaudio/llaudioengine_fmod.cpp
parentChanged version to Experimental 2010.09.18 (diff)
downloadmeta-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_fmod.cpp')
-rw-r--r--linden/indra/llaudio/llaudioengine_fmod.cpp766
1 files changed, 766 insertions, 0 deletions
diff --git a/linden/indra/llaudio/llaudioengine_fmod.cpp b/linden/indra/llaudio/llaudioengine_fmod.cpp
new file mode 100644
index 0000000..85ae863
--- /dev/null
+++ b/linden/indra/llaudio/llaudioengine_fmod.cpp
@@ -0,0 +1,766 @@
1/**
2 * @file audioengine_fmod.cpp
3 * @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * 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
35#include "llstreamingaudio.h"
36#include "llstreamingaudio_fmod.h"
37
38#include "llaudioengine_fmod.h"
39#include "lllistener_fmod.h"
40
41#include "llerror.h"
42#include "llmath.h"
43#include "llrand.h"
44
45#include "fmod.h"
46#include "fmod_errors.h"
47#include "lldir.h"
48#include "llapr.h"
49
50#include "sound_ids.h"
51
52
53extern "C" {
54 void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata);
55}
56
57FSOUND_DSPUNIT *gWindDSP = NULL;
58
59
60LLAudioEngine_FMOD::LLAudioEngine_FMOD()
61{
62 mInited = false;
63 mWindGen = NULL;
64}
65
66
67LLAudioEngine_FMOD::~LLAudioEngine_FMOD()
68{
69}
70
71
72bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata)
73{
74 LLAudioEngine::init(num_channels, userdata);
75
76 // Reserve one extra channel for the http stream.
77 if (!FSOUND_SetMinHardwareChannels(num_channels + 1))
78 {
79 LL_WARNS("AppInit") << "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
80 }
81
82 LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() initializing FMOD" << LL_ENDL;
83
84 F32 version = FSOUND_GetVersion();
85 if (version < FMOD_VERSION)
86 {
87 LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
88 << ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL;
89 //return false;
90 }
91
92 U32 fmod_flags = 0x0;
93
94#if LL_WINDOWS
95 // Windows needs to know which window is frontmost.
96 // This must be called before FSOUND_Init() per the FMOD docs.
97 // This could be used to let FMOD handle muting when we lose focus,
98 // but we don't actually want to do that because we want to distinguish
99 // between minimized and not-focused states.
100 if (!FSOUND_SetHWND(userdata))
101 {
102 LL_WARNS("AppInit") << "Error setting FMOD window: "
103 << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
104 return false;
105 }
106 // Play audio when we don't have focus.
107 // (For example, IM client on top of us.)
108 // This means we also try to play audio when minimized,
109 // so we manually handle muting in that case. JC
110 fmod_flags |= FSOUND_INIT_GLOBALFOCUS;
111#endif
112
113#if LL_LINUX
114 // initialize the FMOD engine
115
116 // This is a hack to use only FMOD's basic FPU mixer
117 // when the LL_VALGRIND environmental variable is set,
118 // otherwise valgrind will fall over on FMOD's MMX detection
119 if (getenv("LL_VALGRIND")) /*Flawfinder: ignore*/
120 {
121 LL_INFOS("AppInit") << "Pacifying valgrind in FMOD init." << LL_ENDL;
122 FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU);
123 }
124
125 // If we don't set an output method, Linux FMOD always
126 // decides on OSS and fails otherwise. So we'll manually
127 // try ESD, then OSS, then ALSA.
128 // Why this order? See SL-13250, but in short, OSS emulated
129 // on top of ALSA is ironically more reliable than raw ALSA.
130 // Ack, and ESD has more reliable failure modes - but has worse
131 // latency - than all of them, so wins for now.
132 bool audio_ok = false;
133
134 if (!audio_ok)
135 if (NULL == getenv("LL_BAD_FMOD_ESD")) /*Flawfinder: ignore*/
136 {
137 LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
138 if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) &&
139 FSOUND_Init(44100, num_channels, fmod_flags))
140 {
141 LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY"
142 << LL_ENDL;
143 audio_ok = true;
144 } else {
145 LL_WARNS("AppInit") << "ESD audio output FAILED to initialize: "
146 << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
147 }
148 } else {
149 LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL;
150 }
151
152 if (!audio_ok)
153 if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/
154 {
155 LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL;
156 if(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) &&
157 FSOUND_Init(44100, num_channels, fmod_flags))
158 {
159 LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
160 audio_ok = true;
161 } else {
162 LL_WARNS("AppInit") << "OSS audio output FAILED to initialize: "
163 << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
164 }
165 } else {
166 LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
167 }
168
169 if (!audio_ok)
170 if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/
171 {
172 LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
173 if(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) &&
174 FSOUND_Init(44100, num_channels, fmod_flags))
175 {
176 LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
177 audio_ok = true;
178 } else {
179 LL_WARNS("AppInit") << "ALSA audio output FAILED to initialize: "
180 << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
181 }
182 } else {
183 LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
184 }
185
186 if (!audio_ok)
187 {
188 LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
189 return false;
190 }
191
192 // On Linux, FMOD causes a SIGPIPE for some netstream error
193 // conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us.
194 // NOW FIXED in FMOD 3.x since 2006-10-01.
195 //signal(SIGPIPE, SIG_IGN);
196
197 // We're interested in logging which output method we
198 // ended up with, for QA purposes.
199 switch (FSOUND_GetOutput())
200 {
201 case FSOUND_OUTPUT_NOSOUND: LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
202 case FSOUND_OUTPUT_OSS: LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
203 case FSOUND_OUTPUT_ESD: LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break;
204 case FSOUND_OUTPUT_ALSA: LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
205 default: LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
206 };
207
208#else // LL_LINUX
209
210 // initialize the FMOD engine
211 if (!FSOUND_Init(44100, num_channels, fmod_flags))
212 {
213 LL_WARNS("AppInit") << "Error initializing FMOD: "
214 << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
215 return false;
216 }
217
218#endif
219
220 // set up our favourite FMOD-native streaming audio implementation if none has already been added
221 if (!getStreamingAudioImpl()) // no existing implementation added
222 setStreamingAudioImpl(new LLStreamingAudio_FMOD());
223
224 LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL;
225
226 mInited = true;
227
228 return true;
229}
230
231
232std::string LLAudioEngine_FMOD::getDriverName(bool verbose)
233{
234 if (verbose)
235 {
236 F32 version = FSOUND_GetVersion();
237 return llformat("FMOD version %f", version);
238 }
239 else
240 {
241 return "FMOD";
242 }
243}
244
245
246void LLAudioEngine_FMOD::allocateListener(void)
247{
248 mListenerp = (LLListener *) new LLListener_FMOD();
249 if (!mListenerp)
250 {
251 llwarns << "Listener creation failed" << llendl;
252 }
253}
254
255
256void LLAudioEngine_FMOD::shutdown()
257{
258 if (gWindDSP)
259 {
260 FSOUND_DSP_SetActive(gWindDSP,false);
261 FSOUND_DSP_Free(gWindDSP);
262 }
263
264 stopInternetStream();
265
266 LLAudioEngine::shutdown();
267
268 llinfos << "LLAudioEngine_FMOD::shutdown() closing FMOD" << llendl;
269 FSOUND_Close();
270 llinfos << "LLAudioEngine_FMOD::shutdown() done closing FMOD" << llendl;
271
272 delete mListenerp;
273 mListenerp = NULL;
274}
275
276
277LLAudioBuffer * LLAudioEngine_FMOD::createBuffer()
278{
279 return new LLAudioBufferFMOD();
280}
281
282
283LLAudioChannel * LLAudioEngine_FMOD::createChannel()
284{
285 return new LLAudioChannelFMOD();
286}
287
288
289void LLAudioEngine_FMOD::initWind()
290{
291 mWindGen = new LLWindGen<MIXBUFFERFORMAT>;
292
293 if (!gWindDSP)
294 {
295 gWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen);
296 }
297 if (gWindDSP)
298 {
299 FSOUND_DSP_SetActive(gWindDSP, true);
300 }
301 mNextWindUpdate = 0.0;
302}
303
304
305void LLAudioEngine_FMOD::cleanupWind()
306{
307 if (gWindDSP)
308 {
309 FSOUND_DSP_SetActive(gWindDSP, false);
310 FSOUND_DSP_Free(gWindDSP);
311 gWindDSP = NULL;
312 }
313
314 delete mWindGen;
315 mWindGen = NULL;
316}
317
318
319//-----------------------------------------------------------------------
320void LLAudioEngine_FMOD::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
321{
322 LLVector3 wind_pos;
323 F64 pitch;
324 F64 center_freq;
325
326 if (!mEnableWind)
327 {
328 return;
329 }
330
331 if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
332 {
333
334 // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
335 // need to convert this to the conventional orientation DS3D and OpenAL use
336 // where +X = right, +Y = up, +Z = backwards
337
338 wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
339
340 // cerr << "Wind update" << endl;
341
342 pitch = 1.0 + mapWindVecToPitch(wind_vec);
343 center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
344
345 mWindGen->mTargetFreq = (F32)center_freq;
346 mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
347 mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
348 }
349}
350
351/*
352//-----------------------------------------------------------------------
353void LLAudioEngine_FMOD::setSourceMinDistance(U16 source_num, F64 distance)
354{
355 if (!mInited)
356 {
357 return;
358 }
359 if (mBuffer[source_num])
360 {
361 mMinDistance[source_num] = (F32) distance;
362 if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
363 {
364 llwarns << "FMOD::setSourceMinDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
365 }
366 }
367}
368
369//-----------------------------------------------------------------------
370void LLAudioEngine_FMOD::setSourceMaxDistance(U16 source_num, F64 distance)
371{
372 if (!mInited)
373 {
374 return;
375 }
376 if (mBuffer[source_num])
377 {
378 mMaxDistance[source_num] = (F32) distance;
379 if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
380 {
381 llwarns << "FMOD::setSourceMaxDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
382 }
383 }
384}
385
386//-----------------------------------------------------------------------
387void LLAudioEngine_FMOD::get3DParams(S32 source_num, S32 *volume, S32 *freq, S32 *inside, S32 *outside, LLVector3 *orient, S32 *out_volume, F32 *min_dist, F32 *max_dist)
388{
389 *volume = 0;
390 *freq = 0;
391 *inside = 0;
392 *outside = 0;
393 *orient = LLVector3::zero;
394 *out_volume = 0;
395 *min_dist = 0.f;
396 *max_dist = 0.f;
397}
398
399*/
400
401
402//-----------------------------------------------------------------------
403void LLAudioEngine_FMOD::setInternalGain(F32 gain)
404{
405 if (!mInited)
406 {
407 return;
408 }
409
410 gain = llclamp( gain, 0.0f, 1.0f );
411 FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) );
412
413 LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
414 if ( saimpl )
415 {
416 // fmod likes its streaming audio channel gain re-asserted after
417 // master volume change.
418 saimpl->setGain(saimpl->getGain());
419 }
420}
421
422//
423// LLAudioChannelFMOD implementation
424//
425
426LLAudioChannelFMOD::LLAudioChannelFMOD() : LLAudioChannel(), mChannelID(0), mLastSamplePos(0)
427{
428}
429
430
431LLAudioChannelFMOD::~LLAudioChannelFMOD()
432{
433 cleanup();
434}
435
436
437bool LLAudioChannelFMOD::updateBuffer()
438{
439 if (LLAudioChannel::updateBuffer())
440 {
441 // Base class update returned true, which means that we need to actually
442 // set up the channel for a different buffer.
443
444 LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer();
445
446 // Grab the FMOD sample associated with the buffer
447 FSOUND_SAMPLE *samplep = bufferp->getSample();
448 if (!samplep)
449 {
450 // This is bad, there should ALWAYS be a sample associated with a legit
451 // buffer.
452 llerrs << "No FMOD sample!" << llendl;
453 return false;
454 }
455
456
457 // Actually play the sound. Start it off paused so we can do all the necessary
458 // setup.
459 mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), true);
460
461 //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
462 }
463
464 // If we have a source for the channel, we need to update its gain.
465 if (mCurrentSourcep)
466 {
467 // SJB: warnings can spam and hurt framerate, disabling
468 if (!FSOUND_SetVolume(mChannelID, llround(getSecondaryGain() * mCurrentSourcep->getGain() * 255.0f)))
469 {
470// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
471 }
472
473 if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF))
474 {
475// llwarns << "Channel " << mChannelID << "Source ID: " << mCurrentSourcep->getID()
476// << " at " << mCurrentSourcep->getPositionGlobal() << llendl;
477// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
478 }
479 }
480
481 return true;
482}
483
484
485void LLAudioChannelFMOD::update3DPosition()
486{
487 if (!mChannelID)
488 {
489 // We're not actually a live channel (i.e., we're not playing back anything)
490 return;
491 }
492
493 LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentBufferp;
494 if (!bufferp)
495 {
496 // We don't have a buffer associated with us (should really have been picked up
497 // by the above if.
498 return;
499 }
500
501 if (mCurrentSourcep->isAmbient())
502 {
503 // Ambient sound, don't need to do any positional updates.
504 bufferp->set3DMode(false);
505 }
506 else
507 {
508 // Localized sound. Update the position and velocity of the sound.
509 bufferp->set3DMode(true);
510
511 LLVector3 float_pos;
512 float_pos.setVec(mCurrentSourcep->getPositionGlobal());
513 if (!FSOUND_3D_SetAttributes(mChannelID, float_pos.mV, mCurrentSourcep->getVelocity().mV))
514 {
515 LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::update3DPosition error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
516 }
517 }
518}
519
520
521void LLAudioChannelFMOD::updateLoop()
522{
523 if (!mChannelID)
524 {
525 // May want to clear up the loop/sample counters.
526 return;
527 }
528
529 //
530 // Hack: We keep track of whether we looped or not by seeing when the
531 // sample position looks like it's going backwards. Not reliable; may
532 // yield false negatives.
533 //
534 U32 cur_pos = FSOUND_GetCurrentPosition(mChannelID);
535 if (cur_pos < (U32)mLastSamplePos)
536 {
537 mLoopedThisFrame = true;
538 }
539 mLastSamplePos = cur_pos;
540}
541
542
543void LLAudioChannelFMOD::cleanup()
544{
545 if (!mChannelID)
546 {
547 //llinfos << "Aborting cleanup with no channelID." << llendl;
548 return;
549 }
550
551 //llinfos << "Cleaning up channel: " << mChannelID << llendl;
552 if (!FSOUND_StopSound(mChannelID))
553 {
554 LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
555 }
556
557 mCurrentBufferp = NULL;
558 mChannelID = 0;
559}
560
561
562void LLAudioChannelFMOD::play()
563{
564 if (!mChannelID)
565 {
566 llwarns << "Playing without a channelID, aborting" << llendl;
567 return;
568 }
569
570 if (!FSOUND_SetPaused(mChannelID, false))
571 {
572 llwarns << "LLAudioChannelFMOD::play error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
573 }
574 getSource()->setPlayedOnce(true);
575}
576
577
578void LLAudioChannelFMOD::playSynced(LLAudioChannel *channelp)
579{
580 LLAudioChannelFMOD *fmod_channelp = (LLAudioChannelFMOD*)channelp;
581 if (!(fmod_channelp->mChannelID && mChannelID))
582 {
583 // Don't have channels allocated to both the master and the slave
584 return;
585 }
586
587 U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength();
588 // Try to match the position of our sync master
589 if (!FSOUND_SetCurrentPosition(mChannelID, position))
590 {
591 llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl;
592 }
593
594 // Start us playing
595 play();
596}
597
598
599bool LLAudioChannelFMOD::isPlaying()
600{
601 if (!mChannelID)
602 {
603 return false;
604 }
605
606 return FSOUND_IsPlaying(mChannelID) && (!FSOUND_GetPaused(mChannelID));
607}
608
609
610
611//
612// LLAudioBufferFMOD implementation
613//
614
615
616LLAudioBufferFMOD::LLAudioBufferFMOD()
617{
618 mSamplep = NULL;
619}
620
621
622LLAudioBufferFMOD::~LLAudioBufferFMOD()
623{
624 if (mSamplep)
625 {
626 // Clean up the associated FMOD sample if it exists.
627 FSOUND_Sample_Free(mSamplep);
628 mSamplep = NULL;
629 }
630}
631
632
633bool LLAudioBufferFMOD::loadWAV(const std::string& filename)
634{
635 // Try to open a wav file from disk. This will eventually go away, as we don't
636 // really want to block doing this.
637 if (filename.empty())
638 {
639 // invalid filename, abort.
640 return false;
641 }
642
643 if (!LLAPRFile::isExist(filename, LL_APR_RPB))
644 {
645 // File not found, abort.
646 return false;
647 }
648
649 if (mSamplep)
650 {
651 // If there's already something loaded in this buffer, clean it up.
652 FSOUND_Sample_Free(mSamplep);
653 mSamplep = NULL;
654 }
655
656 // Load up the wav file into an fmod sample
657#if LL_WINDOWS
658 // MikeS. - Loading the sound file manually and then handing it over to FMOD,
659 // since FMOD uses posix IO internally,
660 // which doesn't work with unicode file paths.
661 LLFILE* sound_file = LLFile::fopen(filename,"rb"); /* Flawfinder: ignore */
662 if (sound_file)
663 {
664 fseek(sound_file,0,SEEK_END);
665 U32 file_length = ftell(sound_file); //Find the length of the file by seeking to the end and getting the offset
666 size_t read_count;
667 fseek(sound_file,0,SEEK_SET); //Seek back to the beginning
668 char* buffer = new char[file_length];
669 llassert(buffer);
670 read_count = fread((void*)buffer,file_length,1,sound_file);//Load it..
671 if(ferror(sound_file)==0 && (read_count == 1)){//No read error, and we got 1 chunk of our size...
672 unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY;
673 //FSOUND_16BITS | FSOUND_MONO | FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL;
674 mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, mode_flags , 0, file_length);
675 }
676 delete[] buffer;
677 fclose(sound_file);
678 }
679#else
680 mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, filename.c_str(), FSOUND_LOOP_NORMAL, 0, 0);
681#endif
682
683 if (!mSamplep)
684 {
685 // We failed to load the file for some reason.
686 llwarns << "Could not load data '" << filename << "': "
687 << FMOD_ErrorString(FSOUND_GetError()) << llendl;
688
689 //
690 // If we EVER want to load wav files provided by end users, we need
691 // to rethink this!
692 //
693 // file is probably corrupt - remove it.
694 LLFile::remove(filename);
695 return false;
696 }
697
698 // Everything went well, return true
699 return true;
700}
701
702
703U32 LLAudioBufferFMOD::getLength()
704{
705 if (!mSamplep)
706 {
707 return 0;
708 }
709
710 return FSOUND_Sample_GetLength(mSamplep);
711}
712
713
714void LLAudioBufferFMOD::set3DMode(bool use3d)
715{
716 U16 current_mode = FSOUND_Sample_GetMode(mSamplep);
717
718 if (use3d)
719 {
720 if (!FSOUND_Sample_SetMode(mSamplep, (current_mode & (~FSOUND_2D))))
721 {
722 llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
723 }
724 }
725 else
726 {
727 if (!FSOUND_Sample_SetMode(mSamplep, current_mode | FSOUND_2D))
728 {
729 llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
730 }
731 }
732}
733
734
735void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata)
736{
737 // originalbuffer = fmod's original mixbuffer.
738 // newbuffer = the buffer passed from the previous DSP unit.
739 // length = length in samples at this mix time.
740 // param = user parameter passed through in FSOUND_DSP_Create.
741 //
742 // modify the buffer in some fashion
743
744 LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *windgen =
745 (LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *)userdata;
746 U8 stride;
747
748#if LL_DARWIN
749 stride = sizeof(LLAudioEngine_FMOD::MIXBUFFERFORMAT);
750#else
751 int mixertype = FSOUND_GetMixer();
752 if (mixertype == FSOUND_MIXER_BLENDMODE ||
753 mixertype == FSOUND_MIXER_QUALITY_FPU)
754 {
755 stride = 4;
756 }
757 else
758 {
759 stride = 2;
760 }
761#endif
762
763 newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length, stride);
764
765 return newbuffer;
766}