Add FMOD Studio support

This commit is contained in:
Drake Arconis
2014-08-10 17:41:10 -04:00
parent a6ac8e1f71
commit 90d2dce07a
21 changed files with 2157 additions and 1710 deletions

View File

@@ -29,8 +29,8 @@ set(cmake_SOURCE_FILES
ELFIO.cmake
EXPAT.cmake
ExamplePlugin.cmake
FMOD.cmake
FMODEX.cmake
FMODSTUDIO.cmake
FindAPR.cmake
FindBerkeleyDB.cmake
FindCARes.cmake

View File

@@ -233,6 +233,29 @@ if(WORD_SIZE EQUAL 32)
)
endif(WORD_SIZE EQUAL 32)
if(FMODSTUDIO)
if (WORD_SIZE EQUAL 32)
set(fmodstudio_dll_file "fmod.dll")
else (WORD_SIZE EQUAL 32)
set(fmodstudio_dll_file "fmod64.dll")
endif (WORD_SIZE EQUAL 32)
find_path(FMODSTUDIO_BINARY_DIR "${fmodstudio_dll_file}"
"${release_src_dir}"
"${FMODSTUDIO_SDK_DIR}/api/lowlevel/lib"
"${FMODSTUDIO_SDK_DIR}"
NO_DEFAULT_PATH
)
if(FMODSTUDIO_BINARY_DIR)
copy_if_different("${FMODSTUDIO_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets "${fmodstudio_dll_file}")
set(all_targets ${all_targets} ${out_targets})
copy_if_different("${FMODSTUDIO_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets "${fmodstudio_dll_file}")
set(all_targets ${all_targets} ${out_targets})
copy_if_different("${FMODSTUDIO_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets "${fmodstudio_dll_file}")
set(all_targets ${all_targets} ${out_targets})
endif(FMODSTUDIO_BINARY_DIR)
endif(FMODSTUDIO)
if(FMODEX)
if (WORD_SIZE EQUAL 32)
@@ -258,25 +281,6 @@ if(FMODEX)
endif(FMODEX_BINARY_DIR)
endif(FMODEX)
if(FMOD)
find_path(FMOD_BINARY_DIR fmod.dll
${release_src_dir}
${FMOD_SDK_DIR}/api
${FMOD_SDK_DIR}
)
if(FMOD_BINARY_DIR)
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmod.dll)
set(all_targets ${all_targets} ${out_targets})
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmod.dll)
set(all_targets ${all_targets} ${out_targets})
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmod.dll)
set(all_targets ${all_targets} ${out_targets})
else(FMOD_BINARY_DIR)
list(APPEND release_files fmod.dll) #Required for compile. This will cause an error in copying binaries.
endif(FMOD_BINARY_DIR)
endif(FMOD)
copy_if_different(
${release_src_dir}
"${CMAKE_CURRENT_BINARY_DIR}/Release"

View File

@@ -1,52 +0,0 @@
# -*- cmake -*-
include(Linking)
if(INSTALL_PROPRIETARY)
include(Prebuilt)
use_prebuilt_binary(fmod)
endif(INSTALL_PROPRIETARY)
find_library(FMOD_LIBRARY
NAMES fmod fmodvc fmod-3.75
PATHS
optimized ${ARCH_PREBUILT_DIRS_RELEASE}
debug ${ARCH_PREBUILT_DIRS_DEBUG}
)
if (NOT FMOD_LIBRARY)
set(FMOD_SDK_DIR CACHE PATH "Path to the FMOD SDK.")
if (FMOD_SDK_DIR)
find_library(FMOD_LIBRARY
NAMES fmodvc fmod-3.75 fmod
PATHS
${FMOD_SDK_DIR}/api/lib
${FMOD_SDK_DIR}/api
${FMOD_SDK_DIR}/lib
${FMOD_SDK_DIR}
)
endif (FMOD_SDK_DIR)
endif (NOT FMOD_LIBRARY)
find_path(FMOD_INCLUDE_DIR fmod.h
${LIBS_PREBUILT_DIR}/include
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include
${FMOD_SDK_DIR}/api/inc
${FMOD_SDK_DIR}/inc
${FMOD_SDK_DIR}
)
if (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
set(FMOD ON CACHE BOOL "Use closed source FMOD sound library.")
else (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
set(FMOD_LIBRARY "")
set(FMOD_INCLUDE_DIR "")
if (FMOD)
message(STATUS "No support for FMOD audio (need to set FMOD_SDK_DIR?)")
endif (FMOD)
set(FMOD OFF CACHE BOOL "Use closed source FMOD sound library.")
endif (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
if (FMOD)
message(STATUS "Building with FMOD audio support")
endif (FMOD)

View File

@@ -2,6 +2,10 @@
include(Linking)
if (FMODEX AND FMODSTUDIO)
message( FATAL_ERROR "You can not enable two FMOD variants at the same time." )
endif (FMODEX AND FMODSTUDIO)
if (NOT FMODEX_LIBRARY)
set(FMODEX_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.")
if (FMODEX_SDK_DIR)

View File

@@ -0,0 +1,83 @@
# -*- cmake -*-
include(Linking)
if (FMODEX AND FMODSTUDIO)
message( FATAL_ERROR "You can not enable two FMOD variants at the same time." )
endif (FMODEX AND FMODSTUDIO)
if (NOT FMODSTUDIO_LIBRARY)
set(FMODSTUDIO_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.")
if (FMODSTUDIO_SDK_DIR)
if(WORD_SIZE EQUAL 32)
find_library(FMODSTUDIO_LIBRARY
fmod_vc fmodL_vc fmod fmodL
PATHS
"${FMODSTUDIO_SDK_DIR}/api/lowlevel/lib"
"${FMODSTUDIO_SDK_DIR}/api/lowlevel"
"${FMODSTUDIO_SDK_DIR}"
)
elseif(WORD_SIZE EQUAL 64)
find_library(FMODSTUDIO_LIBRARY
fmod64_vc fmodL64_vc fmod64 fmodL64
PATHS
"${FMODSTUDIO_SDK_DIR}/api/lowlevel/lib"
"${FMODSTUDIO_SDK_DIR}/api/lowlevel"
"${FMODSTUDIO_SDK_DIR}"
)
endif(WORD_SIZE EQUAL 32)
endif(FMODSTUDIO_SDK_DIR)
if(WINDOWS AND NOT FMODSTUDIO_SDK_DIR)
GET_FILENAME_COMPONENT(FMODSTUDIO_PROG_DIR [HKEY_CURRENT_USER\\Software\\FMOD\ Studio\ API\ Windows] ABSOLUTE CACHE)
if(WORD_SIZE EQUAL 32)
find_library(FMODSTUDIO_LIBRARY
fmod_vc fmodL_vc
PATHS
"${FMODSTUDIO_PROG_DIR}/api/lowlevel/lib"
"${FMODSTUDIO_PROG_DIR}/api/lowlevel"
"${FMODSTUDIO_PROG_DIR}"
)
else(WORD_SIZE EQUAL 32)
find_library(FMODSTUDIO_LIBRARY
fmod64_vc fmodL64_vc
PATHS
"${FMODSTUDIO_PROG_DIR}/api/lowlevel/lib"
"${FMODSTUDIO_PROG_DIR}/api/lowlevel"
"${FMODSTUDIO_PROG_DIR}"
)
endif(WORD_SIZE EQUAL 32)
if(FMODSTUDIO_LIBRARY)
message(STATUS "Found fmodstudio in ${FMODSTUDIO_PROG_DIR}")
set(FMODSTUDIO_SDK_DIR "${FMODSTUDIO_PROG_DIR}")
set(FMODSTUDIO_SDK_DIR "${FMODSTUDIO_PROG_DIR}" CACHE PATH "Path to the FMOD Studio SDK." FORCE)
endif(FMODSTUDIO_LIBRARY)
endif(WINDOWS AND NOT FMODSTUDIO_SDK_DIR)
endif (NOT FMODSTUDIO_LIBRARY)
find_path(FMODSTUDIO_INCLUDE_DIR fmod.hpp
"${LIBS_PREBUILT_DIR}/include/fmodstudio"
"${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/fmodstudio"
"${FMODSTUDIO_SDK_DIR}/api/lowlevel/inc"
"${FMODSTUDIO_SDK_DIR}"
)
if(DARWIN)
set(FMODSTUDIO_ORIG_LIBRARY "${FMODSTUDIO_LIBRARY}")
set(FMODSTUDIO_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/libfmod.dylib")
endif(DARWIN)
if (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
set(FMODSTUDIO ON CACHE BOOL "Use closed source FMOD Studio sound library.")
else (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
set(FMODSTUDIO_LIBRARY "")
set(FMODSTUDIO_INCLUDE_DIR "")
if (FMODSTUDIO)
message(STATUS "No support for FMOD Studio audio (need to set FMODSTUDIO_SDK_DIR?)")
endif (FMODSTUDIO)
set(FMODSTUDIO OFF CACHE BOOL "Use closed source FMOD Studio sound library.")
set(FMODSTUDIO OFF)
endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
if (FMODSTUDIO)
message(STATUS "Building with FMOD Studio audio support")
endif (FMODSTUDIO)

View File

@@ -5,25 +5,25 @@ project(llaudio)
include(00-Common)
include(Audio)
include(LLAudio)
if (FMODSTUDIO)
include(FMODSTUDIO)
endif (FMODSTUDIO)
if (FMODEX)
include(FMODEX)
set(FMOD OFF)
endif (FMODEX)
if (NOT FMODEX)
include(FMOD)
endif (NOT FMODEX)
include(OPENAL)
include(LLCommon)
include(LLMath)
include(LLMessage)
include(LLVFS)
if (FMODSTUDIO)
include_directories(${FMODSTUDIO_INCLUDE_DIR})
endif(FMODSTUDIO)
if (FMODEX)
include_directories(${FMODEX_INCLUDE_DIR})
endif(FMODEX)
if(FMOD)
include_directories(${FMOD_INCLUDE_DIR})
endif (FMOD)
include_directories(
${LLAUDIO_INCLUDE_DIRS}
@@ -58,6 +58,20 @@ set(llaudio_HEADER_FILES
llwindgen.h
)
if (FMODSTUDIO)
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)
list(APPEND llaudio_SOURCE_FILES
llaudioengine_fmodex.cpp
@@ -71,26 +85,6 @@ if (FMODEX)
llstreamingaudio_fmodex.h
)
endif (FMODEX)
if (FMOD)
list(APPEND llaudio_SOURCE_FILES
llaudioengine_fmod.cpp
lllistener_fmod.cpp
llstreamingaudio_fmod.cpp
)
list(APPEND llaudio_HEADER_FILES
llaudioengine_fmod.h
lllistener_fmod.h
llstreamingaudio_fmod.h
)
if (LINUX)
if (${CXX_VERSION} MATCHES "4.[23]")
set_source_files_properties(llaudioengine_fmod.cpp
COMPILE_FLAGS -Wno-error=write-strings)
endif (${CXX_VERSION} MATCHES "4.[23]")
endif (LINUX)
endif (FMOD)
if (OPENAL)
list(APPEND llaudio_SOURCE_FILES

View File

@@ -1,789 +0,0 @@
/**
* @file audioengine_fmod.cpp
* @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D 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_fmod.h"
#include "llaudioengine_fmod.h"
#include "lllistener_fmod.h"
#include "llerror.h"
#include "llmath.h"
#include "llrand.h"
#include "fmod.h"
#include "fmod_errors.h"
#include "lldir.h"
#include "llapr.h"
#include "sound_ids.h"
extern "C" {
void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata);
}
LLAudioEngine_FMOD::LLAudioEngine_FMOD()
{
mInited = false;
mWindGen = NULL;
mWindDSP = NULL;
}
LLAudioEngine_FMOD::~LLAudioEngine_FMOD()
{
}
bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata)
{
LLAudioEngine::init(num_channels, userdata);
// Reserve one extra channel for the http stream.
if (!FSOUND_SetMinHardwareChannels(num_channels + 1))
{
LL_WARNS("AppInit") << "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
}
LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() initializing FMOD" << LL_ENDL;
F32 version = FSOUND_GetVersion();
if (version < FMOD_VERSION)
{
LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
<< ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL;
//return false;
}
U32 fmod_flags = 0x0;
#if LL_WINDOWS
// Windows needs to know which window is frontmost.
// This must be called before FSOUND_Init() per the FMOD docs.
// This could be used to let FMOD handle muting when we lose focus,
// but we don't actually want to do that because we want to distinguish
// between minimized and not-focused states.
if (!FSOUND_SetHWND(userdata))
{
LL_WARNS("AppInit") << "Error setting FMOD window: "
<< FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
return false;
}
// Play audio when we don't have focus.
// (For example, IM client on top of us.)
// This means we also try to play audio when minimized,
// so we manually handle muting in that case. JC
fmod_flags |= FSOUND_INIT_GLOBALFOCUS;
fmod_flags |= FSOUND_INIT_DSOUND_HRTF_FULL;
#endif
#if LL_LINUX
// initialize the FMOD engine
// This is a hack to use only FMOD's basic FPU mixer
// when the LL_VALGRIND environmental variable is set,
// otherwise valgrind will fall over on FMOD's MMX detection
if (getenv("LL_VALGRIND")) /*Flawfinder: ignore*/
{
LL_INFOS("AppInit") << "Pacifying valgrind in FMOD init." << LL_ENDL;
FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU);
}
// If we don't set an output method, Linux FMOD always
// decides on OSS and fails otherwise. So we'll manually
// try ESD, then OSS, then ALSA.
// Why this order? See SL-13250, but in short, OSS emulated
// on top of ALSA is ironically more reliable than raw ALSA.
// Ack, and ESD has more reliable failure modes - but has worse
// latency - than all of them, so wins for now.
bool audio_ok = false;
if (!audio_ok)
{
if (NULL == getenv("LL_BAD_FMOD_ESD")) /*Flawfinder: ignore*/
{
LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) &&
FSOUND_Init(44100, num_channels, fmod_flags))
{
LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY"
<< LL_ENDL;
audio_ok = true;
} else {
LL_WARNS("AppInit") << "ESD audio output FAILED to initialize: "
<< FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
}
} else {
LL_DEBUGS("AppInit") << "ESD 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(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) &&
FSOUND_Init(44100, num_channels, fmod_flags))
{
LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
audio_ok = true;
} else {
LL_WARNS("AppInit") << "OSS audio output FAILED to initialize: "
<< FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
}
} else {
LL_DEBUGS("AppInit") << "OSS 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(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) &&
FSOUND_Init(44100, num_channels, fmod_flags))
{
LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
audio_ok = true;
} else {
LL_WARNS("AppInit") << "ALSA audio output FAILED to initialize: "
<< FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
}
} else {
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
}
}
if (!audio_ok)
{
LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
return false;
}
// On Linux, FMOD causes a SIGPIPE for some netstream error
// conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us.
// NOW FIXED in FMOD 3.x since 2006-10-01.
//signal(SIGPIPE, SIG_IGN);
// We're interested in logging which output method we
// ended up with, for QA purposes.
switch (FSOUND_GetOutput())
{
case FSOUND_OUTPUT_NOSOUND: LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
case FSOUND_OUTPUT_OSS: LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
case FSOUND_OUTPUT_ESD: LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break;
case FSOUND_OUTPUT_ALSA: LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
default: LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
};
#else // LL_LINUX
// initialize the FMOD engine
if (!FSOUND_Init(44100, num_channels, fmod_flags))
{
LL_WARNS("AppInit") << "Error initializing FMOD: "
<< FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
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_FMOD());
LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL;
mInited = true;
return true;
}
std::string LLAudioEngine_FMOD::getDriverName(bool verbose)
{
if (verbose)
{
F32 version = FSOUND_GetVersion();
return llformat("FMOD version %f", version);
}
else
{
return "FMOD";
}
}
void LLAudioEngine_FMOD::allocateListener(void)
{
mListenerp = (LLListener *) new LLListener_FMOD();
if (!mListenerp)
{
llwarns << "Listener creation failed" << llendl;
}
}
void LLAudioEngine_FMOD::shutdown()
{
if (mWindDSP)
{
FSOUND_DSP_SetActive(mWindDSP,false);
FSOUND_DSP_Free(mWindDSP);
}
stopInternetStream();
LLAudioEngine::shutdown();
llinfos << "LLAudioEngine_FMOD::shutdown() closing FMOD" << llendl;
FSOUND_Close();
llinfos << "LLAudioEngine_FMOD::shutdown() done closing FMOD" << llendl;
delete mListenerp;
mListenerp = NULL;
}
LLAudioBuffer * LLAudioEngine_FMOD::createBuffer()
{
return new LLAudioBufferFMOD();
}
LLAudioChannel * LLAudioEngine_FMOD::createChannel()
{
return new LLAudioChannelFMOD();
}
bool LLAudioEngine_FMOD::initWind()
{
if (!mWindGen)
{
bool enable;
switch (FSOUND_GetMixer())
{
case FSOUND_MIXER_MMXP5:
case FSOUND_MIXER_MMXP6:
case FSOUND_MIXER_QUALITY_MMXP5:
case FSOUND_MIXER_QUALITY_MMXP6:
enable = (typeid(MIXBUFFERFORMAT) == typeid(S16));
break;
case FSOUND_MIXER_BLENDMODE:
enable = (typeid(MIXBUFFERFORMAT) == typeid(S32));
break;
case FSOUND_MIXER_QUALITY_FPU:
enable = (typeid(MIXBUFFERFORMAT) == typeid(F32));
break;
default:
// FSOUND_GetMixer() does not return a valid mixer type on Darwin
LL_INFOS("AppInit") << "Unknown FMOD mixer type, assuming default" << LL_ENDL;
enable = true;
break;
}
if (enable)
{
mWindGen = new LLWindGen<MIXBUFFERFORMAT>(FSOUND_GetOutputRate());
}
else
{
LL_WARNS("AppInit") << "Incompatible FMOD mixer type, wind noise disabled" << LL_ENDL;
}
}
mNextWindUpdate = 0.0;
if (mWindGen && !mWindDSP)
{
mWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen);
}
if (mWindDSP)
{
FSOUND_DSP_SetActive(mWindDSP, true);
return true;
}
return false;
}
void LLAudioEngine_FMOD::cleanupWind()
{
if (mWindDSP)
{
FSOUND_DSP_SetActive(mWindDSP, false);
FSOUND_DSP_Free(mWindDSP);
mWindDSP = NULL;
}
delete mWindGen;
mWindGen = NULL;
}
//-----------------------------------------------------------------------
void LLAudioEngine_FMOD::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_FMOD::setSourceMinDistance(U16 source_num, F64 distance)
{
if (!mInited)
{
return;
}
if (mBuffer[source_num])
{
mMinDistance[source_num] = (F32) distance;
if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
{
llwarns << "FMOD::setSourceMinDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
}
}
//-----------------------------------------------------------------------
void LLAudioEngine_FMOD::setSourceMaxDistance(U16 source_num, F64 distance)
{
if (!mInited)
{
return;
}
if (mBuffer[source_num])
{
mMaxDistance[source_num] = (F32) distance;
if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
{
llwarns << "FMOD::setSourceMaxDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
}
}
//-----------------------------------------------------------------------
void LLAudioEngine_FMOD::get3DParams(S32 source_num, S32 *volume, S32 *freq, S32 *inside, S32 *outside, LLVector3 *orient, S32 *out_volume, F32 *min_dist, F32 *max_dist)
{
*volume = 0;
*freq = 0;
*inside = 0;
*outside = 0;
*orient = LLVector3::zero;
*out_volume = 0;
*min_dist = 0.f;
*max_dist = 0.f;
}
*/
//-----------------------------------------------------------------------
void LLAudioEngine_FMOD::setInternalGain(F32 gain)
{
if (!mInited)
{
return;
}
gain = llclamp( gain, 0.0f, 1.0f );
FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) );
LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
if ( saimpl )
{
// fmod likes its streaming audio channel gain re-asserted after
// master volume change.
saimpl->setGain(saimpl->getGain());
}
}
//
// LLAudioChannelFMOD implementation
//
LLAudioChannelFMOD::LLAudioChannelFMOD() : LLAudioChannel(), mChannelID(0), mLastSamplePos(0)
{
}
LLAudioChannelFMOD::~LLAudioChannelFMOD()
{
cleanup();
}
bool LLAudioChannelFMOD::updateBuffer()
{
if (LLAudioChannel::updateBuffer())
{
// Base class update returned true, which means that we need to actually
// set up the channel for a different buffer.
LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer();
// Grab the FMOD sample associated with the buffer
FSOUND_SAMPLE *samplep = bufferp->getSample();
if (!samplep)
{
// This is bad, there should ALWAYS be a sample associated with a legit
// buffer.
llerrs << "No FMOD sample!" << llendl;
return false;
}
// Actually play the sound. Start it off paused so we can do all the necessary
// setup.
mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), true);
//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
if (!FSOUND_SetVolume(mChannelID, llround(getSecondaryGain() * mCurrentSourcep->getGain() * 255.0f)))
{
// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF))
{
// llwarns << "Channel " << mChannelID << "Source ID: " << mCurrentSourcep->getID()
// << " at " << mCurrentSourcep->getPositionGlobal() << llendl;
// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
}
return true;
}
void LLAudioChannelFMOD::update3DPosition()
{
if (!mChannelID)
{
// We're not actually a live channel (i.e., we're not playing back anything)
return;
}
LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)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.
bufferp->set3DMode(false);
}
else
{
// Localized sound. Update the position and velocity of the sound.
bufferp->set3DMode(true);
LLVector3 float_pos;
float_pos.setVec(mCurrentSourcep->getPositionGlobal());
if (!FSOUND_3D_SetAttributes(mChannelID, float_pos.mV, mCurrentSourcep->getVelocity().mV))
{
LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::update3DPosition error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
}
}
}
void LLAudioChannelFMOD::updateLoop()
{
if (!mChannelID)
{
// 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 = FSOUND_GetCurrentPosition(mChannelID);
if (cur_pos < (U32)mLastSamplePos)
{
mLoopedThisFrame = true;
}
mLastSamplePos = cur_pos;
}
void LLAudioChannelFMOD::cleanup()
{
LLAudioChannel::cleanup();
if (!mChannelID)
{
//llinfos << "Aborting cleanup with no channelID." << llendl;
return;
}
//llinfos << "Cleaning up channel: " << mChannelID << llendl;
if (!FSOUND_StopSound(mChannelID))
{
LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
mChannelID = 0;
mLastSamplePos = 0;
}
void LLAudioChannelFMOD::play()
{
if (!mChannelID)
{
llwarns << "Playing without a channelID, aborting" << llendl;
return;
}
if(!FSOUND_IsPaused(mChannelID))
{
FSOUND_SetPaused(mChannelID, true);
FSOUND_SetCurrentPosition(mChannelID, 0);
}
if (!FSOUND_SetPaused(mChannelID, false))
{
llwarns << "LLAudioChannelFMOD::play error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
getSource()->setPlayedOnce(true);
}
void LLAudioChannelFMOD::playSynced(LLAudioChannel *channelp)
{
LLAudioChannelFMOD *fmod_channelp = (LLAudioChannelFMOD*)channelp;
if (!(fmod_channelp->mChannelID && mChannelID))
{
// Don't have channels allocated to both the master and the slave
return;
}
U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength();
// Try to match the position of our sync master
if (!FSOUND_SetCurrentPosition(mChannelID, position))
{
llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl;
}
// Start us playing
play();
}
bool LLAudioChannelFMOD::isPlaying()
{
if (!mChannelID)
{
return false;
}
return FSOUND_IsPlaying(mChannelID) && (!FSOUND_GetPaused(mChannelID));
}
//
// LLAudioBufferFMOD implementation
//
LLAudioBufferFMOD::LLAudioBufferFMOD() : LLAudioBuffer()
{
mSamplep = NULL;
}
LLAudioBufferFMOD::~LLAudioBufferFMOD()
{
if (mSamplep)
{
// Clean up the associated FMOD sample if it exists.
FSOUND_Sample_Free(mSamplep);
mSamplep = NULL;
}
}
bool LLAudioBufferFMOD::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, LL_APR_RPB))
{
// File not found, abort.
return false;
}
if (mSamplep)
{
// If there's already something loaded in this buffer, clean it up.
FSOUND_Sample_Free(mSamplep);
mSamplep = NULL;
}
// Load up the wav file into an fmod sample
#if LL_WINDOWS
// MikeS. - Loading the sound file manually and then handing it over to FMOD,
// since FMOD uses posix IO internally,
// which doesn't work with unicode file paths.
LLFILE* sound_file = LLFile::fopen(filename,"rb"); /* Flawfinder: ignore */
if (sound_file)
{
fseek(sound_file,0,SEEK_END);
U32 file_length = ftell(sound_file); //Find the length of the file by seeking to the end and getting the offset
size_t read_count;
fseek(sound_file,0,SEEK_SET); //Seek back to the beginning
char* buffer = new char[file_length];
llassert(buffer);
read_count = fread((void*)buffer,file_length,1,sound_file);//Load it..
if(ferror(sound_file)==0 && (read_count == 1)){//No read error, and we got 1 chunk of our size...
unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY;
//FSOUND_16BITS | FSOUND_MONO | FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL;
mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, mode_flags , 0, file_length);
}
delete[] buffer;
fclose(sound_file);
}
#else
mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, filename.c_str(), FSOUND_LOOP_NORMAL, 0, 0);
#endif
if (!mSamplep)
{
// We failed to load the file for some reason.
llwarns << "Could not load data '" << filename << "': "
<< FMOD_ErrorString(FSOUND_GetError()) << 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 LLAudioBufferFMOD::getLength()
{
if (!mSamplep)
{
return 0;
}
return FSOUND_Sample_GetLength(mSamplep);
}
void LLAudioBufferFMOD::set3DMode(bool use3d)
{
U16 current_mode = FSOUND_Sample_GetMode(mSamplep);
if (use3d)
{
if (!FSOUND_Sample_SetMode(mSamplep, (current_mode & (~FSOUND_2D))))
{
llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
}
else
{
if (!FSOUND_Sample_SetMode(mSamplep, current_mode | FSOUND_2D))
{
llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
}
}
}
void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata)
{
// 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_FMOD::MIXBUFFERFORMAT> *windgen =
(LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *)userdata;
newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length);
return newbuffer;
}

