PageRenderTime 61ms CodeModel.GetById 16ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llaudio/llaudioengine_fmod.cpp

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