diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/cmake/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/cmake/Copy3rdPartyLibs.cmake | 15 | ||||
| -rw-r--r-- | indra/cmake/FMOD.cmake | 2 | ||||
| -rw-r--r-- | indra/cmake/FMODEX.cmake | 45 | ||||
| -rw-r--r-- | indra/cmake/FindFMODEX.cmake | 66 | ||||
| -rw-r--r-- | indra/llaudio/CMakeLists.txt | 26 | ||||
| -rw-r--r-- | indra/llaudio/llaudioengine.h | 1 | ||||
| -rw-r--r-- | indra/llaudio/llaudioengine_fmodex.cpp | 746 | ||||
| -rw-r--r-- | indra/llaudio/llaudioengine_fmodex.h | 129 | ||||
| -rw-r--r-- | indra/llaudio/lllistener_fmodex.cpp | 135 | ||||
| -rw-r--r-- | indra/llaudio/lllistener_fmodex.h | 65 | ||||
| -rw-r--r-- | indra/llaudio/llstreamingaudio.h | 2 | ||||
| -rw-r--r-- | indra/llaudio/llstreamingaudio_fmodex.cpp | 382 | ||||
| -rw-r--r-- | indra/llaudio/llstreamingaudio_fmodex.h | 75 | ||||
| -rw-r--r-- | indra/llaudio/llwindgen.h | 34 | ||||
| -rw-r--r-- | indra/newview/CMakeLists.txt | 57 | ||||
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 44 | ||||
| -rwxr-xr-x | indra/newview/linux_tools/wrapper.sh | 12 | ||||
| -rw-r--r-- | indra/newview/llstartup.cpp | 15 | ||||
| -rw-r--r-- | indra/newview/llvieweraudio.cpp | 70 | ||||
| -rw-r--r-- | indra/newview/llviewercontrol.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/viewer_manifest.py | 18 | 
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(¤t_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 | 