View File

@@ -1,124 +0,0 @@
/**
* @file audioengine_fmod.h
* @brief Definition of LLAudioEngine class abstracting the audio
* support as a FMOD 3D 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_FMOD_H
#define LL_AUDIOENGINE_FMOD_H
#include "llaudioengine.h"
#include "lllistener_fmod.h"
#include "llwindgen.h"
#include "fmod.h"
class LLAudioStreamManagerFMOD;
class LLAudioEngine_FMOD : public LLAudioEngine
{
public:
LLAudioEngine_FMOD();
virtual ~LLAudioEngine_FMOD();
// 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);
#if LL_DARWIN
typedef S32 MIXBUFFERFORMAT;
#else
typedef S16 MIXBUFFERFORMAT;
#endif
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);
protected:
static signed char F_CALLBACKAPI callbackMetaData(char* name, char* value, void* userdata);
//F32 mMinDistance[MAX_BUFFERS];
//F32 mMaxDistance[MAX_BUFFERS];
bool mInited;
// On Windows, userdata is the HWND of the application window.
void* mUserData;
LLWindGen<MIXBUFFERFORMAT> *mWindGen;
FSOUND_DSPUNIT *mWindDSP;
};
class LLAudioChannelFMOD : public LLAudioChannel
{
public:
LLAudioChannelFMOD();
virtual ~LLAudioChannelFMOD();
protected:
/*virtual*/ void play();
/*virtual*/ void playSynced(LLAudioChannel *channelp);
/*virtual*/ void cleanup();
/*virtual*/ bool isPlaying();
/*virtual*/ bool updateBuffer();
/*virtual*/ void update3DPosition();
/*virtual*/ void updateLoop();
protected:
int mChannelID;
S32 mLastSamplePos;
};
class LLAudioBufferFMOD : public LLAudioBuffer
{
public:
LLAudioBufferFMOD();
virtual ~LLAudioBufferFMOD();
/*virtual*/ bool loadWAV(const std::string& filename);
/*virtual*/ U32 getLength();
friend class LLAudioChannelFMOD;
void set3DMode(bool use3d);
protected:
FSOUND_SAMPLE *getSample() { return mSamplep; }
protected:
FSOUND_SAMPLE *mSamplep;
};
#endif // LL_AUDIOENGINE_FMOD_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,139 @@
/**
* @file audioengine_FMODSTUDIO.h
* @brief Definition of LLAudioEngine class abstracting the audio
* support as a FMOD Studio 3D implementation
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_AUDIOENGINE_FMODSTUDIO_H
#define LL_AUDIOENGINE_FMODSTUDIO_H
#include "llaudioengine.h"
#include "lllistener_fmodstudio.h"
#include "llwindgen.h"
//Stubs
class LLAudioStreamManagerFMODSTUDIO;
namespace FMOD
{
class System;
class Channel;
class ChannelGroup;
class Sound;
class DSP;
}
//Interfaces
class LLAudioEngine_FMODSTUDIO : public LLAudioEngine
{
public:
LLAudioEngine_FMODSTUDIO(bool enable_profiler, bool verbose_debugging);
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 *mWindDSP;
FMOD::System *mSystem;
bool mEnableProfiler;
public:
static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
};
class LLAudioChannelFMODSTUDIO : public LLAudioChannel
{
public:
LLAudioChannelFMODSTUDIO(FMOD::System *audioengine);
virtual ~LLAudioChannelFMODSTUDIO();
void onRelease();
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;
friend class CFMODSoundChecks;
};
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;
friend class CFMODSoundChecks;
};
#endif // LL_AUDIOENGINE_FMODSTUDIO_H

View File

@@ -1,125 +0,0 @@
/**
* @file listener_fmod.cpp
* @brief implementation of LISTENER class abstracting the audio
* support as a FMOD 3D 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_fmod.h"
#include "fmod.h"
//-----------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------
LLListener_FMOD::LLListener_FMOD()
{
init();
}
//-----------------------------------------------------------------------
LLListener_FMOD::~LLListener_FMOD()
{
}
//-----------------------------------------------------------------------
void LLListener_FMOD::init(void)
{
// do inherited
LLListener::init();
mDopplerFactor = 1.0f;
mRolloffFactor = 1.0f;
}
//-----------------------------------------------------------------------
void LLListener_FMOD::translate(LLVector3 offset)
{
LLListener::translate(offset);
FSOUND_3D_Listener_SetAttributes(mPosition.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]);
}
//-----------------------------------------------------------------------
void LLListener_FMOD::setPosition(LLVector3 pos)
{
LLListener::setPosition(pos);
FSOUND_3D_Listener_SetAttributes(pos.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]);
}
//-----------------------------------------------------------------------
void LLListener_FMOD::setVelocity(LLVector3 vel)
{
LLListener::setVelocity(vel);
FSOUND_3D_Listener_SetAttributes(NULL, vel.mV, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]);
}
//-----------------------------------------------------------------------
void LLListener_FMOD::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;
FSOUND_3D_Listener_SetAttributes(NULL, NULL, at.mV[0],at.mV[1],at.mV[2], up.mV[0],up.mV[1],up.mV[2]);
}
//-----------------------------------------------------------------------
void LLListener_FMOD::commitDeferredChanges()
{
FSOUND_Update();
}
void LLListener_FMOD::setRolloffFactor(F32 factor)
{
mRolloffFactor = factor;
FSOUND_3D_SetRolloffFactor(factor);
}
F32 LLListener_FMOD::getRolloffFactor()
{
return mRolloffFactor;
}
void LLListener_FMOD::setDopplerFactor(F32 factor)
{
mDopplerFactor = factor;
FSOUND_3D_SetDopplerFactor(factor);
}
F32 LLListener_FMOD::getDopplerFactor()
{
return mDopplerFactor;
}

View File

@@ -1,58 +0,0 @@
/**
* @file listener_fmod.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_FMOD_H
#define LL_LISTENER_FMOD_H
#include "lllistener.h"
class LLListener_FMOD : public LLListener
{
public:
LLListener_FMOD();
virtual ~LLListener_FMOD();
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:
F32 mDopplerFactor;
F32 mRolloffFactor;
};
#endif

View File

@@ -0,0 +1,141 @@
/**
* @file listener_fmodstudio.cpp
* @brief implementation of LISTENER class abstracting the audio
* support as a FMOD 3D implementation (windows only)
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llaudioengine.h"
#include "lllistener_fmodstudio.h"
#include "fmod.hpp"
//-----------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------
LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system)
{
mSystem = system;
init();
}
//-----------------------------------------------------------------------
LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO()
{
}
//-----------------------------------------------------------------------
void LLListener_FMODSTUDIO::init(void)
{
// do inherited
LLListener::init();
mDopplerFactor = 1.0f;
mRolloffFactor = 1.0f;
}
//-----------------------------------------------------------------------
void LLListener_FMODSTUDIO::translate(LLVector3 offset)
{
LLListener::translate(offset);
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
}
//-----------------------------------------------------------------------
void LLListener_FMODSTUDIO::setPosition(LLVector3 pos)
{
LLListener::setPosition(pos);
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
}
//-----------------------------------------------------------------------
void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel)
{
LLListener::setVelocity(vel);
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
}
//-----------------------------------------------------------------------
void LLListener_FMODSTUDIO::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_FMODSTUDIO::commitDeferredChanges()
{
mSystem->update();
}
void LLListener_FMODSTUDIO::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 fmodstudio, 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_FMODSTUDIO::getRolloffFactor()
{
return mRolloffFactor;
}
void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor)
{
mDopplerFactor = factor;
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
}
F32 LLListener_FMODSTUDIO::getDopplerFactor()
{
return mDopplerFactor;
}

View File

@@ -0,0 +1,71 @@
/**
* @file listener_fmodstudio.h
* @brief Description of LISTENER class abstracting the audio support
* as an FMOD Studio 3D implementation (windows and Linux)
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/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 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

View File

@@ -1,385 +0,0 @@
/**
* @file streamingaudio_fmod.cpp
* @brief LLStreamingAudio_FMOD implementation
*
* $LicenseInfo:firstyear=2009&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.h"
#include "fmod_errors.h"
#include "llstreamingaudio_fmod.h"
class LLAudioStreamManagerFMOD
{
public:
LLAudioStreamManagerFMOD(const std::string& url);
int startStream();
bool stopStream(); // Returns true if the stream was successfully stopped.
bool ready();
const std::string& getURL() { return mInternetStreamURL; }
int getOpenState();
FSOUND_STREAM* getStream() { return mInternetStream; }
protected:
FSOUND_STREAM* mInternetStream;
bool mReady;
std::string mInternetStreamURL;
};
//---------------------------------------------------------------------------
// Internet Streaming
//---------------------------------------------------------------------------
LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
mCurrentInternetStreamp(NULL),
mFMODInternetStreamChannel(-1),
mGain(1.0f),
mMetaData(NULL)
{
// Number of milliseconds of audio to buffer for the audio card.
// Must be larger than the usual Second Life frame stutter time.
FSOUND_Stream_SetBufferSize(200);
// 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_FMOD::~LLStreamingAudio_FMOD()
{
// nothing interesting/safe to do.
}
signed char F_CALLBACKAPI MetaDataCallback(char *name, char *value, void *userdata)
{
std::string szName(name);
if(szName == "TITLE" || szName=="TIT2" || szName=="Title")
(*(LLSD*)userdata)["TITLE"] = value;
if(szName == "ARTIST" || szName=="TPE1" || szName =="WM/AlbumTitle")
(*(LLSD*)userdata)["ARTIST"] = value;
else
(*(LLSD*)userdata)[std::string(name)] = value;
return true;
}
void LLStreamingAudio_FMOD::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 LLAudioStreamManagerFMOD(url);
mURL = url;
if(mCurrentInternetStreamp->getStream())
{
mMetaData = new LLSD;
}
}
else
{
llinfos << "Set internet stream to null" << llendl;
mURL.clear();
}
}
void LLStreamingAudio_FMOD::update()
{
// Kill dead internet streams, if possible
std::list<LLAudioStreamManagerFMOD *>::iterator iter;
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
{
LLAudioStreamManagerFMOD *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;
}
int open_state = mCurrentInternetStreamp->getOpenState();
if (!open_state)
{
// Stream is live
// start the stream if it's ready
if (mFMODInternetStreamChannel < 0)
{
mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream();
if (mFMODInternetStreamChannel != -1)
{
// Reset volume to previously set volume
setGain(getGain());
FSOUND_SetPaused(mFMODInternetStreamChannel, false);
if(mCurrentInternetStreamp->getStream() && mMetaData)
{
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),&MetaDataCallback, mMetaData);
}
}
}
}
switch(open_state)
{
default:
case 0:
// success
break;
case -1:
// stream handle is invalid
llwarns << "InternetStream - invalid handle" << llendl;
stop();
return;
case -2:
// opening
break;
case -3:
// failed to open, file not found, perhaps
llwarns << "InternetStream - failed to open" << llendl;
stop();
return;
case -4:
// connecting
break;
case -5:
// buffering
break;
}
}
void LLStreamingAudio_FMOD::stop()
{
if(mMetaData)
{
if(mCurrentInternetStreamp && mCurrentInternetStreamp->getStream())
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),NULL,NULL);
delete mMetaData;
mMetaData = NULL;
}
if (mFMODInternetStreamChannel != -1)
{
FSOUND_SetPaused(mFMODInternetStreamChannel, true);
FSOUND_SetPriority(mFMODInternetStreamChannel, 0);
mFMODInternetStreamChannel = -1;
}
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_FMOD::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_FMOD::isPlaying()
{
if (mCurrentInternetStreamp)
{
return 1; // Active and playing
}
else if (!mURL.empty())
{
return 2; // "Paused"
}
else
{
return 0;
}
}
F32 LLStreamingAudio_FMOD::getGain()
{
return mGain;
}
std::string LLStreamingAudio_FMOD::getURL()
{
return mURL;
}
void LLStreamingAudio_FMOD::setGain(F32 vol)
{
mGain = vol;
if (mFMODInternetStreamChannel != -1)
{
vol = llclamp(vol * vol, 0.f, 1.f);
int vol_int = llround(vol * 255.f);
FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int);
}
}
///////////////////////////////////////////////////////
// manager of possibly-multiple internet audio streams
LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) :
mInternetStream(NULL),
mReady(false)
{
mInternetStreamURL = url;
mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0);
if (!mInternetStream)
{
llwarns << "Couldn't open fmod stream, error "
<< FMOD_ErrorString(FSOUND_GetError())
<< llendl;
mReady = false;
return;
}
mReady = true;
}
int LLAudioStreamManagerFMOD::startStream()
{
// We need a live and opened stream before we try and play it.
if (!mInternetStream || getOpenState())
{
llwarns << "No internet stream to start playing!" << llendl;
return -1;
}
// Make sure the stream is set to 2D mode.
FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D);
return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true);
}
bool LLAudioStreamManagerFMOD::stopStream()
{
if (mInternetStream)
{
int read_percent = 0;
int status = 0;
int bitrate = 0;
unsigned int flags = 0x0;
FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags);
bool close = true;
switch (status)
{
case FSOUND_STREAM_NET_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)
{
FSOUND_Stream_Close(mInternetStream);
mInternetStream = NULL;
return true;
}
else
{
return false;
}
}
else
{
return true;
}
}
int LLAudioStreamManagerFMOD::getOpenState()
{
int open_state = FSOUND_Stream_GetOpenState(mInternetStream);
return open_state;
}

View File

@@ -1,68 +0,0 @@
/**
* @file streamingaudio_fmod.h
* @author Tofu Linden
* @brief Definition of LLStreamingAudio_FMOD implementation
*
* $LicenseInfo:firstyear=2009&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"
class LLAudioStreamManagerFMOD;
class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
{
public:
LLStreamingAudio_FMOD();
/*virtual*/ ~LLStreamingAudio_FMOD();
/*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 supportsMetaData(){return true;}
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
/*virtual*/ bool supportsWaveData(){return false;}
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1){return false;}
private:
LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
int mFMODInternetStreamChannel;
std::list<LLAudioStreamManagerFMOD *> mDeadStreams;
std::string mURL;
F32 mGain;
LLSD *mMetaData;
};
#endif // LL_STREAMINGAUDIO_FMOD_H

