A stab at fmodex support on windows. To use, install 'FMOD Ex Programmers API' to its defualt program files directory, and run develop.py with -DFMODEX:BOOL=ON set. That /should/ be all it takes.
This commit is contained in:
@@ -35,7 +35,7 @@ set(cmake_SOURCE_FILES
|
|||||||
FindNDOF.cmake
|
FindNDOF.cmake
|
||||||
FindOpenJPEG.cmake
|
FindOpenJPEG.cmake
|
||||||
FindXmlRpcEpi.cmake
|
FindXmlRpcEpi.cmake
|
||||||
FMOD.cmake
|
FMOD.cmake
|
||||||
FreeType.cmake
|
FreeType.cmake
|
||||||
GStreamer010Plugin.cmake
|
GStreamer010Plugin.cmake
|
||||||
GooglePerfTools.cmake
|
GooglePerfTools.cmake
|
||||||
@@ -84,6 +84,10 @@ set(cmake_SOURCE_FILES
|
|||||||
ZLIB.cmake
|
ZLIB.cmake
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(FMODEX)
|
||||||
|
list(APPEND cmake_SOURCE_FILES FMODEX.cmake)
|
||||||
|
endif(FMODEX)
|
||||||
|
|
||||||
source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
|
source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
|
||||||
|
|
||||||
set(master_SOURCE_FILES
|
set(master_SOURCE_FILES
|
||||||
|
|||||||
@@ -243,12 +243,51 @@ set(all_targets ${all_targets} ${out_targets})
|
|||||||
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||||
set(release_files
|
set(release_files
|
||||||
libtcmalloc_minimal.dll
|
libtcmalloc_minimal.dll
|
||||||
fmod.dll
|
|
||||||
libhunspell.dll
|
libhunspell.dll
|
||||||
libapr-1.dll
|
libapr-1.dll
|
||||||
libaprutil-1.dll
|
libaprutil-1.dll
|
||||||
libapriconv-1.dll
|
libapriconv-1.dll
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(FMODEX)
|
||||||
|
find_path(FMODEX_BINARY_DIR fmodex.dll
|
||||||
|
${release_src_dir}
|
||||||
|
${FMODEX_SDK_DIR}/api
|
||||||
|
${FMODEX_SDK_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(FMODEX_BINARY_DIR)
|
||||||
|
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmodex.dll)
|
||||||
|
set(all_targets ${all_targets} ${out_targets})
|
||||||
|
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/ReleaseSSE2" out_targets fmodex.dll)
|
||||||
|
set(all_targets ${all_targets} ${out_targets})
|
||||||
|
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmodex.dll)
|
||||||
|
set(all_targets ${all_targets} ${out_targets})
|
||||||
|
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmodex.dll)
|
||||||
|
set(all_targets ${all_targets} ${out_targets})
|
||||||
|
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}/ReleaseSSE2" 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(
|
copy_if_different(
|
||||||
${release_src_dir}
|
${release_src_dir}
|
||||||
|
|||||||
83
indra/cmake/FMODEX.cmake
Normal file
83
indra/cmake/FMODEX.cmake
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# -*- cmake -*-
|
||||||
|
|
||||||
|
include(Linking)
|
||||||
|
|
||||||
|
if(INSTALL_PROPRIETARY)
|
||||||
|
include(Prebuilt)
|
||||||
|
use_prebuilt_binary(fmodex)
|
||||||
|
endif(INSTALL_PROPRIETARY)
|
||||||
|
|
||||||
|
find_library(FMODEX_LIBRARY_RELEASE
|
||||||
|
NAMES fmodex fmodex_vc fmodexL_vc
|
||||||
|
PATHS
|
||||||
|
${ARCH_PREBUILT_DIRS_RELEASE}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(FMODEX_LIBRARY_DEBUG
|
||||||
|
NAMES fmodex fmodex_vc fmodexL_vc
|
||||||
|
PATHS
|
||||||
|
${ARCH_PREBUILT_DIRS_DEBUG}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||||
|
set(FMODEX_LIBRARY
|
||||||
|
debug ${FMODEX_LIBRARY_DEBUG}
|
||||||
|
optimized ${FMODEX_LIBRARY_RELEASE})
|
||||||
|
elseif (FMODEX_LIBRARY_RELEASE)
|
||||||
|
set(FMODEX_LIBRARY ${FMODEX_LIBRARY_RELEASE})
|
||||||
|
endif (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||||
|
|
||||||
|
if (NOT FMODEX_LIBRARY)
|
||||||
|
set(FMODEX_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.")
|
||||||
|
if (FMODEX_SDK_DIR)
|
||||||
|
find_library(FMODEX_LIBRARY
|
||||||
|
fmodex fmodex_vc fmodexL_vc
|
||||||
|
PATHS
|
||||||
|
${FMODEX_SDK_DIR}/api/lib
|
||||||
|
${FMODEX_SDK_DIR}/api
|
||||||
|
${FMODEX_SDK_DIR}/lib
|
||||||
|
${FMODEX_SDK_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
endif(FMODEX_SDK_DIR)
|
||||||
|
if(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||||
|
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
|
||||||
|
find_library(FMODEX_LIBRARY
|
||||||
|
fmodex_vc fmodexL_vc
|
||||||
|
PATHS
|
||||||
|
${FMODEX_PROG_DIR}/api/lib
|
||||||
|
${FMODEX_PROG_DIR}/api
|
||||||
|
${FMODEX_PROG_DIR}
|
||||||
|
)
|
||||||
|
if(FMODEX_LIBRARY)
|
||||||
|
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
|
||||||
|
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR})
|
||||||
|
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR} CACHE PATH "Path to the FMOD Ex SDK." FORCE)
|
||||||
|
endif(FMODEX_LIBRARY)
|
||||||
|
endif(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||||
|
endif (NOT FMODEX_LIBRARY)
|
||||||
|
|
||||||
|
find_path(FMODEX_INCLUDE_DIR fmod.h
|
||||||
|
${LIBS_PREBUILT_DIR}/include/fmodex
|
||||||
|
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/fmodex
|
||||||
|
${FMODEX_SDK_DIR}/api/inc
|
||||||
|
${FMODEX_SDK_DIR}/inc
|
||||||
|
${FMODEX_SDK_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||||
|
set(FMODEX ON CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||||
|
else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||||
|
set(FMODEX_LIBRARY "")
|
||||||
|
set(FMODEX_INCLUDE_DIR "")
|
||||||
|
if (FMODEX)
|
||||||
|
message(STATUS "No support for FMOD Ex audio (need to set FMODEX_SDK_DIR?)")
|
||||||
|
endif (FMODEX)
|
||||||
|
set(FMODEX OFF CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||||
|
set(FMODEX OFF)
|
||||||
|
endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||||
|
|
||||||
|
if (FMODEX)
|
||||||
|
message(STATUS "Building with FMOD Ex audio support")
|
||||||
|
endif (FMODEX)
|
||||||
@@ -5,16 +5,30 @@ project(llaudio)
|
|||||||
include(00-Common)
|
include(00-Common)
|
||||||
include(Audio)
|
include(Audio)
|
||||||
include(LLAudio)
|
include(LLAudio)
|
||||||
include(FMOD)
|
if(FMODEX)
|
||||||
|
include(FMODEX)
|
||||||
|
if(FMODEX)
|
||||||
|
set(FMOD OFF)
|
||||||
|
endif(FMODEX)
|
||||||
|
endif(FMODEX)
|
||||||
|
if(NOT FMODEX)
|
||||||
|
include(FMOD)
|
||||||
|
endif(NOT FMODEX)
|
||||||
include(OPENAL)
|
include(OPENAL)
|
||||||
include(LLCommon)
|
include(LLCommon)
|
||||||
include(LLMath)
|
include(LLMath)
|
||||||
include(LLMessage)
|
include(LLMessage)
|
||||||
include(LLVFS)
|
include(LLVFS)
|
||||||
|
|
||||||
|
if(FMODEX)
|
||||||
|
include_directories(${FMODEX_INCLUDE_DIR})
|
||||||
|
endif(FMODEX)
|
||||||
|
if(FMOD)
|
||||||
|
include_directories(${FMOD_INCLUDE_DIR})
|
||||||
|
endif(FMOD)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${LLAUDIO_INCLUDE_DIRS}
|
${LLAUDIO_INCLUDE_DIRS}
|
||||||
${FMOD_INCLUDE_DIR}
|
|
||||||
${LLCOMMON_INCLUDE_DIRS}
|
${LLCOMMON_INCLUDE_DIRS}
|
||||||
${LLMATH_INCLUDE_DIRS}
|
${LLMATH_INCLUDE_DIRS}
|
||||||
${LLMESSAGE_INCLUDE_DIRS}
|
${LLMESSAGE_INCLUDE_DIRS}
|
||||||
@@ -46,6 +60,19 @@ set(llaudio_HEADER_FILES
|
|||||||
llwindgen.h
|
llwindgen.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (FMODEX)
|
||||||
|
list(APPEND llaudio_SOURCE_FILES
|
||||||
|
llaudioengine_fmodex.cpp
|
||||||
|
lllistener_fmodex.cpp
|
||||||
|
llstreamingaudio_fmodex.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND llaudio_HEADER_FILES
|
||||||
|
llaudioengine_fmodex.h
|
||||||
|
lllistener_fmodex.h
|
||||||
|
llstreamingaudio_fmodex.h
|
||||||
|
)
|
||||||
|
endif (FMODEX)
|
||||||
if (FMOD)
|
if (FMOD)
|
||||||
list(APPEND llaudio_SOURCE_FILES
|
list(APPEND llaudio_SOURCE_FILES
|
||||||
llaudioengine_fmod.cpp
|
llaudioengine_fmod.cpp
|
||||||
|
|||||||
840
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
840
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
@@ -0,0 +1,840 @@
|
|||||||
|
/**
|
||||||
|
* @file audioengine_FMODEX.cpp
|
||||||
|
* @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "linden_common.h"
|
||||||
|
|
||||||
|
#include "llstreamingaudio.h"
|
||||||
|
#include "llstreamingaudio_fmodex.h"
|
||||||
|
|
||||||
|
#include "llaudioengine_fmodex.h"
|
||||||
|
#include "lllistener_fmodex.h"
|
||||||
|
|
||||||
|
#include "llerror.h"
|
||||||
|
#include "llmath.h"
|
||||||
|
#include "llrand.h"
|
||||||
|
|
||||||
|
#include "fmod.hpp"
|
||||||
|
#include "fmod_errors.h"
|
||||||
|
#include "lldir.h"
|
||||||
|
#include "llapr.h"
|
||||||
|
|
||||||
|
#include "sound_ids.h"
|
||||||
|
|
||||||
|
#if LL_WINDOWS //Some ugly code to make missing fmodex.dll not cause a fatal error.
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include "windows.h"
|
||||||
|
#include <DelayImp.h>
|
||||||
|
#pragma comment(lib, "delayimp.lib")
|
||||||
|
|
||||||
|
bool attemptDelayLoad()
|
||||||
|
{
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||||
|
|
||||||
|
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX()
|
||||||
|
{
|
||||||
|
mInited = false;
|
||||||
|
mWindGen = NULL;
|
||||||
|
mWindDSP = NULL;
|
||||||
|
mSystem = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||||
|
{
|
||||||
|
if(result == FMOD_OK)
|
||||||
|
return false;
|
||||||
|
llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if LL_WINDOWS
|
||||||
|
if(!attemptDelayLoad())
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
U32 version;
|
||||||
|
FMOD_RESULT result;
|
||||||
|
int numdrivers;
|
||||||
|
FMOD_SPEAKERMODE speakermode;
|
||||||
|
FMOD_CAPS caps;
|
||||||
|
char name[256];
|
||||||
|
|
||||||
|
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL;
|
||||||
|
|
||||||
|
result = FMOD::System_Create(&mSystem);
|
||||||
|
if(Check_FMOD_Error(result, "FMOD::System_Create"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer.
|
||||||
|
LLAudioEngine::init(num_channels, userdata);
|
||||||
|
|
||||||
|
result = mSystem->getVersion(&version);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::getVersion");
|
||||||
|
|
||||||
|
if (version < FMOD_VERSION)
|
||||||
|
{
|
||||||
|
LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
|
||||||
|
<< ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LL_WINDOWS
|
||||||
|
//Is this block applicable to linux?
|
||||||
|
{
|
||||||
|
result = mSystem->getNumDrivers(&numdrivers);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::getNumDrivers");
|
||||||
|
if (numdrivers == 0)
|
||||||
|
{
|
||||||
|
result = mSystem->setOutput(FMOD_OUTPUTTYPE_NOSOUND);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::setOutput");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = mSystem->getDriverCaps(0, &caps, 0, &speakermode);
|
||||||
|
Check_FMOD_Error(result,"FMOD::System::getDriverCaps");
|
||||||
|
/*
|
||||||
|
Set the user selected speaker mode.
|
||||||
|
*/
|
||||||
|
result = mSystem->setSpeakerMode(speakermode);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::getDriverCaps");
|
||||||
|
if (caps & FMOD_CAPS_HARDWARE_EMULATED)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The user has the 'Acceleration' slider set to off! This is really bad
|
||||||
|
for latency! You might want to warn the user about this.
|
||||||
|
*/
|
||||||
|
result = mSystem->setDSPBufferSize(1024, 10);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::setDSPBufferSize");
|
||||||
|
}
|
||||||
|
result = mSystem->getDriverInfo(0, name, 256, 0);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::getDriverInfo");
|
||||||
|
if (strstr(name, "SigmaTel"))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Sigmatel sound devices crackle for some reason if the format is PCM 16bit.
|
||||||
|
PCM floating point output seems to solve it.
|
||||||
|
*/
|
||||||
|
result = mSystem->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0, FMOD_DSP_RESAMPLER_LINEAR);
|
||||||
|
Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //LL_WINDOWS
|
||||||
|
|
||||||
|
// Reserve one extra channel for the http stream.
|
||||||
|
result = mSystem->setHardwareChannels(num_channels + 1);
|
||||||
|
Check_FMOD_Error(result,"FMOD::System::setHardwareChannels");
|
||||||
|
|
||||||
|
U32 fmod_flags = FMOD_INIT_NORMAL;
|
||||||
|
|
||||||
|
#if LL_LINUX
|
||||||
|
// 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_FMODEX_ESD")) /*Flawfinder: ignore*/
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
|
||||||
|
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ESD) == FMOD_OK &&
|
||||||
|
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY" << LL_ENDL;
|
||||||
|
audio_ok = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Check_FMOD_Error(result, "ESD audio output FAILED to initialize");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!audio_ok)
|
||||||
|
{
|
||||||
|
if (NULL == getenv("LL_BAD_FMODEX_OSS")) /*Flawfinder: ignore*/
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL;
|
||||||
|
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK &&
|
||||||
|
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
|
||||||
|
audio_ok = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Check_FMOD_Error(result, "OSS audio output FAILED to initialize" << LL_ENDL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!audio_ok)
|
||||||
|
{
|
||||||
|
if (NULL == getenv("LL_BAD_FMODEX_ALSA")) /*Flawfinder: ignore*/
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
|
||||||
|
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ALSA) &&
|
||||||
|
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
|
||||||
|
audio_ok = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Check_FMOD_Error(result, "ALSA audio output FAILED to initialize");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
LL_DEBUGS("AppInit") << "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.
|
||||||
|
FMOD_OUTPUTTYPE output_type;
|
||||||
|
mSystem->getOutput(output_type);
|
||||||
|
switch (output_type)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
result = mSystem->init( num_channels, fmod_flags, 0);
|
||||||
|
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Ok, the speaker mode selected isn't supported by this soundcard. Switch it
|
||||||
|
back to stereo...
|
||||||
|
*/
|
||||||
|
result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
||||||
|
Check_FMOD_Error(result,"Error falling back to stereo mode");
|
||||||
|
/*
|
||||||
|
... and re-init.
|
||||||
|
*/
|
||||||
|
result = mSystem->init(100, FMOD_INIT_NORMAL, 0);
|
||||||
|
}
|
||||||
|
if(Check_FMOD_Error(result, "Error initializing FMOD"))
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||||
|
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||||
|
setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
|
||||||
|
|
||||||
|
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD initialized correctly" << LL_ENDL;
|
||||||
|
|
||||||
|
mInited = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string LLAudioEngine_FMODEX::getDriverName(bool verbose)
|
||||||
|
{
|
||||||
|
llassert_always(mSystem);
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
U32 version;
|
||||||
|
if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion"))
|
||||||
|
{
|
||||||
|
return llformat("FMOD version %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "FMOD";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioEngine_FMODEX::allocateListener(void)
|
||||||
|
{
|
||||||
|
mListenerp = (LLListener *) new LLListener_FMODEX(mSystem);
|
||||||
|
if (!mListenerp)
|
||||||
|
{
|
||||||
|
llwarns << "Listener creation failed" << llendl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioEngine_FMODEX::shutdown()
|
||||||
|
{
|
||||||
|
stopInternetStream();
|
||||||
|
|
||||||
|
LLAudioEngine::shutdown();
|
||||||
|
|
||||||
|
llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD" << llendl;
|
||||||
|
mSystem->close();
|
||||||
|
mSystem->release();
|
||||||
|
llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD" << llendl;
|
||||||
|
|
||||||
|
delete mListenerp;
|
||||||
|
mListenerp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer()
|
||||||
|
{
|
||||||
|
return new LLAudioBufferFMODEX(mSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLAudioChannel * LLAudioEngine_FMODEX::createChannel()
|
||||||
|
{
|
||||||
|
return new LLAudioChannelFMODEX(mSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLAudioEngine_FMODEX::initWind()
|
||||||
|
{
|
||||||
|
if (!mWindGen)
|
||||||
|
{
|
||||||
|
int samplerate;
|
||||||
|
FMOD_SOUND_FORMAT format;
|
||||||
|
mSystem->getSoftwareFormat(&samplerate,&format,NULL,NULL,NULL,NULL);
|
||||||
|
|
||||||
|
//May need to check format. eg, PCM16 may require 16bit LLWindGen.
|
||||||
|
|
||||||
|
/*bool enable;
|
||||||
|
|
||||||
|
FMOD_SOUND_FORMAT format;
|
||||||
|
mSystem->getFormat(0,&format,0,0);
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
mWindGen = new LLWindGen<MIXBUFFERFORMAT>(samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
mNextWindUpdate = 0.0;
|
||||||
|
|
||||||
|
if (!mWindDSP)
|
||||||
|
{
|
||||||
|
FMOD_DSP_DESCRIPTION dspdesc;
|
||||||
|
memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
|
||||||
|
strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
|
||||||
|
dspdesc.read = &windCallback; //Assign callback.
|
||||||
|
dspdesc.userdata = (void*)mWindGen;
|
||||||
|
Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP");
|
||||||
|
}
|
||||||
|
if (mWindDSP)
|
||||||
|
{
|
||||||
|
mSystem->addDSP(mWindDSP, NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioEngine_FMODEX::cleanupWind()
|
||||||
|
{
|
||||||
|
if (mWindDSP)
|
||||||
|
{
|
||||||
|
mWindDSP->remove();
|
||||||
|
mWindDSP->release();
|
||||||
|
mWindDSP = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete mWindGen;
|
||||||
|
mWindGen = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
|
||||||
|
{
|
||||||
|
LLVector3 wind_pos;
|
||||||
|
F64 pitch;
|
||||||
|
F64 center_freq;
|
||||||
|
|
||||||
|
if (!mEnableWind)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
|
||||||
|
{
|
||||||
|
|
||||||
|
// wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
|
||||||
|
// need to convert this to the conventional orientation DS3D and OpenAL use
|
||||||
|
// where +X = right, +Y = up, +Z = backwards
|
||||||
|
|
||||||
|
wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
|
||||||
|
|
||||||
|
// cerr << "Wind update" << endl;
|
||||||
|
|
||||||
|
pitch = 1.0 + mapWindVecToPitch(wind_vec);
|
||||||
|
center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
|
||||||
|
|
||||||
|
mWindGen->mTargetFreq = (F32)center_freq;
|
||||||
|
mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
|
||||||
|
mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLAudioEngine_FMODEX::setInternalGain(F32 gain)
|
||||||
|
{
|
||||||
|
if (!mInited)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gain = llclamp( gain, 0.0f, 1.0f );
|
||||||
|
|
||||||
|
FMOD::ChannelGroup *master_group;
|
||||||
|
mSystem->getMasterChannelGroup(&master_group);
|
||||||
|
|
||||||
|
master_group->setVolume(gain);
|
||||||
|
|
||||||
|
LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
|
||||||
|
if ( saimpl )
|
||||||
|
{
|
||||||
|
// fmod likes its streaming audio channel gain re-asserted after
|
||||||
|
// master volume change.
|
||||||
|
saimpl->setGain(saimpl->getGain());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// LLAudioChannelFMODEX implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystem(system), mChannelp(NULL), mLastSamplePos(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLAudioChannelFMODEX::~LLAudioChannelFMODEX()
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LLAudioChannelFMODEX::updateBuffer()
|
||||||
|
{
|
||||||
|
if (LLAudioChannel::updateBuffer())
|
||||||
|
{
|
||||||
|
// Base class update returned true, which means that we need to actually
|
||||||
|
// set up the channel for a different buffer.
|
||||||
|
|
||||||
|
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer();
|
||||||
|
|
||||||
|
// Grab the FMOD sample associated with the buffer
|
||||||
|
FMOD::Sound *soundp = bufferp->getSound();
|
||||||
|
if (!soundp)
|
||||||
|
{
|
||||||
|
// This is bad, there should ALWAYS be a sound associated with a legit
|
||||||
|
// buffer.
|
||||||
|
llerrs << "No FMOD sound!" << llendl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Actually play the sound. Start it off paused so we can do all the necessary
|
||||||
|
// setup.
|
||||||
|
FMOD_RESULT result = mSystem->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::playSound");
|
||||||
|
|
||||||
|
//llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a source for the channel, we need to update its gain.
|
||||||
|
if (mCurrentSourcep)
|
||||||
|
{
|
||||||
|
// SJB: warnings can spam and hurt framerate, disabling
|
||||||
|
U32 result;
|
||||||
|
|
||||||
|
result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
|
||||||
|
//Check_FMOD_Error(result, "LLAudioChannelFMODEX::updateBuffer");
|
||||||
|
|
||||||
|
result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
|
||||||
|
/*if(Check_FMOD_ERROR(result, "LLAudioChannelFMODEX::updateBuffer"))
|
||||||
|
{
|
||||||
|
S32 index;
|
||||||
|
mChannelp->getIndex(&index);
|
||||||
|
llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
|
||||||
|
<< " at " << mCurrentSourcep->getPositionGlobal() << llendl;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioChannelFMODEX::update3DPosition()
|
||||||
|
{
|
||||||
|
if (!mChannelp)
|
||||||
|
{
|
||||||
|
// We're not actually a live channel (i.e., we're not playing back anything)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp;
|
||||||
|
if (!bufferp)
|
||||||
|
{
|
||||||
|
// We don't have a buffer associated with us (should really have been picked up
|
||||||
|
// by the above if.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrentSourcep->isAmbient())
|
||||||
|
{
|
||||||
|
// Ambient sound, don't need to do any positional updates.
|
||||||
|
set3DMode(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Localized sound. Update the position and velocity of the sound.
|
||||||
|
set3DMode(true);
|
||||||
|
|
||||||
|
LLVector3 float_pos;
|
||||||
|
float_pos.setVec(mCurrentSourcep->getPositionGlobal());
|
||||||
|
FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV);
|
||||||
|
Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioChannelFMODEX::updateLoop()
|
||||||
|
{
|
||||||
|
if (!mChannelp)
|
||||||
|
{
|
||||||
|
// May want to clear up the loop/sample counters.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Hack: We keep track of whether we looped or not by seeing when the
|
||||||
|
// sample position looks like it's going backwards. Not reliable; may
|
||||||
|
// yield false negatives.
|
||||||
|
//
|
||||||
|
U32 cur_pos;
|
||||||
|
mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES);
|
||||||
|
|
||||||
|
if (cur_pos < (U32)mLastSamplePos)
|
||||||
|
{
|
||||||
|
mLoopedThisFrame = true;
|
||||||
|
}
|
||||||
|
mLastSamplePos = cur_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioChannelFMODEX::cleanup()
|
||||||
|
{
|
||||||
|
if (!mChannelp)
|
||||||
|
{
|
||||||
|
//llinfos << "Aborting cleanup with no channel handle." << llendl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//llinfos << "Cleaning up channel: " << mChannelID << llendl;
|
||||||
|
Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
|
||||||
|
|
||||||
|
mCurrentBufferp = NULL;
|
||||||
|
mChannelp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioChannelFMODEX::play()
|
||||||
|
{
|
||||||
|
if (!mChannelp)
|
||||||
|
{
|
||||||
|
llwarns << "Playing without a channel handle, aborting" << llendl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
|
||||||
|
|
||||||
|
getSource()->setPlayedOnce(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp)
|
||||||
|
{
|
||||||
|
LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp;
|
||||||
|
if (!(fmod_channelp->mChannelp && mChannelp))
|
||||||
|
{
|
||||||
|
// Don't have channels allocated to both the master and the slave
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 cur_pos;
|
||||||
|
if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cur_pos %= mCurrentBufferp->getLength();
|
||||||
|
|
||||||
|
// Try to match the position of our sync master
|
||||||
|
Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position");
|
||||||
|
|
||||||
|
// Start us playing
|
||||||
|
play();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LLAudioChannelFMODEX::isPlaying()
|
||||||
|
{
|
||||||
|
if (!mChannelp)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool paused, playing;
|
||||||
|
mChannelp->getPaused(&paused);
|
||||||
|
mChannelp->isPlaying(&playing);
|
||||||
|
return !paused && playing;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// LLAudioChannelFMODEX implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystem(system), mSoundp(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLAudioBufferFMODEX::~LLAudioBufferFMODEX()
|
||||||
|
{
|
||||||
|
if(mSoundp)
|
||||||
|
{
|
||||||
|
mSoundp->release();
|
||||||
|
mSoundp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
|
||||||
|
{
|
||||||
|
// Try to open a wav file from disk. This will eventually go away, as we don't
|
||||||
|
// really want to block doing this.
|
||||||
|
if (filename.empty())
|
||||||
|
{
|
||||||
|
// invalid filename, abort.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!LLAPRFile::isExist(filename, LL_APR_RPB))
|
||||||
|
{
|
||||||
|
// File not found, abort.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSoundp)
|
||||||
|
{
|
||||||
|
// If there's already something loaded in this buffer, clean it up.
|
||||||
|
mSoundp->release();
|
||||||
|
mSoundp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool creation_attempted = false;
|
||||||
|
FMOD_RESULT result = FMOD_OK;
|
||||||
|
|
||||||
|
FMOD_MODE base_mode = FMOD_SOFTWARE | FMOD_LOOP_NORMAL;
|
||||||
|
|
||||||
|
// 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...
|
||||||
|
|
||||||
|
FMOD_CREATESOUNDEXINFO info;
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.cbsize = sizeof(info);
|
||||||
|
info.length = file_length;
|
||||||
|
result = mSystem->createSound(buffer, base_mode | FMOD_OPENMEMORY , &info, &mSoundp);
|
||||||
|
creation_attempted = true;
|
||||||
|
}
|
||||||
|
delete[] buffer;
|
||||||
|
fclose(sound_file);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
result = mSystem->createSound(filename.c_str(), base_mode, 0, &mSoundp);
|
||||||
|
creation_attempted = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (creation_attempted && result != FMOD_OK)
|
||||||
|
{
|
||||||
|
// We failed to load the file for some reason.
|
||||||
|
llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
|
||||||
|
|
||||||
|
//
|
||||||
|
// If we EVER want to load wav files provided by end users, we need
|
||||||
|
// to rethink this!
|
||||||
|
//
|
||||||
|
// file is probably corrupt - remove it.
|
||||||
|
LLFile::remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything went well, return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
U32 LLAudioBufferFMODEX::getLength()
|
||||||
|
{
|
||||||
|
if (!mSoundp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 length;
|
||||||
|
mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLAudioChannelFMODEX::set3DMode(bool use3d)
|
||||||
|
{
|
||||||
|
FMOD_MODE current_mode;
|
||||||
|
if(mChannelp->getMode(¤t_mode) != FMOD_OK)
|
||||||
|
return;
|
||||||
|
FMOD_MODE new_mode = current_mode;
|
||||||
|
new_mode &= ~(use3d ? FMOD_2D : FMOD_3D);
|
||||||
|
new_mode |= use3d ? FMOD_3D : FMOD_2D;
|
||||||
|
|
||||||
|
if(current_mode != new_mode)
|
||||||
|
{
|
||||||
|
mChannelp->setMode(new_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels)
|
||||||
|
{
|
||||||
|
// originalbuffer = fmod's original mixbuffer.
|
||||||
|
// newbuffer = the buffer passed from the previous DSP unit.
|
||||||
|
// length = length in samples at this mix time.
|
||||||
|
// userdata = user parameter passed through in FSOUND_DSP_Create.
|
||||||
|
|
||||||
|
LLWindGen<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *windgen;
|
||||||
|
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
|
||||||
|
|
||||||
|
thisdsp->getUserData((void **)&windgen);
|
||||||
|
S32 channels, configwidth, configheight;
|
||||||
|
thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight);
|
||||||
|
|
||||||
|
windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length);
|
||||||
|
|
||||||
|
return FMOD_OK;
|
||||||
|
}
|
||||||
132
indra/llaudio/llaudioengine_fmodex.h
Normal file
132
indra/llaudio/llaudioengine_fmodex.h
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* @file audioengine_FMODEX.h
|
||||||
|
* @brief Definition of LLAudioEngine class abstracting the audio
|
||||||
|
* support as a FMOD 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_FMODEX_H
|
||||||
|
#define LL_AUDIOENGINE_FMODEX_H
|
||||||
|
|
||||||
|
#include "llaudioengine.h"
|
||||||
|
#include "lllistener_fmod.h"
|
||||||
|
#include "llwindgen.h"
|
||||||
|
|
||||||
|
//Stubs
|
||||||
|
class LLAudioStreamManagerFMODEX;
|
||||||
|
namespace FMOD
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
class Channel;
|
||||||
|
class Sound;
|
||||||
|
class DSP;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Interfaces
|
||||||
|
class LLAudioEngine_FMODEX : public LLAudioEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLAudioEngine_FMODEX();
|
||||||
|
virtual ~LLAudioEngine_FMODEX();
|
||||||
|
|
||||||
|
// initialization/startup/shutdown
|
||||||
|
virtual bool init(const S32 num_channels, void *user_data);
|
||||||
|
virtual std::string getDriverName(bool verbose);
|
||||||
|
virtual void allocateListener();
|
||||||
|
|
||||||
|
virtual void shutdown();
|
||||||
|
|
||||||
|
/*virtual*/ bool initWind();
|
||||||
|
/*virtual*/ void cleanupWind();
|
||||||
|
|
||||||
|
/*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
|
||||||
|
|
||||||
|
typedef F32 MIXBUFFERFORMAT;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// On Windows, userdata is the HWND of the application window.
|
||||||
|
void* mUserData;
|
||||||
|
|
||||||
|
LLWindGen<MIXBUFFERFORMAT> *mWindGen;
|
||||||
|
|
||||||
|
FMOD::DSP *mWindDSP;
|
||||||
|
FMOD::System *mSystem;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LLAudioChannelFMODEX : public LLAudioChannel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLAudioChannelFMODEX(FMOD::System *system);
|
||||||
|
virtual ~LLAudioChannelFMODEX();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*virtual*/ void play();
|
||||||
|
/*virtual*/ void playSynced(LLAudioChannel *channelp);
|
||||||
|
/*virtual*/ void cleanup();
|
||||||
|
/*virtual*/ bool isPlaying();
|
||||||
|
|
||||||
|
/*virtual*/ bool updateBuffer();
|
||||||
|
/*virtual*/ void update3DPosition();
|
||||||
|
/*virtual*/ void updateLoop();
|
||||||
|
|
||||||
|
void set3DMode(bool use3d);
|
||||||
|
protected:
|
||||||
|
FMOD::System *mSystem;
|
||||||
|
FMOD::Channel *mChannelp;
|
||||||
|
S32 mLastSamplePos;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LLAudioBufferFMODEX : public LLAudioBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLAudioBufferFMODEX(FMOD::System *system);
|
||||||
|
virtual ~LLAudioBufferFMODEX();
|
||||||
|
|
||||||
|
/*virtual*/ bool loadWAV(const std::string& filename);
|
||||||
|
/*virtual*/ U32 getLength();
|
||||||
|
friend class LLAudioChannelFMODEX;
|
||||||
|
|
||||||
|
void set3DMode(bool use3d);
|
||||||
|
protected:
|
||||||
|
FMOD::Sound *getSound() { return mSoundp; }
|
||||||
|
FMOD::System *mSystem;
|
||||||
|
FMOD::Sound *mSoundp;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LL_AUDIOENGINE_FMODEX_H
|
||||||
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* @file listener_fmod.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_fmodex.h"
|
||||||
|
#include "fmod.hpp"
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
// constructor
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
|
||||||
|
{
|
||||||
|
mSystem = system;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
LLListener_FMODEX::~LLListener_FMODEX()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLListener_FMODEX::init(void)
|
||||||
|
{
|
||||||
|
// do inherited
|
||||||
|
LLListener::init();
|
||||||
|
mDopplerFactor = 1.0f;
|
||||||
|
mRolloffFactor = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLListener_FMODEX::translate(LLVector3 offset)
|
||||||
|
{
|
||||||
|
LLListener::translate(offset);
|
||||||
|
|
||||||
|
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLListener_FMODEX::setPosition(LLVector3 pos)
|
||||||
|
{
|
||||||
|
LLListener::setPosition(pos);
|
||||||
|
|
||||||
|
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLListener_FMODEX::setVelocity(LLVector3 vel)
|
||||||
|
{
|
||||||
|
LLListener::setVelocity(vel);
|
||||||
|
|
||||||
|
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
|
||||||
|
{
|
||||||
|
LLListener::orient(up, at);
|
||||||
|
|
||||||
|
// Welcome to the transition between right and left
|
||||||
|
// (coordinate systems, that is)
|
||||||
|
// Leaving the at vector alone results in a L/R reversal
|
||||||
|
// since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
|
||||||
|
at = -at;
|
||||||
|
|
||||||
|
mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void LLListener_FMODEX::commitDeferredChanges()
|
||||||
|
{
|
||||||
|
mSystem->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLListener_FMODEX::setRolloffFactor(F32 factor)
|
||||||
|
{
|
||||||
|
mRolloffFactor = factor;
|
||||||
|
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
F32 LLListener_FMODEX::getRolloffFactor()
|
||||||
|
{
|
||||||
|
return mRolloffFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLListener_FMODEX::setDopplerFactor(F32 factor)
|
||||||
|
{
|
||||||
|
mDopplerFactor = factor;
|
||||||
|
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
F32 LLListener_FMODEX::getDopplerFactor()
|
||||||
|
{
|
||||||
|
return mDopplerFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
71
indra/llaudio/lllistener_fmodex.h
Normal file
71
indra/llaudio/lllistener_fmodex.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* @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=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_FMODEX_H
|
||||||
|
#define LL_LISTENER_FMODEX_H
|
||||||
|
|
||||||
|
#include "lllistener.h"
|
||||||
|
|
||||||
|
//Stubs
|
||||||
|
namespace FMOD
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Interfaces
|
||||||
|
class LLListener_FMODEX : public LLListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLListener_FMODEX(FMOD::System *system);
|
||||||
|
virtual ~LLListener_FMODEX();
|
||||||
|
virtual void init();
|
||||||
|
|
||||||
|
virtual void translate(LLVector3 offset);
|
||||||
|
virtual void setPosition(LLVector3 pos);
|
||||||
|
virtual void setVelocity(LLVector3 vel);
|
||||||
|
virtual void orient(LLVector3 up, LLVector3 at);
|
||||||
|
virtual void commitDeferredChanges();
|
||||||
|
|
||||||
|
virtual void setDopplerFactor(F32 factor);
|
||||||
|
virtual F32 getDopplerFactor();
|
||||||
|
virtual void setRolloffFactor(F32 factor);
|
||||||
|
virtual F32 getRolloffFactor();
|
||||||
|
protected:
|
||||||
|
FMOD::System *mSystem;
|
||||||
|
F32 mDopplerFactor;
|
||||||
|
F32 mRolloffFactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
422
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
422
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
/**
|
||||||
|
* @file streamingaudio_fmod.cpp
|
||||||
|
* @brief LLStreamingAudio_FMODEX 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_fmodex.h"
|
||||||
|
|
||||||
|
|
||||||
|
class LLAudioStreamManagerFMODEX
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
|
||||||
|
FMOD::Channel* startStream();
|
||||||
|
bool stopStream(); // Returns true if the stream was successfully stopped.
|
||||||
|
bool ready();
|
||||||
|
|
||||||
|
const std::string& getURL() { return mInternetStreamURL; }
|
||||||
|
|
||||||
|
FMOD_OPENSTATE getOpenState();
|
||||||
|
protected:
|
||||||
|
FMOD::System* mSystem;
|
||||||
|
FMOD::Channel* mStreamChannel;
|
||||||
|
FMOD::Sound* mInternetStream;
|
||||||
|
bool mReady;
|
||||||
|
|
||||||
|
std::string mInternetStreamURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Internet Streaming
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
|
||||||
|
mSystem(system),
|
||||||
|
mCurrentInternetStreamp(NULL),
|
||||||
|
mFMODInternetStreamChannelp(NULL),
|
||||||
|
mGain(1.0f),
|
||||||
|
mMetaData(NULL)
|
||||||
|
{
|
||||||
|
// Number of milliseconds of audio to buffer for the audio card.
|
||||||
|
// Must be larger than the usual Second Life frame stutter time.
|
||||||
|
mSystem->setStreamBufferSize(200, FMOD_TIMEUNIT_MS);
|
||||||
|
|
||||||
|
// Here's where we set the size of the network buffer and some buffering
|
||||||
|
// parameters. In this case we want a network buffer of 16k, we want it
|
||||||
|
// to prebuffer 40% of that when we first connect, and we want it
|
||||||
|
// to rebuffer 80% of that whenever we encounter a buffer underrun.
|
||||||
|
|
||||||
|
// Leave the net buffer properties at the default.
|
||||||
|
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
|
||||||
|
{
|
||||||
|
// nothing interesting/safe to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLStreamingAudio_FMODEX::start(const std::string& url)
|
||||||
|
{
|
||||||
|
//if (!mInited)
|
||||||
|
//{
|
||||||
|
// llwarns << "startInternetStream before audio initialized" << llendl;
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
|
||||||
|
stop();
|
||||||
|
|
||||||
|
if (!url.empty())
|
||||||
|
{
|
||||||
|
llinfos << "Starting internet stream: " << url << llendl;
|
||||||
|
mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
|
||||||
|
mURL = url;
|
||||||
|
mMetaData = new LLSD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
llinfos << "Set internet stream to null" << llendl;
|
||||||
|
mURL.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLStreamingAudio_FMODEX::update()
|
||||||
|
{
|
||||||
|
// Kill dead internet streams, if possible
|
||||||
|
std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
|
||||||
|
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
|
||||||
|
{
|
||||||
|
LLAudioStreamManagerFMODEX *streamp = *iter;
|
||||||
|
if (streamp->stopStream())
|
||||||
|
{
|
||||||
|
llinfos << "Closed dead stream" << llendl;
|
||||||
|
delete streamp;
|
||||||
|
mDeadStreams.erase(iter++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't do anything if there are no streams playing
|
||||||
|
if (!mCurrentInternetStreamp)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState();
|
||||||
|
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLStreamingAudio_FMODEX::stop()
|
||||||
|
{
|
||||||
|
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_FMODEX::pause(int pauseopt)
|
||||||
|
{
|
||||||
|
if (pauseopt < 0)
|
||||||
|
{
|
||||||
|
pauseopt = mCurrentInternetStreamp ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pauseopt)
|
||||||
|
{
|
||||||
|
if (mCurrentInternetStreamp)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
start(getURL());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A stream is "playing" if it has been requested to start. That
|
||||||
|
// doesn't necessarily mean audio is coming out of the speakers.
|
||||||
|
int LLStreamingAudio_FMODEX::isPlaying()
|
||||||
|
{
|
||||||
|
if (mCurrentInternetStreamp)
|
||||||
|
{
|
||||||
|
return 1; // Active and playing
|
||||||
|
}
|
||||||
|
else if (!mURL.empty())
|
||||||
|
{
|
||||||
|
return 2; // "Paused"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
F32 LLStreamingAudio_FMODEX::getGain()
|
||||||
|
{
|
||||||
|
return mGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string LLStreamingAudio_FMODEX::getURL()
|
||||||
|
{
|
||||||
|
return mURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LLStreamingAudio_FMODEX::setGain(F32 vol)
|
||||||
|
{
|
||||||
|
mGain = vol;
|
||||||
|
|
||||||
|
if (mFMODInternetStreamChannelp)
|
||||||
|
{
|
||||||
|
vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
|
||||||
|
|
||||||
|
mFMODInternetStreamChannelp->setVolume(vol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
// manager of possibly-multiple internet audio streams
|
||||||
|
|
||||||
|
LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
|
||||||
|
mSystem(system),
|
||||||
|
mStreamChannel(NULL),
|
||||||
|
mInternetStream(NULL),
|
||||||
|
mReady(false)
|
||||||
|
{
|
||||||
|
mInternetStreamURL = url;
|
||||||
|
|
||||||
|
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING, 0, &mInternetStream);
|
||||||
|
|
||||||
|
if (result!= FMOD_OK)
|
||||||
|
{
|
||||||
|
llwarns << "Couldn't open fmod stream, error "
|
||||||
|
<< FMOD_ErrorString(result)
|
||||||
|
<< llendl;
|
||||||
|
mReady = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
|
||||||
|
{
|
||||||
|
// We need a live and opened stream before we try and play it.
|
||||||
|
if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
|
||||||
|
{
|
||||||
|
llwarns << "No internet stream to start playing!" << llendl;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mStreamChannel)
|
||||||
|
return mStreamChannel; //Already have a channel for this stream.
|
||||||
|
|
||||||
|
mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
|
||||||
|
return mStreamChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LLAudioStreamManagerFMODEX::stopStream()
|
||||||
|
{
|
||||||
|
if (mInternetStream)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
bool close = true;
|
||||||
|
switch (getOpenState())
|
||||||
|
{
|
||||||
|
case FMOD_OPENSTATE_CONNECTING:
|
||||||
|
close = false;
|
||||||
|
break;
|
||||||
|
/*case FSOUND_STREAM_NET_NOTCONNECTED:
|
||||||
|
case FSOUND_STREAM_NET_BUFFERING:
|
||||||
|
case FSOUND_STREAM_NET_READY:
|
||||||
|
case FSOUND_STREAM_NET_ERROR:*/
|
||||||
|
default:
|
||||||
|
close = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close)
|
||||||
|
{
|
||||||
|
mInternetStream->release();
|
||||||
|
mStreamChannel = NULL;
|
||||||
|
mInternetStream = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState()
|
||||||
|
{
|
||||||
|
FMOD_OPENSTATE state;
|
||||||
|
mInternetStream->getOpenState(&state,NULL,NULL,NULL);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
80
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
80
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* @file streamingaudio_fmod.h
|
||||||
|
* @author Tofu Linden
|
||||||
|
* @brief Definition of LLStreamingAudio_FMOD 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_FMOD_H
|
||||||
|
#define LL_STREAMINGAUDIO_FMOD_H
|
||||||
|
|
||||||
|
#include "stdtypes.h" // from llcommon
|
||||||
|
|
||||||
|
#include "llstreamingaudio.h"
|
||||||
|
|
||||||
|
//Stubs
|
||||||
|
class LLAudioStreamManagerFMODEX;
|
||||||
|
namespace FMOD
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
class Channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Interfaces
|
||||||
|
class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLStreamingAudio_FMODEX(FMOD::System *system);
|
||||||
|
/*virtual*/ ~LLStreamingAudio_FMODEX();
|
||||||
|
|
||||||
|
/*virtual*/ void start(const std::string& url);
|
||||||
|
/*virtual*/ void stop();
|
||||||
|
/*virtual*/ void pause(int pause);
|
||||||
|
/*virtual*/ void update();
|
||||||
|
/*virtual*/ int isPlaying();
|
||||||
|
/*virtual*/ void setGain(F32 vol);
|
||||||
|
/*virtual*/ F32 getGain();
|
||||||
|
/*virtual*/ std::string getURL();
|
||||||
|
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not supported.
|
||||||
|
|
||||||
|
private:
|
||||||
|
FMOD::System *mSystem;
|
||||||
|
|
||||||
|
LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
|
||||||
|
FMOD::Channel *mFMODInternetStreamChannelp;
|
||||||
|
std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
|
||||||
|
|
||||||
|
std::string mURL;
|
||||||
|
F32 mGain;
|
||||||
|
|
||||||
|
LLSD *mMetaData;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LL_STREAMINGAUDIO_FMOD_H
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
#define WINDGEN_H
|
#define WINDGEN_H
|
||||||
|
|
||||||
#include "llcommon.h"
|
#include "llcommon.h"
|
||||||
|
#include "llrand.h"
|
||||||
|
|
||||||
template <class MIXBUFFERFORMAT_T>
|
template <class MIXBUFFERFORMAT_T>
|
||||||
class LLWindGen
|
class LLWindGen
|
||||||
@@ -60,7 +61,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const U32 getInputSamplingRate() { return mInputSamplingRate; }
|
const U32 getInputSamplingRate() { return mInputSamplingRate; }
|
||||||
|
const F32 getNextSample();
|
||||||
|
const F32 getClampedSample(bool clamp, F32 sample);
|
||||||
|
|
||||||
// newbuffer = the buffer passed from the previous DSP unit.
|
// newbuffer = the buffer passed from the previous DSP unit.
|
||||||
// numsamples = length in samples-per-channel at this mix time.
|
// numsamples = length in samples-per-channel at this mix time.
|
||||||
// NOTE: generates L/R interleaved stereo
|
// NOTE: generates L/R interleaved stereo
|
||||||
@@ -95,7 +98,7 @@ public:
|
|||||||
|
|
||||||
// Start with white noise
|
// Start with white noise
|
||||||
// This expression is fragile, rearrange it and it will break!
|
// This expression is fragile, rearrange it and it will break!
|
||||||
next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
|
next_sample = getNextSample();
|
||||||
|
|
||||||
// Apply a pinking filter
|
// Apply a pinking filter
|
||||||
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
|
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
|
||||||
@@ -132,23 +135,13 @@ public:
|
|||||||
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
|
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
|
||||||
{
|
{
|
||||||
mLastSample = mLastSample + delta;
|
mLastSample = mLastSample + delta;
|
||||||
S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
|
MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR);
|
||||||
S32 sample_left = (S32)mLastSample - sample_right;
|
MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
|
||||||
|
|
||||||
if (!clip)
|
*cursamplep = sample_left;
|
||||||
{
|
++cursamplep;
|
||||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_left;
|
*cursamplep = sample_right;
|
||||||
++cursamplep;
|
++cursamplep;
|
||||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_right;
|
|
||||||
++cursamplep;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
|
|
||||||
++cursamplep;
|
|
||||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
|
|
||||||
++cursamplep;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,4 +172,9 @@ private:
|
|||||||
F32 mLastSample;
|
F32 mLastSample;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T> inline const F32 LLWindGen<T>::getNextSample() { return (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); }
|
||||||
|
template<> inline const F32 LLWindGen<F32>::getNextSample() { return ll_frand()-.5f; }
|
||||||
|
template<class T> inline const F32 LLWindGen<T>::getClampedSample(bool clamp, F32 sample) { return clamp ? (F32)llclamp((S32)sample,(S32)S16_MIN,(S32)S16_MAX) : sample; }
|
||||||
|
template<> inline const F32 LLWindGen<F32>::getClampedSample(bool clamp, F32 sample) { return sample; }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,7 +7,15 @@ include(Boost)
|
|||||||
include(DBusGlib)
|
include(DBusGlib)
|
||||||
include(DirectX)
|
include(DirectX)
|
||||||
include(ELFIO)
|
include(ELFIO)
|
||||||
include(FMOD)
|
if(FMODEX)
|
||||||
|
include(FMODEX)
|
||||||
|
if(FMODEX)
|
||||||
|
set(FMOD OFF)
|
||||||
|
endif(FMODEX)
|
||||||
|
endif(FMODEX)
|
||||||
|
if(NOT FMODEX)
|
||||||
|
include(FMOD)
|
||||||
|
endif(NOT FMODEX)
|
||||||
include(OPENAL)
|
include(OPENAL)
|
||||||
include(HUNSPELL)
|
include(HUNSPELL)
|
||||||
include(FindOpenGL)
|
include(FindOpenGL)
|
||||||
@@ -1168,7 +1176,6 @@ if (WINDOWS)
|
|||||||
comdlg32
|
comdlg32
|
||||||
${DINPUT_LIBRARY}
|
${DINPUT_LIBRARY}
|
||||||
${DXGUID_LIBRARY}
|
${DXGUID_LIBRARY}
|
||||||
fmodvc
|
|
||||||
gdi32
|
gdi32
|
||||||
kernel32
|
kernel32
|
||||||
odbc32
|
odbc32
|
||||||
@@ -1182,6 +1189,13 @@ if (WINDOWS)
|
|||||||
winspool
|
winspool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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
|
find_library(INTEL_MEMOPS_LIBRARY
|
||||||
NAMES ll_intel_memops
|
NAMES ll_intel_memops
|
||||||
PATHS
|
PATHS
|
||||||
@@ -1288,13 +1302,23 @@ if (OPENAL)
|
|||||||
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL")
|
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL")
|
||||||
endif (OPENAL)
|
endif (OPENAL)
|
||||||
|
|
||||||
if (FMOD)
|
if (FMOD OR FMODEX)
|
||||||
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD")
|
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 (NOT WINDOWS)
|
if (NOT WINDOWS)
|
||||||
set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp)
|
set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp)
|
||||||
add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES})
|
add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES})
|
||||||
set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY})
|
if(FMODEX)
|
||||||
|
set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY})
|
||||||
|
endif(FMODEX)
|
||||||
|
if(FMOD)
|
||||||
|
set(fmodwrapper_needed_LIBRARIES "${fmodwrapper_needed_LIBRARIES} ${FMOD_LIBRARY}")
|
||||||
|
endif(FMOD)
|
||||||
if (DARWIN)
|
if (DARWIN)
|
||||||
list(APPEND fmodwrapper_needed_LIBRARIES ${CARBON_LIBRARY})
|
list(APPEND fmodwrapper_needed_LIBRARIES ${CARBON_LIBRARY})
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
@@ -1308,7 +1332,7 @@ if (FMOD)
|
|||||||
set(FMODWRAPPER_LIBRARY fmodwrapper)
|
set(FMODWRAPPER_LIBRARY fmodwrapper)
|
||||||
target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
|
target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
|
||||||
endif (NOT WINDOWS)
|
endif (NOT WINDOWS)
|
||||||
endif (FMOD)
|
endif (FMOD OR FMODEX)
|
||||||
|
|
||||||
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
|
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
|
||||||
|
|
||||||
@@ -1347,9 +1371,13 @@ if (WINDOWS)
|
|||||||
set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map")
|
set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (FMODEX)
|
||||||
|
set(EXTRA_LINKER_FLAGS "/DELAYLOAD:fmodex.dll")
|
||||||
|
endif (FMODEX)
|
||||||
|
|
||||||
set_target_properties(${VIEWER_BINARY_NAME}
|
set_target_properties(${VIEWER_BINARY_NAME}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS ${GOOGLE_PERFTOOLS_LINKER_FLAGS}"
|
LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS ${GOOGLE_PERFTOOLS_LINKER_FLAGS} ${EXTRA_LINKER_FLAGS}"
|
||||||
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
|
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
|
||||||
LINK_FLAGS_RELEASE ${release_flags}
|
LINK_FLAGS_RELEASE ${release_flags}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,12 +32,24 @@
|
|||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
#if LL_FMODEX
|
||||||
|
void FSOUND_Sound_Init(void);
|
||||||
|
#endif
|
||||||
|
#if LL_FMOD
|
||||||
void FSOUND_Init(void);
|
void FSOUND_Init(void);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void* fmodwrapper(void)
|
void* fmodwrapper(void)
|
||||||
{
|
{
|
||||||
// When building the fmodwrapper library, the linker doesn't seem to want to bring in libfmod.a unless I explicitly
|
// When building the fmodwrapper library, the linker doesn't seem to want to bring in libfmod.a unless I explicitly
|
||||||
// reference at least one symbol in the library. This seemed like the simplest way.
|
// reference at least one symbol in the library. This seemed like the simplest way.
|
||||||
return (void*)&FSOUND_Init;
|
void *ret = NULL;
|
||||||
|
#if LL_FMODEX
|
||||||
|
ret = (void*)&FSOUND_Sound_Init;
|
||||||
|
#endif
|
||||||
|
#if LL_FMOD
|
||||||
|
ret = (void*)&FSOUND_Init;
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,11 @@
|
|||||||
#include "llviewermedia_streamingaudio.h"
|
#include "llviewermedia_streamingaudio.h"
|
||||||
#include "llaudioengine.h"
|
#include "llaudioengine.h"
|
||||||
|
|
||||||
#ifdef LL_FMOD
|
#if LL_FMODEX
|
||||||
|
# include "llaudioengine_fmodex.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LL_FMOD
|
||||||
# include "llaudioengine_fmod.h"
|
# include "llaudioengine_fmod.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -666,6 +670,17 @@ bool idle_startup()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LL_FMODEX
|
||||||
|
if (!gAudiop
|
||||||
|
#if !LL_WINDOWS
|
||||||
|
&& NULL == getenv("LL_BAD_FMODEX_DRIVER")
|
||||||
|
#endif // !LL_WINDOWS
|
||||||
|
)
|
||||||
|
{
|
||||||
|
gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LL_FMOD
|
#ifdef LL_FMOD
|
||||||
if (!gAudiop
|
if (!gAudiop
|
||||||
#if !LL_WINDOWS
|
#if !LL_WINDOWS
|
||||||
|
|||||||
Reference in New Issue
Block a user