diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llvieweraudio.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llvieweraudio.cpp')
-rw-r--r-- | indra/newview/llvieweraudio.cpp | 1185 |
1 files changed, 597 insertions, 588 deletions
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index 318cf199c0..9d17898b5e 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -1,588 +1,597 @@ -/** - * @file llvieweraudio.cpp - * @brief Audio functions that used to be in viewer.cpp - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llaudioengine.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llappviewer.h" -#include "lldeferredsounds.h" -#include "llvieweraudio.h" -#include "llviewercamera.h" -#include "llviewercontrol.h" -#include "llviewerwindow.h" -#include "llvoiceclient.h" -#include "llviewermedia.h" -#include "llviewerregion.h" -#include "llprogressview.h" -#include "llcallbacklist.h" -#include "llstartup.h" -#include "llviewerparcelmgr.h" -#include "llparcel.h" -#include "llviewermessage.h" - -#include "llstreamingaudio.h" - -///////////////////////////////////////////////////////// - -LLViewerAudio::LLViewerAudio() : - mDone(true), - mFadeState(FADE_IDLE), - mFadeTime(), - mIdleListnerActive(false), - mForcedTeleportFade(false), - mWasPlaying(false) -{ - mTeleportFailedConnection = LLViewerParcelMgr::getInstance()-> - setTeleportFailedCallback(boost::bind(&LLViewerAudio::onTeleportFailed, this)); - mTeleportFinishedConnection = LLViewerParcelMgr::getInstance()-> - setTeleportFinishedCallback(boost::bind(&LLViewerAudio::onTeleportFinished, this, _1, _2)); - mTeleportStartedConnection = LLViewerMessage::getInstance()-> - setTeleportStartedCallback(boost::bind(&LLViewerAudio::onTeleportStarted, this)); -} - -LLViewerAudio::~LLViewerAudio() -{ - mTeleportFailedConnection.disconnect(); - mTeleportFinishedConnection.disconnect(); - mTeleportStartedConnection.disconnect(); -} - -void LLViewerAudio::registerIdleListener() -{ - if (!mIdleListnerActive) - { - mIdleListnerActive = true; - doOnIdleRepeating(boost::bind(boost::bind(&LLViewerAudio::onIdleUpdate, this))); - } -} - -void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI) -{ - LL_DEBUGS("AudioEngine") << "Start with outo fade: " << streamURI << LL_ENDL; - - // Old and new stream are identical - if (mNextStreamURI == streamURI) - { - return; - } - - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return; - } - - // Record the URI we are going to be switching to - mNextStreamURI = streamURI; - - switch (mFadeState) - { - case FADE_IDLE: - // If a stream is playing fade it out first - if (!gAudiop->getInternetStreamURL().empty()) - { - // The order of these tests is important, state FADE_OUT will be processed below - mFadeState = FADE_OUT; - } - // Otherwise the new stream can be faded in - else - { - mFadeState = FADE_IN; - - LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); - if (stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"), gSavedSettings.getU32("FMODExDecodeBufferSize")); - - gAudiop->startInternetStream(mNextStreamURI); - } - - startFading(); - break; - - case FADE_OUT: - startFading(); - break; - - case FADE_IN: - break; - - default: - LL_WARNS() << "Unknown fading state: " << mFadeState << LL_ENDL; - return; - } - - registerIdleListener(); -} - -// A return of false from onIdleUpdate means it will be called again next idle update. -// A return of true means we have finished with it and the callback will be deleted. -bool LLViewerAudio::onIdleUpdate() -{ - bool fadeIsFinished = false; - - // There is a delay in the login sequence between when the parcel information has - // arrived and the music stream is started and when the audio system is called to set - // initial volume levels. This code extends the fade time so you hear a full fade in. - if ((LLStartUp::getStartupState() < STATE_STARTED)) - { - stream_fade_timer.reset(); - stream_fade_timer.setTimerExpirySec(mFadeTime); - } - - if (mDone) - { - // This should be a rare or never occurring state. - if (mFadeState == FADE_IDLE) - { - deregisterIdleListener(); - fadeIsFinished = true; // Stop calling onIdleUpdate - } - - // we have finished the current fade operation - if (mFadeState == FADE_OUT) - { - if (gAudiop) - { - // Clear URI - LL_DEBUGS("AudioEngine") << "Done with audio fade" << LL_ENDL; - gAudiop->startInternetStream(LLStringUtil::null); - gAudiop->stopInternetStream(); - } - - if (!mNextStreamURI.empty()) - { - mFadeState = FADE_IN; - - if (gAudiop) - { - LL_DEBUGS("AudioEngine") << "Audio fade in: " << mNextStreamURI << LL_ENDL; - LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); - if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); - - gAudiop->startInternetStream(mNextStreamURI); - } - - startFading(); - } - else - { - mFadeState = FADE_IDLE; - deregisterIdleListener(); - fadeIsFinished = true; // Stop calling onIdleUpdate - } - } - else if (mFadeState == FADE_IN) - { - if (gAudiop && mNextStreamURI != gAudiop->getInternetStreamURL()) - { - mFadeState = FADE_OUT; - startFading(); - } - else - { - mFadeState = FADE_IDLE; - deregisterIdleListener(); - fadeIsFinished = true; // Stop calling onIdleUpdate - } - } - } - - return fadeIsFinished; -} - -void LLViewerAudio::stopInternetStreamWithAutoFade() -{ - mFadeState = FADE_IDLE; - mNextStreamURI = LLStringUtil::null; - mDone = true; - - if (gAudiop) - { - LL_DEBUGS("AudioEngine") << "Stop audio fade" << LL_ENDL; - gAudiop->startInternetStream(LLStringUtil::null); - gAudiop->stopInternetStream(); - } -} - -void LLViewerAudio::startFading() -{ - const F32 AUDIO_MUSIC_FADE_IN_TIME = 3.0f; - const F32 AUDIO_MUSIC_FADE_OUT_TIME = 2.0f; - // This minimum fade time prevents divide by zero and negative times - const F32 AUDIO_MUSIC_MINIMUM_FADE_TIME = 0.01f; - - if (mDone) - { - // The fade state here should only be one of FADE_IN or FADE_OUT, but, in case it is not, - // rather than check for both states assume a fade in and check for the fade out case. - mFadeTime = LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT ? - AUDIO_MUSIC_FADE_OUT_TIME : AUDIO_MUSIC_FADE_IN_TIME; - - // Prevent invalid fade time - mFadeTime = llmax(mFadeTime, AUDIO_MUSIC_MINIMUM_FADE_TIME); - - stream_fade_timer.reset(); - stream_fade_timer.setTimerExpirySec(mFadeTime); - mDone = false; - } -} - -F32 LLViewerAudio::getFadeVolume() -{ - F32 fade_volume = 1.0f; - - if (stream_fade_timer.hasExpired()) - { - mDone = true; - // If we have been fading out set volume to 0 until the next fade state occurs to prevent - // an audio transient. - if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT) - { - fade_volume = 0.0f; - } - } - - if (!mDone) - { - // Calculate how far we are into the fade time - fade_volume = stream_fade_timer.getElapsedTimeF32() / mFadeTime; - - if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT) - { - // If we are not fading in then we are fading out, so invert the fade - // direction; start loud and move towards zero volume. - fade_volume = 1.0f - fade_volume; - } - } - - return fade_volume; -} - -void LLViewerAudio::onTeleportStarted() -{ - if (gAudiop && !LLViewerAudio::getInstance()->getForcedTeleportFade()) - { - // Even though the music was turned off it was starting up (with autoplay disabled) occasionally - // after a failed teleport or after an intra-parcel teleport. Also, the music sometimes was not - // restarting after a successful intra-parcel teleport. Setting mWasPlaying fixes these issues. - LLViewerAudio::getInstance()->setWasPlaying(!gAudiop->getInternetStreamURL().empty()); - LLViewerAudio::getInstance()->setForcedTeleportFade(true); - LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); - LLViewerAudio::getInstance()->setNextStreamURI(LLStringUtil::null); - } -} - -void LLViewerAudio::onTeleportFailed() -{ - // Calling audio_update_volume makes sure that the music stream is properly set to be restored to - // its previous value - audio_update_volume(false); - - if (gAudiop && mWasPlaying) - { - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (parcel) - { - mNextStreamURI = parcel->getMusicURL(); - LL_INFOS() << "Teleport failed -- setting music stream to " << mNextStreamURI << LL_ENDL; - } - } - mWasPlaying = false; -} - -void LLViewerAudio::onTeleportFinished(const LLVector3d& pos, const bool& local) -{ - // Calling audio_update_volume makes sure that the music stream is properly set to be restored to - // its previous value - audio_update_volume(false); - - if (gAudiop && local && mWasPlaying) - { - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (parcel) - { - mNextStreamURI = parcel->getMusicURL(); - LL_INFOS() << "Intraparcel teleport -- setting music stream to " << mNextStreamURI << LL_ENDL; - } - } - mWasPlaying = false; -} - -void init_audio() -{ - if (!gAudiop) - { - LL_WARNS() << "Failed to create an appropriate Audio Engine" << LL_ENDL; - return; - } - LLVector3d lpos_global = gAgentCamera.getCameraPositionGlobal(); - LLVector3 lpos_global_f; - - lpos_global_f.setVec(lpos_global); - - gAudiop->setListener(lpos_global_f, - LLVector3::zero, // LLViewerCamera::getInstance()->getVelocity(), // !!! BUG need to replace this with smoothed velocity! - LLViewerCamera::getInstance()->getUpAxis(), - LLViewerCamera::getInstance()->getAtAxis()); - -// load up our initial set of sounds we'll want so they're in memory and ready to be played - - bool mute_audio = gSavedSettings.getBOOL("MuteAudio"); - - if (!mute_audio && false == gSavedSettings.getBOOL("NoPreload")) - { - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndAlert"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndBadKeystroke"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndChatFromObject"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClick"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClickRelease"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionF"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionM"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingChat"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingIM"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvApplyToObject"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvalidOp"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInventoryCopyToInv"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeDown"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeUp"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCopyToInv"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCreate"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectDelete"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezIn"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezOut"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndSnapshot"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartAutopilot"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartFollowpilot"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartIM"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStopAutopilot"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTeleportOut"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureApplyToObject"))); - //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureCopyToInv"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTyping"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen"))); - gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndRestart"))); - } - - audio_update_volume(true); -} - -void audio_update_volume(bool force_update) -{ - F32 master_volume = gSavedSettings.getF32("AudioLevelMaster"); - bool mute_audio = gSavedSettings.getBOOL("MuteAudio"); - - LLProgressView* progress = gViewerWindow->getProgressView(); - bool progress_view_visible = false; - - if (progress) - { - progress_view_visible = progress->getVisible(); - } - - if (!gViewerWindow->getActive() && gSavedSettings.getBOOL("MuteWhenMinimized")) - { - mute_audio = true; - } - F32 mute_volume = mute_audio ? 0.0f : 1.0f; - - if (gAudiop) - { - // Sound Effects - - gAudiop->setMasterGain ( master_volume ); - - gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler")); - - if(!LLViewerCamera::getInstance()->cameraUnderWater()) - gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff")); - else - gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelUnderwaterRolloff")); - - gAudiop->setMuted(mute_audio || progress_view_visible); - - //Play any deferred sounds when unmuted - if(!gAudiop->getMuted()) - { - LLDeferredSounds::instance().playdeferredSounds(); - } - - if (force_update) - { - audio_update_wind(true); - } - - // handle secondary gains - gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX, - gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX")); - gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_UI, - gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI")); - gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT, - gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient")); - - // Streaming Music - - if (!progress_view_visible && LLViewerAudio::getInstance()->getForcedTeleportFade()) - { - LLViewerAudio::getInstance()->setWasPlaying(!gAudiop->getInternetStreamURL().empty()); - LLViewerAudio::getInstance()->setForcedTeleportFade(false); - } - - F32 music_volume = gSavedSettings.getF32("AudioLevelMusic"); - bool music_muted = gSavedSettings.getBOOL("MuteMusic"); - F32 fade_volume = LLViewerAudio::getInstance()->getFadeVolume(); - - music_volume = mute_volume * master_volume * music_volume * fade_volume; - gAudiop->setInternetStreamGain (music_muted ? 0.f : music_volume); - } - - // Streaming Media - F32 media_volume = gSavedSettings.getF32("AudioLevelMedia"); - bool media_muted = gSavedSettings.getBOOL("MuteMedia"); - media_volume = mute_volume * master_volume * media_volume; - LLViewerMedia::getInstance()->setVolume( media_muted ? 0.0f : media_volume ); - - // Voice, this is parametric singleton, it gets initialized when ready - if (LLVoiceClient::instanceExists()) - { - F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice"); - voice_volume = mute_volume * master_volume * voice_volume; - bool voice_mute = gSavedSettings.getBOOL("MuteVoice"); - LLVoiceClient *voice_inst = LLVoiceClient::getInstance(); - voice_inst->setVoiceVolume(voice_mute ? 0.f : voice_volume); - voice_inst->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic")); - - if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized"))) - { - voice_inst->setMuteMic(true); - } - else - { - voice_inst->setMuteMic(false); - } - } -} - -void audio_update_listener() -{ - if (gAudiop) - { - // update listener position because agent has moved - static LLUICachedControl<S32> mEarLocation("MediaSoundsEarLocation", 0); - LLVector3d ear_position; - switch(mEarLocation) - { - case 0: - default: - ear_position = gAgentCamera.getCameraPositionGlobal(); - break; - - case 1: - ear_position = gAgent.getPositionGlobal(); - break; - } - LLVector3d lpos_global = ear_position; - LLVector3 lpos_global_f; - lpos_global_f.setVec(lpos_global); - - gAudiop->setListener(lpos_global_f, - // LLViewerCamera::getInstance()VelocitySmoothed, - // LLVector3::zero, - gAgent.getVelocity(), // !!! *TODO: need to replace this with smoothed velocity! - LLViewerCamera::getInstance()->getUpAxis(), - LLViewerCamera::getInstance()->getAtAxis()); - } -} - -void audio_update_wind(bool force_update) -{ -#ifdef kAUDIO_ENABLE_WIND - - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - // Scale down the contribution of weather-simulation wind to the - // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s - // whereas steady-state avatar walk velocity is only 3.2 m/s. - // Without this the world feels desolate on first login when you are - // standing still. - static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f); - LLVector3 scaled_wind_vec = gWindVec * wind_level; - - // Mix in the avatar's motion, subtract because when you walk north, - // the apparent wind moves south. - LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity(); - - // rotate the wind vector to be listener (agent) relative - gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal( final_wind_vec ); - - // don't use the setter setMaxWindGain() because we don't - // want to screw up the fade-in on startup by setting actual source gain - // outside the fade-in. - static LLCachedControl<bool> mute_audio(gSavedSettings, "MuteAudio"); - static LLCachedControl<bool> mute_ambient(gSavedSettings, "MuteAmbient"); - static LLCachedControl<F32> level_master(gSavedSettings, "AudioLevelMaster"); - static LLCachedControl<F32> level_ambient(gSavedSettings, "AudioLevelAmbient"); - - F32 master_volume = mute_audio() ? 0.f : level_master(); - F32 ambient_volume = mute_ambient() ? 0.f : level_ambient(); - F32 max_wind_volume = master_volume * ambient_volume; - - const F32 WIND_SOUND_TRANSITION_TIME = 2.f; - // amount to change volume this frame - F32 volume_delta = (LLFrameTimer::getFrameDeltaTimeF32() / WIND_SOUND_TRANSITION_TIME) * max_wind_volume; - if (force_update) - { - // initialize wind volume (force_update) by using large volume_delta - // which is sufficient to completely turn off or turn on wind noise - volume_delta = 1.f; - } - - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - return; - } - - // mute wind when not flying - if (gAgent.getFlying()) - { - // volume increases by volume_delta, up to no more than max_wind_volume - gAudiop->mMaxWindGain = llmin(gAudiop->mMaxWindGain + volume_delta, max_wind_volume); - } - else - { - // volume decreases by volume_delta, down to no less than 0 - gAudiop->mMaxWindGain = llmax(gAudiop->mMaxWindGain - volume_delta, 0.f); - } - - gAudiop->updateWind(gRelativeWindVec, gAgentCamera.getCameraPositionAgent()[VZ] - gAgent.getRegion()->getWaterHeight()); - } -#endif -} +/**
+ * @file llvieweraudio.cpp
+ * @brief Audio functions that used to be in viewer.cpp
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llaudioengine.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llappviewer.h"
+#include "lldeferredsounds.h"
+#include "llvieweraudio.h"
+#include "llviewercamera.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "llvoiceclient.h"
+#include "llviewermedia.h"
+#include "llviewerregion.h"
+#include "llprogressview.h"
+#include "llcallbacklist.h"
+#include "llstartup.h"
+#include "llviewerparcelmgr.h"
+#include "llparcel.h"
+#include "llviewermessage.h"
+
+#include "llstreamingaudio.h"
+
+/////////////////////////////////////////////////////////
+const U32 FMODEX_DECODE_BUFFER_SIZE = 1000; // in milliseconds
+const U32 FMODEX_STREAM_BUFFER_SIZE = 7000; // in milliseconds
+
+LLViewerAudio::LLViewerAudio() :
+ mDone(true),
+ mFadeState(FADE_IDLE),
+ mFadeTime(),
+ mIdleListnerActive(false),
+ mForcedTeleportFade(false),
+ mWasPlaying(false)
+{
+ mTeleportFailedConnection = LLViewerParcelMgr::getInstance()->
+ setTeleportFailedCallback(boost::bind(&LLViewerAudio::onTeleportFailed, this));
+ mTeleportFinishedConnection = LLViewerParcelMgr::getInstance()->
+ setTeleportFinishedCallback(boost::bind(&LLViewerAudio::onTeleportFinished, this, _1, _2));
+ mTeleportStartedConnection = LLViewerMessage::getInstance()->
+ setTeleportStartedCallback(boost::bind(&LLViewerAudio::onTeleportStarted, this));
+}
+
+LLViewerAudio::~LLViewerAudio()
+{
+ mTeleportFailedConnection.disconnect();
+ mTeleportFinishedConnection.disconnect();
+ mTeleportStartedConnection.disconnect();
+}
+
+void LLViewerAudio::registerIdleListener()
+{
+ if (!mIdleListnerActive)
+ {
+ mIdleListnerActive = true;
+ doOnIdleRepeating(boost::bind(boost::bind(&LLViewerAudio::onIdleUpdate, this)));
+ }
+}
+
+void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI)
+{
+ LL_DEBUGS("AudioEngine") << "Start with outo fade: " << streamURI << LL_ENDL;
+
+ // Old and new stream are identical
+ if (mNextStreamURI == streamURI)
+ {
+ return;
+ }
+
+ if (!gAudiop)
+ {
+ LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL;
+ return;
+ }
+
+ // Record the URI we are going to be switching to
+ mNextStreamURI = streamURI;
+
+ switch (mFadeState)
+ {
+ case FADE_IDLE:
+ // If a stream is playing fade it out first
+ if (!gAudiop->getInternetStreamURL().empty())
+ {
+ // The order of these tests is important, state FADE_OUT will be processed below
+ mFadeState = FADE_OUT;
+ }
+ // Otherwise the new stream can be faded in
+ else
+ {
+ mFadeState = FADE_IN;
+
+ LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl();
+ if (stream && stream->supportsAdjustableBufferSizes())
+ stream->setBufferSizes(FMODEX_STREAM_BUFFER_SIZE, FMODEX_DECODE_BUFFER_SIZE);
+
+ gAudiop->startInternetStream(mNextStreamURI);
+ }
+
+ startFading();
+ break;
+
+ case FADE_OUT:
+ startFading();
+ break;
+
+ case FADE_IN:
+ break;
+
+ default:
+ LL_WARNS() << "Unknown fading state: " << mFadeState << LL_ENDL;
+ return;
+ }
+
+ registerIdleListener();
+}
+
+// A return of false from onIdleUpdate means it will be called again next idle update.
+// A return of true means we have finished with it and the callback will be deleted.
+bool LLViewerAudio::onIdleUpdate()
+{
+ bool fadeIsFinished = false;
+
+ // There is a delay in the login sequence between when the parcel information has
+ // arrived and the music stream is started and when the audio system is called to set
+ // initial volume levels. This code extends the fade time so you hear a full fade in.
+ if ((LLStartUp::getStartupState() < STATE_STARTED))
+ {
+ stream_fade_timer.reset();
+ stream_fade_timer.setTimerExpirySec(mFadeTime);
+ }
+
+ if (mDone)
+ {
+ // This should be a rare or never occurring state.
+ if (mFadeState == FADE_IDLE)
+ {
+ deregisterIdleListener();
+ fadeIsFinished = true; // Stop calling onIdleUpdate
+ }
+
+ // we have finished the current fade operation
+ if (mFadeState == FADE_OUT)
+ {
+ if (gAudiop)
+ {
+ // Clear URI
+ LL_DEBUGS("AudioEngine") << "Done with audio fade" << LL_ENDL;
+ gAudiop->startInternetStream(LLStringUtil::null);
+ gAudiop->stopInternetStream();
+ }
+
+ if (!mNextStreamURI.empty())
+ {
+ mFadeState = FADE_IN;
+
+ if (gAudiop)
+ {
+ LL_DEBUGS("AudioEngine") << "Audio fade in: " << mNextStreamURI << LL_ENDL;
+ LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl();
+ if(stream && stream->supportsAdjustableBufferSizes())
+ stream->setBufferSizes(FMODEX_STREAM_BUFFER_SIZE, FMODEX_DECODE_BUFFER_SIZE);
+
+ gAudiop->startInternetStream(mNextStreamURI);
+ }
+
+ startFading();
+ }
+ else
+ {
+ mFadeState = FADE_IDLE;
+ deregisterIdleListener();
+ fadeIsFinished = true; // Stop calling onIdleUpdate
+ }
+ }
+ else if (mFadeState == FADE_IN)
+ {
+ if (gAudiop && mNextStreamURI != gAudiop->getInternetStreamURL())
+ {
+ mFadeState = FADE_OUT;
+ startFading();
+ }
+ else
+ {
+ mFadeState = FADE_IDLE;
+ deregisterIdleListener();
+ fadeIsFinished = true; // Stop calling onIdleUpdate
+ }
+ }
+ }
+
+ return fadeIsFinished;
+}
+
+void LLViewerAudio::stopInternetStreamWithAutoFade()
+{
+ mFadeState = FADE_IDLE;
+ mNextStreamURI = LLStringUtil::null;
+ mDone = true;
+
+ if (gAudiop)
+ {
+ LL_DEBUGS("AudioEngine") << "Stop audio fade" << LL_ENDL;
+ gAudiop->startInternetStream(LLStringUtil::null);
+ gAudiop->stopInternetStream();
+ }
+}
+
+void LLViewerAudio::startFading()
+{
+ const F32 AUDIO_MUSIC_FADE_IN_TIME = 3.0f;
+ const F32 AUDIO_MUSIC_FADE_OUT_TIME = 2.0f;
+ // This minimum fade time prevents divide by zero and negative times
+ const F32 AUDIO_MUSIC_MINIMUM_FADE_TIME = 0.01f;
+
+ if (mDone)
+ {
+ // The fade state here should only be one of FADE_IN or FADE_OUT, but, in case it is not,
+ // rather than check for both states assume a fade in and check for the fade out case.
+ mFadeTime = LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT ?
+ AUDIO_MUSIC_FADE_OUT_TIME : AUDIO_MUSIC_FADE_IN_TIME;
+
+ // Prevent invalid fade time
+ mFadeTime = llmax(mFadeTime, AUDIO_MUSIC_MINIMUM_FADE_TIME);
+
+ stream_fade_timer.reset();
+ stream_fade_timer.setTimerExpirySec(mFadeTime);
+ mDone = false;
+ }
+}
+
+F32 LLViewerAudio::getFadeVolume()
+{
+ F32 fade_volume = 1.0f;
+
+ if (stream_fade_timer.hasExpired())
+ {
+ mDone = true;
+ // If we have been fading out set volume to 0 until the next fade state occurs to prevent
+ // an audio transient.
+ if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
+ {
+ fade_volume = 0.0f;
+ }
+ }
+
+ if (!mDone)
+ {
+ // Calculate how far we are into the fade time
+ fade_volume = stream_fade_timer.getElapsedTimeF32() / mFadeTime;
+
+ if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
+ {
+ // If we are not fading in then we are fading out, so invert the fade
+ // direction; start loud and move towards zero volume.
+ fade_volume = 1.0f - fade_volume;
+ }
+ }
+
+ return fade_volume;
+}
+
+void LLViewerAudio::onTeleportStarted()
+{
+ if (gAudiop && !LLViewerAudio::getInstance()->getForcedTeleportFade())
+ {
+ // Even though the music was turned off it was starting up (with autoplay disabled) occasionally
+ // after a failed teleport or after an intra-parcel teleport. Also, the music sometimes was not
+ // restarting after a successful intra-parcel teleport. Setting mWasPlaying fixes these issues.
+ LLViewerAudio::getInstance()->setWasPlaying(!gAudiop->getInternetStreamURL().empty());
+ LLViewerAudio::getInstance()->setForcedTeleportFade(true);
+ LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
+ LLViewerAudio::getInstance()->setNextStreamURI(LLStringUtil::null);
+ }
+}
+
+void LLViewerAudio::onTeleportFailed()
+{
+ // Calling audio_update_volume makes sure that the music stream is properly set to be restored to
+ // its previous value
+ audio_update_volume(false);
+
+ if (gAudiop && mWasPlaying)
+ {
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (parcel)
+ {
+ mNextStreamURI = parcel->getMusicURL();
+ LL_INFOS() << "Teleport failed -- setting music stream to " << mNextStreamURI << LL_ENDL;
+ }
+ }
+ mWasPlaying = false;
+}
+
+void LLViewerAudio::onTeleportFinished(const LLVector3d& pos, const bool& local)
+{
+ // Calling audio_update_volume makes sure that the music stream is properly set to be restored to
+ // its previous value
+ audio_update_volume(false);
+
+ if (gAudiop && local && mWasPlaying)
+ {
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (parcel)
+ {
+ mNextStreamURI = parcel->getMusicURL();
+ LL_INFOS() << "Intraparcel teleport -- setting music stream to " << mNextStreamURI << LL_ENDL;
+ }
+ }
+ mWasPlaying = false;
+}
+
+void init_audio()
+{
+ if (!gAudiop)
+ {
+ LL_WARNS() << "Failed to create an appropriate Audio Engine" << LL_ENDL;
+ return;
+ }
+ LLVector3d lpos_global = gAgentCamera.getCameraPositionGlobal();
+ LLVector3 lpos_global_f;
+
+ lpos_global_f.setVec(lpos_global);
+
+ gAudiop->setListener(lpos_global_f,
+ LLVector3::zero, // LLViewerCamera::getInstance()->getVelocity(), // !!! BUG need to replace this with smoothed velocity!
+ LLViewerCamera::getInstance()->getUpAxis(),
+ LLViewerCamera::getInstance()->getAtAxis());
+
+// load up our initial set of sounds we'll want so they're in memory and ready to be played
+
+ bool mute_audio = gSavedSettings.getBOOL("MuteAudio");
+
+ if (!mute_audio && false == gSavedSettings.getBOOL("NoPreload"))
+ {
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndAlert")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndBadKeystroke")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndChatFromObject")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClick")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClickRelease")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionF")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionM")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingChat")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingIM")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvApplyToObject")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvalidOp")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInventoryCopyToInv")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeDown")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeUp")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCopyToInv")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCreate")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectDelete")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezIn")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezOut")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndSnapshot")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartAutopilot")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartFollowpilot")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartIM")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStopAutopilot")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTeleportOut")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureApplyToObject")));
+ //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureCopyToInv")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTyping")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen")));
+ gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndRestart")));
+ }
+
+ audio_update_volume(true);
+}
+
+void audio_update_volume(bool force_update)
+{
+ F32 master_volume = gSavedSettings.getF32("AudioLevelMaster");
+ bool mute_audio = gSavedSettings.getBOOL("MuteAudio");
+
+ LLProgressView* progress = gViewerWindow->getProgressView();
+ bool progress_view_visible = false;
+
+ if (progress)
+ {
+ progress_view_visible = progress->getVisible();
+ }
+
+ if (!gViewerWindow->getActive() && gSavedSettings.getBOOL("MuteWhenMinimized"))
+ {
+ mute_audio = true;
+ }
+ F32 mute_volume = mute_audio ? 0.0f : 1.0f;
+
+ if (gAudiop)
+ {
+ // Sound Effects
+
+ gAudiop->setMasterGain ( master_volume );
+
+ const F32 AUDIO_LEVEL_DOPPLER = 1.f;
+ gAudiop->setDopplerFactor(AUDIO_LEVEL_DOPPLER);
+
+ if(!LLViewerCamera::getInstance()->cameraUnderWater())
+ {
+ const F32 AUDIO_LEVEL_ROLLOFF = 1.f;
+ gAudiop->setRolloffFactor(AUDIO_LEVEL_ROLLOFF);
+ }
+ else
+ {
+ const F32 AUDIO_LEVEL_UNDERWATER_ROLLOFF = 5.f;
+ gAudiop->setRolloffFactor(AUDIO_LEVEL_UNDERWATER_ROLLOFF);
+ }
+
+ gAudiop->setMuted(mute_audio || progress_view_visible);
+
+ //Play any deferred sounds when unmuted
+ if(!gAudiop->getMuted())
+ {
+ LLDeferredSounds::instance().playdeferredSounds();
+ }
+
+ if (force_update)
+ {
+ audio_update_wind(true);
+ }
+
+ // handle secondary gains
+ gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX,
+ gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX"));
+ gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_UI,
+ gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI"));
+ gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT,
+ gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient"));
+
+ // Streaming Music
+
+ if (!progress_view_visible && LLViewerAudio::getInstance()->getForcedTeleportFade())
+ {
+ LLViewerAudio::getInstance()->setWasPlaying(!gAudiop->getInternetStreamURL().empty());
+ LLViewerAudio::getInstance()->setForcedTeleportFade(false);
+ }
+
+ F32 music_volume = gSavedSettings.getF32("AudioLevelMusic");
+ bool music_muted = gSavedSettings.getBOOL("MuteMusic");
+ F32 fade_volume = LLViewerAudio::getInstance()->getFadeVolume();
+
+ music_volume = mute_volume * master_volume * music_volume * fade_volume;
+ gAudiop->setInternetStreamGain (music_muted ? 0.f : music_volume);
+ }
+
+ // Streaming Media
+ F32 media_volume = gSavedSettings.getF32("AudioLevelMedia");
+ bool media_muted = gSavedSettings.getBOOL("MuteMedia");
+ media_volume = mute_volume * master_volume * media_volume;
+ LLViewerMedia::getInstance()->setVolume( media_muted ? 0.0f : media_volume );
+
+ // Voice, this is parametric singleton, it gets initialized when ready
+ if (LLVoiceClient::instanceExists())
+ {
+ F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice");
+ voice_volume = mute_volume * master_volume * voice_volume;
+ bool voice_mute = gSavedSettings.getBOOL("MuteVoice");
+ LLVoiceClient *voice_inst = LLVoiceClient::getInstance();
+ voice_inst->setVoiceVolume(voice_mute ? 0.f : voice_volume);
+ voice_inst->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic"));
+
+ if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))
+ {
+ voice_inst->setMuteMic(true);
+ }
+ else
+ {
+ voice_inst->setMuteMic(false);
+ }
+ }
+}
+
+void audio_update_listener()
+{
+ if (gAudiop)
+ {
+ // update listener position because agent has moved
+ static LLUICachedControl<S32> mEarLocation("MediaSoundsEarLocation", 0);
+ LLVector3d ear_position;
+ switch(mEarLocation)
+ {
+ case 0:
+ default:
+ ear_position = gAgentCamera.getCameraPositionGlobal();
+ break;
+
+ case 1:
+ ear_position = gAgent.getPositionGlobal();
+ break;
+ }
+ LLVector3d lpos_global = ear_position;
+ LLVector3 lpos_global_f;
+ lpos_global_f.setVec(lpos_global);
+
+ gAudiop->setListener(lpos_global_f,
+ // LLViewerCamera::getInstance()VelocitySmoothed,
+ // LLVector3::zero,
+ gAgent.getVelocity(), // !!! *TODO: need to replace this with smoothed velocity!
+ LLViewerCamera::getInstance()->getUpAxis(),
+ LLViewerCamera::getInstance()->getAtAxis());
+ }
+}
+
+void audio_update_wind(bool force_update)
+{
+#ifdef kAUDIO_ENABLE_WIND
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ // Scale down the contribution of weather-simulation wind to the
+ // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s
+ // whereas steady-state avatar walk velocity is only 3.2 m/s.
+ // Without this the world feels desolate on first login when you are
+ // standing still.
+ const F32 WIND_LEVEL = 0.5f;
+ LLVector3 scaled_wind_vec = gWindVec * WIND_LEVEL;
+
+ // Mix in the avatar's motion, subtract because when you walk north,
+ // the apparent wind moves south.
+ LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity();
+
+ // rotate the wind vector to be listener (agent) relative
+ gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal( final_wind_vec );
+
+ // don't use the setter setMaxWindGain() because we don't
+ // want to screw up the fade-in on startup by setting actual source gain
+ // outside the fade-in.
+ static LLCachedControl<bool> mute_audio(gSavedSettings, "MuteAudio");
+ static LLCachedControl<bool> mute_ambient(gSavedSettings, "MuteAmbient");
+ static LLCachedControl<F32> level_master(gSavedSettings, "AudioLevelMaster");
+ static LLCachedControl<F32> level_ambient(gSavedSettings, "AudioLevelAmbient");
+
+ F32 master_volume = mute_audio() ? 0.f : level_master();
+ F32 ambient_volume = mute_ambient() ? 0.f : level_ambient();
+ F32 max_wind_volume = master_volume * ambient_volume;
+
+ const F32 WIND_SOUND_TRANSITION_TIME = 2.f;
+ // amount to change volume this frame
+ F32 volume_delta = (LLFrameTimer::getFrameDeltaTimeF32() / WIND_SOUND_TRANSITION_TIME) * max_wind_volume;
+ if (force_update)
+ {
+ // initialize wind volume (force_update) by using large volume_delta
+ // which is sufficient to completely turn off or turn on wind noise
+ volume_delta = 1.f;
+ }
+
+ if (!gAudiop)
+ {
+ LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL;
+ return;
+ }
+
+ // mute wind when not flying
+ if (gAgent.getFlying())
+ {
+ // volume increases by volume_delta, up to no more than max_wind_volume
+ gAudiop->mMaxWindGain = llmin(gAudiop->mMaxWindGain + volume_delta, max_wind_volume);
+ }
+ else
+ {
+ // volume decreases by volume_delta, down to no less than 0
+ gAudiop->mMaxWindGain = llmax(gAudiop->mMaxWindGain - volume_delta, 0.f);
+ }
+
+ gAudiop->updateWind(gRelativeWindVec, gAgentCamera.getCameraPositionAgent()[VZ] - gAgent.getRegion()->getWaterHeight());
+ }
+#endif
+}
|