View File

@@ -0,0 +1,505 @@
/**
* @file streamingaudio_fmodstudio.cpp
* @brief LLStreamingAudio_FMODSTUDIO implementation
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmath.h"
#include "fmod.hpp"
#include "fmod_errors.h"
#include "llstreamingaudio_fmodstudio.h"
class LLAudioStreamManagerFMODSTUDIO
{
public:
LLAudioStreamManagerFMODSTUDIO(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_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
mSystem(system),
mCurrentInternetStreamp(NULL),
mFMODInternetStreamChannelp(NULL),
mGain(1.0f),
mMetaData(NULL)
{
// 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_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO()
{
// nothing interesting/safe to do.
}
void LLStreamingAudio_FMODSTUDIO::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())
{
if(mDeadStreams.empty())
{
llinfos << "Starting internet stream: " << url << llendl;
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,url);
mURL = url;
mMetaData = new LLSD;
}
else
{
llinfos << "Deferring stream load until buffer release: " << url << llendl;
mPendingURL = url;
}
}
else
{
llinfos << "Set internet stream to null" << llendl;
mURL.clear();
}
}
void LLStreamingAudio_FMODSTUDIO::update()
{
// Kill dead internet streams, if possible
std::list<LLAudioStreamManagerFMODSTUDIO *>::iterator iter;
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
{
LLAudioStreamManagerFMODSTUDIO *streamp = *iter;
if (streamp->stopStream())
{
llinfos << "Closed dead stream" << llendl;
delete streamp;
mDeadStreams.erase(iter++);
}
else
{
iter++;
}
}
if(!mDeadStreams.empty())
{
llassert_always(mCurrentInternetStreamp == NULL);
return;
}
if(!mPendingURL.empty())
{
llassert_always(mCurrentInternetStreamp == NULL);
llinfos << "Starting internet stream: " << mPendingURL << llendl;
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,mPendingURL);
mURL = mPendingURL;
mMetaData = new LLSD;
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 = 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);
}
}
else if(open_state == FMOD_OPENSTATE_ERROR)
{
stop();
return;
}
if(mFMODInternetStreamChannelp)
{
if(!mMetaData)
mMetaData = new LLSD;
FMOD::Sound *sound = NULL;
if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
{
FMOD_TAG tag;
S32 tagcount, dirtytagcount;
if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
{
mMetaData->clear();
for(S32 i = 0; i < tagcount; ++i)
{
if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
continue;
std::string name = tag.name;
switch(tag.type) //Crappy tag translate table.
{
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"))
{
llinfos << "Stream forced changing sample rate to " << *((float *)tag.data) << llendl;
mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data));
}
continue;
default:
break;
}
switch(tag.datatype)
{
case(FMOD_TAGDATATYPE_INT):
(*mMetaData)[name]=*(LLSD::Integer*)(tag.data);
llinfos << tag.name << ": " << *(int*)(tag.data) << llendl;
break;
case(FMOD_TAGDATATYPE_FLOAT):
(*mMetaData)[name]=*(LLSD::Float*)(tag.data);
llinfos << tag.name << ": " << *(float*)(tag.data) << llendl;
break;
case(FMOD_TAGDATATYPE_STRING):
{
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
(*mMetaData)[name]=out;
llinfos << tag.name << ": " << out << llendl;
}
break;
case(FMOD_TAGDATATYPE_STRING_UTF16):
{
std::string out((char*)tag.data,tag.datalen);
(*mMetaData)[std::string(tag.name)]=out;
llinfos << tag.name << ": " << out << llendl;
}
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;
llinfos << tag.name << ": " << out << llendl;
}
default:
break;
}
}
}
if(starving)
{
bool paused = false;
mFMODInternetStreamChannelp->getPaused(&paused);
if(!paused)
{
llinfos << "Stream starvation detected! Pausing stream until buffer nearly full." << llendl;
llinfos << " (diskbusy="<<diskbusy<<")" << llendl;
llinfos << " (progress="<<progress<<")" << llendl;
mFMODInternetStreamChannelp->setPaused(true);
}
}
else if(progress > 80)
{
mFMODInternetStreamChannelp->setPaused(false);
}
}
}
}
void LLStreamingAudio_FMODSTUDIO::stop()
{
mPendingURL.clear();
if(mMetaData)
{
delete mMetaData;
mMetaData = NULL;
}
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_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?
mFMODInternetStreamChannelp->setVolume(vol);
}
}
/*virtual*/ bool LLStreamingAudio_FMODSTUDIO::getWaveData(float* arr, S32 count, S32 stride/*=1*/)
{
//if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp)
// return false;
//bool muted=false;
//mFMODInternetStreamChannelp->getMute(&muted);
//if(muted)
// return false;
//static std::vector<float> local_array(count); //Have to have an extra buffer to mix channels. Bleh.
//if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink.
// local_array.resize(count);
//if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK &&
// mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK )
//{
// for(S32 i = count-1;i>=0;i-=stride)
// {
// arr[i] += local_array[i];
// arr[i] *= .5f;
// }
// return true;
//}
return false;
}
///////////////////////////////////////////////////////
// manager of possibly-multiple internet audio streams
LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url) :
mSystem(system),
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)
{
llwarns << "Couldn't open fmod stream, error "
<< FMOD_ErrorString(result)
<< llendl;
mReady = false;
return;
}
mReady = true;
}
FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::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(mInternetStream, NULL, true, &mStreamChannel);
return mStreamChannel;
}
bool LLAudioStreamManagerFMODSTUDIO::stopStream()
{
if (mInternetStream)
{
bool close = true;
switch (getOpenState())
{
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_OPENSTATE LLAudioStreamManagerFMODSTUDIO::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
{
FMOD_OPENSTATE state;
mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
return state;
}
void LLStreamingAudio_FMODSTUDIO::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);
}

View File

@@ -0,0 +1,87 @@
/**
* @file streamingaudio_fmodstudio.h
* @author Tofu Linden
* @brief Definition of LLStreamingAudio_FMODSTUDIO implementation
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/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;
}
//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(int pause);
/*virtual*/ void update();
/*virtual*/ int isPlaying();
/*virtual*/ void setGain(F32 vol);
/*virtual*/ F32 getGain();
/*virtual*/ std::string getURL();
/*virtual*/ bool supportsMetaData(){return true;}
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
/*virtual*/ bool supportsWaveData(){return false;}
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1);
/*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
/*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
private:
FMOD::System *mSystem;
LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp;
FMOD::Channel *mFMODInternetStreamChannelp;
std::list<LLAudioStreamManagerFMODSTUDIO *> mDeadStreams;
std::string mURL;
std::string mPendingURL;
F32 mGain;
LLSD *mMetaData;
};
#endif // LL_STREAMINGAUDIO_FMOD_H

View File

@@ -78,7 +78,7 @@ const F32 DEG_TO_RAD = 0.017453292519943295769236907684886f;
const F32 RAD_TO_DEG = 57.295779513082320876798154814105f;
const F32 F_APPROXIMATELY_ZERO = 0.00001f;
const F32 F_LN10 = 2.3025850929940456840179914546844f;
const F32 OO_LN10 = 0.43429448190325182765112891891661;
const F32 OO_LN10 = 0.4342944819032518276511289189166f;
const F32 F_LN2 = 0.69314718056f;
const F32 OO_LN2 = 1.4426950408889634073599246810019f;

View File

@@ -7,13 +7,12 @@ include(Boost)
include(DBusGlib)
include(DirectX)
include(ELFIO)
if(FMODSTUDIO)
include(FMODSTUDIO)
endif(FMODSTUDIO)
if(FMODEX)
include(FMODEX)
set(FMOD OFF)
endif(FMODEX)
if(FMOD)
include(FMOD)
endif(FMOD)
include(OPENAL)
include(FindOpenGL)
include(Hunspell)
@@ -1302,12 +1301,13 @@ if (WINDOWS)
winspool
)
if(FMODSTUDIO)
list(APPEND viewer_LIBRARIES ${FMODSTUDIO_LIBRARY})
endif(FMODSTUDIO)
if(FMODEX)
list(APPEND viewer_LIBRARIES ${FMODEX_LIBRARY})
endif(FMODEX)
if(FMOD)
list(APPEND viewer_LIBRARIES ${FMOD_LIBRARY})
endif(FMOD)
find_library(INTEL_MEMOPS_LIBRARY
NAMES ll_intel_memops
@@ -1407,37 +1407,15 @@ if (OPENAL)
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL")
endif (OPENAL)
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 (FMODSTUDIO)
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO")
set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY})
endif (FMODSTUDIO)
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})
set_target_properties(
fmodwrapper
PROPERTIES
BUILD_WITH_INSTALL_RPATH 1
INSTALL_NAME_DIR "@executable_path/../Resources"
LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp"
)
set(FMODWRAPPER_LIBRARY fmodwrapper)
target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
else (DARWIN AND FMOD)
# fmodwrapper unnecessary on linux or windows, for fmod and 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)
if (FMODEX)
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY})
endif (FMODEX)
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
@@ -1462,19 +1440,27 @@ set(PACKAGE OFF CACHE BOOL
if (WINDOWS)
set(release_flags "/MAPRelease/${VIEWER_BINARY_NAME}.map")
if (FMOD)
if (FMODSTUDIO)
if (WORD_SIZE EQUAL 32)
set(fmodstudio_dll_file "fmod.dll")
else (WORD_SIZE EQUAL 32)
set(fmodstudio_dll_file "fmod64.dll")
endif (WORD_SIZE EQUAL 32)
if(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMOD_BINARY_DIR}/fmod.dll")
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODSTUDIO_BINARY_DIR}/${fmodstudio_dll_file}")
else(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "--extra_libraries=${FMOD_BINARY_DIR}/fmod.dll")
set(MANIFEST_LIBRARIES "--extra_libraries=${FMODSTUDIO_BINARY_DIR}/${fmodstudio_dll_file}")
endif(MANIFEST_LIBRARIES)
endif (FMOD)
set(EXTRA_LINKER_FLAGS "/DELAYLOAD:${fmodstudio_dll_file}")
endif (FMODSTUDIO)
if (FMODEX)
if (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex.dll")
else (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex64.dll")
endif (WORD_SIZE EQUAL 32)
if (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex.dll")
else (WORD_SIZE EQUAL 32)
set(fmodex_dll_file "fmodex64.dll")
endif (WORD_SIZE EQUAL 32)
if(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_BINARY_DIR}/${fmodex_dll_file}")
@@ -1651,6 +1637,14 @@ if (LINUX)
set(product ${VIEWER_BRANDING_NAME_CAMELCASE}-${ARCH}-${viewer_VERSION})
if (FMODSTUDIO)
if(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODSTUDIO_LIBRARY}")
else(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "--extra_libraries=${FMODSTUDIO_LIBRARY}")
endif(MANIFEST_LIBRARIES)
endif (FMODSTUDIO)
if (FMODEX)
if(MANIFEST_LIBRARIES)
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_LIBRARY}")
@@ -1751,6 +1745,15 @@ if (DARWIN)
add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit basic_plugin_filepicker)
if (FMODSTUDIO)
add_custom_command(OUTPUT "${FMODSTUDIO_LIBRARY}"
COMMAND cp "${FMODSTUDIO_ORIG_LIBRARY}" "${FMODSTUDIO_LIBRARY}"
COMMAND install_name_tool -id "@executable_path/../Resources/libfmod.dylib" ${FMODSTUDIO_LIBRARY}
DEPENDS "${FMODSTUDIO_ORIG_LIBRARY}")
add_custom_target(fmodstudio_modified_library DEPENDS "${FMODSTUDIO_LIBRARY}")
add_dependencies(${VIEWER_BINARY_NAME} fmodstudio_modified_library)
endif (FMODSTUDIO)
if (FMODEX)
add_custom_command(OUTPUT "${FMODEX_LIBRARY}"
COMMAND cp "${FMODEX_ORIG_LIBRARY}" "${FMODEX_LIBRARY}"

View File

@@ -44,12 +44,13 @@
#include "llviewermedia_streamingaudio.h"
#include "llaudioengine.h"
#if LL_FMODEX
# include "llaudioengine_fmodex.h"
#if LL_FMODSTUDIO
# include "llaudioengine_fmodstudio.h"
#endif
#if LL_FMOD
# include "llaudioengine_fmod.h"
#if LL_FMODEX
# include "llaudioengine_fmodex.h"
#endif
#ifdef LL_OPENAL
@@ -415,6 +416,17 @@ void init_audio()
{
gAudiop = NULL;
#ifdef LL_FMODSTUDIO
if (!gAudiop
#if !LL_WINDOWS
&& NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER")
#endif // !LL_WINDOWS
)
{
gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("SHEnableFMODExProfiler"), gSavedSettings.getBOOL("SHEnableFMODEXVerboseDebugging"));
}
#endif
#ifdef LL_FMODEX
if (!gAudiop
#if !LL_WINDOWS
@@ -437,17 +449,6 @@ void init_audio()
}
#endif
#ifdef LL_FMOD
if (!gAudiop
#if !LL_WINDOWS
&& NULL == getenv("LL_BAD_FMOD_DRIVER")
#endif // !LL_WINDOWS
)
{
gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD();
}
#endif
if (gAudiop)
{
#if LL_WINDOWS