Add FMOD Studio support
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
83
indra/cmake/FMODSTUDIO.cmake
Normal file
83
indra/cmake/FMODSTUDIO.cmake
Normal 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)
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
1016
indra/llaudio/llaudioengine_fmodstudio.cpp
Normal file
1016
indra/llaudio/llaudioengine_fmodstudio.cpp
Normal file
File diff suppressed because it is too large
Load Diff
139
indra/llaudio/llaudioengine_fmodstudio.h
Normal file
139
indra/llaudio/llaudioengine_fmodstudio.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
141
indra/llaudio/lllistener_fmodstudio.cpp
Normal file
141
indra/llaudio/lllistener_fmodstudio.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
71
indra/llaudio/lllistener_fmodstudio.h
Normal file
71
indra/llaudio/lllistener_fmodstudio.h
Normal 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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
505
indra/llaudio/llstreamingaudio_fmodstudio.cpp
Normal file
505
indra/llaudio/llstreamingaudio_fmodstudio.cpp
Normal 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);
|
||||
}
|
||||
87
indra/llaudio/llstreamingaudio_fmodstudio.h
Normal file
87
indra/llaudio/llstreamingaudio_fmodstudio.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user