summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/CMakeLists.txt2
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake15
-rw-r--r--indra/cmake/FMOD.cmake2
-rw-r--r--indra/cmake/FMODEX.cmake45
-rw-r--r--indra/cmake/FindFMODEX.cmake66
-rw-r--r--indra/llaudio/CMakeLists.txt26
-rw-r--r--indra/llaudio/llaudioengine.h1
-rw-r--r--indra/llaudio/llaudioengine_fmodex.cpp746
-rw-r--r--indra/llaudio/llaudioengine_fmodex.h129
-rw-r--r--indra/llaudio/lllistener_fmodex.cpp135
-rw-r--r--indra/llaudio/lllistener_fmodex.h65
-rw-r--r--indra/llaudio/llstreamingaudio.h2
-rw-r--r--indra/llaudio/llstreamingaudio_fmodex.cpp382
-rw-r--r--indra/llaudio/llstreamingaudio_fmodex.h75
-rw-r--r--indra/llaudio/llwindgen.h34
-rw-r--r--indra/newview/CMakeLists.txt57
-rw-r--r--indra/newview/app_settings/settings.xml44
-rwxr-xr-xindra/newview/linux_tools/wrapper.sh12
-rw-r--r--indra/newview/llstartup.cpp15
-rw-r--r--indra/newview/llvieweraudio.cpp70
-rw-r--r--indra/newview/llviewercontrol.cpp1
-rw-r--r--indra/newview/viewer_manifest.py18
22 files changed, 1863 insertions, 79 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 569034a6fb..e9c0554641 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -26,6 +26,7 @@ set(cmake_SOURCE_FILES
FindCARes.cmake
FindELFIO.cmake
FindFMOD.cmake
+ FindFMODEX.cmake
FindGooglePerfTools.cmake
FindMono.cmake
FindMySQL.cmake
@@ -33,6 +34,7 @@ set(cmake_SOURCE_FILES
FindXmlRpcEpi.cmake
FindZLIB.cmake
FMOD.cmake
+ FMODEX.cmake
FreeType.cmake
GLOD.cmake
GStreamer010Plugin.cmake
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index c32e357da3..c28361398f 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -62,6 +62,11 @@ if(WINDOWS)
set(release_files ${release_files} libtcmalloc_minimal.dll)
endif(USE_TCMALLOC)
+ if (FMODEX)
+ set(debug_files ${debug_files} fmodexL.dll)
+ set(release_files ${release_files} fmodex.dll)
+ endif (FMODEX)
+
if (FMOD)
set(debug_files ${debug_files} fmod.dll)
set(release_files ${release_files} fmod.dll)
@@ -222,9 +227,15 @@ elseif(DARWIN)
libcollada14dom.dylib
)
- # fmod is statically linked on darwin
- set(fmod_files "")
+ if (FMODEX)
+ #set(debug_files ${debug_files} libfmodexL.dylib)
+ set(release_files ${release_files} libfmodex.dylib)
+ endif (FMODEX)
+ if (FMOD)
+ # fmod is statically linked on darwin
+ set(fmod_files "")
+ endif (FMOD)
elseif(LINUX)
# linux is weird, multiple side by side configurations aren't supported
# and we don't seem to have any debug shared libs built yet anyways...
diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake
index 3586c1160a..ef0ae58bdf 100644
--- a/indra/cmake/FMOD.cmake
+++ b/indra/cmake/FMOD.cmake
@@ -6,7 +6,7 @@
# Open source devs should use the -DFMOD:BOOL=ON then if they want to build with FMOD, whether
# they are using STANDALONE or not.
if (INSTALL_PROPRIETARY)
- set(FMOD ON CACHE BOOL "Use FMOD sound library.")
+ set(FMOD OFF CACHE BOOL "Use FMOD sound library.")
endif (INSTALL_PROPRIETARY)
if (FMOD)
diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake
new file mode 100644
index 0000000000..448392437a
--- /dev/null
+++ b/indra/cmake/FMODEX.cmake
@@ -0,0 +1,45 @@
+# -*- cmake -*-
+
+# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON
+# When building using proprietary binaries though (i.e. having access to LL private servers),
+# we always build with FMODEX.
+# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMOD, whether
+# they are using STANDALONE or not.
+if (INSTALL_PROPRIETARY)
+ set(FMODEX ON CACHE BOOL "Using FMOD Ex sound library.")
+endif (INSTALL_PROPRIETARY)
+
+if (FMODEX)
+ if (STANDALONE)
+ # In that case, we use the version of the library installed on the system
+ set(FMODEX_FIND_REQUIRED ON)
+ include(FindFMODEX)
+ else (STANDALONE)
+ if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
+ # If the path have been specified in the arguments, use that
+ set(FMODEX_LIBRARIES ${FMODEX_LIBRARY})
+ MESSAGE(STATUS "Using FMODEX path: ${FMODEX_LIBRARIES}, ${FMODEX_INCLUDE_DIR}")
+ else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
+ # If not, we're going to try to get the package listed in autobuild.xml
+ # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL)
+ # as accessing the private LL location will fail if you don't have the credential
+ include(Prebuilt)
+ use_prebuilt_binary(fmodex)
+ if (WINDOWS)
+ set(FMODEX_LIBRARY
+ debug fmodexL_vc
+ optimized fmodex_vc)
+ elseif (DARWIN)
+ set(FMODEX_LIBRARY
+ debug fmodexL
+ optimized fmodex)
+ elseif (LINUX)
+ set(FMODEX_LIBRARY
+ debug fmodexL
+ optimized fmodex)
+ endif (WINDOWS)
+ set(FMODEX_LIBRARIES ${FMODEX_LIBRARY})
+ set(FMODEX_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodex)
+ endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
+ endif (STANDALONE)
+endif (FMODEX) \ No newline at end of file
diff --git a/indra/cmake/FindFMODEX.cmake b/indra/cmake/FindFMODEX.cmake
new file mode 100644
index 0000000000..9b9b85d73e
--- /dev/null
+++ b/indra/cmake/FindFMODEX.cmake
@@ -0,0 +1,66 @@
+# -*- cmake -*-
+
+# - Find FMODEX
+# Find the FMODEX includes and library
+# This module defines
+# FMODEX_INCLUDE_DIR, where to find fmod.h and fmod_errors.h
+# FMODEX_LIBRARIES, the libraries needed to use FMODEX.
+# FMODEX, If false, do not try to use FMODEX.
+# also defined, but not for general use are
+# FMODEX_LIBRARY, where to find the FMODEX library.
+
+FIND_PATH(FMODEX_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod)
+
+SET(FMODEX_NAMES ${FMODEX_NAMES} fmodex fmodvc fmodexL_vc)
+FIND_LIBRARY(FMODEX_LIBRARY
+ NAMES ${FMODEX_NAMES}
+ PATH_SUFFIXES fmodex
+ )
+
+IF (FMODEX_SDK_DIR OR WINDOWS)
+ if(WINDOWS)
+ set(FMODEX_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODEX")
+ STRING(REGEX REPLACE "\\\\" "/" FMODEX_SDK_DIR ${FMODEX_SDK_DIR})
+ endif(WINDOWS)
+ find_library(FMODEX_LIBRARY
+ fmodex_vc fmodexL_vc
+ PATHS
+ ${FMODEX_SDK_DIR}/api/lib
+ ${FMODEX_SDK_DIR}/api
+ ${FMODEX_SDK_DIR}
+ )
+ find_path(FMODEX_INCLUDE_DIR fmod.h
+ ${FMODEX_SDK_DIR}/api/inc
+ ${FMODEX_SDK_DIR}/api
+ ${FMODEX_SDK_DIR}
+ )
+ find_path(FMODEX_INCLUDE_DIR fmod.h
+ ${FMODEX_SDK_DIR}/api/inc
+ ${FMODEX_SDK_DIR}/api
+ ${FMODEX_SDK_DIR}
+ )
+ IF (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
+ SET(FMODEX_LIBRARIES ${FMODEX_LIBRARY})
+ SET(FMODEX_FOUND "YES")
+ endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
+ENDIF (FMODEX_SDK_DIR OR WINDOWS)
+
+IF (FMODEX_FOUND)
+ IF (NOT FMODEX_FIND_QUIETLY)
+ MESSAGE(STATUS "Found FMODEX: ${FMODEX_LIBRARIES}")
+ ENDIF (NOT FMODEX_FIND_QUIETLY)
+ELSE (FMODEX_FOUND)
+ IF (FMODEX_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find FMODEX library")
+ ENDIF (FMODEX_FIND_REQUIRED)
+ENDIF (FMODEX_FOUND)
+
+# Deprecated declarations.
+SET (NATIVE_FMODEX_INCLUDE_PATH ${FMODEX_INCLUDE_DIR} )
+GET_FILENAME_COMPONENT (NATIVE_FMODEX_LIB_PATH ${FMODEX_LIBRARY} PATH)
+
+MARK_AS_ADVANCED(
+ FMODEX_LIBRARY
+ FMODEX_INCLUDE_DIR
+ )
+ \ No newline at end of file
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt
index 632e5d46e3..e404cfc10e 100644
--- a/indra/llaudio/CMakeLists.txt
+++ b/indra/llaudio/CMakeLists.txt
@@ -5,7 +5,13 @@ project(llaudio)
include(00-Common)
include(Audio)
include(LLAudio)
-include(FMOD)
+if (FMODEX)
+ include(FMODEX)
+ set(FMOD OFF)
+endif (FMODEX)
+if (NOT FMODEX)
+ include(FMOD)
+endif (NOT FMODEX)
include(OPENAL)
include(LLCommon)
include(LLMath)
@@ -24,7 +30,6 @@ include_directories(
${VORBIS_INCLUDE_DIRS}
${OPENAL_LIB_INCLUDE_DIRS}
${FREEAULT_LIB_INCLUDE_DIRS}
- ${FMOD_INCLUDE_DIR}
)
set(llaudio_SOURCE_FILES
@@ -44,6 +49,23 @@ set(llaudio_HEADER_FILES
llwindgen.h
)
+if (FMODEX)
+ include_directories(
+ ${FMODEX_INCLUDE_DIR}
+ )
+ list(APPEND llaudio_SOURCE_FILES
+ llaudioengine_fmodex.cpp
+ lllistener_fmodex.cpp
+ llstreamingaudio_fmodex.cpp
+ )
+
+ list(APPEND llaudio_HEADER_FILES
+ llaudioengine_fmodex.h
+ lllistener_fmodex.h
+ llstreamingaudio_fmodex.h
+ )
+endif (FMODEX)
+
if (FMOD)
include_directories(
${FMOD_INCLUDE_DIR}
diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h
index df1e4dc305..dbaba0fb91 100644
--- a/indra/llaudio/llaudioengine.h
+++ b/indra/llaudio/llaudioengine.h
@@ -42,7 +42,6 @@
#include "lllistener.h"
const F32 LL_WIND_UPDATE_INTERVAL = 0.1f;
-const F32 LL_ROLLOFF_MULTIPLIER_UNDER_WATER = 5.f; // How much sounds are weaker under water
const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f;
const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f;
diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp
new file mode 100644
index 0000000000..c3c30d87fe
--- /dev/null
+++ b/indra/llaudio/llaudioengine_fmodex.cpp
@@ -0,0 +1,746 @@
+/**
+ * @file audioengine_fmodex.cpp
+ * @brief Implementation of LLAudioEngine class abstracting the audio
+ * support as a FMODEX implementation
+ *
+ * $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 "linden_common.h"
+
+#include "llstreamingaudio.h"
+#include "llstreamingaudio_fmodex.h"
+
+#include "llaudioengine_fmodex.h"
+#include "lllistener_fmodex.h"
+
+#include "llerror.h"
+#include "llmath.h"
+#include "llrand.h"
+
+#include "fmod.hpp"
+#include "fmod_errors.h"
+#include "lldir.h"
+#include "llapr.h"
+
+#include "sound_ids.h"
+
+FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
+
+FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
+
+LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
+{
+ mInited = false;
+ mWindGen = NULL;
+ mWindDSP = NULL;
+ mSystem = NULL;
+ mEnableProfiler = enable_profiler;
+}
+
+
+LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX()
+{
+}
+
+
+inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
+{
+ if(result == FMOD_OK)
+ return false;
+ llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
+ return true;
+}
+
+void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr)
+{
+ if(type & FMOD_MEMORY_STREAM_DECODE)
+ {
+ llinfos << "Decode buffer size: " << size << llendl;
+ }
+ else if(type & FMOD_MEMORY_STREAM_FILE)
+ {
+ llinfos << "Strean buffer size: " << size << llendl;
+ }
+ return new char[size];
+}
+void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr)
+{
+ memset(ptr,0,size);
+ return ptr;
+}
+void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr)
+{
+ delete[] (char*)ptr;
+}
+
+bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
+{
+ U32 version;
+ FMOD_RESULT result;
+
+ LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL;
+
+ //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE);
+ //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize"))
+ // return false;
+
+ result = FMOD::System_Create(&mSystem);
+ if(Check_FMOD_Error(result, "FMOD::System_Create"))
+ return false;
+
+ //will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer.
+ LLAudioEngine::init(num_channels, userdata);
+
+ result = mSystem->getVersion(&version);
+ Check_FMOD_Error(result, "FMOD::System::getVersion");
+
+ if (version < FMOD_VERSION)
+ {
+ LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Ex version (" << version
+ << ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL;
+ }
+
+ result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
+ Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
+
+ // In this case, all sounds, PLUS wind and stream will be software.
+ result = mSystem->setSoftwareChannels(num_channels + 2);
+ Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
+
+ U32 fmod_flags = FMOD_INIT_NORMAL;
+ if(mEnableProfiler)
+ {
+ fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
+ mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]);
+ mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]);
+ mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]);
+ mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]);
+ }
+
+#if LL_LINUX
+ bool audio_ok = false;
+
+ if (!audio_ok)
+ {
+ if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/
+ {
+ LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL;
+ if(mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK &&
+ (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
+ {
+ LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL;
+ audio_ok = true;
+ }
+ else
+ {
+ Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize");
+ }
+ }
+ else
+ {
+ LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL;
+ }
+ }
+ if (!audio_ok)
+ {
+ if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/
+ {
+ LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
+ if(mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK &&
+ (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
+ {
+ LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
+ audio_ok = true;
+ }
+ else
+ {
+ Check_FMOD_Error(result, "ALSA audio output FAILED to initialize");
+ }
+ }
+ else
+ {
+ LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL;
+ }
+ }
+ if (!audio_ok)
+ {
+ if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/
+ {
+ LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL;
+ if(mSystem->setOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK &&
+ (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
+ {
+ LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
+ audio_ok = true;
+ }
+ else
+ {
+ Check_FMOD_Error(result, "OSS audio output FAILED to initialize");
+ }
+ }
+ else
+ {
+ LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
+ }
+ }
+ if (!audio_ok)
+ {
+ LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
+ return false;
+ }
+
+ // We're interested in logging which output method we
+ // ended up with, for QA purposes.
+ FMOD_OUTPUTTYPE output_type;
+ mSystem->getOutput(&output_type);
+ switch (output_type)
+ {
+ case FMOD_OUTPUTTYPE_NOSOUND:
+ LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
+ case FMOD_OUTPUTTYPE_PULSEAUDIO:
+ LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break;
+ case FMOD_OUTPUTTYPE_ALSA:
+ LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
+ case FMOD_OUTPUTTYPE_OSS:
+ LL_INFOS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
+ default:
+ LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
+ };
+#else // LL_LINUX
+
+ // initialize the FMOD engine
+ result = mSystem->init( num_channels + 2, fmod_flags, 0);
+ if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
+ {
+ /*
+ Ok, the speaker mode selected isn't supported by this soundcard. Switch it
+ back to stereo...
+ */
+ result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
+ Check_FMOD_Error(result,"Error falling back to stereo mode");
+ /*
+ ... and re-init.
+ */
+ result = mSystem->init( num_channels + 2, fmod_flags, 0);
+ }
+ if(Check_FMOD_Error(result, "Error initializing FMOD Ex"))
+ return false;
+#endif
+
+ // set up our favourite FMOD-native streaming audio implementation if none has already been added
+ if (!getStreamingAudioImpl()) // no existing implementation added
+ setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
+
+ LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD Ex initialized correctly" << LL_ENDL;
+
+ int r_numbuffers, r_samplerate, r_channels, r_bits;
+ unsigned int r_bufferlength;
+ char r_name[256];
+ mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers);
+ mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits);
+ mSystem->getDriverInfo(0, r_name, 255, 0);
+ r_name[255] = '\0';
+ int latency = 1000.0 * r_bufferlength * r_numbuffers /r_samplerate;
+
+ LL_INFOS("AppInit") << "FMOD device: "<< r_name << "\n"
+ << "FMOD Ex parameters: " << r_samplerate << " Hz * " << r_channels << " * " <<r_bits <<" bit\n"
+ << "\tbuffer " << r_bufferlength << " * " << r_numbuffers << " (" << latency <<"ms)" << LL_ENDL;
+
+ mInited = true;
+
+ return true;
+}
+
+
+std::string LLAudioEngine_FMODEX::getDriverName(bool verbose)
+{
+ llassert_always(mSystem);
+ if (verbose)
+ {
+ U32 version;
+ if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion"))
+ {
+ return llformat("FMOD Ex %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
+ }
+ }
+ return "FMODEx";
+}
+
+
+void LLAudioEngine_FMODEX::allocateListener(void)
+{
+ mListenerp = (LLListener *) new LLListener_FMODEX(mSystem);
+ if (!mListenerp)
+ {
+ llwarns << "Listener creation failed" << llendl;
+ }
+}
+
+
+void LLAudioEngine_FMODEX::shutdown()
+{
+ stopInternetStream();
+
+ llinfos << "About to LLAudioEngine::shutdown()" << llendl;
+ LLAudioEngine::shutdown();
+
+ llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << llendl;
+ mSystem->close();
+ mSystem->release();
+ llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << llendl;
+
+ delete mListenerp;
+ mListenerp = NULL;
+}
+
+
+LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer()
+{
+ return new LLAudioBufferFMODEX(mSystem);
+}
+
+
+LLAudioChannel * LLAudioEngine_FMODEX::createChannel()
+{
+ return new LLAudioChannelFMODEX(mSystem);
+}
+
+bool LLAudioEngine_FMODEX::initWind()
+{
+ mNextWindUpdate = 0.0;
+
+ if (!mWindDSP)
+ {
+ FMOD_DSP_DESCRIPTION dspdesc;
+ memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
+ strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
+ dspdesc.channels=2;
+ dspdesc.read = &windCallback; //Assign callback.
+ if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP"))
+ return false;
+
+ if(mWindGen)
+ delete mWindGen;
+
+ float frequency = 44100;
+ mWindDSP->getDefaults(&frequency,0,0,0);
+ mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
+ mWindDSP->setUserData((void*)mWindGen);
+ }
+
+ if (mWindDSP)
+ {
+ mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0);
+ return true;
+ }
+ return false;
+}
+
+
+void LLAudioEngine_FMODEX::cleanupWind()
+{
+ if (mWindDSP)
+ {
+ mWindDSP->remove();
+ mWindDSP->release();
+ mWindDSP = NULL;
+ }
+
+ delete mWindGen;
+ mWindGen = NULL;
+}
+
+
+//-----------------------------------------------------------------------
+void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
+{
+ LLVector3 wind_pos;
+ F64 pitch;
+ F64 center_freq;
+
+ if (!mEnableWind)
+ {
+ return;
+ }
+
+ if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
+ {
+
+ // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
+ // need to convert this to the conventional orientation DS3D and OpenAL use
+ // where +X = right, +Y = up, +Z = backwards
+
+ wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
+
+ // cerr << "Wind update" << endl;
+
+ pitch = 1.0 + mapWindVecToPitch(wind_vec);
+ center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
+
+ mWindGen->mTargetFreq = (F32)center_freq;
+ mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
+ mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
+ }
+}
+
+//-----------------------------------------------------------------------
+void LLAudioEngine_FMODEX::setInternalGain(F32 gain)
+{
+ if (!mInited)
+ {
+ return;
+ }
+
+ gain = llclamp( gain, 0.0f, 1.0f );
+
+ FMOD::ChannelGroup *master_group;
+ mSystem->getMasterChannelGroup(&master_group);
+
+ master_group->setVolume(gain);
+
+ LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
+ if ( saimpl )
+ {
+ // fmod likes its streaming audio channel gain re-asserted after
+ // master volume change.
+ saimpl->setGain(saimpl->getGain());
+ }
+}
+
+//
+// LLAudioChannelFMODEX implementation
+//
+
+LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0)
+{
+}
+
+
+LLAudioChannelFMODEX::~LLAudioChannelFMODEX()
+{
+ cleanup();
+}
+
+bool LLAudioChannelFMODEX::updateBuffer()
+{
+ if (LLAudioChannel::updateBuffer())
+ {
+ // Base class update returned true, which means that we need to actually
+ // set up the channel for a different buffer.
+
+ LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer();
+
+ // Grab the FMOD sample associated with the buffer
+ FMOD::Sound *soundp = bufferp->getSound();
+ if (!soundp)
+ {
+ // This is bad, there should ALWAYS be a sound associated with a legit
+ // buffer.
+ llerrs << "No FMOD sound!" << llendl;
+ return false;
+ }
+
+
+ // Actually play the sound. Start it off paused so we can do all the necessary
+ // setup.
+ if(!mChannelp)
+ {
+ FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp);
+ Check_FMOD_Error(result, "FMOD::System::playSound");
+ }
+
+ //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
+ }
+
+ // If we have a source for the channel, we need to update its gain.
+ if (mCurrentSourcep)
+ {
+ // SJB: warnings can spam and hurt framerate, disabling
+ FMOD_RESULT result;
+
+ result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
+ //Check_FMOD_Error(result, "FMOD::Channel::setVolume");
+
+ result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
+ /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode"))
+ {
+ S32 index;
+ mChannelp->getIndex(&index);
+ llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
+ << " at " << mCurrentSourcep->getPositionGlobal() << llendl;
+ }*/
+ }
+
+ return true;
+}
+
+
+void LLAudioChannelFMODEX::update3DPosition()
+{
+ if (!mChannelp)
+ {
+ // We're not actually a live channel (i.e., we're not playing back anything)
+ return;
+ }
+
+ LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp;
+ if (!bufferp)
+ {
+ // We don't have a buffer associated with us (should really have been picked up
+ // by the above if.
+ return;
+ }
+
+ if (mCurrentSourcep->isAmbient())
+ {
+ // Ambient sound, don't need to do any positional updates.
+ set3DMode(false);
+ }
+ else
+ {
+ // Localized sound. Update the position and velocity of the sound.
+ set3DMode(true);
+
+ LLVector3 float_pos;
+ float_pos.setVec(mCurrentSourcep->getPositionGlobal());
+ FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV);
+ Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes");
+ }
+}
+
+
+void LLAudioChannelFMODEX::updateLoop()
+{
+ if (!mChannelp)
+ {
+ // May want to clear up the loop/sample counters.
+ return;
+ }
+
+ //
+ // Hack: We keep track of whether we looped or not by seeing when the
+ // sample position looks like it's going backwards. Not reliable; may
+ // yield false negatives.
+ //
+ U32 cur_pos;
+ mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES);
+
+ if (cur_pos < (U32)mLastSamplePos)
+ {
+ mLoopedThisFrame = true;
+ }
+ mLastSamplePos = cur_pos;
+}
+
+
+void LLAudioChannelFMODEX::cleanup()
+{
+ if (!mChannelp)
+ {
+ //llinfos << "Aborting cleanup with no channel handle." << llendl;
+ return;
+ }
+
+ //llinfos << "Cleaning up channel: " << mChannelID << llendl;
+ Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
+
+ mCurrentBufferp = NULL;
+ mChannelp = NULL;
+}
+
+
+void LLAudioChannelFMODEX::play()
+{
+ if (!mChannelp)
+ {
+ llwarns << "Playing without a channel handle, aborting" << llendl;
+ return;
+ }
+
+ Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
+
+ getSource()->setPlayedOnce(true);
+
+ if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()])
+ mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]);
+}
+
+
+void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp)
+{
+ LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp;
+ if (!(fmod_channelp->mChannelp && mChannelp))
+ {
+ // Don't have channels allocated to both the master and the slave
+ return;
+ }
+
+ U32 cur_pos;
+ if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
+ return;
+
+ cur_pos %= mCurrentBufferp->getLength();
+
+ // Try to match the position of our sync master
+ Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position");
+
+ // Start us playing
+ play();
+}
+
+
+bool LLAudioChannelFMODEX::isPlaying()
+{
+ if (!mChannelp)
+ {
+ return false;
+ }
+
+ bool paused, playing;
+ mChannelp->getPaused(&paused);
+ mChannelp->isPlaying(&playing);
+ return !paused && playing;
+}
+
+
+//
+// LLAudioChannelFMODEX implementation
+//
+
+
+LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL)
+{
+}
+
+
+LLAudioBufferFMODEX::~LLAudioBufferFMODEX()
+{
+ if(mSoundp)
+ {
+ mSoundp->release();
+ mSoundp = NULL;
+ }
+}
+
+
+bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
+{
+ // Try to open a wav file from disk. This will eventually go away, as we don't
+ // really want to block doing this.
+ if (filename.empty())
+ {
+ // invalid filename, abort.
+ return false;
+ }
+
+ if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB))
+ {
+ // File not found, abort.
+ return false;
+ }
+
+ if (mSoundp)
+ {
+ // If there's already something loaded in this buffer, clean it up.
+ mSoundp->release();
+ mSoundp = NULL;
+ }
+
+ FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE;
+ FMOD_CREATESOUNDEXINFO exinfo;
+ memset(&exinfo,0,sizeof(exinfo));
+ exinfo.cbsize = sizeof(exinfo);
+ exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
+ // Load up the wav file into an fmod sample
+#if LL_WINDOWS
+ FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp);
+#else
+ FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp);
+#endif
+
+ if (result != FMOD_OK)
+ {
+ // We failed to load the file for some reason.
+ llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
+
+ //
+ // If we EVER want to load wav files provided by end users, we need
+ // to rethink this!
+ //
+ // file is probably corrupt - remove it.
+ LLFile::remove(filename);
+ return false;
+ }
+
+ // Everything went well, return true
+ return true;
+}
+
+
+U32 LLAudioBufferFMODEX::getLength()
+{
+ if (!mSoundp)
+ {
+ return 0;
+ }
+
+ U32 length;
+ mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
+ return length;
+}
+
+
+void LLAudioChannelFMODEX::set3DMode(bool use3d)
+{
+ FMOD_MODE current_mode;
+ if(mChannelp->getMode(&current_mode) != FMOD_OK)
+ return;
+ FMOD_MODE new_mode = current_mode;
+ new_mode &= ~(use3d ? FMOD_2D : FMOD_3D);
+ new_mode |= use3d ? FMOD_3D : FMOD_2D;
+
+ if(current_mode != new_mode)
+ {
+ mChannelp->setMode(new_mode);
+ }
+}
+
+
+FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels)
+{
+ // originalbuffer = fmod's original mixbuffer.
+ // newbuffer = the buffer passed from the previous DSP unit.
+ // length = length in samples at this mix time.
+ // userdata = user parameter passed through in FSOUND_DSP_Create.
+
+ LLWindGen<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *windgen;
+ FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
+
+ thisdsp->getUserData((void **)&windgen);
+ S32 channels, configwidth, configheight;
+ thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight);
+
+ windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length);
+
+ return FMOD_OK;
+}
diff --git a/indra/llaudio/llaudioengine_fmodex.h b/indra/llaudio/llaudioengine_fmodex.h
new file mode 100644
index 0000000000..cf3d967d4f
--- /dev/null
+++ b/indra/llaudio/llaudioengine_fmodex.h
@@ -0,0 +1,129 @@
+/**
+ * @file audioengine_fmodex.h
+ * @brief Definition of LLAudioEngine class abstracting the audio
+ * support as a FMODEX implementation
+ *
+ * $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$
+ */
+
+#ifndef LL_AUDIOENGINE_FMODEX_H
+#define LL_AUDIOENGINE_FMODEX_H
+
+#include "llaudioengine.h"
+#include "lllistener_fmod.h"
+#include "llwindgen.h"
+
+//Stubs
+class LLAudioStreamManagerFMODEX;
+namespace FMOD
+{
+ class System;
+ class Channel;
+ class ChannelGroup;
+ class Sound;
+ class DSP;
+}
+
+//Interfaces
+class LLAudioEngine_FMODEX : public LLAudioEngine
+{
+public:
+ LLAudioEngine_FMODEX(bool enable_profiler);
+ virtual ~LLAudioEngine_FMODEX();
+
+ // initialization/startup/shutdown
+ virtual bool init(const S32 num_channels, void *user_data);
+ virtual std::string getDriverName(bool verbose);
+ virtual void allocateListener();
+
+ virtual void shutdown();
+
+ /*virtual*/ bool initWind();
+ /*virtual*/ void cleanupWind();
+
+ /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
+
+ typedef F32 MIXBUFFERFORMAT;
+
+ FMOD::System *getSystem() const {return mSystem;}
+protected:
+ /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to.
+ /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel.
+
+ /*virtual*/ void setInternalGain(F32 gain);
+
+ bool mInited;
+
+ LLWindGen<MIXBUFFERFORMAT> *mWindGen;
+
+ FMOD::DSP *mWindDSP;
+ FMOD::System *mSystem;
+ bool mEnableProfiler;
+
+public:
+ static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
+};
+
+
+class LLAudioChannelFMODEX : public LLAudioChannel
+{
+public:
+ LLAudioChannelFMODEX(FMOD::System *audioengine);
+ virtual ~LLAudioChannelFMODEX();
+
+protected:
+ /*virtual*/ void play();
+ /*virtual*/ void playSynced(LLAudioChannel *channelp);
+ /*virtual*/ void cleanup();
+ /*virtual*/ bool isPlaying();
+
+ /*virtual*/ bool updateBuffer();
+ /*virtual*/ void update3DPosition();
+ /*virtual*/ void updateLoop();
+
+ void set3DMode(bool use3d);
+protected:
+ FMOD::System *getSystem() const {return mSystemp;}
+ FMOD::System *mSystemp;
+ FMOD::Channel *mChannelp;
+ S32 mLastSamplePos;
+};
+
+
+class LLAudioBufferFMODEX : public LLAudioBuffer
+{
+public:
+ LLAudioBufferFMODEX(FMOD::System *audioengine);
+ virtual ~LLAudioBufferFMODEX();
+
+ /*virtual*/ bool loadWAV(const std::string& filename);
+ /*virtual*/ U32 getLength();
+ friend class LLAudioChannelFMODEX;
+protected:
+ FMOD::System *getSystem() const {return mSystemp;}
+ FMOD::System *mSystemp;
+ FMOD::Sound *getSound() const{ return mSoundp; }
+ FMOD::Sound *mSoundp;
+};
+
+
+#endif // LL_AUDIOENGINE_FMODEX_H
diff --git a/indra/llaudio/lllistener_fmodex.cpp b/indra/llaudio/lllistener_fmodex.cpp
new file mode 100644
index 0000000000..4bc745b89a
--- /dev/null
+++ b/indra/llaudio/lllistener_fmodex.cpp
@@ -0,0 +1,135 @@
+/**
+ * @file listener_fmodex.cpp
+ * @brief Implementation of LISTENER class abstracting the audio
+ * support as a FMODEX implementation (windows only)
+ *
+ * $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 "linden_common.h"
+#include "llaudioengine.h"
+#include "lllistener_fmodex.h"
+#include "fmod.hpp"
+
+//-----------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------
+LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
+{
+ mSystem = system;
+ init();
+}
+
+//-----------------------------------------------------------------------
+LLListener_FMODEX::~LLListener_FMODEX()
+{
+}
+
+//-----------------------------------------------------------------------
+void LLListener_FMODEX::init(void)
+{
+ // do inherited
+ LLListener::init();
+ mDopplerFactor = 1.0f;
+ mRolloffFactor = 1.0f;
+}
+
+//-----------------------------------------------------------------------
+void LLListener_FMODEX::translate(LLVector3 offset)
+{
+ LLListener::translate(offset);
+
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
+}
+
+//-----------------------------------------------------------------------
+void LLListener_FMODEX::setPosition(LLVector3 pos)
+{
+ LLListener::setPosition(pos);
+
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
+}
+
+//-----------------------------------------------------------------------
+void LLListener_FMODEX::setVelocity(LLVector3 vel)
+{
+ LLListener::setVelocity(vel);
+
+ mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
+}
+
+//-----------------------------------------------------------------------
+void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
+{
+ LLListener::orient(up, at);
+
+ // Welcome to the transition between right and left
+ // (coordinate systems, that is)
+ // Leaving the at vector alone results in a L/R reversal
+ // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
+ at = -at;
+
+ mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
+}
+
+//-----------------------------------------------------------------------
+void LLListener_FMODEX::commitDeferredChanges()
+{
+ mSystem->update();
+}
+
+
+void LLListener_FMODEX::setRolloffFactor(F32 factor)
+{
+ //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment.
+ //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well.
+ //In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call.
+ if(mRolloffFactor != factor)
+ {
+ LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL);
+ }
+ mRolloffFactor = factor;
+ mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
+}
+
+
+F32 LLListener_FMODEX::getRolloffFactor()
+{
+ return mRolloffFactor;
+}
+
+
+void LLListener_FMODEX::setDopplerFactor(F32 factor)
+{
+ mDopplerFactor = factor;
+ mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
+}
+
+
+F32 LLListener_FMODEX::getDopplerFactor()
+{
+ return mDopplerFactor;
+}
+
+
diff --git a/indra/llaudio/lllistener_fmodex.h b/indra/llaudio/lllistener_fmodex.h
new file mode 100644
index 0000000000..073b65d53a
--- /dev/null
+++ b/indra/llaudio/lllistener_fmodex.h
@@ -0,0 +1,65 @@
+/**
+ * @file listener_fmodex.h
+ * @brief Description of LISTENER class abstracting the audio support
+ * as an FMOD 3D implementation (windows and Linux)
+ *
+ * $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$
+ */
+
+#ifndef LL_LISTENER_FMODEX_H
+#define LL_LISTENER_FMODEX_H
+
+#include "lllistener.h"
+
+//Stubs
+namespace FMOD
+{
+ class System;
+}
+
+//Interfaces
+class LLListener_FMODEX : public LLListener
+{
+ public:
+ LLListener_FMODEX(FMOD::System *system);
+ virtual ~LLListener_FMODEX();
+ virtual void init();
+
+ virtual void translate(LLVector3 offset);
+ virtual void setPosition(LLVector3 pos);
+ virtual void setVelocity(LLVector3 vel);
+ virtual void orient(LLVector3 up, LLVector3 at);
+ virtual void commitDeferredChanges();
+
+ virtual void setDopplerFactor(F32 factor);
+ virtual F32 getDopplerFactor();
+ virtual void setRolloffFactor(F32 factor);
+ virtual F32 getRolloffFactor();
+ protected:
+ FMOD::System *mSystem;
+ F32 mDopplerFactor;
+ F32 mRolloffFactor;
+};
+
+#endif
+
+
diff --git a/indra/llaudio/llstreamingaudio.h b/indra/llaudio/llstreamingaudio.h
index 20104af744..93479f9d59 100644
--- a/indra/llaudio/llstreamingaudio.h
+++ b/indra/llaudio/llstreamingaudio.h
@@ -45,6 +45,8 @@ class LLStreamingAudioInterface
virtual void setGain(F32 vol) = 0;
virtual F32 getGain() = 0;
virtual std::string getURL() = 0;
+ virtual bool supportsAdjustableBufferSizes(){return false;}
+ virtual void setBufferSizes(U32 streambuffertime, U32 decodebuffertime){};
};
#endif // LL_STREAMINGAUDIO_H
diff --git a/indra/llaudio/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp
new file mode 100644
index 0000000000..463d816331
--- /dev/null
+++ b/indra/llaudio/llstreamingaudio_fmodex.cpp
@@ -0,0 +1,382 @@
+/**
+ * @file streamingaudio_fmodex.cpp
+ * @brief LLStreamingAudio_FMODEX implementation
+ *
+ * $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 "linden_common.h"
+
+#include "llmath.h"
+
+#include "fmod.hpp"
+#include "fmod_errors.h"
+
+#include "llstreamingaudio_fmodex.h"
+
+
+class LLAudioStreamManagerFMODEX
+{
+public:
+ LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
+ FMOD::Channel* startStream();
+ bool stopStream(); // Returns true if the stream was successfully stopped.
+ bool ready();
+
+ const std::string& getURL() { return mInternetStreamURL; }
+
+ FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL);
+protected:
+ FMOD::System* mSystem;
+ FMOD::Channel* mStreamChannel;
+ FMOD::Sound* mInternetStream;
+ bool mReady;
+
+ std::string mInternetStreamURL;
+};
+
+
+
+//---------------------------------------------------------------------------
+// Internet Streaming
+//---------------------------------------------------------------------------
+LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
+ mSystem(system),
+ mCurrentInternetStreamp(NULL),
+ mFMODInternetStreamChannelp(NULL),
+ mGain(1.0f)
+{
+ // Number of milliseconds of audio to buffer for the audio card.
+ // Must be larger than the usual Second Life frame stutter time.
+ const U32 buffer_seconds = 10; //sec
+ const U32 estimated_bitrate = 128; //kbit/sec
+ mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
+
+ // Here's where we set the size of the network buffer and some buffering
+ // parameters. In this case we want a network buffer of 16k, we want it
+ // to prebuffer 40% of that when we first connect, and we want it
+ // to rebuffer 80% of that whenever we encounter a buffer underrun.
+
+ // Leave the net buffer properties at the default.
+ //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
+}
+
+
+LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
+{
+ // nothing interesting/safe to do.
+}
+
+
+void LLStreamingAudio_FMODEX::start(const std::string& url)
+{
+ //if (!mInited)
+ //{
+ // llwarns << "startInternetStream before audio initialized" << llendl;
+ // return;
+ //}
+
+ // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
+ stop();
+
+ if (!url.empty())
+ {
+ llinfos << "Starting internet stream: " << url << llendl;
+ mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
+ mURL = url;
+ }
+ else
+ {
+ llinfos << "Set internet stream to null" << llendl;
+ mURL.clear();
+ }
+}
+
+
+void LLStreamingAudio_FMODEX::update()
+{
+ // Kill dead internet streams, if possible
+ std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
+ for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
+ {
+ LLAudioStreamManagerFMODEX *streamp = *iter;
+ if (streamp->stopStream())
+ {
+ llinfos << "Closed dead stream" << llendl;
+ delete streamp;
+ mDeadStreams.erase(iter++);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+
+ // Don't do anything if there are no streams playing
+ if (!mCurrentInternetStreamp)
+ {
+ return;
+ }
+
+ unsigned int progress;
+ bool starving;
+ bool diskbusy;
+ FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy);
+
+ if (open_state == FMOD_OPENSTATE_READY)
+ {
+ // Stream is live
+
+ // start the stream if it's ready
+ if (!mFMODInternetStreamChannelp &&
+ (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
+ {
+ // Reset volume to previously set volume
+ setGain(getGain());
+ mFMODInternetStreamChannelp->setPaused(false);
+ mLastStarved.stop();
+ }
+ }
+ else if(open_state == FMOD_OPENSTATE_ERROR)
+ {
+ stop();
+ return;
+ }
+
+ if(mFMODInternetStreamChannelp)
+ {
+ FMOD::Sound *sound = NULL;
+
+ if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
+ {
+ if(starving)
+ {
+ if(!mLastStarved.getStarted())
+ {
+ llinfos << "Stream starvation detected! Muting stream audio until it clears." << llendl;
+ llinfos << " (diskbusy="<<diskbusy<<")" << llendl;
+ llinfos << " (progress="<<progress<<")" << llendl;
+ mFMODInternetStreamChannelp->setMute(true);
+ }
+ mLastStarved.start();
+ }
+ else if(mLastStarved.getStarted() && mLastStarved.getElapsedTimeF32() > 1.f)
+ {
+ mLastStarved.stop();
+ mFMODInternetStreamChannelp->setMute(false);
+ }
+ }
+ }
+}
+
+void LLStreamingAudio_FMODEX::stop()
+{
+ mLastStarved.stop();
+
+ if (mFMODInternetStreamChannelp)
+ {
+ mFMODInternetStreamChannelp->setPaused(true);
+ mFMODInternetStreamChannelp->setPriority(0);
+ mFMODInternetStreamChannelp = NULL;
+ }
+
+ if (mCurrentInternetStreamp)
+ {
+ llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
+ if (mCurrentInternetStreamp->stopStream())
+ {
+ delete mCurrentInternetStreamp;
+ }
+ else
+ {
+ llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
+ mDeadStreams.push_back(mCurrentInternetStreamp);
+ }
+ mCurrentInternetStreamp = NULL;
+ //mURL.clear();
+ }
+}
+
+void LLStreamingAudio_FMODEX::pause(int pauseopt)
+{
+ if (pauseopt < 0)
+ {
+ pauseopt = mCurrentInternetStreamp ? 1 : 0;
+ }
+
+ if (pauseopt)
+ {
+ if (mCurrentInternetStreamp)
+ {
+ stop();
+ }
+ }
+ else
+ {
+ start(getURL());
+ }
+}
+
+
+// A stream is "playing" if it has been requested to start. That
+// doesn't necessarily mean audio is coming out of the speakers.
+int LLStreamingAudio_FMODEX::isPlaying()
+{
+ if (mCurrentInternetStreamp)
+ {
+ return 1; // Active and playing
+ }
+ else if (!mURL.empty())
+ {
+ return 2; // "Paused"
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+F32 LLStreamingAudio_FMODEX::getGain()
+{
+ return mGain;
+}
+
+
+std::string LLStreamingAudio_FMODEX::getURL()
+{
+ return mURL;
+}
+
+
+void LLStreamingAudio_FMODEX::setGain(F32 vol)
+{
+ mGain = vol;
+
+ if (mFMODInternetStreamChannelp)
+ {
+ vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
+
+ mFMODInternetStreamChannelp->setVolume(vol);
+ }
+}
+
+///////////////////////////////////////////////////////
+// manager of possibly-multiple internet audio streams
+
+LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
+ mSystem(system),
+ mStreamChannel(NULL),
+ mInternetStream(NULL),
+ mReady(false)
+{
+ mInternetStreamURL = url;
+
+ /*FMOD_CREATESOUNDEXINFO exinfo;
+ memset(&exinfo,0,sizeof(exinfo));
+ exinfo.cbsize = sizeof(exinfo);
+ exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS; //Hint to speed up loading.*/
+
+ FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_MPEGSEARCH | FMOD_IGNORETAGS, 0, &mInternetStream);
+
+ if (result!= FMOD_OK)
+ {
+ llwarns << "Couldn't open fmod stream, error "
+ << FMOD_ErrorString(result)
+ << llendl;
+ mReady = false;
+ return;
+ }
+
+ mReady = true;
+}
+
+FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
+{
+ // We need a live and opened stream before we try and play it.
+ if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
+ {
+ llwarns << "No internet stream to start playing!" << llendl;
+ return NULL;
+ }
+
+ if(mStreamChannel)
+ return mStreamChannel; //Already have a channel for this stream.
+
+ mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
+ return mStreamChannel;
+}
+
+bool LLAudioStreamManagerFMODEX::stopStream()
+{
+ if (mInternetStream)
+ {
+
+
+ bool close = true;
+ switch (getOpenState())
+ {
+ case FMOD_OPENSTATE_CONNECTING:
+ close = false;
+ break;
+ /*case FSOUND_STREAM_NET_NOTCONNECTED:
+ case FSOUND_STREAM_NET_BUFFERING:
+ case FSOUND_STREAM_NET_READY:
+ case FSOUND_STREAM_NET_ERROR:*/
+ default:
+ close = true;
+ }
+
+ if (close)
+ {
+ mInternetStream->release();
+ mStreamChannel = NULL;
+ mInternetStream = NULL;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return true;
+ }
+}
+
+FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
+{
+ FMOD_OPENSTATE state;
+ mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
+ return state;
+}
+
+void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
+{
+ mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES);
+ FMOD_ADVANCEDSETTINGS settings;
+ memset(&settings,0,sizeof(settings));
+ settings.cbsize=sizeof(settings);
+ settings.defaultDecodeBufferSize = decodebuffertime;//ms
+ mSystem->setAdvancedSettings(&settings);
+}
diff --git a/indra/llaudio/llstreamingaudio_fmodex.h b/indra/llaudio/llstreamingaudio_fmodex.h
new file mode 100644
index 0000000000..3751dd60ad
--- /dev/null
+++ b/indra/llaudio/llstreamingaudio_fmodex.h
@@ -0,0 +1,75 @@
+/**
+ * @file streamingaudio_fmodex.h
+ * @brief Definition of LLStreamingAudio_FMODEX implementation
+ *
+ * $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$
+ */
+
+#ifndef LL_STREAMINGAUDIO_FMOD_H
+#define LL_STREAMINGAUDIO_FMOD_H
+
+#include "stdtypes.h" // from llcommon
+
+#include "llstreamingaudio.h"
+#include "lltimer.h"
+
+//Stubs
+class LLAudioStreamManagerFMODEX;
+namespace FMOD
+{
+ class System;
+ class Channel;
+}
+
+//Interfaces
+class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
+{
+ public:
+ LLStreamingAudio_FMODEX(FMOD::System *system);
+ /*virtual*/ ~LLStreamingAudio_FMODEX();
+
+ /*virtual*/ void start(const std::string& url);
+ /*virtual*/ void stop();
+ /*virtual*/ void pause(int pause);
+ /*virtual*/ void update();
+ /*virtual*/ int isPlaying();
+ /*virtual*/ void setGain(F32 vol);
+ /*virtual*/ F32 getGain();
+ /*virtual*/ std::string getURL();
+
+ /*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
+ /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
+private:
+ FMOD::System *mSystem;
+
+ LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
+ FMOD::Channel *mFMODInternetStreamChannelp;
+ std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
+
+ std::string mURL;
+ F32 mGain;
+
+ LLTimer mLastStarved;
+};
+
+
+#endif // LL_STREAMINGAUDIO_FMOD_H
diff --git a/indra/llaudio/llwindgen.h b/indra/llaudio/llwindgen.h
index b9cecb60a1..719b0ecbf2 100644
--- a/indra/llaudio/llwindgen.h
+++ b/indra/llaudio/llwindgen.h
@@ -27,6 +27,7 @@
#define WINDGEN_H
#include "llcommon.h"
+#include "llrand.h"
template <class MIXBUFFERFORMAT_T>
class LLWindGen
@@ -54,7 +55,9 @@ public:
}
const U32 getInputSamplingRate() { return mInputSamplingRate; }
-
+ const F32 getNextSample();
+ const F32 getClampedSample(bool clamp, F32 sample);
+
// newbuffer = the buffer passed from the previous DSP unit.
// numsamples = length in samples-per-channel at this mix time.
// NOTE: generates L/R interleaved stereo
@@ -89,7 +92,7 @@ public:
// Start with white noise
// This expression is fragile, rearrange it and it will break!
- next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
+ next_sample = getNextSample();
// Apply a pinking filter
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
@@ -126,23 +129,13 @@ public:
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
{
mLastSample = mLastSample + delta;
- S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
- S32 sample_left = (S32)mLastSample - sample_right;
+ MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR);
+ MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
- if (!clip)
- {
- *cursamplep = (MIXBUFFERFORMAT_T)sample_left;
- ++cursamplep;
- *cursamplep = (MIXBUFFERFORMAT_T)sample_right;
- ++cursamplep;
- }
- else
- {
- *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
- ++cursamplep;
- *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
- ++cursamplep;
- }
+ *cursamplep = sample_left;
+ ++cursamplep;
+ *cursamplep = sample_right;
+ ++cursamplep;
}
}
@@ -173,4 +166,9 @@ private:
F32 mLastSample;
};
+template<class T> inline const F32 LLWindGen<T>::getNextSample() { return (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); }
+template<> inline const F32 LLWindGen<F32>::getNextSample() { return ll_frand()-.5f; }
+template<class T> inline const F32 LLWindGen<T>::getClampedSample(bool clamp, F32 sample) { return clamp ? (F32)llclamp((S32)sample,(S32)S16_MIN,(S32)S16_MAX) : sample; }
+template<> inline const F32 LLWindGen<F32>::getClampedSample(bool clamp, F32 sample) { return sample; }
+
#endif
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b569808a06..793b01baa1 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -10,7 +10,8 @@ include(DirectX)
include(OpenSSL)
include(DragDrop)
include(EXPAT)
-include(FMOD)
+include(FMODEX)
+set(FMOD OFF)
include(OPENAL)
include(FindOpenGL)
include(Hunspell)
@@ -52,6 +53,14 @@ if (NOT HAVOK_TPV)
add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions)
endif (NOT HAVOK_TPV)
+if(FMODEX)
+ include_directories(${FMODEX_INCLUDE_DIR})
+endif(FMODEX)
+
+if(FMOD)
+ include_directories(${FMOD_INCLUDE_DIR})
+endif(FMOD)
+
include_directories(
${DBUSGLIB_INCLUDE_DIRS}
${JSONCPP_INCLUDE_DIR}
@@ -61,7 +70,6 @@ include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLCOREHTTP_INCLUDE_DIRS}
${LLPHYSICS_INCLUDE_DIRS}
- ${FMOD_INCLUDE_DIR}
${LLIMAGE_INCLUDE_DIRS}
${LLKDU_INCLUDE_DIRS}
${LLINVENTORY_INCLUDE_DIRS}
@@ -1521,10 +1529,15 @@ if (OPENAL)
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL")
endif (OPENAL)
-if (FMOD)
- set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD")
+if (FMOD OR FMODEX)
+ if (FMODEX)
+ set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
+ endif (FMODEX)
+ if (FMOD)
+ set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD")
+ endif (FMOD)
- if (DARWIN)
+ if (DARWIN AND FMOD)
set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp)
add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES})
set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY})
@@ -1537,11 +1550,16 @@ if (FMOD)
)
set(FMODWRAPPER_LIBRARY fmodwrapper)
target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
- else (DARWIN)
- # fmodwrapper unnecessary on linux or windows
- set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY})
- endif (DARWIN)
-endif (FMOD)
+ else (DARWIN AND FMOD)
+ # fmodwrapper unnecessary on linux or windows for fmod and darwin for fmodex
+ if (FMODEX)
+ set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY})
+ endif (FMODEX)
+ if (FMOD)
+ set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY})
+ endif (FMOD)
+ endif (DARWIN AND FMOD)
+endif (FMOD OR FMODEX)
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
@@ -1616,9 +1634,6 @@ if (WINDOWS)
${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll
${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll
- ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll
- ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll
- ${SHARED_LIB_STAGING_DIR}/Debug/fmod.dll
${SHARED_LIB_STAGING_DIR}/Release/msvcr100.dll
${SHARED_LIB_STAGING_DIR}/Release/msvcp100.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcr100.dll
@@ -1683,6 +1698,22 @@ if (WINDOWS)
windows-updater
)
+ if (FMODEX)
+ list(APPEND COPY_INPUT_DEPENDENCIES
+ ${SHARED_LIB_STAGING_DIR}/Release/fmodex.dll
+ ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmodex.dll
+ ${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll
+ )
+ endif (FMODEX)
+
+ if (FMOD)
+ list(APPEND COPY_INPUT_DEPENDENCIES
+ ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll
+ ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll
+ ${SHARED_LIB_STAGING_DIR}/Debug/fmod.dll
+ )
+ endif (FMOD)
+
add_custom_command(
OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat
COMMAND ${PYTHON_EXECUTABLE}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 2e91d10cd3..995546ab23 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -269,6 +269,17 @@
<key>Value</key>
<real>1.0</real>
</map>
+ <key>AudioLevelUnderwaterRolloff</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls the distance-based dropoff of audio volume underwater(fraction or multiple of default audio rolloff)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
<key>AudioLevelSFX</key>
<map>
<key>Comment</key>
@@ -14094,5 +14105,38 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>FMODExProfilerEnable</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable profiler tool if using FMOD Ex</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FMODExDecodeBufferSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Sets the streaming decode buffer size (in milliseconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1000</integer>
+ </map>
+ <key>FMODExStreamBufferSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Sets the streaming buffer size (in milliseconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>7000</integer>
+ </map>
</map>
</llsd>
diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh
index 20936c6460..71b7e74c63 100755
--- a/indra/newview/linux_tools/wrapper.sh
+++ b/indra/newview/linux_tools/wrapper.sh
@@ -4,17 +4,21 @@
## These options are for self-assisted troubleshooting during this beta
## testing phase; you should not usually need to touch them.
+## - Avoids using any FMOD Ex audio driver.
+#export LL_BAD_FMODEX_DRIVER=x
## - Avoids using any OpenAL audio driver.
#export LL_BAD_OPENAL_DRIVER=x
## - Avoids using any FMOD audio driver.
#export LL_BAD_FMOD_DRIVER=x
+## - Avoids using the FMOD Ex PulseAudio audio driver.
+#export LL_BAD_FMOD_PULSEAUDIO=x
+## - Avoids using the FMOD or FMOD Ex ALSA audio driver.
+#export LL_BAD_FMOD_ALSA=x
+## - Avoids using the FMOD or FMOD Ex OSS audio driver.
+#export LL_BAD_FMOD_OSS=x
## - Avoids using the FMOD ESD audio driver.
#export LL_BAD_FMOD_ESD=x
-## - Avoids using the FMOD OSS audio driver.
-#export LL_BAD_FMOD_OSS=x
-## - Avoids using the FMOD ALSA audio driver.
-#export LL_BAD_FMOD_ALSA=x
## - Avoids the optional OpenGL extensions which have proven most problematic
## on some hardware. Disabling this option may cause BETTER PERFORMANCE but
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 0e3007724b..6a874d1af5 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -37,6 +37,10 @@
#include "llviewermedia_streamingaudio.h"
#include "llaudioengine.h"
+#ifdef LL_FMODEX
+# include "llaudioengine_fmodex.h"
+#endif
+
#ifdef LL_FMOD
# include "llaudioengine_fmod.h"
#endif
@@ -623,6 +627,17 @@ bool idle_startup()
{
gAudiop = NULL;
+#ifdef LL_FMODEX
+ if (!gAudiop
+#if !LL_WINDOWS
+ && NULL == getenv("LL_BAD_FMODEX_DRIVER")
+#endif // !LL_WINDOWS
+ )
+ {
+ gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable"));
+ }
+#endif
+
#ifdef LL_OPENAL
if (!gAudiop
#if !LL_WINDOWS
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index 8d8c401dac..f349eeac63 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -43,6 +43,8 @@
#include "llparcel.h"
#include "llviewermessage.h"
+#include "llstreamingaudio.h"
+
/////////////////////////////////////////////////////////
LLViewerAudio::LLViewerAudio() :
@@ -101,6 +103,11 @@ void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI)
else
{
mFadeState = FADE_IN;
+
+ LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl();
+ if(stream && stream->supportsAdjustableBufferSizes())
+ stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize"));
+
gAudiop->startInternetStream(mNextStreamURI);
startFading();
registerIdleListener();
@@ -156,6 +163,11 @@ bool LLViewerAudio::onIdleUpdate()
if (!mNextStreamURI.empty())
{
mFadeState = FADE_IN;
+
+ LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl();
+ if(stream && stream->supportsAdjustableBufferSizes())
+ stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize"));
+
gAudiop->startInternetStream(mNextStreamURI);
startFading();
}
@@ -385,7 +397,12 @@ void audio_update_volume(bool force_update)
gAudiop->setMasterGain ( master_volume );
gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler"));
- gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
+
+ if(!LLViewerCamera::getInstance()->cameraUnderWater())
+ gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
+ else
+ gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelUnderwaterRolloff"));
+
gAudiop->setMuted(mute_audio || progress_view_visible);
if (force_update)
@@ -466,44 +483,22 @@ void audio_update_listener()
void audio_update_wind(bool force_update)
{
#ifdef kAUDIO_ENABLE_WIND
- //
- // Extract height above water to modulate filter by whether above/below water
- //
+
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
- static F32 last_camera_water_height = -1000.f;
- LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent();
- F32 camera_water_height = camera_pos.mV[VZ] - region->getWaterHeight();
-
- //
- // Don't update rolloff factor unless water surface has been crossed
- //
- if (force_update || (last_camera_water_height * camera_water_height) < 0.f)
- {
- static LLUICachedControl<F32> rolloff("AudioLevelRolloff", 1.0f);
- if (camera_water_height < 0.f)
- {
- gAudiop->setRolloffFactor(rolloff * LL_ROLLOFF_MULTIPLIER_UNDER_WATER);
- }
- else
- {
- gAudiop->setRolloffFactor(rolloff);
- }
- }
-
- // 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();
-
+ // 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 );
@@ -536,8 +531,7 @@ void audio_update_wind(bool force_update)
gAudiop->mMaxWindGain = llmax(gAudiop->mMaxWindGain - volume_delta, 0.f);
}
- last_camera_water_height = camera_water_height;
- gAudiop->updateWind(gRelativeWindVec, camera_water_height);
+ gAudiop->updateWind(gRelativeWindVec, gAgentCamera.getCameraPositionAgent()[VZ] - gAgent.getRegion()->getWaterHeight());
}
#endif
}
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 051f5f4485..a62f73deef 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -655,6 +655,7 @@ void settings_setup_listeners()
gSavedSettings.getControl("AudioLevelVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
+ gSavedSettings.getControl("AudioLevelUnderwaterRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index ea75d4f4f6..cdd227e9fe 100644
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -367,6 +367,14 @@ class WindowsManifest(ViewerManifest):
print err.message
print "Skipping COLLADA and GLOD libraries (assumming linked statically)"
+ # Get fmodex dll, continue if missing
+ try:
+ if self.args['configuration'].lower() == 'debug':
+ self.path("fmodexL.dll")
+ else:
+ self.path("fmodex.dll")
+ except:
+ print "Skipping fmodex audio library(assuming other audio engine)"
# Get fmod dll, continue if missing
if not self.path("fmod.dll"):
@@ -743,6 +751,7 @@ class DarwinManifest(ViewerManifest):
"libcollada14dom.dylib",
"libexpat.1.5.2.dylib",
"libexception_handler.dylib",
+ "libfmodex.dylib",
"libGLOD.dylib",
):
dylibs += path_optional(os.path.join(libdir, libfile), libfile)
@@ -1125,6 +1134,15 @@ class Linux_i686Manifest(LinuxManifest):
except:
print "Skipping libfmod-3.75.so - not found"
pass
+
+ try:
+ self.path("libfmodex-*.so")
+ self.path("libfmodex.so")
+ pass
+ except:
+ print "Skipping libfmodex.so - not found"
+ pass
+
self.end_prefix("lib")
# Vivox runtimes