Add support for FMOD Studio, originally by Drake Arconis (Alchemy Viewer), with FS-specific additions by Drakeo
parent
eba0a1133f
commit
5e1c9a92a8
|
|
@ -586,6 +586,66 @@
|
|||
<key>version</key>
|
||||
<string>2.0.1.297014</string>
|
||||
</map>
|
||||
<key>fmodstudio</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>FMOD Studio, copyright (c) Firelight Technologies Pty, Ltd., 2012-2017.</string>
|
||||
<key>description</key>
|
||||
<string>FMOD Studio audio system library</string>
|
||||
<key>license</key>
|
||||
<string>fmodstudio</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/fmodstudio.txt</string>
|
||||
<key>name</key>
|
||||
<string>fmodstudio</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6324120be383af3564f2b46b07f1b765</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>file:///opt/firestorm/fmodstudio-1.10.02-darwin-.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin</string>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>1331456a3df95294eaf44fab990f62cd</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>file:///opt/firestorm/fmodstudio-1.10.02-linux-.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>206f34d4a262a09323bc9d03cd81a2f6</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>file:///c:/cygwin/opt/firestorm/fmodstudio-1.10.02-windows-173500059.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.10.00</string>
|
||||
</map>
|
||||
<key>fmodex</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
@ -3488,7 +3548,7 @@
|
|||
<map>
|
||||
<key>options</key>
|
||||
<array>
|
||||
<string>--fmodex</string>
|
||||
<string>--fmodstudio</string>
|
||||
<string>--kdu</string>
|
||||
<string>--version</string>
|
||||
<string>--btype RelWithDebInfo</string>
|
||||
|
|
@ -3562,7 +3622,7 @@
|
|||
<map>
|
||||
<key>options</key>
|
||||
<array>
|
||||
<string>--fmodex</string>
|
||||
<string>--fmodstudio</string>
|
||||
<string>--kdu</string>
|
||||
<string>--version</string>
|
||||
<string>--platform win32</string>
|
||||
|
|
@ -3598,7 +3658,7 @@
|
|||
<map>
|
||||
<key>options</key>
|
||||
<array>
|
||||
<string>--fmodex</string>
|
||||
<string>--fmodstudio</string>
|
||||
<string>--kdu</string>
|
||||
<string>--version</string>
|
||||
<string>--platform win32</string>
|
||||
|
|
@ -3634,7 +3694,7 @@
|
|||
<map>
|
||||
<key>options</key>
|
||||
<array>
|
||||
<string>--fmodex</string>
|
||||
<string>--fmodstudio</string>
|
||||
<string>--kdu</string>
|
||||
<string>--version</string>
|
||||
<string>--platform win32</string>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ set(cmake_SOURCE_FILES
|
|||
FindAPR.cmake
|
||||
FindAutobuild.cmake
|
||||
FindBerkeleyDB.cmake
|
||||
FindFMODSTUDIO.cmake
|
||||
FindFMODEX.cmake
|
||||
FindGLH.cmake
|
||||
FindGoogleBreakpad.cmake
|
||||
|
|
@ -38,6 +39,7 @@ set(cmake_SOURCE_FILES
|
|||
FindURIPARSER.cmake
|
||||
FindXmlRpcEpi.cmake
|
||||
FindZLIB.cmake
|
||||
FMODSTUDIO.cmake
|
||||
FMODEX.cmake
|
||||
FreeType.cmake
|
||||
GLEXT.cmake
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ if(WINDOWS)
|
|||
if( NOT ND_USE_OPENJPEG2 )
|
||||
set(debug_files ${debug_files} openjpegd.dll )
|
||||
set(release_files ${release_files} openjpeg.dll )
|
||||
else()
|
||||
else()
|
||||
set(debug_files ${debug_files} openjp2.dll )
|
||||
set(release_files ${release_files} openjp2.dll )
|
||||
endif( NOT ND_USE_OPENJPEG2 )
|
||||
|
|
@ -70,6 +70,16 @@ if(WINDOWS)
|
|||
set(release_files ${release_files} libtcmalloc_minimal.dll)
|
||||
endif(USE_TCMALLOC)
|
||||
|
||||
if (FMODSTUDIO)
|
||||
if( NOT ND_BUILD64BIT_ARCH )
|
||||
set(debug_files ${debug_files} fmodL.dll)
|
||||
set(release_files ${release_files} fmod.dll)
|
||||
else( NOT ND_BUILD64BIT_ARCH )
|
||||
set(debug_files ${debug_files} fmodL64.dll)
|
||||
set(release_files ${release_files} fmod64.dll)
|
||||
endif( NOT ND_BUILD64BIT_ARCH )
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
if (FMODEX)
|
||||
if( NOT ND_BUILD64BIT_ARCH )
|
||||
set(debug_files ${debug_files} fmodexL.dll)
|
||||
|
|
@ -185,10 +195,15 @@ elseif(DARWIN)
|
|||
libGLOD.dylib
|
||||
libhunspell-1.3.0.dylib
|
||||
libndofdev.dylib
|
||||
libgrowl.dylib
|
||||
libgrowl.dylib
|
||||
libgrowl++.dylib
|
||||
)
|
||||
|
||||
if (FMODSTUDIO)
|
||||
set(debug_files ${debug_files} libfmodL.dylib)
|
||||
set(release_files ${release_files} libfmod.dylib)
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
if (FMODEX)
|
||||
set(debug_files ${debug_files} libfmodexL.dylib)
|
||||
set(release_files ${release_files} libfmodex.dylib)
|
||||
|
|
@ -247,7 +262,7 @@ elseif(LINUX)
|
|||
libdb-5.1.so
|
||||
libfreetype.so.6.6.2
|
||||
libfreetype.so.6
|
||||
)
|
||||
)
|
||||
endif( NOT ND_BUILD64BIT_ARCH )
|
||||
if( NOT ND_USE_OPENJPEG2 )
|
||||
set(release_files ${release_files} libopenjpeg.so )
|
||||
|
|
@ -258,6 +273,16 @@ elseif(LINUX)
|
|||
set(release_files ${release_files} "libtcmalloc_minimal.so")
|
||||
endif (USE_TCMALLOC)
|
||||
|
||||
if (FMODSTUDIO)
|
||||
if( NOT ND_BUILD64BIT_ARCH )
|
||||
set(debug_files ${debug_files} "libfmodL.so")
|
||||
set(release_files ${release_files} "libfmod.so")
|
||||
else( NOT ND_BUILD64BIT_ARCH )
|
||||
set(debug_files ${debug_files} "libfmodL64.so")
|
||||
set(release_files ${release_files} "libfmod64.so")
|
||||
endif( NOT ND_BUILD64BIT_ARCH )
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
#if (FMODEX)
|
||||
# set(debug_files ${debug_files} "libfmodexL.so")
|
||||
# set(release_files ${release_files} "libfmodex.so")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
# -*- 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 FMODSTUDIO.
|
||||
# Open source devs should use the -DFMODSTUDIO:BOOL=ON then if they want to build with FMOD, whether
|
||||
# they are using USESYSTEMLIBS or not.
|
||||
if (INSTALL_PROPRIETARY)
|
||||
set(FMODSTUDIO ON CACHE BOOL "Using FMOD Studio sound library.")
|
||||
endif (INSTALL_PROPRIETARY)
|
||||
|
||||
|
||||
if (FMODSTUDIO)
|
||||
if (USESYSTEMLIBS)
|
||||
# In that case, we use the version of the library installed on the system
|
||||
set(FMODSTUDIO_FIND_REQUIRED ON)
|
||||
include(FindFMODSTUDIO)
|
||||
else (USESYSTEMLIBS)
|
||||
if (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
|
||||
# If the path have been specified in the arguments, use that
|
||||
set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY})
|
||||
MESSAGE(STATUS "Using FMODSTUDIO path: ${FMODSTUDIO_LIBRARIES}, ${FMODSTUDIO_INCLUDE_DIR}")
|
||||
else (FMODSTUDIO_LIBRARY AND FMODSTUDIO_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(fmodstudio)
|
||||
if (WINDOWS)
|
||||
if (NOT ND_BUILD64BIT_ARCH)
|
||||
set(FMODSTUDIO_LIBRARY
|
||||
debug fmodL_vc
|
||||
optimized fmod_vc)
|
||||
elseif (ND_BUILD64BIT_ARCH)
|
||||
set(FMODSTUDIO_LIBRARY
|
||||
debug fmodL64_vc
|
||||
optimized fmod64_vc)
|
||||
endif(NOT ND_BUILD64BIT_ARCH)
|
||||
elseif (DARWIN)
|
||||
set(FMODSTUDIO_LIBRARY
|
||||
debug fmodL
|
||||
optimized fmod)
|
||||
elseif (LINUX)
|
||||
set(FMODSTUDIO_LIBRARY
|
||||
debug fmodL
|
||||
optimized fmod)
|
||||
endif (WINDOWS)
|
||||
set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY})
|
||||
set(FMODSTUDIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodstudio)
|
||||
endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
|
||||
endif (USESYSTEMLIBS)
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
# - Find FMODSTUDIO
|
||||
# Find the FMODSTUDIO includes and library
|
||||
# This module defines
|
||||
# FMODSTUDIO_INCLUDE_DIR, where to find fmod.h and fmod_errors.h
|
||||
# FMODSTUDIO_LIBRARIES, the libraries needed to use FMODSTUDIO.
|
||||
# FMODSTUDIO, If false, do not try to use FMODSTUDIO.
|
||||
# also defined, but not for general use are
|
||||
# FMODSTUDIO_LIBRARY, where to find the FMODSTUDIO library.
|
||||
|
||||
FIND_PATH(FMODSTUDIO_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod)
|
||||
|
||||
SET(FMODSTUDIO_NAMES ${FMODSTUDIO_NAMES} fmod fmod_vc)
|
||||
FIND_LIBRARY(FMODSTUDIO_LIBRARY
|
||||
NAMES ${FMODSTUDIO_NAMES}
|
||||
PATH_SUFFIXES fmod
|
||||
)
|
||||
|
||||
IF (FMODSTUDIO_SDK_DIR OR WINDOWS)
|
||||
if(WINDOWS)
|
||||
set(FMODSTUDIO_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODSTUDIO")
|
||||
STRING(REGEX REPLACE "\\\\" "/" FMODSTUDIO_SDK_DIR ${FMODSTUDIO_SDK_DIR})
|
||||
endif(WINDOWS)
|
||||
find_library(FMODSTUDIO_LIBRARY
|
||||
fmod_vc fmodL_vc
|
||||
PATHS
|
||||
${FMODSTUDIO_SDK_DIR}/api/lib
|
||||
${FMODSTUDIO_SDK_DIR}/api
|
||||
${FMODSTUDIO_SDK_DIR}
|
||||
)
|
||||
find_path(FMODSTUDIO_INCLUDE_DIR fmod.h
|
||||
${FMODSTUDIO_SDK_DIR}/api/inc
|
||||
${FMODSTUDIO_SDK_DIR}/api
|
||||
${FMODSTUDIO_SDK_DIR}
|
||||
)
|
||||
find_path(FMODSTUDIO_INCLUDE_DIR fmod.h
|
||||
${FMODSTUDIO_SDK_DIR}/api/inc
|
||||
${FMODSTUDIO_SDK_DIR}/api
|
||||
${FMODSTUDIO_SDK_DIR}
|
||||
)
|
||||
IF (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
|
||||
SET(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY})
|
||||
SET(FMODSTUDIO_FOUND "YES")
|
||||
endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
|
||||
ENDIF (FMODSTUDIO_SDK_DIR OR WINDOWS)
|
||||
|
||||
IF (FMODSTUDIO_FOUND)
|
||||
IF (NOT FMODSTUDIO_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found FMODSTUDIO: ${FMODSTUDIO_LIBRARIES}")
|
||||
ENDIF (NOT FMODSTUDIO_FIND_QUIETLY)
|
||||
ELSE (FMODSTUDIO_FOUND)
|
||||
IF (FMODSTUDIO_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find FMODSTUDIO library")
|
||||
ENDIF (FMODSTUDIO_FIND_REQUIRED)
|
||||
ENDIF (FMODSTUDIO_FOUND)
|
||||
|
||||
# Deprecated declarations.
|
||||
SET (NATIVE_FMODSTUDIO_INCLUDE_PATH ${FMODSTUDIO_INCLUDE_DIR} )
|
||||
GET_FILENAME_COMPONENT (NATIVE_FMODSTUDIO_LIB_PATH ${FMODSTUDIO_LIBRARY} PATH)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
FMODSTUDIO_LIBRARY
|
||||
FMODSTUDIO_INCLUDE_DIR
|
||||
)
|
||||
|
|
@ -4,6 +4,7 @@ project(llaudio)
|
|||
|
||||
include(00-Common)
|
||||
include(LLAudio)
|
||||
include(FMODSTUDIO)
|
||||
include(FMODEX)
|
||||
include(OPENAL)
|
||||
include(LLCommon)
|
||||
|
|
@ -42,6 +43,23 @@ set(llaudio_HEADER_FILES
|
|||
llwindgen.h
|
||||
)
|
||||
|
||||
if (FMODSTUDIO)
|
||||
include_directories(
|
||||
${FMODSTUDIO_INCLUDE_DIR}
|
||||
)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmodstudio.cpp
|
||||
lllistener_fmodstudio.cpp
|
||||
llstreamingaudio_fmodstudio.cpp
|
||||
)
|
||||
|
||||
list(APPEND llaudio_HEADER_FILES
|
||||
llaudioengine_fmodstudio.h
|
||||
lllistener_fmodstudio.h
|
||||
llstreamingaudio_fmodstudio.h
|
||||
)
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
if (FMODEX)
|
||||
include_directories(
|
||||
${FMODEX_INCLUDE_DIR}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,749 @@
|
|||
/**
|
||||
* @file audioengine_fmodstudio.cpp
|
||||
* @brief Implementation of LLAudioEngine class abstracting the audio
|
||||
* support as a FMOD Studio implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, 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_fmodstudio.h"
|
||||
|
||||
#include "llaudioengine_fmodstudio.h"
|
||||
#include "lllistener_fmodstudio.h"
|
||||
|
||||
#include "llerror.h"
|
||||
#include "llmath.h"
|
||||
#include "llrand.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_errors.h"
|
||||
#include "lldir.h"
|
||||
|
||||
#include "sound_ids.h"
|
||||
|
||||
#include "indra_constants.h"
|
||||
|
||||
const U32 EXTRA_SOUND_CHANNELS = 10;
|
||||
|
||||
FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
|
||||
|
||||
FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
|
||||
|
||||
LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method)
|
||||
: mInited(false)
|
||||
, mWindGen(NULL)
|
||||
, mWindDSPDesc(NULL)
|
||||
, mWindDSP(NULL)
|
||||
, mSystem(NULL)
|
||||
, mEnableProfiler(enable_profiler)
|
||||
, mResampleMethod(resample_method)
|
||||
{
|
||||
}
|
||||
|
||||
LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO()
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||
{
|
||||
if(result == FMOD_OK)
|
||||
return false;
|
||||
|
||||
if (result != FMOD_ERR_INVALID_HANDLE)
|
||||
{
|
||||
LL_WARNS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata)
|
||||
{
|
||||
U32 version;
|
||||
FMOD_RESULT result;
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL;
|
||||
|
||||
result = FMOD::System_Create(&mSystem);
|
||||
if(Check_FMOD_Error(result, "FMOD::System_Create"))
|
||||
return false;
|
||||
|
||||
//will call LLAudioEngine_FMODSTUDIO::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 Studio version (" << version
|
||||
<< ")! You should be using FMOD Studio" << FMOD_VERSION << LL_ENDL;
|
||||
}
|
||||
|
||||
// In this case, all sounds, PLUS wind and stream will be software.
|
||||
result = mSystem->setSoftwareChannels(num_channels + EXTRA_SOUND_CHANNELS);
|
||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
|
||||
|
||||
FMOD_ADVANCEDSETTINGS adv_settings = { };
|
||||
adv_settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS);
|
||||
switch (mResampleMethod)
|
||||
{
|
||||
default:
|
||||
case RESAMPLE_LINEAR:
|
||||
adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR;
|
||||
break;
|
||||
case RESAMPLE_CUBIC:
|
||||
adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_CUBIC;
|
||||
break;
|
||||
case RESAMPLE_SPLINE:
|
||||
adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_SPLINE;
|
||||
break;
|
||||
}
|
||||
|
||||
// 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 | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE;
|
||||
if(mEnableProfiler)
|
||||
{
|
||||
fmod_flags |= FMOD_INIT_PROFILE_ENABLE;
|
||||
}
|
||||
|
||||
#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((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, const_cast<char*>(APP_NAME.c_str()))) == 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((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, 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)
|
||||
{
|
||||
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;
|
||||
if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput"))
|
||||
{
|
||||
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;
|
||||
default:
|
||||
LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
|
||||
};
|
||||
}
|
||||
#else // LL_LINUX
|
||||
|
||||
// initialize the FMOD engine
|
||||
result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, 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->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0);
|
||||
Check_FMOD_Error(result,"Error falling back to stereo mode");
|
||||
/*
|
||||
... and re-init.
|
||||
*/
|
||||
result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0);
|
||||
}
|
||||
if(Check_FMOD_Error(result, "Error initializing FMOD Studio"))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (mEnableProfiler)
|
||||
{
|
||||
Check_FMOD_Error(mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]), "FMOD::System::createChannelGroup");
|
||||
Check_FMOD_Error(mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]), "FMOD::System::createChannelGroup");
|
||||
Check_FMOD_Error(mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]), "FMOD::System::createChannelGroup");
|
||||
Check_FMOD_Error(mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]), "FMOD::System::createChannelGroup");
|
||||
}
|
||||
|
||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||
setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem));
|
||||
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL;
|
||||
|
||||
int r_numbuffers, r_samplerate, r_channels;
|
||||
unsigned int r_bufferlength;
|
||||
mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers);
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL;
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_numbuffers=" << r_numbuffers << LL_ENDL;
|
||||
|
||||
char r_name[512];
|
||||
mSystem->getDriverInfo(0, r_name, 511, NULL, &r_samplerate, NULL, &r_channels);
|
||||
r_name[511] = '\0';
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_name=\"" << r_name << "\"" << LL_ENDL;
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL;
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_channels=" << r_channels << LL_ENDL;
|
||||
|
||||
int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks.
|
||||
if ( r_samplerate != 0 )
|
||||
latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate);
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): latency=" << latency << "ms" << LL_ENDL;
|
||||
|
||||
mInited = true;
|
||||
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
|
||||
{
|
||||
llassert_always(mSystem);
|
||||
if (verbose)
|
||||
{
|
||||
U32 version;
|
||||
if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion"))
|
||||
{
|
||||
return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
|
||||
}
|
||||
}
|
||||
return "FMOD Studio";
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODSTUDIO::allocateListener(void)
|
||||
{
|
||||
try
|
||||
{
|
||||
mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem);
|
||||
}
|
||||
catch (const std::bad_alloc& e)
|
||||
{
|
||||
LL_WARNS() << "Listener allocation failed due to: " << e.what() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODSTUDIO::shutdown()
|
||||
{
|
||||
LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL;
|
||||
LLAudioEngine::shutdown();
|
||||
|
||||
LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL;
|
||||
if ( mSystem ) // speculative fix for MAINT-2657
|
||||
{
|
||||
Check_FMOD_Error(mSystem->close(), "FMOD::System::close");
|
||||
Check_FMOD_Error(mSystem->release(), "FMOD::System::release");
|
||||
}
|
||||
LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL;
|
||||
|
||||
delete mListenerp;
|
||||
mListenerp = NULL;
|
||||
}
|
||||
|
||||
|
||||
LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer()
|
||||
{
|
||||
return new LLAudioBufferFMODSTUDIO(mSystem);
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel()
|
||||
{
|
||||
return new LLAudioChannelFMODSTUDIO(mSystem);
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODSTUDIO::initWind()
|
||||
{
|
||||
mNextWindUpdate = 0.0;
|
||||
|
||||
cleanupWind();
|
||||
|
||||
mWindDSPDesc = new FMOD_DSP_DESCRIPTION();
|
||||
memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero
|
||||
mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
|
||||
strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); //Set name to "Wind Unit"
|
||||
mWindDSPDesc->numoutputbuffers = 1;
|
||||
mWindDSPDesc->read = &windDSPCallback; //Assign callback.
|
||||
if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP)
|
||||
return false;
|
||||
|
||||
int frequency = 44100;
|
||||
FMOD_SPEAKERMODE mode;
|
||||
if (!Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat"))
|
||||
{
|
||||
mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
|
||||
|
||||
if (!Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData") &&
|
||||
!Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat") &&
|
||||
!Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP"))
|
||||
return true; //Success
|
||||
}
|
||||
|
||||
cleanupWind();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODSTUDIO::cleanupWind()
|
||||
{
|
||||
if (mWindDSP)
|
||||
{
|
||||
FMOD::ChannelGroup* mastergroup = NULL;
|
||||
if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&mastergroup), "FMOD::System::getMasterChannelGroup") && mastergroup)
|
||||
Check_FMOD_Error(mastergroup->removeDSP(mWindDSP), "FMOD::ChannelGroup::removeDSP");
|
||||
Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release");
|
||||
mWindDSP = NULL;
|
||||
}
|
||||
|
||||
delete mWindDSPDesc;
|
||||
mWindDSPDesc = NULL;
|
||||
|
||||
delete mWindGen;
|
||||
mWindGen = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODSTUDIO::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_FMODSTUDIO::setInternalGain(F32 gain)
|
||||
{
|
||||
if (!mInited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gain = llclamp( gain, 0.0f, 1.0f );
|
||||
|
||||
FMOD::ChannelGroup *master_group;
|
||||
if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup"))
|
||||
return;
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODSTUDIO implementation
|
||||
//
|
||||
|
||||
LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool LLAudioChannelFMODSTUDIO::updateBuffer()
|
||||
{
|
||||
if (mCurrentSourcep)
|
||||
{
|
||||
if (LLAudioChannel::updateBuffer())
|
||||
{
|
||||
// Base class update returned true, which means that we need to actually
|
||||
// set up the channel for a different buffer.
|
||||
|
||||
LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *) 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.
|
||||
LL_ERRS() << "No FMOD sound!" << LL_ENDL;
|
||||
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(soundp, nullptr, true, &mChannelp);
|
||||
Check_FMOD_Error(result, "FMOD::System::playSound");
|
||||
}
|
||||
|
||||
//LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL;
|
||||
}
|
||||
|
||||
//FMOD_RESULT result;
|
||||
|
||||
mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
|
||||
//Check_FMOD_Error(result, "FMOD::Channel::setVolume");
|
||||
|
||||
mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
|
||||
/*if(Check_FMOD_Error(result, "FMOD::Channel::setMode"))
|
||||
{
|
||||
S32 index;
|
||||
mChannelp->getIndex(&index);
|
||||
LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
|
||||
<< " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL;
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS() << "No source buffer!" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::update3DPosition()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// We're not actually a live channel (i.e., we're not playing back anything)
|
||||
return;
|
||||
}
|
||||
|
||||
LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)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 LLAudioChannelFMODSTUDIO::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;
|
||||
Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition");
|
||||
|
||||
if (cur_pos < (U32)mLastSamplePos)
|
||||
{
|
||||
mLoopedThisFrame = true;
|
||||
}
|
||||
mLastSamplePos = cur_pos;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::cleanup()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
//LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
//LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL;
|
||||
Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
mChannelp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::play()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused");
|
||||
|
||||
getSource()->setPlayedOnce(true);
|
||||
|
||||
if(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()])
|
||||
Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup");
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::playSynced(LLAudioChannel *channelp)
|
||||
{
|
||||
LLAudioChannelFMODSTUDIO *fmod_channelp = (LLAudioChannelFMODSTUDIO*)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 LLAudioChannelFMODSTUDIO::isPlaying()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool paused, playing;
|
||||
Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused");
|
||||
Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying");
|
||||
return !paused && playing;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODSTUDIO implementation
|
||||
//
|
||||
|
||||
|
||||
LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystemp(system), mSoundp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO()
|
||||
{
|
||||
if(mSoundp)
|
||||
{
|
||||
Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release");
|
||||
mSoundp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioBufferFMODSTUDIO::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 (!gDirUtilp->fileExists(filename))
|
||||
{
|
||||
// File not found, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSoundp)
|
||||
{
|
||||
// If there's already something loaded in this buffer, clean it up.
|
||||
Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release");
|
||||
mSoundp = NULL;
|
||||
}
|
||||
|
||||
FMOD_MODE base_mode = FMOD_LOOP_NORMAL;
|
||||
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
|
||||
FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
// We failed to load the file for some reason.
|
||||
LL_WARNS() << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
|
||||
//
|
||||
// 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 LLAudioBufferFMODSTUDIO::getLength()
|
||||
{
|
||||
if (!mSoundp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 length;
|
||||
Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength");
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d)
|
||||
{
|
||||
FMOD_MODE current_mode;
|
||||
if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode"))
|
||||
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)
|
||||
{
|
||||
Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode");
|
||||
}
|
||||
}
|
||||
|
||||
// *NOTE: This is almost certainly being called on the mixer thread,
|
||||
// not the main thread. May have implications for callees or audio
|
||||
// engine shutdown.
|
||||
|
||||
FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels)
|
||||
{
|
||||
// inbuffer = incomming data.
|
||||
// newbuffer = outgoing data. AKA this DSP's output.
|
||||
// length = length in samples at this mix time. True buffer size, in bytes, would be (length * sizeof(float) * inchannels).
|
||||
// userdata = user-provided data attached this DSP via FMOD::DSP::setUserData.
|
||||
|
||||
LLWindGen<LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT> *windgen;
|
||||
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
|
||||
|
||||
thisdsp->getUserData((void **)&windgen);
|
||||
|
||||
if (windgen)
|
||||
windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* @file audioengine_fmodstudio.h
|
||||
* @brief Definition of LLAudioEngine class abstracting the audio
|
||||
* support as a FMOD Studio implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, 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_FMODSTUDIO_H
|
||||
#define LL_AUDIOENGINE_FMODSTUDIO_H
|
||||
|
||||
#include "llaudioengine.h"
|
||||
#include "llwindgen.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODSTUDIO;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
class ChannelGroup;
|
||||
class Sound;
|
||||
class DSP;
|
||||
}
|
||||
typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION;
|
||||
|
||||
//Interfaces
|
||||
class LLAudioEngine_FMODSTUDIO : public LLAudioEngine
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
RESAMPLE_LINEAR=0,
|
||||
RESAMPLE_CUBIC,
|
||||
RESAMPLE_SPLINE
|
||||
};
|
||||
LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method);
|
||||
virtual ~LLAudioEngine_FMODSTUDIO();
|
||||
|
||||
// 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_DESCRIPTION *mWindDSPDesc;
|
||||
FMOD::DSP *mWindDSP;
|
||||
FMOD::System *mSystem;
|
||||
bool mEnableProfiler;
|
||||
U32 mResampleMethod;
|
||||
|
||||
public:
|
||||
static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
|
||||
};
|
||||
|
||||
|
||||
class LLAudioChannelFMODSTUDIO : public LLAudioChannel
|
||||
{
|
||||
public:
|
||||
LLAudioChannelFMODSTUDIO(FMOD::System *audioengine);
|
||||
virtual ~LLAudioChannelFMODSTUDIO();
|
||||
|
||||
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 LLAudioBufferFMODSTUDIO : public LLAudioBuffer
|
||||
{
|
||||
public:
|
||||
LLAudioBufferFMODSTUDIO(FMOD::System *audioengine);
|
||||
virtual ~LLAudioBufferFMODSTUDIO();
|
||||
|
||||
/*virtual*/ bool loadWAV(const std::string& filename);
|
||||
/*virtual*/ U32 getLength();
|
||||
friend class LLAudioChannelFMODSTUDIO;
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Sound *getSound() const{ return mSoundp; }
|
||||
FMOD::Sound *mSoundp;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_AUDIOENGINE_FMODSTUDIO_H
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
* @file listener_fmodstudio.cpp
|
||||
* @brief Implementation of LISTENER class abstracting the audio
|
||||
* support as a FMOD Studio 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 "llaudioengine.h"
|
||||
#include "lllistener_fmodstudio.h"
|
||||
#include "fmod.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// constructor
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system)
|
||||
: LLListener(),
|
||||
mDopplerFactor(1.0f),
|
||||
mRolloffFactor(1.0f)
|
||||
{
|
||||
mSystem = system;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::translate(LLVector3 offset)
|
||||
{
|
||||
LLListener::translate(offset);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::setPosition(LLVector3 pos)
|
||||
{
|
||||
LLListener::setPosition(pos);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel)
|
||||
{
|
||||
LLListener::setVelocity(vel);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at)
|
||||
{
|
||||
LLListener::orient(up, at);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::commitDeferredChanges()
|
||||
{
|
||||
if(!mSystem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mSystem->update();
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor)
|
||||
{
|
||||
//An internal FMOD Studio 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 fmod studio, which makes it not skip 3D processing next update call.
|
||||
if(mRolloffFactor != factor)
|
||||
{
|
||||
LLVector3 tmp_pos = mPosition - LLVector3(0.f,0.f,.1f);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) tmp_pos.mV, NULL, NULL, NULL);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) mPosition.mV, NULL, NULL, NULL);
|
||||
}
|
||||
mRolloffFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODSTUDIO::getRolloffFactor()
|
||||
{
|
||||
return mRolloffFactor;
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor)
|
||||
{
|
||||
mDopplerFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODSTUDIO::getDopplerFactor()
|
||||
{
|
||||
return mDopplerFactor;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* @file listener_fmodstudio.h
|
||||
* @brief Description of LISTENER class abstracting the audio support
|
||||
* as an FMOD Studio 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_FMODSTUDIO_H
|
||||
#define LL_LISTENER_FMODSTUDIO_H
|
||||
|
||||
#include "lllistener.h"
|
||||
|
||||
//Stubs
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLListener_FMODSTUDIO : public LLListener
|
||||
{
|
||||
public:
|
||||
LLListener_FMODSTUDIO(FMOD::System *system);
|
||||
virtual ~LLListener_FMODSTUDIO();
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,526 @@
|
|||
/**
|
||||
* @file streamingaudio_fmodstudio.cpp
|
||||
* @brief LLStreamingAudio_FMODSTUDIO 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_fmodstudio.h"
|
||||
|
||||
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||
{
|
||||
if (result == FMOD_OK)
|
||||
return false;
|
||||
LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
return true;
|
||||
}
|
||||
|
||||
class LLAudioStreamManagerFMODSTUDIO
|
||||
{
|
||||
public:
|
||||
LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, 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_RESULT getOpenState(FMOD_OPENSTATE& openstate, unsigned int* percentbuffered = NULL, bool* starving = NULL, bool* diskbusy = NULL);
|
||||
protected:
|
||||
FMOD::System* mSystem;
|
||||
FMOD::ChannelGroup* mChannelGroup;
|
||||
FMOD::Channel* mStreamChannel;
|
||||
FMOD::Sound* mInternetStream;
|
||||
bool mReady;
|
||||
|
||||
std::string mInternetStreamURL;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Internet Streaming
|
||||
//---------------------------------------------------------------------------
|
||||
LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
|
||||
mSystem(system),
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mStreamGroup(NULL),
|
||||
mFMODInternetStreamChannelp(NULL),
|
||||
mGain(1.0f)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
// 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
|
||||
result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
|
||||
Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize");
|
||||
|
||||
Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup");
|
||||
}
|
||||
|
||||
LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO()
|
||||
{
|
||||
stop();
|
||||
for (U32 i = 0; i < 100; ++i)
|
||||
{
|
||||
if (releaseDeadStreams())
|
||||
break;
|
||||
ms_sleep(10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::start(const std::string& url)
|
||||
{
|
||||
//if (!mInited)
|
||||
//{
|
||||
// LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
|
||||
stop();
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
if(mDeadStreams.empty())
|
||||
{
|
||||
LL_INFOS() << "Starting internet stream: " << url << LL_ENDL;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url);
|
||||
mURL = url;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL;
|
||||
mPendingURL = url;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "Set internet stream to null" << LL_ENDL;
|
||||
mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::update()
|
||||
{
|
||||
if (!releaseDeadStreams())
|
||||
{
|
||||
llassert_always(mCurrentInternetStreamp == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mPendingURL.empty())
|
||||
{
|
||||
llassert_always(mCurrentInternetStreamp == NULL);
|
||||
LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, mPendingURL);
|
||||
mURL = mPendingURL;
|
||||
mPendingURL.clear();
|
||||
}
|
||||
|
||||
// Don't do anything if there are no streams playing
|
||||
if (!mCurrentInternetStreamp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int progress;
|
||||
bool starving;
|
||||
bool diskbusy;
|
||||
FMOD_OPENSTATE open_state;
|
||||
FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy);
|
||||
|
||||
if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR)
|
||||
{
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
else 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());
|
||||
Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(mFMODInternetStreamChannelp)
|
||||
{
|
||||
FMOD::Sound *sound = NULL;
|
||||
|
||||
// <DKO> FmodEX Error checking
|
||||
//if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
|
||||
if (!Check_FMOD_Error(mFMODInternetStreamChannelp->getCurrentSound(&sound), "FMOD::Channel::getCurrentSound") && sound)
|
||||
// </FS:CR>
|
||||
{
|
||||
FMOD_TAG tag;
|
||||
S32 tagcount, dirtytagcount;
|
||||
|
||||
// <DKO> FmodEX Error checking
|
||||
//if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
|
||||
if (!Check_FMOD_Error(sound->getNumTags(&tagcount, &dirtytagcount), "FMOD::Sound::getNumTags") && dirtytagcount)
|
||||
// </FS:CR>
|
||||
{
|
||||
// <DKO> Stream metadata - originally by Shyotl Khur
|
||||
mMetadata.clear();
|
||||
mNewMetadata = true;
|
||||
// </DKO>
|
||||
for(S32 i = 0; i < tagcount; ++i)
|
||||
{
|
||||
if(sound->getTag(NULL, i, &tag) != FMOD_OK)
|
||||
continue;
|
||||
|
||||
std::string name = tag.name;
|
||||
switch(tag.type)
|
||||
{
|
||||
case(FMOD_TAGTYPE_ID3V2):
|
||||
{
|
||||
if(name == "TIT2") name = "TITLE";
|
||||
else if(name == "TPE1") name = "ARTIST";
|
||||
break;
|
||||
}
|
||||
case(FMOD_TAGTYPE_ASF):
|
||||
{
|
||||
if(name == "Title") name = "TITLE";
|
||||
else if(name == "WM/AlbumArtist") name = "ARTIST";
|
||||
break;
|
||||
}
|
||||
case(FMOD_TAGTYPE_FMOD):
|
||||
{
|
||||
if (!strcmp(tag.name, "Sample Rate Change"))
|
||||
{
|
||||
LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL;
|
||||
mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(tag.datatype)
|
||||
{
|
||||
case(FMOD_TAGDATATYPE_INT):
|
||||
{
|
||||
(mMetadata)[name]=*(LLSD::Integer*)(tag.data);
|
||||
LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(int*)(tag.data) << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case(FMOD_TAGDATATYPE_FLOAT):
|
||||
{
|
||||
(mMetadata)[name]=*(LLSD::Real*)(tag.data);
|
||||
LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(float*)(tag.data) << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case(FMOD_TAGDATATYPE_STRING):
|
||||
{
|
||||
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
||||
(mMetadata)[name]=out;
|
||||
LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
(mMetadata)[std::string(tag.name)]=out;
|
||||
LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
//U16* buf = (U16*)out.c_str();
|
||||
//for(U32 j = 0; j < out.size()/2; ++j)
|
||||
//(((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8));
|
||||
(mMetadata)[std::string(tag.name)]=out;
|
||||
LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(starving)
|
||||
{
|
||||
bool paused = false;
|
||||
if (mFMODInternetStreamChannelp->getPaused(&paused) == FMOD_OK && !paused)
|
||||
{
|
||||
LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL;
|
||||
LL_INFOS() << " (diskbusy="<<diskbusy<<")" << LL_ENDL;
|
||||
LL_INFOS() << " (progress="<<progress<<")" << LL_ENDL;
|
||||
Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused");
|
||||
}
|
||||
}
|
||||
else if(progress > 80)
|
||||
{
|
||||
Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::stop()
|
||||
{
|
||||
mPendingURL.clear();
|
||||
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused");
|
||||
Check_FMOD_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority");
|
||||
mFMODInternetStreamChannelp = NULL;
|
||||
}
|
||||
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
if (mCurrentInternetStreamp->stopStream())
|
||||
{
|
||||
delete mCurrentInternetStreamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
mDeadStreams.push_back(mCurrentInternetStreamp);
|
||||
}
|
||||
mCurrentInternetStreamp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::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_FMODSTUDIO::isPlaying()
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
return 1; // Active and playing
|
||||
}
|
||||
else if (!mURL.empty() || !mPendingURL.empty())
|
||||
{
|
||||
return 2; // "Paused"
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
F32 LLStreamingAudio_FMODSTUDIO::getGain()
|
||||
{
|
||||
return mGain;
|
||||
}
|
||||
|
||||
|
||||
std::string LLStreamingAudio_FMODSTUDIO::getURL()
|
||||
{
|
||||
return mURL;
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol)
|
||||
{
|
||||
mGain = vol;
|
||||
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
|
||||
|
||||
Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume");
|
||||
}
|
||||
}
|
||||
// <DKO> Streamtitle display
|
||||
// virtual
|
||||
bool LLStreamingAudio_FMODSTUDIO::getNewMetadata(LLSD& metadata)
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
if (mNewMetadata)
|
||||
{
|
||||
metadata = mMetadata;
|
||||
mNewMetadata = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return mNewMetadata;
|
||||
}
|
||||
|
||||
metadata = LLSD();
|
||||
return false;
|
||||
}
|
||||
// </DKO>
|
||||
///////////////////////////////////////////////////////
|
||||
// manager of possibly-multiple internet audio streams
|
||||
|
||||
LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) :
|
||||
mSystem(system),
|
||||
mChannelGroup(group),
|
||||
mStreamChannel(NULL),
|
||||
mInternetStream(NULL),
|
||||
mReady(false)
|
||||
{
|
||||
mInternetStreamURL = url;
|
||||
|
||||
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream);
|
||||
|
||||
if (result!= FMOD_OK)
|
||||
{
|
||||
LL_WARNS() << "Couldn't open fmod stream, error "
|
||||
<< FMOD_ErrorString(result)
|
||||
<< LL_ENDL;
|
||||
mReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mReady = true;
|
||||
}
|
||||
|
||||
FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream()
|
||||
{
|
||||
// We need a live and opened stream before we try and play it.
|
||||
FMOD_OPENSTATE open_state;
|
||||
if (getOpenState(open_state) != FMOD_OK || open_state != FMOD_OPENSTATE_READY)
|
||||
{
|
||||
LL_WARNS() << "No internet stream to start playing!" << LL_ENDL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mStreamChannel)
|
||||
return mStreamChannel; //Already have a channel for this stream.
|
||||
|
||||
Check_FMOD_Error(mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel), "FMOD::System::playSound");
|
||||
return mStreamChannel;
|
||||
}
|
||||
|
||||
bool LLAudioStreamManagerFMODSTUDIO::stopStream()
|
||||
{
|
||||
if (mInternetStream)
|
||||
{
|
||||
bool close = true;
|
||||
FMOD_OPENSTATE open_state;
|
||||
if (getOpenState(open_state) == FMOD_OK)
|
||||
{
|
||||
switch (open_state)
|
||||
{
|
||||
case FMOD_OPENSTATE_CONNECTING:
|
||||
close = false;
|
||||
break;
|
||||
default:
|
||||
close = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (close && mInternetStream->release() == FMOD_OK)
|
||||
{
|
||||
mStreamChannel = NULL;
|
||||
mInternetStream = NULL;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_RESULT LLAudioStreamManagerFMODSTUDIO::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy)
|
||||
{
|
||||
if (!mInternetStream)
|
||||
return FMOD_ERR_INVALID_HANDLE;
|
||||
FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
|
||||
Check_FMOD_Error(result, "FMOD::Sound::getOpenState");
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
|
||||
{
|
||||
Check_FMOD_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize");
|
||||
FMOD_ADVANCEDSETTINGS settings;
|
||||
memset(&settings,0,sizeof(settings));
|
||||
settings.cbSize=sizeof(settings);
|
||||
settings.defaultDecodeBufferSize = decodebuffertime;//ms
|
||||
Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings");
|
||||
}
|
||||
|
||||
bool LLStreamingAudio_FMODSTUDIO::releaseDeadStreams()
|
||||
{
|
||||
// Kill dead internet streams, if possible
|
||||
std::list<LLAudioStreamManagerFMODSTUDIO *>::iterator iter;
|
||||
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
|
||||
{
|
||||
LLAudioStreamManagerFMODSTUDIO *streamp = *iter;
|
||||
if (streamp->stopStream())
|
||||
{
|
||||
LL_INFOS() << "Closed dead stream" << LL_ENDL;
|
||||
delete streamp;
|
||||
mDeadStreams.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
return mDeadStreams.empty();
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* @file streamingaudio_fmodstudio.h
|
||||
* @brief Definition of LLStreamingAudio_FMODSTUDIO 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_FMODSTUDIO_H
|
||||
#define LL_STREAMINGAUDIO_FMODSTUDIO_H
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODSTUDIO;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
class ChannelGroup;
|
||||
class DSP;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface
|
||||
{
|
||||
public:
|
||||
LLStreamingAudio_FMODSTUDIO(FMOD::System *system);
|
||||
/*virtual*/ ~LLStreamingAudio_FMODSTUDIO();
|
||||
|
||||
/*virtual*/ void start(const std::string& url);
|
||||
/*virtual*/ void stop();
|
||||
/*virtual*/ void pause(S32 pause);
|
||||
/*virtual*/ void update();
|
||||
/*virtual*/ S32 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);
|
||||
//Streamtitle display DKO
|
||||
virtual bool getNewMetadata(LLSD& metadata);
|
||||
// DKO
|
||||
private:
|
||||
bool releaseDeadStreams();
|
||||
|
||||
FMOD::System *mSystem;
|
||||
|
||||
LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp;
|
||||
FMOD::ChannelGroup* mStreamGroup;
|
||||
FMOD::Channel *mFMODInternetStreamChannelp;
|
||||
std::list<LLAudioStreamManagerFMODSTUDIO *> mDeadStreams;
|
||||
|
||||
std::string mURL;
|
||||
std::string mPendingURL;
|
||||
F32 mGain;
|
||||
// <DKO> Streamtitle display
|
||||
bool mNewMetadata;
|
||||
LLSD mMetadata;
|
||||
// </DKO> Streamtitle display
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H
|
||||
|
|
@ -11,6 +11,7 @@ include(DBusGlib)
|
|||
include(DirectX)
|
||||
include(DragDrop)
|
||||
include(EXPAT)
|
||||
include(FMODSTUDIO)
|
||||
include(FMODEX)
|
||||
include(GLOD)
|
||||
include(GooglePerfTools)
|
||||
|
|
@ -66,6 +67,10 @@ endif (NOT HAVOK_TPV)
|
|||
endif( LLPHYSICSEXTENSIONS_SRC_DIR )
|
||||
# </FS:ND>
|
||||
|
||||
if(FMODSTUDIO)
|
||||
include_directories(${FMODSTUDIO_INCLUDE_DIR})
|
||||
endif(FMODSTUDIO)
|
||||
|
||||
if(FMODEX)
|
||||
include_directories(${FMODEX_INCLUDE_DIR})
|
||||
endif(FMODEX)
|
||||
|
|
@ -2018,6 +2023,11 @@ if (OPENAL)
|
|||
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL")
|
||||
endif (OPENAL)
|
||||
|
||||
if (FMODSTUDIO)
|
||||
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO")
|
||||
set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY})
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
if (FMODEX)
|
||||
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
|
||||
set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY})
|
||||
|
|
@ -2151,6 +2161,14 @@ if (WINDOWS)
|
|||
set( VIEWERMANIFEST_PACKAGE_FLAGS )
|
||||
endif( ND_BUILD64BIT_ARCH )
|
||||
|
||||
if (FMODSTUDIO)
|
||||
list(APPEND COPY_INPUT_DEPENDENCIES
|
||||
${SHARED_LIB_STAGING_DIR}/Release/fmod.dll
|
||||
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll
|
||||
${SHARED_LIB_STAGING_DIR}/Debug/fmodL.dll
|
||||
)
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
if (FMODEX)
|
||||
list(APPEND COPY_INPUT_DEPENDENCIES
|
||||
${SHARED_LIB_STAGING_DIR}/Release/fmodex.dll
|
||||
|
|
|
|||
|
|
@ -19992,6 +19992,17 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>7000</integer>
|
||||
</map>
|
||||
<key>FMODResampleMethod</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sets the method used for internal resampler 0(Linear), 1(Cubic), 2(Spline)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DisablePrecacheDelayAfterTeleporting</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@
|
|||
#include "llviewermedia_streamingaudio.h"
|
||||
#include "llaudioengine.h"
|
||||
|
||||
#ifdef LL_FMODSTUDIO
|
||||
# include "llaudioengine_fmodstudio.h"
|
||||
#endif
|
||||
|
||||
#ifdef LL_FMODEX
|
||||
# include "llaudioengine_fmodex.h"
|
||||
#endif
|
||||
|
|
@ -955,7 +959,16 @@ bool idle_startup()
|
|||
delete gAudiop;
|
||||
gAudiop = NULL;
|
||||
|
||||
#ifdef LL_FMODEX
|
||||
#ifdef LL_FMODSTUDIO
|
||||
#if !LL_WINDOWS
|
||||
if (NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER"))
|
||||
#endif // !LL_WINDOWS
|
||||
{
|
||||
gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODExProfilerEnable"), gSavedSettings.getU32("FMODResampleMethod"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LL_FMODEX
|
||||
#if !LL_WINDOWS
|
||||
if (NULL == getenv("LL_BAD_FMODEX_DRIVER"))
|
||||
#endif // !LL_WINDOWS
|
||||
|
|
@ -977,7 +990,7 @@ bool idle_startup()
|
|||
if (gAudiop)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// FMOD Ex on Windows needs the window handle to stop playing audio
|
||||
// FMOD Studio and FMOD Ex on Windows needs the window handle to stop playing audio
|
||||
// when window is minimized. JC
|
||||
void* window_handle = (HWND)gViewerWindow->getPlatformWindow();
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -433,6 +433,17 @@ class Windows_i686_Manifest(ViewerManifest):
|
|||
print err.message
|
||||
print "Skipping GLOD library (assumming linked statically)"
|
||||
|
||||
# Get fmodstudio dll, continue if missing
|
||||
try:
|
||||
if self.args['configuration'].lower() == 'debug':
|
||||
self.path("fmodL.dll")
|
||||
self.path("fmodL64.dll")
|
||||
else:
|
||||
self.path("fmod.dll")
|
||||
self.path("fmod64.dll")
|
||||
except:
|
||||
print "Skipping fmodstudio audio library(assuming other audio engine)"
|
||||
|
||||
# Get fmodex dll, continue if missing
|
||||
try:
|
||||
if self.args['configuration'].lower() == 'debug':
|
||||
|
|
@ -941,6 +952,18 @@ class DarwinManifest(ViewerManifest):
|
|||
):
|
||||
self.path2basename(relpkgdir, libfile)
|
||||
|
||||
# dylibs that vary based on configuration
|
||||
if self.args['configuration'].lower() == 'debug':
|
||||
for libfile in (
|
||||
"libfmodL.dylib",
|
||||
):
|
||||
dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
|
||||
else:
|
||||
for libfile in (
|
||||
"libfmod.dylib",
|
||||
):
|
||||
dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
|
||||
|
||||
# dylibs that vary based on configuration
|
||||
if self.args['configuration'].lower() == 'debug':
|
||||
for libfile in (
|
||||
|
|
@ -1636,6 +1659,7 @@ class Linux_i686_Manifest(LinuxManifest):
|
|||
try:
|
||||
self.path("libfmodex-*.so")
|
||||
self.path("libfmodex.so")
|
||||
self.path("libfmodex.so*")
|
||||
pass
|
||||
except:
|
||||
print "Skipping libfmodex.so - not found"
|
||||
|
|
@ -1677,6 +1701,9 @@ class Linux_x86_64_Manifest(LinuxManifest):
|
|||
try:
|
||||
self.path("libfmodex64-*.so")
|
||||
self.path("libfmodex64.so")
|
||||
self.path("libfmod64.so")
|
||||
self.path("libfmod.so")
|
||||
self.path("libfmod.so*")
|
||||
pass
|
||||
except:
|
||||
print "Skipping libfmodex.so - not found"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ FALSE=1
|
|||
# <string>-DROOT_PROJECT_NAME:STRING=SecondLife</string>
|
||||
# <string>-DINSTALL_PROPRIETARY=FALSE</string>
|
||||
# <string>-DUSE_KDU=TRUE</string>
|
||||
# <string>-DFMODSTUDIO:BOOL=ON</string>
|
||||
# <string>-DFMODEX:BOOL=ON</string>
|
||||
# <string>-DOPENSIM:BOOL=ON</string>
|
||||
# <string>-DUSE_AVX_OPTIMIZATION:BOOL=OFF</string>
|
||||
|
|
@ -33,6 +34,7 @@ WANTS_CONFIG=$FALSE
|
|||
WANTS_PACKAGE=$FALSE
|
||||
WANTS_VERSION=$FALSE
|
||||
WANTS_KDU=$FALSE
|
||||
WANTS_FMODSTUDIO=$FALSE
|
||||
WANTS_FMODEX=$FALSE
|
||||
WANTS_OPENSIM=$TRUE
|
||||
WANTS_AVX=$FALSE
|
||||
|
|
@ -66,6 +68,7 @@ showUsage()
|
|||
echo " --kdu : Build with KDU"
|
||||
echo " --package : Build installer"
|
||||
echo " --no-package : Build without installer (Overrides --package)"
|
||||
echo " --fmodstudio : Build with FMOD Studio"
|
||||
echo " --fmodex : Build with FMOD Ex"
|
||||
echo " --quicktime : Build with Quicktime (Windows)"
|
||||
echo " --opensim : Build with OpenSim support (Disables Havok features)"
|
||||
|
|
@ -84,7 +87,7 @@ getArgs()
|
|||
# $* = the options passed in from main
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
while getoptex "clean build config version package no-package fmodex ninja jobs: platform: kdu quicktime opensim no-opensim avx avx2 testbuild: help chan: btype:" "$@" ; do
|
||||
while getoptex "clean build config version package no-package fmodstudio fmodex ninja jobs: platform: kdu quicktime opensim no-opensim avx avx2 testbuild: help chan: btype:" "$@" ; do
|
||||
|
||||
#insure options are valid
|
||||
if [ -z "$OPTOPT" ] ; then
|
||||
|
|
@ -102,6 +105,7 @@ getArgs()
|
|||
fi
|
||||
;;
|
||||
kdu) WANTS_KDU=$TRUE;;
|
||||
fmodstudio) WANTS_FMODSTUDIO=$TRUE;;
|
||||
fmodex) WANTS_FMODEX=$TRUE;;
|
||||
opensim) WANTS_OPENSIM=$TRUE;;
|
||||
no-opensim) WANTS_OPENSIM=$FALSE;;
|
||||
|
|
@ -281,6 +285,7 @@ fi
|
|||
echo -e "configure_firestorm.py" > $LOG
|
||||
echo -e " PLATFORM: '$PLATFORM'" | tee -a $LOG
|
||||
echo -e " KDU: `b2a $WANTS_KDU`" | tee -a $LOG
|
||||
echo -e " FMODSTUDIO: `b2a $WANTS_FMODSTUDIO`" | tee -a $LOG
|
||||
echo -e " FMODEX: `b2a $WANTS_FMODEX`" | tee -a $LOG
|
||||
echo -e " OPENSIM: `b2a $WANTS_OPENSIM`" | tee -a $LOG
|
||||
echo -e " AVX: `b2a $WANTS_AVX`" | tee -a $LOG
|
||||
|
|
@ -376,12 +381,16 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then
|
|||
else
|
||||
KDU="-DUSE_KDU:BOOL=OFF"
|
||||
fi
|
||||
if [ $WANTS_FMODSTUDIO -eq $TRUE ] ; then
|
||||
FMODSTUDIO="-DFMODSTUDIO:BOOL=ON"
|
||||
else
|
||||
FMODSTUDIO="-DFMODSTUDIO:BOOL=OFF"
|
||||
fi
|
||||
if [ $WANTS_FMODEX -eq $TRUE ] ; then
|
||||
FMODEX="-DFMODEX:BOOL=ON"
|
||||
else
|
||||
FMODEX="-DFMODEX:BOOL=OFF"
|
||||
fi
|
||||
|
||||
if [ $WANTS_OPENSIM -eq $TRUE ] ; then
|
||||
OPENSIM="-DOPENSIM:BOOL=ON"
|
||||
else
|
||||
|
|
@ -457,7 +466,7 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then
|
|||
UNATTENDED="-DUNATTENDED=ON"
|
||||
fi
|
||||
|
||||
cmake -G "$TARGET" ../indra $CHANNEL $FMODEX $KDU $OPENSIM $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TESTBUILD $PACKAGE $UNATTENDED -DLL_TESTS:BOOL=OFF -DWORD_SIZE:STRING=$WORD_SIZE -DCMAKE_BUILD_TYPE:STRING=$BTYPE \
|
||||
cmake -G "$TARGET" ../indra $CHANNEL $FMODSTUDIO $FMODEX $KDU $OPENSIM $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TESTBUILD $PACKAGE $UNATTENDED -DLL_TESTS:BOOL=OFF -DWORD_SIZE:STRING=$WORD_SIZE -DCMAKE_BUILD_TYPE:STRING=$BTYPE \
|
||||
-DNDTARGET_ARCH:STRING="${TARGET_ARCH}" -DROOT_PROJECT_NAME:STRING=Firestorm $LL_ARGS_PASSTHRU | tee $LOG
|
||||
|
||||
if [ $PLATFORM == "win32" ] ; then
|
||||
|
|
|
|||
Loading…
Reference in New Issue